M114 stage 2

This commit is contained in:
Alexander Frick 2023-06-20 19:43:12 -05:00
parent 761e49a23e
commit 53b000e48d
13 changed files with 1061 additions and 299 deletions

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="1 1 190 190"><clipPath id="c"><circle cx="96" cy="96" r="88"/></clipPath><linearGradient id="d" x1="110.87" x2="52.54" y1="164.5" y2="130.33" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".4"/><stop offset=".33" stop-color="#1a237e" stop-opacity="0"/></linearGradient><linearGradient id="e" x1="30.43" x2="86.54" y1="74.4" y2="41.61" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".2"/><stop offset=".66" stop-color="#1a237e" stop-opacity="0"/></linearGradient><linearGradient id="f" x1="118.57" x2="54.58" y1="169.11" y2="131.57" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".2"/><stop offset=".33" stop-color="#1a237e" stop-opacity="0"/></linearGradient><clipPath id="g"><use xlink:href="#R"/></clipPath><linearGradient id="a" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".3"/><stop offset=".66" stop-color="#1a237e" stop-opacity="0"/></linearGradient><linearGradient id="h" x1="121.86" x2="136.55" y1="49.8" y2="114.13" xlink:href="#a"/><linearGradient id="i" x1="121.87" x2="136.29" y1="50.07" y2="113.01" xlink:href="#a"/><clipPath id="j"><use xlink:href="#S"/></clipPath><linearGradient id="k" x1="29.34" x2="81.84" y1="75.02" y2="44.35" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".6"/><stop offset=".66" stop-color="#1a237e" stop-opacity="0"/></linearGradient><linearGradient id="b" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".2"/><stop offset="1" stop-color="#1a237e" stop-opacity="0"/></linearGradient><radialGradient id="l" cx="92.18" cy="55.95" r="84.08" xlink:href="#b"/><clipPath id="n"><path d="M61.36 116L96 56h88V8H21.97v40.34"/></clipPath><linearGradient id="m" x1="8" x2="130.65" y1="104.24" y2="104.24" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f4b400" stop-opacity=".4"/><stop offset=".09" stop-color="#f2a700" stop-opacity=".3"/><stop offset=".22" stop-color="#f19800" stop-opacity=".13"/><stop offset=".33" stop-color="#f09300" stop-opacity="0"/></linearGradient><radialGradient id="o" cx="21.87" cy="48.52" r="78.04" xlink:href="#b"/><radialGradient id="p" cx="95.84" cy="96.14" r="87.87" xlink:href="#b"/><radialGradient id="q" cx="34.29" cy="32.01" r="176.75" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity=".1"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></radialGradient><g clip-path="url(#c)"><use fill="#5e97f6" xlink:href="#R"/><use fill="url(#d)" xlink:href="#R"/><use fill="#3367d6" xlink:href="#T"/><use fill="url(#e)" xlink:href="#T"/><path fill="#1a237e" fill-opacity=".15" d="M62.3 115.65l-39.83-68.3-.58 1 39.54 67.8z"/><use fill="#5e97f6" xlink:href="#R"/><use fill="url(#f)" xlink:href="#R"/><path fill="#1a237e" fill-opacity=".15" d="M129.84 117.33l-.83-.48L90.62 184h1.15l38.1-66.64z"/><g clip-path="url(#g)"><use fill="#a1c2fa" xlink:href="#S"/><use fill="url(#h)" xlink:href="#S"/></g><use fill="#a1c2fa" xlink:href="#S"/><use fill="url(#i)" xlink:href="#S"/><g clip-path="url(#j)"><use fill="#3367d6" xlink:href="#T"/><use fill="url(#k)" xlink:href="#T"/></g><path fill="url(#l)" d="M96 56v20.95L174.4 56z"/><use fill="url(#m)" clip-path="url(#n)" xlink:href="#R"/><path fill="url(#o)" d="M21.97 48.45l57.25 57.24L61.36 116z"/><path fill="url(#p)" d="M91.83 183.9l20.96-78.2 17.86 10.3z"/><circle cx="96" cy="96" r="40" fill="#f5f5f5"/><circle cx="96" cy="96" r="32" fill="#4285f4"/><path fill="#1a237e" fill-opacity=".2" d="M96 55a40 40 0 00-40 40v1a40 40 0 0140-40h88v-1z"/><path fill="#fff" fill-opacity=".1" d="M130.6 116A39.96 39.96 0 0196 136a39.97 39.97 0 01-34.61-20h-.04L8 24.48v1L61.36 117h.04a39.94 39.94 0 0069.21 0h.05v-1z"/><path fill="#1a237e" d="M97 56c-.17 0-.33.02-.5.03a39.98 39.98 0 010 79.94c.17 0 .33.03.5.03a40 40 0 000-80z" opacity=".1"/><path fill="#fff" fill-opacity=".2" d="M131 117.33a39.72 39.72 0 003.5-32.05 39.72 39.72 0 01-3.87 30.69l.02.04-38.87 68h1.16l38.1-66.64zM96 9a88 88 0 0187.99 87.5l.01-.5A88 88 0 008 96v.5A88 88 0 0196 9z"/><path fill="#1a237e" fill-opacity=".15" d="M96 183a88 88 0 0087.99-87.5l.01.5A88 88 0 018 96l.01-.5A88 88 0 0096 183z"/></g><circle cx="96" cy="96" r="88" fill="url(#q)"/><defs><path id="R" d="M8 184h83.77l38.88-38.88V116H61.36L8 24.48z"/><path id="S" d="M96 56l34.65 60-38.88 68H184V56z"/><path id="T" d="M21.97 8v108h39.4L96 56h88V8z"/></defs></svg> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="1 1 190 190" width="512" height="512"><clipPath id="c"><circle cx="96" cy="96" r="88"/></clipPath><linearGradient id="d" x1="110.87" x2="52.54" y1="164.5" y2="130.33" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".4"/><stop offset=".33" stop-color="#1a237e" stop-opacity="0"/></linearGradient><linearGradient id="e" x1="30.43" x2="86.54" y1="74.4" y2="41.61" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".2"/><stop offset=".66" stop-color="#1a237e" stop-opacity="0"/></linearGradient><linearGradient id="f" x1="118.57" x2="54.58" y1="169.11" y2="131.57" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".2"/><stop offset=".33" stop-color="#1a237e" stop-opacity="0"/></linearGradient><clipPath id="g"><use xlink:href="#R"/></clipPath><linearGradient id="a" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".3"/><stop offset=".66" stop-color="#1a237e" stop-opacity="0"/></linearGradient><linearGradient id="h" x1="121.86" x2="136.55" y1="49.8" y2="114.13" xlink:href="#a"/><linearGradient id="i" x1="121.87" x2="136.29" y1="50.07" y2="113.01" xlink:href="#a"/><clipPath id="j"><use xlink:href="#S"/></clipPath><linearGradient id="k" x1="29.34" x2="81.84" y1="75.02" y2="44.35" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".6"/><stop offset=".66" stop-color="#1a237e" stop-opacity="0"/></linearGradient><linearGradient id="b" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1a237e" stop-opacity=".2"/><stop offset="1" stop-color="#1a237e" stop-opacity="0"/></linearGradient><radialGradient id="l" cx="92.18" cy="55.95" r="84.08" xlink:href="#b"/><clipPath id="n"><path d="M61.36 116L96 56h88V8H21.97v40.34"/></clipPath><linearGradient id="m" x1="8" x2="130.65" y1="104.24" y2="104.24" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f4b400" stop-opacity=".4"/><stop offset=".09" stop-color="#f2a700" stop-opacity=".3"/><stop offset=".22" stop-color="#f19800" stop-opacity=".13"/><stop offset=".33" stop-color="#f09300" stop-opacity="0"/></linearGradient><radialGradient id="o" cx="21.87" cy="48.52" r="78.04" xlink:href="#b"/><radialGradient id="p" cx="95.84" cy="96.14" r="87.87" xlink:href="#b"/><radialGradient id="q" cx="34.29" cy="32.01" r="176.75" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity=".1"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></radialGradient><g clip-path="url(#c)"><use fill="#5e97f6" xlink:href="#R"/><use fill="url(#d)" xlink:href="#R"/><use fill="#3367d6" xlink:href="#T"/><use fill="url(#e)" xlink:href="#T"/><path fill="#1a237e" fill-opacity=".15" d="M62.3 115.65l-39.83-68.3-.58 1 39.54 67.8z"/><use fill="#5e97f6" xlink:href="#R"/><use fill="url(#f)" xlink:href="#R"/><path fill="#1a237e" fill-opacity=".15" d="M129.84 117.33l-.83-.48L90.62 184h1.15l38.1-66.64z"/><g clip-path="url(#g)"><use fill="#a1c2fa" xlink:href="#S"/><use fill="url(#h)" xlink:href="#S"/></g><use fill="#a1c2fa" xlink:href="#S"/><use fill="url(#i)" xlink:href="#S"/><g clip-path="url(#j)"><use fill="#3367d6" xlink:href="#T"/><use fill="url(#k)" xlink:href="#T"/></g><path fill="url(#l)" d="M96 56v20.95L174.4 56z"/><use fill="url(#m)" clip-path="url(#n)" xlink:href="#R"/><path fill="url(#o)" d="M21.97 48.45l57.25 57.24L61.36 116z"/><path fill="url(#p)" d="M91.83 183.9l20.96-78.2 17.86 10.3z"/><circle cx="96" cy="96" r="40" fill="#f5f5f5"/><circle cx="96" cy="96" r="32" fill="#4285f4"/><path fill="#1a237e" fill-opacity=".2" d="M96 55a40 40 0 00-40 40v1a40 40 0 0140-40h88v-1z"/><path fill="#fff" fill-opacity=".1" d="M130.6 116A39.96 39.96 0 0196 136a39.97 39.97 0 01-34.61-20h-.04L8 24.48v1L61.36 117h.04a39.94 39.94 0 0069.21 0h.05v-1z"/><path fill="#1a237e" d="M97 56c-.17 0-.33.02-.5.03a39.98 39.98 0 010 79.94c.17 0 .33.03.5.03a40 40 0 000-80z" opacity=".1"/><path fill="#fff" fill-opacity=".2" d="M131 117.33a39.72 39.72 0 003.5-32.05 39.72 39.72 0 01-3.87 30.69l.02.04-38.87 68h1.16l38.1-66.64zM96 9a88 88 0 0187.99 87.5l.01-.5A88 88 0 008 96v.5A88 88 0 0196 9z"/><path fill="#1a237e" fill-opacity=".15" d="M96 183a88 88 0 0087.99-87.5l.01.5A88 88 0 018 96l.01-.5A88 88 0 0096 183z"/></g><circle cx="96" cy="96" r="88" fill="url(#q)"/><defs><path id="R" d="M8 184h83.77l38.88-38.88V116H61.36L8 24.48z"/><path id="S" d="M96 56l34.65 60-38.88 68H184V56z"/><path id="T" d="M21.97 8v108h39.4L96 56h88V8z"/></defs></svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

511
logos/chromium_logo.svg Normal file
View file

