vaapi_wrapper.cc 135 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555
  1. // Copyright 2013 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_wrapper.h"
  5. #include <dlfcn.h>
  6. #include <drm_fourcc.h>
  7. #include <string.h>
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10. #include <va/va.h>
  11. #include <va/va_drm.h>
  12. #include <va/va_drmcommon.h>
  13. #include <va/va_str.h>
  14. #include <va/va_version.h>
  15. #include <xf86drm.h>
  16. #include <algorithm>
  17. #include <string>
  18. #include <type_traits>
  19. #include <utility>
  20. #include "base/bind.h"
  21. #include "base/callback_helpers.h"
  22. #include "base/containers/contains.h"
  23. #include "base/containers/cxx20_erase.h"
  24. #include "base/containers/fixed_flat_set.h"
  25. #include "base/cpu.h"
  26. #include "base/environment.h"
  27. #include "base/files/scoped_file.h"
  28. #include "base/logging.h"
  29. #include "base/metrics/histogram_macros.h"
  30. #include "base/no_destructor.h"
  31. #include "base/numerics/checked_math.h"
  32. #include "base/numerics/safe_conversions.h"
  33. #include "base/posix/eintr_wrapper.h"
  34. #include "base/strings/pattern.h"
  35. #include "base/strings/string_util.h"
  36. #include "base/strings/stringprintf.h"
  37. #include "base/system/sys_info.h"
  38. #include "base/trace_event/trace_event.h"
  39. #include "build/build_config.h"
  40. #include "build/chromeos_buildflags.h"
  41. #include "media/base/media_switches.h"
  42. #include "media/base/video_codecs.h"
  43. #include "media/base/video_frame.h"
  44. #include "media/base/video_types.h"
  45. #include "media/gpu/macros.h"
  46. // Auto-generated for dlopen libva libraries
  47. #include "media/gpu/vaapi/va_stubs.h"
  48. #include "media/media_buildflags.h"
  49. #include "third_party/libva_protected_content/va_protected_content.h"
  50. #include "third_party/libyuv/include/libyuv.h"
  51. #include "ui/gfx/buffer_format_util.h"
  52. #include "ui/gfx/buffer_types.h"
  53. #include "ui/gfx/geometry/rect.h"
  54. #include "ui/gfx/linux/drm_util_linux.h"
  55. #include "ui/gfx/linux/native_pixmap_dmabuf.h"
  56. #include "ui/gfx/native_pixmap.h"
  57. #include "ui/gfx/native_pixmap_handle.h"
  58. #include "ui/gl/gl_bindings.h"
  59. #include "ui/gl/gl_implementation.h"
  60. #if BUILDFLAG(USE_VAAPI_X11)
  61. typedef XID Drawable;
  62. extern "C" {
  63. #include "media/gpu/vaapi/va_x11.sigs"
  64. }
  65. #include "ui/gfx/x/connection.h" // nogncheck
  66. #endif // BUILDFLAG(USE_VAAPI_X11)
  67. #if defined(USE_OZONE)
  68. #include "ui/ozone/public/ozone_platform.h"
  69. #include "ui/ozone/public/surface_factory_ozone.h"
  70. #endif
  71. #if BUILDFLAG(IS_CHROMEOS_ASH)
  72. #include <va/va_prot.h>
  73. using media_gpu_vaapi::kModuleVa_prot;
  74. #endif
  75. using media_gpu_vaapi::kModuleVa;
  76. using media_gpu_vaapi::kModuleVa_drm;
  77. #if BUILDFLAG(USE_VAAPI_X11)
  78. using media_gpu_vaapi::kModuleVa_x11;
  79. #endif // BUILDFLAG(USE_VAAPI_X11)
  80. using media_gpu_vaapi::InitializeStubs;
  81. using media_gpu_vaapi::IsVaInitialized;
  82. #if BUILDFLAG(USE_VAAPI_X11)
  83. using media_gpu_vaapi::IsVa_x11Initialized;
  84. #endif // BUILDFLAG(USE_VAAPI_X11)
  85. using media_gpu_vaapi::IsVa_drmInitialized;
  86. using media_gpu_vaapi::StubPathMap;
  87. namespace media {
  88. // These values are logged to UMA. Entries should not be renumbered and numeric
  89. // values should never be reused. Please keep in sync with
  90. // "VaapiFunctions" in src/tools/metrics/histograms/enums.xml.
  91. enum class VaapiFunctions {
  92. kVABeginPicture = 0,
  93. kVACreateBuffer = 1,
  94. kVACreateConfig = 2,
  95. kVACreateContext = 3,
  96. kVACreateImage = 4,
  97. kVACreateSurfaces_Allocating = 5,
  98. kVACreateSurfaces_Importing = 6,
  99. kVADestroyBuffer = 7,
  100. kVADestroyConfig = 8,
  101. kVADestroyContext = 9,
  102. kVADestroySurfaces = 10,
  103. kVAEndPicture = 11,
  104. kVAExportSurfaceHandle = 12,
  105. kVAGetConfigAttributes = 13,
  106. kVAPutImage = 14,
  107. kVAPutSurface = 15,
  108. kVAQueryConfigAttributes = 16,
  109. kVAQueryImageFormats = 17,
  110. kVAQuerySurfaceAttributes = 18,
  111. kVAQueryVideoProcPipelineCaps = 19,
  112. kVARenderPicture_VABuffers = 20,
  113. kVARenderPicture_Vpp = 21,
  114. kVASyncSurface = 22,
  115. kVATerminate = 23,
  116. kVAUnmapBuffer = 24,
  117. // Protected mode functions below.
  118. kVACreateProtectedSession = 25,
  119. kVADestroyProtectedSession = 26,
  120. kVAAttachProtectedSession = 27,
  121. kVADetachProtectedSession = 28,
  122. kVAProtectedSessionHwUpdate_Deprecated = 29,
  123. kVAProtectedSessionExecute = 30,
  124. // Anything else is captured in this last entry.
  125. kOtherVAFunction = 31,
  126. kMaxValue = kOtherVAFunction,
  127. };
  128. void ReportVaapiErrorToUMA(const std::string& histogram_name,
  129. VaapiFunctions value) {
  130. UMA_HISTOGRAM_ENUMERATION(histogram_name, value);
  131. }
  132. constexpr std::array<const char*,
  133. static_cast<size_t>(VaapiFunctions::kMaxValue) + 1>
  134. kVaapiFunctionNames = {"vaBeginPicture",
  135. "vaCreateBuffer",
  136. "vaCreateConfig",
  137. "vaCreateContext",
  138. "vaCreateImage",
  139. "vaCreateSurfaces (allocate mode)",
  140. "vaCreateSurfaces (import mode)",
  141. "vaDestroyBuffer",
  142. "vaDestroyConfig",
  143. "vaDestroyContext",
  144. "vaDestroySurfaces",
  145. "vaEndPicture",
  146. "vaExportSurfaceHandle",
  147. "vaGetConfigAttributes",
  148. "vaPutImage",
  149. "vaPutSurface",
  150. "vaQueryConfigAttributes",
  151. "vaQueryImageFormats",
  152. "vaQuerySurfaceAttributes",
  153. "vaQueryVideoProcPipelineCaps",
  154. "vaRenderPicture (|pending_va_buffers_|)",
  155. "vaRenderPicture using Vpp",
  156. "vaSyncSurface",
  157. "vaTerminate",
  158. "vaUnmapBuffer",
  159. "vaCreateProtectedSession",
  160. "vaDestroyProtectedSession",
  161. "vaAttachProtectedSession",
  162. "vaDetachProtectedSession",
  163. "vaProtectedSessionHwUpdate (Deprecated)",
  164. "vaProtectedSessionExecute",
  165. "Other VA function"};
  166. // Translates |function| into a human readable string for logging.
  167. const char* VaapiFunctionName(VaapiFunctions function) {
  168. DCHECK(function <= VaapiFunctions::kMaxValue);
  169. return kVaapiFunctionNames[static_cast<size_t>(function)];
  170. }
  171. } // namespace media
  172. #define LOG_VA_ERROR_AND_REPORT(va_error, function) \
  173. do { \
  174. LOG(ERROR) << VaapiFunctionName(function) \
  175. << " failed, VA error: " << vaErrorStr(va_error); \
  176. report_error_to_uma_cb_.Run(function); \
  177. } while (0)
  178. #define VA_LOG_ON_ERROR(va_res, function) \
  179. do { \
  180. const VAStatus va_res_va_log_on_error = (va_res); \
  181. if (va_res_va_log_on_error != VA_STATUS_SUCCESS) \
  182. LOG_VA_ERROR_AND_REPORT(va_res_va_log_on_error, function); \
  183. } while (0)
  184. #define VA_SUCCESS_OR_RETURN(va_res, function, ret) \
  185. do { \
  186. const VAStatus va_res_va_sucess_or_return = (va_res); \
  187. if (va_res_va_sucess_or_return != VA_STATUS_SUCCESS) { \
  188. LOG_VA_ERROR_AND_REPORT(va_res_va_sucess_or_return, function); \
  189. return (ret); \
  190. } \
  191. DVLOG(3) << VaapiFunctionName(function); \
  192. } while (0)
  193. namespace {
  194. uint32_t BufferFormatToVAFourCC(gfx::BufferFormat fmt) {
  195. switch (fmt) {
  196. case gfx::BufferFormat::BGRX_8888:
  197. return VA_FOURCC_BGRX;
  198. case gfx::BufferFormat::BGRA_8888:
  199. return VA_FOURCC_BGRA;
  200. case gfx::BufferFormat::RGBX_8888:
  201. return VA_FOURCC_RGBX;
  202. case gfx::BufferFormat::RGBA_8888:
  203. return VA_FOURCC_RGBA;
  204. case gfx::BufferFormat::YVU_420:
  205. return VA_FOURCC_YV12;
  206. case gfx::BufferFormat::YUV_420_BIPLANAR:
  207. return VA_FOURCC_NV12;
  208. case gfx::BufferFormat::P010:
  209. return VA_FOURCC_P010;
  210. default:
  211. NOTREACHED() << gfx::BufferFormatToString(fmt);
  212. return 0;
  213. }
  214. }
  215. media::VAImplementation VendorStringToImplementationType(
  216. const std::string& va_vendor_string) {
  217. if (base::StartsWith(va_vendor_string, "Mesa Gallium driver",
  218. base::CompareCase::SENSITIVE)) {
  219. return media::VAImplementation::kMesaGallium;
  220. } else if (base::StartsWith(va_vendor_string, "Intel i965 driver",
  221. base::CompareCase::SENSITIVE)) {
  222. return media::VAImplementation::kIntelI965;
  223. } else if (base::StartsWith(va_vendor_string, "Intel iHD driver",
  224. base::CompareCase::SENSITIVE)) {
  225. return media::VAImplementation::kIntelIHD;
  226. }
  227. return media::VAImplementation::kOther;
  228. }
  229. bool UseGlobalVaapiLock(media::VAImplementation implementation_type) {
  230. // Only iHD and Mesa Gallium are known to be thread safe at the moment.
  231. // * Mesa Gallium: b/144877595
  232. // * iHD: crbug.com/1123429.
  233. constexpr auto kNoVaapiLockImplementations =
  234. base::MakeFixedFlatSet<media::VAImplementation>(
  235. {media::VAImplementation::kMesaGallium,
  236. media::VAImplementation::kIntelIHD});
  237. return !kNoVaapiLockImplementations.contains(implementation_type) ||
  238. base::FeatureList::IsEnabled(media::kGlobalVaapiLock);
  239. }
  240. bool FillVADRMPRIMESurfaceDescriptor(const gfx::NativePixmap& pixmap,
  241. VADRMPRIMESurfaceDescriptor& descriptor) {
  242. memset(&descriptor, 0, sizeof(VADRMPRIMESurfaceDescriptor));
  243. const gfx::BufferFormat buffer_format = pixmap.GetBufferFormat();
  244. const uint32_t va_fourcc = BufferFormatToVAFourCC(buffer_format);
  245. DCHECK(va_fourcc);
  246. const gfx::Size size = pixmap.GetBufferSize();
  247. const size_t num_planes = pixmap.GetNumberOfPlanes();
  248. const int drm_fourcc = ui::GetFourCCFormatFromBufferFormat(buffer_format);
  249. if (drm_fourcc == DRM_FORMAT_INVALID) {
  250. LOG(ERROR) << "Failed to get the DRM format from the buffer format";
  251. return false;
  252. }
  253. if (num_planes > std::size(descriptor.objects)) {
  254. LOG(ERROR) << "Too many planes in the NativePixmap; got " << num_planes
  255. << " but the maximum number is "
  256. << std::size(descriptor.objects);
  257. return false;
  258. }
  259. static_assert(std::size(VADRMPRIMESurfaceDescriptor{}.layers) ==
  260. std::size(VADRMPRIMESurfaceDescriptor{}.objects));
  261. static_assert(
  262. std::size(VADRMPRIMESurfaceDescriptor{}.layers[0].object_index) ==
  263. std::size(VADRMPRIMESurfaceDescriptor{}.objects));
  264. static_assert(std::size(VADRMPRIMESurfaceDescriptor{}.layers[0].offset) ==
  265. std::size(VADRMPRIMESurfaceDescriptor{}.objects));
  266. static_assert(std::size(VADRMPRIMESurfaceDescriptor{}.layers[0].pitch) ==
  267. std::size(VADRMPRIMESurfaceDescriptor{}.objects));
  268. descriptor.fourcc = va_fourcc;
  269. descriptor.width = base::checked_cast<uint32_t>(size.width());
  270. descriptor.height = base::checked_cast<uint32_t>(size.height());
  271. // We can pass the planes as separate layers or all in one layer. The choice
  272. // of doing the latter was arbitrary.
  273. descriptor.num_layers = 1u;
  274. descriptor.layers[0].drm_format = base::checked_cast<uint32_t>(drm_fourcc);
  275. descriptor.layers[0].num_planes = base::checked_cast<uint32_t>(num_planes);
  276. descriptor.num_objects = base::checked_cast<uint32_t>(num_planes);
  277. for (size_t i = 0u; i < num_planes; i++) {
  278. const int dma_buf_fd = pixmap.GetDmaBufFd(i);
  279. if (dma_buf_fd < 0) {
  280. LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap";
  281. return false;
  282. }
  283. const off_t data_size = lseek(dma_buf_fd, /*offset=*/0, SEEK_END);
  284. if (data_size == static_cast<off_t>(-1)) {
  285. PLOG(ERROR) << "Failed to get the size of the dma-buf";
  286. return false;
  287. }
  288. if (lseek(dma_buf_fd, /*offset=*/0, SEEK_SET) == static_cast<off_t>(-1)) {
  289. PLOG(ERROR) << "Failed to reset the file offset of the dma-buf";
  290. return false;
  291. }
  292. descriptor.objects[i].fd = dma_buf_fd;
  293. descriptor.objects[i].size = base::checked_cast<uint32_t>(data_size);
  294. descriptor.objects[i].drm_format_modifier =
  295. pixmap.GetBufferFormatModifier();
  296. descriptor.layers[0].object_index[i] = base::checked_cast<uint32_t>(i);
  297. if (!base::IsValueInRangeForNumericType<uint32_t>(
  298. pixmap.GetDmaBufOffset(i))) {
  299. LOG(ERROR) << "The offset for plane " << i << " is out-of-range";
  300. return false;
  301. }
  302. descriptor.layers[0].offset[i] =
  303. base::checked_cast<uint32_t>(pixmap.GetDmaBufOffset(i));
  304. descriptor.layers[0].pitch[i] = pixmap.GetDmaBufPitch(i);
  305. }
  306. return true;
  307. }
  308. struct VASurfaceAttribExternalBuffersAndFD {
  309. VASurfaceAttribExternalBuffers va_attrib_extbuf;
  310. uintptr_t fd;
  311. };
  312. bool FillVASurfaceAttribExternalBuffers(
  313. const gfx::NativePixmap& pixmap,
  314. VASurfaceAttribExternalBuffersAndFD& va_attrib_extbuf_and_fd) {
  315. VASurfaceAttribExternalBuffers& va_attrib_extbuf =
  316. va_attrib_extbuf_and_fd.va_attrib_extbuf;
  317. memset(&va_attrib_extbuf_and_fd, 0,
  318. sizeof(VASurfaceAttribExternalBuffersAndFD));
  319. const uint32_t va_fourcc = BufferFormatToVAFourCC(pixmap.GetBufferFormat());
  320. DCHECK(va_fourcc);
  321. const gfx::Size size = pixmap.GetBufferSize();
  322. const size_t num_planes = pixmap.GetNumberOfPlanes();
  323. va_attrib_extbuf.pixel_format = va_fourcc;
  324. va_attrib_extbuf.width = base::checked_cast<uint32_t>(size.width());
  325. va_attrib_extbuf.height = base::checked_cast<uint32_t>(size.height());
  326. static_assert(std::size(VASurfaceAttribExternalBuffers{}.pitches) ==
  327. std::size(VASurfaceAttribExternalBuffers{}.offsets));
  328. if (num_planes > std::size(va_attrib_extbuf.pitches)) {
  329. LOG(ERROR) << "Too many planes in the NativePixmap; got " << num_planes
  330. << " but the maximum number is "
  331. << std::size(va_attrib_extbuf.pitches);
  332. return false;
  333. }
  334. for (size_t i = 0; i < num_planes; ++i) {
  335. va_attrib_extbuf.pitches[i] = pixmap.GetDmaBufPitch(i);
  336. va_attrib_extbuf.offsets[i] =
  337. base::checked_cast<uint32_t>(pixmap.GetDmaBufOffset(i));
  338. DVLOG(4) << "plane " << i << ": pitch: " << va_attrib_extbuf.pitches[i]
  339. << " offset: " << va_attrib_extbuf.offsets[i];
  340. }
  341. va_attrib_extbuf.num_planes = base::checked_cast<uint32_t>(num_planes);
  342. const int dma_buf_fd = pixmap.GetDmaBufFd(0);
  343. if (dma_buf_fd < 0) {
  344. LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap";
  345. return false;
  346. }
  347. const off_t data_size = lseek(dma_buf_fd, /*offset=*/0, SEEK_END);
  348. if (data_size == static_cast<off_t>(-1)) {
  349. PLOG(ERROR) << "Failed to get the size of the dma-buf";
  350. return false;
  351. }
  352. if (lseek(dma_buf_fd, /*offset=*/0, SEEK_SET) == static_cast<off_t>(-1)) {
  353. PLOG(ERROR) << "Failed to reset the file offset of the dma-buf";
  354. return false;
  355. }
  356. // If the data size doesn't fit in a uint32_t, we probably have bigger
  357. // problems.
  358. va_attrib_extbuf.data_size = base::checked_cast<uint32_t>(data_size);
  359. // We only have to pass the first file descriptor to a driver. A VA-API driver
  360. // shall create a VASurface from the single fd correctly.
  361. va_attrib_extbuf_and_fd.fd = base::checked_cast<uintptr_t>(dma_buf_fd);
  362. va_attrib_extbuf.buffers = &va_attrib_extbuf_and_fd.fd;
  363. va_attrib_extbuf.num_buffers = 1u;
  364. DCHECK_EQ(va_attrib_extbuf.flags, 0u);
  365. DCHECK_EQ(va_attrib_extbuf.private_data, nullptr);
  366. return true;
  367. }
  368. } // namespace
  369. namespace media {
  370. namespace {
  371. // VAEntrypoint is an enumeration starting from 1, but has no "invalid" value.
  372. constexpr VAEntrypoint kVAEntrypointInvalid = static_cast<VAEntrypoint>(0);
  373. // Returns true if the SoC has a Gen8 GPU. CPU model ID's are referenced from
  374. // the following file in the kernel source: arch/x86/include/asm/intel-family.h.
  375. bool IsGen8Gpu() {
  376. constexpr int kPentiumAndLaterFamily = 0x06;
  377. constexpr int kBroadwellCoreModelId = 0x3D;
  378. constexpr int kBroadwellGT3EModelId = 0x47;
  379. constexpr int kBroadwellXModelId = 0x4F;
  380. constexpr int kBroadwellXeonDModelId = 0x56;
  381. constexpr int kBraswellModelId = 0x4C;
  382. static const base::NoDestructor<base::CPU> cpuid;
  383. static const bool is_gen8_gpu = cpuid->family() == kPentiumAndLaterFamily &&
  384. (cpuid->model() == kBroadwellCoreModelId ||
  385. cpuid->model() == kBroadwellGT3EModelId ||
  386. cpuid->model() == kBroadwellXModelId ||
  387. cpuid->model() == kBroadwellXeonDModelId ||
  388. cpuid->model() == kBraswellModelId);
  389. return is_gen8_gpu;
  390. }
  391. // Returns true if the SoC has a Gen9 GPU. CPU model ID's are referenced from
  392. // the following file in the kernel source: arch/x86/include/asm/intel-family.h.
  393. bool IsGen9Gpu() {
  394. constexpr int kPentiumAndLaterFamily = 0x06;
  395. constexpr int kSkyLakeModelId = 0x5E;
  396. constexpr int kSkyLake_LModelId = 0x4E;
  397. constexpr int kApolloLakeModelId = 0x5c;
  398. static const base::NoDestructor<base::CPU> cpuid;
  399. static const bool is_gen9_gpu = cpuid->family() == kPentiumAndLaterFamily &&
  400. (cpuid->model() == kSkyLakeModelId ||
  401. cpuid->model() == kSkyLake_LModelId ||
  402. cpuid->model() == kApolloLakeModelId);
  403. return is_gen9_gpu;
  404. }
  405. // Returns true if the SoC has a 9.5 GPU. CPU model IDs are referenced from the
  406. // following file in the kernel source: arch/x86/include/asm/intel-family.h.
  407. bool IsGen95Gpu() {
  408. constexpr int kPentiumAndLaterFamily = 0x06;
  409. constexpr int kKabyLakeModelId = 0x9E;
  410. // Amber Lake, Whiskey Lake and some Comet Lake CPU IDs are the same as KBL L.
  411. constexpr int kKabyLake_LModelId = 0x8E;
  412. constexpr int kGeminiLakeModelId = 0x7A;
  413. constexpr int kCometLakeModelId = 0xA5;
  414. constexpr int kCometLake_LModelId = 0xA6;
  415. static const base::NoDestructor<base::CPU> cpuid;
  416. static const bool is_gen95_gpu = cpuid->family() == kPentiumAndLaterFamily &&
  417. (cpuid->model() == kKabyLakeModelId ||
  418. cpuid->model() == kKabyLake_LModelId ||
  419. cpuid->model() == kGeminiLakeModelId ||
  420. cpuid->model() == kCometLakeModelId ||
  421. cpuid->model() == kCometLake_LModelId);
  422. return is_gen95_gpu;
  423. }
  424. // Returns true if the intel hybrid driver is used for decoding |va_profile|.
  425. // https://github.com/intel/intel-hybrid-driver
  426. // Note that since the hybrid driver runs as a part of the i965 driver,
  427. // vaQueryVendorString() returns "Intel i965 driver".
  428. bool IsUsingHybridDriverForDecoding(VAProfile va_profile) {
  429. // Note that Skylake (not gen8) also needs the hybrid decoder for VP9
  430. // decoding. However, it is disabled today on ChromeOS
  431. // (see crrev.com/c/390511).
  432. return va_profile == VAProfileVP9Profile0 && IsGen8Gpu();
  433. }
  434. // Returns true if the SoC is considered a low power one, i.e. it's an Intel
  435. // Pentium, Celeron, or a Core Y-series. See go/intel-socs-101 or
  436. // https://www.intel.com/content/www/us/en/processors/processor-numbers.html.
  437. bool IsLowPowerIntelProcessor() {
  438. constexpr int kPentiumAndLaterFamily = 0x06;
  439. static const base::NoDestructor<base::CPU> cpuid;
  440. static const bool is_core_y_processor =
  441. base::MatchPattern(cpuid->cpu_brand(), "Intel(R) Core(TM) *Y CPU*");
  442. static const bool is_low_power_intel =
  443. cpuid->family() == kPentiumAndLaterFamily &&
  444. (base::Contains(cpuid->cpu_brand(), "Pentium") ||
  445. base::Contains(cpuid->cpu_brand(), "Celeron") || is_core_y_processor);
  446. return is_low_power_intel;
  447. }
  448. bool IsModeDecoding(VaapiWrapper::CodecMode mode) {
  449. return mode == VaapiWrapper::CodecMode::kDecode
  450. #if BUILDFLAG(IS_CHROMEOS_ASH)
  451. || VaapiWrapper::CodecMode::kDecodeProtected
  452. #endif
  453. ;
  454. }
  455. bool IsModeEncoding(VaapiWrapper::CodecMode mode) {
  456. return mode == VaapiWrapper::CodecMode::kEncodeConstantBitrate ||
  457. mode ==
  458. VaapiWrapper::CodecMode::kEncodeConstantQuantizationParameter ||
  459. mode == VaapiWrapper::CodecMode::kEncodeVariableBitrate;
  460. }
  461. bool GetNV12VisibleWidthBytes(int visible_width,
  462. uint32_t plane,
  463. size_t* bytes) {
  464. if (plane == 0) {
  465. *bytes = base::checked_cast<size_t>(visible_width);
  466. return true;
  467. }
  468. *bytes = base::checked_cast<size_t>(visible_width);
  469. return visible_width % 2 == 0 ||
  470. base::CheckAdd<int>(visible_width, 1).AssignIfValid(bytes);
  471. }
  472. // Fill 0 on VAImage's non visible area.
  473. bool ClearNV12Padding(const VAImage& image,
  474. const gfx::Size& visible_size,
  475. uint8_t* data) {
  476. DCHECK_EQ(2u, image.num_planes);
  477. DCHECK_EQ(image.format.fourcc, static_cast<uint32_t>(VA_FOURCC_NV12));
  478. size_t visible_width_bytes[2] = {};
  479. if (!GetNV12VisibleWidthBytes(visible_size.width(), 0u,
  480. &visible_width_bytes[0]) ||
  481. !GetNV12VisibleWidthBytes(visible_size.width(), 1u,
  482. &visible_width_bytes[1])) {
  483. return false;
  484. }
  485. for (uint32_t plane = 0; plane < image.num_planes; plane++) {
  486. size_t row_bytes = base::strict_cast<size_t>(image.pitches[plane]);
  487. if (row_bytes == visible_width_bytes[plane])
  488. continue;
  489. CHECK_GT(row_bytes, visible_width_bytes[plane]);
  490. int visible_height = visible_size.height();
  491. if (plane == 1 && !(base::CheckAdd<int>(visible_size.height(), 1) / 2)
  492. .AssignIfValid(&visible_height)) {
  493. return false;
  494. }
  495. const size_t padding_bytes = row_bytes - visible_width_bytes[plane];
  496. uint8_t* plane_data = data + image.offsets[plane];
  497. for (int row = 0; row < visible_height; row++, plane_data += row_bytes)
  498. memset(plane_data + visible_width_bytes[plane], 0, padding_bytes);
  499. CHECK_GE(base::strict_cast<int>(image.height), visible_height);
  500. size_t image_height = base::strict_cast<size_t>(image.height);
  501. if (plane == 1 && !(base::CheckAdd<size_t>(image.height, 1) / 2)
  502. .AssignIfValid(&image_height)) {
  503. return false;
  504. }
  505. base::CheckedNumeric<size_t> remaining_area(image_height);
  506. remaining_area -= base::checked_cast<size_t>(visible_height);
  507. remaining_area *= row_bytes;
  508. if (!remaining_area.IsValid())
  509. return false;
  510. memset(plane_data, 0, remaining_area.ValueOrDie());
  511. }
  512. return true;
  513. }
  514. // Can't statically initialize the profile map:
  515. // https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
  516. using ProfileCodecMap = std::map<VideoCodecProfile, VAProfile>;
  517. const ProfileCodecMap& GetProfileCodecMap() {
  518. static const base::NoDestructor<ProfileCodecMap> kMediaToVAProfileMap({
  519. // VAProfileH264Baseline is deprecated in <va/va.h> since libva 2.0.0.
  520. {H264PROFILE_BASELINE, VAProfileH264ConstrainedBaseline},
  521. {H264PROFILE_MAIN, VAProfileH264Main},
  522. // TODO(posciak): See if we can/want to support other variants of
  523. // H264PROFILE_HIGH*.
  524. {H264PROFILE_HIGH, VAProfileH264High},
  525. {VP8PROFILE_ANY, VAProfileVP8Version0_3},
  526. {VP9PROFILE_PROFILE0, VAProfileVP9Profile0},
  527. // VaapiWrapper does not support VP9 Profile 1, see b/153680337.
  528. // {VP9PROFILE_PROFILE1, VAProfileVP9Profile1},
  529. {VP9PROFILE_PROFILE2, VAProfileVP9Profile2},
  530. // VaapiWrapper does not support Profile 3.
  531. //{VP9PROFILE_PROFILE3, VAProfileVP9Profile3},
  532. {AV1PROFILE_PROFILE_MAIN, VAProfileAV1Profile0},
  533. // VaapiWrapper does not support AV1 Profile 1.
  534. // {AV1PROFILE_PROFILE_HIGH, VAProfileAV1Profile1},
  535. #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
  536. {HEVCPROFILE_MAIN, VAProfileHEVCMain},
  537. {HEVCPROFILE_MAIN_STILL_PICTURE, VAProfileHEVCMain},
  538. {HEVCPROFILE_MAIN10, VAProfileHEVCMain10},
  539. #endif // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
  540. });
  541. return *kMediaToVAProfileMap;
  542. }
  543. // Maps a VideoCodecProfile |profile| to a VAProfile, or VAProfileNone.
  544. VAProfile ProfileToVAProfile(VideoCodecProfile profile,
  545. VaapiWrapper::CodecMode mode) {
  546. const auto& profiles = GetProfileCodecMap();
  547. const auto& maybe_profile = profiles.find(profile);
  548. if (maybe_profile == profiles.end())
  549. return VAProfileNone;
  550. return maybe_profile->second;
  551. }
  552. bool IsVAProfileSupported(VAProfile va_profile) {
  553. const auto& profiles = GetProfileCodecMap();
  554. // VAProfileJPEGBaseline and VAProfileProtected are always recognized but are
  555. // not video codecs per se.
  556. return va_profile == VAProfileJPEGBaseline ||
  557. #if BUILDFLAG(IS_CHROMEOS_ASH)
  558. va_profile == VAProfileProtected ||
  559. #endif
  560. std::find_if(profiles.begin(), profiles.end(),
  561. [va_profile](const auto& entry) {
  562. return entry.second == va_profile;
  563. }) != profiles.end();
  564. }
  565. bool IsBlockedDriver(VaapiWrapper::CodecMode mode, VAProfile va_profile) {
  566. if (!IsModeEncoding(mode)) {
  567. return va_profile == VAProfileAV1Profile0 &&
  568. !base::FeatureList::IsEnabled(kVaapiAV1Decoder);
  569. }
  570. // TODO(posciak): Remove once VP8 encoding is to be enabled by default.
  571. if (va_profile == VAProfileVP8Version0_3 &&
  572. !base::FeatureList::IsEnabled(kVaapiVP8Encoder)) {
  573. return true;
  574. }
  575. // TODO(crbug.com/811912): Remove once VP9 encoding is enabled by default.
  576. if (va_profile == VAProfileVP9Profile0 &&
  577. !base::FeatureList::IsEnabled(kVaapiVP9Encoder)) {
  578. return true;
  579. }
  580. return false;
  581. }
  582. // This class is a wrapper around its |va_display_| (and its associated
  583. // |va_lock_|) to guarantee mutual exclusion and singleton behaviour.
  584. class VADisplayState {
  585. public:
  586. static VADisplayState* Get();
  587. VADisplayState(const VADisplayState&) = delete;
  588. VADisplayState& operator=(const VADisplayState&) = delete;
  589. // Initialize static data before sandbox is enabled.
  590. static void PreSandboxInitialization();
  591. bool Initialize();
  592. VAStatus Deinitialize();
  593. base::Lock* va_lock() { return &va_lock_; }
  594. VADisplay va_display() const { return va_display_; }
  595. VAImplementation implementation_type() const { return implementation_type_; }
  596. void SetDrmFd(base::PlatformFile fd) { drm_fd_.reset(HANDLE_EINTR(dup(fd))); }
  597. private:
  598. friend class base::NoDestructor<VADisplayState>;
  599. VADisplayState();
  600. ~VADisplayState() = default;
  601. // Implementation of Initialize() called only once.
  602. bool InitializeOnce() EXCLUSIVE_LOCKS_REQUIRED(va_lock_);
  603. bool InitializeVaDisplay_Locked() EXCLUSIVE_LOCKS_REQUIRED(va_lock_);
  604. bool InitializeVaDriver_Locked() EXCLUSIVE_LOCKS_REQUIRED(va_lock_);
  605. int refcount_ GUARDED_BY(va_lock_);
  606. // Libva may or may not be thread safe depending on the backend. If not thread
  607. // safe, we have to do locking for it ourselves. Therefore, this lock may need
  608. // to be taken for the duration of all VA-API calls and for the entire job
  609. // submission sequence in ExecuteAndDestroyPendingBuffers().
  610. base::Lock va_lock_;
  611. // Drm fd used to obtain access to the driver interface by VA.
  612. base::ScopedFD drm_fd_;
  613. // The VADisplay handle. Valid between Initialize() and Deinitialize().
  614. VADisplay va_display_;
  615. // True if vaInitialize() has been called successfully, until Deinitialize().
  616. bool va_initialized_;
  617. // Enumerated version of vaQueryVendorString(). Valid after Initialize().
  618. VAImplementation implementation_type_ = VAImplementation::kInvalid;
  619. };
  620. // static
  621. VADisplayState* VADisplayState::Get() {
  622. static base::NoDestructor<VADisplayState> display_state;
  623. return display_state.get();
  624. }
  625. // static
  626. void VADisplayState::PreSandboxInitialization() {
  627. constexpr char kRenderNodeFilePattern[] = "/dev/dri/renderD%d";
  628. // This loop ends on either the first card that does not exist or the first
  629. // render node that is not vgem.
  630. for (int i = 128;; i++) {
  631. base::FilePath dev_path(FILE_PATH_LITERAL(
  632. base::StringPrintf(kRenderNodeFilePattern, i).c_str()));
  633. base::File drm_file =
  634. base::File(dev_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
  635. base::File::FLAG_WRITE);
  636. if (!drm_file.IsValid())
  637. return;
  638. // Skip the virtual graphics memory manager device.
  639. drmVersionPtr version = drmGetVersion(drm_file.GetPlatformFile());
  640. if (!version)
  641. continue;
  642. std::string version_name(
  643. version->name,
  644. base::checked_cast<std::string::size_type>(version->name_len));
  645. drmFreeVersion(version);
  646. if (base::EqualsCaseInsensitiveASCII(version_name, "vgem"))
  647. continue;
  648. VADisplayState::Get()->SetDrmFd(drm_file.GetPlatformFile());
  649. return;
  650. }
  651. }
  652. VADisplayState::VADisplayState()
  653. : refcount_(0), va_display_(nullptr), va_initialized_(false) {}
  654. bool VADisplayState::Initialize() {
  655. base::AutoLock auto_lock(va_lock_);
  656. #if defined(USE_OZONE) && BUILDFLAG(IS_LINUX)
  657. // TODO(crbug.com/1116701): add vaapi support for other Ozone platforms on
  658. // Linux. See comment in OzonePlatform::PlatformProperties::supports_vaapi
  659. // for more details. This will also require revisiting everything that's
  660. // guarded by USE_VAAPI_X11. For example, if USE_VAAPI_X11 is true, but the
  661. // user chooses the Wayland backend for Ozone at runtime, then many things (if
  662. // not all) that we do for X11 won't apply.
  663. if (!ui::OzonePlatform::GetInstance()->GetPlatformProperties().supports_vaapi)
  664. return false;
  665. #endif
  666. bool libraries_initialized = IsVaInitialized() && IsVa_drmInitialized();
  667. #if BUILDFLAG(USE_VAAPI_X11)
  668. libraries_initialized = libraries_initialized && IsVa_x11Initialized();
  669. #endif
  670. if (!libraries_initialized)
  671. return false;
  672. // Manual refcounting to ensure the rest of the method is called only once.
  673. if (refcount_++ > 0)
  674. return true;
  675. const bool success = InitializeOnce();
  676. UMA_HISTOGRAM_BOOLEAN("Media.VaapiWrapper.VADisplayStateInitializeSuccess",
  677. success);
  678. return success;
  679. }
  680. #if BUILDFLAG(USE_VAAPI_X11)
  681. absl::optional<VADisplay> GetVADisplayStateX11(const base::ScopedFD& drm_fd) {
  682. switch (gl::GetGLImplementation()) {
  683. case gl::kGLImplementationEGLGLES2:
  684. return vaGetDisplayDRM(drm_fd.get());
  685. case gl::kGLImplementationNone:
  686. case gl::kGLImplementationDesktopGL: {
  687. VADisplay display =
  688. vaGetDisplay(x11::Connection::Get()->GetXlibDisplay());
  689. if (vaDisplayIsValid(display))
  690. return display;
  691. return vaGetDisplayDRM(drm_fd.get());
  692. }
  693. case gl::kGLImplementationEGLANGLE:
  694. return vaGetDisplay(x11::Connection::Get()->GetXlibDisplay());
  695. default:
  696. LOG(WARNING) << "VAAPI video acceleration not available for "
  697. << gl::GetGLImplementationGLName(
  698. gl::GetGLImplementationParts());
  699. return absl::nullopt;
  700. }
  701. }
  702. #else
  703. absl::optional<VADisplay> GetVADisplayState(const base::ScopedFD& drm_fd) {
  704. switch (gl::GetGLImplementation()) {
  705. case gl::kGLImplementationEGLGLES2:
  706. case gl::kGLImplementationEGLANGLE:
  707. case gl::kGLImplementationNone:
  708. return vaGetDisplayDRM(drm_fd.get());
  709. default:
  710. LOG(WARNING) << "VAAPI video acceleration not available for "
  711. << gl::GetGLImplementationGLName(
  712. gl::GetGLImplementationParts());
  713. return absl::nullopt;
  714. }
  715. }
  716. #endif // BUILDFLAG(USE_VAAPI_X11)
  717. bool VADisplayState::InitializeVaDisplay_Locked() {
  718. absl::optional<VADisplay> display =
  719. #if BUILDFLAG(USE_VAAPI_X11)
  720. GetVADisplayStateX11(drm_fd_);
  721. #else
  722. GetVADisplayState(drm_fd_);
  723. #endif
  724. if (!display)
  725. return false;
  726. va_display_ = *display;
  727. if (!vaDisplayIsValid(va_display_)) {
  728. LOG(ERROR) << "Could not get a valid VA display";
  729. return false;
  730. }
  731. return true;
  732. }
  733. bool VADisplayState::InitializeVaDriver_Locked() {
  734. // The VAAPI version.
  735. int major_version, minor_version;
  736. VAStatus va_res = vaInitialize(va_display_, &major_version, &minor_version);
  737. if (va_res != VA_STATUS_SUCCESS) {
  738. VLOGF(1) << "vaInitialize failed: " << vaErrorStr(va_res);
  739. return false;
  740. }
  741. const std::string va_vendor_string = vaQueryVendorString(va_display_);
  742. DLOG_IF(WARNING, va_vendor_string.empty())
  743. << "Vendor string empty or error reading.";
  744. DVLOG(1) << "VAAPI version: " << major_version << "." << minor_version << " "
  745. << va_vendor_string;
  746. implementation_type_ = VendorStringToImplementationType(va_vendor_string);
  747. va_initialized_ = true;
  748. // The VAAPI version is determined from what is loaded on the system by
  749. // calling vaInitialize(). Since the libva is now ABI-compatible, relax the
  750. // version check which helps in upgrading the libva, without breaking any
  751. // existing functionality. Make sure the system version is not older than
  752. // the version with which the chromium is built since libva is only
  753. // guaranteed to be backward (and not forward) compatible.
  754. if (VA_MAJOR_VERSION > major_version ||
  755. (VA_MAJOR_VERSION == major_version && VA_MINOR_VERSION > minor_version)) {
  756. VLOGF(1) << "The system version " << major_version << "." << minor_version
  757. << " should be greater than or equal to " << VA_MAJOR_VERSION
  758. << "." << VA_MINOR_VERSION;
  759. return false;
  760. }
  761. return true;
  762. }
  763. bool VADisplayState::InitializeOnce() {
  764. static_assert(
  765. VA_MAJOR_VERSION >= 2 || (VA_MAJOR_VERSION == 1 && VA_MINOR_VERSION >= 1),
  766. "Requires VA-API >= 1.1.0");
  767. // Set VA logging level, unless already set.
  768. constexpr char libva_log_level_env[] = "LIBVA_MESSAGING_LEVEL";
  769. std::unique_ptr<base::Environment> env(base::Environment::Create());
  770. if (!env->HasVar(libva_log_level_env))
  771. env->SetVar(libva_log_level_env, "1");
  772. if (!InitializeVaDisplay_Locked() || !InitializeVaDriver_Locked())
  773. return false;
  774. return true;
  775. }
  776. VAStatus VADisplayState::Deinitialize() {
  777. base::AutoLock auto_lock(va_lock_);
  778. VAStatus va_res = VA_STATUS_SUCCESS;
  779. if (--refcount_ > 0)
  780. return va_res;
  781. // Must check if vaInitialize completed successfully, to work around a bug in
  782. // libva. The bug was fixed upstream:
  783. // http://lists.freedesktop.org/archives/libva/2013-July/001807.html
  784. // TODO(mgiuca): Remove this check, and the |va_initialized_| variable, once
  785. // the fix has rolled out sufficiently.
  786. if (va_initialized_ && va_display_)
  787. va_res = vaTerminate(va_display_);
  788. va_initialized_ = false;
  789. va_display_ = nullptr;
  790. return va_res;
  791. }
  792. // Returns all the VAProfiles that the driver lists as supported, regardless of
  793. // what Chrome supports or not.
  794. std::vector<VAProfile> GetSupportedVAProfiles(const base::Lock* va_lock,
  795. VADisplay va_display) {
  796. MAYBE_ASSERT_ACQUIRED(va_lock);
  797. // Query the driver for supported profiles.
  798. const int max_va_profiles = vaMaxNumProfiles(va_display);
  799. std::vector<VAProfile> va_profiles(
  800. base::checked_cast<size_t>(max_va_profiles));
  801. int num_va_profiles;
  802. const VAStatus va_res =
  803. vaQueryConfigProfiles(va_display, &va_profiles[0], &num_va_profiles);
  804. if (va_res != VA_STATUS_SUCCESS) {
  805. LOG(ERROR) << "vaQueryConfigProfiles failed: " << vaErrorStr(va_res);
  806. return {};
  807. }
  808. if (num_va_profiles < 0 || num_va_profiles > max_va_profiles) {
  809. LOG(ERROR) << "vaQueryConfigProfiles returned: " << num_va_profiles
  810. << " profiles";
  811. return {};
  812. }
  813. va_profiles.resize(base::checked_cast<size_t>(num_va_profiles));
  814. return va_profiles;
  815. }
  816. // Queries the driver for the supported entrypoints for |va_profile|, then
  817. // returns those allowed for |mode|.
  818. std::vector<VAEntrypoint> GetEntryPointsForProfile(const base::Lock* va_lock,
  819. VADisplay va_display,
  820. VaapiWrapper::CodecMode mode,
  821. VAProfile va_profile) {
  822. MAYBE_ASSERT_ACQUIRED(va_lock);
  823. const int max_entrypoints = vaMaxNumEntrypoints(va_display);
  824. std::vector<VAEntrypoint> va_entrypoints(
  825. base::checked_cast<size_t>(max_entrypoints));
  826. int num_va_entrypoints;
  827. const VAStatus va_res = vaQueryConfigEntrypoints(
  828. va_display, va_profile, &va_entrypoints[0], &num_va_entrypoints);
  829. if (va_res != VA_STATUS_SUCCESS) {
  830. LOG(ERROR) << "vaQueryConfigEntrypoints failed, VA error: "
  831. << vaErrorStr(va_res);
  832. return {};
  833. }
  834. if (num_va_entrypoints < 0 || num_va_entrypoints > max_entrypoints) {
  835. LOG(ERROR) << "vaQueryConfigEntrypoints returned: " << num_va_entrypoints
  836. << " entry points, when the max is: " << max_entrypoints;
  837. return {};
  838. }
  839. va_entrypoints.resize(num_va_entrypoints);
  840. const std::vector<VAEntrypoint> kAllowedEntryPoints[] = {
  841. {VAEntrypointVLD}, // kDecode.
  842. #if BUILDFLAG(IS_CHROMEOS_ASH)
  843. {VAEntrypointVLD, VAEntrypointProtectedContent}, // kDecodeProtected.
  844. #endif
  845. {VAEntrypointEncSlice, VAEntrypointEncPicture,
  846. VAEntrypointEncSliceLP}, // kEncodeConstantBitrate.
  847. {VAEntrypointEncSlice,
  848. VAEntrypointEncSliceLP}, // kEncodeConstantQuantizationParameter.
  849. {VAEntrypointEncSlice, VAEntrypointEncSliceLP}, // kEncodeVariableBitrate.
  850. {VAEntrypointVideoProc} // kVideoProcess.
  851. };
  852. static_assert(std::size(kAllowedEntryPoints) == VaapiWrapper::kCodecModeMax,
  853. "");
  854. std::vector<VAEntrypoint> entrypoints;
  855. std::copy_if(va_entrypoints.begin(), va_entrypoints.end(),
  856. std::back_inserter(entrypoints),
  857. [&kAllowedEntryPoints, mode](VAEntrypoint entry_point) {
  858. return base::Contains(kAllowedEntryPoints[mode], entry_point);
  859. });
  860. return entrypoints;
  861. }
  862. bool GetRequiredAttribs(const base::Lock* va_lock,
  863. VADisplay va_display,
  864. VaapiWrapper::CodecMode mode,
  865. VAProfile profile,
  866. VAEntrypoint entrypoint,
  867. std::vector<VAConfigAttrib>* required_attribs) {
  868. MAYBE_ASSERT_ACQUIRED(va_lock);
  869. // Choose a suitable VAConfigAttribRTFormat for every |mode|. For video
  870. // processing, the supported surface attribs may vary according to which RT
  871. // format is set.
  872. if (profile == VAProfileVP9Profile2 || profile == VAProfileVP9Profile3) {
  873. required_attribs->push_back(
  874. {VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420_10BPP});
  875. #if BUILDFLAG(IS_CHROMEOS_ASH)
  876. } else if (profile == VAProfileProtected) {
  877. DCHECK_EQ(mode, VaapiWrapper::kDecodeProtected);
  878. constexpr int kWidevineUsage = 0x1;
  879. required_attribs->push_back(
  880. {VAConfigAttribProtectedContentUsage, kWidevineUsage});
  881. required_attribs->push_back(
  882. {VAConfigAttribProtectedContentCipherAlgorithm, VA_PC_CIPHER_AES});
  883. required_attribs->push_back(
  884. {VAConfigAttribProtectedContentCipherBlockSize, VA_PC_BLOCK_SIZE_128});
  885. required_attribs->push_back(
  886. {VAConfigAttribProtectedContentCipherMode, VA_PC_CIPHER_MODE_CTR});
  887. #endif
  888. } else {
  889. required_attribs->push_back({VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420});
  890. }
  891. #if BUILDFLAG(IS_CHROMEOS_ASH)
  892. if (mode == VaapiWrapper::kDecodeProtected && profile != VAProfileProtected) {
  893. required_attribs->push_back(
  894. {VAConfigAttribEncryption, VA_ENCRYPTION_TYPE_SUBSAMPLE_CTR});
  895. }
  896. #endif
  897. if (!IsModeEncoding(mode))
  898. return true;
  899. if (profile == VAProfileJPEGBaseline)
  900. return true;
  901. if (mode == VaapiWrapper::kEncodeConstantBitrate)
  902. required_attribs->push_back({VAConfigAttribRateControl, VA_RC_CBR});
  903. if (mode == VaapiWrapper::kEncodeConstantQuantizationParameter)
  904. required_attribs->push_back({VAConfigAttribRateControl, VA_RC_CQP});
  905. if (mode == VaapiWrapper::kEncodeVariableBitrate)
  906. required_attribs->push_back({VAConfigAttribRateControl, VA_RC_VBR});
  907. constexpr VAProfile kSupportedH264VaProfilesForEncoding[] = {
  908. VAProfileH264ConstrainedBaseline, VAProfileH264Main, VAProfileH264High};
  909. // VAConfigAttribEncPackedHeaders is H.264 specific.
  910. if (base::Contains(kSupportedH264VaProfilesForEncoding, profile)) {
  911. // Encode with Packed header if the driver supports.
  912. VAConfigAttrib attrib{};
  913. attrib.type = VAConfigAttribEncPackedHeaders;
  914. const VAStatus va_res =
  915. vaGetConfigAttributes(va_display, profile, entrypoint, &attrib, 1);
  916. if (va_res != VA_STATUS_SUCCESS) {
  917. LOG(ERROR) << "vaGetConfigAttributes failed: " << vaProfileStr(profile);
  918. return false;
  919. }
  920. const uint32_t packed_header_attributes =
  921. (VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE |
  922. VA_ENC_PACKED_HEADER_SLICE);
  923. if ((packed_header_attributes & attrib.value) == packed_header_attributes) {
  924. required_attribs->push_back(
  925. {VAConfigAttribEncPackedHeaders, packed_header_attributes});
  926. } else {
  927. required_attribs->push_back(
  928. {VAConfigAttribEncPackedHeaders, VA_ENC_PACKED_HEADER_NONE});
  929. }
  930. }
  931. return true;
  932. }
  933. // Returns true if |va_profile| for |entrypoint| with |required_attribs| is
  934. // supported.
  935. bool AreAttribsSupported(const base::Lock* va_lock,
  936. VADisplay va_display,
  937. VAProfile va_profile,
  938. VAEntrypoint entrypoint,
  939. const std::vector<VAConfigAttrib>& required_attribs) {
  940. MAYBE_ASSERT_ACQUIRED(va_lock);
  941. // Query the driver for required attributes.
  942. std::vector<VAConfigAttrib> attribs = required_attribs;
  943. for (size_t i = 0; i < required_attribs.size(); ++i)
  944. attribs[i].value = 0;
  945. VAStatus va_res = vaGetConfigAttributes(va_display, va_profile, entrypoint,
  946. &attribs[0], attribs.size());
  947. if (va_res != VA_STATUS_SUCCESS) {
  948. LOG(ERROR) << "vaGetConfigAttributes failed error: " << vaErrorStr(va_res);
  949. return false;
  950. }
  951. for (size_t i = 0; i < required_attribs.size(); ++i) {
  952. if (attribs[i].type != required_attribs[i].type ||
  953. (attribs[i].value & required_attribs[i].value) !=
  954. required_attribs[i].value) {
  955. DVLOG(1) << "Unsupported value " << required_attribs[i].value << " for "
  956. << vaConfigAttribTypeStr(required_attribs[i].type);
  957. return false;
  958. }
  959. }
  960. return true;
  961. }
  962. // This class encapsulates reading and giving access to the list of supported
  963. // ProfileInfo entries, in a singleton way.
  964. class VASupportedProfiles {
  965. public:
  966. struct ProfileInfo {
  967. VAProfile va_profile;
  968. VAEntrypoint va_entrypoint;
  969. gfx::Size min_resolution;
  970. gfx::Size max_resolution;
  971. std::vector<uint32_t> pixel_formats;
  972. VaapiWrapper::InternalFormats supported_internal_formats;
  973. };
  974. static const VASupportedProfiles& Get();
  975. VASupportedProfiles(const VASupportedProfiles&) = delete;
  976. VASupportedProfiles& operator=(const VASupportedProfiles&) = delete;
  977. // Determines if |mode| supports |va_profile| (and |va_entrypoint| if defined
  978. // and valid). If so, returns a const pointer to its ProfileInfo, otherwise
  979. // returns nullptr.
  980. // TODO(hiroh): If VAEntrypoint is kVAEntrypointInvalid, the default entry
  981. // point acquired by GetDefaultVaEntryPoint() is used. If the default entry
  982. // point is not supported, the earlier supported entrypoint in
  983. // |kAllowedEntryPopints| is used.
  984. const ProfileInfo* IsProfileSupported(
  985. VaapiWrapper::CodecMode mode,
  986. VAProfile va_profile,
  987. VAEntrypoint va_entrypoint = kVAEntrypointInvalid) const;
  988. private:
  989. friend class base::NoDestructor<VASupportedProfiles>;
  990. friend std::map<VAProfile, std::vector<VAEntrypoint>>
  991. VaapiWrapper::GetSupportedConfigurationsForCodecModeForTesting(
  992. CodecMode mode);
  993. VASupportedProfiles();
  994. ~VASupportedProfiles() = default;
  995. // Fills in |supported_profiles_|.
  996. void FillSupportedProfileInfos(base::Lock* va_lock, VADisplay va_display);
  997. // Fills |profile_info| for |va_profile| and |entrypoint| with
  998. // |required_attribs|. If the return value is true, the operation was
  999. // successful. Otherwise, the information in *|profile_info| shouldn't be
  1000. // relied upon.
  1001. bool FillProfileInfo_Locked(const base::Lock* va_lock,
  1002. VADisplay va_display,
  1003. VAProfile va_profile,
  1004. VAEntrypoint entrypoint,
  1005. std::vector<VAConfigAttrib>& required_attribs,
  1006. ProfileInfo* profile_info) const;
  1007. std::vector<ProfileInfo> supported_profiles_[VaapiWrapper::kCodecModeMax];
  1008. static_assert(std::extent<decltype(supported_profiles_)>() ==
  1009. VaapiWrapper::kCodecModeMax,
  1010. "|supported_profiles_| size is incorrect.");
  1011. const ReportErrorToUMACB report_error_to_uma_cb_;
  1012. };
  1013. // static
  1014. const VASupportedProfiles& VASupportedProfiles::Get() {
  1015. static const base::NoDestructor<VASupportedProfiles> profile_infos;
  1016. return *profile_infos;
  1017. }
  1018. const VASupportedProfiles::ProfileInfo* VASupportedProfiles::IsProfileSupported(
  1019. VaapiWrapper::CodecMode mode,
  1020. VAProfile va_profile,
  1021. VAEntrypoint va_entrypoint) const {
  1022. auto iter = std::find_if(
  1023. supported_profiles_[mode].begin(), supported_profiles_[mode].end(),
  1024. [va_profile, va_entrypoint](const ProfileInfo& profile) {
  1025. return profile.va_profile == va_profile &&
  1026. (va_entrypoint == kVAEntrypointInvalid ||
  1027. profile.va_entrypoint == va_entrypoint);
  1028. });
  1029. if (iter != supported_profiles_[mode].end())
  1030. return &*iter;
  1031. return nullptr;
  1032. }
  1033. VASupportedProfiles::VASupportedProfiles()
  1034. : report_error_to_uma_cb_(base::DoNothing()) {
  1035. VADisplayState* display_state = VADisplayState::Get();
  1036. if (!display_state->Initialize())
  1037. return;
  1038. VADisplay va_display = display_state->va_display();
  1039. DCHECK(va_display) << "VADisplayState hasn't been properly Initialize()d";
  1040. base::Lock* va_lock = display_state->va_lock();
  1041. if (!UseGlobalVaapiLock(display_state->implementation_type())) {
  1042. va_lock = nullptr;
  1043. }
  1044. FillSupportedProfileInfos(va_lock, va_display);
  1045. const VAStatus va_res = display_state->Deinitialize();
  1046. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVATerminate);
  1047. }
  1048. void VASupportedProfiles::FillSupportedProfileInfos(base::Lock* va_lock,
  1049. VADisplay va_display) {
  1050. base::AutoLockMaybe auto_lock(va_lock);
  1051. const std::vector<VAProfile> va_profiles =
  1052. GetSupportedVAProfiles(va_lock, va_display);
  1053. constexpr VaapiWrapper::CodecMode kWrapperModes[] = {
  1054. VaapiWrapper::kDecode,
  1055. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1056. VaapiWrapper::kDecodeProtected,
  1057. #endif
  1058. VaapiWrapper::kEncodeConstantBitrate,
  1059. VaapiWrapper::kEncodeConstantQuantizationParameter,
  1060. VaapiWrapper::kEncodeVariableBitrate,
  1061. VaapiWrapper::kVideoProcess
  1062. };
  1063. static_assert(std::size(kWrapperModes) == VaapiWrapper::kCodecModeMax, "");
  1064. for (VaapiWrapper::CodecMode mode : kWrapperModes) {
  1065. std::vector<ProfileInfo> supported_profile_infos;
  1066. for (const auto& va_profile : va_profiles) {
  1067. if (IsBlockedDriver(mode, va_profile))
  1068. continue;
  1069. if ((mode != VaapiWrapper::kVideoProcess) &&
  1070. !IsVAProfileSupported(va_profile)) {
  1071. continue;
  1072. }
  1073. const std::vector<VAEntrypoint> supported_entrypoints =
  1074. GetEntryPointsForProfile(va_lock, va_display, mode, va_profile);
  1075. for (const auto& entrypoint : supported_entrypoints) {
  1076. std::vector<VAConfigAttrib> required_attribs;
  1077. if (!GetRequiredAttribs(va_lock, va_display, mode, va_profile,
  1078. entrypoint, &required_attribs)) {
  1079. continue;
  1080. }
  1081. if (!AreAttribsSupported(va_lock, va_display, va_profile, entrypoint,
  1082. required_attribs)) {
  1083. continue;
  1084. }
  1085. ProfileInfo profile_info{};
  1086. if (!FillProfileInfo_Locked(va_lock, va_display, va_profile, entrypoint,
  1087. required_attribs, &profile_info)) {
  1088. LOG(ERROR) << "FillProfileInfo_Locked failed for va_profile "
  1089. << vaProfileStr(va_profile) << " and entrypoint "
  1090. << vaEntrypointStr(entrypoint);
  1091. continue;
  1092. }
  1093. supported_profile_infos.push_back(profile_info);
  1094. }
  1095. }
  1096. supported_profiles_[static_cast<int>(mode)] = supported_profile_infos;
  1097. }
  1098. }
  1099. bool VASupportedProfiles::FillProfileInfo_Locked(
  1100. const base::Lock* va_lock,
  1101. VADisplay va_display,
  1102. VAProfile va_profile,
  1103. VAEntrypoint entrypoint,
  1104. std::vector<VAConfigAttrib>& required_attribs,
  1105. ProfileInfo* profile_info) const {
  1106. MAYBE_ASSERT_ACQUIRED(va_lock);
  1107. VAConfigID va_config_id;
  1108. VAStatus va_res =
  1109. vaCreateConfig(va_display, va_profile, entrypoint, &required_attribs[0],
  1110. required_attribs.size(), &va_config_id);
  1111. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVACreateConfig, false);
  1112. base::ScopedClosureRunner vaconfig_destroyer(base::BindOnce(
  1113. [](VADisplay display, VAConfigID id) {
  1114. if (id != VA_INVALID_ID) {
  1115. VAStatus va_res = vaDestroyConfig(display, id);
  1116. if (va_res != VA_STATUS_SUCCESS)
  1117. LOG(ERROR) << "vaDestroyConfig failed. VA error: "
  1118. << vaErrorStr(va_res);
  1119. }
  1120. },
  1121. va_display, va_config_id));
  1122. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1123. // Nothing further to query for protected profile.
  1124. if (va_profile == VAProfileProtected) {
  1125. profile_info->va_profile = va_profile;
  1126. profile_info->va_entrypoint = entrypoint;
  1127. return true;
  1128. }
  1129. #endif
  1130. // Calls vaQuerySurfaceAttributes twice. The first time is to get the number
  1131. // of attributes to prepare the space and the second time is to get all
  1132. // attributes.
  1133. unsigned int num_attribs;
  1134. va_res =
  1135. vaQuerySurfaceAttributes(va_display, va_config_id, nullptr, &num_attribs);
  1136. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAQuerySurfaceAttributes,
  1137. false);
  1138. if (!num_attribs)
  1139. return false;
  1140. std::vector<VASurfaceAttrib> attrib_list(
  1141. base::checked_cast<size_t>(num_attribs));
  1142. va_res = vaQuerySurfaceAttributes(va_display, va_config_id, &attrib_list[0],
  1143. &num_attribs);
  1144. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAQuerySurfaceAttributes,
  1145. false);
  1146. profile_info->va_profile = va_profile;
  1147. profile_info->va_entrypoint = entrypoint;
  1148. profile_info->min_resolution = gfx::Size();
  1149. profile_info->max_resolution = gfx::Size();
  1150. for (const auto& attrib : attrib_list) {
  1151. if (attrib.type == VASurfaceAttribMaxWidth) {
  1152. profile_info->max_resolution.set_width(
  1153. base::strict_cast<int>(attrib.value.value.i));
  1154. } else if (attrib.type == VASurfaceAttribMaxHeight) {
  1155. profile_info->max_resolution.set_height(
  1156. base::strict_cast<int>(attrib.value.value.i));
  1157. } else if (attrib.type == VASurfaceAttribMinWidth) {
  1158. profile_info->min_resolution.set_width(
  1159. base::strict_cast<int>(attrib.value.value.i));
  1160. } else if (attrib.type == VASurfaceAttribMinHeight) {
  1161. profile_info->min_resolution.set_height(
  1162. base::strict_cast<int>(attrib.value.value.i));
  1163. } else if (attrib.type == VASurfaceAttribPixelFormat) {
  1164. // According to va.h, VASurfaceAttribPixelFormat is meaningful as input to
  1165. // vaQuerySurfaceAttributes(). However, per the implementation of
  1166. // i965_QuerySurfaceAttributes(), our usage here should enumerate all the
  1167. // formats.
  1168. profile_info->pixel_formats.push_back(attrib.value.value.i);
  1169. }
  1170. }
  1171. if (profile_info->max_resolution.IsEmpty()) {
  1172. LOG(ERROR) << "Empty codec maximum resolution";
  1173. return false;
  1174. }
  1175. if (va_profile != VAProfileJPEGBaseline) {
  1176. // Set a reasonable minimum value for both encoding and decoding.
  1177. profile_info->min_resolution.SetToMax(gfx::Size(16, 16));
  1178. const bool is_encoding = entrypoint == VAEntrypointEncSliceLP ||
  1179. entrypoint == VAEntrypointEncSlice;
  1180. const bool is_hybrid_decoding = entrypoint == VAEntrypointVLD &&
  1181. IsUsingHybridDriverForDecoding(va_profile);
  1182. // Using HW encoding for small resolutions is less efficient than using a SW
  1183. // encoder. Similarly, using the intel-hybrid-driver for decoding is less
  1184. // efficient than using a SW decoder. In both cases, increase
  1185. // |min_resolution| to QVGA + 1 which is an experimental lower threshold.
  1186. // This can be turned off with kVaapiVideoMinResolutionForPerformance for
  1187. // testing.
  1188. if ((is_encoding || is_hybrid_decoding) &&
  1189. base::FeatureList::IsEnabled(kVaapiVideoMinResolutionForPerformance)) {
  1190. constexpr gfx::Size kMinVideoResolution(320 + 1, 240 + 1);
  1191. profile_info->min_resolution.SetToMax(kMinVideoResolution);
  1192. DVLOG(2) << "Setting the minimum supported resolution for "
  1193. << vaProfileStr(va_profile)
  1194. << (is_encoding ? " encoding" : " decoding") << " to "
  1195. << profile_info->min_resolution.ToString();
  1196. }
  1197. }
  1198. // Create a new configuration to find the supported RT formats. We don't pass
  1199. // required attributes here because we want the driver to tell us all the
  1200. // supported RT formats.
  1201. va_res = vaCreateConfig(va_display, va_profile, entrypoint, nullptr, 0,
  1202. &va_config_id);
  1203. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVACreateConfig, false);
  1204. base::ScopedClosureRunner vaconfig_no_attribs_destroyer(base::BindOnce(
  1205. [](VADisplay display, VAConfigID id) {
  1206. if (id != VA_INVALID_ID) {
  1207. VAStatus va_res = vaDestroyConfig(display, id);
  1208. if (va_res != VA_STATUS_SUCCESS)
  1209. LOG(ERROR) << "vaDestroyConfig failed. VA error: "
  1210. << vaErrorStr(va_res);
  1211. }
  1212. },
  1213. va_display, va_config_id));
  1214. profile_info->supported_internal_formats = {};
  1215. size_t max_num_config_attributes;
  1216. if (!base::CheckedNumeric<int>(vaMaxNumConfigAttributes(va_display))
  1217. .AssignIfValid(&max_num_config_attributes)) {
  1218. LOG(ERROR) << "Can't get the maximum number of config attributes";
  1219. return false;
  1220. }
  1221. std::vector<VAConfigAttrib> config_attributes(max_num_config_attributes);
  1222. int num_config_attributes;
  1223. va_res = vaQueryConfigAttributes(va_display, va_config_id, &va_profile,
  1224. &entrypoint, config_attributes.data(),
  1225. &num_config_attributes);
  1226. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAQueryConfigAttributes, false);
  1227. for (int i = 0; i < num_config_attributes; i++) {
  1228. const VAConfigAttrib& attrib = config_attributes[i];
  1229. if (attrib.type != VAConfigAttribRTFormat)
  1230. continue;
  1231. if (attrib.value & VA_RT_FORMAT_YUV420)
  1232. profile_info->supported_internal_formats.yuv420 = true;
  1233. if (attrib.value & VA_RT_FORMAT_YUV420_10)
  1234. profile_info->supported_internal_formats.yuv420_10 = true;
  1235. if (attrib.value & VA_RT_FORMAT_YUV422)
  1236. profile_info->supported_internal_formats.yuv422 = true;
  1237. if (attrib.value & VA_RT_FORMAT_YUV444)
  1238. profile_info->supported_internal_formats.yuv444 = true;
  1239. break;
  1240. }
  1241. // Now work around some driver misreporting for JPEG decoding.
  1242. if (va_profile == VAProfileJPEGBaseline && entrypoint == VAEntrypointVLD) {
  1243. if (VADisplayState::Get()->implementation_type() ==
  1244. VAImplementation::kMesaGallium) {
  1245. // TODO(andrescj): the VAAPI state tracker in mesa does not report
  1246. // VA_RT_FORMAT_YUV422 as being supported for JPEG decoding. However, it
  1247. // is happy to allocate YUYV surfaces
  1248. // (https://gitlab.freedesktop.org/mesa/mesa/commit/5608f442). Remove this
  1249. // workaround once b/128337341 is resolved.
  1250. profile_info->supported_internal_formats.yuv422 = true;
  1251. }
  1252. }
  1253. const bool is_any_profile_supported =
  1254. profile_info->supported_internal_formats.yuv420 ||
  1255. profile_info->supported_internal_formats.yuv420_10 ||
  1256. profile_info->supported_internal_formats.yuv422 ||
  1257. profile_info->supported_internal_formats.yuv444;
  1258. DLOG_IF(ERROR, !is_any_profile_supported)
  1259. << "No cool internal formats supported";
  1260. return is_any_profile_supported;
  1261. }
  1262. void DestroyVAImage(VADisplay va_display, VAImage image) {
  1263. if (image.image_id != VA_INVALID_ID)
  1264. vaDestroyImage(va_display, image.image_id);
  1265. }
  1266. // This class encapsulates fetching the list of supported output image formats
  1267. // from the VAAPI driver, in a singleton way.
  1268. class VASupportedImageFormats {
  1269. public:
  1270. static const VASupportedImageFormats& Get();
  1271. VASupportedImageFormats(const VASupportedImageFormats&) = delete;
  1272. VASupportedImageFormats& operator=(const VASupportedImageFormats&) = delete;
  1273. bool IsImageFormatSupported(const VAImageFormat& va_format) const;
  1274. const std::vector<VAImageFormat>& GetSupportedImageFormats() const;
  1275. private:
  1276. friend class base::NoDestructor<VASupportedImageFormats>;
  1277. VASupportedImageFormats();
  1278. ~VASupportedImageFormats() = default;
  1279. // Initialize the list of supported image formats.
  1280. bool InitSupportedImageFormats_Locked(const base::Lock* va_lock,
  1281. VADisplay va_display);
  1282. std::vector<VAImageFormat> supported_formats_;
  1283. const ReportErrorToUMACB report_error_to_uma_cb_;
  1284. };
  1285. // static
  1286. const VASupportedImageFormats& VASupportedImageFormats::Get() {
  1287. static const base::NoDestructor<VASupportedImageFormats> image_formats;
  1288. return *image_formats;
  1289. }
  1290. bool VASupportedImageFormats::IsImageFormatSupported(
  1291. const VAImageFormat& va_image_format) const {
  1292. auto it = std::find_if(supported_formats_.begin(), supported_formats_.end(),
  1293. [&va_image_format](const VAImageFormat& format) {
  1294. return format.fourcc == va_image_format.fourcc;
  1295. });
  1296. return it != supported_formats_.end();
  1297. }
  1298. const std::vector<VAImageFormat>&
  1299. VASupportedImageFormats::GetSupportedImageFormats() const {
  1300. #if DCHECK_IS_ON()
  1301. std::string formats_str;
  1302. for (size_t i = 0; i < supported_formats_.size(); i++) {
  1303. if (i > 0)
  1304. formats_str += ", ";
  1305. formats_str += FourccToString(supported_formats_[i].fourcc);
  1306. }
  1307. DVLOG(1) << "Supported image formats: " << formats_str;
  1308. #endif
  1309. return supported_formats_;
  1310. }
  1311. VASupportedImageFormats::VASupportedImageFormats()
  1312. : report_error_to_uma_cb_(base::DoNothing()) {
  1313. VADisplayState* display_state = VADisplayState::Get();
  1314. if (!display_state->Initialize())
  1315. return;
  1316. // Pointer to VADisplayState's members |va_lock_| if using global VA lock or
  1317. // the implementation is not thread safe.
  1318. base::Lock* va_lock = display_state->va_lock();
  1319. if (!UseGlobalVaapiLock(display_state->implementation_type())) {
  1320. va_lock = nullptr;
  1321. }
  1322. {
  1323. base::AutoLockMaybe auto_lock(va_lock);
  1324. VADisplay va_display = display_state->va_display();
  1325. DCHECK(va_display) << "VADisplayState hasn't been properly initialized";
  1326. if (!InitSupportedImageFormats_Locked(va_lock, va_display))
  1327. LOG(ERROR) << "Failed to get supported image formats";
  1328. }
  1329. const VAStatus va_res = display_state->Deinitialize();
  1330. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVATerminate);
  1331. }
  1332. bool VASupportedImageFormats::InitSupportedImageFormats_Locked(
  1333. const base::Lock* va_lock,
  1334. VADisplay va_display) {
  1335. MAYBE_ASSERT_ACQUIRED(va_lock);
  1336. // Query the driver for the max number of image formats and allocate space.
  1337. const int max_image_formats = vaMaxNumImageFormats(va_display);
  1338. if (max_image_formats < 0) {
  1339. LOG(ERROR) << "vaMaxNumImageFormats returned: " << max_image_formats;
  1340. return false;
  1341. }
  1342. supported_formats_.resize(static_cast<size_t>(max_image_formats));
  1343. // Query the driver for the list of supported image formats.
  1344. int num_image_formats;
  1345. const VAStatus va_res = vaQueryImageFormats(
  1346. va_display, supported_formats_.data(), &num_image_formats);
  1347. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAQueryImageFormats, false);
  1348. if (num_image_formats < 0 || num_image_formats > max_image_formats) {
  1349. LOG(ERROR) << "vaQueryImageFormats returned: " << num_image_formats;
  1350. supported_formats_.clear();
  1351. return false;
  1352. }
  1353. // Resize the list to the actual number of formats returned by the driver.
  1354. supported_formats_.resize(static_cast<size_t>(num_image_formats));
  1355. // Now work around some driver misreporting.
  1356. if (VADisplayState::Get()->implementation_type() ==
  1357. VAImplementation::kMesaGallium) {
  1358. // TODO(andrescj): considering that the VAAPI state tracker in mesa can
  1359. // convert from NV12 to IYUV when doing vaGetImage(), it's reasonable to
  1360. // assume that IYUV/I420 is supported. However, it's not currently being
  1361. // reported. See https://gitlab.freedesktop.org/mesa/mesa/commit/b0a44f10.
  1362. // Remove this workaround once b/128340287 is resolved.
  1363. if (std::find_if(supported_formats_.cbegin(), supported_formats_.cend(),
  1364. [](const VAImageFormat& format) {
  1365. return format.fourcc == VA_FOURCC_I420;
  1366. }) == supported_formats_.cend()) {
  1367. VAImageFormat i420_format{};
  1368. i420_format.fourcc = VA_FOURCC_I420;
  1369. supported_formats_.push_back(i420_format);
  1370. }
  1371. }
  1372. return true;
  1373. }
  1374. bool IsLowPowerEncSupported(VAProfile va_profile) {
  1375. constexpr VAProfile kSupportedLowPowerEncodeProfiles[] = {
  1376. VAProfileH264ConstrainedBaseline,
  1377. VAProfileH264Main,
  1378. VAProfileH264High,
  1379. VAProfileVP9Profile0,
  1380. VAProfileVP9Profile2};
  1381. if (!base::Contains(kSupportedLowPowerEncodeProfiles, va_profile))
  1382. return false;
  1383. if ((IsGen95Gpu() || IsGen9Gpu()) &&
  1384. !base::FeatureList::IsEnabled(kVaapiLowPowerEncoderGen9x)) {
  1385. return false;
  1386. }
  1387. if (VASupportedProfiles::Get().IsProfileSupported(
  1388. VaapiWrapper::kEncodeConstantBitrate, va_profile,
  1389. VAEntrypointEncSliceLP)) {
  1390. return true;
  1391. }
  1392. return false;
  1393. }
  1394. bool IsVBREncodingSupported(VAProfile va_profile) {
  1395. if (!base::FeatureList::IsEnabled(kChromeOSHWVBREncoding))
  1396. return false;
  1397. auto mode = VaapiWrapper::CodecMode::kCodecModeMax;
  1398. switch (va_profile) {
  1399. case VAProfileH264ConstrainedBaseline:
  1400. case VAProfileH264Main:
  1401. case VAProfileH264High:
  1402. mode = VaapiWrapper::CodecMode::kEncodeVariableBitrate;
  1403. break;
  1404. default:
  1405. return false;
  1406. }
  1407. return VASupportedProfiles::Get().IsProfileSupported(mode, va_profile);
  1408. }
  1409. } // namespace
  1410. NativePixmapAndSizeInfo::NativePixmapAndSizeInfo() = default;
  1411. NativePixmapAndSizeInfo::~NativePixmapAndSizeInfo() = default;
  1412. // static
  1413. VAImplementation VaapiWrapper::GetImplementationType() {
  1414. return VADisplayState::Get()->implementation_type();
  1415. }
  1416. // static
  1417. scoped_refptr<VaapiWrapper> VaapiWrapper::Create(
  1418. CodecMode mode,
  1419. VAProfile va_profile,
  1420. EncryptionScheme encryption_scheme,
  1421. const ReportErrorToUMACB& report_error_to_uma_cb,
  1422. bool enforce_sequence_affinity) {
  1423. if (!VASupportedProfiles::Get().IsProfileSupported(mode, va_profile)) {
  1424. DVLOG(1) << "Unsupported va_profile: " << vaProfileStr(va_profile);
  1425. return nullptr;
  1426. }
  1427. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1428. // In protected decode |mode| we need to ensure that |va_profile| is supported
  1429. // (which we verified above) and that VAProfileProtected is supported, which
  1430. // we check here.
  1431. if (mode == kDecodeProtected &&
  1432. !VASupportedProfiles::Get().IsProfileSupported(mode,
  1433. VAProfileProtected)) {
  1434. LOG(ERROR) << "Protected content profile not supported";
  1435. return nullptr;
  1436. }
  1437. #endif
  1438. scoped_refptr<VaapiWrapper> vaapi_wrapper(
  1439. new VaapiWrapper(mode, enforce_sequence_affinity));
  1440. if (vaapi_wrapper->VaInitialize(report_error_to_uma_cb)) {
  1441. if (vaapi_wrapper->Initialize(va_profile, encryption_scheme))
  1442. return vaapi_wrapper;
  1443. }
  1444. LOG(ERROR) << "Failed to create VaapiWrapper for va_profile: "
  1445. << vaProfileStr(va_profile);
  1446. return nullptr;
  1447. }
  1448. // static
  1449. scoped_refptr<VaapiWrapper> VaapiWrapper::CreateForVideoCodec(
  1450. CodecMode mode,
  1451. VideoCodecProfile profile,
  1452. EncryptionScheme encryption_scheme,
  1453. const ReportErrorToUMACB& report_error_to_uma_cb,
  1454. bool enforce_sequence_affinity) {
  1455. const VAProfile va_profile = ProfileToVAProfile(profile, mode);
  1456. return Create(mode, va_profile, encryption_scheme, report_error_to_uma_cb,
  1457. enforce_sequence_affinity);
  1458. }
  1459. // static
  1460. std::vector<SVCScalabilityMode> VaapiWrapper::GetSupportedScalabilityModes(
  1461. VideoCodecProfile media_profile,
  1462. VAProfile va_profile) {
  1463. std::vector<SVCScalabilityMode> scalability_modes;
  1464. #if BUILDFLAG(IS_CHROMEOS)
  1465. if (media_profile == VP9PROFILE_PROFILE0) {
  1466. scalability_modes.push_back(SVCScalabilityMode::kL1T2);
  1467. scalability_modes.push_back(SVCScalabilityMode::kL1T3);
  1468. if (base::FeatureList::IsEnabled(kVaapiVp9kSVCHWEncoding) &&
  1469. GetDefaultVaEntryPoint(
  1470. VaapiWrapper::kEncodeConstantQuantizationParameter, va_profile) ==
  1471. VAEntrypointEncSliceLP) {
  1472. scalability_modes.push_back(SVCScalabilityMode::kL2T2Key);
  1473. scalability_modes.push_back(SVCScalabilityMode::kL2T3Key);
  1474. scalability_modes.push_back(SVCScalabilityMode::kL3T2Key);
  1475. scalability_modes.push_back(SVCScalabilityMode::kL3T3Key);
  1476. }
  1477. }
  1478. if (media_profile >= VP8PROFILE_MIN && media_profile <= VP8PROFILE_MAX) {
  1479. if (base::FeatureList::IsEnabled(kVaapiVp8TemporalLayerHWEncoding)) {
  1480. scalability_modes.push_back(SVCScalabilityMode::kL1T2);
  1481. scalability_modes.push_back(SVCScalabilityMode::kL1T3);
  1482. }
  1483. }
  1484. if (media_profile >= H264PROFILE_MIN && media_profile <= H264PROFILE_MAX) {
  1485. if (base::FeatureList::IsEnabled(kVaapiH264TemporalLayerHWEncoding)) {
  1486. scalability_modes.push_back(SVCScalabilityMode::kL1T2);
  1487. scalability_modes.push_back(SVCScalabilityMode::kL1T3);
  1488. }
  1489. }
  1490. #endif
  1491. return scalability_modes;
  1492. }
  1493. // static
  1494. VideoEncodeAccelerator::SupportedProfiles
  1495. VaapiWrapper::GetSupportedEncodeProfiles() {
  1496. VideoEncodeAccelerator::SupportedProfiles profiles;
  1497. for (const auto& [media_profile, va_profile] : GetProfileCodecMap()) {
  1498. DCHECK(va_profile != VAProfileNone);
  1499. const VASupportedProfiles::ProfileInfo* profile_info =
  1500. VASupportedProfiles::Get().IsProfileSupported(kEncodeConstantBitrate,
  1501. va_profile);
  1502. if (!profile_info)
  1503. continue;
  1504. VideoEncodeAccelerator::SupportedProfile profile;
  1505. profile.profile = media_profile;
  1506. profile.min_resolution = profile_info->min_resolution;
  1507. profile.max_resolution = profile_info->max_resolution;
  1508. // Maximum framerate of encoded profile. This value is an arbitrary
  1509. // limit and not taken from HW documentation.
  1510. constexpr int kMaxEncoderFramerate = 30;
  1511. profile.max_framerate_numerator = kMaxEncoderFramerate;
  1512. profile.max_framerate_denominator = 1;
  1513. profile.rate_control_modes = media::VideoEncodeAccelerator::kConstantMode;
  1514. // This code assumes that the resolutions are the same between CBR and VBR.
  1515. // This is checked in a test in vaapi_unittest.cc: VbrAndCbrResolutionsMatch
  1516. if (IsVBREncodingSupported(va_profile)) {
  1517. profile.rate_control_modes |=
  1518. media::VideoEncodeAccelerator::kVariableMode;
  1519. }
  1520. profile.scalability_modes =
  1521. GetSupportedScalabilityModes(media_profile, va_profile);
  1522. profiles.push_back(profile);
  1523. }
  1524. return profiles;
  1525. }
  1526. // static
  1527. VideoDecodeAccelerator::SupportedProfiles
  1528. VaapiWrapper::GetSupportedDecodeProfiles() {
  1529. VideoDecodeAccelerator::SupportedProfiles profiles;
  1530. for (const auto& [media_profile, va_profile] : GetProfileCodecMap()) {
  1531. DCHECK(va_profile != VAProfileNone);
  1532. const VASupportedProfiles::ProfileInfo* profile_info =
  1533. VASupportedProfiles::Get().IsProfileSupported(kDecode, va_profile);
  1534. if (!profile_info)
  1535. continue;
  1536. VideoDecodeAccelerator::SupportedProfile profile;
  1537. profile.profile = media_profile;
  1538. profile.max_resolution = profile_info->max_resolution;
  1539. profile.min_resolution = profile_info->min_resolution;
  1540. profiles.push_back(profile);
  1541. }
  1542. return profiles;
  1543. }
  1544. // static
  1545. bool VaapiWrapper::IsDecodeSupported(VAProfile va_profile) {
  1546. return VASupportedProfiles::Get().IsProfileSupported(kDecode, va_profile);
  1547. }
  1548. // static
  1549. VaapiWrapper::InternalFormats VaapiWrapper::GetDecodeSupportedInternalFormats(
  1550. VAProfile va_profile) {
  1551. const VASupportedProfiles::ProfileInfo* profile_info =
  1552. VASupportedProfiles::Get().IsProfileSupported(kDecode, va_profile);
  1553. if (!profile_info)
  1554. return InternalFormats{};
  1555. return profile_info->supported_internal_formats;
  1556. }
  1557. // static
  1558. bool VaapiWrapper::IsDecodingSupportedForInternalFormat(
  1559. VAProfile va_profile,
  1560. unsigned int rt_format) {
  1561. static const VaapiWrapper::InternalFormats supported_internal_formats(
  1562. VaapiWrapper::GetDecodeSupportedInternalFormats(va_profile));
  1563. switch (rt_format) {
  1564. case VA_RT_FORMAT_YUV420:
  1565. return supported_internal_formats.yuv420;
  1566. case VA_RT_FORMAT_YUV420_10:
  1567. return supported_internal_formats.yuv420_10;
  1568. case VA_RT_FORMAT_YUV422:
  1569. return supported_internal_formats.yuv422;
  1570. case VA_RT_FORMAT_YUV444:
  1571. return supported_internal_formats.yuv444;
  1572. }
  1573. return false;
  1574. }
  1575. // static
  1576. bool VaapiWrapper::GetSupportedResolutions(VAProfile va_profile,
  1577. CodecMode codec_mode,
  1578. gfx::Size& min_size,
  1579. gfx::Size& max_size) {
  1580. const VASupportedProfiles::ProfileInfo* profile_info =
  1581. VASupportedProfiles::Get().IsProfileSupported(codec_mode, va_profile);
  1582. if (!profile_info || profile_info->max_resolution.IsEmpty())
  1583. return false;
  1584. min_size = gfx::Size(std::max(1, profile_info->min_resolution.width()),
  1585. std::max(1, profile_info->min_resolution.height()));
  1586. max_size = profile_info->max_resolution;
  1587. return true;
  1588. }
  1589. // static
  1590. bool VaapiWrapper::GetJpegDecodeSuitableImageFourCC(unsigned int rt_format,
  1591. uint32_t preferred_fourcc,
  1592. uint32_t* suitable_fourcc) {
  1593. if (!IsDecodingSupportedForInternalFormat(VAProfileJPEGBaseline, rt_format))
  1594. return false;
  1595. // Work around some driver-specific conversion issues. If you add a workaround
  1596. // here, please update the VaapiJpegDecoderTest.MinimalImageFormatSupport
  1597. // test.
  1598. DCHECK_NE(VAImplementation::kInvalid, GetImplementationType());
  1599. if (GetImplementationType() == VAImplementation::kMesaGallium) {
  1600. // The VAAPI mesa state tracker only supports conversion from NV12 to YV12
  1601. // and IYUV (synonym of I420).
  1602. if (rt_format == VA_RT_FORMAT_YUV420) {
  1603. if (preferred_fourcc != VA_FOURCC_I420 &&
  1604. preferred_fourcc != VA_FOURCC_YV12) {
  1605. preferred_fourcc = VA_FOURCC_NV12;
  1606. }
  1607. } else if (rt_format == VA_RT_FORMAT_YUV422) {
  1608. preferred_fourcc = VA_FOURCC('Y', 'U', 'Y', 'V');
  1609. } else {
  1610. // Out of the three internal formats we care about (4:2:0, 4:2:2, and
  1611. // 4:4:4), this driver should only support the first two. Since we check
  1612. // for supported internal formats at the beginning of this function, we
  1613. // shouldn't get here.
  1614. NOTREACHED();
  1615. return false;
  1616. }
  1617. } else if (GetImplementationType() == VAImplementation::kIntelI965) {
  1618. // Workaround deduced from observations in samus and nocturne: we found that
  1619. //
  1620. // - For a 4:2:2 image, the internal format is 422H.
  1621. // - For a 4:2:0 image, the internal format is IMC3.
  1622. // - For a 4:4:4 image, the internal format is 444P.
  1623. //
  1624. // For these internal formats and an image format of either 422H or P010, an
  1625. // intermediate NV12 surface is allocated. Then, a conversion is made from
  1626. // {422H, IMC3, 444P} -> NV12 -> {422H, P010}. Unfortunately, the
  1627. // NV12 -> {422H, P010} conversion is unimplemented in
  1628. // i965_image_pl2_processing(). So, when |preferred_fourcc| is either 422H
  1629. // or P010, we can just fallback to I420.
  1630. //
  1631. if (preferred_fourcc == VA_FOURCC_422H ||
  1632. preferred_fourcc == VA_FOURCC_P010) {
  1633. preferred_fourcc = VA_FOURCC_I420;
  1634. }
  1635. } else if (GetImplementationType() == VAImplementation::kIntelIHD) {
  1636. // (b/159896972): iHD v20.1.1 cannot create Y216 and Y416 images from a
  1637. // decoded JPEG on gen 12. It is also failing to support Y800 format.
  1638. if (preferred_fourcc == VA_FOURCC_Y216 ||
  1639. preferred_fourcc == VA_FOURCC_Y416 ||
  1640. preferred_fourcc == VA_FOURCC_Y800) {
  1641. preferred_fourcc = VA_FOURCC_I420;
  1642. }
  1643. }
  1644. if (!VASupportedImageFormats::Get().IsImageFormatSupported(
  1645. VAImageFormat{.fourcc = preferred_fourcc})) {
  1646. preferred_fourcc = VA_FOURCC_I420;
  1647. }
  1648. // After workarounds, assume the conversion is supported.
  1649. *suitable_fourcc = preferred_fourcc;
  1650. return true;
  1651. }
  1652. // static
  1653. bool VaapiWrapper::IsVppResolutionAllowed(const gfx::Size& size) {
  1654. const VASupportedProfiles::ProfileInfo* profile_info =
  1655. VASupportedProfiles::Get().IsProfileSupported(kVideoProcess,
  1656. VAProfileNone);
  1657. if (!profile_info)
  1658. return false;
  1659. return size.width() >= profile_info->min_resolution.width() &&
  1660. size.width() <= profile_info->max_resolution.width() &&
  1661. size.height() >= profile_info->min_resolution.height() &&
  1662. size.height() <= profile_info->max_resolution.height();
  1663. }
  1664. // static
  1665. bool VaapiWrapper::IsVppFormatSupported(uint32_t va_fourcc) {
  1666. const VASupportedProfiles::ProfileInfo* profile_info =
  1667. VASupportedProfiles::Get().IsProfileSupported(kVideoProcess,
  1668. VAProfileNone);
  1669. if (!profile_info)
  1670. return false;
  1671. return base::Contains(profile_info->pixel_formats, va_fourcc);
  1672. }
  1673. // static
  1674. std::vector<Fourcc> VaapiWrapper::GetVppSupportedFormats() {
  1675. const VASupportedProfiles::ProfileInfo* profile_info =
  1676. VASupportedProfiles::Get().IsProfileSupported(kVideoProcess,
  1677. VAProfileNone);
  1678. if (!profile_info)
  1679. return {};
  1680. std::vector<Fourcc> supported_fourccs;
  1681. for (uint32_t pixel_format : profile_info->pixel_formats) {
  1682. auto fourcc = Fourcc::FromVAFourCC(pixel_format);
  1683. if (!fourcc)
  1684. continue;
  1685. supported_fourccs.push_back(*fourcc);
  1686. }
  1687. return supported_fourccs;
  1688. }
  1689. // static
  1690. bool VaapiWrapper::IsVppSupportedForJpegDecodedSurfaceToFourCC(
  1691. unsigned int rt_format,
  1692. uint32_t fourcc) {
  1693. if (!IsDecodingSupportedForInternalFormat(VAProfileJPEGBaseline, rt_format))
  1694. return false;
  1695. // Workaround: for Mesa VAAPI driver, VPP only supports internal surface
  1696. // format for 4:2:0 JPEG image.
  1697. DCHECK_NE(VAImplementation::kInvalid, GetImplementationType());
  1698. if (GetImplementationType() == VAImplementation::kMesaGallium &&
  1699. rt_format != VA_RT_FORMAT_YUV420) {
  1700. return false;
  1701. }
  1702. return IsVppFormatSupported(fourcc);
  1703. }
  1704. // static
  1705. bool VaapiWrapper::IsJpegEncodeSupported() {
  1706. return VASupportedProfiles::Get().IsProfileSupported(kEncodeConstantBitrate,
  1707. VAProfileJPEGBaseline);
  1708. }
  1709. // static
  1710. bool VaapiWrapper::IsImageFormatSupported(const VAImageFormat& format) {
  1711. return VASupportedImageFormats::Get().IsImageFormatSupported(format);
  1712. }
  1713. // static
  1714. const std::vector<VAImageFormat>&
  1715. VaapiWrapper::GetSupportedImageFormatsForTesting() {
  1716. return VASupportedImageFormats::Get().GetSupportedImageFormats();
  1717. }
  1718. // static
  1719. std::map<VAProfile, std::vector<VAEntrypoint>>
  1720. VaapiWrapper::GetSupportedConfigurationsForCodecModeForTesting(CodecMode mode) {
  1721. std::map<VAProfile, std::vector<VAEntrypoint>> configurations;
  1722. for (const auto& supported_profile :
  1723. VASupportedProfiles::Get().supported_profiles_[mode]) {
  1724. configurations[supported_profile.va_profile].push_back(
  1725. supported_profile.va_entrypoint);
  1726. }
  1727. return configurations;
  1728. }
  1729. // static
  1730. VAEntrypoint VaapiWrapper::GetDefaultVaEntryPoint(CodecMode mode,
  1731. VAProfile profile) {
  1732. switch (mode) {
  1733. case VaapiWrapper::kDecode:
  1734. return VAEntrypointVLD;
  1735. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1736. case VaapiWrapper::kDecodeProtected:
  1737. if (profile == VAProfileProtected)
  1738. return VAEntrypointProtectedContent;
  1739. return VAEntrypointVLD;
  1740. #endif
  1741. case VaapiWrapper::kEncodeConstantBitrate:
  1742. case VaapiWrapper::kEncodeConstantQuantizationParameter:
  1743. case VaapiWrapper::kEncodeVariableBitrate:
  1744. if (profile == VAProfileJPEGBaseline)
  1745. return VAEntrypointEncPicture;
  1746. DCHECK(IsModeEncoding(mode));
  1747. if (IsLowPowerEncSupported(profile))
  1748. return VAEntrypointEncSliceLP;
  1749. return VAEntrypointEncSlice;
  1750. case VaapiWrapper::kVideoProcess:
  1751. return VAEntrypointVideoProc;
  1752. case VaapiWrapper::kCodecModeMax:
  1753. NOTREACHED();
  1754. return VAEntrypointVLD;
  1755. }
  1756. }
  1757. // static
  1758. uint32_t VaapiWrapper::BufferFormatToVARTFormat(gfx::BufferFormat fmt) {
  1759. switch (fmt) {
  1760. case gfx::BufferFormat::BGRX_8888:
  1761. case gfx::BufferFormat::BGRA_8888:
  1762. case gfx::BufferFormat::RGBX_8888:
  1763. case gfx::BufferFormat::RGBA_8888:
  1764. return VA_RT_FORMAT_RGB32;
  1765. case gfx::BufferFormat::YVU_420:
  1766. case gfx::BufferFormat::YUV_420_BIPLANAR:
  1767. return VA_RT_FORMAT_YUV420;
  1768. case gfx::BufferFormat::P010:
  1769. return VA_RT_FORMAT_YUV420_10BPP;
  1770. default:
  1771. NOTREACHED() << gfx::BufferFormatToString(fmt);
  1772. return 0;
  1773. }
  1774. }
  1775. bool VaapiWrapper::CreateContextAndSurfaces(
  1776. unsigned int va_format,
  1777. const gfx::Size& size,
  1778. const std::vector<SurfaceUsageHint>& surface_usage_hints,
  1779. size_t num_surfaces,
  1780. std::vector<VASurfaceID>* va_surfaces) {
  1781. CHECK(!enforce_sequence_affinity_ ||
  1782. sequence_checker_.CalledOnValidSequence());
  1783. DVLOG(2) << "Creating " << num_surfaces << " surfaces";
  1784. DCHECK(va_surfaces->empty());
  1785. if (va_context_id_ != VA_INVALID_ID) {
  1786. LOG(ERROR)
  1787. << "The current context should be destroyed before creating a new one";
  1788. return false;
  1789. }
  1790. if (!CreateSurfaces(va_format, size, surface_usage_hints, num_surfaces,
  1791. va_surfaces)) {
  1792. return false;
  1793. }
  1794. const bool success = CreateContext(size);
  1795. if (!success)
  1796. DestroyContextAndSurfaces(*va_surfaces);
  1797. return success;
  1798. }
  1799. std::vector<std::unique_ptr<ScopedVASurface>>
  1800. VaapiWrapper::CreateContextAndScopedVASurfaces(
  1801. unsigned int va_format,
  1802. const gfx::Size& size,
  1803. const std::vector<SurfaceUsageHint>& usage_hints,
  1804. size_t num_surfaces,
  1805. const absl::optional<gfx::Size>& visible_size) {
  1806. CHECK(!enforce_sequence_affinity_ ||
  1807. sequence_checker_.CalledOnValidSequence());
  1808. if (va_context_id_ != VA_INVALID_ID) {
  1809. LOG(ERROR) << "The current context should be destroyed before creating a "
  1810. "new one";
  1811. return {};
  1812. }
  1813. std::vector<std::unique_ptr<ScopedVASurface>> scoped_va_surfaces =
  1814. CreateScopedVASurfaces(va_format, size, usage_hints, num_surfaces,
  1815. visible_size, /*va_fourcc=*/absl::nullopt);
  1816. if (scoped_va_surfaces.empty())
  1817. return {};
  1818. if (CreateContext(size))
  1819. return scoped_va_surfaces;
  1820. DestroyContext();
  1821. return {};
  1822. }
  1823. bool VaapiWrapper::CreateProtectedSession(
  1824. EncryptionScheme encryption,
  1825. const std::vector<uint8_t>& hw_config,
  1826. std::vector<uint8_t>* hw_identifier_out) {
  1827. CHECK(!enforce_sequence_affinity_ ||
  1828. sequence_checker_.CalledOnValidSequence());
  1829. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1830. DCHECK_EQ(va_protected_config_id_, VA_INVALID_ID);
  1831. DCHECK_EQ(va_protected_session_id_, VA_INVALID_ID);
  1832. DCHECK(hw_identifier_out);
  1833. if (mode_ != kDecodeProtected) {
  1834. LOG(ERROR) << "Cannot attached protected context if not in protected mode";
  1835. return false;
  1836. }
  1837. if (encryption == EncryptionScheme::kUnencrypted) {
  1838. LOG(ERROR) << "Must specify encryption scheme for protected mode";
  1839. return false;
  1840. }
  1841. const VAProfile va_profile = VAProfileProtected;
  1842. const VAEntrypoint entrypoint = GetDefaultVaEntryPoint(mode_, va_profile);
  1843. {
  1844. base::AutoLockMaybe auto_lock(va_lock_.get());
  1845. std::vector<VAConfigAttrib> required_attribs;
  1846. if (!GetRequiredAttribs(va_lock_, va_display_, mode_, va_profile,
  1847. entrypoint, &required_attribs)) {
  1848. LOG(ERROR) << "Failed getting required attributes for protected mode";
  1849. return false;
  1850. }
  1851. DCHECK(!required_attribs.empty());
  1852. // We need to adjust the attribute for encryption scheme.
  1853. for (auto& attrib : required_attribs) {
  1854. if (attrib.type == VAConfigAttribProtectedContentCipherMode) {
  1855. attrib.value = (encryption == EncryptionScheme::kCbcs)
  1856. ? VA_PC_CIPHER_MODE_CBC
  1857. : VA_PC_CIPHER_MODE_CTR;
  1858. }
  1859. }
  1860. VAStatus va_res = vaCreateConfig(
  1861. va_display_, va_profile, entrypoint, &required_attribs[0],
  1862. required_attribs.size(), &va_protected_config_id_);
  1863. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVACreateConfig, false);
  1864. va_res = vaCreateProtectedSession(va_display_, va_protected_config_id_,
  1865. &va_protected_session_id_);
  1866. DCHECK(va_res == VA_STATUS_SUCCESS ||
  1867. va_protected_session_id_ == VA_INVALID_ID);
  1868. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVACreateProtectedSession,
  1869. false);
  1870. }
  1871. // We have to hold the VABuffer outside of the lock because its destructor
  1872. // will acquire the lock when it goes out of scope. We also must do this after
  1873. // we create the protected session.
  1874. VAProtectedSessionExecuteBuffer hw_update_buf;
  1875. std::unique_ptr<ScopedVABuffer> hw_update = CreateVABuffer(
  1876. VAProtectedSessionExecuteBufferType, sizeof(hw_update_buf));
  1877. {
  1878. base::AutoLockMaybe auto_lock(va_lock_.get());
  1879. constexpr size_t kHwIdentifierMaxSize = 64;
  1880. memset(&hw_update_buf, 0, sizeof(hw_update_buf));
  1881. hw_update_buf.function_id = VA_TEE_EXEC_TEE_FUNCID_HW_UPDATE;
  1882. hw_update_buf.input.data_size = hw_config.size();
  1883. hw_update_buf.input.data =
  1884. static_cast<void*>(const_cast<uint8_t*>(hw_config.data()));
  1885. hw_update_buf.output.max_data_size = kHwIdentifierMaxSize;
  1886. hw_identifier_out->resize(kHwIdentifierMaxSize);
  1887. hw_update_buf.output.data = hw_identifier_out->data();
  1888. if (!MapAndCopy_Locked(
  1889. hw_update->id(),
  1890. {hw_update->type(), hw_update->size(), &hw_update_buf})) {
  1891. LOG(ERROR) << "Failed mapping Execute buf";
  1892. return false;
  1893. }
  1894. VAStatus va_res = vaProtectedSessionExecute(
  1895. va_display_, va_protected_session_id_, hw_update->id());
  1896. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAProtectedSessionExecute,
  1897. false);
  1898. ScopedVABufferMapping mapping(va_lock_, va_display_, hw_update->id());
  1899. if (!mapping.IsValid()) {
  1900. LOG(ERROR) << "Failed mapping returned Execute buf";
  1901. return false;
  1902. }
  1903. auto* hw_update_buf_out =
  1904. reinterpret_cast<VAProtectedSessionExecuteBuffer*>(mapping.data());
  1905. if (!hw_update_buf_out->output.data_size) {
  1906. LOG(ERROR) << "Received empty HW identifier";
  1907. return false;
  1908. }
  1909. hw_identifier_out->resize(hw_update_buf_out->output.data_size);
  1910. memcpy(hw_identifier_out->data(), hw_update_buf_out->output.data,
  1911. hw_update_buf_out->output.data_size);
  1912. // If the decoding context is created, attach the protected session.
  1913. // Otherwise this is done in CreateContext when the decoding context is
  1914. // created.
  1915. return MaybeAttachProtectedSession_Locked();
  1916. }
  1917. #else
  1918. NOTIMPLEMENTED() << "Protected content mode not supported";
  1919. return false;
  1920. #endif
  1921. }
  1922. bool VaapiWrapper::IsProtectedSessionDead() {
  1923. CHECK(!enforce_sequence_affinity_ ||
  1924. sequence_checker_.CalledOnValidSequence());
  1925. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1926. return IsProtectedSessionDead(va_protected_session_id_);
  1927. #else
  1928. return false;
  1929. #endif
  1930. }
  1931. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1932. bool VaapiWrapper::IsProtectedSessionDead(
  1933. VAProtectedSessionID va_protected_session_id) {
  1934. CHECK(!enforce_sequence_affinity_ ||
  1935. sequence_checker_.CalledOnValidSequence());
  1936. if (va_protected_session_id == VA_INVALID_ID)
  1937. return false;
  1938. uint8_t alive;
  1939. VAProtectedSessionExecuteBuffer tee_exec_buf = {};
  1940. tee_exec_buf.function_id = VA_TEE_EXEC_TEE_FUNCID_IS_SESSION_ALIVE;
  1941. tee_exec_buf.input.data_size = 0;
  1942. tee_exec_buf.input.data = nullptr;
  1943. tee_exec_buf.output.data_size = sizeof(alive);
  1944. tee_exec_buf.output.data = &alive;
  1945. base::AutoLockMaybe auto_lock(va_lock_.get());
  1946. VABufferID buf_id;
  1947. VAStatus va_res = vaCreateBuffer(
  1948. va_display_, va_protected_session_id, VAProtectedSessionExecuteBufferType,
  1949. sizeof(tee_exec_buf), 1, &tee_exec_buf, &buf_id);
  1950. // Failure here is valid if the protected session has been closed.
  1951. if (va_res != VA_STATUS_SUCCESS)
  1952. return true;
  1953. va_res =
  1954. vaProtectedSessionExecute(va_display_, va_protected_session_id, buf_id);
  1955. vaDestroyBuffer(va_display_, buf_id);
  1956. if (va_res != VA_STATUS_SUCCESS)
  1957. return true;
  1958. return !alive;
  1959. }
  1960. #endif
  1961. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1962. VAProtectedSessionID VaapiWrapper::GetProtectedSessionID() const {
  1963. CHECK(!enforce_sequence_affinity_ ||
  1964. sequence_checker_.CalledOnValidSequence());
  1965. return va_protected_session_id_;
  1966. }
  1967. #endif
  1968. void VaapiWrapper::DestroyProtectedSession() {
  1969. CHECK(!enforce_sequence_affinity_ ||
  1970. sequence_checker_.CalledOnValidSequence());
  1971. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1972. if (va_protected_session_id_ == VA_INVALID_ID)
  1973. return;
  1974. base::AutoLockMaybe auto_lock(va_lock_.get());
  1975. VAStatus va_res =
  1976. vaDestroyProtectedSession(va_display_, va_protected_session_id_);
  1977. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroyProtectedSession);
  1978. va_res = vaDestroyConfig(va_display_, va_protected_config_id_);
  1979. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroyConfig);
  1980. va_protected_session_id_ = VA_INVALID_ID;
  1981. va_protected_config_id_ = VA_INVALID_ID;
  1982. #endif
  1983. }
  1984. void VaapiWrapper::DestroyContextAndSurfaces(
  1985. std::vector<VASurfaceID> va_surfaces) {
  1986. CHECK(!enforce_sequence_affinity_ ||
  1987. sequence_checker_.CalledOnValidSequence());
  1988. DestroyContext();
  1989. DestroySurfaces(va_surfaces);
  1990. }
  1991. bool VaapiWrapper::CreateContext(const gfx::Size& size) {
  1992. CHECK(!enforce_sequence_affinity_ ||
  1993. sequence_checker_.CalledOnValidSequence());
  1994. DVLOG(2) << "Creating context";
  1995. base::AutoLockMaybe auto_lock(va_lock_.get());
  1996. // vaCreateContext() doesn't really need an array of VASurfaceIDs (see
  1997. // https://lists.01.org/pipermail/intel-vaapi-media/2017-July/000052.html and
  1998. // https://github.com/intel/libva/issues/251); pass a dummy list of valid
  1999. // (non-null) IDs until the signature gets updated.
  2000. constexpr VASurfaceID* empty_va_surfaces_ids_pointer = nullptr;
  2001. constexpr size_t empty_va_surfaces_ids_size = 0u;
  2002. // No flag must be set and passing picture size is irrelevant in the case of
  2003. // vpp, just passing 0x0.
  2004. const int flag = mode_ != kVideoProcess ? VA_PROGRESSIVE : 0x0;
  2005. const gfx::Size picture_size = mode_ != kVideoProcess ? size : gfx::Size();
  2006. if (base::FeatureList::IsEnabled(kVaapiEnforceVideoMinMaxResolution) &&
  2007. mode_ != kVideoProcess) {
  2008. const VASupportedProfiles::ProfileInfo* profile_info =
  2009. VASupportedProfiles::Get().IsProfileSupported(mode_, va_profile_,
  2010. va_entrypoint_);
  2011. DCHECK(profile_info);
  2012. const bool is_picture_within_bounds =
  2013. gfx::Rect(picture_size)
  2014. .Contains(gfx::Rect(profile_info->min_resolution)) &&
  2015. gfx::Rect(profile_info->max_resolution)
  2016. .Contains(gfx::Rect(picture_size));
  2017. if (!is_picture_within_bounds) {
  2018. VLOG(2) << "Requested resolution=" << picture_size.ToString()
  2019. << " is not within bounds ["
  2020. << profile_info->min_resolution.ToString() << ", "
  2021. << profile_info->max_resolution.ToString() << "]";
  2022. return false;
  2023. }
  2024. }
  2025. VAStatus va_res = vaCreateContext(
  2026. va_display_, va_config_id_, picture_size.width(), picture_size.height(),
  2027. flag, empty_va_surfaces_ids_pointer, empty_va_surfaces_ids_size,
  2028. &va_context_id_);
  2029. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVACreateContext);
  2030. if (va_res != VA_STATUS_SUCCESS)
  2031. return false;
  2032. // TODO(b/200779101): Remove low resolution i965 condition. This was
  2033. // added to avoid a duplicated frame specific to quality 7 at ~400kbps.
  2034. if (IsModeEncoding(mode_) && IsLowPowerIntelProcessor() &&
  2035. !(GetImplementationType() == VAImplementation::kIntelI965 &&
  2036. picture_size.GetArea() <= gfx::Size(320, 240).GetArea())) {
  2037. MaybeSetLowQualityEncoding_Locked();
  2038. }
  2039. // If we have a protected session already, attach it to this new context.
  2040. return MaybeAttachProtectedSession_Locked();
  2041. }
  2042. scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForPixmap(
  2043. scoped_refptr<gfx::NativePixmap> pixmap,
  2044. bool protected_content) {
  2045. CHECK(!enforce_sequence_affinity_ ||
  2046. sequence_checker_.CalledOnValidSequence());
  2047. const gfx::BufferFormat buffer_format = pixmap->GetBufferFormat();
  2048. if (!BufferFormatToVAFourCC(buffer_format)) {
  2049. LOG(ERROR) << "Failed to get the VA fourcc from the buffer format";
  2050. return nullptr;
  2051. }
  2052. // TODO(b/233894465): use the DRM_PRIME_2 API with the Mesa Gallium driver
  2053. // when AMD supports it.
  2054. // TODO(b/233924862): use the DRM_PRIME_2 API with protected content.
  2055. // TODO(b/233929647): use the DRM_PRIME_2 API with the i965 driver.
  2056. // TODO(b/236746283): remove the kNoModifier check once the modifier is
  2057. // plumbed for JPEG decoding and encoding.
  2058. const bool use_drm_prime_2 =
  2059. GetImplementationType() == VAImplementation::kIntelIHD &&
  2060. !protected_content &&
  2061. pixmap->GetBufferFormatModifier() != gfx::NativePixmapHandle::kNoModifier;
  2062. union {
  2063. VADRMPRIMESurfaceDescriptor descriptor;
  2064. VASurfaceAttribExternalBuffersAndFD va_attrib_extbuf_and_fd;
  2065. };
  2066. if (use_drm_prime_2) {
  2067. if (!FillVADRMPRIMESurfaceDescriptor(*pixmap, descriptor))
  2068. return nullptr;
  2069. } else {
  2070. if (!FillVASurfaceAttribExternalBuffers(*pixmap, va_attrib_extbuf_and_fd))
  2071. return nullptr;
  2072. }
  2073. unsigned int va_format =
  2074. base::strict_cast<unsigned int>(BufferFormatToVARTFormat(buffer_format));
  2075. if (!va_format) {
  2076. LOG(ERROR) << "Failed to get the VA RT format from the buffer format";
  2077. return nullptr;
  2078. }
  2079. if (protected_content) {
  2080. if (GetImplementationType() == VAImplementation::kMesaGallium) {
  2081. va_format |= VA_RT_FORMAT_PROTECTED;
  2082. } else {
  2083. va_attrib_extbuf_and_fd.va_attrib_extbuf.flags =
  2084. VA_SURFACE_EXTBUF_DESC_PROTECTED;
  2085. }
  2086. }
  2087. std::vector<VASurfaceAttrib> va_attribs(2);
  2088. va_attribs[0].type = VASurfaceAttribMemoryType;
  2089. va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
  2090. va_attribs[0].value.type = VAGenericValueTypeInteger;
  2091. va_attribs[0].value.value.i = use_drm_prime_2
  2092. ? VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2
  2093. : VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
  2094. va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
  2095. va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
  2096. va_attribs[1].value.type = VAGenericValueTypePointer;
  2097. va_attribs[1].value.value.p = use_drm_prime_2
  2098. ? static_cast<void*>(&descriptor)
  2099. : &va_attrib_extbuf_and_fd.va_attrib_extbuf;
  2100. const gfx::Size size = pixmap->GetBufferSize();
  2101. VASurfaceID va_surface_id = VA_INVALID_ID;
  2102. {
  2103. base::AutoLockMaybe auto_lock(va_lock_.get());
  2104. VAStatus va_res = vaCreateSurfaces(
  2105. va_display_, va_format, base::checked_cast<unsigned int>(size.width()),
  2106. base::checked_cast<unsigned int>(size.height()), &va_surface_id, 1,
  2107. &va_attribs[0], va_attribs.size());
  2108. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVACreateSurfaces_Importing,
  2109. nullptr);
  2110. }
  2111. DVLOG(3) << __func__ << " " << va_surface_id;
  2112. // VASurface shares an ownership of the buffer referred by the passed file
  2113. // descriptor. We can release |pixmap| here.
  2114. return new VASurface(va_surface_id, size, va_format,
  2115. base::BindOnce(&VaapiWrapper::DestroySurface, this));
  2116. }
  2117. scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForUserPtr(
  2118. const gfx::Size& size,
  2119. uintptr_t* buffers,
  2120. size_t buffer_size) {
  2121. CHECK(!enforce_sequence_affinity_ ||
  2122. sequence_checker_.CalledOnValidSequence());
  2123. VASurfaceAttribExternalBuffers va_attrib_extbuf{};
  2124. va_attrib_extbuf.num_planes = 3;
  2125. va_attrib_extbuf.buffers = buffers;
  2126. va_attrib_extbuf.data_size = base::checked_cast<uint32_t>(buffer_size);
  2127. va_attrib_extbuf.num_buffers = 1u;
  2128. va_attrib_extbuf.width = base::checked_cast<uint32_t>(size.width());
  2129. va_attrib_extbuf.height = base::checked_cast<uint32_t>(size.height());
  2130. va_attrib_extbuf.offsets[0] = 0;
  2131. va_attrib_extbuf.offsets[1] = size.GetCheckedArea().ValueOrDie<uint32_t>();
  2132. va_attrib_extbuf.offsets[2] =
  2133. (size.GetCheckedArea() * 2).ValueOrDie<uint32_t>();
  2134. std::fill(va_attrib_extbuf.pitches, va_attrib_extbuf.pitches + 3,
  2135. base::checked_cast<uint32_t>(size.width()));
  2136. va_attrib_extbuf.pixel_format = VA_FOURCC_RGBP;
  2137. std::vector<VASurfaceAttrib> va_attribs(2);
  2138. va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
  2139. va_attribs[0].type = VASurfaceAttribMemoryType;
  2140. va_attribs[0].value.type = VAGenericValueTypeInteger;
  2141. va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR;
  2142. va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
  2143. va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
  2144. va_attribs[1].value.type = VAGenericValueTypePointer;
  2145. va_attribs[1].value.value.p = &va_attrib_extbuf;
  2146. VASurfaceID va_surface_id = VA_INVALID_ID;
  2147. const unsigned int va_format = VA_RT_FORMAT_RGBP;
  2148. {
  2149. base::AutoLockMaybe auto_lock(va_lock_.get());
  2150. VAStatus va_res = vaCreateSurfaces(
  2151. va_display_, va_format, base::checked_cast<unsigned int>(size.width()),
  2152. base::checked_cast<unsigned int>(size.height()), &va_surface_id, 1,
  2153. &va_attribs[0], va_attribs.size());
  2154. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVACreateSurfaces_Importing,
  2155. nullptr);
  2156. }
  2157. DVLOG(2) << __func__ << " " << va_surface_id;
  2158. return new VASurface(va_surface_id, size, va_format,
  2159. base::BindOnce(&VaapiWrapper::DestroySurface, this));
  2160. }
  2161. scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceWithUsageHints(
  2162. unsigned int va_rt_format,
  2163. const gfx::Size& size,
  2164. const std::vector<SurfaceUsageHint>& usage_hints) {
  2165. CHECK(!enforce_sequence_affinity_ ||
  2166. sequence_checker_.CalledOnValidSequence());
  2167. std::vector<VASurfaceID> surfaces;
  2168. if (!CreateSurfaces(va_rt_format, size, usage_hints, 1, &surfaces))
  2169. return nullptr;
  2170. return new VASurface(surfaces[0], size, va_rt_format,
  2171. base::BindOnce(&VaapiWrapper::DestroySurface, this));
  2172. }
  2173. std::unique_ptr<NativePixmapAndSizeInfo>
  2174. VaapiWrapper::ExportVASurfaceAsNativePixmapDmaBufUnwrapped(
  2175. VASurfaceID va_surface_id,
  2176. const gfx::Size& va_surface_size) {
  2177. CHECK(!enforce_sequence_affinity_ ||
  2178. sequence_checker_.CalledOnValidSequence());
  2179. DCHECK_NE(va_surface_id, VA_INVALID_SURFACE);
  2180. DCHECK(!va_surface_size.IsEmpty());
  2181. VADRMPRIMESurfaceDescriptor descriptor;
  2182. {
  2183. base::AutoLockMaybe auto_lock(va_lock_.get());
  2184. VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
  2185. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, nullptr);
  2186. va_res = vaExportSurfaceHandle(
  2187. va_display_, va_surface_id, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
  2188. VA_EXPORT_SURFACE_READ_ONLY | VA_EXPORT_SURFACE_SEPARATE_LAYERS,
  2189. &descriptor);
  2190. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAExportSurfaceHandle,
  2191. nullptr);
  2192. }
  2193. // We only support one bo containing all the planes. The fd should be owned by
  2194. // us: per va/va.h, "the exported handles are owned by the caller."
  2195. //
  2196. // TODO(crbug.com/974438): support multiple buffer objects so that this can
  2197. // work in AMD.
  2198. if (descriptor.num_objects != 1u) {
  2199. DVLOG(1) << "Only surface descriptors with one bo are supported";
  2200. NOTREACHED();
  2201. return nullptr;
  2202. }
  2203. base::ScopedFD bo_fd(descriptor.objects[0].fd);
  2204. const uint64_t bo_modifier = descriptor.objects[0].drm_format_modifier;
  2205. // Translate the pixel format to a gfx::BufferFormat.
  2206. gfx::BufferFormat buffer_format;
  2207. switch (descriptor.fourcc) {
  2208. case VA_FOURCC_IMC3:
  2209. // IMC3 is like I420 but all the planes have the same stride. This is used
  2210. // for decoding 4:2:0 JPEGs in the Intel i965 driver. We don't currently
  2211. // have a gfx::BufferFormat for YUV420. Instead, we reuse YVU_420 and
  2212. // later swap the U and V planes.
  2213. //
  2214. // TODO(andrescj): revisit this once crrev.com/c/1573718 lands.
  2215. buffer_format = gfx::BufferFormat::YVU_420;
  2216. break;
  2217. case VA_FOURCC_NV12:
  2218. buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
  2219. break;
  2220. default:
  2221. LOG(ERROR) << "Cannot export a surface with FOURCC "
  2222. << FourccToString(descriptor.fourcc);
  2223. return nullptr;
  2224. }
  2225. gfx::NativePixmapHandle handle{};
  2226. handle.modifier = bo_modifier;
  2227. for (uint32_t layer = 0; layer < descriptor.num_layers; layer++) {
  2228. // According to va/va_drmcommon.h, if VA_EXPORT_SURFACE_SEPARATE_LAYERS is
  2229. // specified, each layer should contain one plane.
  2230. DCHECK_EQ(1u, descriptor.layers[layer].num_planes);
  2231. auto plane_fd = base::ScopedFD(
  2232. layer == 0 ? bo_fd.release()
  2233. : HANDLE_EINTR(dup(handle.planes[0].fd.get())));
  2234. PCHECK(plane_fd.is_valid());
  2235. constexpr uint64_t kZeroSizeToPreventMapping = 0u;
  2236. handle.planes.emplace_back(
  2237. base::checked_cast<int>(descriptor.layers[layer].pitch[0]),
  2238. base::checked_cast<int>(descriptor.layers[layer].offset[0]),
  2239. kZeroSizeToPreventMapping, std::move(plane_fd));
  2240. }
  2241. if (descriptor.fourcc == VA_FOURCC_IMC3) {
  2242. // Recall that for VA_FOURCC_IMC3, we will return a format of
  2243. // gfx::BufferFormat::YVU_420, so we need to swap the U and V planes to keep
  2244. // the semantics.
  2245. DCHECK_EQ(3u, handle.planes.size());
  2246. std::swap(handle.planes[1], handle.planes[2]);
  2247. }
  2248. auto exported_pixmap = std::make_unique<NativePixmapAndSizeInfo>();
  2249. exported_pixmap->va_surface_resolution =
  2250. gfx::Size(base::checked_cast<int>(descriptor.width),
  2251. base::checked_cast<int>(descriptor.height));
  2252. exported_pixmap->byte_size =
  2253. base::strict_cast<size_t>(descriptor.objects[0].size);
  2254. if (!gfx::Rect(exported_pixmap->va_surface_resolution)
  2255. .Contains(gfx::Rect(va_surface_size))) {
  2256. LOG(ERROR) << "A " << va_surface_size.ToString()
  2257. << " surface cannot be contained by a "
  2258. << exported_pixmap->va_surface_resolution.ToString()
  2259. << " buffer";
  2260. return nullptr;
  2261. }
  2262. exported_pixmap->pixmap = base::MakeRefCounted<gfx::NativePixmapDmaBuf>(
  2263. va_surface_size, buffer_format, std::move(handle));
  2264. return exported_pixmap;
  2265. }
  2266. std::unique_ptr<NativePixmapAndSizeInfo>
  2267. VaapiWrapper::ExportVASurfaceAsNativePixmapDmaBuf(const VASurface& va_surface) {
  2268. CHECK(!enforce_sequence_affinity_ ||
  2269. sequence_checker_.CalledOnValidSequence());
  2270. if (va_surface.id() == VA_INVALID_SURFACE || va_surface.size().IsEmpty() ||
  2271. va_surface.format() == kInvalidVaRtFormat) {
  2272. LOG(ERROR) << "Cannot export an invalid surface";
  2273. return nullptr;
  2274. }
  2275. return ExportVASurfaceAsNativePixmapDmaBufUnwrapped(va_surface.id(),
  2276. va_surface.size());
  2277. }
  2278. std::unique_ptr<NativePixmapAndSizeInfo>
  2279. VaapiWrapper::ExportVASurfaceAsNativePixmapDmaBuf(
  2280. const ScopedVASurface& scoped_va_surface) {
  2281. CHECK(!enforce_sequence_affinity_ ||
  2282. sequence_checker_.CalledOnValidSequence());
  2283. if (!scoped_va_surface.IsValid()) {
  2284. LOG(ERROR) << "Cannot export an invalid surface";
  2285. return nullptr;
  2286. }
  2287. return ExportVASurfaceAsNativePixmapDmaBufUnwrapped(scoped_va_surface.id(),
  2288. scoped_va_surface.size());
  2289. }
  2290. bool VaapiWrapper::SyncSurface(VASurfaceID va_surface_id) {
  2291. CHECK(!enforce_sequence_affinity_ ||
  2292. sequence_checker_.CalledOnValidSequence());
  2293. DCHECK_NE(va_surface_id, VA_INVALID_ID);
  2294. base::AutoLockMaybe auto_lock(va_lock_.get());
  2295. VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
  2296. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, false);
  2297. return true;
  2298. }
  2299. bool VaapiWrapper::SubmitBuffer(VABufferType va_buffer_type,
  2300. size_t size,
  2301. const void* data) {
  2302. CHECK(!enforce_sequence_affinity_ ||
  2303. sequence_checker_.CalledOnValidSequence());
  2304. TRACE_EVENT0("media,gpu", "VaapiWrapper::SubmitBuffer");
  2305. base::AutoLockMaybe auto_lock(va_lock_.get());
  2306. return SubmitBuffer_Locked({va_buffer_type, size, data});
  2307. }
  2308. bool VaapiWrapper::SubmitBuffers(
  2309. const std::vector<VABufferDescriptor>& va_buffers) {
  2310. CHECK(!enforce_sequence_affinity_ ||
  2311. sequence_checker_.CalledOnValidSequence());
  2312. TRACE_EVENT0("media,gpu", "VaapiWrapper::SubmitBuffers");
  2313. base::AutoLockMaybe auto_lock(va_lock_.get());
  2314. for (const VABufferDescriptor& va_buffer : va_buffers) {
  2315. if (!SubmitBuffer_Locked(va_buffer))
  2316. return false;
  2317. }
  2318. return true;
  2319. }
  2320. void VaapiWrapper::DestroyPendingBuffers() {
  2321. CHECK(!enforce_sequence_affinity_ ||
  2322. sequence_checker_.CalledOnValidSequence());
  2323. TRACE_EVENT0("media,gpu", "VaapiWrapper::DestroyPendingBuffers");
  2324. base::AutoLockMaybe auto_lock(va_lock_.get());
  2325. DestroyPendingBuffers_Locked();
  2326. }
  2327. void VaapiWrapper::DestroyPendingBuffers_Locked() {
  2328. CHECK(!enforce_sequence_affinity_ ||
  2329. sequence_checker_.CalledOnValidSequence());
  2330. TRACE_EVENT0("media,gpu", "VaapiWrapper::DestroyPendingBuffers_Locked");
  2331. MAYBE_ASSERT_ACQUIRED(va_lock_);
  2332. for (const auto& pending_va_buf : pending_va_buffers_) {
  2333. VAStatus va_res = vaDestroyBuffer(va_display_, pending_va_buf);
  2334. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroyBuffer);
  2335. }
  2336. pending_va_buffers_.clear();
  2337. }
  2338. bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) {
  2339. CHECK(!enforce_sequence_affinity_ ||
  2340. sequence_checker_.CalledOnValidSequence());
  2341. base::AutoLockMaybe auto_lock(va_lock_.get());
  2342. bool result = Execute_Locked(va_surface_id, pending_va_buffers_);
  2343. DestroyPendingBuffers_Locked();
  2344. return result;
  2345. }
  2346. bool VaapiWrapper::MapAndCopyAndExecute(
  2347. VASurfaceID va_surface_id,
  2348. const std::vector<std::pair<VABufferID, VABufferDescriptor>>& va_buffers) {
  2349. CHECK(!enforce_sequence_affinity_ ||
  2350. sequence_checker_.CalledOnValidSequence());
  2351. DCHECK_NE(va_surface_id, VA_INVALID_SURFACE);
  2352. TRACE_EVENT0("media,gpu", "VaapiWrapper::MapAndCopyAndExecute");
  2353. base::AutoLockMaybe auto_lock(va_lock_.get());
  2354. std::vector<VABufferID> va_buffer_ids;
  2355. for (const auto& va_buffer : va_buffers) {
  2356. const VABufferID va_buffer_id = va_buffer.first;
  2357. const VABufferDescriptor& descriptor = va_buffer.second;
  2358. DCHECK_NE(va_buffer_id, VA_INVALID_ID);
  2359. if (!MapAndCopy_Locked(va_buffer_id, descriptor))
  2360. return false;
  2361. va_buffer_ids.push_back(va_buffer_id);
  2362. }
  2363. return Execute_Locked(va_surface_id, va_buffer_ids);
  2364. }
  2365. #if BUILDFLAG(USE_VAAPI_X11)
  2366. bool VaapiWrapper::PutSurfaceIntoPixmap(VASurfaceID va_surface_id,
  2367. x11::Pixmap x_pixmap,
  2368. gfx::Size dest_size) {
  2369. CHECK(!enforce_sequence_affinity_ ||
  2370. sequence_checker_.CalledOnValidSequence());
  2371. base::AutoLockMaybe auto_lock(va_lock_.get());
  2372. VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
  2373. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, false);
  2374. // Put the data into an X Pixmap.
  2375. va_res =
  2376. vaPutSurface(va_display_, va_surface_id, static_cast<uint32_t>(x_pixmap),
  2377. 0, 0, dest_size.width(), dest_size.height(), 0, 0,
  2378. dest_size.width(), dest_size.height(), nullptr, 0, 0);
  2379. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAPutSurface, false);
  2380. return true;
  2381. }
  2382. #endif // BUILDFLAG(USE_VAAPI_X11)
  2383. std::unique_ptr<ScopedVAImage> VaapiWrapper::CreateVaImage(
  2384. VASurfaceID va_surface_id,
  2385. VAImageFormat* format,
  2386. const gfx::Size& size) {
  2387. CHECK(!enforce_sequence_affinity_ ||
  2388. sequence_checker_.CalledOnValidSequence());
  2389. std::unique_ptr<ScopedVAImage> scoped_image;
  2390. {
  2391. base::AutoLockMaybe auto_lock(va_lock_.get());
  2392. VAStatus va_res = vaSyncSurface(va_display_, va_surface_id);
  2393. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, nullptr);
  2394. scoped_image = std::make_unique<ScopedVAImage>(va_lock_, va_display_,
  2395. va_surface_id, format, size);
  2396. }
  2397. return scoped_image->IsValid() ? std::move(scoped_image) : nullptr;
  2398. }
  2399. bool VaapiWrapper::UploadVideoFrameToSurface(const VideoFrame& frame,
  2400. VASurfaceID va_surface_id,
  2401. const gfx::Size& va_surface_size) {
  2402. CHECK(!enforce_sequence_affinity_ ||
  2403. sequence_checker_.CalledOnValidSequence());
  2404. TRACE_EVENT0("media,gpu", "VaapiWrapper::UploadVideoFrameToSurface");
  2405. base::AutoLockMaybe auto_lock(va_lock_.get());
  2406. TRACE_EVENT0("media,gpu", "VaapiWrapper::UploadVideoFrameToSurfaceLocked");
  2407. if (frame.visible_rect().origin() != gfx::Point(0, 0)) {
  2408. LOG(ERROR) << "The origin of the frame's visible rectangle is not (0, 0), "
  2409. << "frame.visible_rect().origin()="
  2410. << frame.visible_rect().origin().ToString();
  2411. return false;
  2412. }
  2413. const gfx::Size visible_size = frame.visible_rect().size();
  2414. bool needs_va_put_image = false;
  2415. VAImage image;
  2416. VAStatus va_res = vaDeriveImage(va_display_, va_surface_id, &image);
  2417. if (va_res == VA_STATUS_ERROR_OPERATION_FAILED) {
  2418. DVLOG(4) << "vaDeriveImage failed and fallback to Create_PutImage";
  2419. constexpr VAImageFormat kImageFormatNV12{.fourcc = VA_FOURCC_NV12,
  2420. .byte_order = VA_LSB_FIRST,
  2421. .bits_per_pixel = 12};
  2422. VAImageFormat image_format = kImageFormatNV12;
  2423. va_res = vaCreateImage(va_display_, &image_format, va_surface_size.width(),
  2424. va_surface_size.height(), &image);
  2425. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVACreateImage, false);
  2426. needs_va_put_image = true;
  2427. }
  2428. base::ScopedClosureRunner vaimage_deleter(
  2429. base::BindOnce(&DestroyVAImage, va_display_, image));
  2430. if (image.format.fourcc != VA_FOURCC_NV12) {
  2431. LOG(ERROR) << "Unsupported image format: " << image.format.fourcc;
  2432. return false;
  2433. }
  2434. if (image.width % 2 != 0 || image.height % 2 != 0) {
  2435. LOG(ERROR) << "Buffer's width and height are not even, "
  2436. << "width=" << image.width << ", height=" << image.height;
  2437. return false;
  2438. }
  2439. if (!gfx::Rect(image.width, image.height).Contains(gfx::Rect(visible_size))) {
  2440. LOG(ERROR) << "Buffer too small to fit the frame.";
  2441. return false;
  2442. }
  2443. ScopedVABufferMapping mapping(va_lock_, va_display_, image.buf);
  2444. if (!mapping.IsValid())
  2445. return false;
  2446. uint8_t* image_ptr = static_cast<uint8_t*>(mapping.data());
  2447. if (!ClearNV12Padding(image, visible_size, image_ptr)) {
  2448. LOG(ERROR) << "Failed to clear non visible area of VAImage";
  2449. return false;
  2450. }
  2451. int ret = 0;
  2452. {
  2453. TRACE_EVENT0("media,gpu", "VaapiWrapper::UploadVideoFrameToSurface_copy");
  2454. std::unique_ptr<base::AutoUnlock> auto_unlock;
  2455. if (va_lock_)
  2456. auto_unlock = std::make_unique<base::AutoUnlock>(*va_lock_);
  2457. if (frame.format() == PIXEL_FORMAT_I420) {
  2458. ret = libyuv::I420ToNV12(
  2459. frame.data(VideoFrame::kYPlane), frame.stride(VideoFrame::kYPlane),
  2460. frame.data(VideoFrame::kUPlane), frame.stride(VideoFrame::kUPlane),
  2461. frame.data(VideoFrame::kVPlane), frame.stride(VideoFrame::kVPlane),
  2462. image_ptr + image.offsets[0], image.pitches[0],
  2463. image_ptr + image.offsets[1], image.pitches[1], visible_size.width(),
  2464. visible_size.height());
  2465. } else {
  2466. LOG(ERROR) << "Unsupported pixel format: "
  2467. << VideoPixelFormatToString(frame.format());
  2468. return false;
  2469. }
  2470. }
  2471. if (needs_va_put_image) {
  2472. va_res = vaPutImage(va_display_, va_surface_id, image.image_id, 0, 0,
  2473. visible_size.width(), visible_size.height(), 0, 0,
  2474. visible_size.width(), visible_size.height());
  2475. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAPutImage, false);
  2476. }
  2477. return ret == 0;
  2478. }
  2479. std::unique_ptr<ScopedVABuffer> VaapiWrapper::CreateVABuffer(VABufferType type,
  2480. size_t size) {
  2481. CHECK(!enforce_sequence_affinity_ ||
  2482. sequence_checker_.CalledOnValidSequence());
  2483. TRACE_EVENT0("media,gpu", "VaapiWrapper::CreateVABuffer");
  2484. base::AutoLockMaybe auto_lock(va_lock_.get());
  2485. TRACE_EVENT2("media,gpu", "VaapiWrapper::CreateVABufferLocked", "type", type,
  2486. "size", size);
  2487. #if BUILDFLAG(IS_CHROMEOS_ASH)
  2488. VAContextID context_id = type == VAProtectedSessionExecuteBufferType
  2489. ? va_protected_session_id_
  2490. : va_context_id_;
  2491. #else
  2492. VAContextID context_id = va_context_id_;
  2493. #endif
  2494. if (context_id == VA_INVALID_ID)
  2495. return nullptr;
  2496. return ScopedVABuffer::Create(va_lock_, va_display_, context_id, type, size);
  2497. }
  2498. uint64_t VaapiWrapper::GetEncodedChunkSize(VABufferID buffer_id,
  2499. VASurfaceID sync_surface_id) {
  2500. CHECK(!enforce_sequence_affinity_ ||
  2501. sequence_checker_.CalledOnValidSequence());
  2502. TRACE_EVENT0("media,gpu", "VaapiWrapper::GetEncodedChunkSize");
  2503. base::AutoLockMaybe auto_lock(va_lock_.get());
  2504. TRACE_EVENT0("media,gpu", "VaapiWrapper::GetEncodedChunkSizeLocked");
  2505. // vaSyncSurface() is not necessary on Intel platforms as long as there is a
  2506. // vaMapBuffer() like in ScopedVABufferMapping below.
  2507. // vaSyncSurface() synchronizes all active workloads (potentially many, e.g.
  2508. // for k-SVC encoding). On Intel, we'd rather use the more fine-grained
  2509. // vaMapBuffer() in ScopedVABufferMapping below. see b/184312032.
  2510. if (VaapiWrapper::GetImplementationType() != VAImplementation::kIntelI965 &&
  2511. VaapiWrapper::GetImplementationType() != VAImplementation::kIntelIHD) {
  2512. VAStatus va_res = vaSyncSurface(va_display_, sync_surface_id);
  2513. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, 0u);
  2514. }
  2515. ScopedVABufferMapping mapping(va_lock_, va_display_, buffer_id);
  2516. if (!mapping.IsValid())
  2517. return 0u;
  2518. uint64_t coded_data_size = 0;
  2519. for (auto* buffer_segment =
  2520. reinterpret_cast<VACodedBufferSegment*>(mapping.data());
  2521. buffer_segment; buffer_segment = reinterpret_cast<VACodedBufferSegment*>(
  2522. buffer_segment->next)) {
  2523. coded_data_size += buffer_segment->size;
  2524. }
  2525. return coded_data_size;
  2526. }
  2527. bool VaapiWrapper::DownloadFromVABuffer(
  2528. VABufferID buffer_id,
  2529. absl::optional<VASurfaceID> sync_surface_id,
  2530. uint8_t* target_ptr,
  2531. size_t target_size,
  2532. size_t* coded_data_size) {
  2533. CHECK(!enforce_sequence_affinity_ ||
  2534. sequence_checker_.CalledOnValidSequence());
  2535. DCHECK(target_ptr);
  2536. TRACE_EVENT0("media,gpu", "VaapiWrapper::DownloadFromVABuffer");
  2537. base::AutoLockMaybe auto_lock(va_lock_.get());
  2538. TRACE_EVENT0("media,gpu", "VaapiWrapper::DownloadFromVABufferLocked");
  2539. // vaSyncSurface() is not necessary on Intel platforms as long as there is a
  2540. // vaMapBuffer() like in ScopedVABufferMapping below, see b/184312032.
  2541. // |sync_surface_id| will be nullopt because it has been synced already.
  2542. // vaSyncSurface() is not executed in the case.
  2543. if (sync_surface_id &&
  2544. GetImplementationType() != VAImplementation::kIntelI965 &&
  2545. GetImplementationType() != VAImplementation::kIntelIHD) {
  2546. TRACE_EVENT0("media,gpu", "VaapiWrapper::DownloadFromVABuffer_SyncSurface");
  2547. const VAStatus va_res = vaSyncSurface(va_display_, *sync_surface_id);
  2548. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, false);
  2549. }
  2550. ScopedVABufferMapping mapping(va_lock_, va_display_, buffer_id);
  2551. if (!mapping.IsValid())
  2552. return false;
  2553. auto* buffer_segment =
  2554. reinterpret_cast<VACodedBufferSegment*>(mapping.data());
  2555. // memcpy calls should be fast, unlocking and relocking for unmapping might
  2556. // cause another thread to acquire the lock and we'd have to wait delaying the
  2557. // notification that the encode is done.
  2558. {
  2559. TRACE_EVENT0("media,gpu", "VaapiWrapper::DownloadFromVABuffer_copy");
  2560. *coded_data_size = 0;
  2561. while (buffer_segment) {
  2562. DCHECK(buffer_segment->buf);
  2563. if (buffer_segment->size > target_size) {
  2564. LOG(ERROR) << "Insufficient output buffer size: " << target_size
  2565. << ", the buffer segment size: " << buffer_segment->size;
  2566. break;
  2567. }
  2568. memcpy(target_ptr, buffer_segment->buf, buffer_segment->size);
  2569. target_ptr += buffer_segment->size;
  2570. target_size -= buffer_segment->size;
  2571. *coded_data_size += buffer_segment->size;
  2572. buffer_segment =
  2573. reinterpret_cast<VACodedBufferSegment*>(buffer_segment->next);
  2574. }
  2575. }
  2576. return buffer_segment == nullptr;
  2577. }
  2578. bool VaapiWrapper::GetVAEncMaxNumOfRefFrames(VideoCodecProfile profile,
  2579. size_t* max_ref_frames) {
  2580. CHECK(!enforce_sequence_affinity_ ||
  2581. sequence_checker_.CalledOnValidSequence());
  2582. const VAProfile va_profile =
  2583. ProfileToVAProfile(profile, CodecMode::kEncodeConstantBitrate);
  2584. VAConfigAttrib attrib;
  2585. attrib.type = VAConfigAttribEncMaxRefFrames;
  2586. base::AutoLockMaybe auto_lock(va_lock_.get());
  2587. VAStatus va_res = vaGetConfigAttributes(va_display_, va_profile,
  2588. va_entrypoint_, &attrib, 1);
  2589. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAGetConfigAttributes, false);
  2590. *max_ref_frames = attrib.value;
  2591. return true;
  2592. }
  2593. bool VaapiWrapper::GetSupportedPackedHeaders(VideoCodecProfile profile,
  2594. bool& packed_sps,
  2595. bool& packed_pps,
  2596. bool& packed_slice) {
  2597. CHECK(!enforce_sequence_affinity_ ||
  2598. sequence_checker_.CalledOnValidSequence());
  2599. const VAProfile va_profile =
  2600. ProfileToVAProfile(profile, CodecMode::kEncodeConstantBitrate);
  2601. VAConfigAttrib attrib{};
  2602. attrib.type = VAConfigAttribEncPackedHeaders;
  2603. base::AutoLockMaybe auto_lock(va_lock_.get());
  2604. const VAStatus va_res = vaGetConfigAttributes(va_display_, va_profile,
  2605. va_entrypoint_, &attrib, 1);
  2606. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAGetConfigAttributes, false);
  2607. packed_sps = attrib.value & VA_ENC_PACKED_HEADER_SEQUENCE;
  2608. packed_pps = attrib.value & VA_ENC_PACKED_HEADER_PICTURE;
  2609. packed_slice = attrib.value & VA_ENC_PACKED_HEADER_SLICE;
  2610. return true;
  2611. }
  2612. bool VaapiWrapper::IsRotationSupported() {
  2613. CHECK(!enforce_sequence_affinity_ ||
  2614. sequence_checker_.CalledOnValidSequence());
  2615. base::AutoLockMaybe auto_lock(va_lock_.get());
  2616. VAProcPipelineCaps pipeline_caps;
  2617. memset(&pipeline_caps, 0, sizeof(pipeline_caps));
  2618. VAStatus va_res = vaQueryVideoProcPipelineCaps(va_display_, va_context_id_,
  2619. nullptr, 0, &pipeline_caps);
  2620. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAQueryVideoProcPipelineCaps,
  2621. false);
  2622. if (!pipeline_caps.rotation_flags) {
  2623. DVLOG(2) << "VA-API driver doesn't support any rotation";
  2624. return false;
  2625. }
  2626. return true;
  2627. }
  2628. bool VaapiWrapper::BlitSurface(const VASurface& va_surface_src,
  2629. const VASurface& va_surface_dest,
  2630. absl::optional<gfx::Rect> src_rect,
  2631. absl::optional<gfx::Rect> dest_rect,
  2632. VideoRotation rotation
  2633. #if BUILDFLAG(IS_CHROMEOS_ASH)
  2634. ,
  2635. VAProtectedSessionID va_protected_session_id
  2636. #endif
  2637. ) {
  2638. CHECK(!enforce_sequence_affinity_ ||
  2639. sequence_checker_.CalledOnValidSequence());
  2640. DCHECK_EQ(mode_, kVideoProcess);
  2641. base::AutoLockMaybe auto_lock(va_lock_.get());
  2642. // Create a buffer for VPP if it has not been created.
  2643. if (!va_buffer_for_vpp_) {
  2644. DCHECK_NE(VA_INVALID_ID, va_context_id_);
  2645. va_buffer_for_vpp_ =
  2646. ScopedVABuffer::Create(va_lock_, va_display_, va_context_id_,
  2647. VAProcPipelineParameterBufferType,
  2648. sizeof(VAProcPipelineParameterBuffer));
  2649. if (!va_buffer_for_vpp_)
  2650. return false;
  2651. }
  2652. // Note that since we store pointers to these regions in our mapping below,
  2653. // these may be accessed after the Unmap() below. These must therefore live
  2654. // until the end of the function.
  2655. VARectangle input_region;
  2656. VARectangle output_region;
  2657. {
  2658. ScopedVABufferMapping mapping(va_lock_, va_display_,
  2659. va_buffer_for_vpp_->id());
  2660. if (!mapping.IsValid())
  2661. return false;
  2662. auto* pipeline_param =
  2663. reinterpret_cast<VAProcPipelineParameterBuffer*>(mapping.data());
  2664. memset(pipeline_param, 0, sizeof *pipeline_param);
  2665. if (!src_rect)
  2666. src_rect.emplace(gfx::Rect(va_surface_src.size()));
  2667. if (!dest_rect)
  2668. dest_rect.emplace(gfx::Rect(va_surface_dest.size()));
  2669. input_region.x = src_rect->x();
  2670. input_region.y = src_rect->y();
  2671. input_region.width = src_rect->width();
  2672. input_region.height = src_rect->height();
  2673. pipeline_param->surface_region = &input_region;
  2674. pipeline_param->surface = va_surface_src.id();
  2675. pipeline_param->surface_color_standard = VAProcColorStandardNone;
  2676. output_region.x = dest_rect->x();
  2677. output_region.y = dest_rect->y();
  2678. output_region.width = dest_rect->width();
  2679. output_region.height = dest_rect->height();
  2680. pipeline_param->output_region = &output_region;
  2681. pipeline_param->output_background_color = 0xff000000;
  2682. pipeline_param->output_color_standard = VAProcColorStandardNone;
  2683. pipeline_param->filter_flags = VA_FILTER_SCALING_DEFAULT;
  2684. switch (rotation) {
  2685. case VIDEO_ROTATION_0:
  2686. pipeline_param->rotation_state = VA_ROTATION_NONE;
  2687. break;
  2688. case VIDEO_ROTATION_90:
  2689. pipeline_param->rotation_state = VA_ROTATION_90;
  2690. break;
  2691. case VIDEO_ROTATION_180:
  2692. pipeline_param->rotation_state = VA_ROTATION_180;
  2693. break;
  2694. case VIDEO_ROTATION_270:
  2695. pipeline_param->rotation_state = VA_ROTATION_270;
  2696. break;
  2697. }
  2698. }
  2699. #if BUILDFLAG(IS_CHROMEOS_ASH)
  2700. base::ScopedClosureRunner protected_session_detacher;
  2701. if (va_protected_session_id != VA_INVALID_ID) {
  2702. const VAStatus va_res = vaAttachProtectedSession(
  2703. va_display_, va_context_id_, va_protected_session_id);
  2704. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAAttachProtectedSession,
  2705. false);
  2706. // Note that we use a lambda expression to wrap vaDetachProtectedSession()
  2707. // because the function in |protected_session_detacher| must return void.
  2708. protected_session_detacher.ReplaceClosure(base::BindOnce(
  2709. [](VADisplay va_display, VAContextID va_context_id) {
  2710. vaDetachProtectedSession(va_display, va_context_id);
  2711. },
  2712. va_display_, va_context_id_));
  2713. }
  2714. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  2715. TRACE_EVENT2("media,gpu", "VaapiWrapper::BlitSurface", "src_rect",
  2716. src_rect->ToString(), "dest_rect", dest_rect->ToString());
  2717. VAStatus va_res =
  2718. vaBeginPicture(va_display_, va_context_id_, va_surface_dest.id());
  2719. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVABeginPicture, false);
  2720. VABufferID va_buffer_id = va_buffer_for_vpp_->id();
  2721. va_res = vaRenderPicture(va_display_, va_context_id_, &va_buffer_id, 1);
  2722. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVARenderPicture_Vpp, false);
  2723. va_res = vaEndPicture(va_display_, va_context_id_);
  2724. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAEndPicture, false);
  2725. return true;
  2726. }
  2727. // static
  2728. void VaapiWrapper::PreSandboxInitialization() {
  2729. VADisplayState::PreSandboxInitialization();
  2730. const std::string va_suffix(std::to_string(VA_MAJOR_VERSION + 1));
  2731. StubPathMap paths;
  2732. paths[kModuleVa].push_back(std::string("libva.so.") + va_suffix);
  2733. paths[kModuleVa_drm].push_back(std::string("libva-drm.so.") + va_suffix);
  2734. #if BUILDFLAG(USE_VAAPI_X11)
  2735. paths[kModuleVa_x11].push_back(std::string("libva-x11.so.") + va_suffix);
  2736. #endif
  2737. #if BUILDFLAG(IS_CHROMEOS_ASH)
  2738. paths[kModuleVa_prot].push_back(std::string("libva.so.") + va_suffix);
  2739. #endif
  2740. // InitializeStubs dlopen() VA-API libraries
  2741. // libva.so
  2742. // libva-x11.so (X11)
  2743. // libva-drm.so (X11 and Ozone).
  2744. static bool result = InitializeStubs(paths);
  2745. if (!result) {
  2746. static const char kErrorMsg[] = "Failed to initialize VAAPI libs";
  2747. #if BUILDFLAG(IS_CHROMEOS)
  2748. // When Chrome runs on Linux with target_os="chromeos", do not log error
  2749. // message without VAAPI libraries.
  2750. LOG_IF(ERROR, base::SysInfo::IsRunningOnChromeOS()) << kErrorMsg;
  2751. #else
  2752. DVLOG(1) << kErrorMsg;
  2753. #endif
  2754. }
  2755. // VASupportedProfiles::Get creates VADisplayState and in so doing
  2756. // driver associated libraries are dlopen(), to know:
  2757. // i965_drv_video.so
  2758. // hybrid_drv_video.so (platforms that support it)
  2759. // libcmrt.so (platforms that support it)
  2760. VASupportedProfiles::Get();
  2761. }
  2762. VaapiWrapper::VaapiWrapper(CodecMode mode, bool enforce_sequence_affinity)
  2763. : mode_(mode),
  2764. enforce_sequence_affinity_(enforce_sequence_affinity),
  2765. va_lock_(VADisplayState::Get()->va_lock()),
  2766. va_display_(nullptr),
  2767. va_profile_(VAProfileNone),
  2768. va_entrypoint_(kVAEntrypointInvalid) {}
  2769. VaapiWrapper::~VaapiWrapper() {
  2770. CHECK(!enforce_sequence_affinity_ ||
  2771. sequence_checker_.CalledOnValidSequence());
  2772. // Destroy ScopedVABuffer before VaapiWrappers are destroyed to ensure
  2773. // VADisplay is valid on ScopedVABuffer's destruction.
  2774. va_buffer_for_vpp_.reset();
  2775. DestroyPendingBuffers();
  2776. DestroyContext();
  2777. Deinitialize();
  2778. }
  2779. bool VaapiWrapper::Initialize(VAProfile va_profile,
  2780. EncryptionScheme encryption_scheme) {
  2781. CHECK(!enforce_sequence_affinity_ ||
  2782. sequence_checker_.CalledOnValidSequence());
  2783. #if DCHECK_IS_ON()
  2784. if (mode_ == kEncodeConstantQuantizationParameter) {
  2785. DCHECK_NE(va_profile, VAProfileJPEGBaseline)
  2786. << "JPEG Encoding doesn't support CQP bitrate control";
  2787. }
  2788. if (mode_ == kEncodeVariableBitrate) {
  2789. DCHECK_NE(va_profile, VAProfileJPEGBaseline)
  2790. << "JPEG Encoding doesn't support VBR bitrate control";
  2791. }
  2792. #endif // DCHECK_IS_ON()
  2793. #if BUILDFLAG(IS_CHROMEOS_ASH)
  2794. if (encryption_scheme != EncryptionScheme::kUnencrypted &&
  2795. mode_ != kDecodeProtected) {
  2796. return false;
  2797. }
  2798. #endif
  2799. const VAEntrypoint entrypoint = GetDefaultVaEntryPoint(mode_, va_profile);
  2800. base::AutoLockMaybe auto_lock(va_lock_.get());
  2801. std::vector<VAConfigAttrib> required_attribs;
  2802. if (!GetRequiredAttribs(va_lock_, va_display_, mode_, va_profile, entrypoint,
  2803. &required_attribs)) {
  2804. return false;
  2805. }
  2806. #if BUILDFLAG(IS_CHROMEOS_ASH)
  2807. if (encryption_scheme != EncryptionScheme::kUnencrypted) {
  2808. DCHECK(!required_attribs.empty());
  2809. // We need to adjust the attribute for encryption scheme.
  2810. for (auto& attrib : required_attribs) {
  2811. if (attrib.type == VAConfigAttribEncryption) {
  2812. attrib.value = (encryption_scheme == EncryptionScheme::kCbcs)
  2813. ? VA_ENCRYPTION_TYPE_SUBSAMPLE_CBC
  2814. : VA_ENCRYPTION_TYPE_SUBSAMPLE_CTR;
  2815. }
  2816. }
  2817. }
  2818. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  2819. const VAStatus va_res =
  2820. vaCreateConfig(va_display_, va_profile, entrypoint,
  2821. required_attribs.empty() ? nullptr : &required_attribs[0],
  2822. required_attribs.size(), &va_config_id_);
  2823. va_profile_ = va_profile;
  2824. va_entrypoint_ = entrypoint;
  2825. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVACreateConfig, false);
  2826. return true;
  2827. }
  2828. void VaapiWrapper::Deinitialize() {
  2829. CHECK(!enforce_sequence_affinity_ ||
  2830. sequence_checker_.CalledOnValidSequence());
  2831. {
  2832. base::AutoLockMaybe auto_lock(va_lock_.get());
  2833. #if BUILDFLAG(IS_CHROMEOS_ASH)
  2834. if (va_protected_session_id_ != VA_INVALID_ID) {
  2835. VAStatus va_res =
  2836. vaDestroyProtectedSession(va_display_, va_protected_session_id_);
  2837. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroyProtectedSession);
  2838. va_res = vaDestroyConfig(va_display_, va_protected_config_id_);
  2839. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroyConfig);
  2840. }
  2841. #endif
  2842. if (va_config_id_ != VA_INVALID_ID) {
  2843. const VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_);
  2844. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroyConfig);
  2845. }
  2846. #if BUILDFLAG(IS_CHROMEOS_ASH)
  2847. va_protected_session_id_ = VA_INVALID_ID;
  2848. va_protected_config_id_ = VA_INVALID_ID;
  2849. #endif
  2850. va_config_id_ = VA_INVALID_ID;
  2851. va_display_ = nullptr;
  2852. }
  2853. const VAStatus va_res = VADisplayState::Get()->Deinitialize();
  2854. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVATerminate);
  2855. }
  2856. bool VaapiWrapper::VaInitialize(
  2857. const ReportErrorToUMACB& report_error_to_uma_cb) {
  2858. CHECK(!enforce_sequence_affinity_ ||
  2859. sequence_checker_.CalledOnValidSequence());
  2860. report_error_to_uma_cb_ = report_error_to_uma_cb;
  2861. if (!VADisplayState::Get()->Initialize())
  2862. return false;
  2863. DCHECK(va_lock_);
  2864. if (enforce_sequence_affinity_ &&
  2865. !UseGlobalVaapiLock(VADisplayState::Get()->implementation_type())) {
  2866. va_lock_ = nullptr;
  2867. }
  2868. {
  2869. base::AutoLockMaybe auto_lock(va_lock_.get());
  2870. va_display_ = VADisplayState::Get()->va_display();
  2871. DCHECK(va_display_) << "VADisplayState hasn't been properly Initialize()d";
  2872. }
  2873. return true;
  2874. }
  2875. void VaapiWrapper::DestroyContext() {
  2876. CHECK(!enforce_sequence_affinity_ ||
  2877. sequence_checker_.CalledOnValidSequence());
  2878. base::AutoLockMaybe auto_lock(va_lock_.get());
  2879. DVLOG(2) << "Destroying context";
  2880. if (va_context_id_ != VA_INVALID_ID) {
  2881. #if BUILDFLAG(IS_CHROMEOS_ASH)
  2882. if (va_protected_session_id_ != VA_INVALID_ID) {
  2883. const VAStatus va_res =
  2884. vaDetachProtectedSession(va_display_, va_context_id_);
  2885. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADetachProtectedSession);
  2886. }
  2887. #endif
  2888. const VAStatus va_res = vaDestroyContext(va_display_, va_context_id_);
  2889. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroyContext);
  2890. }
  2891. va_context_id_ = VA_INVALID_ID;
  2892. }
  2893. bool VaapiWrapper::CreateSurfaces(
  2894. unsigned int va_format,
  2895. const gfx::Size& size,
  2896. const std::vector<SurfaceUsageHint>& usage_hints,
  2897. size_t num_surfaces,
  2898. std::vector<VASurfaceID>* va_surfaces) {
  2899. CHECK(!enforce_sequence_affinity_ ||
  2900. sequence_checker_.CalledOnValidSequence());
  2901. DVLOG(2) << "Creating " << num_surfaces << " " << size.ToString()
  2902. << " surfaces";
  2903. DCHECK_NE(va_format, kInvalidVaRtFormat);
  2904. DCHECK(va_surfaces->empty());
  2905. va_surfaces->resize(num_surfaces);
  2906. VASurfaceAttrib attribute;
  2907. memset(&attribute, 0, sizeof(attribute));
  2908. attribute.type = VASurfaceAttribUsageHint;
  2909. attribute.flags = VA_SURFACE_ATTRIB_SETTABLE;
  2910. attribute.value.type = VAGenericValueTypeInteger;
  2911. attribute.value.value.i = 0;
  2912. for (SurfaceUsageHint usage_hint : usage_hints)
  2913. attribute.value.value.i |= static_cast<int32_t>(usage_hint);
  2914. static_assert(std::is_same<decltype(attribute.value.value.i), int32_t>::value,
  2915. "attribute.value.value.i is not int32_t");
  2916. static_assert(std::is_same<std::underlying_type<SurfaceUsageHint>::type,
  2917. int32_t>::value,
  2918. "The underlying type of SurfaceUsageHint is not int32_t");
  2919. VAStatus va_res;
  2920. {
  2921. base::AutoLockMaybe auto_lock(va_lock_.get());
  2922. va_res = vaCreateSurfaces(
  2923. va_display_, va_format, base::checked_cast<unsigned int>(size.width()),
  2924. base::checked_cast<unsigned int>(size.height()), va_surfaces->data(),
  2925. num_surfaces, &attribute, 1u);
  2926. }
  2927. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVACreateSurfaces_Allocating);
  2928. return va_res == VA_STATUS_SUCCESS;
  2929. }
  2930. std::vector<std::unique_ptr<ScopedVASurface>>
  2931. VaapiWrapper::CreateScopedVASurfaces(
  2932. unsigned int va_rt_format,
  2933. const gfx::Size& size,
  2934. const std::vector<SurfaceUsageHint>& usage_hints,
  2935. size_t num_surfaces,
  2936. const absl::optional<gfx::Size>& visible_size,
  2937. const absl::optional<uint32_t>& va_fourcc) {
  2938. CHECK(!enforce_sequence_affinity_ ||
  2939. sequence_checker_.CalledOnValidSequence());
  2940. if (kInvalidVaRtFormat == va_rt_format) {
  2941. LOG(ERROR) << "Invalid VA RT format to CreateScopedVASurface";
  2942. return {};
  2943. }
  2944. if (size.IsEmpty()) {
  2945. LOG(ERROR) << "Invalid visible size input to CreateScopedVASurface";
  2946. return {};
  2947. }
  2948. VASurfaceAttrib attribs[2];
  2949. unsigned int num_attribs = 1;
  2950. memset(attribs, 0, sizeof(attribs));
  2951. attribs[0].type = VASurfaceAttribUsageHint;
  2952. attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
  2953. attribs[0].value.type = VAGenericValueTypeInteger;
  2954. attribs[0].value.value.i = 0;
  2955. for (SurfaceUsageHint usage_hint : usage_hints)
  2956. attribs[0].value.value.i |= static_cast<int32_t>(usage_hint);
  2957. if (va_fourcc) {
  2958. num_attribs += 1;
  2959. attribs[1].type = VASurfaceAttribPixelFormat;
  2960. attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
  2961. attribs[1].value.type = VAGenericValueTypeInteger;
  2962. attribs[1].value.value.i = base::checked_cast<int32_t>(*va_fourcc);
  2963. }
  2964. base::AutoLockMaybe auto_lock(va_lock_.get());
  2965. std::vector<VASurfaceID> va_surface_ids(num_surfaces, VA_INVALID_ID);
  2966. const VAStatus va_res = vaCreateSurfaces(
  2967. va_display_, va_rt_format, base::checked_cast<unsigned int>(size.width()),
  2968. base::checked_cast<unsigned int>(size.height()), va_surface_ids.data(),
  2969. num_surfaces, attribs, num_attribs);
  2970. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVACreateSurfaces_Allocating,
  2971. std::vector<std::unique_ptr<ScopedVASurface>>{});
  2972. DCHECK(!base::Contains(va_surface_ids, VA_INVALID_ID))
  2973. << "Invalid VA surface id after vaCreateSurfaces";
  2974. DCHECK(!visible_size.has_value() || !visible_size->IsEmpty());
  2975. std::vector<std::unique_ptr<ScopedVASurface>> scoped_va_surfaces;
  2976. scoped_va_surfaces.reserve(num_surfaces);
  2977. for (const VASurfaceID va_surface_id : va_surface_ids) {
  2978. auto scoped_va_surface = std::make_unique<ScopedVASurface>(
  2979. this, va_surface_id, visible_size.has_value() ? *visible_size : size,
  2980. va_rt_format);
  2981. DCHECK(scoped_va_surface->IsValid());
  2982. scoped_va_surfaces.push_back(std::move(scoped_va_surface));
  2983. }
  2984. return scoped_va_surfaces;
  2985. }
  2986. void VaapiWrapper::DestroySurfaces(std::vector<VASurfaceID> va_surfaces) {
  2987. CHECK(!enforce_sequence_affinity_ ||
  2988. sequence_checker_.CalledOnValidSequence());
  2989. DVLOG(2) << "Destroying " << va_surfaces.size() << " surfaces";
  2990. // vaDestroySurfaces() makes no guarantees about VA_INVALID_SURFACE.
  2991. base::Erase(va_surfaces, VA_INVALID_SURFACE);
  2992. if (va_surfaces.empty())
  2993. return;
  2994. base::AutoLockMaybe auto_lock(va_lock_.get());
  2995. const VAStatus va_res =
  2996. vaDestroySurfaces(va_display_, va_surfaces.data(), va_surfaces.size());
  2997. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroySurfaces);
  2998. }
  2999. void VaapiWrapper::DestroySurface(VASurfaceID va_surface_id) {
  3000. CHECK(!enforce_sequence_affinity_ ||
  3001. sequence_checker_.CalledOnValidSequence());
  3002. if (va_surface_id == VA_INVALID_SURFACE)
  3003. return;
  3004. DVLOG(3) << __func__ << " " << va_surface_id;
  3005. base::AutoLockMaybe auto_lock(va_lock_.get());
  3006. const VAStatus va_res = vaDestroySurfaces(va_display_, &va_surface_id, 1);
  3007. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVADestroySurfaces);
  3008. }
  3009. bool VaapiWrapper::Execute_Locked(VASurfaceID va_surface_id,
  3010. const std::vector<VABufferID>& va_buffers) {
  3011. CHECK(!enforce_sequence_affinity_ ||
  3012. sequence_checker_.CalledOnValidSequence());
  3013. TRACE_EVENT0("media,gpu", "VaapiWrapper::Execute_Locked");
  3014. MAYBE_ASSERT_ACQUIRED(va_lock_);
  3015. DVLOG(4) << "Pending VA bufs to commit: " << pending_va_buffers_.size();
  3016. DVLOG(4) << "Target VA surface " << va_surface_id;
  3017. const auto decode_start_time = base::TimeTicks::Now();
  3018. // Get ready to execute for given surface.
  3019. VAStatus va_res = vaBeginPicture(va_display_, va_context_id_, va_surface_id);
  3020. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVABeginPicture, false);
  3021. if (!va_buffers.empty()) {
  3022. // vaRenderPicture() needs a non-const pointer, possibly unnecessarily.
  3023. VABufferID* va_buffers_data = const_cast<VABufferID*>(va_buffers.data());
  3024. va_res = vaRenderPicture(va_display_, va_context_id_, va_buffers_data,
  3025. base::checked_cast<int>(va_buffers.size()));
  3026. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVARenderPicture_VABuffers,
  3027. false);
  3028. }
  3029. // Instruct HW codec to start processing the submitted commands. In theory,
  3030. // this shouldn't be blocking, relying on vaSyncSurface() instead, however
  3031. // evidence points to it actually waiting for the job to be done.
  3032. va_res = vaEndPicture(va_display_, va_context_id_);
  3033. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVAEndPicture, false);
  3034. if (IsModeDecoding(mode_) && va_profile_ != VAProfileNone &&
  3035. va_profile_ != VAProfileJPEGBaseline) {
  3036. UMA_HISTOGRAM_TIMES("Media.PlatformVideoDecoding.Decode",
  3037. base::TimeTicks::Now() - decode_start_time);
  3038. }
  3039. return true;
  3040. }
  3041. bool VaapiWrapper::SubmitBuffer_Locked(const VABufferDescriptor& va_buffer) {
  3042. CHECK(!enforce_sequence_affinity_ ||
  3043. sequence_checker_.CalledOnValidSequence());
  3044. TRACE_EVENT0("media,gpu", "VaapiWrapper::SubmitBuffer_Locked");
  3045. MAYBE_ASSERT_ACQUIRED(va_lock_);
  3046. DCHECK(IsValidVABufferType(va_buffer.type));
  3047. base::ScopedClosureRunner pending_buffers_destroyer_on_failure(base::BindOnce(
  3048. &VaapiWrapper::DestroyPendingBuffers_Locked, base::Unretained(this)));
  3049. unsigned int va_buffer_size;
  3050. // We use a null |va_buffer|.data for testing: it signals that we want this
  3051. // SubmitBuffer_Locked() call to fail.
  3052. if (!va_buffer.data || !base::CheckedNumeric<size_t>(va_buffer.size)
  3053. .AssignIfValid(&va_buffer_size)) {
  3054. return false;
  3055. }
  3056. VABufferID buffer_id;
  3057. {
  3058. TRACE_EVENT2("media,gpu",
  3059. "VaapiWrapper::SubmitBuffer_Locked_vaCreateBuffer", "type",
  3060. va_buffer.type, "size", va_buffer_size);
  3061. // The type of |data| in vaCreateBuffer() is void*, though a driver must not
  3062. // change the |data| buffer. We execute const_cast to limit the type
  3063. // mismatch. https://github.com/intel/libva/issues/597
  3064. const VAStatus va_res = vaCreateBuffer(
  3065. va_display_, va_context_id_, va_buffer.type, va_buffer_size, 1,
  3066. const_cast<void*>(va_buffer.data), &buffer_id);
  3067. VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVACreateBuffer, false);
  3068. }
  3069. pending_va_buffers_.push_back(buffer_id);
  3070. pending_buffers_destroyer_on_failure.ReplaceClosure(base::DoNothing());
  3071. return true;
  3072. }
  3073. bool VaapiWrapper::MapAndCopy_Locked(VABufferID va_buffer_id,
  3074. const VABufferDescriptor& va_buffer) {
  3075. CHECK(!enforce_sequence_affinity_ ||
  3076. sequence_checker_.CalledOnValidSequence());
  3077. MAYBE_ASSERT_ACQUIRED(va_lock_);
  3078. DCHECK_NE(va_buffer_id, VA_INVALID_ID);
  3079. DCHECK(IsValidVABufferType(va_buffer.type));
  3080. DCHECK(va_buffer.data);
  3081. ScopedVABufferMapping mapping(
  3082. va_lock_, va_display_, va_buffer_id,
  3083. base::BindOnce(base::IgnoreResult(&vaDestroyBuffer), va_display_));
  3084. if (!mapping.IsValid())
  3085. return false;
  3086. return memcpy(mapping.data(), va_buffer.data, va_buffer.size);
  3087. }
  3088. void VaapiWrapper::MaybeSetLowQualityEncoding_Locked() {
  3089. CHECK(!enforce_sequence_affinity_ ||
  3090. sequence_checker_.CalledOnValidSequence());
  3091. DCHECK(IsModeEncoding(mode_));
  3092. MAYBE_ASSERT_ACQUIRED(va_lock_);
  3093. // Query if encoding quality (VAConfigAttribEncQualityRange) is supported, and
  3094. // if so, use the associated value for lowest quality and power consumption.
  3095. VAConfigAttrib attrib{};
  3096. attrib.type = VAConfigAttribEncQualityRange;
  3097. const VAStatus va_res = vaGetConfigAttributes(va_display_, va_profile_,
  3098. va_entrypoint_, &attrib, 1);
  3099. if (va_res != VA_STATUS_SUCCESS) {
  3100. LOG(ERROR) << "vaGetConfigAttributes failed: " << vaProfileStr(va_profile_);
  3101. return;
  3102. }
  3103. // From libva's va.h: 'A value less than or equal to 1 means that the
  3104. // encoder only has a single "quality setting,"'.
  3105. if (attrib.value == VA_ATTRIB_NOT_SUPPORTED || attrib.value <= 1u)
  3106. return;
  3107. const size_t temp_size = sizeof(VAEncMiscParameterBuffer) +
  3108. sizeof(VAEncMiscParameterBufferQualityLevel);
  3109. std::vector<char> temp(temp_size);
  3110. auto* const va_buffer =
  3111. reinterpret_cast<VAEncMiscParameterBuffer*>(temp.data());
  3112. va_buffer->type = VAEncMiscParameterTypeQualityLevel;
  3113. auto* const enc_quality =
  3114. reinterpret_cast<VAEncMiscParameterBufferQualityLevel*>(va_buffer->data);
  3115. enc_quality->quality_level = attrib.value;
  3116. const bool success =
  3117. SubmitBuffer_Locked({VAEncMiscParameterBufferType, temp_size, va_buffer});
  3118. LOG_IF(ERROR, !success) << "Error setting encoding quality to "
  3119. << enc_quality->quality_level;
  3120. }
  3121. bool VaapiWrapper::MaybeAttachProtectedSession_Locked() {
  3122. CHECK(!enforce_sequence_affinity_ ||
  3123. sequence_checker_.CalledOnValidSequence());
  3124. MAYBE_ASSERT_ACQUIRED(va_lock_);
  3125. if (va_context_id_ == VA_INVALID_ID)
  3126. return true;
  3127. #if BUILDFLAG(IS_CHROMEOS_ASH)
  3128. if (va_protected_session_id_ == VA_INVALID_ID)
  3129. return true;
  3130. VAStatus va_res = vaAttachProtectedSession(va_display_, va_context_id_,
  3131. va_protected_session_id_);
  3132. VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVAAttachProtectedSession);
  3133. return va_res == VA_STATUS_SUCCESS;
  3134. #else
  3135. return true;
  3136. #endif
  3137. }
  3138. } // namespace media