summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--license.txt937
-rw-r--r--src/common/logging/filter.cpp1
-rw-r--r--src/common/logging/types.h1
-rw-r--r--src/common/math_util.h50
-rw-r--r--src/core/CMakeLists.txt29
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h7
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp7
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h10
-rw-r--r--src/core/hle/service/nvdrv/nvdata.h10
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h3
-rw-r--r--src/core/hle/service/nvflinger/binder.h42
-rw-r--r--src/core/hle/service/nvflinger/buffer_item.h46
-rw-r--r--src/core/hle/service/nvflinger/buffer_item_consumer.cpp59
-rw-r--r--src/core/hle/service/nvflinger/buffer_item_consumer.h28
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.cpp225
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.h37
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.cpp134
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.h99
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_defs.h21
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.cpp937
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.h83
-rw-r--r--src/core/hle/service/nvflinger/buffer_slot.h39
-rw-r--r--src/core/hle/service/nvflinger/buffer_transform_flags.h25
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.cpp130
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.h61
-rw-r--r--src/core/hle/service/nvflinger/consumer_listener.h26
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.cpp20
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.h76
-rw-r--r--src/core/hle/service/nvflinger/hos_binder_driver_server.cpp36
-rw-r--r--src/core/hle/service/nvflinger/hos_binder_driver_server.h37
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp81
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h26
-rw-r--r--src/core/hle/service/nvflinger/parcel.h172
-rw-r--r--src/core/hle/service/nvflinger/pixel_format.h21
-rw-r--r--src/core/hle/service/nvflinger/producer_listener.h16
-rw-r--r--src/core/hle/service/nvflinger/status.h28
-rw-r--r--src/core/hle/service/nvflinger/ui/fence.h32
-rw-r--r--src/core/hle/service/nvflinger/ui/graphic_buffer.h100
-rw-r--r--src/core/hle/service/nvflinger/window.h53
-rw-r--r--src/core/hle/service/service.cpp6
-rw-r--r--src/core/hle/service/service.h4
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp50
-rw-r--r--src/core/hle/service/vi/display/vi_display.h29
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp6
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h57
-rw-r--r--src/core/hle/service/vi/vi.cpp690
-rw-r--r--src/core/hle/service/vi/vi.h10
-rw-r--r--src/core/hle/service/vi/vi_m.cpp9
-rw-r--r--src/core/hle/service/vi/vi_m.h7
-rw-r--r--src/core/hle/service/vi/vi_s.cpp9
-rw-r--r--src/core/hle/service/vi/vi_s.h7
-rw-r--r--src/core/hle/service/vi/vi_u.cpp9
-rw-r--r--src/core/hle/service/vi/vi_u.h7
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.cpp5
-rw-r--r--src/shader_recompiler/frontend/ir/value.h4
-rw-r--r--src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp98
-rw-r--r--src/video_core/framebuffer_config.h29
-rw-r--r--src/video_core/gpu.h1
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp8
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp10
-rw-r--r--src/video_core/surface.cpp8
-rw-r--r--src/video_core/surface.h2
65 files changed, 3707 insertions, 1121 deletions
diff --git a/README.md b/README.md
index c09d49ca4..139eb8599 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,6 @@ If you wish to support us a different way, please join our [Discord](https://dis
77 77
78## License 78## License
79 79
80yuzu is licensed under the GPLv2 (or any later version). Refer to the [license.txt](https://github.com/yuzu-emu/yuzu/blob/master/license.txt) file. 80yuzu is licensed under the GPLv3 (or any later version). Refer to the [license.txt](https://github.com/yuzu-emu/yuzu/blob/master/license.txt) file.
81 81
82The [Skyline-Emulator Team](https://github.com/skyline-emu/skyline) is exempt from GPLv2 for the contributions from all these contributors [FernandoS27](https://github.com/FernandoS27), [lioncash](https://github.com/lioncash), [bunnei](https://github.com/bunnei), [ReinUsesLisp](https://github.com/ReinUsesLisp), [Morph1984](https://github.com/Morph1984), [ogniK5377](https://github.com/ogniK5377), [german77](https://github.com/german77), [ameerj](https://github.com/ameerj), [Kelebek1](https://github.com/Kelebek1) and [lat9nq](https://github.com/lat9nq). They may only use the code from these contributors under Mozilla Public License, version 2.0. 82The [Skyline-Emulator Team](https://github.com/skyline-emu/skyline) is exempt from GPLv3 for the contributions from all these contributors [FernandoS27](https://github.com/FernandoS27), [lioncash](https://github.com/lioncash), [bunnei](https://github.com/bunnei), [ReinUsesLisp](https://github.com/ReinUsesLisp), [Morph1984](https://github.com/Morph1984), [ogniK5377](https://github.com/ogniK5377), [german77](https://github.com/german77), [ameerj](https://github.com/ameerj), [Kelebek1](https://github.com/Kelebek1) and [lat9nq](https://github.com/lat9nq). They may only use the code from these contributors under Mozilla Public License, version 2.0.
diff --git a/license.txt b/license.txt
index 495f3e676..e72bfddab 100644
--- a/license.txt
+++ b/license.txt
@@ -1,285 +1,626 @@
1 GNU GENERAL PUBLIC LICENSE 1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991 2 Version 3, 29 June 2007
3 3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 4 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies 5 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed. 6 of this license document, but changing it is not allowed.
8 7
9 Preamble 8 Preamble
10 9
11 The licenses for most software are designed to take away your 10 The GNU General Public License is a free, copyleft license for
12freedom to share and change it. By contrast, the GNU General Public 11software and other kinds of works.
13License is intended to guarantee your freedom to share and change free 12
14software--to make sure the software is free for all its users. This 13 The licenses for most software and other practical works are designed
15General Public License applies to most of the Free Software 14to take away your freedom to share and change the works. By contrast,
16Foundation's software and to any other program whose authors commit to 15the GNU General Public License is intended to guarantee your freedom to
17using it. (Some other Free Software Foundation software is covered by 16share and change all versions of a program--to make sure it remains free
18the GNU Lesser General Public License instead.) You can apply it to 17software for all its users. We, the Free Software Foundation, use the
18GNU General Public License for most of our software; it applies also to
19any other work released this way by its authors. You can apply it to
19your programs, too. 20your programs, too.
20 21
21 When we speak of free software, we are referring to freedom, not 22 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you 23price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for 24have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it 25them if you wish), that you receive source code or can get it if you
25if you want it, that you can change the software or use pieces of it 26want it, that you can change the software or use pieces of it in new
26in new free programs; and that you know you can do these things. 27free programs, and that you know you can do these things.
27 28
28 To protect your rights, we need to make restrictions that forbid 29 To protect your rights, we need to prevent others from denying you
29anyone to deny you these rights or to ask you to surrender the rights. 30these rights or asking you to surrender the rights. Therefore, you have
30These restrictions translate to certain responsibilities for you if you 31certain responsibilities if you distribute copies of the software, or if
31distribute copies of the software, or if you modify it. 32you modify it: responsibilities to respect the freedom of others.
32 33
33 For example, if you distribute copies of such a program, whether 34 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that 35gratis or for a fee, you must pass on to the recipients the same
35you have. You must make sure that they, too, receive or can get the 36freedoms that you received. You must make sure that they, too, receive
36source code. And you must show them these terms so they know their 37or can get the source code. And you must show them these terms so they
37rights. 38know their rights.
38 39
39 We protect your rights with two steps: (1) copyright the software, and 40 Developers that use the GNU GPL protect your rights with two steps:
40(2) offer you this license which gives you legal permission to copy, 41(1) assert copyright on the software, and (2) offer you this License
41distribute and/or modify the software. 42giving you legal permission to copy, distribute and/or modify it.
42 43
43 Also, for each author's protection and ours, we want to make certain 44 For the developers' and authors' protection, the GPL clearly explains
44that everyone understands that there is no warranty for this free 45that there is no warranty for this free software. For both users' and
45software. If the software is modified by someone else and passed on, we 46authors' sake, the GPL requires that modified versions be marked as
46want its recipients to know that what they have is not the original, so 47changed, so that their problems will not be attributed erroneously to
47that any problems introduced by others will not reflect on the original 48authors of previous versions.
48authors' reputations. 49
49 50 Some devices are designed to deny users access to install or run
50 Finally, any free program is threatened constantly by software 51modified versions of the software inside them, although the manufacturer
51patents. We wish to avoid the danger that redistributors of a free 52can do so. This is fundamentally incompatible with the aim of
52program will individually obtain patent licenses, in effect making the 53protecting users' freedom to change the software. The systematic
53program proprietary. To prevent this, we have made it clear that any 54pattern of such abuse occurs in the area of products for individuals to
54patent must be licensed for everyone's free use or not licensed at all. 55use, which is precisely where it is most unacceptable. Therefore, we
56have designed this version of the GPL to prohibit the practice for those
57products. If such problems arise substantially in other domains, we
58stand ready to extend this provision to those domains in future versions
59of the GPL, as needed to protect the freedom of users.
60
61 Finally, every program is threatened constantly by software patents.
62States should not allow patents to restrict development and use of
63software on general-purpose computers, but in those that do, we wish to
64avoid the special danger that patents applied to a free program could
65make it effectively proprietary. To prevent this, the GPL assures that
66patents cannot be used to render the program non-free.
55 67
56 The precise terms and conditions for copying, distribution and 68 The precise terms and conditions for copying, distribution and
57modification follow. 69modification follow.
58 70
59 GNU GENERAL PUBLIC LICENSE 71 TERMS AND CONDITIONS
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 72
61 73 0. Definitions.
62 0. This License applies to any program or other work which contains 74
63a notice placed by the copyright holder saying it may be distributed 75 "This License" refers to version 3 of the GNU General Public License.
64under the terms of this General Public License. The "Program", below, 76
65refers to any such program or work, and a "work based on the Program" 77 "Copyright" also means copyright-like laws that apply to other kinds of
66means either the Program or any derivative work under copyright law: 78works, such as semiconductor masks.
67that is to say, a work containing the Program or a portion of it, 79
68either verbatim or with modifications and/or translated into another 80 "The Program" refers to any copyrightable work licensed under this
69language. (Hereinafter, translation is included without limitation in 81License. Each licensee is addressed as "you". "Licensees" and
70the term "modification".) Each licensee is addressed as "you". 82"recipients" may be individuals or organizations.
71 83
72Activities other than copying, distribution and modification are not 84 To "modify" a work means to copy from or adapt all or part of the work
73covered by this License; they are outside its scope. The act of 85in a fashion requiring copyright permission, other than the making of an
74running the Program is not restricted, and the output from the Program 86exact copy. The resulting work is called a "modified version" of the
75is covered only if its contents constitute a work based on the 87earlier work or a work "based on" the earlier work.
76Program (independent of having been made by running the Program). 88
77Whether that is true depends on what the Program does. 89 A "covered work" means either the unmodified Program or a work based
78 90on the Program.
79 1. You may copy and distribute verbatim copies of the Program's 91
80source code as you receive it, in any medium, provided that you 92 To "propagate" a work means to do anything with it that, without
81conspicuously and appropriately publish on each copy an appropriate 93permission, would make you directly or secondarily liable for
82copyright notice and disclaimer of warranty; keep intact all the 94infringement under applicable copyright law, except executing it on a
83notices that refer to this License and to the absence of any warranty; 95computer or modifying a private copy. Propagation includes copying,
84and give any other recipients of the Program a copy of this License 96distribution (with or without modification), making available to the
85along with the Program. 97public, and in some countries other activities as well.
86 98
87You may charge a fee for the physical act of transferring a copy, and 99 To "convey" a work means any kind of propagation that enables other
88you may at your option offer warranty protection in exchange for a fee. 100parties to make or receive copies. Mere interaction with a user through
89 101a computer network, with no transfer of a copy, is not conveying.
90 2. You may modify your copy or copies of the Program or any portion 102
91of it, thus forming a work based on the Program, and copy and 103 An interactive user interface displays "Appropriate Legal Notices"
92distribute such modifications or work under the terms of Section 1 104to the extent that it includes a convenient and prominently visible
93above, provided that you also meet all of these conditions: 105feature that (1) displays an appropriate copyright notice, and (2)
94 106tells the user that there is no warranty for the work (except to the
95 a) You must cause the modified files to carry prominent notices 107extent that warranties are provided), that licensees may convey the
96 stating that you changed the files and the date of any change. 108work under this License, and how to view a copy of this License. If
97 109the interface presents a list of user commands or options, such as a
98 b) You must cause any work that you distribute or publish, that in 110menu, a prominent item in the list meets this criterion.
99 whole or in part contains or is derived from the Program or any 111
100 part thereof, to be licensed as a whole at no charge to all third 112 1. Source Code.
101 parties under the terms of this License. 113
102 114 The "source code" for a work means the preferred form of the work
103 c) If the modified program normally reads commands interactively 115for making modifications to it. "Object code" means any non-source
104 when run, you must cause it, when started running for such 116form of a work.
105 interactive use in the most ordinary way, to print or display an 117
106 announcement including an appropriate copyright notice and a 118 A "Standard Interface" means an interface that either is an official
107 notice that there is no warranty (or else, saying that you provide 119standard defined by a recognized standards body, or, in the case of
108 a warranty) and that users may redistribute the program under 120interfaces specified for a particular programming language, one that
109 these conditions, and telling the user how to view a copy of this 121is widely used among developers working in that language.
110 License. (Exception: if the Program itself is interactive but 122
111 does not normally print such an announcement, your work based on 123 The "System Libraries" of an executable work include anything, other
112 the Program is not required to print an announcement.) 124than the work as a whole, that (a) is included in the normal form of
113 125packaging a Major Component, but which is not part of that Major
114These requirements apply to the modified work as a whole. If 126Component, and (b) serves only to enable use of the work with that
115identifiable sections of that work are not derived from the Program, 127Major Component, or to implement a Standard Interface for which an
116and can be reasonably considered independent and separate works in 128implementation is available to the public in source code form. A
117themselves, then this License, and its terms, do not apply to those 129"Major Component", in this context, means a major essential component
118sections when you distribute them as separate works. But when you 130(kernel, window system, and so on) of the specific operating system
119distribute the same sections as part of a whole which is a work based 131(if any) on which the executable work runs, or a compiler used to
120on the Program, the distribution of the whole must be on the terms of 132produce the work, or an object code interpreter used to run it.
121this License, whose permissions for other licensees extend to the 133
122entire whole, and thus to each and every part regardless of who wrote it. 134 The "Corresponding Source" for a work in object code form means all
123 135the source code needed to generate, install, and (for an executable
124Thus, it is not the intent of this section to claim rights or contest 136work) run the object code and to modify the work, including scripts to
125your rights to work written entirely by you; rather, the intent is to 137control those activities. However, it does not include the work's
126exercise the right to control the distribution of derivative or 138System Libraries, or general-purpose tools or generally available free
127collective works based on the Program. 139programs which are used unmodified in performing those activities but
128 140which are not part of the work. For example, Corresponding Source
129In addition, mere aggregation of another work not based on the Program 141includes interface definition files associated with source files for
130with the Program (or with a work based on the Program) on a volume of 142the work, and the source code for shared libraries and dynamically
131a storage or distribution medium does not bring the other work under 143linked subprograms that the work is specifically designed to require,
132the scope of this License. 144such as by intimate data communication or control flow between those
133 145subprograms and other parts of the work.
134 3. You may copy and distribute the Program (or a work based on it, 146
135under Section 2) in object code or executable form under the terms of 147 The Corresponding Source need not include anything that users
136Sections 1 and 2 above provided that you also do one of the following: 148can regenerate automatically from other parts of the Corresponding
137 149Source.
138 a) Accompany it with the complete corresponding machine-readable 150
139 source code, which must be distributed under the terms of Sections 151 The Corresponding Source for a work in source code form is that
140 1 and 2 above on a medium customarily used for software interchange; or, 152same work.
141 153
142 b) Accompany it with a written offer, valid for at least three 154 2. Basic Permissions.
143 years, to give any third party, for a charge no more than your 155
144 cost of physically performing source distribution, a complete 156 All rights granted under this License are granted for the term of
145 machine-readable copy of the corresponding source code, to be 157copyright on the Program, and are irrevocable provided the stated
146 distributed under the terms of Sections 1 and 2 above on a medium 158conditions are met. This License explicitly affirms your unlimited
147 customarily used for software interchange; or, 159permission to run the unmodified Program. The output from running a
148 160covered work is covered by this License only if the output, given its
149 c) Accompany it with the information you received as to the offer 161content, constitutes a covered work. This License acknowledges your
150 to distribute corresponding source code. (This alternative is 162rights of fair use or other equivalent, as provided by copyright law.
151 allowed only for noncommercial distribution and only if you 163
152 received the program in object code or executable form with such 164 You may make, run and propagate covered works that you do not
153 an offer, in accord with Subsection b above.) 165convey, without conditions so long as your license otherwise remains
154 166in force. You may convey covered works to others for the sole purpose
155The source code for a work means the preferred form of the work for 167of having them make modifications exclusively for you, or provide you
156making modifications to it. For an executable work, complete source 168with facilities for running those works, provided that you comply with
157code means all the source code for all modules it contains, plus any 169the terms of this License in conveying all material for which you do
158associated interface definition files, plus the scripts used to 170not control copyright. Those thus making or running the covered works
159control compilation and installation of the executable. However, as a 171for you must do so exclusively on your behalf, under your direction
160special exception, the source code distributed need not include 172and control, on terms that prohibit them from making any copies of
161anything that is normally distributed (in either source or binary 173your copyrighted material outside their relationship with you.
162form) with the major components (compiler, kernel, and so on) of the 174
163operating system on which the executable runs, unless that component 175 Conveying under any other circumstances is permitted solely under
164itself accompanies the executable. 176the conditions stated below. Sublicensing is not allowed; section 10
165 177makes it unnecessary.
166If distribution of executable or object code is made by offering 178
167access to copy from a designated place, then offering equivalent 179 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
168access to copy the source code from the same place counts as 180
169distribution of the source code, even though third parties are not 181 No covered work shall be deemed part of an effective technological
170compelled to copy the source along with the object code. 182measure under any applicable law fulfilling obligations under article
171 18311 of the WIPO copyright treaty adopted on 20 December 1996, or
172 4. You may not copy, modify, sublicense, or distribute the Program 184similar laws prohibiting or restricting circumvention of such
173except as expressly provided under this License. Any attempt 185measures.
174otherwise to copy, modify, sublicense or distribute the Program is 186
175void, and will automatically terminate your rights under this License. 187 When you convey a covered work, you waive any legal power to forbid
176However, parties who have received copies, or rights, from you under 188circumvention of technological measures to the extent such circumvention
177this License will not have their licenses terminated so long as such 189is effected by exercising rights under this License with respect to
178parties remain in full compliance. 190the covered work, and you disclaim any intention to limit operation or
179 191modification of the work as a means of enforcing, against the work's
180 5. You are not required to accept this License, since you have not 192users, your or third parties' legal rights to forbid circumvention of
181signed it. However, nothing else grants you permission to modify or 193technological measures.
182distribute the Program or its derivative works. These actions are 194
183prohibited by law if you do not accept this License. Therefore, by 195 4. Conveying Verbatim Copies.
184modifying or distributing the Program (or any work based on the 196
185Program), you indicate your acceptance of this License to do so, and 197 You may convey verbatim copies of the Program's source code as you
186all its terms and conditions for copying, distributing or modifying 198receive it, in any medium, provided that you conspicuously and
187the Program or works based on it. 199appropriately publish on each copy an appropriate copyright notice;
188 200keep intact all notices stating that this License and any
189 6. Each time you redistribute the Program (or any work based on the 201non-permissive terms added in accord with section 7 apply to the code;
190Program), the recipient automatically receives a license from the 202keep intact all notices of the absence of any warranty; and give all
191original licensor to copy, distribute or modify the Program subject to 203recipients a copy of this License along with the Program.
192these terms and conditions. You may not impose any further 204
193restrictions on the recipients' exercise of the rights granted herein. 205 You may charge any price or no price for each copy that you convey,
194You are not responsible for enforcing compliance by third parties to 206and you may offer support or warranty protection for a fee.
207
208 5. Conveying Modified Source Versions.
209
210 You may convey a work based on the Program, or the modifications to
211produce it from the Program, in the form of source code under the
212terms of section 4, provided that you also meet all of these conditions:
213
214 a) The work must carry prominent notices stating that you modified
215 it, and giving a relevant date.
216
217 b) The work must carry prominent notices stating that it is
218 released under this License and any conditions added under section
219 7. This requirement modifies the requirement in section 4 to
220 "keep intact all notices".
221
222 c) You must license the entire work, as a whole, under this
223 License to anyone who comes into possession of a copy. This
224 License will therefore apply, along with any applicable section 7
225 additional terms, to the whole of the work, and all its parts,
226 regardless of how they are packaged. This License gives no
227 permission to license the work in any other way, but it does not
228 invalidate such permission if you have separately received it.
229
230 d) If the work has interactive user interfaces, each must display
231 Appropriate Legal Notices; however, if the Program has interactive
232 interfaces that do not display Appropriate Legal Notices, your
233 work need not make them do so.
234
235 A compilation of a covered work with other separate and independent
236works, which are not by their nature extensions of the covered work,
237and which are not combined with it such as to form a larger program,
238in or on a volume of a storage or distribution medium, is called an
239"aggregate" if the compilation and its resulting copyright are not
240used to limit the access or legal rights of the compilation's users
241beyond what the individual works permit. Inclusion of a covered work
242in an aggregate does not cause this License to apply to the other
243parts of the aggregate.
244
245 6. Conveying Non-Source Forms.
246
247 You may convey a covered work in object code form under the terms
248of sections 4 and 5, provided that you also convey the
249machine-readable Corresponding Source under the terms of this License,
250in one of these ways:
251
252 a) Convey the object code in, or embodied in, a physical product
253 (including a physical distribution medium), accompanied by the
254 Corresponding Source fixed on a durable physical medium
255 customarily used for software interchange.
256
257 b) Convey the object code in, or embodied in, a physical product
258 (including a physical distribution medium), accompanied by a
259 written offer, valid for at least three years and valid for as
260 long as you offer spare parts or customer support for that product
261 model, to give anyone who possesses the object code either (1) a
262 copy of the Corresponding Source for all the software in the
263 product that is covered by this License, on a durable physical
264 medium customarily used for software interchange, for a price no
265 more than your reasonable cost of physically performing this
266 conveying of source, or (2) access to copy the
267 Corresponding Source from a network server at no charge.
268
269 c) Convey individual copies of the object code with a copy of the
270 written offer to provide the Corresponding Source. This
271 alternative is allowed only occasionally and noncommercially, and
272 only if you received the object code with such an offer, in accord
273 with subsection 6b.
274
275 d) Convey the object code by offering access from a designated
276 place (gratis or for a charge), and offer equivalent access to the
277 Corresponding Source in the same way through the same place at no
278 further charge. You need not require recipients to copy the
279 Corresponding Source along with the object code. If the place to
280 copy the object code is a network server, the Corresponding Source
281 may be on a different server (operated by you or a third party)
282 that supports equivalent copying facilities, provided you maintain
283 clear directions next to the object code saying where to find the
284 Corresponding Source. Regardless of what server hosts the
285 Corresponding Source, you remain obligated to ensure that it is
286 available for as long as needed to satisfy these requirements.
287
288 e) Convey the object code using peer-to-peer transmission, provided
289 you inform other peers where the object code and Corresponding
290 Source of the work are being offered to the general public at no
291 charge under subsection 6d.
292
293 A separable portion of the object code, whose source code is excluded
294from the Corresponding Source as a System Library, need not be
295included in conveying the object code work.
296
297 A "User Product" is either (1) a "consumer product", which means any
298tangible personal property which is normally used for personal, family,
299or household purposes, or (2) anything designed or sold for incorporation
300into a dwelling. In determining whether a product is a consumer product,
301doubtful cases shall be resolved in favor of coverage. For a particular
302product received by a particular user, "normally used" refers to a
303typical or common use of that class of product, regardless of the status
304of the particular user or of the way in which the particular user
305actually uses, or expects or is expected to use, the product. A product
306is a consumer product regardless of whether the product has substantial
307commercial, industrial or non-consumer uses, unless such uses represent
308the only significant mode of use of the product.
309
310 "Installation Information" for a User Product means any methods,
311procedures, authorization keys, or other information required to install
312and execute modified versions of a covered work in that User Product from
313a modified version of its Corresponding Source. The information must
314suffice to ensure that the continued functioning of the modified object
315code is in no case prevented or interfered with solely because
316modification has been made.
317
318 If you convey an object code work under this section in, or with, or
319specifically for use in, a User Product, and the conveying occurs as
320part of a transaction in which the right of possession and use of the
321User Product is transferred to the recipient in perpetuity or for a
322fixed term (regardless of how the transaction is characterized), the
323Corresponding Source conveyed under this section must be accompanied
324by the Installation Information. But this requirement does not apply
325if neither you nor any third party retains the ability to install
326modified object code on the User Product (for example, the work has
327been installed in ROM).
328
329 The requirement to provide Installation Information does not include a
330requirement to continue to provide support service, warranty, or updates
331for a work that has been modified or installed by the recipient, or for
332the User Product in which it has been modified or installed. Access to a
333network may be denied when the modification itself materially and
334adversely affects the operation of the network or violates the rules and
335protocols for communication across the network.
336
337 Corresponding Source conveyed, and Installation Information provided,
338in accord with this section must be in a format that is publicly
339documented (and with an implementation available to the public in
340source code form), and must require no special password or key for
341unpacking, reading or copying.
342
343 7. Additional Terms.
344
345 "Additional permissions" are terms that supplement the terms of this
346License by making exceptions from one or more of its conditions.
347Additional permissions that are applicable to the entire Program shall
348be treated as though they were included in this License, to the extent
349that they are valid under applicable law. If additional permissions
350apply only to part of the Program, that part may be used separately
351under those permissions, but the entire Program remains governed by
352this License without regard to the additional permissions.
353
354 When you convey a copy of a covered work, you may at your option
355remove any additional permissions from that copy, or from any part of
356it. (Additional permissions may be written to require their own
357removal in certain cases when you modify the work.) You may place
358additional permissions on material, added by you to a covered work,
359for which you have or can give appropriate copyright permission.
360
361 Notwithstanding any other provision of this License, for material you
362add to a covered work, you may (if authorized by the copyright holders of
363that material) supplement the terms of this License with terms:
364
365 a) Disclaiming warranty or limiting liability differently from the
366 terms of sections 15 and 16 of this License; or
367
368 b) Requiring preservation of specified reasonable legal notices or
369 author attributions in that material or in the Appropriate Legal
370 Notices displayed by works containing it; or
371
372 c) Prohibiting misrepresentation of the origin of that material, or
373 requiring that modified versions of such material be marked in
374 reasonable ways as different from the original version; or
375
376 d) Limiting the use for publicity purposes of names of licensors or
377 authors of the material; or
378
379 e) Declining to grant rights under trademark law for use of some
380 trade names, trademarks, or service marks; or
381
382 f) Requiring indemnification of licensors and authors of that
383 material by anyone who conveys the material (or modified versions of
384 it) with contractual assumptions of liability to the recipient, for
385 any liability that these contractual assumptions directly impose on
386 those licensors and authors.
387
388 All other non-permissive additional terms are considered "further
389restrictions" within the meaning of section 10. If the Program as you
390received it, or any part of it, contains a notice stating that it is
391governed by this License along with a term that is a further
392restriction, you may remove that term. If a license document contains
393a further restriction but permits relicensing or conveying under this
394License, you may add to a covered work material governed by the terms
395of that license document, provided that the further restriction does
396not survive such relicensing or conveying.
397
398 If you add terms to a covered work in accord with this section, you
399must place, in the relevant source files, a statement of the
400additional terms that apply to those files, or a notice indicating
401where to find the applicable terms.
402
403 Additional terms, permissive or non-permissive, may be stated in the
404form of a separately written license, or stated as exceptions;
405the above requirements apply either way.
406
407 8. Termination.
408
409 You may not propagate or modify a covered work except as expressly
410provided under this License. Any attempt otherwise to propagate or
411modify it is void, and will automatically terminate your rights under
412this License (including any patent licenses granted under the third
413paragraph of section 11).
414
415 However, if you cease all violation of this License, then your
416license from a particular copyright holder is reinstated (a)
417provisionally, unless and until the copyright holder explicitly and
418finally terminates your license, and (b) permanently, if the copyright
419holder fails to notify you of the violation by some reasonable means
420prior to 60 days after the cessation.
421
422 Moreover, your license from a particular copyright holder is
423reinstated permanently if the copyright holder notifies you of the
424violation by some reasonable means, this is the first time you have
425received notice of violation of this License (for any work) from that
426copyright holder, and you cure the violation prior to 30 days after
427your receipt of the notice.
428
429 Termination of your rights under this section does not terminate the
430licenses of parties who have received copies or rights from you under
431this License. If your rights have been terminated and not permanently
432reinstated, you do not qualify to receive new licenses for the same
433material under section 10.
434
435 9. Acceptance Not Required for Having Copies.
436
437 You are not required to accept this License in order to receive or
438run a copy of the Program. Ancillary propagation of a covered work
439occurring solely as a consequence of using peer-to-peer transmission
440to receive a copy likewise does not require acceptance. However,
441nothing other than this License grants you permission to propagate or
442modify any covered work. These actions infringe copyright if you do
443not accept this License. Therefore, by modifying or propagating a
444covered work, you indicate your acceptance of this License to do so.
445
446 10. Automatic Licensing of Downstream Recipients.
447
448 Each time you convey a covered work, the recipient automatically
449receives a license from the original licensors, to run, modify and
450propagate that work, subject to this License. You are not responsible
451for enforcing compliance by third parties with this License.
452
453 An "entity transaction" is a transaction transferring control of an
454organization, or substantially all assets of one, or subdividing an
455organization, or merging organizations. If propagation of a covered
456work results from an entity transaction, each party to that
457transaction who receives a copy of the work also receives whatever
458licenses to the work the party's predecessor in interest had or could
459give under the previous paragraph, plus a right to possession of the
460Corresponding Source of the work from the predecessor in interest, if
461the predecessor has it or can get it with reasonable efforts.
462
463 You may not impose any further restrictions on the exercise of the
464rights granted or affirmed under this License. For example, you may
465not impose a license fee, royalty, or other charge for exercise of
466rights granted under this License, and you may not initiate litigation
467(including a cross-claim or counterclaim in a lawsuit) alleging that
468any patent claim is infringed by making, using, selling, offering for
469sale, or importing the Program or any portion of it.
470
471 11. Patents.
472
473 A "contributor" is a copyright holder who authorizes use under this
474License of the Program or a work on which the Program is based. The
475work thus licensed is called the contributor's "contributor version".
476
477 A contributor's "essential patent claims" are all patent claims
478owned or controlled by the contributor, whether already acquired or
479hereafter acquired, that would be infringed by some manner, permitted
480by this License, of making, using, or selling its contributor version,
481but do not include claims that would be infringed only as a
482consequence of further modification of the contributor version. For
483purposes of this definition, "control" includes the right to grant
484patent sublicenses in a manner consistent with the requirements of
195this License. 485this License.
196 486
197 7. If, as a consequence of a court judgment or allegation of patent 487 Each contributor grants you a non-exclusive, worldwide, royalty-free
198infringement or for any other reason (not limited to patent issues), 488patent license under the contributor's essential patent claims, to
199conditions are imposed on you (whether by court order, agreement or 489make, use, sell, offer for sale, import and otherwise run, modify and
490propagate the contents of its contributor version.
491
492 In the following three paragraphs, a "patent license" is any express
493agreement or commitment, however denominated, not to enforce a patent
494(such as an express permission to practice a patent or covenant not to
495sue for patent infringement). To "grant" such a patent license to a
496party means to make such an agreement or commitment not to enforce a
497patent against the party.
498
499 If you convey a covered work, knowingly relying on a patent license,
500and the Corresponding Source of the work is not available for anyone
501to copy, free of charge and under the terms of this License, through a
502publicly available network server or other readily accessible means,
503then you must either (1) cause the Corresponding Source to be so
504available, or (2) arrange to deprive yourself of the benefit of the
505patent license for this particular work, or (3) arrange, in a manner
506consistent with the requirements of this License, to extend the patent
507license to downstream recipients. "Knowingly relying" means you have
508actual knowledge that, but for the patent license, your conveying the
509covered work in a country, or your recipient's use of the covered work
510in a country, would infringe one or more identifiable patents in that
511country that you have reason to believe are valid.
512
513 If, pursuant to or in connection with a single transaction or
514arrangement, you convey, or propagate by procuring conveyance of, a
515covered work, and grant a patent license to some of the parties
516receiving the covered work authorizing them to use, propagate, modify
517or convey a specific copy of the covered work, then the patent license
518you grant is automatically extended to all recipients of the covered
519work and works based on it.
520
521 A patent license is "discriminatory" if it does not include within
522the scope of its coverage, prohibits the exercise of, or is
523conditioned on the non-exercise of one or more of the rights that are
524specifically granted under this License. You may not convey a covered
525work if you are a party to an arrangement with a third party that is
526in the business of distributing software, under which you make payment
527to the third party based on the extent of your activity of conveying
528the work, and under which the third party grants, to any of the
529parties who would receive the covered work from you, a discriminatory
530patent license (a) in connection with copies of the covered work
531conveyed by you (or copies made from those copies), or (b) primarily
532for and in connection with specific products or compilations that
533contain the covered work, unless you entered into that arrangement,
534or that patent license was granted, prior to 28 March 2007.
535
536 Nothing in this License shall be construed as excluding or limiting
537any implied license or other defenses to infringement that may
538otherwise be available to you under applicable patent law.
539
540 12. No Surrender of Others' Freedom.
541
542 If conditions are imposed on you (whether by court order, agreement or
200otherwise) that contradict the conditions of this License, they do not 543otherwise) that contradict the conditions of this License, they do not
201excuse you from the conditions of this License. If you cannot 544excuse you from the conditions of this License. If you cannot convey a
202distribute so as to satisfy simultaneously your obligations under this 545covered work so as to satisfy simultaneously your obligations under this
203License and any other pertinent obligations, then as a consequence you 546License and any other pertinent obligations, then as a consequence you may
204may not distribute the Program at all. For example, if a patent 547not convey it at all. For example, if you agree to terms that obligate you
205license would not permit royalty-free redistribution of the Program by 548to collect a royalty for further conveying from those to whom you convey
206all those who receive copies directly or indirectly through you, then 549the Program, the only way you could satisfy both those terms and this
207the only way you could satisfy both it and this License would be to 550License would be to refrain entirely from conveying the Program.
208refrain entirely from distribution of the Program. 551
209 552 13. Use with the GNU Affero General Public License.
210If any portion of this section is held invalid or unenforceable under 553
211any particular circumstance, the balance of the section is intended to 554 Notwithstanding any other provision of this License, you have
212apply and the section as a whole is intended to apply in other 555permission to link or combine any covered work with a work licensed
213circumstances. 556under version 3 of the GNU Affero General Public License into a single
214 557combined work, and to convey the resulting work. The terms of this
215It is not the purpose of this section to induce you to infringe any 558License will continue to apply to the part which is the covered work,
216patents or other property right claims or to contest validity of any 559but the special requirements of the GNU Affero General Public License,
217such claims; this section has the sole purpose of protecting the 560section 13, concerning interaction through a network will apply to the
218integrity of the free software distribution system, which is 561combination as such.
219implemented by public license practices. Many people have made 562
220generous contributions to the wide range of software distributed 563 14. Revised Versions of this License.
221through that system in reliance on consistent application of that 564
222system; it is up to the author/donor to decide if he or she is willing 565 The Free Software Foundation may publish revised and/or new versions of
223to distribute software through any other system and a licensee cannot 566the GNU General Public License from time to time. Such new versions will
224impose that choice.
225
226This section is intended to make thoroughly clear what is believed to
227be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230certain countries either by patents or by copyrighted interfaces, the
231original copyright holder who places the Program under this License
232may add an explicit geographical distribution limitation excluding
233those countries, so that distribution is permitted only in or among
234countries not thus excluded. In such case, this License incorporates
235the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238of the General Public License from time to time. Such new versions will
239be similar in spirit to the present version, but may differ in detail to 567be similar in spirit to the present version, but may differ in detail to
240address new problems or concerns. 568address new problems or concerns.
241 569
242Each version is given a distinguishing version number. If the Program 570 Each version is given a distinguishing version number. If the
243specifies a version number of this License which applies to it and "any 571Program specifies that a certain numbered version of the GNU General
244later version", you have the option of following the terms and conditions 572Public License "or any later version" applies to it, you have the
245either of that version or of any later version published by the Free 573option of following the terms and conditions either of that numbered
246Software Foundation. If the Program does not specify a version number of 574version or of any later version published by the Free Software
247this License, you may choose any version ever published by the Free Software 575Foundation. If the Program does not specify a version number of the
248Foundation. 576GNU General Public License, you may choose any version ever published
249 577by the Free Software Foundation.
250 10. If you wish to incorporate parts of the Program into other free 578
251programs whose distribution conditions are different, write to the author 579 If the Program specifies that a proxy can decide which future
252to ask for permission. For software which is copyrighted by the Free 580versions of the GNU General Public License can be used, that proxy's
253Software Foundation, write to the Free Software Foundation; we sometimes 581public statement of acceptance of a version permanently authorizes you
254make exceptions for this. Our decision will be guided by the two goals 582to choose that version for the Program.
255of preserving the free status of all derivatives of our free software and 583
256of promoting the sharing and reuse of software generally. 584 Later license versions may give you additional or different
257 585permissions. However, no additional obligations are imposed on any
258 NO WARRANTY 586author or copyright holder as a result of your choosing to follow a
259 587later version.
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 588
261FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 589 15. Disclaimer of Warranty.
262OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 590
263PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 591 THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
264OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 592APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
265MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 593HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
266TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 594OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
267PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 595THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
268REPAIR OR CORRECTION. 596PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
269 597IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 598ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
271WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 599
272REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 600 16. Limitation of Liability.
273INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 601
274OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 602 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
275TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 603WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
276YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 604THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
277PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 605GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
278POSSIBILITY OF SUCH DAMAGES. 606USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
279 607DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
280 END OF TERMS AND CONDITIONS 608PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
281 609EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
282 How to Apply These Terms to Your New Programs 610SUCH DAMAGES.
611
612 17. Interpretation of Sections 15 and 16.
613
614 If the disclaimer of warranty and limitation of liability provided
615above cannot be given local legal effect according to their terms,
616reviewing courts shall apply local law that most closely approximates
617an absolute waiver of all civil liability in connection with the
618Program, unless a warranty or assumption of liability accompanies a
619copy of the Program in return for a fee.
620
621 END OF TERMS AND CONDITIONS
622
623 How to Apply These Terms to Your New Programs
283 624
284 If you develop a new program, and you want it to be of the greatest 625 If you develop a new program, and you want it to be of the greatest
285possible use to the public, the best way to achieve this is to make it 626possible use to the public, the best way to achieve this is to make it
@@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms.
287 628
288 To do so, attach the following notices to the program. It is safest 629 To do so, attach the following notices to the program. It is safest
289to attach them to the start of each source file to most effectively 630to attach them to the start of each source file to most effectively
290convey the exclusion of warranty; and each file should have at least 631state the exclusion of warranty; and each file should have at least
291the "copyright" line and a pointer to where the full notice is found. 632the "copyright" line and a pointer to where the full notice is found.
292 633
293 <one line to give the program's name and a brief idea of what it does.> 634 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) <year> <name of author> 635 Copyright (C) <year> <name of author>
295 636
296 This program is free software; you can redistribute it and/or modify 637 This program is free software: you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by 638 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or 639 the Free Software Foundation, either version 3 of the License, or
299 (at your option) any later version. 640 (at your option) any later version.
300 641
301 This program is distributed in the hope that it will be useful, 642 This program is distributed in the hope that it will be useful,
@@ -303,63 +644,31 @@ the "copyright" line and a pointer to where the full notice is found.
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 644 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details. 645 GNU General Public License for more details.
305 646
306 You should have received a copy of the GNU General Public License along 647 You should have received a copy of the GNU General Public License
307 with this program; if not, write to the Free Software Foundation, Inc., 648 along with this program. If not, see <https://www.gnu.org/licenses/>.
308 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 649
310Also add information on how to contact you by electronic and paper mail. 650Also add information on how to contact you by electronic and paper mail.
311 651
312If the program is interactive, make it output a short notice like this 652 If the program does terminal interaction, make it output a short
313when it starts in an interactive mode: 653notice like this when it starts in an interactive mode:
314 654
315 Gnomovision version 69, Copyright (C) year name of author 655 <program> Copyright (C) <year> <name of author>
316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 656 This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 This is free software, and you are welcome to redistribute it 657 This is free software, and you are welcome to redistribute it
318 under certain conditions; type `show c' for details. 658 under certain conditions; type `show c' for details.
319 659
320The hypothetical commands `show w' and `show c' should show the appropriate 660The hypothetical commands `show w' and `show c' should show the appropriate
321parts of the General Public License. Of course, the commands you use may 661parts of the General Public License. Of course, your program's commands
322be called something other than `show w' and `show c'; they could even be 662might be different; for a GUI interface, you would use an "about box".
323mouse-clicks or menu items--whatever suits your program. 663
324 664 You should also get your employer (if you work as a programmer) or school,
325You should also get your employer (if you work as a programmer) or your 665if any, to sign a "copyright disclaimer" for the program, if necessary.
326school, if any, to sign a "copyright disclaimer" for the program, if 666For more information on this, and how to apply and follow the GNU GPL, see
327necessary. Here is a sample; alter the names: 667<https://www.gnu.org/licenses/>.
328 668
329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program 669 The GNU General Public License does not permit incorporating your program
330 `Gnomovision' (which makes passes at compilers) written by James Hacker. 670into proprietary programs. If your program is a subroutine library, you
331 671may consider it more useful to permit linking proprietary applications with
332 <signature of Ty Coon>, 1 April 1989 672the library. If this is what you want to do, use the GNU Lesser General
333 Ty Coon, President of Vice 673Public License instead of this License. But first, please read
334 674<https://www.gnu.org/licenses/why-not-lgpl.html>. \ No newline at end of file
335This General Public License does not permit incorporating your program into
336proprietary programs. If your program is a subroutine library, you may
337consider it more useful to permit linking proprietary applications with the
338library. If this is what you want to do, use the GNU Lesser General
339Public License instead of this License.
340
341
342The icons used in this project have the following licenses:
343
344Icon Name | License | Origin/Author
345--- | --- | ---
346checked.png | CC BY-ND 3.0 | https://icons8.com
347failed.png | CC BY-ND 3.0 | https://icons8.com
348lock.png | CC BY-ND 3.0 | https://icons8.com
349plus_folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com
350bad_folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com
351chip.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com
352folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com
353plus.png (Default, Dark) | CC0 1.0 | Designed by BreadFish64 from the Citra team
354sd_card.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com
355plus_folder.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
356bad_folder.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
357chip.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
358folder.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
359plus.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
360sd_card.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
361star.png | CC BY-ND 3.0 | https://icons8.com
362
363Note:
364Some icons are different in different themes, and they are separately listed
365only when they have different licenses/origins.
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 4afc1369a..9120cc178 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -119,6 +119,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
119 SUB(Service, NPNS) \ 119 SUB(Service, NPNS) \
120 SUB(Service, NS) \ 120 SUB(Service, NS) \
121 SUB(Service, NVDRV) \ 121 SUB(Service, NVDRV) \
122 SUB(Service, NVFlinger) \
122 SUB(Service, OLSC) \ 123 SUB(Service, OLSC) \
123 SUB(Service, PCIE) \ 124 SUB(Service, PCIE) \
124 SUB(Service, PCTL) \ 125 SUB(Service, PCTL) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index 2b6e4daa7..f803ab796 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -87,6 +87,7 @@ enum class Class : u8 {
87 Service_NPNS, ///< The NPNS service 87 Service_NPNS, ///< The NPNS service
88 Service_NS, ///< The NS services 88 Service_NS, ///< The NS services
89 Service_NVDRV, ///< The NVDRV (Nvidia driver) service 89 Service_NVDRV, ///< The NVDRV (Nvidia driver) service
90 Service_NVFlinger, ///< The NVFlinger service
90 Service_OLSC, ///< The OLSC service 91 Service_OLSC, ///< The OLSC service
91 Service_PCIE, ///< The PCIe service 92 Service_PCIE, ///< The PCIe service
92 Service_PCTL, ///< The PCTL (Parental control) service 93 Service_PCTL, ///< The PCTL (Parental control) service
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 510c4e56d..54485bf53 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
7#include <cstdlib> 8#include <cstdlib>
8#include <type_traits> 9#include <type_traits>
9 10
@@ -20,10 +21,32 @@ struct Rectangle {
20 21
21 constexpr Rectangle() = default; 22 constexpr Rectangle() = default;
22 23
24 constexpr Rectangle(T width, T height) : right(width), bottom(height) {}
25
23 constexpr Rectangle(T left_, T top_, T right_, T bottom_) 26 constexpr Rectangle(T left_, T top_, T right_, T bottom_)
24 : left(left_), top(top_), right(right_), bottom(bottom_) {} 27 : left(left_), top(top_), right(right_), bottom(bottom_) {}
25 28
26 [[nodiscard]] T GetWidth() const { 29 [[nodiscard]] constexpr T Left() const {
30 return left;
31 }
32
33 [[nodiscard]] constexpr T Top() const {
34 return top;
35 }
36
37 [[nodiscard]] constexpr T Right() const {
38 return right;
39 }
40
41 [[nodiscard]] constexpr T Bottom() const {
42 return bottom;
43 }
44
45 [[nodiscard]] constexpr bool IsEmpty() const {
46 return (GetWidth() <= 0) || (GetHeight() <= 0);
47 }
48
49 [[nodiscard]] constexpr T GetWidth() const {
27 if constexpr (std::is_floating_point_v<T>) { 50 if constexpr (std::is_floating_point_v<T>) {
28 return std::abs(right - left); 51 return std::abs(right - left);
29 } else { 52 } else {
@@ -31,7 +54,7 @@ struct Rectangle {
31 } 54 }
32 } 55 }
33 56
34 [[nodiscard]] T GetHeight() const { 57 [[nodiscard]] constexpr T GetHeight() const {
35 if constexpr (std::is_floating_point_v<T>) { 58 if constexpr (std::is_floating_point_v<T>) {
36 return std::abs(bottom - top); 59 return std::abs(bottom - top);
37 } else { 60 } else {
@@ -39,18 +62,35 @@ struct Rectangle {
39 } 62 }
40 } 63 }
41 64
42 [[nodiscard]] Rectangle<T> TranslateX(const T x) const { 65 [[nodiscard]] constexpr Rectangle<T> TranslateX(const T x) const {
43 return Rectangle{left + x, top, right + x, bottom}; 66 return Rectangle{left + x, top, right + x, bottom};
44 } 67 }
45 68
46 [[nodiscard]] Rectangle<T> TranslateY(const T y) const { 69 [[nodiscard]] constexpr Rectangle<T> TranslateY(const T y) const {
47 return Rectangle{left, top + y, right, bottom + y}; 70 return Rectangle{left, top + y, right, bottom + y};
48 } 71 }
49 72
50 [[nodiscard]] Rectangle<T> Scale(const float s) const { 73 [[nodiscard]] constexpr Rectangle<T> Scale(const float s) const {
51 return Rectangle{left, top, static_cast<T>(static_cast<float>(left + GetWidth()) * s), 74 return Rectangle{left, top, static_cast<T>(static_cast<float>(left + GetWidth()) * s),
52 static_cast<T>(static_cast<float>(top + GetHeight()) * s)}; 75 static_cast<T>(static_cast<float>(top + GetHeight()) * s)};
53 } 76 }
77
78 [[nodiscard]] constexpr bool operator==(const Rectangle<T>& rhs) const {
79 return (left == rhs.left) && (top == rhs.top) && (right == rhs.right) &&
80 (bottom == rhs.bottom);
81 }
82
83 [[nodiscard]] constexpr bool operator!=(const Rectangle<T>& rhs) const {
84 return !operator==(rhs);
85 }
86
87 [[nodiscard]] constexpr bool Intersect(const Rectangle<T>& with, Rectangle<T>* result) const {
88 result->left = std::max(left, with.left);
89 result->top = std::max(top, with.top);
90 result->right = std::min(right, with.right);
91 result->bottom = std::min(bottom, with.bottom);
92 return !result->IsEmpty();
93 }
54}; 94};
55 95
56template <typename T> 96template <typename T>
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a6f442316..6536d0544 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -535,10 +535,35 @@ add_library(core STATIC
535 hle/service/nvdrv/nvmemp.h 535 hle/service/nvdrv/nvmemp.h
536 hle/service/nvdrv/syncpoint_manager.cpp 536 hle/service/nvdrv/syncpoint_manager.cpp
537 hle/service/nvdrv/syncpoint_manager.h 537 hle/service/nvdrv/syncpoint_manager.h
538 hle/service/nvflinger/buffer_queue.cpp 538 hle/service/nvflinger/binder.h
539 hle/service/nvflinger/buffer_queue.h 539 hle/service/nvflinger/buffer_item.h
540 hle/service/nvflinger/buffer_item_consumer.cpp
541 hle/service/nvflinger/buffer_item_consumer.h
542 hle/service/nvflinger/buffer_queue_consumer.cpp
543 hle/service/nvflinger/buffer_queue_consumer.h
544 hle/service/nvflinger/buffer_queue_core.cpp
545 hle/service/nvflinger/buffer_queue_core.h
546 hle/service/nvflinger/buffer_queue_defs.h
547 hle/service/nvflinger/buffer_queue_producer.cpp
548 hle/service/nvflinger/buffer_queue_producer.h
549 hle/service/nvflinger/buffer_slot.h
550 hle/service/nvflinger/buffer_transform_flags.h
551 hle/service/nvflinger/consumer_base.cpp
552 hle/service/nvflinger/consumer_base.h
553 hle/service/nvflinger/consumer_listener.h
554 hle/service/nvflinger/graphic_buffer_producer.cpp
555 hle/service/nvflinger/graphic_buffer_producer.h
556 hle/service/nvflinger/hos_binder_driver_server.cpp
557 hle/service/nvflinger/hos_binder_driver_server.h
540 hle/service/nvflinger/nvflinger.cpp 558 hle/service/nvflinger/nvflinger.cpp
541 hle/service/nvflinger/nvflinger.h 559 hle/service/nvflinger/nvflinger.h
560 hle/service/nvflinger/parcel.h
561 hle/service/nvflinger/pixel_format.h
562 hle/service/nvflinger/producer_listener.h
563 hle/service/nvflinger/status.h
564 hle/service/nvflinger/ui/fence.h
565 hle/service/nvflinger/ui/graphic_buffer.h
566 hle/service/nvflinger/window.h
542 hle/service/olsc/olsc.cpp 567 hle/service/olsc/olsc.cpp
543 hle/service/olsc/olsc.h 568 hle/service/olsc/olsc.h
544 hle/service/pcie/pcie.cpp 569 hle/service/pcie/pcie.cpp
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 68f1e9060..9fad45fe1 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -38,18 +38,16 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>&
38void nvdisp_disp0::OnOpen(DeviceFD fd) {} 38void nvdisp_disp0::OnOpen(DeviceFD fd) {}
39void nvdisp_disp0::OnClose(DeviceFD fd) {} 39void nvdisp_disp0::OnClose(DeviceFD fd) {}
40 40
41void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, 41void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width,
42 u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform, 42 u32 height, u32 stride, android::BufferTransformFlags transform,
43 const Common::Rectangle<int>& crop_rect) { 43 const Common::Rectangle<int>& crop_rect) {
44 const VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); 44 const VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
45 LOG_TRACE(Service, 45 LOG_TRACE(Service,
46 "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", 46 "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
47 addr, offset, width, height, stride, format); 47 addr, offset, width, height, stride, format);
48 48
49 const auto pixel_format = static_cast<Tegra::FramebufferConfig::PixelFormat>(format); 49 const Tegra::FramebufferConfig framebuffer{addr, offset, width, height,
50 const auto transform_flags = static_cast<Tegra::FramebufferConfig::TransformFlags>(transform); 50 stride, format, transform, crop_rect};
51 const Tegra::FramebufferConfig framebuffer{addr, offset, width, height,
52 stride, pixel_format, transform_flags, crop_rect};
53 51
54 system.GetPerfStats().EndSystemFrame(); 52 system.GetPerfStats().EndSystemFrame();
55 system.GPU().SwapBuffers(&framebuffer); 53 system.GPU().SwapBuffers(&framebuffer);
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index de01e1d5f..30b5da429 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -9,7 +9,8 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/math_util.h" 10#include "common/math_util.h"
11#include "core/hle/service/nvdrv/devices/nvdevice.h" 11#include "core/hle/service/nvdrv/devices/nvdevice.h"
12#include "core/hle/service/nvflinger/buffer_queue.h" 12#include "core/hle/service/nvflinger/buffer_transform_flags.h"
13#include "core/hle/service/nvflinger/pixel_format.h"
13 14
14namespace Service::Nvidia::Devices { 15namespace Service::Nvidia::Devices {
15 16
@@ -31,8 +32,8 @@ public:
31 void OnClose(DeviceFD fd) override; 32 void OnClose(DeviceFD fd) override;
32 33
33 /// Performs a screen flip, drawing the buffer pointed to by the handle. 34 /// Performs a screen flip, drawing the buffer pointed to by the handle.
34 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, 35 void flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height,
35 NVFlinger::BufferQueue::BufferTransformFlags transform, 36 u32 stride, android::BufferTransformFlags transform,
36 const Common::Rectangle<int>& crop_rect); 37 const Common::Rectangle<int>& crop_rect);
37 38
38private: 39private:
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 0a043e386..dde5b1507 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -187,7 +187,7 @@ NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::ve
187 return NvResult::Success; 187 return NvResult::Success;
188} 188}
189 189
190static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { 190static std::vector<Tegra::CommandHeader> BuildWaitCommandList(NvFence fence) {
191 return { 191 return {
192 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, 192 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1,
193 Tegra::SubmissionMode::Increasing), 193 Tegra::SubmissionMode::Increasing),
@@ -198,7 +198,8 @@ static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) {
198 }; 198 };
199} 199}
200 200
201static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(Fence fence, u32 add_increment) { 201static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(NvFence fence,
202 u32 add_increment) {
202 std::vector<Tegra::CommandHeader> result{ 203 std::vector<Tegra::CommandHeader> result{
203 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, 204 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1,
204 Tegra::SubmissionMode::Increasing), 205 Tegra::SubmissionMode::Increasing),
@@ -213,7 +214,7 @@ static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(Fence fence,
213 return result; 214 return result;
214} 215}
215 216
216static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence fence, 217static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(NvFence fence,
217 u32 add_increment) { 218 u32 add_increment) {
218 std::vector<Tegra::CommandHeader> result{ 219 std::vector<Tegra::CommandHeader> result{
219 Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1, 220 Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 3e4f3b6a7..b2e943e45 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -109,7 +109,7 @@ private:
109 static_assert(sizeof(IoctlGetErrorNotification) == 16, 109 static_assert(sizeof(IoctlGetErrorNotification) == 16,
110 "IoctlGetErrorNotification is incorrect size"); 110 "IoctlGetErrorNotification is incorrect size");
111 111
112 static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); 112 static_assert(sizeof(NvFence) == 8, "Fence is incorrect size");
113 113
114 struct IoctlAllocGpfifoEx { 114 struct IoctlAllocGpfifoEx {
115 u32_le num_entries{}; 115 u32_le num_entries{};
@@ -127,7 +127,7 @@ private:
127 u32_le num_entries{}; // in 127 u32_le num_entries{}; // in
128 u32_le flags{}; // in 128 u32_le flags{}; // in
129 u32_le unk0{}; // in (1 works) 129 u32_le unk0{}; // in (1 works)
130 Fence fence_out{}; // out 130 NvFence fence_out{}; // out
131 u32_le unk1{}; // in 131 u32_le unk1{}; // in
132 u32_le unk2{}; // in 132 u32_le unk2{}; // in
133 u32_le unk3{}; // in 133 u32_le unk3{}; // in
@@ -153,13 +153,13 @@ private:
153 BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt 153 BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt
154 BitField<8, 1, u32_le> increment; // increment the returned fence 154 BitField<8, 1, u32_le> increment; // increment the returned fence
155 } flags; 155 } flags;
156 Fence fence_out{}; // returned new fence object for others to wait on 156 NvFence fence_out{}; // returned new fence object for others to wait on
157 157
158 u32 AddIncrementValue() const { 158 u32 AddIncrementValue() const {
159 return flags.add_increment.Value() << 1; 159 return flags.add_increment.Value() << 1;
160 } 160 }
161 }; 161 };
162 static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), 162 static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(NvFence),
163 "IoctlSubmitGpfifo is incorrect size"); 163 "IoctlSubmitGpfifo is incorrect size");
164 164
165 struct IoctlGetWaitbase { 165 struct IoctlGetWaitbase {
@@ -194,7 +194,7 @@ private:
194 194
195 std::shared_ptr<nvmap> nvmap_dev; 195 std::shared_ptr<nvmap> nvmap_dev;
196 SyncpointManager& syncpoint_manager; 196 SyncpointManager& syncpoint_manager;
197 Fence channel_fence; 197 NvFence channel_fence;
198}; 198};
199 199
200} // namespace Service::Nvidia::Devices 200} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h
index 5ab221fc1..3069c3c80 100644
--- a/src/core/hle/service/nvdrv/nvdata.h
+++ b/src/core/hle/service/nvdrv/nvdata.h
@@ -16,17 +16,11 @@ using DeviceFD = s32;
16 16
17constexpr DeviceFD INVALID_NVDRV_FD = -1; 17constexpr DeviceFD INVALID_NVDRV_FD = -1;
18 18
19struct Fence { 19struct NvFence {
20 s32 id; 20 s32 id;
21 u32 value; 21 u32 value;
22}; 22};
23 23static_assert(sizeof(NvFence) == 8, "NvFence has wrong size");
24static_assert(sizeof(Fence) == 8, "Fence has wrong size");
25
26struct MultiFence {
27 u32 num_fences;
28 std::array<Fence, 4> fences;
29};
30 24
31enum class NvResult : u32 { 25enum class NvResult : u32 {
32 Success = 0x0, 26 Success = 0x0,
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index a5af5b785..11cf6c0d1 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -12,6 +12,7 @@
12#include "core/hle/service/kernel_helpers.h" 12#include "core/hle/service/kernel_helpers.h"
13#include "core/hle/service/nvdrv/nvdata.h" 13#include "core/hle/service/nvdrv/nvdata.h"
14#include "core/hle/service/nvdrv/syncpoint_manager.h" 14#include "core/hle/service/nvdrv/syncpoint_manager.h"
15#include "core/hle/service/nvflinger/ui/fence.h"
15#include "core/hle/service/service.h" 16#include "core/hle/service/service.h"
16 17
17namespace Core { 18namespace Core {
@@ -37,7 +38,7 @@ class nvdevice;
37/// Represents an Nvidia event 38/// Represents an Nvidia event
38struct NvEvent { 39struct NvEvent {
39 Kernel::KEvent* event{}; 40 Kernel::KEvent* event{};
40 Fence fence{}; 41 NvFence fence{};
41}; 42};
42 43
43struct EventInterface { 44struct EventInterface {
diff --git a/src/core/hle/service/nvflinger/binder.h b/src/core/hle/service/nvflinger/binder.h
new file mode 100644
index 000000000..7d0d4d819
--- /dev/null
+++ b/src/core/hle/service/nvflinger/binder.h
@@ -0,0 +1,42 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/binder/IBinder.h
6
7#pragma once
8
9#include "common/common_types.h"
10
11namespace Kernel {
12class HLERequestContext;
13class KReadableEvent;
14} // namespace Kernel
15
16namespace Service::android {
17
18enum class TransactionId {
19 RequestBuffer = 1,
20 SetBufferCount = 2,
21 DequeueBuffer = 3,
22 DetachBuffer = 4,
23 DetachNextBuffer = 5,
24 AttachBuffer = 6,
25 QueueBuffer = 7,
26 CancelBuffer = 8,
27 Query = 9,
28 Connect = 10,
29 Disconnect = 11,
30 AllocateBuffers = 13,
31 SetPreallocatedBuffer = 14,
32 GetBufferHistory = 17,
33};
34
35class IBinder {
36public:
37 virtual void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code,
38 u32 flags) = 0;
39 virtual Kernel::KReadableEvent& GetNativeHandle() = 0;
40};
41
42} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_item.h b/src/core/hle/service/nvflinger/buffer_item.h
new file mode 100644
index 000000000..64b82b851
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_item.h
@@ -0,0 +1,46 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferItem.h
6
7#pragma once
8
9#include <memory>
10
11#include "common/common_types.h"
12#include "common/math_util.h"
13#include "core/hle/service/nvflinger/ui/fence.h"
14#include "core/hle/service/nvflinger/window.h"
15
16namespace Service::android {
17
18class GraphicBuffer;
19
20class BufferItem final {
21public:
22 constexpr BufferItem() = default;
23
24 std::shared_ptr<GraphicBuffer> graphic_buffer;
25 Fence fence;
26 Common::Rectangle<s32> crop;
27 NativeWindowTransform transform{};
28 u32 scaling_mode{};
29 s64 timestamp{};
30 bool is_auto_timestamp{};
31 u64 frame_number{};
32
33 // The default value for buf, used to indicate this doesn't correspond to a slot.
34 static constexpr s32 INVALID_BUFFER_SLOT = -1;
35 union {
36 s32 slot{INVALID_BUFFER_SLOT};
37 s32 buf;
38 };
39
40 bool is_droppable{};
41 bool acquire_called{};
42 bool transform_to_display_inverse{};
43 s32 swap_interval{};
44};
45
46} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
new file mode 100644
index 000000000..7f32c0775
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
@@ -0,0 +1,59 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2012 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferItemConsumer.cpp
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/hle/service/nvflinger/buffer_item.h"
10#include "core/hle/service/nvflinger/buffer_item_consumer.h"
11#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
12
13namespace Service::android {
14
15BufferItemConsumer::BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer_)
16 : ConsumerBase{std::move(consumer_)} {}
17
18Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
19 bool wait_for_fence) {
20 if (!item) {
21 return Status::BadValue;
22 }
23
24 std::unique_lock lock(mutex);
25
26 if (const auto status = AcquireBufferLocked(item, present_when); status != Status::NoError) {
27 if (status != Status::NoBufferAvailable) {
28 LOG_ERROR(Service_NVFlinger, "Failed to acquire buffer: {}", status);
29 }
30 return status;
31 }
32
33 if (wait_for_fence) {
34 UNIMPLEMENTED();
35 }
36
37 item->graphic_buffer = slots[item->slot].graphic_buffer;
38
39 return Status::NoError;
40}
41
42Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, Fence& release_fence) {
43 std::unique_lock lock(mutex);
44
45 if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence);
46 status != Status::NoError) {
47 LOG_ERROR(Service_NVFlinger, "Failed to add fence: {}", status);
48 }
49
50 if (const auto status = ReleaseBufferLocked(item.buf, item.graphic_buffer);
51 status != Status::NoError) {
52 LOG_WARNING(Service_NVFlinger, "Failed to release buffer: {}", status);
53 return status;
54 }
55
56 return Status::NoError;
57}
58
59} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.h b/src/core/hle/service/nvflinger/buffer_item_consumer.h
new file mode 100644
index 000000000..536db81e2
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_item_consumer.h
@@ -0,0 +1,28 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2012 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferItemConsumer.h
6
7#pragma once
8
9#include <chrono>
10#include <memory>
11
12#include "common/common_types.h"
13#include "core/hle/service/nvflinger/consumer_base.h"
14#include "core/hle/service/nvflinger/status.h"
15
16namespace Service::android {
17
18class BufferItem;
19
20class BufferItemConsumer final : public ConsumerBase {
21public:
22 explicit BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer);
23 Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
24 bool wait_for_fence = true);
25 Status ReleaseBuffer(const BufferItem& item, Fence& release_fence);
26};
27
28} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
new file mode 100644
index 000000000..677bec932
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
@@ -0,0 +1,225 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp
6
7#include "common/logging/log.h"
8#include "core/hle/service/nvflinger/buffer_item.h"
9#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
10#include "core/hle/service/nvflinger/buffer_queue_core.h"
11#include "core/hle/service/nvflinger/producer_listener.h"
12
13namespace Service::android {
14
15BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_)
16 : core{std::move(core_)}, slots{core->slots} {}
17
18BufferQueueConsumer::~BufferQueueConsumer() = default;
19
20Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
21 std::chrono::nanoseconds expected_present,
22 u64 max_frame_number) {
23 s32 num_dropped_buffers{};
24
25 std::shared_ptr<IProducerListener> listener;
26 {
27 std::unique_lock lock(core->mutex);
28
29 // Check that the consumer doesn't currently have the maximum number of buffers acquired.
30 const s32 num_acquired_buffers{
31 static_cast<s32>(std::count_if(slots.begin(), slots.end(), [](const auto& slot) {
32 return slot.buffer_state == BufferState::Acquired;
33 }))};
34
35 if (num_acquired_buffers >= core->max_acquired_buffer_count + 1) {
36 LOG_ERROR(Service_NVFlinger, "max acquired buffer count reached: {} (max {})",
37 num_acquired_buffers, core->max_acquired_buffer_count);
38 return Status::InvalidOperation;
39 }
40
41 // Check if the queue is empty.
42 if (core->queue.empty()) {
43 return Status::NoBufferAvailable;
44 }
45
46 auto front(core->queue.begin());
47
48 // If expected_present is specified, we may not want to return a buffer yet.
49 if (expected_present.count() != 0) {
50 constexpr auto MAX_REASONABLE_NSEC = 1000000000LL; // 1 second
51
52 // The expected_present argument indicates when the buffer is expected to be
53 // presented on-screen.
54 while (core->queue.size() > 1 && !core->queue[0].is_auto_timestamp) {
55 const auto& buffer_item{core->queue[1]};
56
57 // If dropping entry[0] would leave us with a buffer that the consumer is not yet
58 // ready for, don't drop it.
59 if (max_frame_number && buffer_item.frame_number > max_frame_number) {
60 break;
61 }
62
63 // If entry[1] is timely, drop entry[0] (and repeat).
64 const auto desired_present = buffer_item.timestamp;
65 if (desired_present < expected_present.count() - MAX_REASONABLE_NSEC ||
66 desired_present > expected_present.count()) {
67 // This buffer is set to display in the near future, or desired_present is
68 // garbage.
69 LOG_DEBUG(Service_NVFlinger, "nodrop desire={} expect={}", desired_present,
70 expected_present.count());
71 break;
72 }
73
74 LOG_DEBUG(Service_NVFlinger, "drop desire={} expect={} size={}", desired_present,
75 expected_present.count(), core->queue.size());
76
77 if (core->StillTracking(*front)) {
78 // Front buffer is still in mSlots, so mark the slot as free
79 slots[front->slot].buffer_state = BufferState::Free;
80 core->free_buffers.push_back(front->slot);
81 listener = core->connected_producer_listener;
82 ++num_dropped_buffers;
83 }
84
85 core->queue.erase(front);
86 front = core->queue.begin();
87 }
88
89 // See if the front buffer is ready to be acquired.
90 const auto desired_present = front->timestamp;
91 const auto buffer_is_due =
92 desired_present <= expected_present.count() ||
93 desired_present > expected_present.count() + MAX_REASONABLE_NSEC;
94 const auto consumer_is_ready =
95 max_frame_number > 0 ? front->frame_number <= max_frame_number : true;
96
97 if (!buffer_is_due || !consumer_is_ready) {
98 LOG_DEBUG(Service_NVFlinger, "defer desire={} expect={}", desired_present,
99 expected_present.count());
100 return Status::PresentLater;
101 }
102
103 LOG_DEBUG(Service_NVFlinger, "accept desire={} expect={}", desired_present,
104 expected_present.count());
105 }
106
107 const auto slot = front->slot;
108 *out_buffer = *front;
109
110 LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot);
111
112 // If the front buffer is still being tracked, update its slot state
113 if (core->StillTracking(*front)) {
114 slots[slot].acquire_called = true;
115 slots[slot].needs_cleanup_on_release = false;
116 slots[slot].buffer_state = BufferState::Acquired;
117 slots[slot].fence = Fence::NoFence();
118 }
119
120 // If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr
121 // to avoid unnecessarily remapping this buffer on the consumer side.
122 if (out_buffer->acquire_called) {
123 out_buffer->graphic_buffer = nullptr;
124 }
125
126 core->queue.erase(front);
127
128 // We might have freed a slot while dropping old buffers, or the producer may be blocked
129 // waiting for the number of buffers in the queue to decrease.
130 core->SignalDequeueCondition();
131 }
132
133 if (listener != nullptr) {
134 for (s32 i = 0; i < num_dropped_buffers; ++i) {
135 listener->OnBufferReleased();
136 }
137 }
138
139 return Status::NoError;
140}
141
142Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence) {
143 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
144 LOG_ERROR(Service_NVFlinger, "slot {} out of range", slot);
145 return Status::BadValue;
146 }
147
148 std::shared_ptr<IProducerListener> listener;
149 {
150 std::unique_lock lock(core->mutex);
151
152 // If the frame number has changed because the buffer has been reallocated, we can ignore
153 // this ReleaseBuffer for the old buffer.
154 if (frame_number != slots[slot].frame_number) {
155 return Status::StaleBufferSlot;
156 }
157
158 // Make sure this buffer hasn't been queued while acquired by the consumer.
159 auto current(core->queue.begin());
160 while (current != core->queue.end()) {
161 if (current->slot == slot) {
162 LOG_ERROR(Service_NVFlinger, "buffer slot {} pending release is currently queued",
163 slot);
164 return Status::BadValue;
165 }
166 ++current;
167 }
168
169 if (slots[slot].buffer_state == BufferState::Acquired) {
170 slots[slot].fence = release_fence;
171 slots[slot].buffer_state = BufferState::Free;
172
173 core->free_buffers.push_back(slot);
174
175 listener = core->connected_producer_listener;
176
177 LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot);
178 } else if (slots[slot].needs_cleanup_on_release) {
179 LOG_DEBUG(Service_NVFlinger, "releasing a stale buffer slot {} (state = {})", slot,
180 slots[slot].buffer_state);
181
182 slots[slot].needs_cleanup_on_release = false;
183
184 return Status::StaleBufferSlot;
185 } else {
186 LOG_ERROR(Service_NVFlinger, "attempted to release buffer slot {} but its state was {}",
187 slot, slots[slot].buffer_state);
188
189 return Status::BadValue;
190 }
191
192 core->dequeue_condition.notify_all();
193 }
194
195 // Call back without lock held
196 if (listener != nullptr) {
197 listener->OnBufferReleased();
198 }
199
200 return Status::NoError;
201}
202
203Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_listener,
204 bool controlled_by_app) {
205 if (consumer_listener == nullptr) {
206 LOG_ERROR(Service_NVFlinger, "consumer_listener may not be nullptr");
207 return Status::BadValue;
208 }
209
210 LOG_DEBUG(Service_NVFlinger, "controlled_by_app={}", controlled_by_app);
211
212 BufferQueueCore::AutoLock lock(core);
213
214 if (core->is_abandoned) {
215 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
216 return Status::NoInit;
217 }
218
219 core->consumer_listener = consumer_listener;
220 core->consumer_controlled_by_app = controlled_by_app;
221
222 return Status::NoError;
223}
224
225} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.h b/src/core/hle/service/nvflinger/buffer_queue_consumer.h
new file mode 100644
index 000000000..f22854394
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.h
@@ -0,0 +1,37 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueConsumer.h
6
7#pragma once
8
9#include <chrono>
10#include <memory>
11
12#include "common/common_types.h"
13#include "core/hle/service/nvflinger/buffer_queue_defs.h"
14#include "core/hle/service/nvflinger/status.h"
15
16namespace Service::android {
17
18class BufferItem;
19class BufferQueueCore;
20class IConsumerListener;
21
22class BufferQueueConsumer final {
23public:
24 explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
25 ~BufferQueueConsumer();
26
27 Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present,
28 u64 max_frame_number = 0);
29 Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
30 Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app);
31
32private:
33 std::shared_ptr<BufferQueueCore> core;
34 BufferQueueDefs::SlotsType& slots;
35};
36
37} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
new file mode 100644
index 000000000..eb93b43ee
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
@@ -0,0 +1,134 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueCore.cpp
6
7#include "common/assert.h"
8
9#include "core/hle/service/nvflinger/buffer_queue_core.h"
10
11namespace Service::android {
12
13BufferQueueCore::BufferQueueCore() : lock{mutex, std::defer_lock} {
14 for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
15 free_slots.insert(slot);
16 }
17}
18
19BufferQueueCore::~BufferQueueCore() = default;
20
21void BufferQueueCore::NotifyShutdown() {
22 std::unique_lock lk(mutex);
23
24 is_shutting_down = true;
25
26 SignalDequeueCondition();
27}
28
29void BufferQueueCore::SignalDequeueCondition() {
30 dequeue_condition.notify_all();
31}
32
33bool BufferQueueCore::WaitForDequeueCondition() {
34 if (is_shutting_down) {
35 return false;
36 }
37
38 dequeue_condition.wait(lock);
39
40 return true;
41}
42
43s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const {
44 // If DequeueBuffer is allowed to error out, we don't have to add an extra buffer.
45 if (!use_async_buffer) {
46 return max_acquired_buffer_count;
47 }
48
49 if (dequeue_buffer_cannot_block || async) {
50 return max_acquired_buffer_count + 1;
51 }
52
53 return max_acquired_buffer_count;
54}
55
56s32 BufferQueueCore::GetMinMaxBufferCountLocked(bool async) const {
57 return GetMinUndequeuedBufferCountLocked(async) + 1;
58}
59
60s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const {
61 const auto min_buffer_count = GetMinMaxBufferCountLocked(async);
62 auto max_buffer_count = std::max(default_max_buffer_count, min_buffer_count);
63
64 if (override_max_buffer_count != 0) {
65 ASSERT(override_max_buffer_count >= min_buffer_count);
66 max_buffer_count = override_max_buffer_count;
67 }
68
69 // Any buffers that are dequeued by the producer or sitting in the queue waiting to be consumed
70 // need to have their slots preserved.
71 for (s32 slot = max_buffer_count; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
72 const auto state = slots[slot].buffer_state;
73 if (state == BufferState::Queued || state == BufferState::Dequeued) {
74 max_buffer_count = slot + 1;
75 }
76 }
77
78 return max_buffer_count;
79}
80
81s32 BufferQueueCore::GetPreallocatedBufferCountLocked() const {
82 return static_cast<s32>(std::count_if(slots.begin(), slots.end(),
83 [](const auto& slot) { return slot.is_preallocated; }));
84}
85
86void BufferQueueCore::FreeBufferLocked(s32 slot) {
87 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
88
89 const auto had_buffer = slots[slot].graphic_buffer != nullptr;
90
91 slots[slot].graphic_buffer.reset();
92
93 if (slots[slot].buffer_state == BufferState::Acquired) {
94 slots[slot].needs_cleanup_on_release = true;
95 }
96
97 if (slots[slot].buffer_state != BufferState::Free) {
98 free_slots.insert(slot);
99 } else if (had_buffer) {
100 // If the slot was FREE, but we had a buffer, we need to move this slot from the free
101 // buffers list to the the free slots list.
102 free_buffers.remove(slot);
103 free_slots.insert(slot);
104 }
105
106 slots[slot].buffer_state = BufferState::Free;
107 slots[slot].acquire_called = false;
108 slots[slot].frame_number = 0;
109 slots[slot].fence = Fence::NoFence();
110}
111
112void BufferQueueCore::FreeAllBuffersLocked() {
113 queue.clear();
114 buffer_has_been_queued = false;
115
116 for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
117 FreeBufferLocked(slot);
118 }
119}
120
121bool BufferQueueCore::StillTracking(const BufferItem& item) const {
122 const BufferSlot& slot = slots[item.slot];
123
124 return (slot.graphic_buffer != nullptr) && (item.graphic_buffer == slot.graphic_buffer);
125}
126
127void BufferQueueCore::WaitWhileAllocatingLocked() const {
128 while (is_allocating) {
129 std::unique_lock lk(mutex);
130 is_allocating_condition.wait(lk);
131 }
132}
133
134} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h
new file mode 100644
index 000000000..a3cd89f1c
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.h
@@ -0,0 +1,99 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueCore.h
6
7#pragma once
8
9#include <condition_variable>
10#include <list>
11#include <memory>
12#include <mutex>
13#include <set>
14#include <vector>
15
16#include "core/hle/service/nvflinger/buffer_item.h"
17#include "core/hle/service/nvflinger/buffer_queue_defs.h"
18#include "core/hle/service/nvflinger/pixel_format.h"
19#include "core/hle/service/nvflinger/status.h"
20#include "core/hle/service/nvflinger/window.h"
21
22namespace Service::android {
23
24class IConsumerListener;
25class IProducerListener;
26
27class BufferQueueCore final {
28 friend class BufferQueueProducer;
29 friend class BufferQueueConsumer;
30
31public:
32 static constexpr s32 INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT;
33
34 BufferQueueCore();
35 ~BufferQueueCore();
36
37 void NotifyShutdown();
38
39private:
40 void SignalDequeueCondition();
41 bool WaitForDequeueCondition();
42
43 s32 GetMinUndequeuedBufferCountLocked(bool async) const;
44 s32 GetMinMaxBufferCountLocked(bool async) const;
45 s32 GetMaxBufferCountLocked(bool async) const;
46 s32 GetPreallocatedBufferCountLocked() const;
47 void FreeBufferLocked(s32 slot);
48 void FreeAllBuffersLocked();
49 bool StillTracking(const BufferItem& item) const;
50 void WaitWhileAllocatingLocked() const;
51
52private:
53 class AutoLock final {
54 public:
55 AutoLock(std::shared_ptr<BufferQueueCore>& core_) : core{core_} {
56 core->lock.lock();
57 }
58
59 ~AutoLock() {
60 core->lock.unlock();
61 }
62
63 private:
64 std::shared_ptr<BufferQueueCore>& core;
65 };
66
67private:
68 mutable std::mutex mutex;
69 mutable std::unique_lock<std::mutex> lock;
70 bool is_abandoned{};
71 bool consumer_controlled_by_app{};
72 std::shared_ptr<IConsumerListener> consumer_listener;
73 u32 consumer_usage_bit{};
74 NativeWindowApi connected_api{NativeWindowApi::NoConnectedApi};
75 std::shared_ptr<IProducerListener> connected_producer_listener;
76 BufferQueueDefs::SlotsType slots{};
77 std::vector<BufferItem> queue;
78 std::set<s32> free_slots;
79 std::list<s32> free_buffers;
80 s32 override_max_buffer_count{};
81 mutable std::condition_variable dequeue_condition;
82 const bool use_async_buffer{}; // This is always disabled on HOS
83 bool dequeue_buffer_cannot_block{};
84 PixelFormat default_buffer_format{PixelFormat::Rgba8888};
85 u32 default_width{1};
86 u32 default_height{1};
87 s32 default_max_buffer_count{2};
88 const s32 max_acquired_buffer_count{}; // This is always zero on HOS
89 bool buffer_has_been_queued{};
90 u64 frame_counter{};
91 u32 transform_hint{};
92 bool is_allocating{};
93 mutable std::condition_variable is_allocating_condition;
94 bool allow_allocation{true};
95 u64 buffer_age{};
96 bool is_shutting_down{};
97};
98
99} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_defs.h b/src/core/hle/service/nvflinger/buffer_queue_defs.h
new file mode 100644
index 000000000..387d3d36a
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_defs.h
@@ -0,0 +1,21 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueDefs.h
6
7#pragma once
8
9#include <array>
10
11#include "common/common_types.h"
12#include "core/hle/service/nvflinger/buffer_slot.h"
13
14namespace Service::android::BufferQueueDefs {
15
16// BufferQueue will keep track of at most this value of buffers.
17constexpr s32 NUM_BUFFER_SLOTS = 64;
18
19using SlotsType = std::array<BufferSlot, NUM_BUFFER_SLOTS>;
20
21} // namespace Service::android::BufferQueueDefs
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
new file mode 100644
index 000000000..078091904
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
@@ -0,0 +1,937 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueProducer.cpp
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "common/settings.h"
10#include "core/core.h"
11#include "core/hle/kernel/hle_ipc.h"
12#include "core/hle/kernel/k_event.h"
13#include "core/hle/kernel/k_readable_event.h"
14#include "core/hle/kernel/k_writable_event.h"
15#include "core/hle/kernel/kernel.h"
16#include "core/hle/service/kernel_helpers.h"
17#include "core/hle/service/nvdrv/nvdrv.h"
18#include "core/hle/service/nvflinger/buffer_queue_core.h"
19#include "core/hle/service/nvflinger/buffer_queue_producer.h"
20#include "core/hle/service/nvflinger/consumer_listener.h"
21#include "core/hle/service/nvflinger/parcel.h"
22#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
23#include "core/hle/service/nvflinger/window.h"
24#include "core/hle/service/vi/vi.h"
25
26namespace Service::android {
27
28BufferQueueProducer::BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_,
29 std::shared_ptr<BufferQueueCore> buffer_queue_core_)
30 : service_context{service_context_}, core{std::move(buffer_queue_core_)}, slots(core->slots) {
31 buffer_wait_event = service_context.CreateEvent("BufferQueue:WaitEvent");
32}
33
34BufferQueueProducer::~BufferQueueProducer() {
35 service_context.CloseEvent(buffer_wait_event);
36}
37
38Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf) {
39 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
40
41 BufferQueueCore::AutoLock lock(core);
42
43 if (core->is_abandoned) {
44 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
45 return Status::NoInit;
46 }
47 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
48 LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot,
49 BufferQueueDefs::NUM_BUFFER_SLOTS);
50 return Status::BadValue;
51 } else if (slots[slot].buffer_state != BufferState::Dequeued) {
52 LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot,
53 slots[slot].buffer_state);
54 return Status::BadValue;
55 }
56
57 slots[slot].request_buffer_called = true;
58 *buf = slots[slot].graphic_buffer;
59
60 return Status::NoError;
61}
62
63Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
64 LOG_DEBUG(Service_NVFlinger, "count = {}", buffer_count);
65 std::shared_ptr<IConsumerListener> listener;
66
67 {
68 BufferQueueCore::AutoLock lock(core);
69 core->WaitWhileAllocatingLocked();
70 if (core->is_abandoned) {
71 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
72 return Status::NoInit;
73 }
74
75 if (buffer_count > BufferQueueDefs::NUM_BUFFER_SLOTS) {
76 LOG_ERROR(Service_NVFlinger, "buffer_count {} too large (max {})", buffer_count,
77 BufferQueueDefs::NUM_BUFFER_SLOTS);
78 return Status::BadValue;
79 }
80
81 // There must be no dequeued buffers when changing the buffer count.
82 for (s32 s{}; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
83 if (slots[s].buffer_state == BufferState::Dequeued) {
84 LOG_ERROR(Service_NVFlinger, "buffer owned by producer");
85 return Status::BadValue;
86 }
87 }
88
89 if (buffer_count == 0) {
90 core->override_max_buffer_count = 0;
91 core->SignalDequeueCondition();
92 return Status::NoError;
93 }
94
95 const s32 min_buffer_slots = core->GetMinMaxBufferCountLocked(false);
96 if (buffer_count < min_buffer_slots) {
97 LOG_ERROR(Service_NVFlinger, "requested buffer count {} is less than minimum {}",
98 buffer_count, min_buffer_slots);
99 return Status::BadValue;
100 }
101
102 // Here we are guaranteed that the producer doesn't have any dequeued buffers and will
103 // release all of its buffer references.
104 if (core->GetPreallocatedBufferCountLocked() <= 0) {
105 core->FreeAllBuffersLocked();
106 }
107
108 core->override_max_buffer_count = buffer_count;
109 core->SignalDequeueCondition();
110 buffer_wait_event->GetWritableEvent().Signal();
111 listener = core->consumer_listener;
112 }
113
114 // Call back without lock held
115 if (listener != nullptr) {
116 listener->OnBuffersReleased();
117 }
118
119 return Status::NoError;
120}
121
122Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,
123 Status* returnFlags) const {
124 bool try_again = true;
125
126 while (try_again) {
127 if (core->is_abandoned) {
128 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
129 return Status::NoInit;
130 }
131
132 const s32 max_buffer_count = core->GetMaxBufferCountLocked(async);
133 if (async && core->override_max_buffer_count) {
134 if (core->override_max_buffer_count < max_buffer_count) {
135 LOG_ERROR(Service_NVFlinger, "async mode is invalid with buffer count override");
136 return Status::BadValue;
137 }
138 }
139
140 // Free up any buffers that are in slots beyond the max buffer count
141 for (s32 s = max_buffer_count; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
142 ASSERT(slots[s].buffer_state == BufferState::Free);
143 if (slots[s].graphic_buffer != nullptr) {
144 core->FreeBufferLocked(s);
145 *returnFlags |= Status::ReleaseAllBuffers;
146 }
147 }
148
149 s32 dequeued_count{};
150 s32 acquired_count{};
151 for (s32 s{}; s < max_buffer_count; ++s) {
152 switch (slots[s].buffer_state) {
153 case BufferState::Dequeued:
154 ++dequeued_count;
155 break;
156 case BufferState::Acquired:
157 ++acquired_count;
158 break;
159 default:
160 break;
161 }
162 }
163
164 // Producers are not allowed to dequeue more than one buffer if they did not set a buffer
165 // count
166 if (!core->override_max_buffer_count && dequeued_count) {
167 LOG_ERROR(Service_NVFlinger,
168 "can't dequeue multiple buffers without setting the buffer count");
169 return Status::InvalidOperation;
170 }
171
172 // See whether a buffer has been queued since the last SetBufferCount so we know whether to
173 // perform the min undequeued buffers check below
174 if (core->buffer_has_been_queued) {
175 // Make sure the producer is not trying to dequeue more buffers than allowed
176 const s32 new_undequeued_count = max_buffer_count - (dequeued_count + 1);
177 const s32 min_undequeued_count = core->GetMinUndequeuedBufferCountLocked(async);
178 if (new_undequeued_count < min_undequeued_count) {
179 LOG_ERROR(Service_NVFlinger,
180 "min undequeued buffer count({}) exceeded (dequeued={} undequeued={})",
181 min_undequeued_count, dequeued_count, new_undequeued_count);
182 return Status::InvalidOperation;
183 }
184 }
185
186 *found = BufferQueueCore::INVALID_BUFFER_SLOT;
187
188 // If we disconnect and reconnect quickly, we can be in a state where our slots are empty
189 // but we have many buffers in the queue. This can cause us to run out of memory if we
190 // outrun the consumer. Wait here if it looks like we have too many buffers queued up.
191 const bool too_many_buffers = core->queue.size() > static_cast<size_t>(max_buffer_count);
192 if (too_many_buffers) {
193 LOG_ERROR(Service_NVFlinger, "queue size is {}, waiting", core->queue.size());
194 } else {
195 if (!core->free_buffers.empty()) {
196 auto slot = core->free_buffers.begin();
197 *found = *slot;
198 core->free_buffers.erase(slot);
199 } else if (core->allow_allocation && !core->free_slots.empty()) {
200 auto slot = core->free_slots.begin();
201 // Only return free slots up to the max buffer count
202 if (*slot < max_buffer_count) {
203 *found = *slot;
204 core->free_slots.erase(slot);
205 }
206 }
207 }
208
209 // If no buffer is found, or if the queue has too many buffers outstanding, wait for a
210 // buffer to be acquired or released, or for the max buffer count to change.
211 try_again = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || too_many_buffers;
212 if (try_again) {
213 // Return an error if we're in non-blocking mode (producer and consumer are controlled
214 // by the application).
215 if (core->dequeue_buffer_cannot_block &&
216 (acquired_count <= core->max_acquired_buffer_count)) {
217 return Status::WouldBlock;
218 }
219
220 if (!core->WaitForDequeueCondition()) {
221 // We are no longer running
222 return Status::NoError;
223 }
224 }
225 }
226
227 return Status::NoError;
228}
229
230Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool async, u32 width,
231 u32 height, PixelFormat format, u32 usage) {
232 LOG_DEBUG(Service_NVFlinger, "async={} w={} h={} format={}, usage={}", async ? "true" : "false",
233 width, height, format, usage);
234
235 if ((width != 0 && height == 0) || (width == 0 && height != 0)) {
236 LOG_ERROR(Service_NVFlinger, "invalid size: w={} h={}", width, height);
237 return Status::BadValue;
238 }
239
240 Status return_flags = Status::NoError;
241 bool attached_by_consumer = false;
242 {
243 BufferQueueCore::AutoLock lock(core);
244 core->WaitWhileAllocatingLocked();
245 if (format == PixelFormat::NoFormat) {
246 format = core->default_buffer_format;
247 }
248
249 // Enable the usage bits the consumer requested
250 usage |= core->consumer_usage_bit;
251 const bool use_default_size = !width && !height;
252 if (use_default_size) {
253 width = core->default_width;
254 height = core->default_height;
255 }
256
257 s32 found = BufferItem::INVALID_BUFFER_SLOT;
258 while (found == BufferItem::INVALID_BUFFER_SLOT) {
259 Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags);
260 if (status != Status::NoError) {
261 return status;
262 }
263
264 // This should not happen
265 if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
266 LOG_DEBUG(Service_NVFlinger, "no available buffer slots");
267 return Status::Busy;
268 }
269
270 const std::shared_ptr<GraphicBuffer>& buffer(slots[found].graphic_buffer);
271
272 // If we are not allowed to allocate new buffers, WaitForFreeSlotThenRelock must have
273 // returned a slot containing a buffer. If this buffer would require reallocation to
274 // meet the requested attributes, we free it and attempt to get another one.
275 if (!core->allow_allocation) {
276 if (buffer->NeedsReallocation(width, height, format, usage)) {
277 core->FreeBufferLocked(found);
278 found = BufferItem::INVALID_BUFFER_SLOT;
279 continue;
280 }
281 }
282 }
283
284 *out_slot = found;
285 attached_by_consumer = slots[found].attached_by_consumer;
286 slots[found].buffer_state = BufferState::Dequeued;
287
288 const std::shared_ptr<GraphicBuffer>& buffer(slots[found].graphic_buffer);
289
290 if ((buffer == nullptr) || buffer->NeedsReallocation(width, height, format, usage)) {
291 slots[found].acquire_called = false;
292 slots[found].graphic_buffer = nullptr;
293 slots[found].request_buffer_called = false;
294 slots[found].fence = Fence::NoFence();
295 core->buffer_age = 0;
296 return_flags |= Status::BufferNeedsReallocation;
297 } else {
298 // We add 1 because that will be the frame number when this buffer
299 // is queued
300 core->buffer_age = core->frame_counter + 1 - slots[found].frame_number;
301 }
302
303 LOG_DEBUG(Service_NVFlinger, "setting buffer age to {}", core->buffer_age);
304
305 *out_fence = slots[found].fence;
306
307 slots[found].fence = Fence::NoFence();
308 }
309
310 if ((return_flags & Status::BufferNeedsReallocation) != Status::None) {
311 LOG_DEBUG(Service_NVFlinger, "allocating a new buffer for slot {}", *out_slot);
312
313 auto graphic_buffer = std::make_shared<GraphicBuffer>(width, height, format, usage);
314 if (graphic_buffer == nullptr) {
315 LOG_ERROR(Service_NVFlinger, "creating GraphicBuffer failed");
316 return Status::NoMemory;
317 }
318
319 {
320 BufferQueueCore::AutoLock lock(core);
321 if (core->is_abandoned) {
322 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
323 return Status::NoInit;
324 }
325
326 slots[*out_slot].graphic_buffer = graphic_buffer;
327 }
328 }
329
330 if (attached_by_consumer) {
331 return_flags |= Status::BufferNeedsReallocation;
332 }
333
334 LOG_DEBUG(Service_NVFlinger, "returning slot={} frame={}, flags={}", *out_slot,
335 slots[*out_slot].frame_number, return_flags);
336 return return_flags;
337}
338
339Status BufferQueueProducer::DetachBuffer(s32 slot) {
340 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
341
342 BufferQueueCore::AutoLock lock(core);
343 if (core->is_abandoned) {
344 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
345 return Status::NoInit;
346 }
347
348 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
349 LOG_ERROR(Service_NVFlinger, "slot {} out of range [0, {})", slot,
350 BufferQueueDefs::NUM_BUFFER_SLOTS);
351 return Status::BadValue;
352 } else if (slots[slot].buffer_state != BufferState::Dequeued) {
353 LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot,
354 slots[slot].buffer_state);
355 return Status::BadValue;
356 } else if (!slots[slot].request_buffer_called) {
357 LOG_ERROR(Service_NVFlinger, "buffer in slot {} has not been requested", slot);
358 return Status::BadValue;
359 }
360
361 core->FreeBufferLocked(slot);
362 core->SignalDequeueCondition();
363
364 return Status::NoError;
365}
366
367Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out_buffer,
368 Fence* out_fence) {
369 if (out_buffer == nullptr) {
370 LOG_ERROR(Service_NVFlinger, "out_buffer must not be nullptr");
371 return Status::BadValue;
372 } else if (out_fence == nullptr) {
373 LOG_ERROR(Service_NVFlinger, "out_fence must not be nullptr");
374 return Status::BadValue;
375 }
376
377 BufferQueueCore::AutoLock lock(core);
378
379 core->WaitWhileAllocatingLocked();
380
381 if (core->is_abandoned) {
382 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
383 return Status::NoInit;
384 }
385 if (core->free_buffers.empty()) {
386 return Status::NoMemory;
387 }
388
389 const s32 found = core->free_buffers.front();
390 core->free_buffers.remove(found);
391
392 LOG_DEBUG(Service_NVFlinger, "Detached slot {}", found);
393
394 *out_buffer = slots[found].graphic_buffer;
395 *out_fence = slots[found].fence;
396
397 core->FreeBufferLocked(found);
398
399 return Status::NoError;
400}
401
402Status BufferQueueProducer::AttachBuffer(s32* out_slot,
403 const std::shared_ptr<GraphicBuffer>& buffer) {
404 if (out_slot == nullptr) {
405 LOG_ERROR(Service_NVFlinger, "out_slot must not be nullptr");
406 return Status::BadValue;
407 } else if (buffer == nullptr) {
408 LOG_ERROR(Service_NVFlinger, "Cannot attach nullptr buffer");
409 return Status::BadValue;
410 }
411
412 BufferQueueCore::AutoLock lock(core);
413 core->WaitWhileAllocatingLocked();
414
415 Status return_flags = Status::NoError;
416 s32 found{};
417
418 const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags);
419 if (status != Status::NoError) {
420 return status;
421 }
422
423 if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
424 LOG_ERROR(Service_NVFlinger, "No available buffer slots");
425 return Status::Busy;
426 }
427
428 *out_slot = found;
429
430 LOG_DEBUG(Service_NVFlinger, "Returning slot {} flags={}", *out_slot, return_flags);
431
432 slots[*out_slot].graphic_buffer = buffer;
433 slots[*out_slot].buffer_state = BufferState::Dequeued;
434 slots[*out_slot].fence = Fence::NoFence();
435 slots[*out_slot].request_buffer_called = true;
436
437 return return_flags;
438}
439
440Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
441 QueueBufferOutput* output) {
442 s64 timestamp{};
443 bool is_auto_timestamp{};
444 Common::Rectangle<s32> crop;
445 NativeWindowScalingMode scaling_mode{};
446 NativeWindowTransform transform;
447 u32 sticky_transform_{};
448 bool async{};
449 s32 swap_interval{};
450 Fence fence{};
451
452 input.Deflate(&timestamp, &is_auto_timestamp, &crop, &scaling_mode, &transform,
453 &sticky_transform_, &async, &swap_interval, &fence);
454
455 switch (scaling_mode) {
456 case NativeWindowScalingMode::Freeze:
457 case NativeWindowScalingMode::ScaleToWindow:
458 case NativeWindowScalingMode::ScaleCrop:
459 case NativeWindowScalingMode::NoScaleCrop:
460 break;
461 default:
462 LOG_ERROR(Service_NVFlinger, "unknown scaling mode {}", scaling_mode);
463 return Status::BadValue;
464 }
465
466 std::shared_ptr<IConsumerListener> frameAvailableListener;
467 std::shared_ptr<IConsumerListener> frameReplacedListener;
468 s32 callback_ticket{};
469 BufferItem item;
470
471 {
472 BufferQueueCore::AutoLock lock(core);
473
474 if (core->is_abandoned) {
475 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
476 return Status::NoInit;
477 }
478
479 const s32 max_buffer_count = core->GetMaxBufferCountLocked(async);
480 if (async && core->override_max_buffer_count) {
481 if (core->override_max_buffer_count < max_buffer_count) {
482 LOG_ERROR(Service_NVFlinger, "async mode is invalid with "
483 "buffer count override");
484 return Status::BadValue;
485 }
486 }
487
488 if (slot < 0 || slot >= max_buffer_count) {
489 LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot,
490 max_buffer_count);
491 return Status::BadValue;
492 } else if (slots[slot].buffer_state != BufferState::Dequeued) {
493 LOG_ERROR(Service_NVFlinger,
494 "slot {} is not owned by the producer "
495 "(state = {})",
496 slot, slots[slot].buffer_state);
497 return Status::BadValue;
498 } else if (!slots[slot].request_buffer_called) {
499 LOG_ERROR(Service_NVFlinger,
500 "slot {} was queued without requesting "
501 "a buffer",
502 slot);
503 return Status::BadValue;
504 }
505
506 LOG_DEBUG(Service_NVFlinger,
507 "slot={} frame={} time={} crop=[{},{},{},{}] transform={} scale={}", slot,
508 core->frame_counter + 1, timestamp, crop.Left(), crop.Top(), crop.Right(),
509 crop.Bottom(), transform, scaling_mode);
510
511 const std::shared_ptr<GraphicBuffer>& graphic_buffer(slots[slot].graphic_buffer);
512 Common::Rectangle<s32> buffer_rect(graphic_buffer->Width(), graphic_buffer->Height());
513 Common::Rectangle<s32> cropped_rect;
514 [[maybe_unused]] const bool unused = crop.Intersect(buffer_rect, &cropped_rect);
515
516 if (cropped_rect != crop) {
517 LOG_ERROR(Service_NVFlinger, "crop rect is not contained within the buffer in slot {}",
518 slot);
519 return Status::BadValue;
520 }
521
522 slots[slot].fence = fence;
523 slots[slot].buffer_state = BufferState::Queued;
524 ++core->frame_counter;
525 slots[slot].frame_number = core->frame_counter;
526
527 item.acquire_called = slots[slot].acquire_called;
528 item.graphic_buffer = slots[slot].graphic_buffer;
529 item.crop = crop;
530 item.transform = transform & ~NativeWindowTransform::InverseDisplay;
531 item.transform_to_display_inverse =
532 (transform & NativeWindowTransform::InverseDisplay) != NativeWindowTransform::None;
533 item.scaling_mode = static_cast<u32>(scaling_mode);
534 item.timestamp = timestamp;
535 item.is_auto_timestamp = is_auto_timestamp;
536 item.frame_number = core->frame_counter;
537 item.slot = slot;
538 item.fence = fence;
539 item.is_droppable = core->dequeue_buffer_cannot_block || async;
540 item.swap_interval = swap_interval;
541 sticky_transform = sticky_transform_;
542
543 if (core->queue.empty()) {
544 // When the queue is empty, we can simply queue this buffer
545 core->queue.push_back(item);
546 frameAvailableListener = core->consumer_listener;
547 } else {
548 // When the queue is not empty, we need to look at the front buffer
549 // state to see if we need to replace it
550 auto front(core->queue.begin());
551
552 if (front->is_droppable) {
553 // If the front queued buffer is still being tracked, we first
554 // mark it as freed
555 if (core->StillTracking(*front)) {
556 slots[front->slot].buffer_state = BufferState::Free;
557 core->free_buffers.push_front(front->slot);
558 }
559 // Overwrite the droppable buffer with the incoming one
560 *front = item;
561 frameReplacedListener = core->consumer_listener;
562 } else {
563 core->queue.push_back(item);
564 frameAvailableListener = core->consumer_listener;
565 }
566 }
567
568 core->buffer_has_been_queued = true;
569 core->SignalDequeueCondition();
570 output->Inflate(core->default_width, core->default_height, core->transform_hint,
571 static_cast<u32>(core->queue.size()));
572
573 // Take a ticket for the callback functions
574 callback_ticket = next_callback_ticket++;
575 }
576
577 // Don't send the GraphicBuffer through the callback, and don't send the slot number, since the
578 // consumer shouldn't need it
579 item.graphic_buffer.reset();
580 item.slot = BufferItem::INVALID_BUFFER_SLOT;
581
582 // Call back without the main BufferQueue lock held, but with the callback lock held so we can
583 // ensure that callbacks occur in order
584 {
585 std::unique_lock lock(callback_mutex);
586 while (callback_ticket != current_callback_ticket) {
587 std::unique_lock<std::mutex> lk(callback_mutex);
588 callback_condition.wait(lk);
589 }
590
591 if (frameAvailableListener != nullptr) {
592 frameAvailableListener->OnFrameAvailable(item);
593 } else if (frameReplacedListener != nullptr) {
594 frameReplacedListener->OnFrameReplaced(item);
595 }
596
597 ++current_callback_ticket;
598 callback_condition.notify_all();
599 }
600
601 return Status::NoError;
602}
603
604void BufferQueueProducer::CancelBuffer(s32 slot, const Fence& fence) {
605 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
606
607 BufferQueueCore::AutoLock lock(core);
608
609 if (core->is_abandoned) {
610 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
611 return;
612 }
613
614 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
615 LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot,
616 BufferQueueDefs::NUM_BUFFER_SLOTS);
617 return;
618 } else if (slots[slot].buffer_state != BufferState::Dequeued) {
619 LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot,
620 slots[slot].buffer_state);
621 return;
622 }
623
624 core->free_buffers.push_front(slot);
625 slots[slot].buffer_state = BufferState::Free;
626 slots[slot].fence = fence;
627
628 core->SignalDequeueCondition();
629 buffer_wait_event->GetWritableEvent().Signal();
630}
631
632Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) {
633 BufferQueueCore::AutoLock lock(core);
634
635 if (out_value == nullptr) {
636 LOG_ERROR(Service_NVFlinger, "outValue was nullptr");
637 return Status::BadValue;
638 }
639
640 if (core->is_abandoned) {
641 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
642 return Status::NoInit;
643 }
644
645 u32 value{};
646 switch (what) {
647 case NativeWindow::Width:
648 value = core->default_width;
649 break;
650 case NativeWindow::Height:
651 value = core->default_height;
652 break;
653 case NativeWindow::Format:
654 value = static_cast<u32>(core->default_buffer_format);
655 break;
656 case NativeWindow::MinUndequeedBuffers:
657 value = core->GetMinUndequeuedBufferCountLocked(false);
658 break;
659 case NativeWindow::StickyTransform:
660 value = sticky_transform;
661 break;
662 case NativeWindow::ConsumerRunningBehind:
663 value = (core->queue.size() > 1);
664 break;
665 case NativeWindow::ConsumerUsageBits:
666 value = core->consumer_usage_bit;
667 break;
668 case NativeWindow::BufferAge:
669 if (core->buffer_age > INT32_MAX) {
670 value = 0;
671 } else {
672 value = static_cast<u32>(core->buffer_age);
673 }
674 break;
675 default:
676 UNREACHABLE();
677 return Status::BadValue;
678 }
679
680 LOG_DEBUG(Service_NVFlinger, "what = {}, value = {}", what, value);
681
682 *out_value = static_cast<s32>(value);
683
684 return Status::NoError;
685}
686
687Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& listener,
688 NativeWindowApi api, bool producer_controlled_by_app,
689 QueueBufferOutput* output) {
690 BufferQueueCore::AutoLock lock(core);
691
692 LOG_DEBUG(Service_NVFlinger, "api = {} producer_controlled_by_app = {}", api,
693 producer_controlled_by_app);
694
695 if (core->is_abandoned) {
696 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
697 return Status::NoInit;
698 }
699
700 if (core->consumer_listener == nullptr) {
701 LOG_ERROR(Service_NVFlinger, "BufferQueue has no consumer");
702 return Status::NoInit;
703 }
704
705 if (output == nullptr) {
706 LOG_ERROR(Service_NVFlinger, "output was nullptr");
707 return Status::BadValue;
708 }
709
710 if (core->connected_api != NativeWindowApi::NoConnectedApi) {
711 LOG_ERROR(Service_NVFlinger, "already connected (cur = {} req = {})", core->connected_api,
712 api);
713 return Status::BadValue;
714 }
715
716 Status status = Status::NoError;
717 switch (api) {
718 case NativeWindowApi::Egl:
719 case NativeWindowApi::Cpu:
720 case NativeWindowApi::Media:
721 case NativeWindowApi::Camera:
722 core->connected_api = api;
723 output->Inflate(core->default_width, core->default_height, core->transform_hint,
724 static_cast<u32>(core->queue.size()));
725 core->connected_producer_listener = listener;
726 break;
727 default:
728 LOG_ERROR(Service_NVFlinger, "unknown api = {}", api);
729 status = Status::BadValue;
730 break;
731 }
732
733 core->buffer_has_been_queued = false;
734 core->dequeue_buffer_cannot_block =
735 core->consumer_controlled_by_app && producer_controlled_by_app;
736 core->allow_allocation = true;
737
738 return status;
739}
740
741Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
742 LOG_DEBUG(Service_NVFlinger, "api = {}", api);
743
744 Status status = Status::NoError;
745 std::shared_ptr<IConsumerListener> listener;
746
747 {
748 BufferQueueCore::AutoLock lock(core);
749
750 core->WaitWhileAllocatingLocked();
751
752 if (core->is_abandoned) {
753 // Disconnecting after the surface has been abandoned is a no-op.
754 return Status::NoError;
755 }
756
757 switch (api) {
758 case NativeWindowApi::Egl:
759 case NativeWindowApi::Cpu:
760 case NativeWindowApi::Media:
761 case NativeWindowApi::Camera:
762 if (core->connected_api == api) {
763 core->FreeAllBuffersLocked();
764 core->connected_producer_listener = nullptr;
765 core->connected_api = NativeWindowApi::NoConnectedApi;
766 core->SignalDequeueCondition();
767 buffer_wait_event->GetWritableEvent().Signal();
768 listener = core->consumer_listener;
769 } else if (core->connected_api != NativeWindowApi::NoConnectedApi) {
770 LOG_ERROR(Service_NVFlinger, "still connected to another api (cur = {} req = {})",
771 core->connected_api, api);
772 status = Status::BadValue;
773 }
774 break;
775 default:
776 LOG_ERROR(Service_NVFlinger, "unknown api = {}", api);
777 status = Status::BadValue;
778 break;
779 }
780 }
781
782 // Call back without lock held
783 if (listener != nullptr) {
784 listener->OnBuffersReleased();
785 }
786
787 return status;
788}
789
790Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
791 const std::shared_ptr<GraphicBuffer>& buffer) {
792 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
793
794 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
795 return Status::BadValue;
796 }
797
798 BufferQueueCore::AutoLock lock(core);
799
800 slots[slot] = {};
801 slots[slot].graphic_buffer = buffer;
802
803 // Most games preallocate a buffer and pass a valid buffer here. However, it is possible for
804 // this to be called with an empty buffer, Naruto Ultimate Ninja Storm is a game that does this.
805 if (buffer) {
806 slots[slot].is_preallocated = true;
807
808 core->override_max_buffer_count = core->GetPreallocatedBufferCountLocked();
809 core->default_width = buffer->Width();
810 core->default_height = buffer->Height();
811 core->default_buffer_format = buffer->Format();
812 }
813
814 core->SignalDequeueCondition();
815 buffer_wait_event->GetWritableEvent().Signal();
816
817 return Status::NoError;
818}
819
820void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId code, u32 flags) {
821 Status status{Status::NoError};
822 Parcel parcel_in{ctx.ReadBuffer()};
823 Parcel parcel_out{};
824
825 switch (code) {
826 case TransactionId::Connect: {
827 const auto enable_listener = parcel_in.Read<bool>();
828 const auto api = parcel_in.Read<NativeWindowApi>();
829 const auto producer_controlled_by_app = parcel_in.Read<bool>();
830
831 UNIMPLEMENTED_IF_MSG(enable_listener, "Listener is unimplemented!");
832
833 std::shared_ptr<IProducerListener> listener;
834 QueueBufferOutput output{};
835
836 status = Connect(listener, api, producer_controlled_by_app, &output);
837
838 parcel_out.Write(output);
839 break;
840 }
841 case TransactionId::SetPreallocatedBuffer: {
842 const auto slot = parcel_in.Read<s32>();
843 const auto buffer = parcel_in.ReadObject<GraphicBuffer>();
844
845 status = SetPreallocatedBuffer(slot, buffer);
846 break;
847 }
848 case TransactionId::DequeueBuffer: {
849 const auto is_async = parcel_in.Read<bool>();
850 const auto width = parcel_in.Read<u32>();
851 const auto height = parcel_in.Read<u32>();
852 const auto pixel_format = parcel_in.Read<PixelFormat>();
853 const auto usage = parcel_in.Read<u32>();
854
855 s32 slot{};
856 Fence fence{};
857
858 status = DequeueBuffer(&slot, &fence, is_async, width, height, pixel_format, usage);
859
860 parcel_out.Write(slot);
861 parcel_out.WriteObject(&fence);
862 break;
863 }
864 case TransactionId::RequestBuffer: {
865 const auto slot = parcel_in.Read<s32>();
866
867 std::shared_ptr<GraphicBuffer> buf;
868
869 status = RequestBuffer(slot, &buf);
870
871 parcel_out.WriteObject(buf);
872 break;
873 }
874 case TransactionId::QueueBuffer: {
875 const auto slot = parcel_in.Read<s32>();
876
877 QueueBufferInput input{parcel_in};
878 QueueBufferOutput output;
879
880 status = QueueBuffer(slot, input, &output);
881
882 parcel_out.Write(output);
883 break;
884 }
885 case TransactionId::Query: {
886 const auto what = parcel_in.Read<NativeWindow>();
887
888 s32 value{};
889
890 status = Query(what, &value);
891
892 parcel_out.Write(value);
893 break;
894 }
895 case TransactionId::CancelBuffer: {
896 const auto slot = parcel_in.Read<s32>();
897 const auto fence = parcel_in.ReadFlattened<Fence>();
898
899 CancelBuffer(slot, fence);
900 break;
901 }
902 case TransactionId::Disconnect: {
903 const auto api = parcel_in.Read<NativeWindowApi>();
904
905 status = Disconnect(api);
906 break;
907 }
908 case TransactionId::DetachBuffer: {
909 const auto slot = parcel_in.Read<s32>();
910
911 status = DetachBuffer(slot);
912 break;
913 }
914 case TransactionId::SetBufferCount: {
915 const auto buffer_count = parcel_in.Read<s32>();
916
917 status = SetBufferCount(buffer_count);
918 break;
919 }
920 case TransactionId::GetBufferHistory:
921 LOG_WARNING(Service_NVFlinger, "(STUBBED) called, transaction=GetBufferHistory");
922 break;
923 default:
924 ASSERT_MSG(false, "Unimplemented TransactionId {}", code);
925 break;
926 }
927
928 parcel_out.Write(status);
929
930 ctx.WriteBuffer(parcel_out.Serialize());
931}
932
933Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() {
934 return buffer_wait_event->GetReadableEvent();
935}
936
937} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h
new file mode 100644
index 000000000..5ddeebe0c
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h
@@ -0,0 +1,83 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueProducer.h
6
7#pragma once
8
9#include <condition_variable>
10#include <memory>
11#include <mutex>
12
13#include "common/common_funcs.h"
14#include "core/hle/service/nvdrv/nvdata.h"
15#include "core/hle/service/nvflinger/binder.h"
16#include "core/hle/service/nvflinger/buffer_queue_defs.h"
17#include "core/hle/service/nvflinger/buffer_slot.h"
18#include "core/hle/service/nvflinger/graphic_buffer_producer.h"
19#include "core/hle/service/nvflinger/pixel_format.h"
20#include "core/hle/service/nvflinger/status.h"
21#include "core/hle/service/nvflinger/window.h"
22
23namespace Kernel {
24class KernelCore;
25class KEvent;
26class KReadableEvent;
27class KWritableEvent;
28} // namespace Kernel
29
30namespace Service::KernelHelpers {
31class ServiceContext;
32} // namespace Service::KernelHelpers
33
34namespace Service::android {
35
36class BufferQueueCore;
37class IProducerListener;
38
39class BufferQueueProducer final : public IBinder {
40public:
41 explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_,
42 std::shared_ptr<BufferQueueCore> buffer_queue_core_);
43 ~BufferQueueProducer();
44
45 void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code, u32 flags) override;
46
47 Kernel::KReadableEvent& GetNativeHandle() override;
48
49public:
50 Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf);
51 Status SetBufferCount(s32 buffer_count);
52 Status DequeueBuffer(s32* out_slot, android::Fence* out_fence, bool async, u32 width,
53 u32 height, PixelFormat format, u32 usage);
54 Status DetachBuffer(s32 slot);
55 Status DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out_buffer, Fence* out_fence);
56 Status AttachBuffer(s32* outSlot, const std::shared_ptr<GraphicBuffer>& buffer);
57 Status QueueBuffer(s32 slot, const QueueBufferInput& input, QueueBufferOutput* output);
58 void CancelBuffer(s32 slot, const Fence& fence);
59 Status Query(NativeWindow what, s32* out_value);
60 Status Connect(const std::shared_ptr<IProducerListener>& listener, NativeWindowApi api,
61 bool producer_controlled_by_app, QueueBufferOutput* output);
62
63 Status Disconnect(NativeWindowApi api);
64 Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<GraphicBuffer>& buffer);
65
66private:
67 BufferQueueProducer(const BufferQueueProducer&) = delete;
68
69 Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* returnFlags) const;
70
71 Kernel::KEvent* buffer_wait_event{};
72 Service::KernelHelpers::ServiceContext& service_context;
73
74 std::shared_ptr<BufferQueueCore> core;
75 BufferQueueDefs::SlotsType& slots;
76 u32 sticky_transform{};
77 std::mutex callback_mutex;
78 s32 next_callback_ticket{};
79 s32 current_callback_ticket{};
80 std::condition_variable callback_condition;
81};
82
83} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_slot.h b/src/core/hle/service/nvflinger/buffer_slot.h
new file mode 100644
index 000000000..e3ea58910
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_slot.h
@@ -0,0 +1,39 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferSlot.h
6
7#pragma once
8
9#include <memory>
10
11#include "common/common_types.h"
12#include "core/hle/service/nvflinger/ui/fence.h"
13
14namespace Service::android {
15
16class GraphicBuffer;
17
18enum class BufferState : u32 {
19 Free = 0,
20 Dequeued = 1,
21 Queued = 2,
22 Acquired = 3,
23};
24
25struct BufferSlot final {
26 constexpr BufferSlot() = default;
27
28 std::shared_ptr<GraphicBuffer> graphic_buffer;
29 BufferState buffer_state{BufferState::Free};
30 bool request_buffer_called{};
31 u64 frame_number{};
32 Fence fence;
33 bool acquire_called{};
34 bool needs_cleanup_on_release{};
35 bool attached_by_consumer{};
36 bool is_preallocated{};
37};
38
39} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_transform_flags.h b/src/core/hle/service/nvflinger/buffer_transform_flags.h
new file mode 100644
index 000000000..e8e6300e3
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_transform_flags.h
@@ -0,0 +1,25 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::android {
9
10enum class BufferTransformFlags : u32 {
11 /// No transform flags are set
12 Unset = 0x00,
13 /// Flip source image horizontally (around the vertical axis)
14 FlipH = 0x01,
15 /// Flip source image vertically (around the horizontal axis)
16 FlipV = 0x02,
17 /// Rotate source image 90 degrees clockwise
18 Rotate90 = 0x04,
19 /// Rotate source image 180 degrees
20 Rotate180 = 0x03,
21 /// Rotate source image 270 degrees clockwise
22 Rotate270 = 0x07,
23};
24
25} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp
new file mode 100644
index 000000000..3ccbb7fb8
--- /dev/null
+++ b/src/core/hle/service/nvflinger/consumer_base.cpp
@@ -0,0 +1,130 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2010 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/ConsumerBase.cpp
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/hle/service/nvflinger/buffer_item.h"
10#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
11#include "core/hle/service/nvflinger/buffer_queue_core.h"
12#include "core/hle/service/nvflinger/consumer_base.h"
13#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
14
15namespace Service::android {
16
17ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_)
18 : consumer{std::move(consumer_)} {}
19
20ConsumerBase::~ConsumerBase() {
21 std::unique_lock lock(mutex);
22
23 ASSERT_MSG(is_abandoned, "consumer is not abandoned!");
24}
25
26void ConsumerBase::Connect(bool controlled_by_app) {
27 consumer->Connect(shared_from_this(), controlled_by_app);
28}
29
30void ConsumerBase::FreeBufferLocked(s32 slot_index) {
31 LOG_DEBUG(Service_NVFlinger, "slot_index={}", slot_index);
32
33 slots[slot_index].graphic_buffer = nullptr;
34 slots[slot_index].fence = Fence::NoFence();
35 slots[slot_index].frame_number = 0;
36}
37
38void ConsumerBase::OnFrameAvailable(const BufferItem& item) {
39 std::unique_lock lock(mutex);
40 LOG_DEBUG(Service_NVFlinger, "called");
41}
42
43void ConsumerBase::OnFrameReplaced(const BufferItem& item) {
44 std::unique_lock lock(mutex);
45 LOG_DEBUG(Service_NVFlinger, "called");
46}
47
48void ConsumerBase::OnBuffersReleased() {
49 std::unique_lock lock(mutex);
50 LOG_DEBUG(Service_NVFlinger, "called");
51}
52
53void ConsumerBase::OnSidebandStreamChanged() {}
54
55Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when,
56 u64 max_frame_number) {
57 if (is_abandoned) {
58 LOG_ERROR(Service_NVFlinger, "consumer is abandoned!");
59 return Status::NoInit;
60 }
61
62 Status err = consumer->AcquireBuffer(item, present_when, max_frame_number);
63 if (err != Status::NoError) {
64 return err;
65 }
66
67 if (item->graphic_buffer != nullptr) {
68 if (slots[item->slot].graphic_buffer != nullptr) {
69 FreeBufferLocked(item->slot);
70 }
71 slots[item->slot].graphic_buffer = item->graphic_buffer;
72 }
73
74 slots[item->slot].frame_number = item->frame_number;
75 slots[item->slot].fence = item->fence;
76
77 LOG_DEBUG(Service_NVFlinger, "slot={}", item->slot);
78
79 return Status::NoError;
80}
81
82Status ConsumerBase::AddReleaseFenceLocked(s32 slot,
83 const std::shared_ptr<GraphicBuffer> graphic_buffer,
84 const Fence& fence) {
85 LOG_DEBUG(Service_NVFlinger, "slot={}", slot);
86
87 // If consumer no longer tracks this graphic_buffer, we can safely
88 // drop this fence, as it will never be received by the producer.
89
90 if (!StillTracking(slot, graphic_buffer)) {
91 return Status::NoError;
92 }
93
94 slots[slot].fence = fence;
95
96 return Status::NoError;
97}
98
99Status ConsumerBase::ReleaseBufferLocked(s32 slot,
100 const std::shared_ptr<GraphicBuffer> graphic_buffer) {
101 // If consumer no longer tracks this graphic_buffer (we received a new
102 // buffer on the same slot), the buffer producer is definitely no longer
103 // tracking it.
104
105 if (!StillTracking(slot, graphic_buffer)) {
106 return Status::NoError;
107 }
108
109 LOG_DEBUG(Service_NVFlinger, "slot={}", slot);
110 Status err = consumer->ReleaseBuffer(slot, slots[slot].frame_number, slots[slot].fence);
111 if (err == Status::StaleBufferSlot) {
112 FreeBufferLocked(slot);
113 }
114
115 slots[slot].fence = Fence::NoFence();
116
117 return err;
118}
119
120bool ConsumerBase::StillTracking(s32 slot,
121 const std::shared_ptr<GraphicBuffer> graphic_buffer) const {
122 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
123 return false;
124 }
125
126 return (slots[slot].graphic_buffer != nullptr &&
127 slots[slot].graphic_buffer->Handle() == graphic_buffer->Handle());
128}
129
130} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h
new file mode 100644
index 000000000..9ab949420
--- /dev/null
+++ b/src/core/hle/service/nvflinger/consumer_base.h
@@ -0,0 +1,61 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2010 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/ConsumerBase.h
6
7#pragma once
8
9#include <array>
10#include <chrono>
11#include <memory>
12#include <mutex>
13
14#include "common/common_types.h"
15#include "core/hle/service/nvflinger/buffer_queue_defs.h"
16#include "core/hle/service/nvflinger/consumer_listener.h"
17#include "core/hle/service/nvflinger/status.h"
18
19namespace Service::android {
20
21class BufferItem;
22class BufferQueueConsumer;
23
24class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> {
25public:
26 void Connect(bool controlled_by_app);
27
28protected:
29 explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_);
30 virtual ~ConsumerBase();
31
32 virtual void OnFrameAvailable(const BufferItem& item) override;
33 virtual void OnFrameReplaced(const BufferItem& item) override;
34 virtual void OnBuffersReleased() override;
35 virtual void OnSidebandStreamChanged() override;
36
37 void FreeBufferLocked(s32 slot_index);
38 Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when,
39 u64 max_frame_number = 0);
40 Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer);
41 bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer) const;
42 Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer,
43 const Fence& fence);
44
45 struct Slot final {
46 std::shared_ptr<GraphicBuffer> graphic_buffer;
47 Fence fence;
48 u64 frame_number{};
49 };
50
51protected:
52 std::array<Slot, BufferQueueDefs::NUM_BUFFER_SLOTS> slots;
53
54 bool is_abandoned{};
55
56 std::unique_ptr<BufferQueueConsumer> consumer;
57
58 mutable std::mutex mutex;
59};
60
61} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/consumer_listener.h b/src/core/hle/service/nvflinger/consumer_listener.h
new file mode 100644
index 000000000..b6d1c3e9a
--- /dev/null
+++ b/src/core/hle/service/nvflinger/consumer_listener.h
@@ -0,0 +1,26 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IConsumerListener.h
6
7#pragma once
8
9namespace Service::android {
10
11class BufferItem;
12
13/// ConsumerListener is the interface through which the BufferQueue notifies the consumer of events
14/// that the consumer may wish to react to.
15class IConsumerListener {
16public:
17 IConsumerListener() = default;
18 virtual ~IConsumerListener() = default;
19
20 virtual void OnFrameAvailable(const BufferItem& item) = 0;
21 virtual void OnFrameReplaced(const BufferItem& item) = 0;
22 virtual void OnBuffersReleased() = 0;
23 virtual void OnSidebandStreamChanged() = 0;
24};
25
26}; // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
new file mode 100644
index 000000000..d4da98ddb
--- /dev/null
+++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
@@ -0,0 +1,20 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2010 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp
6
7#pragma once
8
9#include "core/hle/service/nvflinger/graphic_buffer_producer.h"
10#include "core/hle/service/nvflinger/parcel.h"
11
12namespace Service::android {
13
14QueueBufferInput::QueueBufferInput(Parcel& parcel) {
15 parcel.ReadFlattened(*this);
16}
17
18QueueBufferOutput::QueueBufferOutput() = default;
19
20} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvflinger/graphic_buffer_producer.h
new file mode 100644
index 000000000..98d27871c
--- /dev/null
+++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.h
@@ -0,0 +1,76 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2010 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IGraphicBufferProducer.h
6
7#pragma once
8
9#include "common/common_funcs.h"
10#include "common/common_types.h"
11#include "common/math_util.h"
12#include "core/hle/service/nvflinger/ui/fence.h"
13#include "core/hle/service/nvflinger/window.h"
14
15namespace Service::android {
16
17class Parcel;
18
19#pragma pack(push, 1)
20struct QueueBufferInput final {
21 explicit QueueBufferInput(Parcel& parcel);
22
23 void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_,
24 NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_,
25 u32* sticky_transform_, bool* async_, s32* swap_interval_, Fence* fence_) const {
26 *timestamp_ = timestamp;
27 *is_auto_timestamp_ = static_cast<bool>(is_auto_timestamp);
28 *crop_ = crop;
29 *scaling_mode_ = scaling_mode;
30 *transform_ = transform;
31 *sticky_transform_ = sticky_transform;
32 *async_ = static_cast<bool>(async);
33 *swap_interval_ = swap_interval;
34 *fence_ = fence;
35 }
36
37private:
38 s64 timestamp{};
39 s32 is_auto_timestamp{};
40 Common::Rectangle<s32> crop{};
41 NativeWindowScalingMode scaling_mode{};
42 NativeWindowTransform transform{};
43 u32 sticky_transform{};
44 s32 async{};
45 s32 swap_interval{};
46 Fence fence{};
47};
48#pragma pack(pop)
49static_assert(sizeof(QueueBufferInput) == 84, "QueueBufferInput has wrong size");
50
51struct QueueBufferOutput final {
52 QueueBufferOutput();
53
54 void Deflate(u32* width_, u32* height_, u32* transform_hint_, u32* num_pending_buffers_) const {
55 *width_ = width;
56 *height_ = height;
57 *transform_hint_ = transform_hint;
58 *num_pending_buffers_ = num_pending_buffers;
59 }
60
61 void Inflate(u32 width_, u32 height_, u32 transform_hint_, u32 num_pending_buffers_) {
62 width = width_;
63 height = height_;
64 transform_hint = transform_hint_;
65 num_pending_buffers = num_pending_buffers_;
66 }
67
68private:
69 u32 width{};
70 u32 height{};
71 u32 transform_hint{};
72 u32 num_pending_buffers{};
73};
74static_assert(sizeof(QueueBufferOutput) == 16, "QueueBufferOutput has wrong size");
75
76} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp
new file mode 100644
index 000000000..0c937d682
--- /dev/null
+++ b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp
@@ -0,0 +1,36 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#include <mutex>
5
6#include "common/common_types.h"
7#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
8
9namespace Service::NVFlinger {
10
11HosBinderDriverServer::HosBinderDriverServer(Core::System& system_)
12 : service_context(system_, "HosBinderDriverServer") {}
13
14HosBinderDriverServer::~HosBinderDriverServer() {}
15
16u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) {
17 std::lock_guard lk{lock};
18
19 last_id++;
20
21 producers[last_id] = std::move(binder);
22
23 return last_id;
24}
25
26android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) {
27 std::lock_guard lk{lock};
28
29 if (auto search = producers.find(id); search != producers.end()) {
30 return search->second.get();
31 }
32
33 return {};
34}
35
36} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.h b/src/core/hle/service/nvflinger/hos_binder_driver_server.h
new file mode 100644
index 000000000..cbca87fa0
--- /dev/null
+++ b/src/core/hle/service/nvflinger/hos_binder_driver_server.h
@@ -0,0 +1,37 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include <memory>
7#include <mutex>
8#include <unordered_map>
9
10#include "common/common_types.h"
11#include "core/hle/service/kernel_helpers.h"
12#include "core/hle/service/nvflinger/binder.h"
13
14namespace Core {
15class System;
16}
17
18namespace Service::NVFlinger {
19
20class HosBinderDriverServer final {
21public:
22 explicit HosBinderDriverServer(Core::System& system_);
23 ~HosBinderDriverServer();
24
25 u64 RegisterProducer(std::unique_ptr<android::IBinder>&& binder);
26
27 android::IBinder* TryGetProducer(u64 id);
28
29private:
30 KernelHelpers::ServiceContext service_context;
31
32 std::unordered_map<u64, std::unique_ptr<android::IBinder>> producers;
33 std::mutex lock;
34 u64 last_id{};
35};
36
37} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 01e69de30..76ce1fbfd 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -1,6 +1,5 @@
1// Copyright 2018 yuzu emulator team 1// SPDX-License-Identifier: GPL-3.0-or-later
2// Licensed under GPLv2 or any later version 2// Copyright 2021 yuzu Emulator Project
3// Refer to the license.txt file included.
4 3
5#include <algorithm> 4#include <algorithm>
6#include <optional> 5#include <optional>
@@ -16,8 +15,11 @@
16#include "core/hle/kernel/k_readable_event.h" 15#include "core/hle/kernel/k_readable_event.h"
17#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 16#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
18#include "core/hle/service/nvdrv/nvdrv.h" 17#include "core/hle/service/nvdrv/nvdrv.h"
19#include "core/hle/service/nvflinger/buffer_queue.h" 18#include "core/hle/service/nvflinger/buffer_item_consumer.h"
19#include "core/hle/service/nvflinger/buffer_queue_core.h"
20#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
20#include "core/hle/service/nvflinger/nvflinger.h" 21#include "core/hle/service/nvflinger/nvflinger.h"
22#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
21#include "core/hle/service/vi/display/vi_display.h" 23#include "core/hle/service/vi/display/vi_display.h"
22#include "core/hle/service/vi/layer/vi_layer.h" 24#include "core/hle/service/vi/layer/vi_layer.h"
23#include "video_core/gpu.h" 25#include "video_core/gpu.h"
@@ -53,13 +55,14 @@ void NVFlinger::SplitVSync(std::stop_token stop_token) {
53 } 55 }
54} 56}
55 57
56NVFlinger::NVFlinger(Core::System& system_) 58NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_)
57 : system(system_), service_context(system_, "nvflinger") { 59 : system(system_), service_context(system_, "nvflinger"),
58 displays.emplace_back(0, "Default", service_context, system); 60 hos_binder_driver_server(hos_binder_driver_server_) {
59 displays.emplace_back(1, "External", service_context, system); 61 displays.emplace_back(0, "Default", hos_binder_driver_server, service_context, system);
60 displays.emplace_back(2, "Edid", service_context, system); 62 displays.emplace_back(1, "External", hos_binder_driver_server, service_context, system);
61 displays.emplace_back(3, "Internal", service_context, system); 63 displays.emplace_back(2, "Edid", hos_binder_driver_server, service_context, system);
62 displays.emplace_back(4, "Null", service_context, system); 64 displays.emplace_back(3, "Internal", hos_binder_driver_server, service_context, system);
65 displays.emplace_back(4, "Null", hos_binder_driver_server, service_context, system);
63 guard = std::make_shared<std::mutex>(); 66 guard = std::make_shared<std::mutex>();
64 67
65 // Schedule the screen composition events 68 // Schedule the screen composition events
@@ -83,12 +86,15 @@ NVFlinger::NVFlinger(Core::System& system_)
83} 86}
84 87
85NVFlinger::~NVFlinger() { 88NVFlinger::~NVFlinger() {
86 for (auto& buffer_queue : buffer_queues) {
87 buffer_queue->Disconnect();
88 }
89 if (!system.IsMulticore()) { 89 if (!system.IsMulticore()) {
90 system.CoreTiming().UnscheduleEvent(composition_event, 0); 90 system.CoreTiming().UnscheduleEvent(composition_event, 0);
91 } 91 }
92
93 for (auto& display : displays) {
94 for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
95 display.GetLayer(layer).Core().NotifyShutdown();
96 }
97 }
92} 98}
93 99
94void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { 100void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
@@ -125,10 +131,8 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
125} 131}
126 132
127void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) { 133void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
128 const u32 buffer_queue_id = next_buffer_queue_id++; 134 const auto buffer_id = next_buffer_queue_id++;
129 buffer_queues.emplace_back( 135 display.CreateLayer(layer_id, buffer_id);
130 std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id, service_context));
131 display.CreateLayer(layer_id, *buffer_queues.back());
132} 136}
133 137
134void NVFlinger::CloseLayer(u64 layer_id) { 138void NVFlinger::CloseLayer(u64 layer_id) {
@@ -147,7 +151,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
147 return std::nullopt; 151 return std::nullopt;
148 } 152 }
149 153
150 return layer->GetBufferQueue().GetId(); 154 return layer->GetBinderId();
151} 155}
152 156
153Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) { 157Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
@@ -161,18 +165,6 @@ Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
161 return &display->GetVSyncEvent(); 165 return &display->GetVSyncEvent();
162} 166}
163 167
164BufferQueue* NVFlinger::FindBufferQueue(u32 id) {
165 const auto lock_guard = Lock();
166 const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
167 [id](const auto& queue) { return queue->GetId() == id; });
168
169 if (itr == buffer_queues.end()) {
170 return nullptr;
171 }
172
173 return itr->get();
174}
175
176VI::Display* NVFlinger::FindDisplay(u64 display_id) { 168VI::Display* NVFlinger::FindDisplay(u64 display_id) {
177 const auto itr = 169 const auto itr =
178 std::find_if(displays.begin(), displays.end(), 170 std::find_if(displays.begin(), displays.end(),
@@ -246,23 +238,22 @@ void NVFlinger::Compose() {
246 238
247 // TODO(Subv): Support more than 1 layer. 239 // TODO(Subv): Support more than 1 layer.
248 VI::Layer& layer = display.GetLayer(0); 240 VI::Layer& layer = display.GetLayer(0);
249 auto& buffer_queue = layer.GetBufferQueue();
250 241
251 // Search for a queued buffer and acquire it 242 android::BufferItem buffer{};
252 auto buffer = buffer_queue.AcquireBuffer(); 243 const auto status = layer.GetConsumer().AcquireBuffer(&buffer, {}, false);
253 244
254 if (!buffer) { 245 if (status != android::Status::NoError) {
255 continue; 246 continue;
256 } 247 }
257 248
258 const auto& igbp_buffer = buffer->get().igbp_buffer; 249 const auto& igbp_buffer = *buffer.graphic_buffer;
259 250
260 if (!system.IsPoweredOn()) { 251 if (!system.IsPoweredOn()) {
261 return; // We are likely shutting down 252 return; // We are likely shutting down
262 } 253 }
263 254
264 auto& gpu = system.GPU(); 255 auto& gpu = system.GPU();
265 const auto& multi_fence = buffer->get().multi_fence; 256 const auto& multi_fence = buffer.fence;
266 guard->unlock(); 257 guard->unlock();
267 for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { 258 for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) {
268 const auto& fence = multi_fence.fences[fence_id]; 259 const auto& fence = multi_fence.fences[fence_id];
@@ -278,12 +269,18 @@ void NVFlinger::Compose() {
278 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); 269 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");
279 ASSERT(nvdisp); 270 ASSERT(nvdisp);
280 271
281 nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.external_format, 272 Common::Rectangle<int> crop_rect{
282 igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, 273 static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()),
283 buffer->get().transform, buffer->get().crop_rect); 274 static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())};
275
276 nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(),
277 igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(),
278 static_cast<android::BufferTransformFlags>(buffer.transform), crop_rect);
279
280 swap_interval = buffer.swap_interval;
284 281
285 swap_interval = buffer->get().swap_interval; 282 auto fence = android::Fence::NoFence();
286 buffer_queue.ReleaseBuffer(buffer->get().slot); 283 layer.GetConsumer().ReleaseBuffer(buffer, fence);
287 } 284 }
288} 285}
289 286
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 7935cf773..ed160f6f9 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -1,6 +1,5 @@
1// Copyright 2018 yuzu emulator team 1// SPDX-License-Identifier: GPL-3.0-or-later
2// Licensed under GPLv2 or any later version 2// Copyright 2021 yuzu Emulator Project
3// Refer to the license.txt file included.
4 3
5#pragma once 4#pragma once
6 5
@@ -37,13 +36,16 @@ class Display;
37class Layer; 36class Layer;
38} // namespace Service::VI 37} // namespace Service::VI
39 38
40namespace Service::NVFlinger { 39namespace Service::android {
40class BufferQueueCore;
41class BufferQueueProducer;
42} // namespace Service::android
41 43
42class BufferQueue; 44namespace Service::NVFlinger {
43 45
44class NVFlinger final { 46class NVFlinger final {
45public: 47public:
46 explicit NVFlinger(Core::System& system_); 48 explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
47 ~NVFlinger(); 49 ~NVFlinger();
48 50
49 /// Sets the NVDrv module instance to use to send buffers to the GPU. 51 /// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -72,9 +74,6 @@ public:
72 /// If an invalid display ID is provided, then nullptr is returned. 74 /// If an invalid display ID is provided, then nullptr is returned.
73 [[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id); 75 [[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id);
74 76
75 /// Obtains a buffer queue identified by the ID.
76 [[nodiscard]] BufferQueue* FindBufferQueue(u32 id);
77
78 /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when 77 /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
79 /// finished. 78 /// finished.
80 void Compose(); 79 void Compose();
@@ -82,6 +81,12 @@ public:
82 [[nodiscard]] s64 GetNextTicks() const; 81 [[nodiscard]] s64 GetNextTicks() const;
83 82
84private: 83private:
84 struct Layer {
85 std::unique_ptr<android::BufferQueueCore> core;
86 std::unique_ptr<android::BufferQueueProducer> producer;
87 };
88
89private:
85 [[nodiscard]] std::unique_lock<std::mutex> Lock() const { 90 [[nodiscard]] std::unique_lock<std::mutex> Lock() const {
86 return std::unique_lock{*guard}; 91 return std::unique_lock{*guard};
87 } 92 }
@@ -111,7 +116,6 @@ private:
111 std::shared_ptr<Nvidia::Module> nvdrv; 116 std::shared_ptr<Nvidia::Module> nvdrv;
112 117
113 std::list<VI::Display> displays; 118 std::list<VI::Display> displays;
114 std::vector<std::unique_ptr<BufferQueue>> buffer_queues;
115 119
116 /// Id to use for the next layer that is created, this counter is shared among all displays. 120 /// Id to use for the next layer that is created, this counter is shared among all displays.
117 u64 next_layer_id = 1; 121 u64 next_layer_id = 1;
@@ -131,6 +135,8 @@ private:
131 std::jthread vsync_thread; 135 std::jthread vsync_thread;
132 136
133 KernelHelpers::ServiceContext service_context; 137 KernelHelpers::ServiceContext service_context;
138
139 HosBinderDriverServer& hos_binder_driver_server;
134}; 140};
135 141
136} // namespace Service::NVFlinger 142} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h
new file mode 100644
index 000000000..aa36e6479
--- /dev/null
+++ b/src/core/hle/service/nvflinger/parcel.h
@@ -0,0 +1,172 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include <memory>
7#include <vector>
8
9#include "common/alignment.h"
10#include "common/assert.h"
11#include "common/common_types.h"
12
13namespace Service::android {
14
15class Parcel final {
16public:
17 static constexpr std::size_t DefaultBufferSize = 0x40;
18
19 Parcel() : buffer(DefaultBufferSize) {}
20
21 template <typename T>
22 explicit Parcel(const T& out_data) : buffer(DefaultBufferSize) {
23 Write(out_data);
24 }
25
26 explicit Parcel(std::vector<u8> in_data) : buffer(std::move(in_data)) {
27 DeserializeHeader();
28 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
29 }
30
31 template <typename T>
32 void Read(T& val) {
33 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
34 ASSERT(read_index + sizeof(T) <= buffer.size());
35
36 std::memcpy(&val, buffer.data() + read_index, sizeof(T));
37 read_index += sizeof(T);
38 read_index = Common::AlignUp(read_index, 4);
39 }
40
41 template <typename T>
42 T Read() {
43 T val;
44 Read(val);
45 return val;
46 }
47
48 template <typename T>
49 void ReadFlattened(T& val) {
50 const auto flattened_size = Read<s64>();
51 ASSERT(sizeof(T) == flattened_size);
52 Read(val);
53 }
54
55 template <typename T>
56 T ReadFlattened() {
57 T val;
58 ReadFlattened(val);
59 return val;
60 }
61
62 template <typename T>
63 T ReadUnaligned() {
64 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
65 ASSERT(read_index + sizeof(T) <= buffer.size());
66
67 T val;
68 std::memcpy(&val, buffer.data() + read_index, sizeof(T));
69 read_index += sizeof(T);
70 return val;
71 }
72
73 template <typename T>
74 const std::shared_ptr<T> ReadObject() {
75 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
76
77 const auto is_valid{Read<bool>()};
78
79 if (is_valid) {
80 auto result = std::make_shared<T>();
81 ReadFlattened(*result);
82 return result;
83 }
84
85 return {};
86 }
87
88 std::u16string ReadInterfaceToken() {
89 [[maybe_unused]] const u32 unknown = Read<u32>();
90 const u32 length = Read<u32>();
91
92 std::u16string token;
93 token.reserve(length + 1);
94
95 for (u32 ch = 0; ch < length + 1; ++ch) {
96 token.push_back(ReadUnaligned<u16>());
97 }
98
99 read_index = Common::AlignUp(read_index, 4);
100
101 return token;
102 }
103
104 template <typename T>
105 void Write(const T& val) {
106 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
107
108 if (buffer.size() < write_index + sizeof(T)) {
109 buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
110 }
111
112 std::memcpy(buffer.data() + write_index, &val, sizeof(T));
113 write_index += sizeof(T);
114 write_index = Common::AlignUp(write_index, 4);
115 }
116
117 template <typename T>
118 void WriteObject(const T* ptr) {
119 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
120
121 if (!ptr) {
122 Write<u32>(0);
123 return;
124 }
125
126 Write<u32>(1);
127 Write<s64>(sizeof(T));
128 Write(*ptr);
129 }
130
131 template <typename T>
132 void WriteObject(const std::shared_ptr<T> ptr) {
133 WriteObject(ptr.get());
134 }
135
136 void DeserializeHeader() {
137 ASSERT(buffer.size() > sizeof(Header));
138
139 Header header{};
140 std::memcpy(&header, buffer.data(), sizeof(Header));
141
142 read_index = header.data_offset;
143 }
144
145 std::vector<u8> Serialize() const {
146 ASSERT(read_index == 0);
147
148 Header header{};
149 header.data_size = static_cast<u32>(write_index - sizeof(Header));
150 header.data_offset = sizeof(Header);
151 header.objects_size = 4;
152 header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size);
153 std::memcpy(buffer.data(), &header, sizeof(Header));
154
155 return buffer;
156 }
157
158private:
159 struct Header {
160 u32 data_size;
161 u32 data_offset;
162 u32 objects_size;
163 u32 objects_offset;
164 };
165 static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
166
167 mutable std::vector<u8> buffer;
168 std::size_t read_index = 0;
169 std::size_t write_index = sizeof(Header);
170};
171
172} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/pixel_format.h b/src/core/hle/service/nvflinger/pixel_format.h
new file mode 100644
index 000000000..8a77d8bea
--- /dev/null
+++ b/src/core/hle/service/nvflinger/pixel_format.h
@@ -0,0 +1,21 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::android {
9
10enum class PixelFormat : u32 {
11 NoFormat = 0,
12 Rgba8888 = 1,
13 Rgbx8888 = 2,
14 Rgb888 = 3,
15 Rgb565 = 4,
16 Bgra8888 = 5,
17 Rgba5551 = 6,
18 Rgba4444 = 7,
19};
20
21} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/producer_listener.h b/src/core/hle/service/nvflinger/producer_listener.h
new file mode 100644
index 000000000..468e06431
--- /dev/null
+++ b/src/core/hle/service/nvflinger/producer_listener.h
@@ -0,0 +1,16 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IProducerListener.h
6
7#pragma once
8
9namespace Service::android {
10
11class IProducerListener {
12public:
13 virtual void OnBufferReleased() = 0;
14};
15
16} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/status.h b/src/core/hle/service/nvflinger/status.h
new file mode 100644
index 000000000..a003eda89
--- /dev/null
+++ b/src/core/hle/service/nvflinger/status.h
@@ -0,0 +1,28 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace Service::android {
10
11enum class Status : s32 {
12 None = 0,
13 NoError = 0,
14 StaleBufferSlot = 1,
15 NoBufferAvailable = 2,
16 PresentLater = 3,
17 WouldBlock = -11,
18 NoMemory = -12,
19 Busy = -16,
20 NoInit = -19,
21 BadValue = -22,
22 InvalidOperation = -37,
23 BufferNeedsReallocation = 1,
24 ReleaseAllBuffers = 2,
25};
26DECLARE_ENUM_FLAG_OPERATORS(Status);
27
28} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/ui/fence.h b/src/core/hle/service/nvflinger/ui/fence.h
new file mode 100644
index 000000000..4a74e26a3
--- /dev/null
+++ b/src/core/hle/service/nvflinger/ui/fence.h
@@ -0,0 +1,32 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2012 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/Fence.h
6
7#pragma once
8
9#include <array>
10
11#include "common/common_types.h"
12#include "core/hle/service/nvdrv/nvdata.h"
13
14namespace Service::android {
15
16class Fence {
17public:
18 constexpr Fence() = default;
19
20 static constexpr Fence NoFence() {
21 Fence fence;
22 fence.fences[0].id = -1;
23 return fence;
24 }
25
26public:
27 u32 num_fences{};
28 std::array<Service::Nvidia::NvFence, 4> fences{};
29};
30static_assert(sizeof(Fence) == 36, "Fence has wrong size");
31
32} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/ui/graphic_buffer.h b/src/core/hle/service/nvflinger/ui/graphic_buffer.h
new file mode 100644
index 000000000..7abbf78ba
--- /dev/null
+++ b/src/core/hle/service/nvflinger/ui/graphic_buffer.h
@@ -0,0 +1,100 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2007 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/GraphicBuffer.h
6
7#pragma once
8
9#include "common/common_funcs.h"
10#include "common/common_types.h"
11#include "core/hle/service/nvflinger/pixel_format.h"
12
13namespace Service::android {
14
15class GraphicBuffer final {
16public:
17 constexpr GraphicBuffer() = default;
18
19 constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
20 : width{static_cast<s32>(width_)}, height{static_cast<s32>(height_)}, format{format_},
21 usage{static_cast<s32>(usage_)} {}
22
23 constexpr u32 Width() const {
24 return static_cast<u32>(width);
25 }
26
27 constexpr u32 Height() const {
28 return static_cast<u32>(height);
29 }
30
31 constexpr u32 Stride() const {
32 return static_cast<u32>(stride);
33 }
34
35 constexpr u32 Usage() const {
36 return static_cast<u32>(usage);
37 }
38
39 constexpr PixelFormat Format() const {
40 return format;
41 }
42
43 constexpr u32 BufferId() const {
44 return buffer_id;
45 }
46
47 constexpr PixelFormat ExternalFormat() const {
48 return external_format;
49 }
50
51 constexpr u32 Handle() const {
52 return handle;
53 }
54
55 constexpr u32 Offset() const {
56 return offset;
57 }
58
59 constexpr bool NeedsReallocation(u32 width_, u32 height_, PixelFormat format_,
60 u32 usage_) const {
61 if (static_cast<s32>(width_) != width) {
62 return true;
63 }
64
65 if (static_cast<s32>(height_) != height) {
66 return true;
67 }
68
69 if (format_ != format) {
70 return true;
71 }
72
73 if ((static_cast<u32>(usage) & usage_) != usage_) {
74 return true;
75 }
76
77 return false;
78 }
79
80private:
81 u32 magic{};
82 s32 width{};
83 s32 height{};
84 s32 stride{};
85 PixelFormat format{};
86 s32 usage{};
87 INSERT_PADDING_WORDS(1);
88 u32 index{};
89 INSERT_PADDING_WORDS(3);
90 u32 buffer_id{};
91 INSERT_PADDING_WORDS(6);
92 PixelFormat external_format{};
93 INSERT_PADDING_WORDS(10);
94 u32 handle{};
95 u32 offset{};
96 INSERT_PADDING_WORDS(60);
97};
98static_assert(sizeof(GraphicBuffer) == 0x16C, "GraphicBuffer has wrong size");
99
100} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/window.h b/src/core/hle/service/nvflinger/window.h
new file mode 100644
index 000000000..e26f8160e
--- /dev/null
+++ b/src/core/hle/service/nvflinger/window.h
@@ -0,0 +1,53 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace Service::android {
10
11/// Attributes queryable with Query
12enum class NativeWindow : s32 {
13 Width = 0,
14 Height = 1,
15 Format = 2,
16 MinUndequeedBuffers = 3,
17 QueuesToWindowComposer = 4,
18 ConcreteType = 5,
19 DefaultWidth = 6,
20 DefaultHeight = 7,
21 TransformHint = 8,
22 ConsumerRunningBehind = 9,
23 ConsumerUsageBits = 10,
24 StickyTransform = 11,
25 DefaultDataSpace = 12,
26 BufferAge = 13,
27};
28
29/// Parameter for Connect/Disconnect
30enum class NativeWindowApi : s32 {
31 NoConnectedApi = 0,
32 Egl = 1,
33 Cpu = 2,
34 Media = 3,
35 Camera = 4,
36};
37
38/// Scaling mode parameter for QueueBuffer
39enum class NativeWindowScalingMode : s32 {
40 Freeze = 0,
41 ScaleToWindow = 1,
42 ScaleCrop = 2,
43 NoScaleCrop = 3,
44};
45
46/// Transform parameter for QueueBuffer
47enum class NativeWindowTransform : u32 {
48 None = 0x0,
49 InverseDisplay = 0x08,
50};
51DECLARE_ENUM_FLAG_OPERATORS(NativeWindowTransform);
52
53} // namespace Service::android
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index eb1138313..ab3286db9 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -49,6 +49,7 @@
49#include "core/hle/service/npns/npns.h" 49#include "core/hle/service/npns/npns.h"
50#include "core/hle/service/ns/ns.h" 50#include "core/hle/service/ns/ns.h"
51#include "core/hle/service/nvdrv/nvdrv.h" 51#include "core/hle/service/nvdrv/nvdrv.h"
52#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
52#include "core/hle/service/nvflinger/nvflinger.h" 53#include "core/hle/service/nvflinger/nvflinger.h"
53#include "core/hle/service/olsc/olsc.h" 54#include "core/hle/service/olsc/olsc.h"
54#include "core/hle/service/pcie/pcie.h" 55#include "core/hle/service/pcie/pcie.h"
@@ -230,7 +231,8 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& sessi
230 231
231/// Initialize Services 232/// Initialize Services
232Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) 233Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system)
233 : nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system)} { 234 : hos_binder_driver_server{std::make_unique<NVFlinger::HosBinderDriverServer>(system)},
235 nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system, *hos_binder_driver_server)} {
234 236
235 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it 237 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
236 // here and pass it into the respective InstallInterfaces functions. 238 // here and pass it into the respective InstallInterfaces functions.
@@ -290,7 +292,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
290 SSL::InstallInterfaces(*sm, system); 292 SSL::InstallInterfaces(*sm, system);
291 Time::InstallInterfaces(system); 293 Time::InstallInterfaces(system);
292 USB::InstallInterfaces(*sm, system); 294 USB::InstallInterfaces(*sm, system);
293 VI::InstallInterfaces(*sm, system, *nv_flinger); 295 VI::InstallInterfaces(*sm, system, *nv_flinger, *hos_binder_driver_server);
294 WLAN::InstallInterfaces(*sm, system); 296 WLAN::InstallInterfaces(*sm, system);
295} 297}
296 298
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index c9d6b879d..b9ab2c465 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -33,8 +33,9 @@ class FileSystemController;
33} 33}
34 34
35namespace NVFlinger { 35namespace NVFlinger {
36class HosBinderDriverServer;
36class NVFlinger; 37class NVFlinger;
37} 38} // namespace NVFlinger
38 39
39namespace SM { 40namespace SM {
40class ServiceManager; 41class ServiceManager;
@@ -236,6 +237,7 @@ public:
236 ~Services(); 237 ~Services();
237 238
238private: 239private:
240 std::unique_ptr<NVFlinger::HosBinderDriverServer> hos_binder_driver_server;
239 std::unique_ptr<NVFlinger::NVFlinger> nv_flinger; 241 std::unique_ptr<NVFlinger::NVFlinger> nv_flinger;
240}; 242};
241 243
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index b7705c02a..558022511 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -13,14 +13,34 @@
13#include "core/hle/kernel/k_readable_event.h" 13#include "core/hle/kernel/k_readable_event.h"
14#include "core/hle/kernel/k_writable_event.h" 14#include "core/hle/kernel/k_writable_event.h"
15#include "core/hle/service/kernel_helpers.h" 15#include "core/hle/service/kernel_helpers.h"
16#include "core/hle/service/nvflinger/buffer_item_consumer.h"
17#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
18#include "core/hle/service/nvflinger/buffer_queue_core.h"
19#include "core/hle/service/nvflinger/buffer_queue_producer.h"
20#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
16#include "core/hle/service/vi/display/vi_display.h" 21#include "core/hle/service/vi/display/vi_display.h"
17#include "core/hle/service/vi/layer/vi_layer.h" 22#include "core/hle/service/vi/layer/vi_layer.h"
18 23
19namespace Service::VI { 24namespace Service::VI {
20 25
21Display::Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_, 26struct BufferQueue {
22 Core::System& system_) 27 std::shared_ptr<android::BufferQueueCore> core;
23 : display_id{id}, name{std::move(name_)}, service_context{service_context_} { 28 std::unique_ptr<android::BufferQueueProducer> producer;
29 std::unique_ptr<android::BufferQueueConsumer> consumer;
30};
31
32static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context) {
33 auto buffer_queue_core = std::make_shared<android::BufferQueueCore>();
34 return {buffer_queue_core,
35 std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core),
36 std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
37}
38
39Display::Display(u64 id, std::string name_,
40 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_,
41 KernelHelpers::ServiceContext& service_context_, Core::System& system_)
42 : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_},
43 service_context{service_context_} {
24 vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id)); 44 vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id));
25} 45}
26 46
@@ -44,21 +64,29 @@ void Display::SignalVSyncEvent() {
44 vsync_event->GetWritableEvent().Signal(); 64 vsync_event->GetWritableEvent().Signal();
45} 65}
46 66
47void Display::CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue) { 67void Display::CreateLayer(u64 layer_id, u32 binder_id) {
48 // TODO(Subv): Support more than 1 layer.
49 ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment"); 68 ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment");
50 69
51 layers.emplace_back(std::make_shared<Layer>(layer_id, buffer_queue)); 70 auto [core, producer, consumer] = CreateBufferQueue(service_context);
71
72 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer));
73 buffer_item_consumer->Connect(false);
74
75 layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer,
76 std::move(buffer_item_consumer)));
77
78 hos_binder_driver_server.RegisterProducer(std::move(producer));
52} 79}
53 80
54void Display::CloseLayer(u64 layer_id) { 81void Display::CloseLayer(u64 layer_id) {
55 std::erase_if(layers, [layer_id](const auto& layer) { return layer->GetID() == layer_id; }); 82 std::erase_if(layers,
83 [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; });
56} 84}
57 85
58Layer* Display::FindLayer(u64 layer_id) { 86Layer* Display::FindLayer(u64 layer_id) {
59 const auto itr = 87 const auto itr =
60 std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) { 88 std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
61 return layer->GetID() == layer_id; 89 return layer->GetLayerId() == layer_id;
62 }); 90 });
63 91
64 if (itr == layers.end()) { 92 if (itr == layers.end()) {
@@ -70,8 +98,8 @@ Layer* Display::FindLayer(u64 layer_id) {
70 98
71const Layer* Display::FindLayer(u64 layer_id) const { 99const Layer* Display::FindLayer(u64 layer_id) const {
72 const auto itr = 100 const auto itr =
73 std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) { 101 std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
74 return layer->GetID() == layer_id; 102 return layer->GetLayerId() == layer_id;
75 }); 103 });
76 104
77 if (itr == layers.end()) { 105 if (itr == layers.end()) {
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 329f4ba86..e93d084ee 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -15,12 +15,17 @@ namespace Kernel {
15class KEvent; 15class KEvent;
16} 16}
17 17
18namespace Service::NVFlinger { 18namespace Service::android {
19class BufferQueue; 19class BufferQueueProducer;
20} 20}
21
21namespace Service::KernelHelpers { 22namespace Service::KernelHelpers {
22class ServiceContext; 23class ServiceContext;
23} // namespace Service::KernelHelpers 24}
25
26namespace Service::NVFlinger {
27class HosBinderDriverServer;
28}
24 29
25namespace Service::VI { 30namespace Service::VI {
26 31
@@ -35,12 +40,13 @@ public:
35 /// Constructs a display with a given unique ID and name. 40 /// Constructs a display with a given unique ID and name.
36 /// 41 ///
37 /// @param id The unique ID for this display. 42 /// @param id The unique ID for this display.
43 /// @param hos_binder_driver_server_ NVFlinger HOSBinderDriver server instance.
38 /// @param service_context_ The ServiceContext for the owning service. 44 /// @param service_context_ The ServiceContext for the owning service.
39 /// @param name_ The name for this display. 45 /// @param name_ The name for this display.
40 /// @param system_ The global system instance. 46 /// @param system_ The global system instance.
41 /// 47 ///
42 Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_, 48 Display(u64 id, std::string name_, NVFlinger::HosBinderDriverServer& hos_binder_driver_server_,
43 Core::System& system_); 49 KernelHelpers::ServiceContext& service_context_, Core::System& system_);
44 ~Display(); 50 ~Display();
45 51
46 /// Gets the unique ID assigned to this display. 52 /// Gets the unique ID assigned to this display.
@@ -64,6 +70,10 @@ public:
64 /// Gets a layer for this display based off an index. 70 /// Gets a layer for this display based off an index.
65 const Layer& GetLayer(std::size_t index) const; 71 const Layer& GetLayer(std::size_t index) const;
66 72
73 std::size_t GetNumLayers() const {
74 return layers.size();
75 }
76
67 /// Gets the readable vsync event. 77 /// Gets the readable vsync event.
68 Kernel::KReadableEvent& GetVSyncEvent(); 78 Kernel::KReadableEvent& GetVSyncEvent();
69 79
@@ -72,10 +82,10 @@ public:
72 82
73 /// Creates and adds a layer to this display with the given ID. 83 /// Creates and adds a layer to this display with the given ID.
74 /// 84 ///
75 /// @param layer_id The ID to assign to the created layer. 85 /// @param layer_id The ID to assign to the created layer.
76 /// @param buffer_queue The buffer queue for the layer instance to use. 86 /// @param binder_id The ID assigned to the buffer queue.
77 /// 87 ///
78 void CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue); 88 void CreateLayer(u64 layer_id, u32 binder_id);
79 89
80 /// Closes and removes a layer from this display with the given ID. 90 /// Closes and removes a layer from this display with the given ID.
81 /// 91 ///
@@ -104,9 +114,10 @@ public:
104private: 114private:
105 u64 display_id; 115 u64 display_id;
106 std::string name; 116 std::string name;
117 NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
107 KernelHelpers::ServiceContext& service_context; 118 KernelHelpers::ServiceContext& service_context;
108 119
109 std::vector<std::shared_ptr<Layer>> layers; 120 std::vector<std::unique_ptr<Layer>> layers;
110 Kernel::KEvent* vsync_event{}; 121 Kernel::KEvent* vsync_event{};
111}; 122};
112 123
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
index 9bc382587..93858e91f 100644
--- a/src/core/hle/service/vi/layer/vi_layer.cpp
+++ b/src/core/hle/service/vi/layer/vi_layer.cpp
@@ -6,7 +6,11 @@
6 6
7namespace Service::VI { 7namespace Service::VI {
8 8
9Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : layer_id{id}, buffer_queue{queue} {} 9Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
10 android::BufferQueueProducer& binder_,
11 std::shared_ptr<android::BufferItemConsumer>&& consumer_)
12 : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
13 consumer_)} {}
10 14
11Layer::~Layer() = default; 15Layer::~Layer() = default;
12 16
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
index ebdd85505..c28b14450 100644
--- a/src/core/hle/service/vi/layer/vi_layer.h
+++ b/src/core/hle/service/vi/layer/vi_layer.h
@@ -4,11 +4,15 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9namespace Service::NVFlinger { 11namespace Service::android {
10class BufferQueue; 12class BufferItemConsumer;
11} 13class BufferQueueCore;
14class BufferQueueProducer;
15} // namespace Service::android
12 16
13namespace Service::VI { 17namespace Service::VI {
14 18
@@ -17,10 +21,13 @@ class Layer {
17public: 21public:
18 /// Constructs a layer with a given ID and buffer queue. 22 /// Constructs a layer with a given ID and buffer queue.
19 /// 23 ///
20 /// @param id The ID to assign to this layer. 24 /// @param layer_id_ The ID to assign to this layer.
21 /// @param queue The buffer queue for this layer to use. 25 /// @param binder_id_ The binder ID to assign to this layer.
26 /// @param binder_ The buffer producer queue for this layer to use.
22 /// 27 ///
23 Layer(u64 id, NVFlinger::BufferQueue& queue); 28 Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
29 android::BufferQueueProducer& binder_,
30 std::shared_ptr<android::BufferItemConsumer>&& consumer_);
24 ~Layer(); 31 ~Layer();
25 32
26 Layer(const Layer&) = delete; 33 Layer(const Layer&) = delete;
@@ -30,23 +37,47 @@ public:
30 Layer& operator=(Layer&&) = delete; 37 Layer& operator=(Layer&&) = delete;
31 38
32 /// Gets the ID for this layer. 39 /// Gets the ID for this layer.
33 u64 GetID() const { 40 u64 GetLayerId() const {
34 return layer_id; 41 return layer_id;
35 } 42 }
36 43
44 /// Gets the binder ID for this layer.
45 u32 GetBinderId() const {
46 return binder_id;
47 }
48
37 /// Gets a reference to the buffer queue this layer is using. 49 /// Gets a reference to the buffer queue this layer is using.
38 NVFlinger::BufferQueue& GetBufferQueue() { 50 android::BufferQueueProducer& GetBufferQueue() {
39 return buffer_queue; 51 return binder;
40 } 52 }
41 53
42 /// Gets a const reference to the buffer queue this layer is using. 54 /// Gets a const reference to the buffer queue this layer is using.
43 const NVFlinger::BufferQueue& GetBufferQueue() const { 55 const android::BufferQueueProducer& GetBufferQueue() const {
44 return buffer_queue; 56 return binder;
57 }
58
59 android::BufferItemConsumer& GetConsumer() {
60 return *consumer;
61 }
62
63 const android::BufferItemConsumer& GetConsumer() const {
64 return *consumer;
65 }
66
67 android::BufferQueueCore& Core() {
68 return core;
69 }
70
71 const android::BufferQueueCore& Core() const {
72 return core;
45 } 73 }
46 74
47private: 75private:
48 u64 layer_id; 76 const u64 layer_id;
49 NVFlinger::BufferQueue& buffer_queue; 77 const u32 binder_id;
78 android::BufferQueueCore& core;
79 android::BufferQueueProducer& binder;
80 std::shared_ptr<android::BufferItemConsumer> consumer;
50}; 81};
51 82
52} // namespace Service::VI 83} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 75ee3e5e4..430cbc546 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -22,8 +22,11 @@
22#include "core/hle/kernel/k_readable_event.h" 22#include "core/hle/kernel/k_readable_event.h"
23#include "core/hle/kernel/k_thread.h" 23#include "core/hle/kernel/k_thread.h"
24#include "core/hle/service/nvdrv/nvdata.h" 24#include "core/hle/service/nvdrv/nvdata.h"
25#include "core/hle/service/nvflinger/buffer_queue.h" 25#include "core/hle/service/nvflinger/binder.h"
26#include "core/hle/service/nvflinger/buffer_queue_producer.h"
27#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
26#include "core/hle/service/nvflinger/nvflinger.h" 28#include "core/hle/service/nvflinger/nvflinger.h"
29#include "core/hle/service/nvflinger/parcel.h"
27#include "core/hle/service/service.h" 30#include "core/hle/service/service.h"
28#include "core/hle/service/vi/vi.h" 31#include "core/hle/service/vi/vi.h"
29#include "core/hle/service/vi/vi_m.h" 32#include "core/hle/service/vi/vi_m.h"
@@ -57,447 +60,24 @@ struct DisplayInfo {
57}; 60};
58static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); 61static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
59 62
60class Parcel { 63class NativeWindow final {
61public: 64public:
62 // This default size was chosen arbitrarily. 65 constexpr explicit NativeWindow(u32 id_) : id{id_} {}
63 static constexpr std::size_t DefaultBufferSize = 0x40;
64 Parcel() : buffer(DefaultBufferSize) {}
65 explicit Parcel(std::vector<u8> data) : buffer(std::move(data)) {}
66 virtual ~Parcel() = default;
67
68 template <typename T>
69 T Read() {
70 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
71 ASSERT(read_index + sizeof(T) <= buffer.size());
72
73 T val;
74 std::memcpy(&val, buffer.data() + read_index, sizeof(T));
75 read_index += sizeof(T);
76 read_index = Common::AlignUp(read_index, 4);
77 return val;
78 }
79
80 template <typename T>
81 T ReadUnaligned() {
82 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
83 ASSERT(read_index + sizeof(T) <= buffer.size());
84
85 T val;
86 std::memcpy(&val, buffer.data() + read_index, sizeof(T));
87 read_index += sizeof(T);
88 return val;
89 }
90
91 std::vector<u8> ReadBlock(std::size_t length) {
92 ASSERT(read_index + length <= buffer.size());
93 const u8* const begin = buffer.data() + read_index;
94 const u8* const end = begin + length;
95 std::vector<u8> data(begin, end);
96 read_index += length;
97 read_index = Common::AlignUp(read_index, 4);
98 return data;
99 }
100
101 std::u16string ReadInterfaceToken() {
102 [[maybe_unused]] const u32 unknown = Read<u32_le>();
103 const u32 length = Read<u32_le>();
104
105 std::u16string token{};
106
107 for (u32 ch = 0; ch < length + 1; ++ch) {
108 token.push_back(ReadUnaligned<u16_le>());
109 }
110
111 read_index = Common::AlignUp(read_index, 4);
112
113 return token;
114 }
115
116 template <typename T>
117 void Write(const T& val) {
118 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
119
120 if (buffer.size() < write_index + sizeof(T)) {
121 buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
122 }
123
124 std::memcpy(buffer.data() + write_index, &val, sizeof(T));
125 write_index += sizeof(T);
126 write_index = Common::AlignUp(write_index, 4);
127 }
128
129 template <typename T>
130 void WriteObject(const T& val) {
131 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
132
133 const u32_le size = static_cast<u32>(sizeof(val));
134 Write(size);
135 // TODO(Subv): Support file descriptors.
136 Write<u32_le>(0); // Fd count.
137 Write(val);
138 }
139
140 void Deserialize() {
141 ASSERT(buffer.size() > sizeof(Header));
142
143 Header header{};
144 std::memcpy(&header, buffer.data(), sizeof(Header));
145
146 read_index = header.data_offset;
147 DeserializeData();
148 }
149
150 std::vector<u8> Serialize() {
151 ASSERT(read_index == 0);
152 write_index = sizeof(Header);
153
154 SerializeData();
155
156 Header header{};
157 header.data_size = static_cast<u32_le>(write_index - sizeof(Header));
158 header.data_offset = sizeof(Header);
159 header.objects_size = 4;
160 header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size);
161 std::memcpy(buffer.data(), &header, sizeof(Header));
162
163 return buffer;
164 }
165
166protected:
167 virtual void SerializeData() {}
168
169 virtual void DeserializeData() {}
170
171private:
172 struct Header {
173 u32_le data_size;
174 u32_le data_offset;
175 u32_le objects_size;
176 u32_le objects_offset;
177 };
178 static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
179
180 std::vector<u8> buffer;
181 std::size_t read_index = 0;
182 std::size_t write_index = 0;
183};
184
185class NativeWindow : public Parcel {
186public:
187 explicit NativeWindow(u32 id) {
188 data.id = id;
189 }
190 ~NativeWindow() override = default;
191
192protected:
193 void SerializeData() override {
194 Write(data);
195 }
196
197private:
198 struct Data {
199 u32_le magic = 2;
200 u32_le process_id = 1;
201 u32_le id;
202 INSERT_PADDING_WORDS(3);
203 std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
204 INSERT_PADDING_WORDS(2);
205 };
206 static_assert(sizeof(Data) == 0x28, "ParcelData has wrong size");
207
208 Data data{};
209};
210
211class IGBPConnectRequestParcel : public Parcel {
212public:
213 explicit IGBPConnectRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
214 Deserialize();
215 }
216
217 void DeserializeData() override {
218 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
219 data = Read<Data>();
220 }
221
222 struct Data {
223 u32_le unk;
224 u32_le api;
225 u32_le producer_controlled_by_app;
226 };
227
228 Data data;
229};
230
231class IGBPConnectResponseParcel : public Parcel {
232public:
233 explicit IGBPConnectResponseParcel(u32 width, u32 height) {
234 data.width = width;
235 data.height = height;
236 }
237 ~IGBPConnectResponseParcel() override = default;
238
239protected:
240 void SerializeData() override {
241 Write(data);
242 }
243
244private:
245 struct Data {
246 u32_le width;
247 u32_le height;
248 u32_le transform_hint;
249 u32_le num_pending_buffers;
250 u32_le status;
251 };
252 static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
253
254 Data data{};
255};
256
257/// Represents a parcel containing one int '0' as its data
258/// Used by DetachBuffer and Disconnect
259class IGBPEmptyResponseParcel : public Parcel {
260protected:
261 void SerializeData() override {
262 Write(data);
263 }
264
265private:
266 struct Data {
267 u32_le unk_0{};
268 };
269
270 Data data{};
271};
272
273class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
274public:
275 explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer_)
276 : Parcel(std::move(buffer_)) {
277 Deserialize();
278 }
279
280 void DeserializeData() override {
281 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
282 data = Read<Data>();
283 if (data.contains_object != 0) {
284 buffer_container = Read<BufferContainer>();
285 }
286 }
287
288 struct Data {
289 u32_le slot;
290 u32_le contains_object;
291 };
292
293 struct BufferContainer {
294 u32_le graphic_buffer_length;
295 INSERT_PADDING_WORDS(1);
296 NVFlinger::IGBPBuffer buffer{};
297 };
298
299 Data data{};
300 BufferContainer buffer_container{};
301};
302
303class IGBPSetPreallocatedBufferResponseParcel : public Parcel {
304protected:
305 void SerializeData() override {
306 // TODO(Subv): Find out what this means
307 Write<u32>(0);
308 }
309};
310
311class IGBPCancelBufferRequestParcel : public Parcel {
312public:
313 explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
314 Deserialize();
315 }
316
317 void DeserializeData() override {
318 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
319 data = Read<Data>();
320 }
321
322 struct Data {
323 u32_le slot;
324 Service::Nvidia::MultiFence multi_fence;
325 };
326
327 Data data;
328};
329
330class IGBPCancelBufferResponseParcel : public Parcel {
331protected:
332 void SerializeData() override {
333 Write<u32>(0); // Success
334 }
335};
336
337class IGBPDequeueBufferRequestParcel : public Parcel {
338public:
339 explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
340 Deserialize();
341 }
342
343 void DeserializeData() override {
344 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
345 data = Read<Data>();
346 }
347
348 struct Data {
349 u32_le pixel_format;
350 u32_le width;
351 u32_le height;
352 u32_le get_frame_timestamps;
353 u32_le usage;
354 };
355
356 Data data;
357};
358
359class IGBPDequeueBufferResponseParcel : public Parcel {
360public:
361 explicit IGBPDequeueBufferResponseParcel(u32 slot_, Nvidia::MultiFence& multi_fence_)
362 : slot(slot_), multi_fence(multi_fence_) {}
363
364protected:
365 void SerializeData() override {
366 Write(slot);
367 Write<u32_le>(1);
368 WriteObject(multi_fence);
369 Write<u32_le>(0);
370 }
371
372 u32_le slot;
373 Service::Nvidia::MultiFence multi_fence;
374};
375
376class IGBPRequestBufferRequestParcel : public Parcel {
377public:
378 explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
379 Deserialize();
380 }
381
382 void DeserializeData() override {
383 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
384 slot = Read<u32_le>();
385 }
386
387 u32_le slot;
388};
389
390class IGBPRequestBufferResponseParcel : public Parcel {
391public:
392 explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer_) : buffer(buffer_) {}
393 ~IGBPRequestBufferResponseParcel() override = default;
394
395protected:
396 void SerializeData() override {
397 // TODO(Subv): Figure out what this value means, writing non-zero here will make libnx
398 // try to read an IGBPBuffer object from the parcel.
399 Write<u32_le>(1);
400 WriteObject(buffer);
401 Write<u32_le>(0);
402 }
403
404 NVFlinger::IGBPBuffer buffer;
405};
406
407class IGBPQueueBufferRequestParcel : public Parcel {
408public:
409 explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
410 Deserialize();
411 }
412
413 void DeserializeData() override {
414 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
415 data = Read<Data>();
416 }
417
418 struct Data {
419 u32_le slot;
420 INSERT_PADDING_WORDS(3);
421 u32_le timestamp;
422 s32_le is_auto_timestamp;
423 s32_le crop_top;
424 s32_le crop_left;
425 s32_le crop_right;
426 s32_le crop_bottom;
427 s32_le scaling_mode;
428 NVFlinger::BufferQueue::BufferTransformFlags transform;
429 u32_le sticky_transform;
430 INSERT_PADDING_WORDS(1);
431 u32_le swap_interval;
432 Service::Nvidia::MultiFence multi_fence;
433
434 Common::Rectangle<int> GetCropRect() const {
435 return {crop_left, crop_top, crop_right, crop_bottom};
436 }
437 };
438 static_assert(sizeof(Data) == 96, "ParcelData has wrong size");
439
440 Data data;
441};
442
443class IGBPQueueBufferResponseParcel : public Parcel {
444public:
445 explicit IGBPQueueBufferResponseParcel(u32 width, u32 height) {
446 data.width = width;
447 data.height = height;
448 }
449 ~IGBPQueueBufferResponseParcel() override = default;
450
451protected:
452 void SerializeData() override {
453 Write(data);
454 }
455
456private:
457 struct Data {
458 u32_le width;
459 u32_le height;
460 u32_le transform_hint;
461 u32_le num_pending_buffers;
462 u32_le status;
463 };
464 static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
465
466 Data data{};
467};
468
469class IGBPQueryRequestParcel : public Parcel {
470public:
471 explicit IGBPQueryRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
472 Deserialize();
473 }
474
475 void DeserializeData() override {
476 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
477 type = Read<u32_le>();
478 }
479
480 u32 type;
481};
482
483class IGBPQueryResponseParcel : public Parcel {
484public:
485 explicit IGBPQueryResponseParcel(u32 value_) : value{value_} {}
486 ~IGBPQueryResponseParcel() override = default;
487
488protected:
489 void SerializeData() override {
490 Write(value);
491 }
492 66
493private: 67private:
494 u32_le value; 68 const u32 magic = 2;
69 const u32 process_id = 1;
70 const u32 id;
71 INSERT_PADDING_WORDS(3);
72 std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
73 INSERT_PADDING_WORDS(2);
495}; 74};
75static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");
496 76
497class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { 77class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
498public: 78public:
499 explicit IHOSBinderDriver(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) 79 explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
500 : ServiceFramework{system_, "IHOSBinderDriver"}, nv_flinger(nv_flinger_) { 80 : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) {
501 static const FunctionInfo functions[] = { 81 static const FunctionInfo functions[] = {
502 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, 82 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
503 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, 83 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
@@ -508,147 +88,16 @@ public:
508 } 88 }
509 89
510private: 90private:
511 enum class TransactionId {
512 RequestBuffer = 1,
513 SetBufferCount = 2,
514 DequeueBuffer = 3,
515 DetachBuffer = 4,
516 DetachNextBuffer = 5,
517 AttachBuffer = 6,
518 QueueBuffer = 7,
519 CancelBuffer = 8,
520 Query = 9,
521 Connect = 10,
522 Disconnect = 11,
523
524 AllocateBuffers = 13,
525 SetPreallocatedBuffer = 14,
526
527 GetBufferHistory = 17
528 };
529
530 void TransactParcel(Kernel::HLERequestContext& ctx) { 91 void TransactParcel(Kernel::HLERequestContext& ctx) {
531 IPC::RequestParser rp{ctx}; 92 IPC::RequestParser rp{ctx};
532 const u32 id = rp.Pop<u32>(); 93 const u32 id = rp.Pop<u32>();
533 const auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); 94 const auto transaction = static_cast<android::TransactionId>(rp.Pop<u32>());
534 const u32 flags = rp.Pop<u32>(); 95 const u32 flags = rp.Pop<u32>();
535 96
536 LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, 97 LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
537 transaction, flags); 98 transaction, flags);
538 99
539 auto& buffer_queue = *nv_flinger.FindBufferQueue(id); 100 server.TryGetProducer(id)->Transact(ctx, transaction, flags);
540
541 switch (transaction) {
542 case TransactionId::Connect: {
543 IGBPConnectRequestParcel request{ctx.ReadBuffer()};
544 IGBPConnectResponseParcel response{static_cast<u32>(DisplayResolution::UndockedWidth),
545 static_cast<u32>(DisplayResolution::UndockedHeight)};
546
547 buffer_queue.Connect();
548
549 ctx.WriteBuffer(response.Serialize());
550 break;
551 }
552 case TransactionId::SetPreallocatedBuffer: {
553 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
554
555 buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer_container.buffer);
556
557 IGBPSetPreallocatedBufferResponseParcel response{};
558 ctx.WriteBuffer(response.Serialize());
559 break;
560 }
561 case TransactionId::DequeueBuffer: {
562 IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
563 const u32 width{request.data.width};
564 const u32 height{request.data.height};
565
566 do {
567 if (auto result = buffer_queue.DequeueBuffer(width, height); result) {
568 // Buffer is available
569 IGBPDequeueBufferResponseParcel response{result->first, *result->second};
570 ctx.WriteBuffer(response.Serialize());
571 break;
572 }
573 } while (buffer_queue.IsConnected());
574
575 break;
576 }
577 case TransactionId::RequestBuffer: {
578 IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
579
580 auto& buffer = buffer_queue.RequestBuffer(request.slot);
581 IGBPRequestBufferResponseParcel response{buffer};
582 ctx.WriteBuffer(response.Serialize());
583
584 break;
585 }
586 case TransactionId::QueueBuffer: {
587 IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()};
588
589 buffer_queue.QueueBuffer(request.data.slot, request.data.transform,
590 request.data.GetCropRect(), request.data.swap_interval,
591 request.data.multi_fence);
592
593 IGBPQueueBufferResponseParcel response{1280, 720};
594 ctx.WriteBuffer(response.Serialize());
595 break;
596 }
597 case TransactionId::Query: {
598 IGBPQueryRequestParcel request{ctx.ReadBuffer()};
599
600 const u32 value =
601 buffer_queue.Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type));
602
603 IGBPQueryResponseParcel response{value};
604 ctx.WriteBuffer(response.Serialize());
605 break;
606 }
607 case TransactionId::CancelBuffer: {
608 IGBPCancelBufferRequestParcel request{ctx.ReadBuffer()};
609
610 buffer_queue.CancelBuffer(request.data.slot, request.data.multi_fence);
611
612 IGBPCancelBufferResponseParcel response{};
613 ctx.WriteBuffer(response.Serialize());
614 break;
615 }
616 case TransactionId::Disconnect: {
617 LOG_WARNING(Service_VI, "(STUBBED) called, transaction=Disconnect");
618 const auto buffer = ctx.ReadBuffer();
619
620 buffer_queue.Disconnect();
621
622 IGBPEmptyResponseParcel response{};
623 ctx.WriteBuffer(response.Serialize());
624 break;
625 }
626 case TransactionId::DetachBuffer: {
627 const auto buffer = ctx.ReadBuffer();
628
629 IGBPEmptyResponseParcel response{};
630 ctx.WriteBuffer(response.Serialize());
631 break;
632 }
633 case TransactionId::SetBufferCount: {
634 LOG_WARNING(Service_VI, "(STUBBED) called, transaction=SetBufferCount");
635 [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
636
637 IGBPEmptyResponseParcel response{};
638 ctx.WriteBuffer(response.Serialize());
639 break;
640 }
641 case TransactionId::GetBufferHistory: {
642 LOG_WARNING(Service_VI, "(STUBBED) called, transaction=GetBufferHistory");
643 [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
644
645 IGBPEmptyResponseParcel response{};
646 ctx.WriteBuffer(response.Serialize());
647 break;
648 }
649 default:
650 ASSERT_MSG(false, "Unimplemented");
651 }
652 101
653 IPC::ResponseBuilder rb{ctx, 2}; 102 IPC::ResponseBuilder rb{ctx, 2};
654 rb.Push(ResultSuccess); 103 rb.Push(ResultSuccess);
@@ -674,13 +123,13 @@ private:
674 123
675 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); 124 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
676 125
677 // TODO(Subv): Find out what this actually is.
678 IPC::ResponseBuilder rb{ctx, 2, 1}; 126 IPC::ResponseBuilder rb{ctx, 2, 1};
679 rb.Push(ResultSuccess); 127 rb.Push(ResultSuccess);
680 rb.PushCopyObjects(nv_flinger.FindBufferQueue(id)->GetBufferWaitEvent()); 128 rb.PushCopyObjects(server.TryGetProducer(id)->GetNativeHandle());
681 } 129 }
682 130
683 NVFlinger::NVFlinger& nv_flinger; 131private:
132 NVFlinger::HosBinderDriverServer& server;
684}; 133};
685 134
686class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { 135class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
@@ -937,7 +386,40 @@ private:
937 386
938class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { 387class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
939public: 388public:
940 explicit IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); 389 IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
390 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
391 : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_},
392 hos_binder_driver_server{hos_binder_driver_server_} {
393
394 static const FunctionInfo functions[] = {
395 {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
396 {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
397 {102, &IApplicationDisplayService::GetManagerDisplayService,
398 "GetManagerDisplayService"},
399 {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
400 "GetIndirectDisplayTransactionService"},
401 {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
402 {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
403 {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
404 {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
405 {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
406 {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
407 {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
408 {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"},
409 {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
410 {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
411 {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
412 {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
413 {2450, &IApplicationDisplayService::GetIndirectLayerImageMap,
414 "GetIndirectLayerImageMap"},
415 {2451, nullptr, "GetIndirectLayerImageCropMap"},
416 {2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
417 "GetIndirectLayerImageRequiredMemoryInfo"},
418 {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
419 {5203, nullptr, "GetDisplayVsyncEventForDebug"},
420 };
421 RegisterHandlers(functions);
422 }
941 423
942private: 424private:
943 enum class ConvertedScaleMode : u64 { 425 enum class ConvertedScaleMode : u64 {
@@ -961,7 +443,7 @@ private:
961 443
962 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 444 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
963 rb.Push(ResultSuccess); 445 rb.Push(ResultSuccess);
964 rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger); 446 rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
965 } 447 }
966 448
967 void GetSystemDisplayService(Kernel::HLERequestContext& ctx) { 449 void GetSystemDisplayService(Kernel::HLERequestContext& ctx) {
@@ -985,7 +467,7 @@ private:
985 467
986 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 468 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
987 rb.Push(ResultSuccess); 469 rb.Push(ResultSuccess);
988 rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger); 470 rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
989 } 471 }
990 472
991 void OpenDisplay(Kernel::HLERequestContext& ctx) { 473 void OpenDisplay(Kernel::HLERequestContext& ctx) {
@@ -1089,7 +571,7 @@ private:
1089 void ListDisplays(Kernel::HLERequestContext& ctx) { 571 void ListDisplays(Kernel::HLERequestContext& ctx) {
1090 LOG_WARNING(Service_VI, "(STUBBED) called"); 572 LOG_WARNING(Service_VI, "(STUBBED) called");
1091 573
1092 DisplayInfo display_info; 574 const DisplayInfo display_info;
1093 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); 575 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
1094 IPC::ResponseBuilder rb{ctx, 4}; 576 IPC::ResponseBuilder rb{ctx, 4};
1095 rb.Push(ResultSuccess); 577 rb.Push(ResultSuccess);
@@ -1124,8 +606,8 @@ private:
1124 return; 606 return;
1125 } 607 }
1126 608
1127 NativeWindow native_window{*buffer_queue_id}; 609 const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
1128 const auto buffer_size = ctx.WriteBuffer(native_window.Serialize()); 610 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
1129 611
1130 IPC::ResponseBuilder rb{ctx, 4}; 612 IPC::ResponseBuilder rb{ctx, 4};
1131 rb.Push(ResultSuccess); 613 rb.Push(ResultSuccess);
@@ -1170,8 +652,8 @@ private:
1170 return; 652 return;
1171 } 653 }
1172 654
1173 NativeWindow native_window{*buffer_queue_id}; 655 const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
1174 const auto buffer_size = ctx.WriteBuffer(native_window.Serialize()); 656 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
1175 657
1176 IPC::ResponseBuilder rb{ctx, 6}; 658 IPC::ResponseBuilder rb{ctx, 6};
1177 rb.Push(ResultSuccess); 659 rb.Push(ResultSuccess);
@@ -1287,39 +769,9 @@ private:
1287 } 769 }
1288 770
1289 NVFlinger::NVFlinger& nv_flinger; 771 NVFlinger::NVFlinger& nv_flinger;
772 NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
1290}; 773};
1291 774
1292IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
1293 NVFlinger::NVFlinger& nv_flinger_)
1294 : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_} {
1295 static const FunctionInfo functions[] = {
1296 {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
1297 {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
1298 {102, &IApplicationDisplayService::GetManagerDisplayService, "GetManagerDisplayService"},
1299 {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
1300 "GetIndirectDisplayTransactionService"},
1301 {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
1302 {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
1303 {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
1304 {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
1305 {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
1306 {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
1307 {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
1308 {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"},
1309 {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
1310 {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
1311 {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
1312 {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
1313 {2450, &IApplicationDisplayService::GetIndirectLayerImageMap, "GetIndirectLayerImageMap"},
1314 {2451, nullptr, "GetIndirectLayerImageCropMap"},
1315 {2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
1316 "GetIndirectLayerImageRequiredMemoryInfo"},
1317 {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
1318 {5203, nullptr, "GetDisplayVsyncEventForDebug"},
1319 };
1320 RegisterHandlers(functions);
1321}
1322
1323static bool IsValidServiceAccess(Permission permission, Policy policy) { 775static bool IsValidServiceAccess(Permission permission, Policy policy) {
1324 if (permission == Permission::User) { 776 if (permission == Permission::User) {
1325 return policy == Policy::User; 777 return policy == Policy::User;
@@ -1333,7 +785,9 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
1333} 785}
1334 786
1335void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system, 787void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
1336 NVFlinger::NVFlinger& nv_flinger, Permission permission) { 788 NVFlinger::NVFlinger& nv_flinger,
789 NVFlinger::HosBinderDriverServer& hos_binder_driver_server,
790 Permission permission) {
1337 IPC::RequestParser rp{ctx}; 791 IPC::RequestParser rp{ctx};
1338 const auto policy = rp.PopEnum<Policy>(); 792 const auto policy = rp.PopEnum<Policy>();
1339 793
@@ -1346,14 +800,18 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System&
1346 800
1347 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 801 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1348 rb.Push(ResultSuccess); 802 rb.Push(ResultSuccess);
1349 rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger); 803 rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger, hos_binder_driver_server);
1350} 804}
1351 805
1352void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system, 806void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
1353 NVFlinger::NVFlinger& nv_flinger) { 807 NVFlinger::NVFlinger& nv_flinger,
1354 std::make_shared<VI_M>(system, nv_flinger)->InstallAsService(service_manager); 808 NVFlinger::HosBinderDriverServer& hos_binder_driver_server) {
1355 std::make_shared<VI_S>(system, nv_flinger)->InstallAsService(service_manager); 809 std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server)
1356 std::make_shared<VI_U>(system, nv_flinger)->InstallAsService(service_manager); 810 ->InstallAsService(service_manager);
811 std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server)
812 ->InstallAsService(service_manager);
813 std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server)
814 ->InstallAsService(service_manager);
1357} 815}
1358 816
1359} // namespace Service::VI 817} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 2fd7f8e61..d68f2646b 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -15,8 +15,9 @@ class HLERequestContext;
15} 15}
16 16
17namespace Service::NVFlinger { 17namespace Service::NVFlinger {
18class HosBinderDriverServer;
18class NVFlinger; 19class NVFlinger;
19} 20} // namespace Service::NVFlinger
20 21
21namespace Service::SM { 22namespace Service::SM {
22class ServiceManager; 23class ServiceManager;
@@ -47,11 +48,14 @@ enum class Policy {
47 48
48namespace detail { 49namespace detail {
49void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system, 50void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
50 NVFlinger::NVFlinger& nv_flinger, Permission permission); 51 NVFlinger::NVFlinger& nv_flinger,
52 NVFlinger::HosBinderDriverServer& hos_binder_driver_server,
53 Permission permission);
51} // namespace detail 54} // namespace detail
52 55
53/// Registers all VI services with the specified service manager. 56/// Registers all VI services with the specified service manager.
54void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system, 57void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
55 NVFlinger::NVFlinger& nv_flinger); 58 NVFlinger::NVFlinger& nv_flinger,
59 NVFlinger::HosBinderDriverServer& hos_binder_driver_server);
56 60
57} // namespace Service::VI 61} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp
index 87db1c416..be0255f3d 100644
--- a/src/core/hle/service/vi/vi_m.cpp
+++ b/src/core/hle/service/vi/vi_m.cpp
@@ -8,8 +8,10 @@
8 8
9namespace Service::VI { 9namespace Service::VI {
10 10
11VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) 11VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
12 : ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_} { 12 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
13 : ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
14 hos_binder_driver_server_} {
13 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
14 {2, &VI_M::GetDisplayService, "GetDisplayService"}, 16 {2, &VI_M::GetDisplayService, "GetDisplayService"},
15 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 17 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +24,8 @@ VI_M::~VI_M() = default;
22void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { 24void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_VI, "called"); 25 LOG_DEBUG(Service_VI, "called");
24 26
25 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::Manager); 27 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
28 Permission::Manager);
26} 29}
27 30
28} // namespace Service::VI 31} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h
index d79c41beb..efbd34e09 100644
--- a/src/core/hle/service/vi/vi_m.h
+++ b/src/core/hle/service/vi/vi_m.h
@@ -15,20 +15,23 @@ class HLERequestContext;
15} 15}
16 16
17namespace Service::NVFlinger { 17namespace Service::NVFlinger {
18class HosBinderDriverServer;
18class NVFlinger; 19class NVFlinger;
19} 20} // namespace Service::NVFlinger
20 21
21namespace Service::VI { 22namespace Service::VI {
22 23
23class VI_M final : public ServiceFramework<VI_M> { 24class VI_M final : public ServiceFramework<VI_M> {
24public: 25public:
25 explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); 26 explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
27 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
26 ~VI_M() override; 28 ~VI_M() override;
27 29
28private: 30private:
29 void GetDisplayService(Kernel::HLERequestContext& ctx); 31 void GetDisplayService(Kernel::HLERequestContext& ctx);
30 32
31 NVFlinger::NVFlinger& nv_flinger; 33 NVFlinger::NVFlinger& nv_flinger;
34 NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
32}; 35};
33 36
34} // namespace Service::VI 37} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp
index 5cd22f7df..7996a6811 100644
--- a/src/core/hle/service/vi/vi_s.cpp
+++ b/src/core/hle/service/vi/vi_s.cpp
@@ -8,8 +8,10 @@
8 8
9namespace Service::VI { 9namespace Service::VI {
10 10
11VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) 11VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
12 : ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_} { 12 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
13 : ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
14 hos_binder_driver_server_} {
13 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
14 {1, &VI_S::GetDisplayService, "GetDisplayService"}, 16 {1, &VI_S::GetDisplayService, "GetDisplayService"},
15 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 17 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +24,8 @@ VI_S::~VI_S() = default;
22void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) { 24void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_VI, "called"); 25 LOG_DEBUG(Service_VI, "called");
24 26
25 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::System); 27 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
28 Permission::System);
26} 29}
27 30
28} // namespace Service::VI 31} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h
index 5f1f8f290..3812c5061 100644
--- a/src/core/hle/service/vi/vi_s.h
+++ b/src/core/hle/service/vi/vi_s.h
@@ -15,20 +15,23 @@ class HLERequestContext;
15} 15}
16 16
17namespace Service::NVFlinger { 17namespace Service::NVFlinger {
18class HosBinderDriverServer;
18class NVFlinger; 19class NVFlinger;
19} 20} // namespace Service::NVFlinger
20 21
21namespace Service::VI { 22namespace Service::VI {
22 23
23class VI_S final : public ServiceFramework<VI_S> { 24class VI_S final : public ServiceFramework<VI_S> {
24public: 25public:
25 explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); 26 explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
27 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
26 ~VI_S() override; 28 ~VI_S() override;
27 29
28private: 30private:
29 void GetDisplayService(Kernel::HLERequestContext& ctx); 31 void GetDisplayService(Kernel::HLERequestContext& ctx);
30 32
31 NVFlinger::NVFlinger& nv_flinger; 33 NVFlinger::NVFlinger& nv_flinger;
34 NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
32}; 35};
33 36
34} // namespace Service::VI 37} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp
index 0079d51f0..57c888313 100644
--- a/src/core/hle/service/vi/vi_u.cpp
+++ b/src/core/hle/service/vi/vi_u.cpp
@@ -8,8 +8,10 @@
8 8
9namespace Service::VI { 9namespace Service::VI {
10 10
11VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) 11VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
12 : ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_} { 12 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
13 : ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
14 hos_binder_driver_server_} {
13 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
14 {0, &VI_U::GetDisplayService, "GetDisplayService"}, 16 {0, &VI_U::GetDisplayService, "GetDisplayService"},
15 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 17 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +24,8 @@ VI_U::~VI_U() = default;
22void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) { 24void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_VI, "called"); 25 LOG_DEBUG(Service_VI, "called");
24 26
25 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::User); 27 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
28 Permission::User);
26} 29}
27 30
28} // namespace Service::VI 31} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h
index 8e3885c73..b08e56576 100644
--- a/src/core/hle/service/vi/vi_u.h
+++ b/src/core/hle/service/vi/vi_u.h
@@ -15,20 +15,23 @@ class HLERequestContext;
15} 15}
16 16
17namespace Service::NVFlinger { 17namespace Service::NVFlinger {
18class HosBinderDriverServer;
18class NVFlinger; 19class NVFlinger;
19} 20} // namespace Service::NVFlinger
20 21
21namespace Service::VI { 22namespace Service::VI {
22 23
23class VI_U final : public ServiceFramework<VI_U> { 24class VI_U final : public ServiceFramework<VI_U> {
24public: 25public:
25 explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); 26 explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
27 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
26 ~VI_U() override; 28 ~VI_U() override;
27 29
28private: 30private:
29 void GetDisplayService(Kernel::HLERequestContext& ctx); 31 void GetDisplayService(Kernel::HLERequestContext& ctx);
30 32
31 NVFlinger::NVFlinger& nv_flinger; 33 NVFlinger::NVFlinger& nv_flinger;
34 NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
32}; 35};
33 36
34} // namespace Service::VI 37} // namespace Service::VI
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp
index 631446cf7..4a2564f47 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.cpp
+++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp
@@ -326,6 +326,11 @@ void Inst::AddPhiOperand(Block* predecessor, const Value& value) {
326 phi_args.emplace_back(predecessor, value); 326 phi_args.emplace_back(predecessor, value);
327} 327}
328 328
329void Inst::ErasePhiOperand(size_t index) {
330 const auto operand_it{phi_args.begin() + static_cast<ptrdiff_t>(index)};
331 phi_args.erase(operand_it);
332}
333
329void Inst::OrderPhiArgs() { 334void Inst::OrderPhiArgs() {
330 if (op != Opcode::Phi) { 335 if (op != Opcode::Phi) {
331 throw LogicError("{} is not a Phi instruction", op); 336 throw LogicError("{} is not a Phi instruction", op);
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h
index 947579852..14f6e55bc 100644
--- a/src/shader_recompiler/frontend/ir/value.h
+++ b/src/shader_recompiler/frontend/ir/value.h
@@ -179,9 +179,13 @@ public:
179 179
180 /// Get a pointer to the block of a phi argument. 180 /// Get a pointer to the block of a phi argument.
181 [[nodiscard]] Block* PhiBlock(size_t index) const; 181 [[nodiscard]] Block* PhiBlock(size_t index) const;
182
182 /// Add phi operand to a phi instruction. 183 /// Add phi operand to a phi instruction.
183 void AddPhiOperand(Block* predecessor, const Value& value); 184 void AddPhiOperand(Block* predecessor, const Value& value);
184 185
186 // Erase the phi operand at the given index.
187 void ErasePhiOperand(size_t index);
188
185 /// Orders the Phi arguments from farthest away to nearest. 189 /// Orders the Phi arguments from farthest away to nearest.
186 void OrderPhiArgs(); 190 void OrderPhiArgs();
187 191
diff --git a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
index 400836301..6697fde85 100644
--- a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
+++ b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
@@ -2,24 +2,104 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6
7#include <boost/container/small_vector.hpp>
8
5#include "shader_recompiler/frontend/ir/basic_block.h" 9#include "shader_recompiler/frontend/ir/basic_block.h"
6#include "shader_recompiler/frontend/ir/value.h" 10#include "shader_recompiler/frontend/ir/value.h"
7#include "shader_recompiler/ir_opt/passes.h" 11#include "shader_recompiler/ir_opt/passes.h"
8 12
9namespace Shader::Optimization { 13namespace Shader::Optimization {
10 14namespace {
11void DeadCodeEliminationPass(IR::Program& program) { 15template <bool TEST_USES>
16void DeadInstElimination(IR::Block* const block) {
12 // We iterate over the instructions in reverse order. 17 // We iterate over the instructions in reverse order.
13 // This is because removing an instruction reduces the number of uses for earlier instructions. 18 // This is because removing an instruction reduces the number of uses for earlier instructions.
14 for (IR::Block* const block : program.post_order_blocks) { 19 auto it{block->end()};
15 auto it{block->end()}; 20 while (it != block->begin()) {
16 while (it != block->begin()) { 21 --it;
17 --it; 22 if constexpr (TEST_USES) {
18 if (!it->HasUses() && !it->MayHaveSideEffects()) { 23 if (it->HasUses() || it->MayHaveSideEffects()) {
19 it->Invalidate(); 24 continue;
20 it = block->Instructions().erase(it); 25 }
26 }
27 it->Invalidate();
28 it = block->Instructions().erase(it);
29 }
30}
31
32void DeletedPhiArgElimination(IR::Program& program, std::span<const IR::Block*> dead_blocks) {
33 for (IR::Block* const block : program.blocks) {
34 for (IR::Inst& phi : *block) {
35 if (!IR::IsPhi(phi)) {
36 continue;
37 }
38 for (size_t i = 0; i < phi.NumArgs(); ++i) {
39 if (std::ranges::find(dead_blocks, phi.PhiBlock(i)) == dead_blocks.end()) {
40 continue;
41 }
42 // Phi operand at this index is an unreachable block
43 phi.ErasePhiOperand(i);
44 --i;
45 }
46 }
47 }
48}
49
50void DeadBranchElimination(IR::Program& program) {
51 boost::container::small_vector<const IR::Block*, 3> dead_blocks;
52 const auto begin_it{program.syntax_list.begin()};
53 for (auto node_it = begin_it; node_it != program.syntax_list.end(); ++node_it) {
54 if (node_it->type != IR::AbstractSyntaxNode::Type::If) {
55 continue;
56 }
57 IR::Inst* const cond_ref{node_it->data.if_node.cond.Inst()};
58 const IR::U1 cond{cond_ref->Arg(0)};
59 if (!cond.IsImmediate()) {
60 continue;
61 }
62 if (cond.U1()) {
63 continue;
64 }
65 // False immediate condition. Remove condition ref, erase the entire branch.
66 cond_ref->Invalidate();
67 // Account for nested if-statements within the if(false) branch
68 u32 nested_ifs{1u};
69 while (node_it->type != IR::AbstractSyntaxNode::Type::EndIf || nested_ifs > 0) {
70 node_it = program.syntax_list.erase(node_it);
71 switch (node_it->type) {
72 case IR::AbstractSyntaxNode::Type::If:
73 ++nested_ifs;
74 break;
75 case IR::AbstractSyntaxNode::Type::EndIf:
76 --nested_ifs;
77 break;
78 case IR::AbstractSyntaxNode::Type::Block: {
79 IR::Block* const block{node_it->data.block};
80 DeadInstElimination<false>(block);
81 dead_blocks.push_back(block);
82 break;
83 }
84 default:
85 break;
21 } 86 }
22 } 87 }
88 // Erase EndIf node of the if(false) branch
89 node_it = program.syntax_list.erase(node_it);
90 // Account for loop increment
91 --node_it;
92 }
93 if (!dead_blocks.empty()) {
94 DeletedPhiArgElimination(program, std::span(dead_blocks.data(), dead_blocks.size()));
95 }
96}
97} // namespace
98
99void DeadCodeEliminationPass(IR::Program& program) {
100 DeadBranchElimination(program);
101 for (IR::Block* const block : program.post_order_blocks) {
102 DeadInstElimination<true>(block);
23 } 103 }
24} 104}
25 105
diff --git a/src/video_core/framebuffer_config.h b/src/video_core/framebuffer_config.h
index b1d455e30..93349bb78 100644
--- a/src/video_core/framebuffer_config.h
+++ b/src/video_core/framebuffer_config.h
@@ -6,41 +6,22 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/math_util.h" 8#include "common/math_util.h"
9#include "core/hle/service/nvflinger/buffer_transform_flags.h"
10#include "core/hle/service/nvflinger/pixel_format.h"
9 11
10namespace Tegra { 12namespace Tegra {
13
11/** 14/**
12 * Struct describing framebuffer configuration 15 * Struct describing framebuffer configuration
13 */ 16 */
14struct FramebufferConfig { 17struct FramebufferConfig {
15 enum class PixelFormat : u32 {
16 A8B8G8R8_UNORM = 1,
17 RGB565_UNORM = 4,
18 B8G8R8A8_UNORM = 5,
19 };
20
21 enum class TransformFlags : u32 {
22 /// No transform flags are set
23 Unset = 0x00,
24 /// Flip source image horizontally (around the vertical axis)
25 FlipH = 0x01,
26 /// Flip source image vertically (around the horizontal axis)
27 FlipV = 0x02,
28 /// Rotate source image 90 degrees clockwise
29 Rotate90 = 0x04,
30 /// Rotate source image 180 degrees
31 Rotate180 = 0x03,
32 /// Rotate source image 270 degrees clockwise
33 Rotate270 = 0x07,
34 };
35
36 VAddr address{}; 18 VAddr address{};
37 u32 offset{}; 19 u32 offset{};
38 u32 width{}; 20 u32 width{};
39 u32 height{}; 21 u32 height{};
40 u32 stride{}; 22 u32 stride{};
41 PixelFormat pixel_format{}; 23 Service::android::PixelFormat pixel_format{};
42 24 Service::android::BufferTransformFlags transform_flags{};
43 TransformFlags transform_flags{};
44 Common::Rectangle<int> crop_rect; 25 Common::Rectangle<int> crop_rect;
45}; 26};
46 27
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 26b8ea233..97c029140 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -8,6 +8,7 @@
8 8
9#include "common/bit_field.h" 9#include "common/bit_field.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/service/nvdrv/nvdata.h"
11#include "video_core/cdma_pusher.h" 12#include "video_core/cdma_pusher.h"
12#include "video_core/framebuffer_config.h" 13#include "video_core/framebuffer_config.h"
13 14
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 795c97831..f8f29013a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -323,12 +323,12 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
323 323
324 GLint internal_format; 324 GLint internal_format;
325 switch (framebuffer.pixel_format) { 325 switch (framebuffer.pixel_format) {
326 case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: 326 case Service::android::PixelFormat::Rgba8888:
327 internal_format = GL_RGBA8; 327 internal_format = GL_RGBA8;
328 texture.gl_format = GL_RGBA; 328 texture.gl_format = GL_RGBA;
329 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; 329 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
330 break; 330 break;
331 case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: 331 case Service::android::PixelFormat::Rgb565:
332 internal_format = GL_RGB565; 332 internal_format = GL_RGB565;
333 texture.gl_format = GL_RGB; 333 texture.gl_format = GL_RGB;
334 texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; 334 texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
@@ -464,8 +464,8 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
464 const auto& texcoords = screen_info.display_texcoords; 464 const auto& texcoords = screen_info.display_texcoords;
465 auto left = texcoords.left; 465 auto left = texcoords.left;
466 auto right = texcoords.right; 466 auto right = texcoords.right;
467 if (framebuffer_transform_flags != Tegra::FramebufferConfig::TransformFlags::Unset) { 467 if (framebuffer_transform_flags != Service::android::BufferTransformFlags::Unset) {
468 if (framebuffer_transform_flags == Tegra::FramebufferConfig::TransformFlags::FlipV) { 468 if (framebuffer_transform_flags == Service::android::BufferTransformFlags::FlipV) {
469 // Flip the framebuffer vertically 469 // Flip the framebuffer vertically
470 left = texcoords.right; 470 left = texcoords.right;
471 right = texcoords.left; 471 right = texcoords.left;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 35706cf05..aa206878b 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -46,7 +46,7 @@ struct TextureInfo {
46 GLsizei height; 46 GLsizei height;
47 GLenum gl_format; 47 GLenum gl_format;
48 GLenum gl_type; 48 GLenum gl_type;
49 Tegra::FramebufferConfig::PixelFormat pixel_format; 49 Service::android::PixelFormat pixel_format;
50}; 50};
51 51
52/// Structure used for storing information about the display target for the Switch screen 52/// Structure used for storing information about the display target for the Switch screen
@@ -135,7 +135,7 @@ private:
135 std::vector<u8> gl_framebuffer_data; 135 std::vector<u8> gl_framebuffer_data;
136 136
137 /// Used for transforming the framebuffer orientation 137 /// Used for transforming the framebuffer orientation
138 Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{}; 138 Service::android::BufferTransformFlags framebuffer_transform_flags{};
139 Common::Rectangle<int> framebuffer_crop_rect; 139 Common::Rectangle<int> framebuffer_crop_rect;
140}; 140};
141 141
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 0ec85682b..d893c1952 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -94,11 +94,11 @@ std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) {
94 94
95VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { 95VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) {
96 switch (framebuffer.pixel_format) { 96 switch (framebuffer.pixel_format) {
97 case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: 97 case Service::android::PixelFormat::Rgba8888:
98 return VK_FORMAT_A8B8G8R8_UNORM_PACK32; 98 return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
99 case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: 99 case Service::android::PixelFormat::Rgb565:
100 return VK_FORMAT_R5G6B5_UNORM_PACK16; 100 return VK_FORMAT_R5G6B5_UNORM_PACK16;
101 case Tegra::FramebufferConfig::PixelFormat::B8G8R8A8_UNORM: 101 case Service::android::PixelFormat::Bgra8888:
102 return VK_FORMAT_B8G8R8A8_UNORM; 102 return VK_FORMAT_B8G8R8A8_UNORM;
103 default: 103 default:
104 UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", 104 UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}",
@@ -1390,9 +1390,9 @@ void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfi
1390 auto right = texcoords.right; 1390 auto right = texcoords.right;
1391 1391
1392 switch (framebuffer_transform_flags) { 1392 switch (framebuffer_transform_flags) {
1393 case Tegra::FramebufferConfig::TransformFlags::Unset: 1393 case Service::android::BufferTransformFlags::Unset:
1394 break; 1394 break;
1395 case Tegra::FramebufferConfig::TransformFlags::FlipV: 1395 case Service::android::BufferTransformFlags::FlipV:
1396 // Flip the framebuffer vertically 1396 // Flip the framebuffer vertically
1397 left = texcoords.right; 1397 left = texcoords.right;
1398 right = texcoords.left; 1398 right = texcoords.left;
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index a36015c8c..5f428d35d 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -190,13 +190,13 @@ PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format)
190 } 190 }
191} 191}
192 192
193PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { 193PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format) {
194 switch (format) { 194 switch (format) {
195 case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: 195 case Service::android::PixelFormat::Rgba8888:
196 return PixelFormat::A8B8G8R8_UNORM; 196 return PixelFormat::A8B8G8R8_UNORM;
197 case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: 197 case Service::android::PixelFormat::Rgb565:
198 return PixelFormat::R5G6B5_UNORM; 198 return PixelFormat::R5G6B5_UNORM;
199 case Tegra::FramebufferConfig::PixelFormat::B8G8R8A8_UNORM: 199 case Service::android::PixelFormat::Bgra8888:
200 return PixelFormat::B8G8R8A8_UNORM; 200 return PixelFormat::B8G8R8A8_UNORM;
201 default: 201 default:
202 UNIMPLEMENTED_MSG("Unimplemented format={}", format); 202 UNIMPLEMENTED_MSG("Unimplemented format={}", format);
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 33e8d24ab..5704cf16a 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -460,7 +460,7 @@ PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format);
460 460
461PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format); 461PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format);
462 462
463PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format); 463PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format);
464 464
465SurfaceType GetFormatType(PixelFormat pixel_format); 465SurfaceType GetFormatType(PixelFormat pixel_format);
466 466