@ -0,0 +1,511 @@
<svg version="1.1" id="logo_x5F_chrome_x5F_chromium_x5F_192px_x5F_clr"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 192 192" enable-background="new 0 0 192 192" width="512" height="512" xml:space="preserve">
<g>
<g>
<g>
<defs>
<circle id="SVGID_1_" cx="96" cy="96" r="88"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" overflow="visible"/>
</clipPath>
<g clip-path="url(#SVGID_2_)">
<g>
<image overflow="visible" opacity="0.25" width="147" height="184" xlink:href="data:image/png;base64,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
AABJRU5ErkJggg==" transform="matrix(1 0 0 1 0 16)">
</image>
<polygon fill="#5E97F6" points="8,184 91.77,184 130.65,145.12 130.65,116 61.36,116 8,24.48 "/>
</g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="110.8717" y1="164.4955" x2="52.5384" y2="130.3288">
<stop offset="0" style="stop-color:#1A237E;stop-opacity:0.4"/>
<stop offset="0.33" style="stop-color:#1A237E;stop-opacity:0"/>
</linearGradient>
<polygon fill="url(#SVGID_3_)" points="8,184 91.77,184 130.65,145.12 130.65,116 61.36,116 8,24.48 "/>
</g>
<g clip-path="url(#SVGID_2_)">
<polygon fill="#3367D6" points="21.97,8 21.97,116 61.36,116 96,56 184,56 184,8 "/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="30.4287" y1="74.399" x2="86.5413" y2="41.6095">
<stop offset="0" style="stop-color:#1A237E;stop-opacity:0.2"/>
<stop offset="0.66" style="stop-color:#1A237E;stop-opacity:0"/>
</linearGradient>
<polygon fill="url(#SVGID_4_)" points="21.97,8 21.97,116 61.36,116 96,56 184,56 184,8 "/>
</g>
<polygon clip-path="url(#SVGID_2_)" fill="#1A237E" fill-opacity="0.15" points="62.31,115.65 22.48,47.34 21.9,48.34
61.44,116.14 "/>
<g clip-path="url(#SVGID_2_)">
<polygon fill="#5E97F6" points="8,184 91.77,184 130.65,145.12 130.65,116 61.36,116 8,24.48 "/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="118.568" y1="169.112" x2="54.5757" y2="131.5679">
<stop offset="0" style="stop-color:#1A237E;stop-opacity:0.2"/>
<stop offset="0.33" style="stop-color:#1A237E;stop-opacity:0"/>
</linearGradient>
<polygon fill="url(#SVGID_5_)" points="8,184 91.77,184 130.65,145.12 130.65,116 61.36,116 8,24.48 "/>
</g>
<polygon clip-path="url(#SVGID_2_)" fill="#1A237E" fill-opacity="0.15" points="129.84,117.33 129.01,116.85 90.62,184
91.77,184 129.87,117.36 "/>
<g clip-path="url(#SVGID_2_)">
<defs>
<polygon id="SVGID_6_" points="8,184 91.77,184 130.65,145.12 130.65,116 61.36,116 8,24.48 "/>
</defs>
<clipPath id="SVGID_7_">
<use xlink:href="#SVGID_6_" overflow="visible"/>
</clipPath>
<g clip-path="url(#SVGID_7_)">
<g>
<image overflow="visible" opacity="0.2" width="117" height="152" xlink:href="data:image/png;base64,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
9ZxNLsJBfSUAAAAASUVORK5CYII=" transform="matrix(1 0 0 1 79 48)">
</image>
<polygon fill="#A1C2FA" points="96,56 130.65,116 91.77,184 184,184 184,56 "/>
</g>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="121.8584" y1="49.8038" x2="136.5469" y2="114.1304">
<stop offset="0" style="stop-color:#1A237E;stop-opacity:0.3"/>
<stop offset="0.66" style="stop-color:#1A237E;stop-opacity:0"/>
</linearGradient>
<polygon fill="url(#SVGID_8_)" points="96,56 130.65,116 91.77,184 184,184 184,56 "/>
</g>
</g>
<g clip-path="url(#SVGID_2_)">
<polygon fill="#A1C2FA" points="96,56 130.65,116 91.77,184 184,184 184,56 "/>
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="121.8721" y1="50.0745" x2="136.2861" y2="113.0091">
<stop offset="0" style="stop-color:#1A237E;stop-opacity:0.3"/>
<stop offset="0.66" style="stop-color:#1A237E;stop-opacity:0"/>
</linearGradient>
<polygon fill="url(#SVGID_9_)" points="96,56 130.65,116 91.77,184 184,184 184,56 "/>
</g>
<g clip-path="url(#SVGID_2_)">
<defs>
<polygon id="SVGID_10_" points="96,56 130.65,116 91.77,184 184,184 184,56 "/>
</defs>
<clipPath id="SVGID_11_">
<use xlink:href="#SVGID_10_" overflow="visible"/>
</clipPath>
<g clip-path="url(#SVGID_11_)">
<g>
<image overflow="visible" opacity="0.2" width="187" height="132" xlink:href="data:image/png;base64,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" transform="matrix(1 0 0 1 13 -2)">
</image>
<polygon fill="#3367D6" points="21.97,8 21.97,116 61.36,116 96,56 184,56 184,8 "/>
</g>
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="29.3366" y1="75.0206" x2="81.8366" y2="44.3539">
<stop offset="0" style="stop-color:#1A237E;stop-opacity:0.6"/>
<stop offset="0.66" style="stop-color:#1A237E;stop-opacity:0"/>
</linearGradient>
<polygon fill="url(#SVGID_12_)" points="21.97,8 21.97,116 61.36,116 96,56 184,56 184,8 "/>
</g>
</g>
<radialGradient id="SVGID_13_" cx="668.1758" cy="55.9477" r="84.078" gradientTransform="matrix(1 0 0 1 -576 0)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#1A237E;stop-opacity:0.2"/>
<stop offset="1" style="stop-color:#1A237E;stop-opacity:0"/>
</radialGradient>
<polygon clip-path="url(#SVGID_2_)" fill="url(#SVGID_13_)" points="96,56 96,76.95 174.4,56 "/>
<g clip-path="url(#SVGID_2_)">
<defs>
<polyline id="SVGID_14_" points="61.36,116 96,56 184,56 184,8 21.97,8 21.97,48.34 "/>
</defs>
<clipPath id="SVGID_15_">
<use xlink:href="#SVGID_14_" overflow="visible"/>
</clipPath>
<linearGradient id="SVGID_16_" gradientUnits="userSpaceOnUse" x1="8" y1="104.2421" x2="130.6484" y2="104.2421">
<stop offset="0" style="stop-color:#F4B400;stop-opacity:0.4"/>
<stop offset="0.0863" style="stop-color:#F2A700;stop-opacity:0.2954"/>
<stop offset="0.2188" style="stop-color:#F19800;stop-opacity:0.1348"/>
<stop offset="0.33" style="stop-color:#F09300;stop-opacity:0"/>
</linearGradient>
<polygon clip-path="url(#SVGID_15_)" fill="url(#SVGID_16_)" points="8,184 91.77,184 130.65,145.12 130.65,116 61.36,116
8,24.48 "/>
</g>
<radialGradient id="SVGID_17_" cx="597.8745" cy="48.5197" r="78.0437" gradientTransform="matrix(1 0 0 1 -576 0)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#1A237E;stop-opacity:0.2"/>
<stop offset="1" style="stop-color:#1A237E;stop-opacity:0"/>
</radialGradient>
<polygon clip-path="url(#SVGID_2_)" fill="url(#SVGID_17_)" points="21.97,48.45 79.22,105.69 61.36,116 "/>
<radialGradient id="SVGID_18_" cx="671.8437" cy="96.1384" r="87.8699" gradientTransform="matrix(1 0 0 1 -576 0)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#1A237E;stop-opacity:0.2"/>
<stop offset="1" style="stop-color:#1A237E;stop-opacity:0"/>
</radialGradient>
<polygon clip-path="url(#SVGID_2_)" fill="url(#SVGID_18_)" points="91.83,183.89 112.79,105.69 130.65,116 "/>
<g clip-path="url(#SVGID_2_)">
<g>
<circle fill="#F5F5F5" cx="96" cy="96" r="40"/>
</g>
<g>
<circle fill="#4285F4" cx="96" cy="96" r="32"/>
</g>
</g>
<g clip-path="url(#SVGID_2_)">
<path fill="#1A237E" fill-opacity="0.2" d="M96,55c-22.09,0-40,17.91-40,40v1c0-22.09,17.91-40,40-40h88v-1H96z"/>
<path fill="#FFFFFF" fill-opacity="0.1" d="M130.6,116c-6.92,11.94-19.81,20-34.6,20c-14.8,0-27.69-8.06-34.61-20h-0.04L8,24.48
v1L61.36,117h0.04c6.92,11.94,19.81,20,34.61,20c14.79,0,27.68-8.05,34.6-20h0.05v-1H130.6z"/>
<g>
<g>
<path opacity="0.1" fill="#1A237E" d="M97,56c-0.17,0-0.33,0.02-0.5,0.03C118.36,56.3,136,74.08,136,96
s-17.64,39.7-39.5,39.97c0.17,0,0.33,0.03,0.5,0.03c22.09,0,40-17.91,40-40S119.09,56,97,56z"/>
</g>
<path fill="#FFFFFF" fill-opacity="0.2" d="M131,117.33c3.4-5.88,5.37-12.68,5.37-19.96c0-4.22-0.66-8.28-1.87-12.09
c0.95,3.42,1.5,7.01,1.5,10.73c0,7.28-1.97,14.08-5.37,19.96l0.02,0.04l-38.87,68h1.16l38.09-66.64L131,117.33z"/>
</g>
</g>
<g clip-path="url(#SVGID_2_)">
<path fill="#FFFFFF" fill-opacity="0.2" d="M96,9c48.43,0,87.72,39.13,87.99,87.5c0-0.17,0.01-0.33,0.01-0.5
c0-48.6-39.4-88-88-88S8,47.4,8,96c0,0.17,0.01,0.33,0.01,0.5C8.28,48.13,47.57,9,96,9z"/>
<path fill="#1A237E" fill-opacity="0.15" d="M96,183c48.43,0,87.72-39.13,87.99-87.5c0,0.17,0.01,0.33,0.01,0.5
c0,48.6-39.4,88-88,88S8,144.6,8,96c0-0.17,0.01-0.33,0.01-0.5C8.28,143.87,47.57,183,96,183z"/>
</g>
</g>
<rect x="0" fill="none" width="192" height="192"/>
</g>
<radialGradient id="SVGID_19_" cx="34.2861" cy="32.0137" r="176.7461" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.1"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
</radialGradient>
<circle fill="url(#SVGID_19_)" cx="96" cy="96" r="88"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 36 KiB

View file

