diff options
author | Alistair Strachan | 2018-09-27 14:31:56 -0500 |
---|---|---|
committer | Alistair Strachan | 2018-09-27 14:32:51 -0500 |
commit | e77f68c1d7a607019f9cf36d47b8f33fcb9b7146 (patch) | |
tree | 0ee57162c5dd375cf49b1699dac54289f520b012 | |
parent | c6e38de712579ec0145302f8f9e456ba1e7214f1 (diff) | |
parent | e0067bdc75566629c9143818c8f3970c16c8825e (diff) | |
download | external-libkmsxx-e77f68c1d7a607019f9cf36d47b8f33fcb9b7146.tar.gz external-libkmsxx-e77f68c1d7a607019f9cf36d47b8f33fcb9b7146.tar.xz external-libkmsxx-e77f68c1d7a607019f9cf36d47b8f33fcb9b7146.zip |
Merge commit 'e0067bdc75566629c9143818c8f3970c16c8825e'
Bug: 110964307
Bug: 116741782
Signed-off-by: Alistair Strachan <astrachan@google.com>
Change-Id: I2130490f8fa61743217cbf2081640773960ea843
128 files changed, 16604 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7efae50 --- /dev/null +++ b/.gitignore | |||
@@ -0,0 +1,7 @@ | |||
1 | *.swp | ||
2 | *.a | ||
3 | *.so | ||
4 | build | ||
5 | *.txt.user | ||
6 | *.patch | ||
7 | py/__pycache__ | ||
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c6d1083 --- /dev/null +++ b/.gitmodules | |||
@@ -0,0 +1,3 @@ | |||
1 | [submodule "ext/pybind11"] | ||
2 | path = ext/pybind11 | ||
3 | url = https://github.com/pybind/pybind11.git | ||
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..353026a --- /dev/null +++ b/.travis.yml | |||
@@ -0,0 +1,81 @@ | |||
1 | # Ubuntu 14.04 Trusty support | ||
2 | sudo: required | ||
3 | dist: trusty | ||
4 | |||
5 | # Only build test master & travis | ||
6 | branches: | ||
7 | only: | ||
8 | - master | ||
9 | - travis | ||
10 | |||
11 | # Enable C++ support | ||
12 | language: cpp | ||
13 | |||
14 | addons: | ||
15 | apt: | ||
16 | sources: &sources | ||
17 | - ubuntu-toolchain-r-test | ||
18 | packages: &packages | ||
19 | - libegl1-mesa-dev | ||
20 | - libgles2-mesa-dev | ||
21 | - libwayland-dev | ||
22 | - libx11-xcb-dev | ||
23 | - libx11-dev | ||
24 | - libgbm-dev | ||
25 | |||
26 | # Need MYCC and MYCXX as travis overwrites CC and CXX | ||
27 | |||
28 | matrix: | ||
29 | include: | ||
30 | - compiler: gcc | ||
31 | addons: | ||
32 | apt: | ||
33 | sources: *sources | ||
34 | packages: [*packages, 'g++-4.8'] | ||
35 | env: MYCC=gcc-4.8 MYCXX=g++-4.8 | ||
36 | |||
37 | - compiler: gcc | ||
38 | addons: | ||
39 | apt: | ||
40 | sources: *sources | ||
41 | packages: [*packages, 'g++-4.9'] | ||
42 | # g++-4.9 gives a warning, disable it | ||
43 | env: MYCC=gcc-4.9 MYCXX=g++-4.9 CXXFLAGS=-Wno-maybe-uninitialized | ||
44 | |||
45 | - compiler: gcc | ||
46 | addons: | ||
47 | apt: | ||
48 | sources: *sources | ||
49 | packages: [*packages, 'g++-5'] | ||
50 | env: MYCC=gcc-5 MYCXX=g++-5 | ||
51 | |||
52 | - compiler: gcc | ||
53 | addons: | ||
54 | apt: | ||
55 | sources: *sources | ||
56 | packages: [*packages, 'g++-6'] | ||
57 | env: MYCC=gcc-6 MYCXX=g++-6 | ||
58 | |||
59 | - compiler: gcc | ||
60 | addons: | ||
61 | apt: | ||
62 | sources: *sources | ||
63 | packages: [*packages, 'g++-7'] | ||
64 | env: MYCC=gcc-7 MYCXX=g++-7 | ||
65 | |||
66 | - compiler: clang | ||
67 | addons: | ||
68 | apt: | ||
69 | sources: [*sources, 'llvm-toolchain-precise-3.8'] | ||
70 | packages: [*packages, 'clang-3.8'] | ||
71 | env: MYCC=clang-3.8 MYCXX=clang++-3.8 | ||
72 | |||
73 | # Build steps | ||
74 | script: | ||
75 | - mkdir build | ||
76 | - cd build | ||
77 | - CC=$MYCC CXX=$MYCXX cmake -DTREAT_WARNINGS_AS_ERRORS=1 -DKMSXX_ENABLE_KMSCUBE=1 -DKMSXX_ENABLE_PYTHON=1 .. && make VERBOSE=1 | ||
78 | |||
79 | notifications: | ||
80 | email: | ||
81 | - tomi.valkeinen@iki.fi | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..57088bc --- /dev/null +++ b/CMakeLists.txt | |||
@@ -0,0 +1,88 @@ | |||
1 | cmake_minimum_required(VERSION 2.8) | ||
2 | project(kms++) | ||
3 | |||
4 | include(LTO.cmake) | ||
5 | |||
6 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) | ||
7 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) | ||
8 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) | ||
9 | |||
10 | include(CheckCXXCompilerFlag) | ||
11 | |||
12 | IF(NOT CMAKE_BUILD_TYPE) | ||
13 | message(STATUS "Setting build type to 'Release' as none was specified.") | ||
14 | SET(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) | ||
15 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") | ||
16 | ENDIF() | ||
17 | |||
18 | string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) | ||
19 | |||
20 | option(BUILD_SHARED_LIBS "Build shared libs" FALSE) | ||
21 | option(TREAT_WARNINGS_AS_ERRORS "Treat warnings as errors" FALSE) | ||
22 | |||
23 | set(KMSXX_ENABLE_PYTHON ON CACHE BOOL "Enable Python wrappers") | ||
24 | set(KMSXX_PYTHON_VERSION "python3;python2" CACHE STRING "Python pkgconfig package") | ||
25 | |||
26 | set(KMSXX_ENABLE_KMSCUBE OFF CACHE BOOL "Enable kmscube") | ||
27 | |||
28 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall") | ||
29 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wno-unused-parameter") | ||
30 | |||
31 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") | ||
32 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wno-unused-parameter") | ||
33 | |||
34 | if (CMAKE_COMPILER_IS_GNUCC) | ||
35 | if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) | ||
36 | # GCC 4.x seems to warn too much | ||
37 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-field-initializers") | ||
38 | endif() | ||
39 | endif() | ||
40 | |||
41 | # HACK: cmake always adds "-rdynamic", this removes it | ||
42 | SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") | ||
43 | SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") | ||
44 | |||
45 | set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) | ||
46 | |||
47 | if (TREAT_WARNINGS_AS_ERRORS) | ||
48 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") | ||
49 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") | ||
50 | endif() | ||
51 | |||
52 | # static link libc | ||
53 | # set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++") | ||
54 | |||
55 | check_lto() | ||
56 | |||
57 | if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) | ||
58 | if (LTO_WORKS) | ||
59 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto") | ||
60 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") | ||
61 | set(CMAKE_AR "${LTO_AR}") | ||
62 | set(CMAKE_RANLIB "${LTO_RANLIB}") | ||
63 | endif() | ||
64 | endif() | ||
65 | |||
66 | find_package(PkgConfig REQUIRED) | ||
67 | pkg_check_modules(LIBDRM libdrm>=2.4.64 REQUIRED) | ||
68 | |||
69 | pkg_check_modules(LIBDRM_OMAP libdrm_omap) | ||
70 | if(LIBDRM_OMAP_FOUND) | ||
71 | add_definitions(-DHAS_LIBDRM_OMAP) | ||
72 | endif() | ||
73 | |||
74 | enable_testing() | ||
75 | |||
76 | add_subdirectory(kms++) | ||
77 | add_subdirectory(kms++util) | ||
78 | add_subdirectory(utils) | ||
79 | |||
80 | if(KMSXX_ENABLE_KMSCUBE) | ||
81 | add_subdirectory(kmscube) | ||
82 | endif() | ||
83 | |||
84 | if(KMSXX_ENABLE_PYTHON) | ||
85 | add_subdirectory(py) | ||
86 | endif() | ||
87 | |||
88 | add_custom_target(docs SOURCES "README.md") | ||
@@ -0,0 +1,373 @@ | |||
1 | Mozilla Public License Version 2.0 | ||
2 | ================================== | ||
3 | |||
4 | 1. Definitions | ||
5 | -------------- | ||
6 | |||
7 | 1.1. "Contributor" | ||
8 | means each individual or legal entity that creates, contributes to | ||
9 | the creation of, or owns Covered Software. | ||
10 | |||
11 | 1.2. "Contributor Version" | ||
12 | means the combination of the Contributions of others (if any) used | ||
13 | by a Contributor and that particular Contributor's Contribution. | ||
14 | |||
15 | 1.3. "Contribution" | ||
16 | means Covered Software of a particular Contributor. | ||
17 | |||
18 | 1.4. "Covered Software" | ||
19 | means Source Code Form to which the initial Contributor has attached | ||
20 | the notice in Exhibit A, the Executable Form of such Source Code | ||
21 | Form, and Modifications of such Source Code Form, in each case | ||
22 | including portions thereof. | ||
23 | |||
24 | 1.5. "Incompatible With Secondary Licenses" | ||
25 | means | ||
26 | |||
27 | (a) that the initial Contributor has attached the notice described | ||
28 | in Exhibit B to the Covered Software; or | ||
29 | |||
30 | (b) that the Covered Software was made available under the terms of | ||
31 | version 1.1 or earlier of the License, but not also under the | ||
32 | terms of a Secondary License. | ||
33 | |||
34 | 1.6. "Executable Form" | ||
35 | means any form of the work other than Source Code Form. | ||
36 | |||
37 | 1.7. "Larger Work" | ||
38 | means a work that combines Covered Software with other material, in | ||
39 | a separate file or files, that is not Covered Software. | ||
40 | |||
41 | 1.8. "License" | ||
42 | means this document. | ||
43 | |||
44 | 1.9. "Licensable" | ||
45 | means having the right to grant, to the maximum extent possible, | ||
46 | whether at the time of the initial grant or subsequently, any and | ||
47 | all of the rights conveyed by this License. | ||
48 | |||
49 | 1.10. "Modifications" | ||
50 | means any of the following: | ||
51 | |||
52 | (a) any file in Source Code Form that results from an addition to, | ||
53 | deletion from, or modification of the contents of Covered | ||
54 | Software; or | ||
55 | |||
56 | (b) any new file in Source Code Form that contains any Covered | ||
57 | Software. | ||
58 | |||
59 | 1.11. "Patent Claims" of a Contributor | ||
60 | means any patent claim(s), including without limitation, method, | ||
61 | process, and apparatus claims, in any patent Licensable by such | ||
62 | Contributor that would be infringed, but for the grant of the | ||
63 | License, by the making, using, selling, offering for sale, having | ||
64 | made, import, or transfer of either its Contributions or its | ||
65 | Contributor Version. | ||
66 | |||
67 | 1.12. "Secondary License" | ||
68 | means either the GNU General Public License, Version 2.0, the GNU | ||
69 | Lesser General Public License, Version 2.1, the GNU Affero General | ||
70 | Public License, Version 3.0, or any later versions of those | ||
71 | licenses. | ||
72 | |||
73 | 1.13. "Source Code Form" | ||
74 | means the form of the work preferred for making modifications. | ||
75 | |||
76 | 1.14. "You" (or "Your") | ||
77 | means an individual or a legal entity exercising rights under this | ||
78 | License. For legal entities, "You" includes any entity that | ||
79 | controls, is controlled by, or is under common control with You. For | ||
80 | purposes of this definition, "control" means (a) the power, direct | ||
81 | or indirect, to cause the direction or management of such entity, | ||
82 | whether by contract or otherwise, or (b) ownership of more than | ||
83 | fifty percent (50%) of the outstanding shares or beneficial | ||
84 | ownership of such entity. | ||
85 | |||
86 | 2. License Grants and Conditions | ||
87 | -------------------------------- | ||
88 | |||
89 | 2.1. Grants | ||
90 | |||
91 | Each Contributor hereby grants You a world-wide, royalty-free, | ||
92 | non-exclusive license: | ||
93 | |||
94 | (a) under intellectual property rights (other than patent or trademark) | ||
95 | Licensable by such Contributor to use, reproduce, make available, | ||
96 | modify, display, perform, distribute, and otherwise exploit its | ||
97 | Contributions, either on an unmodified basis, with Modifications, or | ||
98 | as part of a Larger Work; and | ||
99 | |||
100 | (b) under Patent Claims of such Contributor to make, use, sell, offer | ||
101 | for sale, have made, import, and otherwise transfer either its | ||
102 | Contributions or its Contributor Version. | ||
103 | |||
104 | 2.2. Effective Date | ||
105 | |||
106 | The licenses granted in Section 2.1 with respect to any Contribution | ||
107 | become effective for each Contribution on the date the Contributor first | ||
108 | distributes such Contribution. | ||
109 | |||
110 | 2.3. Limitations on Grant Scope | ||
111 | |||
112 | The licenses granted in this Section 2 are the only rights granted under | ||
113 | this License. No additional rights or licenses will be implied from the | ||
114 | distribution or licensing of Covered Software under this License. | ||
115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a | ||
116 | Contributor: | ||
117 | |||
118 | (a) for any code that a Contributor has removed from Covered Software; | ||
119 | or | ||
120 | |||
121 | (b) for infringements caused by: (i) Your and any other third party's | ||
122 | modifications of Covered Software, or (ii) the combination of its | ||
123 | Contributions with other software (except as part of its Contributor | ||
124 | Version); or | ||
125 | |||
126 | (c) under Patent Claims infringed by Covered Software in the absence of | ||
127 | its Contributions. | ||
128 | |||
129 | This License does not grant any rights in the trademarks, service marks, | ||
130 | or logos of any Contributor (except as may be necessary to comply with | ||
131 | the notice requirements in Section 3.4). | ||
132 | |||
133 | 2.4. Subsequent Licenses | ||
134 | |||
135 | No Contributor makes additional grants as a result of Your choice to | ||
136 | distribute the Covered Software under a subsequent version of this | ||
137 | License (see Section 10.2) or under the terms of a Secondary License (if | ||
138 | permitted under the terms of Section 3.3). | ||
139 | |||
140 | 2.5. Representation | ||
141 | |||
142 | Each Contributor represents that the Contributor believes its | ||
143 | Contributions are its original creation(s) or it has sufficient rights | ||
144 | to grant the rights to its Contributions conveyed by this License. | ||
145 | |||
146 | 2.6. Fair Use | ||
147 | |||
148 | This License is not intended to limit any rights You have under | ||
149 | applicable copyright doctrines of fair use, fair dealing, or other | ||
150 | equivalents. | ||
151 | |||
152 | 2.7. Conditions | ||
153 | |||
154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted | ||
155 | in Section 2.1. | ||
156 | |||
157 | 3. Responsibilities | ||
158 | ------------------- | ||
159 | |||
160 | 3.1. Distribution of Source Form | ||
161 | |||
162 | All distribution of Covered Software in Source Code Form, including any | ||
163 | Modifications that You create or to which You contribute, must be under | ||
164 | the terms of this License. You must inform recipients that the Source | ||
165 | Code Form of the Covered Software is governed by the terms of this | ||
166 | License, and how they can obtain a copy of this License. You may not | ||
167 | attempt to alter or restrict the recipients' rights in the Source Code | ||
168 | Form. | ||
169 | |||
170 | 3.2. Distribution of Executable Form | ||
171 | |||
172 | If You distribute Covered Software in Executable Form then: | ||
173 | |||
174 | (a) such Covered Software must also be made available in Source Code | ||
175 | Form, as described in Section 3.1, and You must inform recipients of | ||
176 | the Executable Form how they can obtain a copy of such Source Code | ||
177 | Form by reasonable means in a timely manner, at a charge no more | ||
178 | than the cost of distribution to the recipient; and | ||
179 | |||
180 | (b) You may distribute such Executable Form under the terms of this | ||
181 | License, or sublicense it under different terms, provided that the | ||
182 | license for the Executable Form does not attempt to limit or alter | ||
183 | the recipients' rights in the Source Code Form under this License. | ||
184 | |||
185 | 3.3. Distribution of a Larger Work | ||
186 | |||
187 | You may create and distribute a Larger Work under terms of Your choice, | ||
188 | provided that You also comply with the requirements of this License for | ||
189 | the Covered Software. If the Larger Work is a combination of Covered | ||
190 | Software with a work governed by one or more Secondary Licenses, and the | ||
191 | Covered Software is not Incompatible With Secondary Licenses, this | ||
192 | License permits You to additionally distribute such Covered Software | ||
193 | under the terms of such Secondary License(s), so that the recipient of | ||
194 | the Larger Work may, at their option, further distribute the Covered | ||
195 | Software under the terms of either this License or such Secondary | ||
196 | License(s). | ||
197 | |||
198 | 3.4. Notices | ||
199 | |||
200 | You may not remove or alter the substance of any license notices | ||
201 | (including copyright notices, patent notices, disclaimers of warranty, | ||
202 | or limitations of liability) contained within the Source Code Form of | ||
203 | the Covered Software, except that You may alter any license notices to | ||
204 | the extent required to remedy known factual inaccuracies. | ||
205 | |||
206 | 3.5. Application of Additional Terms | ||
207 | |||
208 | You may choose to offer, and to charge a fee for, warranty, support, | ||
209 | indemnity or liability obligations to one or more recipients of Covered | ||
210 | Software. However, You may do so only on Your own behalf, and not on | ||
211 | behalf of any Contributor. You must make it absolutely clear that any | ||
212 | such warranty, support, indemnity, or liability obligation is offered by | ||
213 | You alone, and You hereby agree to indemnify every Contributor for any | ||
214 | liability incurred by such Contributor as a result of warranty, support, | ||
215 | indemnity or liability terms You offer. You may include additional | ||
216 | disclaimers of warranty and limitations of liability specific to any | ||
217 | jurisdiction. | ||
218 | |||
219 | 4. Inability to Comply Due to Statute or Regulation | ||
220 | --------------------------------------------------- | ||
221 | |||
222 | If it is impossible for You to comply with any of the terms of this | ||
223 | License with respect to some or all of the Covered Software due to | ||
224 | statute, judicial order, or regulation then You must: (a) comply with | ||
225 | the terms of this License to the maximum extent possible; and (b) | ||
226 | describe the limitations and the code they affect. Such description must | ||
227 | be placed in a text file included with all distributions of the Covered | ||
228 | Software under this License. Except to the extent prohibited by statute | ||
229 | or regulation, such description must be sufficiently detailed for a | ||
230 | recipient of ordinary skill to be able to understand it. | ||
231 | |||
232 | 5. Termination | ||
233 | -------------- | ||
234 | |||
235 | 5.1. The rights granted under this License will terminate automatically | ||
236 | if You fail to comply with any of its terms. However, if You become | ||
237 | compliant, then the rights granted under this License from a particular | ||
238 | Contributor are reinstated (a) provisionally, unless and until such | ||
239 | Contributor explicitly and finally terminates Your grants, and (b) on an | ||
240 | ongoing basis, if such Contributor fails to notify You of the | ||
241 | non-compliance by some reasonable means prior to 60 days after You have | ||
242 | come back into compliance. Moreover, Your grants from a particular | ||
243 | Contributor are reinstated on an ongoing basis if such Contributor | ||
244 | notifies You of the non-compliance by some reasonable means, this is the | ||
245 | first time You have received notice of non-compliance with this License | ||
246 | from such Contributor, and You become compliant prior to 30 days after | ||
247 | Your receipt of the notice. | ||
248 | |||
249 | 5.2. If You initiate litigation against any entity by asserting a patent | ||
250 | infringement claim (excluding declaratory judgment actions, | ||
251 | counter-claims, and cross-claims) alleging that a Contributor Version | ||
252 | directly or indirectly infringes any patent, then the rights granted to | ||
253 | You by any and all Contributors for the Covered Software under Section | ||
254 | 2.1 of this License shall terminate. | ||
255 | |||
256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all | ||
257 | end user license agreements (excluding distributors and resellers) which | ||
258 | have been validly granted by You or Your distributors under this License | ||
259 | prior to termination shall survive termination. | ||
260 | |||
261 | ************************************************************************ | ||
262 | * * | ||
263 | * 6. Disclaimer of Warranty * | ||
264 | * ------------------------- * | ||
265 | * * | ||
266 | * Covered Software is provided under this License on an "as is" * | ||
267 | * basis, without warranty of any kind, either expressed, implied, or * | ||
268 | * statutory, including, without limitation, warranties that the * | ||
269 | * Covered Software is free of defects, merchantable, fit for a * | ||
270 | * particular purpose or non-infringing. The entire risk as to the * | ||
271 | * quality and performance of the Covered Software is with You. * | ||
272 | * Should any Covered Software prove defective in any respect, You * | ||
273 | * (not any Contributor) assume the cost of any necessary servicing, * | ||
274 | * repair, or correction. This disclaimer of warranty constitutes an * | ||
275 | * essential part of this License. No use of any Covered Software is * | ||
276 | * authorized under this License except under this disclaimer. * | ||
277 | * * | ||
278 | ************************************************************************ | ||
279 | |||
280 | ************************************************************************ | ||
281 | * * | ||
282 | * 7. Limitation of Liability * | ||
283 | * -------------------------- * | ||
284 | * * | ||
285 | * Under no circumstances and under no legal theory, whether tort * | ||
286 | * (including negligence), contract, or otherwise, shall any * | ||
287 | * Contributor, or anyone who distributes Covered Software as * | ||
288 | * permitted above, be liable to You for any direct, indirect, * | ||
289 | * special, incidental, or consequential damages of any character * | ||
290 | * including, without limitation, damages for lost profits, loss of * | ||
291 | * goodwill, work stoppage, computer failure or malfunction, or any * | ||
292 | * and all other commercial damages or losses, even if such party * | ||
293 | * shall have been informed of the possibility of such damages. This * | ||
294 | * limitation of liability shall not apply to liability for death or * | ||
295 | * personal injury resulting from such party's negligence to the * | ||
296 | * extent applicable law prohibits such limitation. Some * | ||
297 | * jurisdictions do not allow the exclusion or limitation of * | ||
298 | * incidental or consequential damages, so this exclusion and * | ||
299 | * limitation may not apply to You. * | ||
300 | * * | ||
301 | ************************************************************************ | ||
302 | |||
303 | 8. Litigation | ||
304 | ------------- | ||
305 | |||
306 | Any litigation relating to this License may be brought only in the | ||
307 | courts of a jurisdiction where the defendant maintains its principal | ||
308 | place of business and such litigation shall be governed by laws of that | ||
309 | jurisdiction, without reference to its conflict-of-law provisions. | ||
310 | Nothing in this Section shall prevent a party's ability to bring | ||
311 | cross-claims or counter-claims. | ||
312 | |||
313 | 9. Miscellaneous | ||
314 | ---------------- | ||
315 | |||
316 | This License represents the complete agreement concerning the subject | ||
317 | matter hereof. If any provision of this License is held to be | ||
318 | unenforceable, such provision shall be reformed only to the extent | ||
319 | necessary to make it enforceable. Any law or regulation which provides | ||
320 | that the language of a contract shall be construed against the drafter | ||
321 | shall not be used to construe this License against a Contributor. | ||
322 | |||
323 | 10. Versions of the License | ||
324 | --------------------------- | ||
325 | |||
326 | 10.1. New Versions | ||
327 | |||
328 | Mozilla Foundation is the license steward. Except as provided in Section | ||
329 | 10.3, no one other than the license steward has the right to modify or | ||
330 | publish new versions of this License. Each version will be given a | ||
331 | distinguishing version number. | ||
332 | |||
333 | 10.2. Effect of New Versions | ||
334 | |||
335 | You may distribute the Covered Software under the terms of the version | ||
336 | of the License under which You originally received the Covered Software, | ||
337 | or under the terms of any subsequent version published by the license | ||
338 | steward. | ||
339 | |||
340 | 10.3. Modified Versions | ||
341 | |||
342 | If you create software not governed by this License, and you want to | ||
343 | create a new license for such software, you may create and use a | ||
344 | modified version of this License if you rename the license and remove | ||
345 | any references to the name of the license steward (except to note that | ||
346 | such modified license differs from this License). | ||
347 | |||
348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary | ||
349 | Licenses | ||
350 | |||
351 | If You choose to distribute Source Code Form that is Incompatible With | ||
352 | Secondary Licenses under the terms of this version of the License, the | ||
353 | notice described in Exhibit B of this License must be attached. | ||
354 | |||
355 | Exhibit A - Source Code Form License Notice | ||
356 | ------------------------------------------- | ||
357 | |||
358 | This Source Code Form is subject to the terms of the Mozilla Public | ||
359 | License, v. 2.0. If a copy of the MPL was not distributed with this | ||
360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
361 | |||
362 | If it is not possible or desirable to put the notice in a particular | ||
363 | file, then You may include the notice in a location (such as a LICENSE | ||
364 | file in a relevant directory) where a recipient would be likely to look | ||
365 | for such a notice. | ||
366 | |||
367 | You may add additional accurate notices of copyright ownership. | ||
368 | |||
369 | Exhibit B - "Incompatible With Secondary Licenses" Notice | ||
370 | --------------------------------------------------------- | ||
371 | |||
372 | This Source Code Form is "Incompatible With Secondary Licenses", as | ||
373 | defined by the Mozilla Public License, v. 2.0. | ||
diff --git a/LTO.cmake b/LTO.cmake new file mode 100644 index 0000000..9a18d77 --- /dev/null +++ b/LTO.cmake | |||
@@ -0,0 +1,32 @@ | |||
1 | function(check_lto) | ||
2 | if (DEFINED LTO_WORKS) | ||
3 | return() | ||
4 | endif() | ||
5 | |||
6 | set(LTO_WORKS FALSE CACHE INTERNAL "LTO works") | ||
7 | |||
8 | CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG) | ||
9 | |||
10 | if (NOT HAS_LTO_FLAG) | ||
11 | return() | ||
12 | endif() | ||
13 | |||
14 | find_program(LTO_AR NAMES "${CMAKE_C_COMPILER}-ar" gcc-ar) | ||
15 | find_program(LTO_RANLIB NAMES "${CMAKE_C_COMPILER}-ranlib" gcc-ranlib) | ||
16 | |||
17 | if (NOT LTO_AR OR NOT LTO_RANLIB) | ||
18 | return() | ||
19 | endif() | ||
20 | |||
21 | EXECUTE_PROCESS(COMMAND "${LTO_AR}" --version RESULT_VARIABLE ret OUTPUT_QUIET ERROR_QUIET) | ||
22 | if (ret) | ||
23 | return() | ||
24 | endif() | ||
25 | |||
26 | EXECUTE_PROCESS(COMMAND "${LTO_RANLIB}" --version RESULT_VARIABLE ret OUTPUT_QUIET ERROR_QUIET) | ||
27 | if (ret) | ||
28 | return() | ||
29 | endif() | ||
30 | |||
31 | set(LTO_WORKS TRUE CACHE INTERNAL "LTO works") | ||
32 | endfunction() | ||
diff --git a/README.md b/README.md new file mode 100644 index 0000000..f0f3b97 --- /dev/null +++ b/README.md | |||
@@ -0,0 +1,99 @@ | |||
1 | [](https://travis-ci.org/tomba/kmsxx) | ||
2 | |||
3 | # kms++ - C++ library for kernel mode setting | ||
4 | |||
5 | kms++ is a C++11 library for kernel mode setting. | ||
6 | |||
7 | Also included are some simple utilities for KMS and python bindings for kms++. | ||
8 | |||
9 | ## Utilities | ||
10 | |||
11 | - kmstest - set modes and planes and show test pattern on crtcs/planes, and test page flips | ||
12 | - kmsprint - print information about DRM objects | ||
13 | - kmsview - view raw images | ||
14 | - kmscube - rotating 3D cube on crtcs/planes | ||
15 | - kmscapture - show captured frames from a camera on screen | ||
16 | |||
17 | ## Dependencies: | ||
18 | |||
19 | - libdrm | ||
20 | - Python 3.x (for python bindings) | ||
21 | |||
22 | ## Build instructions: | ||
23 | |||
24 | To build the Python bindings you need to set up the git-submodule for pybind11: | ||
25 | |||
26 | ``` | ||
27 | git submodule update --init | ||
28 | ``` | ||
29 | |||
30 | And to compile: | ||
31 | |||
32 | ``` | ||
33 | $ mkdir build | ||
34 | $ cd build | ||
35 | $ cmake .. | ||
36 | $ make -j4 | ||
37 | ``` | ||
38 | |||
39 | ## Cross compiling instructions: | ||
40 | |||
41 | Directions for cross compiling depend on your environment. | ||
42 | |||
43 | These are for mine with buildroot: | ||
44 | |||
45 | ``` | ||
46 | $ mkdir build | ||
47 | $ cd build | ||
48 | $ cmake -DCMAKE_TOOLCHAIN_FILE=<buildrootpath>/output/host/usr/share/buildroot/toolchainfile.cmake .. | ||
49 | $ make -j4 | ||
50 | ``` | ||
51 | |||
52 | Your environment may provide similar toolchainfile. If not, you can create a toolchainfile of your own, something along these lines: | ||
53 | |||
54 | ``` | ||
55 | SET(CMAKE_SYSTEM_NAME Linux) | ||
56 | |||
57 | SET(BROOT "<buildroot>/output/") | ||
58 | |||
59 | # specify the cross compiler | ||
60 | SET(CMAKE_C_COMPILER ${BROOT}/host/usr/bin/arm-buildroot-linux-gnueabihf-gcc) | ||
61 | SET(CMAKE_CXX_COMPILER ${BROOT}/host/usr/bin/arm-buildroot-linux-gnueabihf-g++) | ||
62 | |||
63 | # where is the target environment | ||
64 | SET(CMAKE_FIND_ROOT_PATH ${BROOT}/target ${BROOT}/host) | ||
65 | |||
66 | SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) | ||
67 | SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) | ||
68 | SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) | ||
69 | ``` | ||
70 | |||
71 | ## Build options | ||
72 | |||
73 | You can use the following cmake flags to control the build. Use `-DFLAG=VALUE` to set them. | ||
74 | |||
75 | Option name | Values | Default | Notes | ||
76 | --------------------- | ------------- | --------------- | -------- | ||
77 | CMAKE_BUILD_TYPE | Release/Debug | Release | | ||
78 | BUILD_SHARED_LIBS | ON/OFF | OFF | | ||
79 | KMSXX_ENABLE_PYTHON | ON/OFF | ON | | ||
80 | KMSXX_ENABLE_KMSCUBE | ON/OFF | OFF | | ||
81 | KMSXX_PYTHON_VERSION | python3/python2 | python3;python2 | Name of the python pkgconfig file | ||
82 | |||
83 | ## Env variables | ||
84 | |||
85 | You can use the following runtime environmental variables to control the behavior of kms++. | ||
86 | |||
87 | Variable | Description | ||
88 | --------------------------------- | ------------- | ||
89 | KMSXX_DISABLE_UNIVERSAL_PLANES | Set to disable the use of universal planes | ||
90 | KMSXX_DISABLE_ATOMIC | Set to disable the use of atomic modesetting | ||
91 | |||
92 | ## Python notes | ||
93 | |||
94 | You can run the python code directly from the build dir by defining PYTHONPATH env variable. For example: | ||
95 | |||
96 | ``` | ||
97 | PYTHONPATH=build/py py/tests/hpd.py | ||
98 | |||
99 | ``` | ||
@@ -0,0 +1,8 @@ | |||
1 | |||
2 | C++ move semantics for classes (especially for Framebuffers)? | ||
3 | |||
4 | Proper error checks and use of exceptions | ||
5 | |||
6 | Free drmModeConnectorPtr (and similar for other drm objects) after use, instead | ||
7 | of storing it. | ||
8 | |||
diff --git a/ext/pybind11 b/ext/pybind11 new file mode 160000 | |||
Subproject 086d53e8c66a84d0ec723d5435918c76edd878e | |||
diff --git a/kms++/CMakeLists.txt b/kms++/CMakeLists.txt new file mode 100644 index 0000000..10352a2 --- /dev/null +++ b/kms++/CMakeLists.txt | |||
@@ -0,0 +1,33 @@ | |||
1 | include_directories(${LIBDRM_INCLUDE_DIRS}) | ||
2 | link_directories(${LIBDRM_LIBRARY_DIRS}) | ||
3 | |||
4 | include_directories(${LIBDRM_OMAP_INCLUDE_DIRS}) | ||
5 | link_directories(${LIBDRM_OMAP_LIBRARY_DIRS}) | ||
6 | |||
7 | file(GLOB SRCS "src/*.cpp" "src/*.h") | ||
8 | file(GLOB PUB_HDRS "inc/kms++/*.h") | ||
9 | |||
10 | if(LIBDRM_OMAP_FOUND) | ||
11 | file(GLOB OMAP_SRCS "src/omap/*.cpp" "src/omap/*.h") | ||
12 | file(GLOB OMAP_PUB_HDRS "inc/kms++/omap/*.h") | ||
13 | |||
14 | set(SRCS ${SRCS} ${OMAP_SRCS}) | ||
15 | set(PUB_HDRS ${PUB_HDRS} ${OMAP_PUB_HDRS}) | ||
16 | endif() | ||
17 | |||
18 | add_library(kms++ ${SRCS} ${PUB_HDRS}) | ||
19 | |||
20 | target_include_directories(kms++ PUBLIC | ||
21 | $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc> | ||
22 | $<INSTALL_INTERFACE:include> | ||
23 | PRIVATE src) | ||
24 | |||
25 | target_link_libraries(kms++ ${LIBDRM_LIBRARIES} ${LIBDRM_OMAP_LIBRARIES}) | ||
26 | |||
27 | set_target_properties(kms++ PROPERTIES | ||
28 | PUBLIC_HEADER "${PUB_HDRS}") | ||
29 | |||
30 | install(TARGETS kms++ | ||
31 | LIBRARY DESTINATION lib | ||
32 | ARCHIVE DESTINATION lib | ||
33 | PUBLIC_HEADER DESTINATION include/kms++) | ||
diff --git a/kms++/inc/kms++/atomicreq.h b/kms++/inc/kms++/atomicreq.h new file mode 100644 index 0000000..a678b54 --- /dev/null +++ b/kms++/inc/kms++/atomicreq.h | |||
@@ -0,0 +1,39 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <cstdint> | ||
4 | #include <string> | ||
5 | #include <map> | ||
6 | |||
7 | struct _drmModeAtomicReq; | ||
8 | |||
9 | #include "decls.h" | ||
10 | |||
11 | namespace kms | ||
12 | { | ||
13 | class AtomicReq | ||
14 | { | ||
15 | public: | ||
16 | AtomicReq(Card& card); | ||
17 | ~AtomicReq(); | ||
18 | |||
19 | AtomicReq(const AtomicReq& other) = delete; | ||
20 | AtomicReq& operator=(const AtomicReq& other) = delete; | ||
21 | |||
22 | void add(uint32_t ob_id, uint32_t prop_id, uint64_t value); | ||
23 | void add(DrmPropObject *ob, Property *prop, uint64_t value); | ||
24 | void add(DrmPropObject *ob, const std::string& prop, uint64_t value); | ||
25 | void add(DrmPropObject *ob, const std::map<std::string, uint64_t>& values); | ||
26 | |||
27 | void add_display(Connector* conn, Crtc* crtc, Blob* videomode, | ||
28 | Plane* primary, Framebuffer* fb); | ||
29 | |||
30 | int test(bool allow_modeset = false); | ||
31 | int commit(void* data, bool allow_modeset = false); | ||
32 | int commit_sync(bool allow_modeset = false); | ||
33 | |||
34 | private: | ||
35 | Card& m_card; | ||
36 | _drmModeAtomicReq* m_req; | ||
37 | }; | ||
38 | |||
39 | } | ||
diff --git a/kms++/inc/kms++/blob.h b/kms++/inc/kms++/blob.h new file mode 100644 index 0000000..fd872f1 --- /dev/null +++ b/kms++/inc/kms++/blob.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "drmobject.h" | ||
4 | #include <vector> | ||
5 | |||
6 | namespace kms | ||
7 | { | ||
8 | |||
9 | class Blob : public DrmObject | ||
10 | { | ||
11 | public: | ||
12 | Blob(Card& card, uint32_t blob_id); | ||
13 | Blob(Card& card, void* data, size_t len); | ||
14 | virtual ~Blob(); | ||
15 | |||
16 | std::vector<uint8_t> data(); | ||
17 | |||
18 | private: | ||
19 | bool m_created; | ||
20 | }; | ||
21 | |||
22 | } | ||
diff --git a/kms++/inc/kms++/card.h b/kms++/inc/kms++/card.h new file mode 100644 index 0000000..c86278d --- /dev/null +++ b/kms++/inc/kms++/card.h | |||
@@ -0,0 +1,72 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <cstdint> | ||
4 | #include <vector> | ||
5 | #include <map> | ||
6 | |||
7 | #include "decls.h" | ||
8 | #include "pipeline.h" | ||
9 | |||
10 | namespace kms | ||
11 | { | ||
12 | class Card | ||
13 | { | ||
14 | friend class Framebuffer; | ||
15 | public: | ||
16 | Card(); | ||
17 | Card(const std::string& device); | ||
18 | virtual ~Card(); | ||
19 | |||
20 | Card(const Card& other) = delete; | ||
21 | Card& operator=(const Card& other) = delete; | ||
22 | |||
23 | int fd() const { return m_fd; } | ||
24 | |||
25 | void drop_master(); | ||
26 | |||
27 | Connector* get_first_connected_connector() const; | ||
28 | |||
29 | DrmObject* get_object(uint32_t id) const; | ||
30 | Connector* get_connector(uint32_t id) const; | ||
31 | Crtc* get_crtc(uint32_t id) const; | ||
32 | Encoder* get_encoder(uint32_t id) const; | ||
33 | Plane* get_plane(uint32_t id) const; | ||
34 | Property* get_prop(uint32_t id) const; | ||
35 | |||
36 | bool master() const { return m_master; } | ||
37 | bool has_atomic() const { return m_has_atomic; } | ||
38 | bool has_has_universal_planes() const { return m_has_universal_planes; } | ||
39 | |||
40 | const std::vector<Connector*> get_connectors() const { return m_connectors; } | ||
41 | const std::vector<Encoder*> get_encoders() const { return m_encoders; } | ||
42 | const std::vector<Crtc*> get_crtcs() const { return m_crtcs; } | ||
43 | const std::vector<Plane*> get_planes() const { return m_planes; } | ||
44 | const std::vector<Property*> get_properties() const { return m_properties; } | ||
45 | |||
46 | const std::vector<DrmObject*> get_objects() const; | ||
47 | |||
48 | std::vector<Pipeline> get_connected_pipelines(); | ||
49 | |||
50 | void call_page_flip_handlers(); | ||
51 | |||
52 | int disable_all(); | ||
53 | |||
54 | private: | ||
55 | void restore_modes(); | ||
56 | |||
57 | std::map<uint32_t, DrmObject*> m_obmap; | ||
58 | |||
59 | std::vector<Connector*> m_connectors; | ||
60 | std::vector<Encoder*> m_encoders; | ||
61 | std::vector<Crtc*> m_crtcs; | ||
62 | std::vector<Plane*> m_planes; | ||
63 | std::vector<Property*> m_properties; | ||
64 | std::vector<Framebuffer*> m_framebuffers; | ||
65 | |||
66 | int m_fd; | ||
67 | bool m_master; | ||
68 | |||
69 | bool m_has_atomic; | ||
70 | bool m_has_universal_planes; | ||
71 | }; | ||
72 | } | ||
diff --git a/kms++/inc/kms++/connector.h b/kms++/inc/kms++/connector.h new file mode 100644 index 0000000..3407730 --- /dev/null +++ b/kms++/inc/kms++/connector.h | |||
@@ -0,0 +1,53 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <vector> | ||
4 | |||
5 | #include "drmpropobject.h" | ||
6 | #include "videomode.h" | ||
7 | |||
8 | namespace kms | ||
9 | { | ||
10 | |||
11 | struct ConnectorPriv; | ||
12 | |||
13 | class Connector : public DrmPropObject | ||
14 | { | ||
15 | friend class Card; | ||
16 | public: | ||
17 | void refresh(); | ||
18 | |||
19 | Videomode get_default_mode() const; | ||
20 | |||
21 | Videomode get_mode(const std::string& mode) const; | ||
22 | Videomode get_mode(unsigned xres, unsigned yres, float vrefresh, bool ilace) const; | ||
23 | |||
24 | Crtc* get_current_crtc() const; | ||
25 | std::vector<Crtc*> get_possible_crtcs() const; | ||
26 | |||
27 | bool connected() const; | ||
28 | |||
29 | const std::string& fullname() const { return m_fullname; } | ||
30 | uint32_t connector_type() const; | ||
31 | uint32_t connector_type_id() const; | ||
32 | uint32_t mmWidth() const; | ||
33 | uint32_t mmHeight() const; | ||
34 | uint32_t subpixel() const; | ||
35 | const std::string& subpixel_str() const; | ||
36 | std::vector<Videomode> get_modes() const; | ||
37 | std::vector<Encoder*> get_encoders() const; | ||
38 | private: | ||
39 | Connector(Card& card, uint32_t id, uint32_t idx); | ||
40 | ~Connector(); | ||
41 | |||
42 | void setup(); | ||
43 | void restore_mode(); | ||
44 | |||
45 | ConnectorPriv* m_priv; | ||
46 | |||
47 | std::string m_fullname; | ||
48 | |||
49 | Encoder* m_current_encoder; | ||
50 | |||
51 | Crtc* m_saved_crtc; | ||
52 | }; | ||
53 | } | ||
diff --git a/kms++/inc/kms++/crtc.h b/kms++/inc/kms++/crtc.h new file mode 100644 index 0000000..ea20ef8 --- /dev/null +++ b/kms++/inc/kms++/crtc.h | |||
@@ -0,0 +1,54 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <vector> | ||
4 | |||
5 | #include "drmpropobject.h" | ||
6 | |||
7 | namespace kms | ||
8 | { | ||
9 | |||
10 | struct CrtcPriv; | ||
11 | |||
12 | class Crtc : public DrmPropObject | ||
13 | { | ||
14 | friend class Card; | ||
15 | friend class Connector; | ||
16 | public: | ||
17 | void refresh(); | ||
18 | |||
19 | const std::vector<Plane*>& get_possible_planes() const { return m_possible_planes; } | ||
20 | |||
21 | int set_mode(Connector* conn, const Videomode& mode); | ||
22 | int set_mode(Connector* conn, Framebuffer& fb, const Videomode& mode); | ||
23 | |||
24 | int set_plane(Plane *plane, Framebuffer &fb, | ||
25 | int32_t dst_x, int32_t dst_y, uint32_t dst_w, uint32_t dst_h, | ||
26 | float src_x, float src_y, float src_w, float src_h); | ||
27 | int disable_mode(); | ||
28 | |||
29 | int disable_plane(Plane* plane); | ||
30 | |||
31 | Plane* get_primary_plane(); | ||
32 | |||
33 | int page_flip(Framebuffer& fb, void *data); | ||
34 | |||
35 | uint32_t buffer_id() const; | ||
36 | uint32_t x() const; | ||
37 | uint32_t y() const; | ||
38 | uint32_t width() const; | ||
39 | uint32_t height() const; | ||
40 | int mode_valid() const; | ||
41 | Videomode mode() const; | ||
42 | int gamma_size() const; | ||
43 | private: | ||
44 | Crtc(Card& card, uint32_t id, uint32_t idx); | ||
45 | ~Crtc(); | ||
46 | |||
47 | void setup(); | ||
48 | void restore_mode(Connector *conn); | ||
49 | |||
50 | CrtcPriv* m_priv; | ||
51 | |||
52 | std::vector<Plane*> m_possible_planes; | ||
53 | }; | ||
54 | } | ||
diff --git a/kms++/inc/kms++/decls.h b/kms++/inc/kms++/decls.h new file mode 100644 index 0000000..91bce13 --- /dev/null +++ b/kms++/inc/kms++/decls.h | |||
@@ -0,0 +1,20 @@ | |||
1 | #pragma once | ||
2 | |||
3 | namespace kms | ||
4 | { | ||
5 | class AtomicReq; | ||
6 | class Blob; | ||
7 | class Card; | ||
8 | class Connector; | ||
9 | class Crtc; | ||
10 | class DrmObject; | ||
11 | class DrmPropObject; | ||
12 | class DumbFramebuffer; | ||
13 | class Encoder; | ||
14 | class ExtFramebuffer; | ||
15 | class Framebuffer; | ||
16 | class PageFlipHandlerBase; | ||
17 | class Plane; | ||
18 | class Property; | ||
19 | struct Videomode; | ||
20 | } | ||
diff --git a/kms++/inc/kms++/drmobject.h b/kms++/inc/kms++/drmobject.h new file mode 100644 index 0000000..a939aa7 --- /dev/null +++ b/kms++/inc/kms++/drmobject.h | |||
@@ -0,0 +1,40 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <map> | ||
4 | |||
5 | #include "decls.h" | ||
6 | |||
7 | namespace kms | ||
8 | { | ||
9 | |||
10 | class DrmObject | ||
11 | { | ||
12 | friend class Card; | ||
13 | public: | ||
14 | DrmObject(const DrmObject& other) = delete; | ||
15 | DrmObject& operator=(const DrmObject& other) = delete; | ||
16 | |||
17 | uint32_t id() const { return m_id; } | ||
18 | Card& card() const { return m_card; } | ||
19 | |||
20 | uint32_t object_type() const { return m_object_type; } | ||
21 | uint32_t idx() const { return m_idx; } | ||
22 | |||
23 | protected: | ||
24 | DrmObject(Card& card, uint32_t object_type); | ||
25 | DrmObject(Card& card, uint32_t id, uint32_t object_type, uint32_t idx = 0); | ||
26 | |||
27 | virtual ~DrmObject(); | ||
28 | |||
29 | virtual void setup() { } | ||
30 | |||
31 | virtual void set_id(uint32_t id); | ||
32 | |||
33 | private: | ||
34 | Card& m_card; | ||
35 | |||
36 | uint32_t m_id; | ||
37 | uint32_t m_object_type; | ||
38 | uint32_t m_idx; | ||
39 | }; | ||
40 | } | ||
diff --git a/kms++/inc/kms++/drmpropobject.h b/kms++/inc/kms++/drmpropobject.h new file mode 100644 index 0000000..38de584 --- /dev/null +++ b/kms++/inc/kms++/drmpropobject.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <map> | ||
4 | #include <memory> | ||
5 | |||
6 | #include "drmobject.h" | ||
7 | #include "decls.h" | ||
8 | |||
9 | namespace kms | ||
10 | { | ||
11 | |||
12 | class DrmPropObject : public DrmObject | ||
13 | { | ||
14 | friend class Card; | ||
15 | public: | ||
16 | void refresh_props(); | ||
17 | |||
18 | Property* get_prop(const std::string& name) const; | ||
19 | |||
20 | uint64_t get_prop_value(uint32_t id) const; | ||
21 | uint64_t get_prop_value(const std::string& name) const; | ||
22 | std::unique_ptr<Blob> get_prop_value_as_blob(const std::string& name) const; | ||
23 | |||
24 | const std::map<uint32_t, uint64_t>& get_prop_map() const { return m_prop_values; } | ||
25 | |||
26 | int set_prop_value(uint32_t id, uint64_t value); | ||
27 | int set_prop_value(const std::string& name, uint64_t value); | ||
28 | |||
29 | protected: | ||
30 | DrmPropObject(Card& card, uint32_t object_type); | ||
31 | DrmPropObject(Card& card, uint32_t id, uint32_t object_type, uint32_t idx = 0); | ||
32 | |||
33 | virtual ~DrmPropObject(); | ||
34 | |||
35 | private: | ||
36 | std::map<uint32_t, uint64_t> m_prop_values; | ||
37 | }; | ||
38 | } | ||
diff --git a/kms++/inc/kms++/dumbframebuffer.h b/kms++/inc/kms++/dumbframebuffer.h new file mode 100644 index 0000000..fb99d0e --- /dev/null +++ b/kms++/inc/kms++/dumbframebuffer.h | |||
@@ -0,0 +1,47 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "framebuffer.h" | ||
4 | #include "pixelformats.h" | ||
5 | |||
6 | namespace kms | ||
7 | { | ||
8 | |||
9 | class DumbFramebuffer : public Framebuffer | ||
10 | { | ||
11 | public: | ||
12 | DumbFramebuffer(Card& card, uint32_t width, uint32_t height, const std::string& fourcc); | ||
13 | DumbFramebuffer(Card& card, uint32_t width, uint32_t height, PixelFormat format); | ||
14 | virtual ~DumbFramebuffer(); | ||
15 | |||
16 | uint32_t width() const { return Framebuffer::width(); } | ||
17 | uint32_t height() const { return Framebuffer::height(); } | ||
18 | |||
19 | PixelFormat format() const { return m_format; } | ||
20 | unsigned num_planes() const { return m_num_planes; } | ||
21 | |||
22 | uint32_t handle(unsigned plane) const { return m_planes[plane].handle; } | ||
23 | uint32_t stride(unsigned plane) const { return m_planes[plane].stride; } | ||
24 | uint32_t size(unsigned plane) const { return m_planes[plane].size; } | ||
25 | uint32_t offset(unsigned plane) const { return m_planes[plane].offset; } | ||
26 | uint8_t* map(unsigned plane); | ||
27 | int prime_fd(unsigned plane); | ||
28 | |||
29 | private: | ||
30 | struct FramebufferPlane { | ||
31 | uint32_t handle; | ||
32 | int prime_fd; | ||
33 | uint32_t size; | ||
34 | uint32_t stride; | ||
35 | uint32_t offset; | ||
36 | uint8_t *map; | ||
37 | }; | ||
38 | |||
39 | void Create(); | ||
40 | void Destroy(); | ||
41 | |||
42 | unsigned m_num_planes; | ||
43 | struct FramebufferPlane m_planes[4]; | ||
44 | |||
45 | PixelFormat m_format; | ||
46 | }; | ||
47 | } | ||
diff --git a/kms++/inc/kms++/encoder.h b/kms++/inc/kms++/encoder.h new file mode 100644 index 0000000..1d36adc --- /dev/null +++ b/kms++/inc/kms++/encoder.h | |||
@@ -0,0 +1,27 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <vector> | ||
4 | #include "drmpropobject.h" | ||
5 | |||
6 | namespace kms | ||
7 | { | ||
8 | |||
9 | struct EncoderPriv; | ||
10 | |||
11 | class Encoder : public DrmPropObject | ||
12 | { | ||
13 | friend class Card; | ||
14 | public: | ||
15 | void refresh(); | ||
16 | |||
17 | Crtc* get_crtc() const; | ||
18 | std::vector<Crtc*> get_possible_crtcs() const; | ||
19 | |||
20 | const std::string& get_encoder_type() const; | ||
21 | private: | ||
22 | Encoder(Card& card, uint32_t id, uint32_t idx); | ||
23 | ~Encoder(); | ||
24 | |||
25 | EncoderPriv* m_priv; | ||
26 | }; | ||
27 | } | ||
diff --git a/kms++/inc/kms++/extframebuffer.h b/kms++/inc/kms++/extframebuffer.h new file mode 100644 index 0000000..5f0660c --- /dev/null +++ b/kms++/inc/kms++/extframebuffer.h | |||
@@ -0,0 +1,47 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "framebuffer.h" | ||
4 | #include "pixelformats.h" | ||
5 | |||
6 | namespace kms | ||
7 | { | ||
8 | |||
9 | class ExtFramebuffer : public Framebuffer | ||
10 | { | ||
11 | public: | ||
12 | ExtFramebuffer(Card& card, uint32_t width, uint32_t height, PixelFormat format, | ||
13 | std::vector<uint32_t> handles, std::vector<uint32_t> pitches, std::vector<uint32_t> offsets); | ||
14 | ExtFramebuffer(Card& card, uint32_t width, uint32_t height, PixelFormat format, | ||
15 | std::vector<int> fds, std::vector<uint32_t> pitches, std::vector<uint32_t> offsets); | ||
16 | virtual ~ExtFramebuffer(); | ||
17 | |||
18 | uint32_t width() const { return Framebuffer::width(); } | ||
19 | uint32_t height() const { return Framebuffer::height(); } | ||
20 | |||
21 | PixelFormat format() const { return m_format; } | ||
22 | unsigned num_planes() const { return m_num_planes; } | ||
23 | |||
24 | uint32_t handle(unsigned plane) const { return m_planes[plane].handle; } | ||
25 | uint32_t stride(unsigned plane) const { return m_planes[plane].stride; } | ||
26 | uint32_t size(unsigned plane) const { return m_planes[plane].size; } | ||
27 | uint32_t offset(unsigned plane) const { return m_planes[plane].offset; } | ||
28 | uint8_t* map(unsigned plane); | ||
29 | int prime_fd(unsigned plane); | ||
30 | |||
31 | private: | ||
32 | struct FramebufferPlane { | ||
33 | uint32_t handle; | ||
34 | int prime_fd; | ||
35 | uint32_t size; | ||
36 | uint32_t stride; | ||
37 | uint32_t offset; | ||
38 | uint8_t *map; | ||
39 | }; | ||
40 | |||
41 | unsigned m_num_planes; | ||
42 | struct FramebufferPlane m_planes[4]; | ||
43 | |||
44 | PixelFormat m_format; | ||
45 | }; | ||
46 | |||
47 | } | ||
diff --git a/kms++/inc/kms++/framebuffer.h b/kms++/inc/kms++/framebuffer.h new file mode 100644 index 0000000..3d43d08 --- /dev/null +++ b/kms++/inc/kms++/framebuffer.h | |||
@@ -0,0 +1,43 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "drmobject.h" | ||
4 | #include "pixelformats.h" | ||
5 | |||
6 | namespace kms | ||
7 | { | ||
8 | class IFramebuffer { | ||
9 | public: | ||
10 | virtual ~IFramebuffer() { } | ||
11 | |||
12 | virtual uint32_t width() const = 0; | ||
13 | virtual uint32_t height() const = 0; | ||
14 | |||
15 | virtual PixelFormat format() const { throw std::runtime_error("not implemented"); } | ||
16 | virtual unsigned num_planes() const { throw std::runtime_error("not implemented"); } | ||
17 | |||
18 | virtual uint32_t stride(unsigned plane) const { throw std::runtime_error("not implemented"); } | ||
19 | virtual uint32_t size(unsigned plane) const { throw std::runtime_error("not implemented"); } | ||
20 | virtual uint32_t offset(unsigned plane) const { throw std::runtime_error("not implemented"); } | ||
21 | virtual uint8_t* map(unsigned plane) { throw std::runtime_error("not implemented"); } | ||
22 | virtual int prime_fd(unsigned plane) { throw std::runtime_error("not implemented"); } | ||
23 | }; | ||
24 | |||
25 | class Framebuffer : public DrmObject, public IFramebuffer | ||
26 | { | ||
27 | public: | ||
28 | Framebuffer(Card& card, uint32_t id); | ||
29 | virtual ~Framebuffer(); | ||
30 | |||
31 | uint32_t width() const { return m_width; } | ||
32 | uint32_t height() const { return m_height; } | ||
33 | |||
34 | void flush(); | ||
35 | protected: | ||
36 | Framebuffer(Card& card, uint32_t width, uint32_t height); | ||
37 | |||
38 | private: | ||
39 | uint32_t m_width; | ||
40 | uint32_t m_height; | ||
41 | }; | ||
42 | |||
43 | } | ||
diff --git a/kms++/inc/kms++/kms++.h b/kms++/inc/kms++/kms++.h new file mode 100644 index 0000000..3365ef7 --- /dev/null +++ b/kms++/inc/kms++/kms++.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "atomicreq.h" | ||
4 | #include "card.h" | ||
5 | #include "connector.h" | ||
6 | #include "crtc.h" | ||
7 | #include "encoder.h" | ||
8 | #include "framebuffer.h" | ||
9 | #include "dumbframebuffer.h" | ||
10 | #include "extframebuffer.h" | ||
11 | #include "plane.h" | ||
12 | #include "property.h" | ||
13 | #include "blob.h" | ||
14 | #include "pipeline.h" | ||
15 | #include "pagefliphandler.h" | ||
diff --git a/kms++/inc/kms++/mode_cvt.h b/kms++/inc/kms++/mode_cvt.h new file mode 100644 index 0000000..8902e4a --- /dev/null +++ b/kms++/inc/kms++/mode_cvt.h | |||
@@ -0,0 +1,10 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <kms++/videomode.h> | ||
4 | |||
5 | namespace kms | ||
6 | { | ||
7 | |||
8 | Videomode videomode_from_cvt(uint32_t hact, uint32_t vact, uint32_t refresh, bool ilace, bool reduced_v2, bool video_optimized); | ||
9 | |||
10 | } | ||
diff --git a/kms++/inc/kms++/modedb.h b/kms++/inc/kms++/modedb.h new file mode 100644 index 0000000..b6447c6 --- /dev/null +++ b/kms++/inc/kms++/modedb.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <cstdint> | ||
4 | #include "videomode.h" | ||
5 | |||
6 | namespace kms | ||
7 | { | ||
8 | struct Videomode; | ||
9 | |||
10 | extern const Videomode dmt_modes[]; | ||
11 | extern const Videomode cea_modes[]; | ||
12 | |||
13 | const Videomode& find_dmt(uint32_t width, uint32_t height, float vrefresh, bool ilace); | ||
14 | const Videomode& find_cea(uint32_t width, uint32_t height, float vrefresh, bool ilace); | ||
15 | |||
16 | } | ||
diff --git a/kms++/inc/kms++/omap/omapcard.h b/kms++/inc/kms++/omap/omapcard.h new file mode 100644 index 0000000..5c2f3a5 --- /dev/null +++ b/kms++/inc/kms++/omap/omapcard.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <kms++/card.h> | ||
4 | |||
5 | struct omap_device; | ||
6 | |||
7 | namespace kms | ||
8 | { | ||
9 | class OmapCard : public Card | ||
10 | { | ||
11 | public: | ||
12 | OmapCard(); | ||
13 | OmapCard(const std::string& device); | ||
14 | virtual ~OmapCard(); | ||
15 | |||
16 | struct omap_device* dev() const { return m_omap_dev; } | ||
17 | |||
18 | private: | ||
19 | struct omap_device* m_omap_dev; | ||
20 | }; | ||
21 | } | ||
diff --git a/kms++/inc/kms++/omap/omapframebuffer.h b/kms++/inc/kms++/omap/omapframebuffer.h new file mode 100644 index 0000000..70bf946 --- /dev/null +++ b/kms++/inc/kms++/omap/omapframebuffer.h | |||
@@ -0,0 +1,62 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <kms++/framebuffer.h> | ||
4 | #include <kms++/pixelformats.h> | ||
5 | |||
6 | struct omap_bo; | ||
7 | |||
8 | namespace kms | ||
9 | { | ||
10 | class OmapCard; | ||
11 | |||
12 | class OmapFramebuffer : public Framebuffer | ||
13 | { | ||
14 | public: | ||
15 | enum Flags | ||
16 | { | ||
17 | None = 0, | ||
18 | Tiled = 1 << 0, | ||
19 | MemContig = 1 << 1, | ||
20 | MemTiler = 1 << 2, | ||
21 | MemPin = 1 << 3, | ||
22 | }; | ||
23 | |||
24 | OmapFramebuffer(OmapCard& card, uint32_t width, uint32_t height, const std::string& fourcc, Flags flags = Flags::None); | ||
25 | OmapFramebuffer(OmapCard& card, uint32_t width, uint32_t height, PixelFormat format, Flags flags = Flags::None); | ||
26 | virtual ~OmapFramebuffer(); | ||
27 | |||
28 | uint32_t width() const { return Framebuffer::width(); } | ||
29 | uint32_t height() const { return Framebuffer::height(); } | ||
30 | |||
31 | PixelFormat format() const { return m_format; } | ||
32 | unsigned num_planes() const { return m_num_planes; } | ||
33 | |||
34 | uint32_t handle(unsigned plane) const { return m_planes[plane].handle; } | ||
35 | uint32_t stride(unsigned plane) const { return m_planes[plane].stride; } | ||
36 | uint32_t size(unsigned plane) const { return m_planes[plane].size; } | ||
37 | uint32_t offset(unsigned plane) const { return m_planes[plane].offset; } | ||
38 | uint8_t* map(unsigned plane); | ||
39 | int prime_fd(unsigned plane); | ||
40 | |||
41 | private: | ||
42 | OmapCard& m_omap_card; | ||
43 | |||
44 | struct FramebufferPlane { | ||
45 | struct omap_bo* omap_bo; | ||
46 | uint32_t handle; | ||
47 | int prime_fd; | ||
48 | uint32_t size; | ||
49 | uint32_t stride; | ||
50 | uint32_t offset; | ||
51 | uint8_t* map; | ||
52 | }; | ||
53 | |||
54 | void Create(Flags buffer_flags); | ||
55 | void Destroy(); | ||
56 | |||
57 | unsigned m_num_planes; | ||
58 | struct FramebufferPlane m_planes[3]; | ||
59 | |||
60 | PixelFormat m_format; | ||
61 | }; | ||
62 | } | ||
diff --git a/kms++/inc/kms++/omap/omapkms++.h b/kms++/inc/kms++/omap/omapkms++.h new file mode 100644 index 0000000..0d86841 --- /dev/null +++ b/kms++/inc/kms++/omap/omapkms++.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <kms++/omap/omapcard.h> | ||
4 | #include <kms++/omap/omapframebuffer.h> | ||
diff --git a/kms++/inc/kms++/pagefliphandler.h b/kms++/inc/kms++/pagefliphandler.h new file mode 100644 index 0000000..79cda0d --- /dev/null +++ b/kms++/inc/kms++/pagefliphandler.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #pragma once | ||
2 | |||
3 | namespace kms { | ||
4 | class PageFlipHandlerBase | ||
5 | { | ||
6 | public: | ||
7 | PageFlipHandlerBase() { } | ||
8 | virtual ~PageFlipHandlerBase() { } | ||
9 | virtual void handle_page_flip(uint32_t frame, double time) = 0; | ||
10 | }; | ||
11 | } | ||
diff --git a/kms++/inc/kms++/pipeline.h b/kms++/inc/kms++/pipeline.h new file mode 100644 index 0000000..ef04ec1 --- /dev/null +++ b/kms++/inc/kms++/pipeline.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "decls.h" | ||
4 | |||
5 | namespace kms | ||
6 | { | ||
7 | struct Pipeline { | ||
8 | Crtc* crtc; | ||
9 | Connector* connector; | ||
10 | }; | ||
11 | } | ||
diff --git a/kms++/inc/kms++/pixelformats.h b/kms++/inc/kms++/pixelformats.h new file mode 100644 index 0000000..6392de1 --- /dev/null +++ b/kms++/inc/kms++/pixelformats.h | |||
@@ -0,0 +1,67 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <cstdint> | ||
4 | #include <string> | ||
5 | |||
6 | namespace kms | ||
7 | { | ||
8 | constexpr uint32_t MakeFourCC(const char *fourcc) | ||
9 | { | ||
10 | return fourcc[0] | (fourcc[1] << 8) | (fourcc[2] << 16) | (fourcc[3] << 24); | ||
11 | } | ||
12 | |||
13 | enum class PixelFormat : uint32_t | ||
14 | { | ||
15 | Undefined = 0, | ||
16 | |||
17 | NV12 = MakeFourCC("NV12"), | ||
18 | NV21 = MakeFourCC("NV21"), | ||
19 | |||
20 | UYVY = MakeFourCC("UYVY"), | ||
21 | YUYV = MakeFourCC("YUYV"), | ||
22 | YVYU = MakeFourCC("YVYU"), | ||
23 | VYUY = MakeFourCC("VYUY"), | ||
24 | |||
25 | XRGB8888 = MakeFourCC("XR24"), | ||
26 | XBGR8888 = MakeFourCC("XB24"), | ||
27 | ARGB8888 = MakeFourCC("AR24"), | ||
28 | ABGR8888 = MakeFourCC("AB24"), | ||
29 | |||
30 | RGB888 = MakeFourCC("RG24"), | ||
31 | BGR888 = MakeFourCC("BG24"), | ||
32 | |||
33 | RGB565 = MakeFourCC("RG16"), | ||
34 | BGR565 = MakeFourCC("BG16"), | ||
35 | }; | ||
36 | |||
37 | static inline PixelFormat FourCCToPixelFormat(const std::string& fourcc) | ||
38 | { | ||
39 | return (PixelFormat)MakeFourCC(fourcc.c_str()); | ||
40 | } | ||
41 | |||
42 | static inline std::string PixelFormatToFourCC(PixelFormat f) | ||
43 | { | ||
44 | char buf[5] = { (char)(((int)f >> 0) & 0xff), | ||
45 | (char)(((int)f >> 8) & 0xff), | ||
46 | (char)(((int)f >> 16) & 0xff), | ||
47 | (char)(((int)f >> 24) & 0xff), | ||
48 | 0 }; | ||
49 | return std::string(buf); | ||
50 | } | ||
51 | |||
52 | struct PixelFormatPlaneInfo | ||
53 | { | ||
54 | uint8_t bitspp; | ||
55 | uint8_t xsub; | ||
56 | uint8_t ysub; | ||
57 | }; | ||
58 | |||
59 | struct PixelFormatInfo | ||
60 | { | ||
61 | uint8_t num_planes; | ||
62 | struct PixelFormatPlaneInfo planes[4]; | ||
63 | }; | ||
64 | |||
65 | const struct PixelFormatInfo& get_pixel_format_info(PixelFormat format); | ||
66 | |||
67 | } | ||
diff --git a/kms++/inc/kms++/plane.h b/kms++/inc/kms++/plane.h new file mode 100644 index 0000000..27e819b --- /dev/null +++ b/kms++/inc/kms++/plane.h | |||
@@ -0,0 +1,42 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "drmpropobject.h" | ||
4 | |||
5 | namespace kms | ||
6 | { | ||
7 | |||
8 | enum class PlaneType | ||
9 | { | ||
10 | Overlay = 1 << 0, | ||
11 | Primary = 1 << 1, | ||
12 | Cursor = 1 << 2, | ||
13 | }; | ||
14 | |||
15 | struct PlanePriv; | ||
16 | |||
17 | class Plane : public DrmPropObject | ||
18 | { | ||
19 | friend class Card; | ||
20 | public: | ||
21 | bool supports_crtc(Crtc* crtc) const; | ||
22 | bool supports_format(PixelFormat fmt) const; | ||
23 | |||
24 | PlaneType plane_type() const; | ||
25 | |||
26 | std::vector<Crtc*> get_possible_crtcs() const; | ||
27 | std::vector<PixelFormat> get_formats() const; | ||
28 | uint32_t crtc_id() const; | ||
29 | uint32_t fb_id() const; | ||
30 | |||
31 | uint32_t crtc_x() const; | ||
32 | uint32_t crtc_y() const; | ||
33 | uint32_t x() const; | ||
34 | uint32_t y() const; | ||
35 | uint32_t gamma_size() const; | ||
36 | private: | ||
37 | Plane(Card& card, uint32_t id, uint32_t idx); | ||
38 | ~Plane(); | ||
39 | |||
40 | PlanePriv* m_priv; | ||
41 | }; | ||
42 | } | ||
diff --git a/kms++/inc/kms++/property.h b/kms++/inc/kms++/property.h new file mode 100644 index 0000000..b9097ff --- /dev/null +++ b/kms++/inc/kms++/property.h | |||
@@ -0,0 +1,44 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "drmobject.h" | ||
4 | #include <map> | ||
5 | #include <vector> | ||
6 | |||
7 | namespace kms | ||
8 | { | ||
9 | |||
10 | struct PropertyPriv; | ||
11 | |||
12 | enum class PropertyType | ||
13 | { | ||
14 | Range, | ||
15 | Enum, | ||
16 | Blob, | ||
17 | Bitmask, | ||
18 | Object, | ||
19 | SignedRange, | ||
20 | }; | ||
21 | |||
22 | class Property : public DrmObject | ||
23 | { | ||
24 | friend class Card; | ||
25 | public: | ||
26 | const std::string& name() const; | ||
27 | |||
28 | bool is_immutable() const; | ||
29 | bool is_pending() const; | ||
30 | |||
31 | PropertyType type() const { return m_type; } | ||
32 | std::map<uint64_t, std::string> get_enums() const; | ||
33 | std::vector<uint64_t> get_values() const; | ||
34 | std::vector<uint32_t> get_blob_ids() const; | ||
35 | private: | ||
36 | Property(Card& card, uint32_t id); | ||
37 | ~Property(); | ||
38 | |||
39 | PropertyType m_type; | ||
40 | |||
41 | PropertyPriv* m_priv; | ||
42 | std::string m_name; | ||
43 | }; | ||
44 | } | ||
diff --git a/kms++/inc/kms++/videomode.h b/kms++/inc/kms++/videomode.h new file mode 100644 index 0000000..d7f5258 --- /dev/null +++ b/kms++/inc/kms++/videomode.h | |||
@@ -0,0 +1,58 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <string> | ||
4 | #include <cstdint> | ||
5 | #include <memory> | ||
6 | |||
7 | #include "blob.h" | ||
8 | |||
9 | namespace kms | ||
10 | { | ||
11 | |||
12 | enum class SyncPolarity | ||
13 | { | ||
14 | Undefined, | ||
15 | Positive, | ||
16 | Negative, | ||
17 | }; | ||
18 | |||
19 | struct Videomode | ||
20 | { | ||
21 | std::string name; | ||
22 | |||
23 | uint32_t clock; | ||
24 | uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; | ||
25 | uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; | ||
26 | |||
27 | uint32_t vrefresh; | ||
28 | |||
29 | uint32_t flags; // DRM_MODE_FLAG_* | ||
30 | uint32_t type; // DRM_MODE_TYPE_* | ||
31 | |||
32 | std::unique_ptr<Blob> to_blob(Card& card) const; | ||
33 | |||
34 | uint16_t hfp() const { return hsync_start - hdisplay; } | ||
35 | uint16_t hsw() const { return hsync_end - hsync_start; } | ||
36 | uint16_t hbp() const { return htotal - hsync_end; } | ||
37 | |||
38 | uint16_t vfp() const { return vsync_start - vdisplay; } | ||
39 | uint16_t vsw() const { return vsync_end - vsync_start; } | ||
40 | uint16_t vbp() const { return vtotal - vsync_end; } | ||
41 | |||
42 | float calculated_vrefresh() const; | ||
43 | |||
44 | bool interlace() const; | ||
45 | SyncPolarity hsync() const; | ||
46 | SyncPolarity vsync() const; | ||
47 | |||
48 | void set_interlace(bool ilace); | ||
49 | void set_hsync(SyncPolarity pol); | ||
50 | void set_vsync(SyncPolarity pol); | ||
51 | |||
52 | std::string to_string() const; | ||
53 | }; | ||
54 | |||
55 | struct Videomode videomode_from_timings(uint32_t clock_khz, | ||
56 | uint16_t hact, uint16_t hfp, uint16_t hsw, uint16_t hbp, | ||
57 | uint16_t vact, uint16_t vfp, uint16_t vsw, uint16_t vbp); | ||
58 | } | ||
diff --git a/kms++/src/atomicreq.cpp b/kms++/src/atomicreq.cpp new file mode 100644 index 0000000..28128f2 --- /dev/null +++ b/kms++/src/atomicreq.cpp | |||
@@ -0,0 +1,117 @@ | |||
1 | #include <cassert> | ||
2 | #include <stdexcept> | ||
3 | |||
4 | #include <xf86drm.h> | ||
5 | #include <xf86drmMode.h> | ||
6 | |||
7 | #include <kms++/kms++.h> | ||
8 | |||
9 | #ifndef DRM_CLIENT_CAP_ATOMIC | ||
10 | |||
11 | #define DRM_MODE_ATOMIC_TEST_ONLY 0 | ||
12 | #define DRM_MODE_ATOMIC_NONBLOCK 0 | ||
13 | |||
14 | struct _drmModeAtomicReq; | ||
15 | typedef struct _drmModeAtomicReq* drmModeAtomicReqPtr; | ||
16 | |||
17 | static inline drmModeAtomicReqPtr drmModeAtomicAlloc() { return 0; } | ||
18 | static inline void drmModeAtomicFree(drmModeAtomicReqPtr) { } | ||
19 | static inline int drmModeAtomicAddProperty(drmModeAtomicReqPtr, uint32_t, uint32_t, uint64_t) { return 0; } | ||
20 | static inline int drmModeAtomicCommit(int, drmModeAtomicReqPtr, int, void*) { return 0; } | ||
21 | |||
22 | #endif // DRM_CLIENT_CAP_ATOMIC | ||
23 | |||
24 | using namespace std; | ||
25 | |||
26 | namespace kms | ||
27 | { | ||
28 | AtomicReq::AtomicReq(Card& card) | ||
29 | : m_card(card) | ||
30 | { | ||
31 | assert(card.has_atomic()); | ||
32 | m_req = drmModeAtomicAlloc(); | ||
33 | } | ||
34 | |||
35 | AtomicReq::~AtomicReq() | ||
36 | { | ||
37 | drmModeAtomicFree(m_req); | ||
38 | } | ||
39 | |||
40 | void AtomicReq::add(uint32_t ob_id, uint32_t prop_id, uint64_t value) | ||
41 | { | ||
42 | int r = drmModeAtomicAddProperty(m_req, ob_id, prop_id, value); | ||
43 | if (r <= 0) | ||
44 | throw std::invalid_argument("foo"); | ||
45 | } | ||
46 | |||
47 | void AtomicReq::add(DrmPropObject* ob, Property *prop, uint64_t value) | ||
48 | { | ||
49 | add(ob->id(), prop->id(), value); | ||
50 | } | ||
51 | |||
52 | void AtomicReq::add(kms::DrmPropObject* ob, const string& prop, uint64_t value) | ||
53 | { | ||
54 | add(ob, ob->get_prop(prop), value); | ||
55 | } | ||
56 | |||
57 | void AtomicReq::add(kms::DrmPropObject* ob, const map<string, uint64_t>& values) | ||
58 | { | ||
59 | for(const auto& kvp : values) | ||
60 | add(ob, kvp.first, kvp.second); | ||
61 | } | ||
62 | |||
63 | void AtomicReq::add_display(Connector* conn, Crtc* crtc, Blob* videomode, Plane* primary, Framebuffer* fb) | ||
64 | { | ||
65 | add(conn, { | ||
66 | { "CRTC_ID", crtc->id() }, | ||
67 | }); | ||
68 | |||
69 | add(crtc, { | ||
70 | { "ACTIVE", 1 }, | ||
71 | { "MODE_ID", videomode->id() }, | ||
72 | }); | ||
73 | |||
74 | add(primary, { | ||
75 | { "FB_ID", fb->id() }, | ||
76 | { "CRTC_ID", crtc->id() }, | ||
77 | { "SRC_X", 0 << 16 }, | ||
78 | { "SRC_Y", 0 << 16 }, | ||
79 | { "SRC_W", fb->width() << 16 }, | ||
80 | { "SRC_H", fb->height() << 16 }, | ||
81 | { "CRTC_X", 0 }, | ||
82 | { "CRTC_Y", 0 }, | ||
83 | { "CRTC_W", fb->width() }, | ||
84 | { "CRTC_H", fb->height() }, | ||
85 | }); | ||
86 | } | ||
87 | |||
88 | int AtomicReq::test(bool allow_modeset) | ||
89 | { | ||
90 | uint32_t flags = DRM_MODE_ATOMIC_TEST_ONLY; | ||
91 | |||
92 | if (allow_modeset) | ||
93 | flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; | ||
94 | |||
95 | return drmModeAtomicCommit(m_card.fd(), m_req, flags, 0); | ||
96 | } | ||
97 | |||
98 | int AtomicReq::commit(void* data, bool allow_modeset) | ||
99 | { | ||
100 | uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK; | ||
101 | |||
102 | if (allow_modeset) | ||
103 | flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; | ||
104 | |||
105 | return drmModeAtomicCommit(m_card.fd(), m_req, flags, data); | ||
106 | } | ||
107 | |||
108 | int AtomicReq::commit_sync(bool allow_modeset) | ||
109 | { | ||
110 | uint32_t flags = 0; | ||
111 | |||
112 | if (allow_modeset) | ||
113 | flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; | ||
114 | |||
115 | return drmModeAtomicCommit(m_card.fd(), m_req, flags, 0); | ||
116 | } | ||
117 | } | ||
diff --git a/kms++/src/blob.cpp b/kms++/src/blob.cpp new file mode 100644 index 0000000..e1cd1f8 --- /dev/null +++ b/kms++/src/blob.cpp | |||
@@ -0,0 +1,51 @@ | |||
1 | #include <xf86drm.h> | ||
2 | #include <xf86drmMode.h> | ||
3 | |||
4 | #include <kms++/kms++.h> | ||
5 | |||
6 | using namespace std; | ||
7 | |||
8 | namespace kms | ||
9 | { | ||
10 | |||
11 | Blob::Blob(Card& card, uint32_t blob_id) | ||
12 | : DrmObject(card, blob_id, DRM_MODE_OBJECT_BLOB), m_created(false) | ||
13 | { | ||
14 | // XXX should we verify that the blob_id is a blob object? | ||
15 | } | ||
16 | |||
17 | Blob::Blob(Card& card, void* data, size_t len) | ||
18 | : DrmObject(card, DRM_MODE_OBJECT_BLOB), m_created(true) | ||
19 | { | ||
20 | uint32_t id; | ||
21 | |||
22 | int r = drmModeCreatePropertyBlob(card.fd(), data, len, &id); | ||
23 | if (r) | ||
24 | throw invalid_argument("FAILED TO CREATE PROP\n"); | ||
25 | |||
26 | set_id(id); | ||
27 | } | ||
28 | |||
29 | Blob::~Blob() | ||
30 | { | ||
31 | if (m_created) | ||
32 | drmModeDestroyPropertyBlob(card().fd(), id()); | ||
33 | } | ||
34 | |||
35 | vector<uint8_t> Blob::data() | ||
36 | { | ||
37 | drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(card().fd(), id()); | ||
38 | |||
39 | if (!blob) | ||
40 | throw invalid_argument("Blob data not available"); | ||
41 | |||
42 | uint8_t* data = (uint8_t*)blob->data; | ||
43 | |||
44 | auto v = vector<uint8_t>(data, data + blob->length); | ||
45 | |||
46 | drmModeFreePropertyBlob(blob); | ||
47 | |||
48 | return v; | ||
49 | } | ||
50 | |||
51 | } | ||
diff --git a/kms++/src/card.cpp b/kms++/src/card.cpp new file mode 100644 index 0000000..f7f1a5a --- /dev/null +++ b/kms++/src/card.cpp | |||
@@ -0,0 +1,247 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <unistd.h> | ||
3 | #include <fcntl.h> | ||
4 | #include <utility> | ||
5 | #include <stdexcept> | ||
6 | #include <string.h> | ||
7 | #include <algorithm> | ||
8 | |||
9 | #include <xf86drm.h> | ||
10 | #include <xf86drmMode.h> | ||
11 | |||
12 | #include <kms++/kms++.h> | ||
13 | |||
14 | using namespace std; | ||
15 | |||
16 | namespace kms | ||
17 | { | ||
18 | |||
19 | Card::Card() | ||
20 | : Card("/dev/dri/card0") | ||
21 | { | ||
22 | } | ||
23 | |||
24 | |||
25 | Card::Card(const std::string& device) | ||
26 | { | ||
27 | int fd = open(device.c_str(), O_RDWR | O_CLOEXEC); | ||
28 | if (fd < 0) | ||
29 | throw invalid_argument(string(strerror(errno)) + " opening " + device); | ||
30 | m_fd = fd; | ||
31 | |||
32 | int r; | ||
33 | |||
34 | r = drmSetMaster(fd); | ||
35 | m_master = r == 0; | ||
36 | |||
37 | if (getenv("KMSXX_DISABLE_UNIVERSAL_PLANES") == 0) { | ||
38 | r = drmSetClientCap(m_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); | ||
39 | m_has_universal_planes = r == 0; | ||
40 | } else { | ||
41 | m_has_universal_planes = false; | ||
42 | } | ||
43 | |||
44 | #ifdef DRM_CLIENT_CAP_ATOMIC | ||
45 | if (getenv("KMSXX_DISABLE_ATOMIC") == 0) { | ||
46 | r = drmSetClientCap(m_fd, DRM_CLIENT_CAP_ATOMIC, 1); | ||
47 | m_has_atomic = r == 0; | ||
48 | } else { | ||
49 | m_has_atomic = false; | ||
50 | } | ||
51 | #else | ||
52 | m_has_atomic = false; | ||
53 | #endif | ||
54 | |||
55 | uint64_t has_dumb; | ||
56 | r = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb); | ||
57 | if (r || !has_dumb) | ||
58 | throw invalid_argument("Dumb buffers not available"); | ||
59 | |||
60 | auto res = drmModeGetResources(m_fd); | ||
61 | if (!res) | ||
62 | throw invalid_argument("Can't get card resources"); | ||
63 | |||
64 | for (int i = 0; i < res->count_connectors; ++i) { | ||
65 | uint32_t id = res->connectors[i]; | ||
66 | auto ob = new Connector(*this, id, i); | ||
67 | m_obmap[id] = ob; | ||
68 | m_connectors.push_back(ob); | ||
69 | } | ||
70 | |||
71 | for (int i = 0; i < res->count_crtcs; ++i) { | ||
72 | uint32_t id = res->crtcs[i]; | ||
73 | auto ob = new Crtc(*this, id, i); | ||
74 | m_obmap[id] = ob; | ||
75 | m_crtcs.push_back(ob); | ||
76 | } | ||
77 | |||
78 | for (int i = 0; i < res->count_encoders; ++i) { | ||
79 | uint32_t id = res->encoders[i]; | ||
80 | auto ob = new Encoder(*this, id, i); | ||
81 | m_obmap[id] = ob; | ||
82 | m_encoders.push_back(ob); | ||
83 | } | ||
84 | |||
85 | drmModeFreeResources(res); | ||
86 | |||
87 | auto planeRes = drmModeGetPlaneResources(m_fd); | ||
88 | |||
89 | for (uint i = 0; i < planeRes->count_planes; ++i) { | ||
90 | uint32_t id = planeRes->planes[i]; | ||
91 | auto ob = new Plane(*this, id, i); | ||
92 | m_obmap[id] = ob; | ||
93 | m_planes.push_back(ob); | ||
94 | } | ||
95 | |||
96 | drmModeFreePlaneResources(planeRes); | ||
97 | |||
98 | // collect all possible props | ||
99 | for (auto ob : get_objects()) { | ||
100 | auto props = drmModeObjectGetProperties(m_fd, ob->id(), ob->object_type()); | ||
101 | |||
102 | if (props == nullptr) | ||
103 | continue; | ||
104 | |||
105 | for (unsigned i = 0; i < props->count_props; ++i) { | ||
106 | uint32_t prop_id = props->props[i]; | ||
107 | |||
108 | if (m_obmap.find(prop_id) == m_obmap.end()) { | ||
109 | auto ob = new Property(*this, prop_id); | ||
110 | m_obmap[prop_id] = ob; | ||
111 | m_properties.push_back(ob); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | drmModeFreeObjectProperties(props); | ||
116 | } | ||
117 | |||
118 | for (auto pair : m_obmap) | ||
119 | pair.second->setup(); | ||
120 | } | ||
121 | |||
122 | Card::~Card() | ||
123 | { | ||
124 | restore_modes(); | ||
125 | |||
126 | while (m_framebuffers.size() > 0) | ||
127 | delete m_framebuffers.back(); | ||
128 | |||
129 | for (auto pair : m_obmap) | ||
130 | delete pair.second; | ||
131 | |||
132 | close(m_fd); | ||
133 | } | ||
134 | |||
135 | void Card::drop_master() | ||
136 | { | ||
137 | drmDropMaster(fd()); | ||
138 | } | ||
139 | |||
140 | void Card::restore_modes() | ||
141 | { | ||
142 | for (auto conn : get_connectors()) | ||
143 | conn->restore_mode(); | ||
144 | } | ||
145 | |||
146 | Connector* Card::get_first_connected_connector() const | ||
147 | { | ||
148 | for(auto c : m_connectors) { | ||
149 | if (c->connected()) | ||
150 | return c; | ||
151 | } | ||
152 | |||
153 | throw invalid_argument("no connected connectors"); | ||
154 | } | ||
155 | |||
156 | DrmObject* Card::get_object(uint32_t id) const | ||
157 | { | ||
158 | auto iter = m_obmap.find(id); | ||
159 | if (iter != m_obmap.end()) | ||
160 | return iter->second; | ||
161 | return nullptr; | ||
162 | } | ||
163 | |||
164 | const vector<DrmObject*> Card::get_objects() const | ||
165 | { | ||
166 | vector<DrmObject*> v; | ||
167 | for(auto pair : m_obmap) | ||
168 | v.push_back(pair.second); | ||
169 | return v; | ||
170 | } | ||
171 | |||
172 | Connector* Card::get_connector(uint32_t id) const { return dynamic_cast<Connector*>(get_object(id)); } | ||
173 | Crtc* Card::get_crtc(uint32_t id) const { return dynamic_cast<Crtc*>(get_object(id)); } | ||
174 | Encoder* Card::get_encoder(uint32_t id) const { return dynamic_cast<Encoder*>(get_object(id)); } | ||
175 | Property* Card::get_prop(uint32_t id) const { return dynamic_cast<Property*>(get_object(id)); } | ||
176 | Plane* Card::get_plane(uint32_t id) const { return dynamic_cast<Plane*>(get_object(id)); } | ||
177 | |||
178 | std::vector<kms::Pipeline> Card::get_connected_pipelines() | ||
179 | { | ||
180 | vector<Pipeline> outputs; | ||
181 | |||
182 | for (auto conn : get_connectors()) | ||
183 | { | ||
184 | if (conn->connected() == false) | ||
185 | continue; | ||
186 | |||
187 | Crtc* crtc = conn->get_current_crtc(); | ||
188 | |||
189 | if (!crtc) { | ||
190 | for (auto possible : conn->get_possible_crtcs()) { | ||
191 | if (find_if(outputs.begin(), outputs.end(), [possible](Pipeline out) { return out.crtc == possible; }) == outputs.end()) { | ||
192 | crtc = possible; | ||
193 | break; | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | |||
198 | if (!crtc) | ||
199 | throw invalid_argument(string("Connector #") + | ||
200 | to_string(conn->idx()) + | ||
201 | " has no possible crtcs"); | ||
202 | |||
203 | outputs.push_back(Pipeline { crtc, conn }); | ||
204 | } | ||
205 | |||
206 | return outputs; | ||
207 | } | ||
208 | |||
209 | static void page_flip_handler(int fd, unsigned int frame, | ||
210 | unsigned int sec, unsigned int usec, | ||
211 | void *data) | ||
212 | { | ||
213 | auto handler = (PageFlipHandlerBase*)data; | ||
214 | double time = sec + usec / 1000000.0; | ||
215 | handler->handle_page_flip(frame, time); | ||
216 | } | ||
217 | |||
218 | void Card::call_page_flip_handlers() | ||
219 | { | ||
220 | drmEventContext ev { }; | ||
221 | ev.version = DRM_EVENT_CONTEXT_VERSION; | ||
222 | ev.page_flip_handler = page_flip_handler; | ||
223 | |||
224 | drmHandleEvent(fd(), &ev); | ||
225 | } | ||
226 | |||
227 | int Card::disable_all() | ||
228 | { | ||
229 | AtomicReq req(*this); | ||
230 | |||
231 | for (Crtc* c : m_crtcs) { | ||
232 | req.add(c, { | ||
233 | { "ACTIVE", 0 }, | ||
234 | }); | ||
235 | } | ||
236 | |||
237 | for (Plane* p : m_planes) { | ||
238 | req.add(p, { | ||
239 | { "FB_ID", 0 }, | ||
240 | { "CRTC_ID", 0 }, | ||
241 | }); | ||
242 | } | ||
243 | |||
244 | return req.commit_sync(true); | ||
245 | } | ||
246 | |||
247 | } | ||
diff --git a/kms++/src/connector.cpp b/kms++/src/connector.cpp new file mode 100644 index 0000000..47759be --- /dev/null +++ b/kms++/src/connector.cpp | |||
@@ -0,0 +1,273 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <iostream> | ||
3 | #include <unistd.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <cassert> | ||
6 | #include <cmath> | ||
7 | |||
8 | #include <kms++/kms++.h> | ||
9 | #include "helpers.h" | ||
10 | |||
11 | using namespace std; | ||
12 | |||
13 | namespace kms | ||
14 | { | ||
15 | |||
16 | #ifndef DRM_MODE_CONNECTOR_DPI | ||
17 | #define DRM_MODE_CONNECTOR_DPI 17 | ||
18 | #endif | ||
19 | |||
20 | static const map<int, string> connector_names = { | ||
21 | { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, | ||
22 | { DRM_MODE_CONNECTOR_VGA, "VGA" }, | ||
23 | { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, | ||
24 | { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, | ||
25 | { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, | ||
26 | { DRM_MODE_CONNECTOR_Composite, "Composite" }, | ||
27 | { DRM_MODE_CONNECTOR_SVIDEO, "S-Video" }, | ||
28 | { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, | ||
29 | { DRM_MODE_CONNECTOR_Component, "Component" }, | ||
30 | { DRM_MODE_CONNECTOR_9PinDIN, "9-Pin-DIN" }, | ||
31 | { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, | ||
32 | { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, | ||
33 | { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, | ||
34 | { DRM_MODE_CONNECTOR_TV, "TV" }, | ||
35 | { DRM_MODE_CONNECTOR_eDP, "eDP" }, | ||
36 | { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, | ||
37 | { DRM_MODE_CONNECTOR_DSI, "DSI" }, | ||
38 | { DRM_MODE_CONNECTOR_DPI, "DPI" }, | ||
39 | }; | ||
40 | |||
41 | static const map<int, string> connection_str = { | ||
42 | { 0, "<unknown>" }, | ||
43 | { DRM_MODE_CONNECTED, "Connected" }, | ||
44 | { DRM_MODE_DISCONNECTED, "Disconnected" }, | ||
45 | { DRM_MODE_UNKNOWNCONNECTION, "Unknown" }, | ||
46 | }; | ||
47 | |||
48 | static const map<int, string> subpix_str = { | ||
49 | #define DEF_SUBPIX(c) { DRM_MODE_SUBPIXEL_##c, #c } | ||
50 | DEF_SUBPIX(UNKNOWN), | ||
51 | DEF_SUBPIX(HORIZONTAL_RGB), | ||
52 | DEF_SUBPIX(HORIZONTAL_BGR), | ||
53 | DEF_SUBPIX(VERTICAL_RGB), | ||
54 | DEF_SUBPIX(VERTICAL_BGR), | ||
55 | DEF_SUBPIX(NONE), | ||
56 | #undef DEF_SUBPIX | ||
57 | }; | ||
58 | |||
59 | struct ConnectorPriv | ||
60 | { | ||
61 | drmModeConnectorPtr drm_connector; | ||
62 | }; | ||
63 | |||
64 | Connector::Connector(Card &card, uint32_t id, uint32_t idx) | ||
65 | :DrmPropObject(card, id, DRM_MODE_OBJECT_CONNECTOR, idx) | ||
66 | { | ||
67 | m_priv = new ConnectorPriv(); | ||
68 | |||
69 | m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id()); | ||
70 | assert(m_priv->drm_connector); | ||
71 | |||
72 | // XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id. | ||
73 | // XXX So refresh the props again here. | ||
74 | refresh_props(); | ||
75 | |||
76 | const auto& name = connector_names.at(m_priv->drm_connector->connector_type); | ||
77 | m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id); | ||
78 | } | ||
79 | |||
80 | Connector::~Connector() | ||
81 | { | ||
82 | drmModeFreeConnector(m_priv->drm_connector); | ||
83 | delete m_priv; | ||
84 | } | ||
85 | |||
86 | void Connector::refresh() | ||
87 | { | ||
88 | drmModeFreeConnector(m_priv->drm_connector); | ||
89 | |||
90 | m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id()); | ||
91 | assert(m_priv->drm_connector); | ||
92 | |||
93 | // XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id. | ||
94 | // XXX So refresh the props again here. | ||
95 | refresh_props(); | ||
96 | |||
97 | const auto& name = connector_names.at(m_priv->drm_connector->connector_type); | ||
98 | m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id); | ||
99 | } | ||
100 | |||
101 | void Connector::setup() | ||
102 | { | ||
103 | if (m_priv->drm_connector->encoder_id != 0) | ||
104 | m_current_encoder = card().get_encoder(m_priv->drm_connector->encoder_id); | ||
105 | else | ||
106 | m_current_encoder = 0; | ||
107 | |||
108 | if (m_current_encoder) | ||
109 | m_saved_crtc = m_current_encoder->get_crtc(); | ||
110 | else | ||
111 | m_saved_crtc = 0; | ||
112 | } | ||
113 | |||
114 | void Connector::restore_mode() | ||
115 | { | ||
116 | if (m_saved_crtc) | ||
117 | m_saved_crtc->restore_mode(this); | ||
118 | } | ||
119 | |||
120 | Videomode Connector::get_default_mode() const | ||
121 | { | ||
122 | if (m_priv->drm_connector->count_modes == 0) | ||
123 | throw invalid_argument("no modes available\n"); | ||
124 | drmModeModeInfo drmmode = m_priv->drm_connector->modes[0]; | ||
125 | |||
126 | return drm_mode_to_video_mode(drmmode); | ||
127 | } | ||
128 | |||
129 | Videomode Connector::get_mode(const string& mode) const | ||
130 | { | ||
131 | auto c = m_priv->drm_connector; | ||
132 | |||
133 | size_t idx = mode.find('@'); | ||
134 | |||
135 | string name = idx == string::npos ? mode : mode.substr(0, idx); | ||
136 | float vrefresh = idx == string::npos ? 0.0 : stod(mode.substr(idx + 1)); | ||
137 | |||
138 | for (int i = 0; i < c->count_modes; i++) { | ||
139 | Videomode m = drm_mode_to_video_mode(c->modes[i]); | ||
140 | |||
141 | if (m.name != name) | ||
142 | continue; | ||
143 | |||
144 | if (vrefresh && vrefresh != m.calculated_vrefresh()) | ||
145 | continue; | ||
146 | |||
147 | return m; | ||
148 | } | ||
149 | |||
150 | throw invalid_argument(mode + ": mode not found"); | ||
151 | } | ||
152 | |||
153 | Videomode Connector::get_mode(unsigned xres, unsigned yres, float vrefresh, bool ilace) const | ||
154 | { | ||
155 | auto c = m_priv->drm_connector; | ||
156 | |||
157 | for (int i = 0; i < c->count_modes; i++) { | ||
158 | Videomode m = drm_mode_to_video_mode(c->modes[i]); | ||
159 | |||
160 | if (m.hdisplay != xres || m.vdisplay != yres) | ||
161 | continue; | ||
162 | |||
163 | if (ilace != m.interlace()) | ||
164 | continue; | ||
165 | |||
166 | if (vrefresh && vrefresh != m.calculated_vrefresh()) | ||
167 | continue; | ||
168 | |||
169 | return m; | ||
170 | } | ||
171 | |||
172 | // If not found, do another round using rounded vrefresh | ||
173 | |||
174 | for (int i = 0; i < c->count_modes; i++) { | ||
175 | Videomode m = drm_mode_to_video_mode(c->modes[i]); | ||
176 | |||
177 | if (m.hdisplay != xres || m.vdisplay != yres) | ||
178 | continue; | ||
179 | |||
180 | if (ilace != m.interlace()) | ||
181 | continue; | ||
182 | |||
183 | if (vrefresh && vrefresh != roundf(m.calculated_vrefresh())) | ||
184 | continue; | ||
185 | |||
186 | return m; | ||
187 | } | ||
188 | |||
189 | throw invalid_argument("mode not found"); | ||
190 | } | ||
191 | |||
192 | bool Connector::connected() const | ||
193 | { | ||
194 | return m_priv->drm_connector->connection == DRM_MODE_CONNECTED || | ||
195 | m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION; | ||
196 | } | ||
197 | |||
198 | vector<Crtc*> Connector::get_possible_crtcs() const | ||
199 | { | ||
200 | vector<Crtc*> crtcs; | ||
201 | |||
202 | for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) { | ||
203 | auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]); | ||
204 | |||
205 | auto l = enc->get_possible_crtcs(); | ||
206 | |||
207 | crtcs.insert(crtcs.end(), l.begin(), l.end()); | ||
208 | } | ||
209 | |||
210 | return crtcs; | ||
211 | } | ||
212 | |||
213 | Crtc* Connector::get_current_crtc() const | ||
214 | { | ||
215 | if (m_current_encoder) | ||
216 | return m_current_encoder->get_crtc(); | ||
217 | else | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | uint32_t Connector::connector_type() const | ||
222 | { | ||
223 | return m_priv->drm_connector->connector_type; | ||
224 | } | ||
225 | |||
226 | uint32_t Connector::connector_type_id() const | ||
227 | { | ||
228 | return m_priv->drm_connector->connector_type_id; | ||
229 | } | ||
230 | |||
231 | uint32_t Connector::mmWidth() const | ||
232 | { | ||
233 | return m_priv->drm_connector->mmWidth; | ||
234 | } | ||
235 | |||
236 | uint32_t Connector::mmHeight() const | ||
237 | { | ||
238 | return m_priv->drm_connector->mmHeight; | ||
239 | } | ||
240 | |||
241 | uint32_t Connector::subpixel() const | ||
242 | { | ||
243 | return m_priv->drm_connector->subpixel; | ||
244 | } | ||
245 | |||
246 | const string& Connector::subpixel_str() const | ||
247 | { | ||
248 | return subpix_str.at(subpixel()); | ||
249 | } | ||
250 | |||
251 | std::vector<Videomode> Connector::get_modes() const | ||
252 | { | ||
253 | vector<Videomode> modes; | ||
254 | |||
255 | for (int i = 0; i < m_priv->drm_connector->count_modes; i++) | ||
256 | modes.push_back(drm_mode_to_video_mode( | ||
257 | m_priv->drm_connector->modes[i])); | ||
258 | |||
259 | return modes; | ||
260 | } | ||
261 | |||
262 | std::vector<Encoder*> Connector::get_encoders() const | ||
263 | { | ||
264 | vector<Encoder*> encoders; | ||
265 | |||
266 | for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) { | ||
267 | auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]); | ||
268 | encoders.push_back(enc); | ||
269 | } | ||
270 | return encoders; | ||
271 | } | ||
272 | |||
273 | } | ||
diff --git a/kms++/src/crtc.cpp b/kms++/src/crtc.cpp new file mode 100644 index 0000000..f94216f --- /dev/null +++ b/kms++/src/crtc.cpp | |||
@@ -0,0 +1,183 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <iostream> | ||
3 | #include <unistd.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <cassert> | ||
6 | |||
7 | #include <kms++/kms++.h> | ||
8 | #include "helpers.h" | ||
9 | |||
10 | using namespace std; | ||
11 | |||
12 | namespace kms | ||
13 | { | ||
14 | |||
15 | struct CrtcPriv | ||
16 | { | ||
17 | drmModeCrtcPtr drm_crtc; | ||
18 | }; | ||
19 | |||
20 | Crtc::Crtc(Card &card, uint32_t id, uint32_t idx) | ||
21 | :DrmPropObject(card, id, DRM_MODE_OBJECT_CRTC, idx) | ||
22 | { | ||
23 | m_priv = new CrtcPriv(); | ||
24 | m_priv->drm_crtc = drmModeGetCrtc(this->card().fd(), this->id()); | ||
25 | assert(m_priv->drm_crtc); | ||
26 | } | ||
27 | |||
28 | Crtc::~Crtc() | ||
29 | { | ||
30 | drmModeFreeCrtc(m_priv->drm_crtc); | ||
31 | delete m_priv; | ||
32 | } | ||
33 | |||
34 | void Crtc::refresh() | ||
35 | { | ||
36 | drmModeFreeCrtc(m_priv->drm_crtc); | ||
37 | |||
38 | m_priv->drm_crtc = drmModeGetCrtc(this->card().fd(), this->id()); | ||
39 | assert(m_priv->drm_crtc); | ||
40 | } | ||
41 | |||
42 | void Crtc::setup() | ||
43 | { | ||
44 | for (Plane* plane : card().get_planes()) { | ||
45 | if (plane->supports_crtc(this)) | ||
46 | m_possible_planes.push_back(plane); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | void Crtc::restore_mode(Connector* conn) | ||
51 | { | ||
52 | auto c = m_priv->drm_crtc; | ||
53 | |||
54 | uint32_t conns[] = { conn->id() }; | ||
55 | |||
56 | drmModeSetCrtc(card().fd(), id(), c->buffer_id, | ||
57 | c->x, c->y, | ||
58 | conns, 1, &c->mode); | ||
59 | } | ||
60 | |||
61 | int Crtc::set_mode(Connector* conn, const Videomode& mode) | ||
62 | { | ||
63 | AtomicReq req(card()); | ||
64 | |||
65 | unique_ptr<Blob> blob = mode.to_blob(card()); | ||
66 | |||
67 | req.add(conn, { | ||
68 | { "CRTC_ID", this->id() }, | ||
69 | }); | ||
70 | |||
71 | req.add(this, { | ||
72 | { "ACTIVE", 1 }, | ||
73 | { "MODE_ID", blob->id() }, | ||
74 | }); | ||
75 | |||
76 | int r = req.commit_sync(true); | ||
77 | |||
78 | refresh(); | ||
79 | |||
80 | return r; | ||
81 | } | ||
82 | |||
83 | int Crtc::set_mode(Connector* conn, Framebuffer& fb, const Videomode& mode) | ||
84 | { | ||
85 | uint32_t conns[] = { conn->id() }; | ||
86 | drmModeModeInfo drmmode = video_mode_to_drm_mode(mode); | ||
87 | |||
88 | return drmModeSetCrtc(card().fd(), id(), fb.id(), | ||
89 | 0, 0, | ||
90 | conns, 1, &drmmode); | ||
91 | } | ||
92 | |||
93 | int Crtc::disable_mode() | ||
94 | { | ||
95 | return drmModeSetCrtc(card().fd(), id(), 0, 0, 0, 0, 0, 0); | ||
96 | } | ||
97 | |||
98 | static inline uint32_t conv(float x) | ||
99 | { | ||
100 | // XXX fix the conversion for fractional part | ||
101 | return ((uint32_t)x) << 16; | ||
102 | } | ||
103 | |||
104 | int Crtc::set_plane(Plane* plane, Framebuffer& fb, | ||
105 | int32_t dst_x, int32_t dst_y, uint32_t dst_w, uint32_t dst_h, | ||
106 | float src_x, float src_y, float src_w, float src_h) | ||
107 | { | ||
108 | return drmModeSetPlane(card().fd(), plane->id(), id(), fb.id(), 0, | ||
109 | dst_x, dst_y, dst_w, dst_h, | ||
110 | conv(src_x), conv(src_y), conv(src_w), conv(src_h)); | ||
111 | } | ||
112 | |||
113 | int Crtc::disable_plane(Plane* plane) | ||
114 | { | ||
115 | return drmModeSetPlane(card().fd(), plane->id(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); | ||
116 | } | ||
117 | |||
118 | Plane* Crtc::get_primary_plane() | ||
119 | { | ||
120 | Plane *primary = nullptr; | ||
121 | |||
122 | for (Plane* p : get_possible_planes()) { | ||
123 | if (p->plane_type() != PlaneType::Primary) | ||
124 | continue; | ||
125 | |||
126 | if (p->crtc_id() == id()) | ||
127 | return p; | ||
128 | |||
129 | primary = p; | ||
130 | } | ||
131 | |||
132 | if (primary) | ||
133 | return primary; | ||
134 | |||
135 | throw invalid_argument(string("No primary plane for crtc ") + to_string(id())); | ||
136 | } | ||
137 | |||
138 | int Crtc::page_flip(Framebuffer& fb, void *data) | ||
139 | { | ||
140 | return drmModePageFlip(card().fd(), id(), fb.id(), DRM_MODE_PAGE_FLIP_EVENT, data); | ||
141 | } | ||
142 | |||
143 | uint32_t Crtc::buffer_id() const | ||
144 | { | ||
145 | return m_priv->drm_crtc->buffer_id; | ||
146 | } | ||
147 | |||
148 | uint32_t Crtc::x() const | ||
149 | { | ||
150 | return m_priv->drm_crtc->x; | ||
151 | } | ||
152 | |||
153 | uint32_t Crtc::y() const | ||
154 | { | ||
155 | return m_priv->drm_crtc->y; | ||
156 | } | ||
157 | |||
158 | uint32_t Crtc::width() const | ||
159 | { | ||
160 | return m_priv->drm_crtc->width; | ||
161 | } | ||
162 | |||
163 | uint32_t Crtc::height() const | ||
164 | { | ||
165 | return m_priv->drm_crtc->height; | ||
166 | } | ||
167 | |||
168 | int Crtc::mode_valid() const | ||
169 | { | ||
170 | return m_priv->drm_crtc->mode_valid; | ||
171 | } | ||
172 | |||
173 | Videomode Crtc::mode() const | ||
174 | { | ||
175 | return drm_mode_to_video_mode(m_priv->drm_crtc->mode); | ||
176 | } | ||
177 | |||
178 | int Crtc::gamma_size() const | ||
179 | { | ||
180 | return m_priv->drm_crtc->gamma_size; | ||
181 | } | ||
182 | |||
183 | } | ||
diff --git a/kms++/src/drmobject.cpp b/kms++/src/drmobject.cpp new file mode 100644 index 0000000..f94fc5d --- /dev/null +++ b/kms++/src/drmobject.cpp | |||
@@ -0,0 +1,34 @@ | |||
1 | #include <string.h> | ||
2 | #include <iostream> | ||
3 | #include <stdexcept> | ||
4 | |||
5 | #include <xf86drm.h> | ||
6 | #include <xf86drmMode.h> | ||
7 | |||
8 | #include <kms++/kms++.h> | ||
9 | |||
10 | using namespace std; | ||
11 | |||
12 | namespace kms | ||
13 | { | ||
14 | |||
15 | DrmObject::DrmObject(Card& card, uint32_t object_type) | ||
16 | :m_card(card), m_id(-1), m_object_type(object_type), m_idx(0) | ||
17 | { | ||
18 | } | ||
19 | |||
20 | DrmObject::DrmObject(Card& card, uint32_t id, uint32_t object_type, uint32_t idx) | ||
21 | :m_card(card), m_id(id), m_object_type(object_type), m_idx(idx) | ||
22 | { | ||
23 | } | ||
24 | |||
25 | DrmObject::~DrmObject() | ||
26 | { | ||
27 | |||
28 | } | ||
29 | |||
30 | void DrmObject::set_id(uint32_t id) | ||
31 | { | ||
32 | m_id = id; | ||
33 | } | ||
34 | } | ||
diff --git a/kms++/src/drmpropobject.cpp b/kms++/src/drmpropobject.cpp new file mode 100644 index 0000000..f5a3c97 --- /dev/null +++ b/kms++/src/drmpropobject.cpp | |||
@@ -0,0 +1,98 @@ | |||
1 | #include <string.h> | ||
2 | #include <iostream> | ||
3 | #include <stdexcept> | ||
4 | |||
5 | #include <xf86drm.h> | ||
6 | #include <xf86drmMode.h> | ||
7 | |||
8 | #include <kms++/kms++.h> | ||
9 | |||
10 | using namespace std; | ||
11 | |||
12 | namespace kms | ||
13 | { | ||
14 | |||
15 | DrmPropObject::DrmPropObject(Card& card, uint32_t object_type) | ||
16 | : DrmObject(card, object_type) | ||
17 | { | ||
18 | } | ||
19 | |||
20 | DrmPropObject::DrmPropObject(Card& card, uint32_t id, uint32_t object_type, uint32_t idx) | ||
21 | : DrmObject(card, id, object_type, idx) | ||
22 | { | ||
23 | refresh_props(); | ||
24 | } | ||
25 | |||
26 | DrmPropObject::~DrmPropObject() | ||
27 | { | ||
28 | |||
29 | } | ||
30 | |||
31 | void DrmPropObject::refresh_props() | ||
32 | { | ||
33 | auto props = drmModeObjectGetProperties(card().fd(), this->id(), this->object_type()); | ||
34 | |||
35 | if (props == nullptr) | ||
36 | return; | ||
37 | |||
38 | for (unsigned i = 0; i < props->count_props; ++i) { | ||
39 | uint32_t prop_id = props->props[i]; | ||
40 | uint64_t prop_value = props->prop_values[i]; | ||
41 | |||
42 | m_prop_values[prop_id] = prop_value; | ||
43 | } | ||
44 | |||
45 | drmModeFreeObjectProperties(props); | ||
46 | } | ||
47 | |||
48 | Property* DrmPropObject::get_prop(const string& name) const | ||
49 | { | ||
50 | for (auto pair : m_prop_values) { | ||
51 | auto prop = card().get_prop(pair.first); | ||
52 | |||
53 | if (name == prop->name()) | ||
54 | return prop; | ||
55 | } | ||
56 | |||
57 | throw invalid_argument(string("property ") + name + " not found"); | ||
58 | } | ||
59 | |||
60 | uint64_t DrmPropObject::get_prop_value(uint32_t id) const | ||
61 | { | ||
62 | return m_prop_values.at(id); | ||
63 | } | ||
64 | |||
65 | uint64_t DrmPropObject::get_prop_value(const string& name) const | ||
66 | { | ||
67 | for (auto pair : m_prop_values) { | ||
68 | auto prop = card().get_prop(pair.first); | ||
69 | if (name == prop->name()) | ||
70 | return m_prop_values.at(prop->id()); | ||
71 | } | ||
72 | |||
73 | throw invalid_argument("property not found: " + name); | ||
74 | } | ||
75 | |||
76 | unique_ptr<Blob> DrmPropObject::get_prop_value_as_blob(const string& name) const | ||
77 | { | ||
78 | uint32_t blob_id = (uint32_t)get_prop_value(name); | ||
79 | |||
80 | return unique_ptr<Blob>(new Blob(card(), blob_id)); | ||
81 | } | ||
82 | |||
83 | int DrmPropObject::set_prop_value(uint32_t id, uint64_t value) | ||
84 | { | ||
85 | return drmModeObjectSetProperty(card().fd(), this->id(), this->object_type(), id, value); | ||
86 | } | ||
87 | |||
88 | int DrmPropObject::set_prop_value(const string &name, uint64_t value) | ||
89 | { | ||
90 | Property* prop = get_prop(name); | ||
91 | |||
92 | if (prop == nullptr) | ||
93 | throw invalid_argument("property not found: " + name); | ||
94 | |||
95 | return set_prop_value(prop->id(), value); | ||
96 | } | ||
97 | |||
98 | } | ||
diff --git a/kms++/src/dumbframebuffer.cpp b/kms++/src/dumbframebuffer.cpp new file mode 100644 index 0000000..b21e8ff --- /dev/null +++ b/kms++/src/dumbframebuffer.cpp | |||
@@ -0,0 +1,137 @@ | |||
1 | |||
2 | #include <cstring> | ||
3 | #include <stdexcept> | ||
4 | #include <sys/mman.h> | ||
5 | #include <xf86drm.h> | ||
6 | #include <xf86drmMode.h> | ||
7 | #include <fcntl.h> | ||
8 | #include <unistd.h> | ||
9 | #include <drm_fourcc.h> | ||
10 | #include <drm.h> | ||
11 | #include <drm_mode.h> | ||
12 | |||
13 | #include <kms++/kms++.h> | ||
14 | |||
15 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
16 | |||
17 | using namespace std; | ||
18 | |||
19 | namespace kms | ||
20 | { | ||
21 | |||
22 | DumbFramebuffer::DumbFramebuffer(Card &card, uint32_t width, uint32_t height, const string& fourcc) | ||
23 | :DumbFramebuffer(card, width, height, FourCCToPixelFormat(fourcc)) | ||
24 | { | ||
25 | } | ||
26 | |||
27 | DumbFramebuffer::DumbFramebuffer(Card& card, uint32_t width, uint32_t height, PixelFormat format) | ||
28 | :Framebuffer(card, width, height), m_format(format) | ||
29 | { | ||
30 | Create(); | ||
31 | } | ||
32 | |||
33 | DumbFramebuffer::~DumbFramebuffer() | ||
34 | { | ||
35 | Destroy(); | ||
36 | } | ||
37 | |||
38 | void DumbFramebuffer::Create() | ||
39 | { | ||
40 | int r; | ||
41 | |||
42 | const PixelFormatInfo& format_info = get_pixel_format_info(m_format); | ||
43 | |||
44 | m_num_planes = format_info.num_planes; | ||
45 | |||
46 | for (int i = 0; i < format_info.num_planes; ++i) { | ||
47 | const PixelFormatPlaneInfo& pi = format_info.planes[i]; | ||
48 | FramebufferPlane& plane = m_planes[i]; | ||
49 | |||
50 | /* create dumb buffer */ | ||
51 | struct drm_mode_create_dumb creq = drm_mode_create_dumb(); | ||
52 | creq.width = width(); | ||
53 | creq.height = height() / pi.ysub; | ||
54 | creq.bpp = pi.bitspp; | ||
55 | r = drmIoctl(card().fd(), DRM_IOCTL_MODE_CREATE_DUMB, &creq); | ||
56 | if (r) | ||
57 | throw invalid_argument(string("DRM_IOCTL_MODE_CREATE_DUMB failed: ") + strerror(errno)); | ||
58 | |||
59 | plane.handle = creq.handle; | ||
60 | plane.stride = creq.pitch; | ||
61 | plane.size = creq.height * creq.pitch; | ||
62 | plane.offset = 0; | ||
63 | plane.map = 0; | ||
64 | plane.prime_fd = -1; | ||
65 | } | ||
66 | |||
67 | /* create framebuffer object for the dumb-buffer */ | ||
68 | uint32_t bo_handles[4] = { m_planes[0].handle, m_planes[1].handle }; | ||
69 | uint32_t pitches[4] = { m_planes[0].stride, m_planes[1].stride }; | ||
70 | uint32_t offsets[4] = { m_planes[0].offset, m_planes[1].offset }; | ||
71 | uint32_t id; | ||
72 | r = drmModeAddFB2(card().fd(), width(), height(), (uint32_t)format(), | ||
73 | bo_handles, pitches, offsets, &id, 0); | ||
74 | if (r) | ||
75 | throw invalid_argument(string("drmModeAddFB2 failed: ") + strerror(errno)); | ||
76 | |||
77 | set_id(id); | ||
78 | } | ||
79 | |||
80 | void DumbFramebuffer::Destroy() | ||
81 | { | ||
82 | /* delete framebuffer */ | ||
83 | drmModeRmFB(card().fd(), id()); | ||
84 | |||
85 | for (uint i = 0; i < m_num_planes; ++i) { | ||
86 | FramebufferPlane& plane = m_planes[i]; | ||
87 | |||
88 | /* unmap buffer */ | ||
89 | if (plane.map) | ||
90 | munmap(plane.map, plane.size); | ||
91 | |||
92 | /* delete dumb buffer */ | ||
93 | struct drm_mode_destroy_dumb dreq = drm_mode_destroy_dumb(); | ||
94 | dreq.handle = plane.handle; | ||
95 | drmIoctl(card().fd(), DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); | ||
96 | if (plane.prime_fd >= 0) | ||
97 | ::close(plane.prime_fd); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | uint8_t* DumbFramebuffer::map(unsigned plane) | ||
102 | { | ||
103 | FramebufferPlane& p = m_planes[plane]; | ||
104 | |||
105 | if (p.map) | ||
106 | return p.map; | ||
107 | |||
108 | /* prepare buffer for memory mapping */ | ||
109 | struct drm_mode_map_dumb mreq = drm_mode_map_dumb(); | ||
110 | mreq.handle = p.handle; | ||
111 | int r = drmIoctl(card().fd(), DRM_IOCTL_MODE_MAP_DUMB, &mreq); | ||
112 | if (r) | ||
113 | throw invalid_argument(string("DRM_IOCTL_MODE_MAP_DUMB failed: ") + strerror(errno)); | ||
114 | |||
115 | /* perform actual memory mapping */ | ||
116 | p.map = (uint8_t *)mmap(0, p.size, PROT_READ | PROT_WRITE, MAP_SHARED, | ||
117 | card().fd(), mreq.offset); | ||
118 | if (p.map == MAP_FAILED) | ||
119 | throw invalid_argument(string("mmap failed: ") + strerror(errno)); | ||
120 | |||
121 | return p.map; | ||
122 | } | ||
123 | |||
124 | int DumbFramebuffer::prime_fd(unsigned int plane) | ||
125 | { | ||
126 | if (m_planes[plane].prime_fd >= 0) | ||
127 | return m_planes[plane].prime_fd; | ||
128 | |||
129 | int r = drmPrimeHandleToFD(card().fd(), m_planes[plane].handle, | ||
130 | DRM_CLOEXEC | O_RDWR, &m_planes[plane].prime_fd); | ||
131 | if (r) | ||
132 | throw std::runtime_error("drmPrimeHandleToFD failed"); | ||
133 | |||
134 | return m_planes[plane].prime_fd; | ||
135 | } | ||
136 | |||
137 | } | ||
diff --git a/kms++/src/encoder.cpp b/kms++/src/encoder.cpp new file mode 100644 index 0000000..9cd5304 --- /dev/null +++ b/kms++/src/encoder.cpp | |||
@@ -0,0 +1,85 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <iostream> | ||
3 | #include <unistd.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <cassert> | ||
6 | #include <xf86drm.h> | ||
7 | #include <xf86drmMode.h> | ||
8 | |||
9 | #include <kms++/kms++.h> | ||
10 | |||
11 | using namespace std; | ||
12 | |||
13 | namespace kms | ||
14 | { | ||
15 | |||
16 | struct EncoderPriv | ||
17 | { | ||
18 | drmModeEncoderPtr drm_encoder; | ||
19 | }; | ||
20 | |||
21 | static const map<int, string> encoder_types = { | ||
22 | #define DEF_ENC(c) { DRM_MODE_ENCODER_##c, #c } | ||
23 | DEF_ENC(NONE), | ||
24 | DEF_ENC(DAC), | ||
25 | DEF_ENC(TMDS), | ||
26 | DEF_ENC(LVDS), | ||
27 | DEF_ENC(TVDAC), | ||
28 | DEF_ENC(VIRTUAL), | ||
29 | DEF_ENC(DSI), | ||
30 | { 7, "DPMST" }, | ||
31 | #undef DEF_ENC | ||
32 | }; | ||
33 | |||
34 | Encoder::Encoder(Card &card, uint32_t id, uint32_t idx) | ||
35 | :DrmPropObject(card, id, DRM_MODE_OBJECT_ENCODER, idx) | ||
36 | { | ||
37 | m_priv = new EncoderPriv(); | ||
38 | m_priv->drm_encoder = drmModeGetEncoder(this->card().fd(), this->id()); | ||
39 | assert(m_priv->drm_encoder); | ||
40 | } | ||
41 | |||
42 | Encoder::~Encoder() | ||
43 | { | ||
44 | drmModeFreeEncoder(m_priv->drm_encoder); | ||
45 | delete m_priv; | ||
46 | } | ||
47 | |||
48 | void Encoder::refresh() | ||
49 | { | ||
50 | drmModeFreeEncoder(m_priv->drm_encoder); | ||
51 | |||
52 | m_priv->drm_encoder = drmModeGetEncoder(this->card().fd(), this->id()); | ||
53 | assert(m_priv->drm_encoder); | ||
54 | } | ||
55 | |||
56 | Crtc* Encoder::get_crtc() const | ||
57 | { | ||
58 | if (m_priv->drm_encoder->crtc_id) | ||
59 | return card().get_crtc(m_priv->drm_encoder->crtc_id); | ||
60 | else | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | vector<Crtc*> Encoder::get_possible_crtcs() const | ||
65 | { | ||
66 | unsigned bits = m_priv->drm_encoder->possible_crtcs; | ||
67 | vector<Crtc*> crtcs; | ||
68 | |||
69 | for (int idx = 0; bits; idx++, bits >>= 1) { | ||
70 | if ((bits & 1) == 0) | ||
71 | continue; | ||
72 | |||
73 | auto crtc = card().get_crtcs()[idx]; | ||
74 | crtcs.push_back(crtc); | ||
75 | } | ||
76 | |||
77 | return crtcs; | ||
78 | } | ||
79 | |||
80 | const string& Encoder::get_encoder_type() const | ||
81 | { | ||
82 | return encoder_types.at(m_priv->drm_encoder->encoder_type); | ||
83 | } | ||
84 | |||
85 | } | ||
diff --git a/kms++/src/extframebuffer.cpp b/kms++/src/extframebuffer.cpp new file mode 100644 index 0000000..c1f562e --- /dev/null +++ b/kms++/src/extframebuffer.cpp | |||
@@ -0,0 +1,115 @@ | |||
1 | |||
2 | #include <cstring> | ||
3 | #include <stdexcept> | ||
4 | #include <sys/mman.h> | ||
5 | #include <xf86drm.h> | ||
6 | #include <xf86drmMode.h> | ||
7 | |||
8 | #include <kms++/kms++.h> | ||
9 | |||
10 | using namespace std; | ||
11 | |||
12 | namespace kms | ||
13 | { | ||
14 | |||
15 | ExtFramebuffer::ExtFramebuffer(Card& card, uint32_t width, uint32_t height, PixelFormat format, | ||
16 | vector<uint32_t> handles, vector<uint32_t> pitches, vector<uint32_t> offsets) | ||
17 | : Framebuffer(card, width, height) | ||
18 | { | ||
19 | m_format = format; | ||
20 | |||
21 | const PixelFormatInfo& format_info = get_pixel_format_info(format); | ||
22 | |||
23 | m_num_planes = format_info.num_planes; | ||
24 | |||
25 | for (int i = 0; i < format_info.num_planes; ++i) { | ||
26 | FramebufferPlane& plane = m_planes[i]; | ||
27 | |||
28 | plane.handle = handles[i]; | ||
29 | plane.prime_fd = 0; | ||
30 | |||
31 | plane.stride = pitches[i]; | ||
32 | plane.offset = offsets[i]; | ||
33 | plane.size = plane.stride * height; | ||
34 | plane.map = 0; | ||
35 | } | ||
36 | |||
37 | uint32_t id; | ||
38 | int r = drmModeAddFB2(card.fd(), width, height, (uint32_t)format, handles.data(), pitches.data(), offsets.data(), &id, 0); | ||
39 | if (r) | ||
40 | throw std::invalid_argument(string("Failed to create ExtFramebuffer: ") + strerror(r)); | ||
41 | |||
42 | set_id(id); | ||
43 | } | ||
44 | |||
45 | ExtFramebuffer::ExtFramebuffer(Card& card, uint32_t width, uint32_t height, PixelFormat format, | ||
46 | vector<int> fds, vector<uint32_t> pitches, vector<uint32_t> offsets) | ||
47 | : Framebuffer(card, width, height) | ||
48 | { | ||
49 | int r; | ||
50 | |||
51 | m_format = format; | ||
52 | |||
53 | const PixelFormatInfo& format_info = get_pixel_format_info(format); | ||
54 | |||
55 | m_num_planes = format_info.num_planes; | ||
56 | |||
57 | for (int i = 0; i < format_info.num_planes; ++i) { | ||
58 | FramebufferPlane& plane = m_planes[i]; | ||
59 | |||
60 | plane.prime_fd = fds[i]; | ||
61 | |||
62 | r = drmPrimeFDToHandle(card.fd(), fds[i], &plane.handle); | ||
63 | if (r) | ||
64 | throw invalid_argument(string("drmPrimeFDToHandle: ") + strerror(errno)); | ||
65 | |||
66 | plane.stride = pitches[i]; | ||
67 | plane.offset = offsets[i]; | ||
68 | plane.size = plane.stride * height; | ||
69 | plane.map = 0; | ||
70 | } | ||
71 | |||
72 | uint32_t id; | ||
73 | uint32_t bo_handles[4] = { m_planes[0].handle, m_planes[1].handle }; | ||
74 | r = drmModeAddFB2(card.fd(), width, height, (uint32_t)format, | ||
75 | bo_handles, pitches.data(), offsets.data(), &id, 0); | ||
76 | if (r) | ||
77 | throw invalid_argument(string("drmModeAddFB2 failed: ") + strerror(errno)); | ||
78 | |||
79 | set_id(id); | ||
80 | } | ||
81 | |||
82 | ExtFramebuffer::~ExtFramebuffer() | ||
83 | { | ||
84 | drmModeRmFB(card().fd(), id()); | ||
85 | } | ||
86 | |||
87 | uint8_t* ExtFramebuffer::map(unsigned plane) | ||
88 | { | ||
89 | FramebufferPlane& p = m_planes[plane]; | ||
90 | |||
91 | if (!p.prime_fd) | ||
92 | throw invalid_argument("cannot mmap non-dmabuf fb"); | ||
93 | |||
94 | if (p.map) | ||
95 | return p.map; | ||
96 | |||
97 | p.map = (uint8_t *)mmap(0, p.size, PROT_READ | PROT_WRITE, MAP_SHARED, | ||
98 | p.prime_fd, 0); | ||
99 | if (p.map == MAP_FAILED) | ||
100 | throw invalid_argument(string("mmap failed: ") + strerror(errno)); | ||
101 | |||
102 | return p.map; | ||
103 | } | ||
104 | |||
105 | int ExtFramebuffer::prime_fd(unsigned plane) | ||
106 | { | ||
107 | FramebufferPlane& p = m_planes[plane]; | ||
108 | |||
109 | if (!p.prime_fd) | ||
110 | throw invalid_argument("no primefb for non-dmabuf fb"); | ||
111 | |||
112 | return p.prime_fd; | ||
113 | } | ||
114 | |||
115 | } | ||
diff --git a/kms++/src/framebuffer.cpp b/kms++/src/framebuffer.cpp new file mode 100644 index 0000000..39c4e16 --- /dev/null +++ b/kms++/src/framebuffer.cpp | |||
@@ -0,0 +1,56 @@ | |||
1 | #include <algorithm> | ||
2 | #include <cstring> | ||
3 | #include <stdexcept> | ||
4 | #include <sys/mman.h> | ||
5 | #include <xf86drm.h> | ||
6 | #include <xf86drmMode.h> | ||
7 | |||
8 | #include <kms++/kms++.h> | ||
9 | |||
10 | using namespace std; | ||
11 | |||
12 | namespace kms | ||
13 | { | ||
14 | |||
15 | Framebuffer::Framebuffer(Card& card, uint32_t width, uint32_t height) | ||
16 | : DrmObject(card, DRM_MODE_OBJECT_FB), m_width(width), m_height(height) | ||
17 | { | ||
18 | card.m_framebuffers.push_back(this); | ||
19 | } | ||
20 | |||
21 | Framebuffer::Framebuffer(Card& card, uint32_t id) | ||
22 | : DrmObject(card, id, DRM_MODE_OBJECT_FB) | ||
23 | { | ||
24 | auto fb = drmModeGetFB(card.fd(), id); | ||
25 | |||
26 | if (fb) { | ||
27 | m_width = fb->width; | ||
28 | m_height = fb->height; | ||
29 | |||
30 | drmModeFreeFB(fb); | ||
31 | } else { | ||
32 | m_width = m_height = 0; | ||
33 | } | ||
34 | |||
35 | card.m_framebuffers.push_back(this); | ||
36 | } | ||
37 | |||
38 | void Framebuffer::flush() | ||
39 | { | ||
40 | drmModeClip clip { }; | ||
41 | clip.x1 = clip.y1 = 0; | ||
42 | clip.x2 = width(); | ||
43 | clip.y2 = height(); | ||
44 | |||
45 | drmModeDirtyFB(card().fd(), id(), &clip, 1); | ||
46 | } | ||
47 | |||
48 | Framebuffer::~Framebuffer() | ||
49 | { | ||
50 | auto& fbs = card().m_framebuffers; | ||
51 | auto iter = find(fbs.begin(), fbs.end(), this); | ||
52 | card().m_framebuffers.erase(iter); | ||
53 | } | ||
54 | |||
55 | |||
56 | } | ||
diff --git a/kms++/src/helpers.cpp b/kms++/src/helpers.cpp new file mode 100644 index 0000000..8bd082b --- /dev/null +++ b/kms++/src/helpers.cpp | |||
@@ -0,0 +1,72 @@ | |||
1 | |||
2 | #include <kms++/kms++.h> | ||
3 | #include "helpers.h" | ||
4 | #include <cstring> | ||
5 | |||
6 | #define CPY(field) dst.field = src.field | ||
7 | |||
8 | namespace kms | ||
9 | { | ||
10 | Videomode drm_mode_to_video_mode(const drmModeModeInfo& drmmode) | ||
11 | { | ||
12 | Videomode mode = { }; | ||
13 | |||
14 | auto& src = drmmode; | ||
15 | auto& dst = mode; | ||
16 | |||
17 | CPY(clock); | ||
18 | |||
19 | CPY(hdisplay); | ||
20 | CPY(hsync_start); | ||
21 | CPY(hsync_end); | ||
22 | CPY(htotal); | ||
23 | CPY(hskew); | ||
24 | |||
25 | CPY(vdisplay); | ||
26 | CPY(vsync_start); | ||
27 | CPY(vsync_end); | ||
28 | CPY(vtotal); | ||
29 | CPY(vscan); | ||
30 | |||
31 | CPY(vrefresh); | ||
32 | |||
33 | CPY(flags); | ||
34 | CPY(type); | ||
35 | |||
36 | mode.name = drmmode.name; | ||
37 | |||
38 | return mode; | ||
39 | } | ||
40 | |||
41 | drmModeModeInfo video_mode_to_drm_mode(const Videomode& mode) | ||
42 | { | ||
43 | drmModeModeInfo drmmode = { }; | ||
44 | |||
45 | auto& src = mode; | ||
46 | auto& dst = drmmode; | ||
47 | |||
48 | CPY(clock); | ||
49 | |||
50 | CPY(hdisplay); | ||
51 | CPY(hsync_start); | ||
52 | CPY(hsync_end); | ||
53 | CPY(htotal); | ||
54 | CPY(hskew); | ||
55 | |||
56 | CPY(vdisplay); | ||
57 | CPY(vsync_start); | ||
58 | CPY(vsync_end); | ||
59 | CPY(vtotal); | ||
60 | CPY(vscan); | ||
61 | |||
62 | CPY(vrefresh); | ||
63 | |||
64 | CPY(flags); | ||
65 | CPY(type); | ||
66 | |||
67 | strncpy(drmmode.name, mode.name.c_str(), sizeof(drmmode.name)); | ||
68 | drmmode.name[sizeof(drmmode.name) - 1] = 0; | ||
69 | |||
70 | return drmmode; | ||
71 | } | ||
72 | } | ||
diff --git a/kms++/src/helpers.h b/kms++/src/helpers.h new file mode 100644 index 0000000..4eb597c --- /dev/null +++ b/kms++/src/helpers.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <xf86drm.h> | ||
4 | #include <xf86drmMode.h> | ||
5 | |||
6 | namespace kms | ||
7 | { | ||
8 | struct Videomode; | ||
9 | |||
10 | Videomode drm_mode_to_video_mode(const drmModeModeInfo& drmmode); | ||
11 | drmModeModeInfo video_mode_to_drm_mode(const Videomode& mode); | ||
12 | } | ||
diff --git a/kms++/src/mode_cvt.cpp b/kms++/src/mode_cvt.cpp new file mode 100644 index 0000000..41503c7 --- /dev/null +++ b/kms++/src/mode_cvt.cpp | |||
@@ -0,0 +1,154 @@ | |||
1 | // Supports CVT 1.2 reduced blanking modes v1 and v2 | ||
2 | |||
3 | #include <kms++/kms++.h> | ||
4 | #include <cmath> | ||
5 | |||
6 | using namespace std; | ||
7 | |||
8 | namespace kms | ||
9 | { | ||
10 | |||
11 | static float CELL_GRAN = 8; | ||
12 | static float CELL_GRAN_RND = round(CELL_GRAN); | ||
13 | |||
14 | struct CVTConsts | ||
15 | { | ||
16 | float CLOCK_STEP; | ||
17 | float MIN_V_BPORCH; | ||
18 | float RB_H_BLANK; | ||
19 | float RB_H_FPORCH; | ||
20 | float RB_H_SYNC; | ||
21 | float RB_H_BPORCH; | ||
22 | float RB_MIN_V_BLANK; | ||
23 | float RB_V_FPORCH; | ||
24 | float REFRESH_MULTIPLIER; | ||
25 | }; | ||
26 | |||
27 | static const CVTConsts cvt_consts_v1 = | ||
28 | { | ||
29 | .CLOCK_STEP = 0.25, // Fixed | ||
30 | .MIN_V_BPORCH = 6, // Min | ||
31 | .RB_H_BLANK = 160, // Fixed | ||
32 | .RB_H_FPORCH = 48, // Fixed | ||
33 | .RB_H_SYNC = 32, // Fixed | ||
34 | .RB_H_BPORCH = 80, // Fixed | ||
35 | .RB_MIN_V_BLANK = 460, // Min | ||
36 | .RB_V_FPORCH = 3, // Fixed | ||
37 | .REFRESH_MULTIPLIER = 1,// Fixed | ||
38 | }; | ||
39 | |||
40 | static const CVTConsts cvt_consts_v2 = | ||
41 | { | ||
42 | .CLOCK_STEP = 0.001, // Fixed | ||
43 | .MIN_V_BPORCH = 6, // Fixed | ||
44 | .RB_H_BLANK = 80, // Fixed | ||
45 | .RB_H_FPORCH = 8, // Fixed | ||
46 | .RB_H_SYNC = 32, // Fixed | ||
47 | .RB_H_BPORCH = 40, // Fixed | ||
48 | .RB_MIN_V_BLANK = 460, // Min | ||
49 | .RB_V_FPORCH = 1, // Min | ||
50 | .REFRESH_MULTIPLIER = 1,// or 1000/1001 | ||
51 | }; | ||
52 | |||
53 | Videomode videomode_from_cvt(uint32_t hact, uint32_t vact, uint32_t refresh, bool ilace, bool reduced_v2, bool video_optimized) | ||
54 | { | ||
55 | CVTConsts c = reduced_v2 ? cvt_consts_v2 : cvt_consts_v1; | ||
56 | |||
57 | if (video_optimized) | ||
58 | c.REFRESH_MULTIPLIER = 1000.0/1001.0; | ||
59 | |||
60 | bool INT_RQD = ilace; | ||
61 | |||
62 | float H_PIXELS = hact; | ||
63 | float V_LINES = vact; | ||
64 | float IP_FREQ_RQD = refresh ? refresh : 60; | ||
65 | if (ilace) | ||
66 | IP_FREQ_RQD /= 2; | ||
67 | |||
68 | float V_SYNC_RND; | ||
69 | |||
70 | if (reduced_v2) { | ||
71 | V_SYNC_RND = 8; | ||
72 | } else { | ||
73 | if (hact * 3 == vact * 4) | ||
74 | V_SYNC_RND = 4; | ||
75 | else if (hact * 9 == vact * 16) | ||
76 | V_SYNC_RND = 5; | ||
77 | else if (hact * 10 == vact * 16) | ||
78 | V_SYNC_RND = 6; | ||
79 | else if (hact == 1280 && (vact == 1024 || vact == 768)) | ||
80 | V_SYNC_RND = 7; | ||
81 | else | ||
82 | V_SYNC_RND = 10; | ||
83 | } | ||
84 | |||
85 | // 5.2.1 | ||
86 | float V_FIELD_RATE_RQD = INT_RQD ? IP_FREQ_RQD * 2 : IP_FREQ_RQD; | ||
87 | |||
88 | // 5.2.2 | ||
89 | float H_PIXELS_RND = floor(H_PIXELS / CELL_GRAN_RND) * CELL_GRAN_RND; | ||
90 | |||
91 | // 5.2.3 | ||
92 | float LEFT_MARGIN = 0; | ||
93 | float RIGHT_MARGIN = 0; | ||
94 | |||
95 | // 5.2.4 | ||
96 | float TOTAL_ACTIVE_PIXELS = H_PIXELS_RND + LEFT_MARGIN + RIGHT_MARGIN; | ||
97 | |||
98 | // 5.2.5 | ||
99 | float V_LINES_RND = INT_RQD ? floor(V_LINES / 2) : floor(V_LINES); | ||
100 | |||
101 | // 5.2.6 | ||
102 | float TOP_MARGIN = 0; | ||
103 | float BOT_MARGIN = 0; | ||
104 | |||
105 | // 5.2.7 | ||
106 | float INTERLACE = INT_RQD ? 0.5 : 0; | ||
107 | |||
108 | // 5.4.8 | ||
109 | float H_PERIOD_EST = ((1000000 / V_FIELD_RATE_RQD) - c.RB_MIN_V_BLANK) / (V_LINES_RND + TOP_MARGIN + BOT_MARGIN); | ||
110 | |||
111 | // 5.4.9 | ||
112 | float VBI_LINES = floor(c.RB_MIN_V_BLANK / H_PERIOD_EST) + 1; | ||
113 | |||
114 | // 5.4.10 | ||
115 | float RB_MIN_VBI = c.RB_V_FPORCH + V_SYNC_RND + c.MIN_V_BPORCH; | ||
116 | float ACT_VBI_LINES = VBI_LINES < RB_MIN_VBI ? RB_MIN_VBI : VBI_LINES; | ||
117 | |||
118 | // 5.4.11 | ||
119 | float TOTAL_V_LINES = ACT_VBI_LINES + V_LINES_RND + TOP_MARGIN + BOT_MARGIN + INTERLACE; | ||
120 | |||
121 | // 5.4.12 | ||
122 | float TOTAL_PIXELS = c.RB_H_BLANK + TOTAL_ACTIVE_PIXELS; | ||
123 | |||
124 | // 5.4.13 | ||
125 | float ACT_PIXEL_FREQ = c.CLOCK_STEP * floor((V_FIELD_RATE_RQD * TOTAL_V_LINES * TOTAL_PIXELS / 1000000 * c.REFRESH_MULTIPLIER) / c.CLOCK_STEP); | ||
126 | |||
127 | // 5.4.14 | ||
128 | //float ACT_H_FREQ = 1000 * ACT_PIXEL_FREQ / TOTAL_PIXELS; | ||
129 | |||
130 | // 5.4.15 | ||
131 | //float ACT_FIELD_RATE = 1000 * ACT_H_FREQ / TOTAL_V_LINES; | ||
132 | |||
133 | // 5.4.16 | ||
134 | //float ACT_FRAME_RATE = INT_RQD ? ACT_FIELD_RATE / 2 : ACT_FIELD_RATE; | ||
135 | |||
136 | // 3.4.3.7 Adjust vfp | ||
137 | if (reduced_v2) | ||
138 | c.RB_V_FPORCH = ACT_VBI_LINES - V_SYNC_RND - c.MIN_V_BPORCH; | ||
139 | |||
140 | Videomode mode; | ||
141 | |||
142 | mode = videomode_from_timings(ACT_PIXEL_FREQ * 1000, | ||
143 | H_PIXELS_RND, c.RB_H_FPORCH, c.RB_H_SYNC, c.RB_H_BPORCH, | ||
144 | V_LINES_RND * (INT_RQD ? 2 : 1), c.RB_V_FPORCH, V_SYNC_RND, ACT_VBI_LINES - V_SYNC_RND - c.RB_V_FPORCH); | ||
145 | |||
146 | mode.set_hsync(SyncPolarity::Positive); | ||
147 | mode.set_vsync(SyncPolarity::Negative); | ||
148 | |||
149 | mode.set_interlace(INT_RQD); | ||
150 | |||
151 | return mode; | ||
152 | } | ||
153 | |||
154 | } | ||
diff --git a/kms++/src/modedb.cpp b/kms++/src/modedb.cpp new file mode 100644 index 0000000..5d5d373 --- /dev/null +++ b/kms++/src/modedb.cpp | |||
@@ -0,0 +1,59 @@ | |||
1 | #include <xf86drm.h> | ||
2 | #include <stdexcept> | ||
3 | #include <cmath> | ||
4 | |||
5 | #include <kms++/modedb.h> | ||
6 | |||
7 | using namespace std; | ||
8 | |||
9 | namespace kms | ||
10 | { | ||
11 | |||
12 | static const Videomode& find_from_table(const Videomode* modes, uint32_t width, uint32_t height, float vrefresh, bool ilace) | ||
13 | { | ||
14 | for (unsigned i = 0; modes[i].clock; ++i) { | ||
15 | const Videomode& m = modes[i]; | ||
16 | |||
17 | if (m.hdisplay != width || m.vdisplay != height) | ||
18 | continue; | ||
19 | |||
20 | if (ilace != m.interlace()) | ||
21 | continue; | ||
22 | |||
23 | if (vrefresh && vrefresh != m.calculated_vrefresh()) | ||
24 | continue; | ||
25 | |||
26 | return m; | ||
27 | } | ||
28 | |||
29 | // If not found, do another round using rounded vrefresh | ||
30 | |||
31 | for (unsigned i = 0; modes[i].clock; ++i) { | ||
32 | const Videomode& m = modes[i]; | ||
33 | |||
34 | if (m.hdisplay != width || m.vdisplay != height) | ||
35 | continue; | ||
36 | |||
37 | if (ilace != m.interlace()) | ||
38 | continue; | ||
39 | |||
40 | if (vrefresh && vrefresh != roundf(m.calculated_vrefresh())) | ||
41 | continue; | ||
42 | |||
43 | return m; | ||
44 | } | ||
45 | |||
46 | throw invalid_argument("mode not found"); | ||
47 | } | ||
48 | |||
49 | const Videomode& find_dmt(uint32_t width, uint32_t height, float vrefresh, bool ilace) | ||
50 | { | ||
51 | return find_from_table(dmt_modes, width, height, vrefresh, ilace); | ||
52 | } | ||
53 | |||
54 | const Videomode& find_cea(uint32_t width, uint32_t height, float vrefresh, bool ilace) | ||
55 | { | ||
56 | return find_from_table(cea_modes, width, height, vrefresh, ilace); | ||
57 | } | ||
58 | |||
59 | } | ||
diff --git a/kms++/src/modedb_cea.cpp b/kms++/src/modedb_cea.cpp new file mode 100644 index 0000000..a99a612 --- /dev/null +++ b/kms++/src/modedb_cea.cpp | |||
@@ -0,0 +1,402 @@ | |||
1 | /* From Linux kernel: drm_edid.c */ | ||
2 | /* | ||
3 | * Copyright (c) 2006 Luc Verhaegen (quirks list) | ||
4 | * Copyright (c) 2007-2008 Intel Corporation | ||
5 | * Jesse Barnes <jesse.barnes@intel.com> | ||
6 | * Copyright 2010 Red Hat, Inc. | ||
7 | * | ||
8 | * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from | ||
9 | * FB layer. | ||
10 | * Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com> | ||
11 | * | ||
12 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
13 | * copy of this software and associated documentation files (the "Software"), | ||
14 | * to deal in the Software without restriction, including without limitation | ||
15 | * the rights to use, copy, modify, merge, publish, distribute, sub license, | ||
16 | * and/or sell copies of the Software, and to permit persons to whom the | ||
17 | * Software is furnished to do so, subject to the following conditions: | ||
18 | * | ||
19 | * The above copyright notice and this permission notice (including the | ||
20 | * next paragraph) shall be included in all copies or substantial portions | ||
21 | * of the Software. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
25 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
26 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
28 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
29 | * DEALINGS IN THE SOFTWARE. | ||
30 | */ | ||
31 | |||
32 | #include <kms++/modedb.h> | ||
33 | |||
34 | #include <xf86drm.h> | ||
35 | |||
36 | namespace kms | ||
37 | { | ||
38 | |||
39 | #define DIV_ROUND(n, d) (((n) + (d) / 2) / (d)) | ||
40 | |||
41 | #define DRM_MODE(nm, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \ | ||
42 | .name = nm, .clock = (c), \ | ||
43 | .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), .htotal = (ht), .hskew = (hsk), \ | ||
44 | .vdisplay = (vd), .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), .vscan = (vs), \ | ||
45 | .vrefresh = DIV_ROUND(c * 1000, ht * vt) * (((f) & DRM_MODE_FLAG_INTERLACE) ? 2 : 1), \ | ||
46 | .flags = (f), .type = 0 | ||
47 | |||
48 | /* | ||
49 | * Probably taken from CEA-861 spec. | ||
50 | * This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c. | ||
51 | */ | ||
52 | const Videomode cea_modes[] = { | ||
53 | /* 1 - 640x480@60Hz */ | ||
54 | { DRM_MODE("640x480", 25175, 640, 656, | ||
55 | 752, 800, 0, 480, 490, 492, 525, 0, | ||
56 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
57 | }, | ||
58 | /* 2 - 720x480@60Hz */ | ||
59 | { DRM_MODE("720x480", 27000, 720, 736, | ||
60 | 798, 858, 0, 480, 489, 495, 525, 0, | ||
61 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
62 | }, | ||
63 | /* 3 - 720x480@60Hz */ | ||
64 | { DRM_MODE("720x480", 27000, 720, 736, | ||
65 | 798, 858, 0, 480, 489, 495, 525, 0, | ||
66 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
67 | }, | ||
68 | /* 4 - 1280x720@60Hz */ | ||
69 | { DRM_MODE("1280x720", 74250, 1280, 1390, | ||
70 | 1430, 1650, 0, 720, 725, 730, 750, 0, | ||
71 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
72 | }, | ||
73 | /* 5 - 1920x1080i@60Hz */ | ||
74 | { DRM_MODE("1920x1080i", 74250, 1920, 2008, | ||
75 | 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, | ||
76 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | ||
77 | DRM_MODE_FLAG_INTERLACE), | ||
78 | }, | ||
79 | /* 6 - 720(1440)x480i@60Hz */ | ||
80 | { DRM_MODE("720x480i", 13500, 720, 739, | ||
81 | 801, 858, 0, 480, 488, 494, 525, 0, | ||
82 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
83 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
84 | }, | ||
85 | /* 7 - 720(1440)x480i@60Hz */ | ||
86 | { DRM_MODE("720x480i", 13500, 720, 739, | ||
87 | 801, 858, 0, 480, 488, 494, 525, 0, | ||
88 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
89 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
90 | }, | ||
91 | /* 8 - 720(1440)x240@60Hz */ | ||
92 | { DRM_MODE("720x240", 13500, 720, 739, | ||
93 | 801, 858, 0, 240, 244, 247, 262, 0, | ||
94 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
95 | DRM_MODE_FLAG_DBLCLK), | ||
96 | }, | ||
97 | /* 9 - 720(1440)x240@60Hz */ | ||
98 | { DRM_MODE("720x240", 13500, 720, 739, | ||
99 | 801, 858, 0, 240, 244, 247, 262, 0, | ||
100 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
101 | DRM_MODE_FLAG_DBLCLK), | ||
102 | }, | ||
103 | /* 10 - 2880x480i@60Hz */ | ||
104 | { DRM_MODE("2880x480i", 54000, 2880, 2956, | ||
105 | 3204, 3432, 0, 480, 488, 494, 525, 0, | ||
106 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
107 | DRM_MODE_FLAG_INTERLACE), | ||
108 | }, | ||
109 | /* 11 - 2880x480i@60Hz */ | ||
110 | { DRM_MODE("2880x480i", 54000, 2880, 2956, | ||
111 | 3204, 3432, 0, 480, 488, 494, 525, 0, | ||
112 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
113 | DRM_MODE_FLAG_INTERLACE), | ||
114 | }, | ||
115 | /* 12 - 2880x240@60Hz */ | ||
116 | { DRM_MODE("2880x240", 54000, 2880, 2956, | ||
117 | 3204, 3432, 0, 240, 244, 247, 262, 0, | ||
118 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
119 | }, | ||
120 | /* 13 - 2880x240@60Hz */ | ||
121 | { DRM_MODE("2880x240", 54000, 2880, 2956, | ||
122 | 3204, 3432, 0, 240, 244, 247, 262, 0, | ||
123 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
124 | }, | ||
125 | /* 14 - 1440x480@60Hz */ | ||
126 | { DRM_MODE("1440x480", 54000, 1440, 1472, | ||
127 | 1596, 1716, 0, 480, 489, 495, 525, 0, | ||
128 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
129 | }, | ||
130 | /* 15 - 1440x480@60Hz */ | ||
131 | { DRM_MODE("1440x480", 54000, 1440, 1472, | ||
132 | 1596, 1716, 0, 480, 489, 495, 525, 0, | ||
133 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
134 | }, | ||
135 | /* 16 - 1920x1080@60Hz */ | ||
136 | { DRM_MODE("1920x1080", 148500, 1920, 2008, | ||
137 | 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | ||
138 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
139 | }, | ||
140 | /* 17 - 720x576@50Hz */ | ||
141 | { DRM_MODE("720x576", 27000, 720, 732, | ||
142 | 796, 864, 0, 576, 581, 586, 625, 0, | ||
143 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
144 | }, | ||
145 | /* 18 - 720x576@50Hz */ | ||
146 | { DRM_MODE("720x576", 27000, 720, 732, | ||
147 | 796, 864, 0, 576, 581, 586, 625, 0, | ||
148 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
149 | }, | ||
150 | /* 19 - 1280x720@50Hz */ | ||
151 | { DRM_MODE("1280x720", 74250, 1280, 1720, | ||
152 | 1760, 1980, 0, 720, 725, 730, 750, 0, | ||
153 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
154 | }, | ||
155 | /* 20 - 1920x1080i@50Hz */ | ||
156 | { DRM_MODE("1920x1080i", 74250, 1920, 2448, | ||
157 | 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, | ||
158 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | ||
159 | DRM_MODE_FLAG_INTERLACE), | ||
160 | }, | ||
161 | /* 21 - 720(1440)x576i@50Hz */ | ||
162 | { DRM_MODE("720x576i", 13500, 720, 732, | ||
163 | 795, 864, 0, 576, 580, 586, 625, 0, | ||
164 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
165 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
166 | }, | ||
167 | /* 22 - 720(1440)x576i@50Hz */ | ||
168 | { DRM_MODE("720x576i", 13500, 720, 732, | ||
169 | 795, 864, 0, 576, 580, 586, 625, 0, | ||
170 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
171 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
172 | }, | ||
173 | /* 23 - 720(1440)x288@50Hz */ | ||
174 | { DRM_MODE("720x288", 13500, 720, 732, | ||
175 | 795, 864, 0, 288, 290, 293, 312, 0, | ||
176 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
177 | DRM_MODE_FLAG_DBLCLK), | ||
178 | }, | ||
179 | /* 24 - 720(1440)x288@50Hz */ | ||
180 | { DRM_MODE("720x288", 13500, 720, 732, | ||
181 | 795, 864, 0, 288, 290, 293, 312, 0, | ||
182 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
183 | DRM_MODE_FLAG_DBLCLK), | ||
184 | }, | ||
185 | /* 25 - 2880x576i@50Hz */ | ||
186 | { DRM_MODE("2880x576i", 54000, 2880, 2928, | ||
187 | 3180, 3456, 0, 576, 580, 586, 625, 0, | ||
188 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
189 | DRM_MODE_FLAG_INTERLACE), | ||
190 | }, | ||
191 | /* 26 - 2880x576i@50Hz */ | ||
192 | { DRM_MODE("2880x576i", 54000, 2880, 2928, | ||
193 | 3180, 3456, 0, 576, 580, 586, 625, 0, | ||
194 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
195 | DRM_MODE_FLAG_INTERLACE), | ||
196 | }, | ||
197 | /* 27 - 2880x288@50Hz */ | ||
198 | { DRM_MODE("2880x288", 54000, 2880, 2928, | ||
199 | 3180, 3456, 0, 288, 290, 293, 312, 0, | ||
200 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
201 | }, | ||
202 | /* 28 - 2880x288@50Hz */ | ||
203 | { DRM_MODE("2880x288", 54000, 2880, 2928, | ||
204 | 3180, 3456, 0, 288, 290, 293, 312, 0, | ||
205 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
206 | }, | ||
207 | /* 29 - 1440x576@50Hz */ | ||
208 | { DRM_MODE("1440x576", 54000, 1440, 1464, | ||
209 | 1592, 1728, 0, 576, 581, 586, 625, 0, | ||
210 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
211 | }, | ||
212 | /* 30 - 1440x576@50Hz */ | ||
213 | { DRM_MODE("1440x576", 54000, 1440, 1464, | ||
214 | 1592, 1728, 0, 576, 581, 586, 625, 0, | ||
215 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
216 | }, | ||
217 | /* 31 - 1920x1080@50Hz */ | ||
218 | { DRM_MODE("1920x1080", 148500, 1920, 2448, | ||
219 | 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, | ||
220 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
221 | }, | ||
222 | /* 32 - 1920x1080@24Hz */ | ||
223 | { DRM_MODE("1920x1080", 74250, 1920, 2558, | ||
224 | 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, | ||
225 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
226 | }, | ||
227 | /* 33 - 1920x1080@25Hz */ | ||
228 | { DRM_MODE("1920x1080", 74250, 1920, 2448, | ||
229 | 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, | ||
230 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
231 | }, | ||
232 | /* 34 - 1920x1080@30Hz */ | ||
233 | { DRM_MODE("1920x1080", 74250, 1920, 2008, | ||
234 | 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | ||
235 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
236 | }, | ||
237 | /* 35 - 2880x480@60Hz */ | ||
238 | { DRM_MODE("2880x480", 108000, 2880, 2944, | ||
239 | 3192, 3432, 0, 480, 489, 495, 525, 0, | ||
240 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
241 | }, | ||
242 | /* 36 - 2880x480@60Hz */ | ||
243 | { DRM_MODE("2880x480", 108000, 2880, 2944, | ||
244 | 3192, 3432, 0, 480, 489, 495, 525, 0, | ||
245 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
246 | }, | ||
247 | /* 37 - 2880x576@50Hz */ | ||
248 | { DRM_MODE("2880x576", 108000, 2880, 2928, | ||
249 | 3184, 3456, 0, 576, 581, 586, 625, 0, | ||
250 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
251 | }, | ||
252 | /* 38 - 2880x576@50Hz */ | ||
253 | { DRM_MODE("2880x576", 108000, 2880, 2928, | ||
254 | 3184, 3456, 0, 576, 581, 586, 625, 0, | ||
255 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
256 | }, | ||
257 | /* 39 - 1920x1080i@50Hz */ | ||
258 | { DRM_MODE("1920x1080i", 72000, 1920, 1952, | ||
259 | 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, | ||
260 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
261 | DRM_MODE_FLAG_INTERLACE), | ||
262 | }, | ||
263 | /* 40 - 1920x1080i@100Hz */ | ||
264 | { DRM_MODE("1920x1080i", 148500, 1920, 2448, | ||
265 | 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, | ||
266 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | ||
267 | DRM_MODE_FLAG_INTERLACE), | ||
268 | }, | ||
269 | /* 41 - 1280x720@100Hz */ | ||
270 | { DRM_MODE("1280x720", 148500, 1280, 1720, | ||
271 | 1760, 1980, 0, 720, 725, 730, 750, 0, | ||
272 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
273 | }, | ||
274 | /* 42 - 720x576@100Hz */ | ||
275 | { DRM_MODE("720x576", 54000, 720, 732, | ||
276 | 796, 864, 0, 576, 581, 586, 625, 0, | ||
277 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
278 | }, | ||
279 | /* 43 - 720x576@100Hz */ | ||
280 | { DRM_MODE("720x576", 54000, 720, 732, | ||
281 | 796, 864, 0, 576, 581, 586, 625, 0, | ||
282 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
283 | }, | ||
284 | /* 44 - 720(1440)x576i@100Hz */ | ||
285 | { DRM_MODE("720x576i", 27000, 720, 732, | ||
286 | 795, 864, 0, 576, 580, 586, 625, 0, | ||
287 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
288 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
289 | }, | ||
290 | /* 45 - 720(1440)x576i@100Hz */ | ||
291 | { DRM_MODE("720x576i", 27000, 720, 732, | ||
292 | 795, 864, 0, 576, 580, 586, 625, 0, | ||
293 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
294 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
295 | }, | ||
296 | /* 46 - 1920x1080i@120Hz */ | ||
297 | { DRM_MODE("1920x1080i", 148500, 1920, 2008, | ||
298 | 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, | ||
299 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | ||
300 | DRM_MODE_FLAG_INTERLACE), | ||
301 | }, | ||
302 | /* 47 - 1280x720@120Hz */ | ||
303 | { DRM_MODE("1280x720", 148500, 1280, 1390, | ||
304 | 1430, 1650, 0, 720, 725, 730, 750, 0, | ||
305 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
306 | }, | ||
307 | /* 48 - 720x480@120Hz */ | ||
308 | { DRM_MODE("720x480", 54000, 720, 736, | ||
309 | 798, 858, 0, 480, 489, 495, 525, 0, | ||
310 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
311 | }, | ||
312 | /* 49 - 720x480@120Hz */ | ||
313 | { DRM_MODE("720x480", 54000, 720, 736, | ||
314 | 798, 858, 0, 480, 489, 495, 525, 0, | ||
315 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
316 | }, | ||
317 | /* 50 - 720(1440)x480i@120Hz */ | ||
318 | { DRM_MODE("720x480i", 27000, 720, 739, | ||
319 | 801, 858, 0, 480, 488, 494, 525, 0, | ||
320 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
321 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
322 | }, | ||
323 | /* 51 - 720(1440)x480i@120Hz */ | ||
324 | { DRM_MODE("720x480i", 27000, 720, 739, | ||
325 | 801, 858, 0, 480, 488, 494, 525, 0, | ||
326 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
327 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
328 | }, | ||
329 | /* 52 - 720x576@200Hz */ | ||
330 | { DRM_MODE("720x576", 108000, 720, 732, | ||
331 | 796, 864, 0, 576, 581, 586, 625, 0, | ||
332 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
333 | }, | ||
334 | /* 53 - 720x576@200Hz */ | ||
335 | { DRM_MODE("720x576", 108000, 720, 732, | ||
336 | 796, 864, 0, 576, 581, 586, 625, 0, | ||
337 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
338 | }, | ||
339 | /* 54 - 720(1440)x576i@200Hz */ | ||
340 | { DRM_MODE("720x576i", 54000, 720, 732, | ||
341 | 795, 864, 0, 576, 580, 586, 625, 0, | ||
342 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
343 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
344 | }, | ||
345 | /* 55 - 720(1440)x576i@200Hz */ | ||
346 | { DRM_MODE("720x576i", 54000, 720, 732, | ||
347 | 795, 864, 0, 576, 580, 586, 625, 0, | ||
348 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
349 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
350 | }, | ||
351 | /* 56 - 720x480@240Hz */ | ||
352 | { DRM_MODE("720x480", 108000, 720, 736, | ||
353 | 798, 858, 0, 480, 489, 495, 525, 0, | ||
354 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
355 | }, | ||
356 | /* 57 - 720x480@240Hz */ | ||
357 | { DRM_MODE("720x480", 108000, 720, 736, | ||
358 | 798, 858, 0, 480, 489, 495, 525, 0, | ||
359 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
360 | }, | ||
361 | /* 58 - 720(1440)x480i@240 */ | ||
362 | { DRM_MODE("720x480i", 54000, 720, 739, | ||
363 | 801, 858, 0, 480, 488, 494, 525, 0, | ||
364 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
365 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
366 | }, | ||
367 | /* 59 - 720(1440)x480i@240 */ | ||
368 | { DRM_MODE("720x480i", 54000, 720, 739, | ||
369 | 801, 858, 0, 480, 488, 494, 525, 0, | ||
370 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||
371 | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||
372 | }, | ||
373 | /* 60 - 1280x720@24Hz */ | ||
374 | { DRM_MODE("1280x720", 59400, 1280, 3040, | ||
375 | 3080, 3300, 0, 720, 725, 730, 750, 0, | ||
376 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
377 | }, | ||
378 | /* 61 - 1280x720@25Hz */ | ||
379 | { DRM_MODE("1280x720", 74250, 1280, 3700, | ||
380 | 3740, 3960, 0, 720, 725, 730, 750, 0, | ||
381 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
382 | }, | ||
383 | /* 62 - 1280x720@30Hz */ | ||
384 | { DRM_MODE("1280x720", 74250, 1280, 3040, | ||
385 | 3080, 3300, 0, 720, 725, 730, 750, 0, | ||
386 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
387 | }, | ||
388 | /* 63 - 1920x1080@120Hz */ | ||
389 | { DRM_MODE("1920x1080", 297000, 1920, 2008, | ||
390 | 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | ||
391 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
392 | }, | ||
393 | /* 64 - 1920x1080@100Hz */ | ||
394 | { DRM_MODE("1920x1080", 297000, 1920, 2448, | ||
395 | 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, | ||
396 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
397 | }, | ||
398 | /* TERMINATOR */ | ||
399 | { }, | ||
400 | }; | ||
401 | |||
402 | } | ||
diff --git a/kms++/src/modedb_dmt.cpp b/kms++/src/modedb_dmt.cpp new file mode 100644 index 0000000..7dee6b1 --- /dev/null +++ b/kms++/src/modedb_dmt.cpp | |||
@@ -0,0 +1,204 @@ | |||
1 | /* Generated from DMTr1 v13.pdf */ | ||
2 | |||
3 | #include <kms++/modedb.h> | ||
4 | |||
5 | #include <xf86drm.h> | ||
6 | |||
7 | namespace kms | ||
8 | { | ||
9 | |||
10 | #define DIV_ROUND(n, d) (((n) + (d) / 2) / (d)) | ||
11 | |||
12 | // hd, hss, hse, ht, vd, vss, vse, vt | ||
13 | |||
14 | #define DRM_MODE(nm, c, hact, hfp, hsw, hbp, vact, vfp, vsw, vbp, f) \ | ||
15 | { \ | ||
16 | .name = nm, .clock = c, \ | ||
17 | .hdisplay = (hact), .hsync_start = (hact) + (hfp), .hsync_end = (hact) + (hfp) + (hsw), .htotal = (hact) + (hfp) + (hsw) + (hbp), .hskew = 0, \ | ||
18 | .vdisplay = (vact), .vsync_start = (vact) + (vfp), .vsync_end = (vact) + (vfp) + (vsw), .vtotal = (vact) + (vfp) + (vsw) + (vbp), .vscan = 0, \ | ||
19 | .vrefresh = DIV_ROUND(c * 1000, ((hact) + (hfp) + (hsw) + (hbp)) * ((vact) + (vfp) + (vsw) + (vbp))) * (((f) & DRM_MODE_FLAG_INTERLACE) ? 2 : 1), \ | ||
20 | .flags = (f), .type = 0 \ | ||
21 | } | ||
22 | |||
23 | const Videomode dmt_modes[] = { | ||
24 | // 0x1 - 640 x 350 @ 85Hz | ||
25 | DRM_MODE("640 x 350 @ 85Hz", 31500, 640, 32, 64, 96, 350, 32, 3, 60, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
26 | // 0x2 - 640 x 400 @ 85Hz | ||
27 | DRM_MODE("640 x 400 @ 85Hz", 31500, 640, 32, 64, 96, 400, 1, 3, 41, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC), | ||
28 | // 0x3 - 720 x 400 @ 85Hz | ||
29 | DRM_MODE("720 x 400 @ 85Hz", 35500, 720, 36, 72, 108, 400, 1, 3, 42, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC), | ||