@ -248,6 +248,10 @@ void AddHardwareSecureWidevine(std::vector<content::CdmInfo>* cdms) {
switches::kLacrosEnablePlatformHevc)) { switches::kLacrosEnablePlatformHevc)) {
capability.video_codecs.emplace(media::VideoCodec::kHEVC, kAllProfiles); capability.video_codecs.emplace(media::VideoCodec::kHEVC, kAllProfiles);
} }
#elif BUILDFLAG(IS_CHROMEOS_ASH)
if (base::FeatureList::IsEnabled(media::kPlatformHEVCDecoderSupport)) {
capability.video_codecs.emplace(media::VideoCodec::kHEVC, kAllProfiles);
}
#else #else
capability.video_codecs.emplace(media::VideoCodec::kHEVC, kAllProfiles); capability.video_codecs.emplace(media::VideoCodec::kHEVC, kAllProfiles);
#endif // BUILDFLAG(IS_CHROMEOS_LACROS) #endif // BUILDFLAG(IS_CHROMEOS_LACROS)

View file

@ -285,9 +285,6 @@ if (!is_android && !is_mac) {
# Chromium functionality directly into the executable. # Chromium functionality directly into the executable.
":dependencies", ":dependencies",
# For configuring PartitionAlloc
"//base/allocator:buildflags",
# For the sampling profiler. # For the sampling profiler.
"//chrome/common/profiler", "//chrome/common/profiler",
@ -433,7 +430,6 @@ if (is_win) {
":chrome_dll_manifest", ":chrome_dll_manifest",
":chrome_dll_version", ":chrome_dll_version",
":dependencies", ":dependencies",
"//base/allocator:buildflags",
"//chrome/app:chrome_dll_resources", "//chrome/app:chrome_dll_resources",
"//chrome/app:command_ids", "//chrome/app:command_ids",
"//chrome/app/theme:chrome_unscaled_resources", "//chrome/app/theme:chrome_unscaled_resources",
@ -947,6 +943,8 @@ if (is_win) {
bundle_data("chrome_framework_resources") { bundle_data("chrome_framework_resources") {
sources = [ sources = [
"//ui/gl/resources/angle-metal/gpu_shader_cache.bin",
# This image is used to badge the lock icon in the # This image is used to badge the lock icon in the
# authentication dialogs, such as those used for installation # authentication dialogs, such as those used for installation
# from disk image and Keystone promotion (if so enabled). It # from disk image and Keystone promotion (if so enabled). It
@ -1161,7 +1159,6 @@ if (is_win) {
deps = [ deps = [
":dependencies", ":dependencies",
"//base/allocator:buildflags",
"//build:chromeos_buildflags", "//build:chromeos_buildflags",
"//chrome/app:command_ids", "//chrome/app:command_ids",
"//chrome/app:notification_metrics", "//chrome/app:notification_metrics",
@ -1428,6 +1425,7 @@ group("dependencies") {
"//build:branding_buildflags", "//build:branding_buildflags",
"//build:chromeos_buildflags", "//build:chromeos_buildflags",
"//chrome/browser", "//chrome/browser",
"//chrome/browser:buildflags",
"//chrome/browser/policy:path_parser", "//chrome/browser/policy:path_parser",
"//chrome/child", "//chrome/child",
"//chrome/common", "//chrome/common",

View file

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2023 Alex313031. -->
<!-- This grd file contains images that are pre-scaled for device scale <!-- This grd file contains images that are pre-scaled for device scale
factors. The image returned by ui::ResourceBundle::GetImageNamed() factors. The image returned by ui::ResourceBundle::GetImageNamed()
will contain multiple gfx:ImageSkiaReps for each scale factors. The will contain multiple gfx:ImageSkiaReps for each scale factors. The
@ -9,7 +10,6 @@
currently set to true for all resources, but the default will currently set to true for all resources, but the default will
become false in near future. become false in near future.
--> -->
<!-- Copyright (c) 2023 Alex313031. -->
<grit latest_public_release="0" current_release="1" output_all_resource_defines="false"> <grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
<outputs> <outputs>
<output filename="grit/theme_resources.h" type="rc_header" context="default_100_percent"> <output filename="grit/theme_resources.h" type="rc_header" context="default_100_percent">
@ -275,6 +275,8 @@
<structure type="chrome_scaled_image" name="IDR_SAVE_CARD_DARK" file="common/save_card_dark.png" /> <structure type="chrome_scaled_image" name="IDR_SAVE_CARD_DARK" file="common/save_card_dark.png" />
<structure type="chrome_scaled_image" name="IDR_SAVE_CARD_SECURELY_DARK" file="common/save_card_securely_dark.png" /> <structure type="chrome_scaled_image" name="IDR_SAVE_CARD_SECURELY_DARK" file="common/save_card_securely_dark.png" />
<structure type="chrome_scaled_image" name="IDR_SAVE_CARD_SECURELY" file="common/save_card_securely.png" /> <structure type="chrome_scaled_image" name="IDR_SAVE_CARD_SECURELY" file="common/save_card_securely.png" />
<structure type="chrome_scaled_image" name="IDR_MIGRATE_ADDRESS_AVATAR50_X135_Y54" file="common/migrate_address_avatar50_x135_y54.png" />
<structure type="chrome_scaled_image" name="IDR_MIGRATE_ADDRESS_AVATAR50_X135_Y54_DARK" file="common/migrate_address_avatar50_x135_y54_dark.png" />
<structure type="chrome_scaled_image" name="IDR_PRIVACY_SANDBOX_CONFIRMATION_BANNER" file="common/privacy_sandbox_confirmation_banner.png" /> <structure type="chrome_scaled_image" name="IDR_PRIVACY_SANDBOX_CONFIRMATION_BANNER" file="common/privacy_sandbox_confirmation_banner.png" />
<structure type="chrome_scaled_image" name="IDR_PRIVACY_SANDBOX_CONFIRMATION_BANNER_DARK" file="common/privacy_sandbox_confirmation_banner_dark.png" /> <structure type="chrome_scaled_image" name="IDR_PRIVACY_SANDBOX_CONFIRMATION_BANNER_DARK" file="common/privacy_sandbox_confirmation_banner_dark.png" />
</if> </if>

View file

@ -248,6 +248,10 @@ void AddHardwareSecureWidevine(std::vector<content::CdmInfo>* cdms) {
switches::kLacrosEnablePlatformHevc)) { switches::kLacrosEnablePlatformHevc)) {
capability.video_codecs.emplace(media::VideoCodec::kHEVC, kAllProfiles); capability.video_codecs.emplace(media::VideoCodec::kHEVC, kAllProfiles);
} }
#elif BUILDFLAG(IS_CHROMEOS_ASH)
if (base::FeatureList::IsEnabled(media::kPlatformHEVCDecoderSupport)) {
capability.video_codecs.emplace(media::VideoCodec::kHEVC, kAllProfiles);
}
#else #else
capability.video_codecs.emplace(media::VideoCodec::kHEVC, kAllProfiles); capability.video_codecs.emplace(media::VideoCodec::kHEVC, kAllProfiles);
#endif // BUILDFLAG(IS_CHROMEOS_LACROS) #endif // BUILDFLAG(IS_CHROMEOS_LACROS)

View file

@ -65,6 +65,7 @@ about:version template page
</if> </if>
<div id="company"><a target="_blank" rel="noopener" href="https://github.com/Alex313031/Thorium">$i18n{company}</a></div> <div id="company"><a target="_blank" rel="noopener" href="https://github.com/Alex313031/Thorium">$i18n{company}</a></div>
<div id="copyright">$i18n{copyright}</div> <div id="copyright">$i18n{copyright}</div>
<br/>
<!-- Thorium Mascot. --> <!-- Thorium Mascot. -->
<picture title="Thorium Mascot"> <picture title="Thorium Mascot">
<source srcset="chrome://theme/IDR_PRODUCT_MASCOT, <source srcset="chrome://theme/IDR_PRODUCT_MASCOT,

View file

@ -77,6 +77,8 @@ target(link_target_type, "gpu_sources") {
"//services/service_manager/public/mojom", "//services/service_manager/public/mojom",
"//services/tracing/public/cpp", "//services/tracing/public/cpp",
"//services/viz/privileged/mojom", "//services/viz/privileged/mojom",
"//services/webnn",
"//services/webnn/public/mojom",
"//skia", "//skia",
"//third_party/angle:angle_gpu_info_util", "//third_party/angle:angle_gpu_info_util",
"//ui/gfx/ipc", "//ui/gfx/ipc",
@ -145,6 +147,5 @@ target(link_target_type, "gpu_sources") {
if (is_linux && use_vaapi) { if (is_linux && use_vaapi) {
public_configs = [ "//build/config/linux/libva" ] public_configs = [ "//build/config/linux/libva" ]
configs += [ "//build/config/linux/libva" ]
} }
} }

View file

@ -7,9 +7,12 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h" #include "build/chromeos_buildflags.h"
#include "components/system_media_controls/linux/buildflags/buildflags.h" #include "components/system_media_controls/linux/buildflags/buildflags.h"
#include "gpu/config/gpu_finch_features.h"
#include "media/media_buildflags.h" #include "media/media_buildflags.h"
#if BUILDFLAG(IS_LINUX) #if BUILDFLAG(IS_LINUX)
@ -96,9 +99,6 @@ const char kForceProtectedVideoOutputBuffers[] =
const char kDisableAudioInput[] = "disable-audio-input"; const char kDisableAudioInput[] = "disable-audio-input";
// Present video content as overlays.
const char kUseOverlaysForVideo[] = "use-overlays-for-video";
// Minimum size for buffer size used for output video frames in // Minimum size for buffer size used for output video frames in
// FuchsiaVideoDecoder. May be set to avoid re-allocating video buffers when an // FuchsiaVideoDecoder. May be set to avoid re-allocating video buffers when an
// application upgrades video resolution mid-stream. // application upgrades video resolution mid-stream.
@ -295,6 +295,16 @@ const char kDisableUseMojoVideoDecoderForPepper[] =
namespace media { namespace media {
// Enables customized AudioRendererAlgorithmParameters.
BASE_FEATURE(kAudioRendererAlgorithmParameters,
"AudioRendererAlgorithmParameters",
base::FEATURE_DISABLED_BY_DEFAULT);
const base::FeatureParam<base::TimeDelta>
kAudioRendererAlgorithmStartingCapacityForEncrypted{
&kAudioRendererAlgorithmParameters, "starting_capacity_for_encrypted",
base::Milliseconds(500)};
// Prefer FFmpeg to LibVPX for Vp8 decoding with opaque alpha mode. // Prefer FFmpeg to LibVPX for Vp8 decoding with opaque alpha mode.
BASE_FEATURE(kFFmpegDecodeOpaqueVP8, BASE_FEATURE(kFFmpegDecodeOpaqueVP8,
"FFmpegDecodeOpaqueVP8", "FFmpegDecodeOpaqueVP8",
@ -526,6 +536,12 @@ BASE_FEATURE(kUseMultiPlaneFormatForHardwareVideo,
"UseMultiPlaneFormatForHardwareVideo", "UseMultiPlaneFormatForHardwareVideo",
base::FEATURE_DISABLED_BY_DEFAULT); base::FEATURE_DISABLED_BY_DEFAULT);
// Enables creating single shared image and mailbox for multi-planar formats for
// software video decoders.
BASE_FEATURE(kUseMultiPlaneFormatForSoftwareVideo,
"UseMultiPlaneFormatForSoftwareVideo",
base::FEATURE_DISABLED_BY_DEFAULT);
// Enables binding software video NV12/P010 GMBs as separate shared images. // Enables binding software video NV12/P010 GMBs as separate shared images.
BASE_FEATURE(kMultiPlaneSoftwareVideoSharedImages, BASE_FEATURE(kMultiPlaneSoftwareVideoSharedImages,
"MultiPlaneSoftwareVideoSharedImages", "MultiPlaneSoftwareVideoSharedImages",
@ -557,7 +573,7 @@ BASE_FEATURE(kOpenscreenCastStreamingSession,
// information on the quality of the session using RTCP logs. // information on the quality of the session using RTCP logs.
BASE_FEATURE(kEnableRtcpReporting, BASE_FEATURE(kEnableRtcpReporting,
"EnableRtcpReporting", "EnableRtcpReporting",
base::FEATURE_ENABLED_BY_DEFAULT); base::FEATURE_DISABLED_BY_DEFAULT);
// Approach original pre-REC MSE object URL autorevoking behavior, though await // Approach original pre-REC MSE object URL autorevoking behavior, though await
// actual attempt to use the object URL for attachment to perform revocation. // actual attempt to use the object URL for attachment to perform revocation.
@ -703,9 +719,10 @@ BASE_FEATURE(kVaapiVideoDecodeLinux,
"VaapiVideoDecoder", "VaapiVideoDecoder",
base::FEATURE_ENABLED_BY_DEFAULT); base::FEATURE_ENABLED_BY_DEFAULT);
// Temporary fix TODO: Alex313031
BASE_FEATURE(kVaapiVideoDecodeLinuxGL, BASE_FEATURE(kVaapiVideoDecodeLinuxGL,
"VaapiVideoDecodeLinuxGL", "VaapiVideoDecodeLinuxGL",
base::FEATURE_ENABLED_BY_DEFAULT); base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kVaapiVideoEncodeLinux, BASE_FEATURE(kVaapiVideoEncodeLinux,
"VaapiVideoEncoder", "VaapiVideoEncoder",
@ -748,6 +765,11 @@ BASE_FEATURE(kVaapiVP9Encoder,
"VaapiVP9Encoder", "VaapiVP9Encoder",
base::FEATURE_ENABLED_BY_DEFAULT); base::FEATURE_ENABLED_BY_DEFAULT);
// Enable VA-API hardware encode acceleration for AV1.
BASE_FEATURE(kVaapiAV1Encoder,
"VaapiAV1Encoder",
base::FEATURE_ENABLED_BY_DEFAULT);
// Enable global VA-API lock. Disable this to use lock-free VA-API function // Enable global VA-API lock. Disable this to use lock-free VA-API function
// calls for thread safe backends. // calls for thread safe backends.
BASE_FEATURE(kGlobalVaapiLock, BASE_FEATURE(kGlobalVaapiLock,
@ -1106,7 +1128,7 @@ BASE_FEATURE(kIncludeIRCamerasInDeviceEnumeration,
// Enables software rate controller encoding acceleration for Windows. // Enables software rate controller encoding acceleration for Windows.
const base::Feature MEDIA_EXPORT kMediaFoundationUseSoftwareRateCtrl{ const base::Feature MEDIA_EXPORT kMediaFoundationUseSoftwareRateCtrl{
"MediaFoundationUseSoftwareRateCtrl", base::FEATURE_DISABLED_BY_DEFAULT}; "MediaFoundationUseSoftwareRateCtrl", base::FEATURE_ENABLED_BY_DEFAULT};
// Enables MediaFoundation based video capture // Enables MediaFoundation based video capture
BASE_FEATURE(kMediaFoundationVideoCapture, BASE_FEATURE(kMediaFoundationVideoCapture,
@ -1218,12 +1240,20 @@ BASE_FEATURE(kAllowClearDolbyVisionInMseWhenPlatformEncryptedDvEnabled,
base::FEATURE_ENABLED_BY_DEFAULT); base::FEATURE_ENABLED_BY_DEFAULT);
#endif #endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_CHROMEOS_ASH)
// Expose the out-of-process video decoding feature from ash-chrome to
// lacros-chrome through the crosapi.
const base::Feature MEDIA_EXPORT kExposeOutOfProcessVideoDecodingToLacros{
"ExposeOutOfProcessVideoDecodingToLacros",
base::FEATURE_ENABLED_BY_DEFAULT};
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
// Spawn utility processes to perform hardware decode acceleration instead of // Spawn utility processes to perform hardware decode acceleration instead of
// using the GPU process. // using the GPU process.
const base::Feature MEDIA_EXPORT kUseOutOfProcessVideoDecoding{ const base::Feature MEDIA_EXPORT kUseOutOfProcessVideoDecoding{
"UseOutOfProcessVideoDecoding", base::FEATURE_DISABLED_BY_DEFAULT}; "UseOutOfProcessVideoDecoding", base::FEATURE_DISABLED_BY_DEFAULT};
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #endif // BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// Spawn utility processes to perform hardware encode acceleration instead of // Spawn utility processes to perform hardware encode acceleration instead of
@ -1244,6 +1274,9 @@ BASE_FEATURE(kUseSequencedTaskRunnerForMediaService,
"UseSequencedTaskRunnerForMediaService", "UseSequencedTaskRunnerForMediaService",
base::FEATURE_DISABLED_BY_DEFAULT); base::FEATURE_DISABLED_BY_DEFAULT);
// SequencedTaskRunner isn't supported on Windows since the accelerator requires
// a COM STA TaskRunner.
#if !BUILDFLAG(IS_WIN)
// Use SequencedTaskRunner for MojoVideoEncodeAcceleratorProvider. // Use SequencedTaskRunner for MojoVideoEncodeAcceleratorProvider.
BASE_FEATURE(kUseSequencedTaskRunnerForMojoVEAProvider, BASE_FEATURE(kUseSequencedTaskRunnerForMojoVEAProvider,
"UseSequencedTaskRunnerForMojoVEAProvider", "UseSequencedTaskRunnerForMojoVEAProvider",
@ -1253,12 +1286,13 @@ BASE_FEATURE(kUseSequencedTaskRunnerForMojoVEAProvider,
base::FEATURE_DISABLED_BY_DEFAULT base::FEATURE_DISABLED_BY_DEFAULT
#endif #endif
); );
#endif // !BUILDFLAG(IS_WIN)
// Use SequencedTaskRunner for each MojoVideoEncodeAcceleratorService. Replaces // Use TaskRunner for each MojoVideoEncodeAcceleratorService. Replaces
// per-accelerator encoding task runner. // per-accelerator encoding task runner.
BASE_FEATURE(kUseSequencedTaskRunnerForMojoVEAService, BASE_FEATURE(kUseTaskRunnerForMojoVEAService,
"UseSequencedTaskRunnerForMojoVEAService", "UseTaskRunnerForMojoVEAService",
#if BUILDFLAG(IS_APPLE) #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN)
base::FEATURE_ENABLED_BY_DEFAULT base::FEATURE_ENABLED_BY_DEFAULT
#else #else
base::FEATURE_DISABLED_BY_DEFAULT base::FEATURE_DISABLED_BY_DEFAULT
@ -1480,12 +1514,32 @@ bool IsVideoCaptureAcceleratedJpegDecodingEnabled() {
#endif #endif
} }
bool IsMultiPlaneFormatForHardwareVideoEnabled() {
return base::FeatureList::IsEnabled(features::kPassthroughYuvRgbConversion) &&
base::FeatureList::IsEnabled(kUseMultiPlaneFormatForHardwareVideo);
}
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
bool IsMediaFoundationD3D11VideoCaptureEnabled() { bool IsMediaFoundationD3D11VideoCaptureEnabled() {
return base::FeatureList::IsEnabled(kMediaFoundationD3D11VideoCapture); return base::FeatureList::IsEnabled(kMediaFoundationD3D11VideoCapture);
} }
#endif #endif
#if BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
bool IsOutOfProcessVideoDecodingEnabled() {
#if BUILDFLAG(IS_CASTOS)
// The sandbox for OOP-VD was designed assuming that we're not on CastOS (see
// go/oop-vd-sandbox).
//
// TODO(b/210759684): revisit the sandbox to see if this restriction is
// necessary.
return false;
#else
return base::FeatureList::IsEnabled(kUseOutOfProcessVideoDecoding);
#endif
}
#endif // BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
// Return bitmask of audio formats supported by EDID. // Return bitmask of audio formats supported by EDID.
uint32_t GetPassthroughAudioFormats() { uint32_t GetPassthroughAudioFormats() {
#if BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS) #if BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS)

View file

@ -184,6 +184,110 @@ const char* VaapiFunctionName(VaapiFunctions function) {
return kVaapiFunctionNames[static_cast<size_t>(function)]; return kVaapiFunctionNames[static_cast<size_t>(function)];
} }
// This class is a wrapper around its |va_display_| (and its associated
// |va_lock_|) to guarantee mutual exclusion and singleton behaviour.
//
// Users of this class should hold onto a non-null VADisplayStateHandle for as
// long as they need to access any of the VADisplayStateSingleton methods. This
// guarantees that the VADisplayStateSingleton is properly initialized.
//
// Details:
//
// A VADisplayStateSingleton is immutable from the point of view of its users.
// That is, as long as a non-null VADisplayStateHandle exists, the va_display(),
// implementation_type(), and vendor_string() methods always return the same
// values.
//
// It's not strictly necessary to acquire the lock returned by va_lock() before
// calling va_display(), implementation_type(), or vendor_string(). However, on
// older drivers, it maybe necessary to acquire that lock before using the
// VADisplay returned by va_display() on any libva calls. That's because older
// drivers may not guarantee that it's safe to use the same VADisplay
// concurrently.
class VADisplayStateSingleton {
public:
VADisplayStateSingleton(const VADisplayStateSingleton&) = delete;
VADisplayStateSingleton& operator=(const VADisplayStateSingleton&) = delete;
// This method must be called exactly once before trying to acquire a
// VADisplayStateHandle.
static void PreSandboxInitialization();
// If an initialized VADisplayStateSingleton exists, this method returns a
// VADisplayStateHandle to it. Otherwise, it attempts to initialize a
// VADisplayStateSingleton: if successful, it returns a VADisplayStateHandle
// to it; otherwise, it returns a null VADisplayStateHandle.
//
// This method is thread- and sequence- safe.
static VADisplayStateHandle GetHandle();
base::Lock* va_lock() const { return &va_lock_; }
VADisplay va_display() const { return va_display_; }
VAImplementation implementation_type() const { return implementation_type_; }
const std::string& vendor_string() const { return va_vendor_string_; }
private:
friend class base::NoDestructor<VADisplayStateSingleton>;
friend class VADisplayStateHandle;
static VADisplayStateSingleton& GetInstance();
VADisplayStateSingleton() = default;
~VADisplayStateSingleton() = default;
// If this method returns false, the VADisplayStateSingleton is unchanged.
bool Initialize() EXCLUSIVE_LOCKS_REQUIRED(lock_);
void OnRefDestroyed();
// This lock makes reference counting and initialization/de-initialization
// thread- and sequence-safe. It's independent of |va_lock_| which is only
// used to guard the VADisplay in case the libva backend is not known to be
// thread-safe.
//
// Note: the reason we don't use the same lock for everything is that it's
// perfectly valid for a user to try to acquire a VADisplayStateHandle while
// being in a block where libva calls are being made, so |va_lock_| could
// already be acquired in that situation and trying to acquire it again for
// reference counting would cause a deadlock.
base::Lock lock_;
// DRM FD used to obtain access to the driver interface by VA.
base::ScopedFD drm_fd_ GUARDED_BY(lock_);
int refcount_ GUARDED_BY(lock_) = 0;
// Libva may or may not be thread safe depending on the backend. If not thread
// safe, we have to do locking for it ourselves. Therefore, this lock may need
// to be acquired for the duration of all VA-API calls and for the entire job
// submission sequence in ExecuteAndDestroyPendingBuffers().
//
// Note: this field is made mutable to be able to mark va_lock() const: that
// way, we convey that that method does not really change the
// VADisplayStateSingleton. It's only mutable so that users of the
// VADisplayStateSingleton can acquire the lock.
//
// TODO(andrescj): maybe it's better to provide an AcquireVALock() method so
// that we control exactly how the lock can be used.
mutable base::Lock va_lock_;
// Note: the following members are deliberately not annotated with either
// GUARDED_BY(lock_) or GUARDED_BY(va_lock_) because this annotation cannot
// capture the required thread model: these members can't change as long as a
// non-null VADisplayStateHandle exists, and users of VADisplayStateSingleton
// should ensure that a non-null VADisplayStateHandle exists as long as they
// need access to the VADisplayStateSingleton. Therefore, the accessor methods
// don't need to acquire any lock.
VADisplay va_display_ = nullptr;
// Enumerated version of vaQueryVendorString().
VAImplementation implementation_type_ = VAImplementation::kInvalid;
// String representing a driver acquired by vaQueryVendorString().
std::string va_vendor_string_;
};
} // namespace media } // namespace media
#define LOG_VA_ERROR_AND_REPORT(va_error, function) \ #define LOG_VA_ERROR_AND_REPORT(va_error, function) \
@ -253,6 +357,10 @@ media::VAImplementation VendorStringToImplementationType(
} }
bool UseGlobalVaapiLock(media::VAImplementation implementation_type) { bool UseGlobalVaapiLock(media::VAImplementation implementation_type) {
if (!media::VaapiWrapper::allow_disabling_global_lock_) {
return true;
}
// Only iHD and Mesa Gallium are known to be thread safe at the moment. // Only iHD and Mesa Gallium are known to be thread safe at the moment.
// * Mesa Gallium: b/144877595 // * Mesa Gallium: b/144877595
// * iHD: crbug.com/1123429. // * iHD: crbug.com/1123429.
@ -608,8 +716,7 @@ const ProfileCodecMap& GetProfileCodecMap() {
} }
// Maps a VideoCodecProfile |profile| to a VAProfile, or VAProfileNone. // Maps a VideoCodecProfile |profile| to a VAProfile, or VAProfileNone.
VAProfile ProfileToVAProfile(VideoCodecProfile profile, VAProfile ProfileToVAProfile(VideoCodecProfile profile) {
VaapiWrapper::CodecMode mode) {
const auto& profiles = GetProfileCodecMap(); const auto& profiles = GetProfileCodecMap();
const auto& maybe_profile = profiles.find(profile); const auto& maybe_profile = profiles.find(profile);
if (maybe_profile == profiles.end()) if (maybe_profile == profiles.end())
@ -617,15 +724,29 @@ VAProfile ProfileToVAProfile(VideoCodecProfile profile,
return maybe_profile->second; return maybe_profile->second;
} }
bool IsVAProfileSupported(VAProfile va_profile) { bool IsVAProfileSupported(VAProfile va_profile, bool is_encoding) {
const auto& profiles = GetProfileCodecMap();
// VAProfileJPEGBaseline and VAProfileProtected are always recognized but are // VAProfileJPEGBaseline and VAProfileProtected are always recognized but are
// not video codecs per se. // not video codecs per se.
return va_profile == VAProfileJPEGBaseline || if (va_profile == VAProfileJPEGBaseline) {
return true;
}
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH)
va_profile == VAProfileProtected || if (va_profile == VAProfileProtected) {
return true;
}
#endif #endif
base::Contains(profiles, va_profile, if (is_encoding) {
constexpr VAProfile kSupportableEncoderProfiles[] = {
VAProfileH264ConstrainedBaseline,
VAProfileH264Main,
VAProfileH264High,
VAProfileVP8Version0_3,
VAProfileVP9Profile0,
VAProfileAV1Profile0,
};
return base::Contains(kSupportableEncoderProfiles, va_profile);
}
return base::Contains(GetProfileCodecMap(), va_profile,
&ProfileCodecMap::value_type::second); &ProfileCodecMap::value_type::second);
} }
@ -647,6 +768,11 @@ bool IsBlockedDriver(VaapiWrapper::CodecMode mode,
return true; return true;
} }
if (va_profile == VAProfileAV1Profile0 &&
!base::FeatureList::IsEnabled(kVaapiAV1Encoder)) {
return true;
}
if (mode == VaapiWrapper::CodecMode::kEncodeVariableBitrate) { if (mode == VaapiWrapper::CodecMode::kEncodeVariableBitrate) {
// The rate controller on grunt is not good enough to support VBR encoding, // The rate controller on grunt is not good enough to support VBR encoding,
// b/253988139. // b/253988139.
@ -661,138 +787,6 @@ bool IsBlockedDriver(VaapiWrapper::CodecMode mode,
return false; return false;
} }
// This class is a wrapper around its |va_display_| (and its associated
// |va_lock_|) to guarantee mutual exclusion and singleton behaviour.
class VADisplayState {
public:
static VADisplayState* Get();
VADisplayState(const VADisplayState&) = delete;
VADisplayState& operator=(const VADisplayState&) = delete;
// Initialize static data before sandbox is enabled.
static void PreSandboxInitialization();
bool Initialize();
VAStatus Deinitialize();
base::Lock* va_lock() { return &va_lock_; }
VADisplay va_display() const { return va_display_; }
VAImplementation implementation_type() const { return implementation_type_; }
const std::string& vendor_string() const { return va_vendor_string_; }
void SetDrmFd(base::PlatformFile fd) { drm_fd_.reset(HANDLE_EINTR(dup(fd))); }
private:
friend class base::NoDestructor<VADisplayState>;
VADisplayState();
~VADisplayState() = default;
// Implementation of Initialize() called only once.
bool InitializeOnce() EXCLUSIVE_LOCKS_REQUIRED(va_lock_);
bool InitializeVaDisplay_Locked() EXCLUSIVE_LOCKS_REQUIRED(va_lock_);
bool InitializeVaDriver_Locked() EXCLUSIVE_LOCKS_REQUIRED(va_lock_);
int refcount_ GUARDED_BY(va_lock_);
// Libva may or may not be thread safe depending on the backend. If not thread
// safe, we have to do locking for it ourselves. Therefore, this lock may need
// to be taken for the duration of all VA-API calls and for the entire job
// submission sequence in ExecuteAndDestroyPendingBuffers().
base::Lock va_lock_;
// Drm fd used to obtain access to the driver interface by VA.
base::ScopedFD drm_fd_;
// The VADisplay handle. Valid between Initialize() and Deinitialize().
VADisplay va_display_;
// True if vaInitialize() has been called successfully, until Deinitialize().
bool va_initialized_;
// Enumerated version of vaQueryVendorString(). Valid after Initialize().
VAImplementation implementation_type_ = VAImplementation::kInvalid;
// String representing a driver acquired by vaQueryVendorString().
std::string va_vendor_string_;
};
// static
VADisplayState* VADisplayState::Get() {
static base::NoDestructor<VADisplayState> display_state;
return display_state.get();
}
// static
void VADisplayState::PreSandboxInitialization() {
constexpr char kRenderNodeFilePattern[] = "/dev/dri/renderD%d";
const char kNvidiaPath[] = "/dev/dri/nvidiactl";
// TODO: Is this still needed?
base::File nvidia_file = base::File(
base::FilePath::FromUTF8Unsafe(kNvidiaPath),
base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE);
// This loop ends on either the first card that does not exist or the first
// render node that is not vgem.
for (int i = 128;; i++) {
base::FilePath dev_path(FILE_PATH_LITERAL(
base::StringPrintf(kRenderNodeFilePattern, i).c_str()));
base::File drm_file =
base::File(dev_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
base::File::FLAG_WRITE);
if (!drm_file.IsValid())
return;
// Skip the virtual graphics memory manager device.
drmVersionPtr version = drmGetVersion(drm_file.GetPlatformFile());
if (!version)
continue;
std::string version_name(
version->name,
base::checked_cast<std::string::size_type>(version->name_len));
drmFreeVersion(version);
if (base::EqualsCaseInsensitiveASCII(version_name, "vgem"))
continue;
VADisplayState::Get()->SetDrmFd(drm_file.GetPlatformFile());
return;
}
}
VADisplayState::VADisplayState()
: refcount_(0), va_display_(nullptr), va_initialized_(false) {}
bool VADisplayState::Initialize() {
base::AutoLock auto_lock(va_lock_);
#if BUILDFLAG(IS_OZONE) && BUILDFLAG(IS_LINUX)
// TODO(crbug.com/1116701): add vaapi support for other Ozone platforms on
// Linux. See comment in OzonePlatform::PlatformProperties::supports_vaapi
// for more details. This will also require revisiting everything that's
// guarded by USE_VAAPI_X11. For example, if USE_VAAPI_X11 is true, but the
// user chooses the Wayland backend for Ozone at runtime, then many things (if
// not all) that we do for X11 won't apply.
if (!ui::OzonePlatform::GetInstance()->GetPlatformProperties().supports_vaapi)
return false;
#endif
bool libraries_initialized = IsVaInitialized() && IsVa_drmInitialized();
#if BUILDFLAG(USE_VAAPI_X11)
libraries_initialized = libraries_initialized && IsVa_x11Initialized();
#endif
if (!libraries_initialized)
return false;
// Manual refcounting to ensure the rest of the method is called only once.
if (refcount_++ > 0)
return true;
const bool success = InitializeOnce();
UMA_HISTOGRAM_BOOLEAN("Media.VaapiWrapper.VADisplayStateInitializeSuccess",
success);
return success;
}
#if BUILDFLAG(USE_VAAPI_X11) #if BUILDFLAG(USE_VAAPI_X11)
absl::optional<VADisplay> GetVADisplayStateX11(const base::ScopedFD& drm_fd) { absl::optional<VADisplay> GetVADisplayStateX11(const base::ScopedFD& drm_fd) {
@ -837,90 +831,6 @@ absl::optional<VADisplay> GetVADisplayState(const base::ScopedFD& drm_fd) {
#endif // BUILDFLAG(USE_VAAPI_X11) #endif // BUILDFLAG(USE_VAAPI_X11)
bool VADisplayState::InitializeVaDisplay_Locked() {
absl::optional<VADisplay> display =
#if BUILDFLAG(USE_VAAPI_X11)
GetVADisplayStateX11(drm_fd_);
#else
GetVADisplayState(drm_fd_);
#endif
if (!display)
return false;
va_display_ = *display;
if (!vaDisplayIsValid(va_display_)) {
LOG(ERROR) << "Could not get a valid VA display";
return false;
}
return true;
}
bool VADisplayState::InitializeVaDriver_Locked() {
// The VAAPI version.
int major_version, minor_version;
VAStatus va_res = vaInitialize(va_display_, &major_version, &minor_version);
if (va_res != VA_STATUS_SUCCESS) {
VLOGF(1) << "vaInitialize failed: " << vaErrorStr(va_res);
return false;
}
va_vendor_string_ = vaQueryVendorString(va_display_);
DLOG_IF(WARNING, va_vendor_string_.empty())
<< "Vendor string empty or error reading.";
DVLOG(1) << "VAAPI version: " << major_version << "." << minor_version << " "
<< va_vendor_string_;
implementation_type_ = VendorStringToImplementationType(va_vendor_string_);
va_initialized_ = true;
// The VAAPI version is determined from what is loaded on the system by
// calling vaInitialize(). Since the libva is now ABI-compatible, relax the
// version check which helps in upgrading the libva, without breaking any
// existing functionality. Make sure the system version is not older than
// the version with which the chromium is built since libva is only
// guaranteed to be backward (and not forward) compatible.
if (VA_MAJOR_VERSION > major_version ||
(VA_MAJOR_VERSION == major_version && VA_MINOR_VERSION > minor_version)) {
VLOGF(1) << "The system version " << major_version << "." << minor_version
<< " should be greater than or equal to " << VA_MAJOR_VERSION
<< "." << VA_MINOR_VERSION;
return false;
}
return true;
}
bool VADisplayState::InitializeOnce() {
// Set VA logging level, unless already set.
constexpr char libva_log_level_env[] = "LIBVA_MESSAGING_LEVEL";
std::unique_ptr<base::Environment> env(base::Environment::Create());
if (!env->HasVar(libva_log_level_env))
env->SetVar(libva_log_level_env, "1");
if (!InitializeVaDisplay_Locked() || !InitializeVaDriver_Locked())
return false;
return true;
}
VAStatus VADisplayState::Deinitialize() {
base::AutoLock auto_lock(va_lock_);
VAStatus va_res = VA_STATUS_SUCCESS;
if (--refcount_ > 0)
return va_res;
// Must check if vaInitialize completed successfully, to work around a bug in
// libva. The bug was fixed upstream:
// http://lists.freedesktop.org/archives/libva/2013-July/001807.html
// TODO(mgiuca): Remove this check, and the |va_initialized_| variable, once
// the fix has rolled out sufficiently.
if (va_initialized_ && va_display_)
va_res = vaTerminate(va_display_);
va_initialized_ = false;
va_display_ = nullptr;
return va_res;
}
// Returns all the VAProfiles that the driver lists as supported, regardless of // Returns all the VAProfiles that the driver lists as supported, regardless of
// what Chrome supports or not. // what Chrome supports or not.
std::vector<VAProfile> GetSupportedVAProfiles(const base::Lock* va_lock, std::vector<VAProfile> GetSupportedVAProfiles(const base::Lock* va_lock,
@ -1197,12 +1107,14 @@ const VASupportedProfiles::ProfileInfo* VASupportedProfiles::IsProfileSupported(
VASupportedProfiles::VASupportedProfiles() VASupportedProfiles::VASupportedProfiles()
: report_error_to_uma_cb_(base::DoNothing()) { : report_error_to_uma_cb_(base::DoNothing()) {
VADisplayState* display_state = VADisplayState::Get(); VADisplayStateHandle display_state = VADisplayStateSingleton::GetHandle();
if (!display_state->Initialize()) if (!display_state) {
return; return;
}
VADisplay va_display = display_state->va_display(); VADisplay va_display = display_state->va_display();
DCHECK(va_display) << "VADisplayState hasn't been properly Initialize()d"; DCHECK(va_display)
<< "VADisplayStateSingleton hasn't been properly initialized";
base::Lock* va_lock = display_state->va_lock(); base::Lock* va_lock = display_state->va_lock();
if (!UseGlobalVaapiLock(display_state->implementation_type())) { if (!UseGlobalVaapiLock(display_state->implementation_type())) {
@ -1211,9 +1123,6 @@ VASupportedProfiles::VASupportedProfiles()
FillSupportedProfileInfos(va_lock, va_display, FillSupportedProfileInfos(va_lock, va_display,
display_state->vendor_string()); display_state->vendor_string());
const VAStatus va_res = display_state->Deinitialize();
VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVATerminate);
} }
void VASupportedProfiles::FillSupportedProfileInfos( void VASupportedProfiles::FillSupportedProfileInfos(
@ -1245,7 +1154,7 @@ void VASupportedProfiles::FillSupportedProfileInfos(
continue; continue;
if ((mode != VaapiWrapper::kVideoProcess) && if ((mode != VaapiWrapper::kVideoProcess) &&
!IsVAProfileSupported(va_profile)) { !IsVAProfileSupported(va_profile, IsModeEncoding(mode))) {
continue; continue;
} }
@ -1432,7 +1341,18 @@ bool VASupportedProfiles::FillProfileInfo_Locked(
// Now work around some driver misreporting for JPEG decoding. // Now work around some driver misreporting for JPEG decoding.
if (va_profile == VAProfileJPEGBaseline && entrypoint == VAEntrypointVLD) { if (va_profile == VAProfileJPEGBaseline && entrypoint == VAEntrypointVLD) {
if (VADisplayState::Get()->implementation_type() == auto va_display_state_handle = VADisplayStateSingleton::GetHandle();
// Note: FillProfileInfo_Locked() is called only from
// FillSupportedProfileInfos() which in turn is called only from the
// VASupportedProfiles constructor. This call occurs while a valid
// VADisplayStateHandle exists (because of the check in the constructor).
// That means that at this point, there is an initialized
// VADisplayStateSingleton, so the VADisplayStateSingleton::GetHandle() call
// above must produce a valid handle.
CHECK(va_display_state_handle);
if (va_display_state_handle->implementation_type() ==
VAImplementation::kMesaGallium) { VAImplementation::kMesaGallium) {
// TODO(andrescj): the VAAPI state tracker in mesa does not report // TODO(andrescj): the VAAPI state tracker in mesa does not report
// VA_RT_FORMAT_YUV422 as being supported for JPEG decoding. However, it // VA_RT_FORMAT_YUV422 as being supported for JPEG decoding. However, it
@ -1512,12 +1432,13 @@ VASupportedImageFormats::GetSupportedImageFormats() const {
VASupportedImageFormats::VASupportedImageFormats() VASupportedImageFormats::VASupportedImageFormats()
: report_error_to_uma_cb_(base::DoNothing()) { : report_error_to_uma_cb_(base::DoNothing()) {
VADisplayState* display_state = VADisplayState::Get(); auto display_state = VADisplayStateSingleton::GetHandle();
if (!display_state->Initialize()) if (!display_state) {
return; return;
}
// Pointer to VADisplayState's members |va_lock_| if using global VA lock or // Pointer to VADisplayStateSingleton's |va_lock_| member if using a global VA
// the implementation is not thread safe. // lock or if the implementation is not thread-safe.
base::Lock* va_lock = display_state->va_lock(); base::Lock* va_lock = display_state->va_lock();
if (!UseGlobalVaapiLock(display_state->implementation_type())) { if (!UseGlobalVaapiLock(display_state->implementation_type())) {
va_lock = nullptr; va_lock = nullptr;
@ -1526,14 +1447,12 @@ VASupportedImageFormats::VASupportedImageFormats()
{ {
base::AutoLockMaybe auto_lock(va_lock); base::AutoLockMaybe auto_lock(va_lock);
VADisplay va_display = display_state->va_display(); VADisplay va_display = display_state->va_display();
DCHECK(va_display) << "VADisplayState hasn't been properly initialized"; DCHECK(va_display)
<< "VADisplayStateSingleton hasn't been properly initialized";
if (!InitSupportedImageFormats_Locked(va_lock, va_display)) if (!InitSupportedImageFormats_Locked(va_lock, va_display))
LOG(ERROR) << "Failed to get supported image formats"; LOG(ERROR) << "Failed to get supported image formats";
} }
const VAStatus va_res = display_state->Deinitialize();
VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVATerminate);
} }
bool VASupportedImageFormats::InitSupportedImageFormats_Locked( bool VASupportedImageFormats::InitSupportedImageFormats_Locked(
@ -1564,7 +1483,17 @@ bool VASupportedImageFormats::InitSupportedImageFormats_Locked(
supported_formats_.resize(static_cast<size_t>(num_image_formats)); supported_formats_.resize(static_cast<size_t>(num_image_formats));
// Now work around some driver misreporting. // Now work around some driver misreporting.
if (VADisplayState::Get()->implementation_type() == auto va_display_state_handle = VADisplayStateSingleton::GetHandle();
// Note: InitSupportedImageFormats_Locked() is called only from the
// VASupportedImageFormats constructor. This call occurs while a valid
// VADisplayStateHandle exists (because of the check in the constructor). That
// means that at this point, there is an initialized VADisplayStateSingleton,
// so the VADisplayStateSingleton::GetHandle() call above must produce a valid
// handle.
CHECK(va_display_state_handle);
if (va_display_state_handle->implementation_type() ==
VAImplementation::kMesaGallium) { VAImplementation::kMesaGallium) {
// TODO(andrescj): considering that the VAAPI state tracker in mesa can // TODO(andrescj): considering that the VAAPI state tracker in mesa can
// convert from NV12 to IYUV when doing vaGetImage(), it's reasonable to // convert from NV12 to IYUV when doing vaGetImage(), it's reasonable to
@ -1588,7 +1517,8 @@ bool IsLowPowerEncSupported(VAProfile va_profile) {
VAProfileH264Main, VAProfileH264Main,
VAProfileH264High, VAProfileH264High,
VAProfileVP9Profile0, VAProfileVP9Profile0,
VAProfileVP9Profile2}; VAProfileAV1Profile0,
};
if (!base::Contains(kSupportedLowPowerEncodeProfiles, va_profile)) if (!base::Contains(kSupportedLowPowerEncodeProfiles, va_profile))
return false; return false;
@ -1622,13 +1552,210 @@ bool IsVBREncodingSupported(VAProfile va_profile) {
} // namespace } // namespace
// static
VADisplayStateSingleton& VADisplayStateSingleton::GetInstance() {
static base::NoDestructor<VADisplayStateSingleton> va_display_state;
return *va_display_state;
}
// static
void VADisplayStateSingleton::PreSandboxInitialization() {
VADisplayStateSingleton& va_display_state = GetInstance();
base::AutoLock lock(va_display_state.lock_);
constexpr char kRenderNodeFilePattern[] = "/dev/dri/renderD%d";
const char kNvidiaDriPath[] = "/dev/dri/nvidiactl";
const char kNvidiaPath[] = "/dev/nvidiactl";
// TODO: Is this still needed?
base::File nvidia_file = base::File(
base::FilePath::FromUTF8Unsafe(kNvidiaPath),
base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE);
// This loop ends on either the first card that does not exist or the first
// render node that is not vgem.
for (int i = 128;; i++) {
base::FilePath dev_path(FILE_PATH_LITERAL(
base::StringPrintf(kRenderNodeFilePattern, i).c_str()));
base::File drm_file =
base::File(dev_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
base::File::FLAG_WRITE);
if (!drm_file.IsValid()) {
return;
}
// Skip the virtual graphics memory manager device.
drmVersionPtr version = drmGetVersion(drm_file.GetPlatformFile());
if (!version) {
continue;
}
std::string version_name(
version->name,
base::checked_cast<std::string::size_type>(version->name_len));
drmFreeVersion(version);
if (base::EqualsCaseInsensitiveASCII(version_name, "vgem")) {
continue;
}
va_display_state.drm_fd_ = base::ScopedFD(drm_file.TakePlatformFile());
return;
}
}
// static
VADisplayStateHandle VADisplayStateSingleton::GetHandle() {
VADisplayStateSingleton& va_display_state = GetInstance();
base::AutoLock lock(va_display_state.lock_);
if (va_display_state.refcount_ > 0) {
// There's already an initialized VADisplayStateSingleton. Return a handle
// to it.
CHECK_LT(va_display_state.refcount_,
std::numeric_limits<decltype(va_display_state.refcount_)>::max());
va_display_state.refcount_++;
return VADisplayStateHandle(&va_display_state);
}
if (!va_display_state.drm_fd_.is_valid()) {
VLOGF(1)
<< "Either VADisplayStateSingleton::PreSandboxInitialization() hasn't "
"been called or that method failed to find a suitable render node";
return {};
}
#if BUILDFLAG(IS_OZONE) && BUILDFLAG(IS_LINUX)
// TODO(crbug.com/1116701): add vaapi support for other Ozone platforms on
// Linux. See comment in OzonePlatform::PlatformProperties::supports_vaapi
// for more details. This will also require revisiting everything that's
// guarded by USE_VAAPI_X11. For example, if USE_VAAPI_X11 is true, but the
// user chooses the Wayland backend for Ozone at runtime, then many things (if
// not all) that we do for X11 won't apply.
if (!ui::OzonePlatform::GetInstance()
->GetPlatformProperties()
.supports_vaapi) {
return {};
}
#endif
bool libraries_initialized = IsVaInitialized() && IsVa_drmInitialized();
#if BUILDFLAG(USE_VAAPI_X11)
libraries_initialized = libraries_initialized && IsVa_x11Initialized();
#endif
if (!libraries_initialized) {
return {};
}
const bool success = va_display_state.Initialize();
UMA_HISTOGRAM_BOOLEAN("Media.VaapiWrapper.VADisplayStateInitializeSuccess",
success);
return success ? VADisplayStateHandle(&va_display_state) : VADisplayStateHandle();
}
bool VADisplayStateSingleton::Initialize() {
// Set VA logging level, unless already set.
constexpr char libva_log_level_env[] = "LIBVA_MESSAGING_LEVEL";
std::unique_ptr<base::Environment> env(base::Environment::Create());
if (!env->HasVar(libva_log_level_env)) {
env->SetVar(libva_log_level_env, "1");
}
absl::optional<VADisplay> display =
#if BUILDFLAG(USE_VAAPI_X11)
GetVADisplayStateX11(drm_fd_);
#else
GetVADisplayState(drm_fd_);
#endif
if (!display) {
return false;
}
VADisplay va_display = *display;
base::ScopedClosureRunner va_display_cleaner_cb(base::BindOnce(
[](VADisplay va_display) {
if (vaDisplayIsValid(va_display)) {
vaTerminate(va_display);
}
},
va_display));
if (!vaDisplayIsValid(va_display)) {
LOG(ERROR) << "Could not get a valid VA display";
return false;
}
// The VA-API version.
int major_version, minor_version;
VAStatus va_res = vaInitialize(va_display, &major_version, &minor_version);
if (va_res != VA_STATUS_SUCCESS) {
VLOGF(1) << "vaInitialize failed: " << vaErrorStr(va_res);
return false;
}
const std::string va_vendor_string = vaQueryVendorString(va_display);
if (va_vendor_string.empty()) {
VLOGF(1) << "vaQueryVendorString returned an empty string";
return false;
}
DVLOG(1) << "VAAPI version: " << major_version << "." << minor_version << " "
<< va_vendor_string;
const VAImplementation implementation_type =
VendorStringToImplementationType(va_vendor_string);
// The VAAPI version is determined from what is loaded on the system by
// calling vaInitialize(). Since the libva is now ABI-compatible, relax the
// version check which helps in upgrading the libva, without breaking any
// existing functionality. Make sure the system version is not older than
// the version with which the chromium is built since libva is only
// guaranteed to be backward (and not forward) compatible.
if (VA_MAJOR_VERSION > major_version ||
(VA_MAJOR_VERSION == major_version && VA_MINOR_VERSION > minor_version)) {
VLOGF(1) << "The system version " << major_version << "." << minor_version
<< " should be greater than or equal to " << VA_MAJOR_VERSION
<< "." << VA_MINOR_VERSION;
return false;
}
std::ignore = va_display_cleaner_cb.Release();
refcount_ = 1;
va_display_ = va_display;
implementation_type_ = implementation_type;
va_vendor_string_ = va_vendor_string;
return true;
}
void VADisplayStateSingleton::OnRefDestroyed() {
base::AutoLock lock(lock_);
if (--refcount_ > 0) {
return;
}
// No more handles to the VADisplayStateSingleton remain. We can clean up.
vaTerminate(va_display_);
va_display_ = nullptr;
implementation_type_ = VAImplementation::kInvalid;
va_vendor_string_ = "";
}
VADisplayStateHandle::VADisplayStateHandle() : va_display_state_(nullptr) {}
VADisplayStateHandle::VADisplayStateHandle(
VADisplayStateSingleton* va_display_state)
: va_display_state_(va_display_state) {}
VADisplayStateHandle::~VADisplayStateHandle() {
if (va_display_state_) {
va_display_state_->OnRefDestroyed();
}
}
NativePixmapAndSizeInfo::NativePixmapAndSizeInfo() = default; NativePixmapAndSizeInfo::NativePixmapAndSizeInfo() = default;
NativePixmapAndSizeInfo::~NativePixmapAndSizeInfo() = default; NativePixmapAndSizeInfo::~NativePixmapAndSizeInfo() = default;
// static // static
VAImplementation VaapiWrapper::GetImplementationType() { VAImplementation VaapiWrapper::GetImplementationType() {
return VADisplayState::Get()->implementation_type(); auto va_display_state_handle = VADisplayStateSingleton::GetHandle();
return va_display_state_handle
? va_display_state_handle->implementation_type()
: VAImplementation::kInvalid;
} }
// static // static
@ -1654,8 +1781,13 @@ scoped_refptr<VaapiWrapper> VaapiWrapper::Create(
} }
#endif #endif
scoped_refptr<VaapiWrapper> vaapi_wrapper( auto va_display_state_handle = VADisplayStateSingleton::GetHandle();
new VaapiWrapper(mode, enforce_sequence_affinity)); if (!va_display_state_handle) {
return nullptr;
}
scoped_refptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper(
std::move(va_display_state_handle), mode, enforce_sequence_affinity));
if (vaapi_wrapper->VaInitialize(report_error_to_uma_cb)) { if (vaapi_wrapper->VaInitialize(report_error_to_uma_cb)) {
if (vaapi_wrapper->Initialize(va_profile, encryption_scheme)) if (vaapi_wrapper->Initialize(va_profile, encryption_scheme))
return vaapi_wrapper; return vaapi_wrapper;
@ -1672,7 +1804,7 @@ scoped_refptr<VaapiWrapper> VaapiWrapper::CreateForVideoCodec(
EncryptionScheme encryption_scheme, EncryptionScheme encryption_scheme,
const ReportErrorToUMACB& report_error_to_uma_cb, const ReportErrorToUMACB& report_error_to_uma_cb,
bool enforce_sequence_affinity) { bool enforce_sequence_affinity) {
const VAProfile va_profile = ProfileToVAProfile(profile, mode); const VAProfile va_profile = ProfileToVAProfile(profile);
return Create(mode, va_profile, encryption_scheme, report_error_to_uma_cb, return Create(mode, va_profile, encryption_scheme, report_error_to_uma_cb,
enforce_sequence_affinity); enforce_sequence_affinity);
} }
@ -1947,13 +2079,6 @@ bool VaapiWrapper::IsVppSupportedForJpegDecodedSurfaceToFourCC(
if (!IsDecodingSupportedForInternalFormat(VAProfileJPEGBaseline, rt_format)) if (!IsDecodingSupportedForInternalFormat(VAProfileJPEGBaseline, rt_format))
return false; return false;
// Workaround: for Mesa VAAPI driver, VPP only supports internal surface
// format for 4:2:0 JPEG image.
DCHECK_NE(VAImplementation::kInvalid, GetImplementationType());
if (GetImplementationType() == VAImplementation::kMesaGallium &&
rt_format != VA_RT_FORMAT_YUV420) {
return false;
}
return IsVppFormatSupported(fourcc); return IsVppFormatSupported(fourcc);
} }
@ -2950,8 +3075,7 @@ bool VaapiWrapper::GetVAEncMaxNumOfRefFrames(VideoCodecProfile profile,
size_t* max_ref_frames) { size_t* max_ref_frames) {
CHECK(!enforce_sequence_affinity_ || CHECK(!enforce_sequence_affinity_ ||
sequence_checker_.CalledOnValidSequence()); sequence_checker_.CalledOnValidSequence());
const VAProfile va_profile = const VAProfile va_profile = ProfileToVAProfile(profile);
ProfileToVAProfile(profile, CodecMode::kEncodeConstantBitrate);
VAConfigAttrib attrib; VAConfigAttrib attrib;
attrib.type = VAConfigAttribEncMaxRefFrames; attrib.type = VAConfigAttribEncMaxRefFrames;
@ -2970,8 +3094,7 @@ bool VaapiWrapper::GetSupportedPackedHeaders(VideoCodecProfile profile,
bool& packed_slice) { bool& packed_slice) {
CHECK(!enforce_sequence_affinity_ || CHECK(!enforce_sequence_affinity_ ||
sequence_checker_.CalledOnValidSequence()); sequence_checker_.CalledOnValidSequence());
const VAProfile va_profile = const VAProfile va_profile = ProfileToVAProfile(profile);
ProfileToVAProfile(profile, CodecMode::kEncodeConstantBitrate);
VAConfigAttrib attrib{}; VAConfigAttrib attrib{};
attrib.type = VAConfigAttribEncPackedHeaders; attrib.type = VAConfigAttribEncPackedHeaders;
base::AutoLockMaybe auto_lock(va_lock_.get()); base::AutoLockMaybe auto_lock(va_lock_.get());
@ -3115,8 +3238,13 @@ bool VaapiWrapper::BlitSurface(const VASurface& va_surface_src,
} }
// static // static
void VaapiWrapper::PreSandboxInitialization() { bool VaapiWrapper::allow_disabling_global_lock_ = false;
VADisplayState::PreSandboxInitialization();
// static
void VaapiWrapper::PreSandboxInitialization(bool allow_disabling_global_lock) {
allow_disabling_global_lock_ = allow_disabling_global_lock;
VADisplayStateSingleton::PreSandboxInitialization();
const std::string va_suffix(std::to_string(VA_MAJOR_VERSION + 1)); const std::string va_suffix(std::to_string(VA_MAJOR_VERSION + 1));
StubPathMap paths; StubPathMap paths;
@ -3137,10 +3265,16 @@ void VaapiWrapper::PreSandboxInitialization() {
static bool result = InitializeStubs(paths); static bool result = InitializeStubs(paths);
if (!result) { if (!result) {
static const char kErrorMsg[] = "Failed to initialize VAAPI libs"; static const char kErrorMsg[] = "Failed to initialize VAAPI libs";
#if BUILDFLAG(IS_CHROMEOS)
// When Chrome runs on Linux with target_os="chromeos", do not log error
// message without VAAPI libraries.
LOG_IF(ERROR, base::SysInfo::IsRunningOnChromeOS()) << kErrorMsg;
#else
LOG(ERROR) << kErrorMsg; LOG(ERROR) << kErrorMsg;
#endif
} }
// VASupportedProfiles::Get creates VADisplayState and in so doing // VASupportedProfiles::Get creates VADisplayStateSingleton and in so doing
// driver associated libraries are dlopen(), to know: // driver associated libraries are dlopen(), to know:
// i965_drv_video.so // i965_drv_video.so
// hybrid_drv_video.so (platforms that support it) // hybrid_drv_video.so (platforms that support it)
@ -3148,11 +3282,17 @@ void VaapiWrapper::PreSandboxInitialization() {
VASupportedProfiles::Get(); VASupportedProfiles::Get();
} }
VaapiWrapper::VaapiWrapper(CodecMode mode, bool enforce_sequence_affinity) VaapiWrapper::VaapiWrapper(VADisplayStateHandle va_display_state_handle,
CodecMode mode,
bool enforce_sequence_affinity)
: mode_(mode), : mode_(mode),
enforce_sequence_affinity_(enforce_sequence_affinity), enforce_sequence_affinity_(enforce_sequence_affinity),
va_lock_(VADisplayState::Get()->va_lock()), va_display_state_handle_(std::move(va_display_state_handle)),
va_display_(nullptr), va_lock_(va_display_state_handle_ ? va_display_state_handle_->va_lock()
: nullptr),
va_display_(va_display_state_handle_
? va_display_state_handle_->va_display()
: nullptr),
va_profile_(VAProfileNone), va_profile_(VAProfileNone),
va_entrypoint_(kVAEntrypointInvalid) {} va_entrypoint_(kVAEntrypointInvalid) {}
@ -3248,9 +3388,6 @@ void VaapiWrapper::Deinitialize() {
va_config_id_ = VA_INVALID_ID; va_config_id_ = VA_INVALID_ID;
va_display_ = nullptr; va_display_ = nullptr;
} }
const VAStatus va_res = VADisplayState::Get()->Deinitialize();
VA_LOG_ON_ERROR(va_res, VaapiFunctions::kVATerminate);
} }
bool VaapiWrapper::VaInitialize( bool VaapiWrapper::VaInitialize(
@ -3258,20 +3395,13 @@ bool VaapiWrapper::VaInitialize(
CHECK(!enforce_sequence_affinity_ || CHECK(!enforce_sequence_affinity_ ||
sequence_checker_.CalledOnValidSequence()); sequence_checker_.CalledOnValidSequence());
report_error_to_uma_cb_ = report_error_to_uma_cb; report_error_to_uma_cb_ = report_error_to_uma_cb;
if (!VADisplayState::Get()->Initialize())
return false;
DCHECK(va_lock_); DCHECK(va_lock_);
if (enforce_sequence_affinity_ && if (enforce_sequence_affinity_ &&
!UseGlobalVaapiLock(VADisplayState::Get()->implementation_type())) { !UseGlobalVaapiLock(va_display_state_handle_->implementation_type())) {
va_lock_ = nullptr; va_lock_ = nullptr;
} }
{
base::AutoLockMaybe auto_lock(va_lock_.get());
va_display_ = VADisplayState::Get()->va_display();
DCHECK(va_display_) << "VADisplayState hasn't been properly Initialize()d";
}
return true; return true;
} }

View file

@ -54,6 +54,7 @@ class Rect;
namespace media { namespace media {
constexpr unsigned int kInvalidVaRtFormat = 0u; constexpr unsigned int kInvalidVaRtFormat = 0u;
class VADisplayStateSingleton;
class VideoFrame; class VideoFrame;
// Enum, function and callback type to allow VaapiWrapper to log errors in VA // Enum, function and callback type to allow VaapiWrapper to log errors in VA
@ -97,6 +98,42 @@ enum class VAImplementation {
kInvalid, kInvalid,
}; };
// A VADisplayStateHandle is somewhat like a scoped_refptr for a
// VADisplayStateSingleton (an internal class used to keep track of a singleton
// VADisplay). As long as a non-null VADisplayStateHandle exists, the underlying
// VADisplay is initialized and can be used. When the last non-null
// VADisplayStateHandle is destroyed, the underlying VADisplay is cleaned up.
//
// Unlike a scoped_refptr, a VADisplayStateHandle is move-only.
//
// Note: a VADisplayStateHandle instance is thread- and sequence-safe, but the
// underlying VADisplay may need protection. See the comments for the
// VADisplayStateSingleton documentation.
class VADisplayStateHandle {
public:
// Creates a null VADisplayStateHandle.
VADisplayStateHandle();
VADisplayStateHandle(VADisplayStateHandle&& other) = default;
VADisplayStateHandle& operator=(VADisplayStateHandle&& other) = default;
VADisplayStateHandle(const VADisplayStateHandle&) = delete;
VADisplayStateHandle& operator=(const VADisplayStateHandle&) = delete;
~VADisplayStateHandle();
VADisplayStateSingleton* operator->() { return va_display_state_; }
explicit operator bool() const { return !!va_display_state_; }
private:
friend class VADisplayStateSingleton;
explicit VADisplayStateHandle(VADisplayStateSingleton* va_display_state);
raw_ptr<VADisplayStateSingleton> va_display_state_;
};
// This class handles VA-API calls and ensures proper locking of VA-API calls // This class handles VA-API calls and ensures proper locking of VA-API calls
// to libva, the userspace shim to the HW codec driver. The thread safety of // to libva, the userspace shim to the HW codec driver. The thread safety of
// libva depends on the backend. If the backend is not thread-safe, we need to // libva depends on the backend. If the backend is not thread-safe, we need to
@ -124,6 +161,11 @@ enum class VAImplementation {
class MEDIA_GPU_EXPORT VaapiWrapper class MEDIA_GPU_EXPORT VaapiWrapper
: public base::RefCountedThreadSafe<VaapiWrapper> { : public base::RefCountedThreadSafe<VaapiWrapper> {
public: public:
// Whether it's okay or not to try to disable the VA-API global lock on the
// current process. This is intended to be set only once during process
// start-up.
static bool allow_disabling_global_lock_;
enum CodecMode { enum CodecMode {
kDecode, kDecode,
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH)
@ -537,14 +579,17 @@ class MEDIA_GPU_EXPORT VaapiWrapper
); );
// Initialize static data before sandbox is enabled. // Initialize static data before sandbox is enabled.
static void PreSandboxInitialization(); static void PreSandboxInitialization(
bool allow_disabling_global_lock = false);
// vaDestroySurfaces() a vector or a single VASurfaceID. // vaDestroySurfaces() a vector or a single VASurfaceID.
virtual void DestroySurfaces(std::vector<VASurfaceID> va_surfaces); virtual void DestroySurfaces(std::vector<VASurfaceID> va_surfaces);
virtual void DestroySurface(VASurfaceID va_surface_id); virtual void DestroySurface(VASurfaceID va_surface_id);
protected: protected:
explicit VaapiWrapper(CodecMode mode, bool enforce_sequence_affinity = true); VaapiWrapper(VADisplayStateHandle va_display_state_handle,
CodecMode mode,
bool enforce_sequence_affinity = true);
virtual ~VaapiWrapper(); virtual ~VaapiWrapper();
private: private:
@ -629,13 +674,21 @@ class MEDIA_GPU_EXPORT VaapiWrapper
const bool enforce_sequence_affinity_; const bool enforce_sequence_affinity_;
base::SequenceCheckerImpl sequence_checker_; base::SequenceCheckerImpl sequence_checker_;
// If using global VA lock, this is a pointer to VADisplayState's member // This is declared before |va_display_| and |va_lock_| to guarantee their
// |va_lock_|. Guaranteed to be valid for the lifetime of VaapiWrapper. // validity for as long as the VaapiWrapper is alive.
VADisplayStateHandle va_display_state_handle_;
// If using a global VA lock, this is a pointer to VADisplayStateSingleton's
// member |va_lock_|. Guaranteed to be valid for the lifetime of the
// VaapiWrapper due to the |va_display_state_handle_| above.
raw_ptr<base::Lock> va_lock_; raw_ptr<base::Lock> va_lock_;
// Guaranteed to be valid for the lifetime of the VaapiWrapper due to the
// |va_display_state_handle_| above.
VADisplay va_display_ GUARDED_BY(va_lock_);
// VA handles. // VA handles.
// All valid after successful Initialize() and until Deinitialize(). // All valid after successful Initialize() and until Deinitialize().
VADisplay va_display_ GUARDED_BY(va_lock_);
VAConfigID va_config_id_{VA_INVALID_ID}; VAConfigID va_config_id_{VA_INVALID_ID};
// Created in CreateContext() or CreateContextAndSurfaces() and valid until // Created in CreateContext() or CreateContextAndSurfaces() and valid until
// DestroyContext() or DestroyContextAndSurfaces(). // DestroyContext() or DestroyContextAndSurfaces().

View file

@ -29,7 +29,6 @@
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h" #include "base/task/single_thread_task_runner.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/types/optional_util.h" #include "base/types/optional_util.h"
#include "base/values.h" #include "base/values.h"
#include "build/build_config.h" #include "build/build_config.h"
@ -44,6 +43,7 @@
#include "net/base/privacy_mode.h" #include "net/base/privacy_mode.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/base/trace_constants.h" #include "net/base/trace_constants.h"
#include "net/base/tracing.h"
#include "net/base/url_util.h" #include "net/base/url_util.h"
#include "net/cert/cert_status_flags.h" #include "net/cert/cert_status_flags.h"
#include "net/cert/ct_policy_status.h" #include "net/cert/ct_policy_status.h"

View file

@ -515,6 +515,10 @@ if (build_with_chromium) {
data = [ "google/test/data/" ] data = [ "google/test/data/" ]
if (is_ios) {
bundle_deps = [ "google:zlib_pak_bundle_data" ]
}
deps = [ deps = [
":zlib", ":zlib",
"google:compression_utils", "google:compression_utils",