aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlistair Strachan2018-09-27 14:31:56 -0500
committerAlistair Strachan2018-09-27 14:32:51 -0500
commite77f68c1d7a607019f9cf36d47b8f33fcb9b7146 (patch)
tree0ee57162c5dd375cf49b1699dac54289f520b012
parentc6e38de712579ec0145302f8f9e456ba1e7214f1 (diff)
parente0067bdc75566629c9143818c8f3970c16c8825e (diff)
downloadexternal-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
-rw-r--r--.gitignore7
-rw-r--r--.gitmodules3
-rw-r--r--.travis.yml81
-rw-r--r--CMakeLists.txt88
-rw-r--r--LICENSE373
-rw-r--r--LTO.cmake32
-rw-r--r--README.md99
-rw-r--r--TODO8
m---------ext/pybind110
-rw-r--r--kms++/CMakeLists.txt33
-rw-r--r--kms++/inc/kms++/atomicreq.h39
-rw-r--r--kms++/inc/kms++/blob.h22
-rw-r--r--kms++/inc/kms++/card.h72
-rw-r--r--kms++/inc/kms++/connector.h53
-rw-r--r--kms++/inc/kms++/crtc.h54
-rw-r--r--kms++/inc/kms++/decls.h20
-rw-r--r--kms++/inc/kms++/drmobject.h40
-rw-r--r--kms++/inc/kms++/drmpropobject.h38
-rw-r--r--kms++/inc/kms++/dumbframebuffer.h47
-rw-r--r--kms++/inc/kms++/encoder.h27
-rw-r--r--kms++/inc/kms++/extframebuffer.h47
-rw-r--r--kms++/inc/kms++/framebuffer.h43
-rw-r--r--kms++/inc/kms++/kms++.h15
-rw-r--r--kms++/inc/kms++/mode_cvt.h10
-rw-r--r--kms++/inc/kms++/modedb.h16
-rw-r--r--kms++/inc/kms++/omap/omapcard.h21
-rw-r--r--kms++/inc/kms++/omap/omapframebuffer.h62
-rw-r--r--kms++/inc/kms++/omap/omapkms++.h4
-rw-r--r--kms++/inc/kms++/pagefliphandler.h11
-rw-r--r--kms++/inc/kms++/pipeline.h11
-rw-r--r--kms++/inc/kms++/pixelformats.h67
-rw-r--r--kms++/inc/kms++/plane.h42
-rw-r--r--kms++/inc/kms++/property.h44
-rw-r--r--kms++/inc/kms++/videomode.h58
-rw-r--r--kms++/src/atomicreq.cpp117
-rw-r--r--kms++/src/blob.cpp51
-rw-r--r--kms++/src/card.cpp247
-rw-r--r--kms++/src/connector.cpp273
-rw-r--r--kms++/src/crtc.cpp183
-rw-r--r--kms++/src/drmobject.cpp34
-rw-r--r--kms++/src/drmpropobject.cpp98
-rw-r--r--kms++/src/dumbframebuffer.cpp137
-rw-r--r--kms++/src/encoder.cpp85
-rw-r--r--kms++/src/extframebuffer.cpp115
-rw-r--r--kms++/src/framebuffer.cpp56
-rw-r--r--kms++/src/helpers.cpp72
-rw-r--r--kms++/src/helpers.h12
-rw-r--r--kms++/src/mode_cvt.cpp154
-rw-r--r--kms++/src/modedb.cpp59
-rw-r--r--kms++/src/modedb_cea.cpp402
-rw-r--r--kms++/src/modedb_dmt.cpp204
-rw-r--r--kms++/src/omap/omapcard.cpp29
-rw-r--r--kms++/src/omap/omapframebuffer.cpp184
-rw-r--r--kms++/src/pixelformats.cpp36
-rw-r--r--kms++/src/plane.cpp140
-rw-r--r--kms++/src/property.cpp87
-rw-r--r--kms++/src/videomode.cpp121
-rw-r--r--kms++util/CMakeLists.txt18
-rw-r--r--kms++util/inc/kms++util/color.h49
-rw-r--r--kms++util/inc/kms++util/cpuframebuffer.h44
-rw-r--r--kms++util/inc/kms++util/extcpuframebuffer.h43
-rw-r--r--kms++util/inc/kms++util/kms++util.h71
-rw-r--r--kms++util/inc/kms++util/opts.h38
-rw-r--r--kms++util/inc/kms++util/resourcemanager.h32
-rw-r--r--kms++util/inc/kms++util/stopwatch.h28
-rw-r--r--kms++util/inc/kms++util/strhelpers.h33
-rw-r--r--kms++util/inc/kms++util/videodevice.h86
-rw-r--r--kms++util/src/color.cpp147
-rw-r--r--kms++util/src/colorbar.cpp132
-rw-r--r--kms++util/src/cpuframebuffer.cpp36
-rw-r--r--kms++util/src/drawing.cpp275
-rw-r--r--kms++util/src/extcpuframebuffer.cpp49
-rw-r--r--kms++util/src/font_8x8.h2570
-rw-r--r--kms++util/src/opts.cpp117
-rw-r--r--kms++util/src/resourcemanager.cpp206
-rw-r--r--kms++util/src/strhelpers.cpp27
-rw-r--r--kms++util/src/testpat.cpp199
-rw-r--r--kms++util/src/videodevice.cpp461
-rw-r--r--kmscube/CMakeLists.txt45
-rw-r--r--kmscube/cube-egl.cpp121
-rw-r--r--kmscube/cube-egl.h34
-rw-r--r--kmscube/cube-gbm.cpp370
-rw-r--r--kmscube/cube-gles2.cpp264
-rw-r--r--kmscube/cube-gles2.h22
-rw-r--r--kmscube/cube-null.cpp36
-rw-r--r--kmscube/cube-wl.cpp108
-rw-r--r--kmscube/cube-x11.cpp155
-rw-r--r--kmscube/cube.cpp80
-rw-r--r--kmscube/cube.h11
-rw-r--r--kmscube/esTransform.c235
-rw-r--r--kmscube/esTransform.h125
-rw-r--r--py/CMakeLists.txt2
-rw-r--r--py/pykms/CMakeLists.txt30
-rw-r--r--py/pykms/__init__.py139
-rw-r--r--py/pykms/pykms.cpp28
-rw-r--r--py/pykms/pykmsbase.cpp246
-rw-r--r--py/pykms/pykmsomap.cpp42
-rw-r--r--py/pykms/pykmsutil.cpp62
-rw-r--r--py/pykms/pyvid.cpp39
-rw-r--r--py/tests/CMakeLists.txt7
-rwxr-xr-xpy/tests/alpha-test.py62
-rwxr-xr-xpy/tests/big_fb.py279
-rwxr-xr-xpy/tests/cam.py78
-rwxr-xr-xpy/tests/ctm_test.py86
-rwxr-xr-xpy/tests/db.py96
-rwxr-xr-xpy/tests/functest.py18
-rwxr-xr-xpy/tests/gamma.py40
-rwxr-xr-xpy/tests/hpd.py22
-rwxr-xr-xpy/tests/iact.py42
-rwxr-xr-xpy/tests/kmsmodeview.py317
-rwxr-xr-xpy/tests/modeset_event.py73
-rwxr-xr-xpy/tests/plane_csc.py66
-rwxr-xr-xpy/tests/plane_hog.py136
-rwxr-xr-xpy/tests/rottest.py171
-rwxr-xr-xpy/tests/scale.py60
-rwxr-xr-xpy/tests/sync.py234
-rwxr-xr-xpy/tests/test.py65
-rwxr-xr-xpy/tests/trans-test.py331
-rwxr-xr-xscripts/dmt.py107
-rw-r--r--utils/CMakeLists.txt29
-rw-r--r--utils/fbtest.cpp58
-rw-r--r--utils/kmsblank.cpp104
-rw-r--r--utils/kmscapture.cpp425
-rw-r--r--utils/kmsprint.cpp540
-rw-r--r--utils/kmstest.cpp1108
-rw-r--r--utils/kmsview.cpp123
-rw-r--r--utils/wbcap.cpp420
-rw-r--r--utils/wbm2m.cpp169
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
4build
5*.txt.user
6*.patch
7py/__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
2sudo: required
3dist: trusty
4
5# Only build test master & travis
6branches:
7 only:
8 - master
9 - travis
10
11# Enable C++ support
12language: cpp
13
14addons:
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
28matrix:
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
74script:
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
79notifications:
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 @@
1cmake_minimum_required(VERSION 2.8)
2project(kms++)
3
4include(LTO.cmake)
5
6set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
7set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
8set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
9
10include(CheckCXXCompilerFlag)
11
12IF(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")
16ENDIF()
17
18string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
19
20option(BUILD_SHARED_LIBS "Build shared libs" FALSE)
21option(TREAT_WARNINGS_AS_ERRORS "Treat warnings as errors" FALSE)
22
23set(KMSXX_ENABLE_PYTHON ON CACHE BOOL "Enable Python wrappers")
24set(KMSXX_PYTHON_VERSION "python3;python2" CACHE STRING "Python pkgconfig package")
25
26set(KMSXX_ENABLE_KMSCUBE OFF CACHE BOOL "Enable kmscube")
27
28set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall")
29set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wno-unused-parameter")
30
31set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
32set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wno-unused-parameter")
33
34if (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()
39endif()
40
41# HACK: cmake always adds "-rdynamic", this removes it
42SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
43SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
44
45set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
46
47if (TREAT_WARNINGS_AS_ERRORS)
48 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
49 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
50endif()
51
52# static link libc
53# set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
54
55check_lto()
56
57if (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()
64endif()
65
66find_package(PkgConfig REQUIRED)
67pkg_check_modules(LIBDRM libdrm>=2.4.64 REQUIRED)
68
69pkg_check_modules(LIBDRM_OMAP libdrm_omap)
70if(LIBDRM_OMAP_FOUND)
71 add_definitions(-DHAS_LIBDRM_OMAP)
72endif()
73
74enable_testing()
75
76add_subdirectory(kms++)
77add_subdirectory(kms++util)
78add_subdirectory(utils)
79
80if(KMSXX_ENABLE_KMSCUBE)
81 add_subdirectory(kmscube)
82endif()
83
84if(KMSXX_ENABLE_PYTHON)
85 add_subdirectory(py)
86endif()
87
88add_custom_target(docs SOURCES "README.md")
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..14e2f77
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,373 @@
1Mozilla Public License Version 2.0
2==================================
3
41. Definitions
5--------------
6
71.1. "Contributor"
8 means each individual or legal entity that creates, contributes to
9 the creation of, or owns Covered Software.
10
111.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
151.3. "Contribution"
16 means Covered Software of a particular Contributor.
17
181.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
241.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
341.6. "Executable Form"
35 means any form of the work other than Source Code Form.
36
371.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
411.8. "License"
42 means this document.
43
441.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
491.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
591.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
671.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
731.13. "Source Code Form"
74 means the form of the work preferred for making modifications.
75
761.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
862. License Grants and Conditions
87--------------------------------
88
892.1. Grants
90
91Each Contributor hereby grants You a world-wide, royalty-free,
92non-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
1042.2. Effective Date
105
106The licenses granted in Section 2.1 with respect to any Contribution
107become effective for each Contribution on the date the Contributor first
108distributes such Contribution.
109
1102.3. Limitations on Grant Scope
111
112The licenses granted in this Section 2 are the only rights granted under
113this License. No additional rights or licenses will be implied from the
114distribution or licensing of Covered Software under this License.
115Notwithstanding Section 2.1(b) above, no patent license is granted by a
116Contributor:
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
129This License does not grant any rights in the trademarks, service marks,
130or logos of any Contributor (except as may be necessary to comply with
131the notice requirements in Section 3.4).
132
1332.4. Subsequent Licenses
134
135No Contributor makes additional grants as a result of Your choice to
136distribute the Covered Software under a subsequent version of this
137License (see Section 10.2) or under the terms of a Secondary License (if
138permitted under the terms of Section 3.3).
139
1402.5. Representation
141
142Each Contributor represents that the Contributor believes its
143Contributions are its original creation(s) or it has sufficient rights
144to grant the rights to its Contributions conveyed by this License.
145
1462.6. Fair Use
147
148This License is not intended to limit any rights You have under
149applicable copyright doctrines of fair use, fair dealing, or other
150equivalents.
151
1522.7. Conditions
153
154Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155in Section 2.1.
156
1573. Responsibilities
158-------------------
159
1603.1. Distribution of Source Form
161
162All distribution of Covered Software in Source Code Form, including any
163Modifications that You create or to which You contribute, must be under
164the terms of this License. You must inform recipients that the Source
165Code Form of the Covered Software is governed by the terms of this
166License, and how they can obtain a copy of this License. You may not
167attempt to alter or restrict the recipients' rights in the Source Code
168Form.
169
1703.2. Distribution of Executable Form
171
172If 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
1853.3. Distribution of a Larger Work
186
187You may create and distribute a Larger Work under terms of Your choice,
188provided that You also comply with the requirements of this License for
189the Covered Software. If the Larger Work is a combination of Covered
190Software with a work governed by one or more Secondary Licenses, and the
191Covered Software is not Incompatible With Secondary Licenses, this
192License permits You to additionally distribute such Covered Software
193under the terms of such Secondary License(s), so that the recipient of
194the Larger Work may, at their option, further distribute the Covered
195Software under the terms of either this License or such Secondary
196License(s).
197
1983.4. Notices
199
200You may not remove or alter the substance of any license notices
201(including copyright notices, patent notices, disclaimers of warranty,
202or limitations of liability) contained within the Source Code Form of
203the Covered Software, except that You may alter any license notices to
204the extent required to remedy known factual inaccuracies.
205
2063.5. Application of Additional Terms
207
208You may choose to offer, and to charge a fee for, warranty, support,
209indemnity or liability obligations to one or more recipients of Covered
210Software. However, You may do so only on Your own behalf, and not on
211behalf of any Contributor. You must make it absolutely clear that any
212such warranty, support, indemnity, or liability obligation is offered by
213You alone, and You hereby agree to indemnify every Contributor for any
214liability incurred by such Contributor as a result of warranty, support,
215indemnity or liability terms You offer. You may include additional
216disclaimers of warranty and limitations of liability specific to any
217jurisdiction.
218
2194. Inability to Comply Due to Statute or Regulation
220---------------------------------------------------
221
222If it is impossible for You to comply with any of the terms of this
223License with respect to some or all of the Covered Software due to
224statute, judicial order, or regulation then You must: (a) comply with
225the terms of this License to the maximum extent possible; and (b)
226describe the limitations and the code they affect. Such description must
227be placed in a text file included with all distributions of the Covered
228Software under this License. Except to the extent prohibited by statute
229or regulation, such description must be sufficiently detailed for a
230recipient of ordinary skill to be able to understand it.
231
2325. Termination
233--------------
234
2355.1. The rights granted under this License will terminate automatically
236if You fail to comply with any of its terms. However, if You become
237compliant, then the rights granted under this License from a particular
238Contributor are reinstated (a) provisionally, unless and until such
239Contributor explicitly and finally terminates Your grants, and (b) on an
240ongoing basis, if such Contributor fails to notify You of the
241non-compliance by some reasonable means prior to 60 days after You have
242come back into compliance. Moreover, Your grants from a particular
243Contributor are reinstated on an ongoing basis if such Contributor
244notifies You of the non-compliance by some reasonable means, this is the
245first time You have received notice of non-compliance with this License
246from such Contributor, and You become compliant prior to 30 days after
247Your receipt of the notice.
248
2495.2. If You initiate litigation against any entity by asserting a patent
250infringement claim (excluding declaratory judgment actions,
251counter-claims, and cross-claims) alleging that a Contributor Version
252directly or indirectly infringes any patent, then the rights granted to
253You by any and all Contributors for the Covered Software under Section
2542.1 of this License shall terminate.
255
2565.3. In the event of termination under Sections 5.1 or 5.2 above, all
257end user license agreements (excluding distributors and resellers) which
258have been validly granted by You or Your distributors under this License
259prior 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
3038. Litigation
304-------------
305
306Any litigation relating to this License may be brought only in the
307courts of a jurisdiction where the defendant maintains its principal
308place of business and such litigation shall be governed by laws of that
309jurisdiction, without reference to its conflict-of-law provisions.
310Nothing in this Section shall prevent a party's ability to bring
311cross-claims or counter-claims.
312
3139. Miscellaneous
314----------------
315
316This License represents the complete agreement concerning the subject
317matter hereof. If any provision of this License is held to be
318unenforceable, such provision shall be reformed only to the extent
319necessary to make it enforceable. Any law or regulation which provides
320that the language of a contract shall be construed against the drafter
321shall not be used to construe this License against a Contributor.
322
32310. Versions of the License
324---------------------------
325
32610.1. New Versions
327
328Mozilla Foundation is the license steward. Except as provided in Section
32910.3, no one other than the license steward has the right to modify or
330publish new versions of this License. Each version will be given a
331distinguishing version number.
332
33310.2. Effect of New Versions
334
335You may distribute the Covered Software under the terms of the version
336of the License under which You originally received the Covered Software,
337or under the terms of any subsequent version published by the license
338steward.
339
34010.3. Modified Versions
341
342If you create software not governed by this License, and you want to
343create a new license for such software, you may create and use a
344modified version of this License if you rename the license and remove
345any references to the name of the license steward (except to note that
346such modified license differs from this License).
347
34810.4. Distributing Source Code Form that is Incompatible With Secondary
349Licenses
350
351If You choose to distribute Source Code Form that is Incompatible With
352Secondary Licenses under the terms of this version of the License, the
353notice described in Exhibit B of this License must be attached.
354
355Exhibit 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
362If it is not possible or desirable to put the notice in a particular
363file, then You may include the notice in a location (such as a LICENSE
364file in a relevant directory) where a recipient would be likely to look
365for such a notice.
366
367You may add additional accurate notices of copyright ownership.
368
369Exhibit 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 @@
1function(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")
32endfunction()
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[![Build Status](https://travis-ci.org/tomba/kmsxx.svg?branch=master)](https://travis-ci.org/tomba/kmsxx)
2
3# kms++ - C++ library for kernel mode setting
4
5kms++ is a C++11 library for kernel mode setting.
6
7Also 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
24To build the Python bindings you need to set up the git-submodule for pybind11:
25
26```
27git submodule update --init
28```
29
30And to compile:
31
32```
33$ mkdir build
34$ cd build
35$ cmake ..
36$ make -j4
37```
38
39## Cross compiling instructions:
40
41Directions for cross compiling depend on your environment.
42
43These 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
52Your environment may provide similar toolchainfile. If not, you can create a toolchainfile of your own, something along these lines:
53
54```
55SET(CMAKE_SYSTEM_NAME Linux)
56
57SET(BROOT "<buildroot>/output/")
58
59# specify the cross compiler
60SET(CMAKE_C_COMPILER ${BROOT}/host/usr/bin/arm-buildroot-linux-gnueabihf-gcc)
61SET(CMAKE_CXX_COMPILER ${BROOT}/host/usr/bin/arm-buildroot-linux-gnueabihf-g++)
62
63# where is the target environment
64SET(CMAKE_FIND_ROOT_PATH ${BROOT}/target ${BROOT}/host)
65
66SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
67SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
68SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
69```
70
71## Build options
72
73You can use the following cmake flags to control the build. Use `-DFLAG=VALUE` to set them.
74
75Option name | Values | Default | Notes
76--------------------- | ------------- | --------------- | --------
77CMAKE_BUILD_TYPE | Release/Debug | Release |
78BUILD_SHARED_LIBS | ON/OFF | OFF |
79KMSXX_ENABLE_PYTHON | ON/OFF | ON |
80KMSXX_ENABLE_KMSCUBE | ON/OFF | OFF |
81KMSXX_PYTHON_VERSION | python3/python2 | python3;python2 | Name of the python pkgconfig file
82
83## Env variables
84
85You can use the following runtime environmental variables to control the behavior of kms++.
86
87Variable | Description
88--------------------------------- | -------------
89KMSXX_DISABLE_UNIVERSAL_PLANES | Set to disable the use of universal planes
90KMSXX_DISABLE_ATOMIC | Set to disable the use of atomic modesetting
91
92## Python notes
93
94You can run the python code directly from the build dir by defining PYTHONPATH env variable. For example:
95
96```
97PYTHONPATH=build/py py/tests/hpd.py
98
99```
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..9696666
--- /dev/null
+++ b/TODO
@@ -0,0 +1,8 @@
1
2C++ move semantics for classes (especially for Framebuffers)?
3
4Proper error checks and use of exceptions
5
6Free drmModeConnectorPtr (and similar for other drm objects) after use, instead
7of 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 @@
1include_directories(${LIBDRM_INCLUDE_DIRS})
2link_directories(${LIBDRM_LIBRARY_DIRS})
3
4include_directories(${LIBDRM_OMAP_INCLUDE_DIRS})
5link_directories(${LIBDRM_OMAP_LIBRARY_DIRS})
6
7file(GLOB SRCS "src/*.cpp" "src/*.h")
8file(GLOB PUB_HDRS "inc/kms++/*.h")
9
10if(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})
16endif()
17
18add_library(kms++ ${SRCS} ${PUB_HDRS})
19
20target_include_directories(kms++ PUBLIC
21 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
22 $<INSTALL_INTERFACE:include>
23 PRIVATE src)
24
25target_link_libraries(kms++ ${LIBDRM_LIBRARIES} ${LIBDRM_OMAP_LIBRARIES})
26
27set_target_properties(kms++ PROPERTIES
28 PUBLIC_HEADER "${PUB_HDRS}")
29
30install(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
7struct _drmModeAtomicReq;
8
9#include "decls.h"
10
11namespace kms
12{
13class AtomicReq
14{
15public:
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
34private:
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
6namespace kms
7{
8
9class Blob : public DrmObject
10{
11public:
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
18private:
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
10namespace kms
11{
12class Card
13{
14 friend class Framebuffer;
15public:
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
54private:
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
8namespace kms
9{
10
11struct ConnectorPriv;
12
13class Connector : public DrmPropObject
14{
15 friend class Card;
16public:
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;
38private:
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
7namespace kms
8{
9
10struct CrtcPriv;
11
12class Crtc : public DrmPropObject
13{
14 friend class Card;
15 friend class Connector;
16public:
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;
43private:
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
3namespace kms
4{
5class AtomicReq;
6class Blob;
7class Card;
8class Connector;
9class Crtc;
10class DrmObject;
11class DrmPropObject;
12class DumbFramebuffer;
13class Encoder;
14class ExtFramebuffer;
15class Framebuffer;
16class PageFlipHandlerBase;
17class Plane;
18class Property;
19struct 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
7namespace kms
8{
9
10class DrmObject
11{
12 friend class Card;
13public:
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
23protected:
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
33private:
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
9namespace kms
10{
11
12class DrmPropObject : public DrmObject
13{
14 friend class Card;
15public:
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
29protected:
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
35private:
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
6namespace kms
7{
8
9class DumbFramebuffer : public Framebuffer
10{
11public:
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
29private:
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
6namespace kms
7{
8
9struct EncoderPriv;
10
11class Encoder : public DrmPropObject
12{
13 friend class Card;
14public:
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;
21private:
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
6namespace kms
7{
8
9class ExtFramebuffer : public Framebuffer
10{
11public:
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
31private:
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
6namespace kms
7{
8class IFramebuffer {
9public:
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
25class Framebuffer : public DrmObject, public IFramebuffer
26{
27public:
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();
35protected:
36 Framebuffer(Card& card, uint32_t width, uint32_t height);
37
38private:
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
5namespace kms
6{
7
8Videomode 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
6namespace kms
7{
8struct Videomode;
9
10extern const Videomode dmt_modes[];
11extern const Videomode cea_modes[];
12
13const Videomode& find_dmt(uint32_t width, uint32_t height, float vrefresh, bool ilace);
14const 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
5struct omap_device;
6
7namespace kms
8{
9class OmapCard : public Card
10{
11public:
12 OmapCard();
13 OmapCard(const std::string& device);
14 virtual ~OmapCard();
15
16 struct omap_device* dev() const { return m_omap_dev; }
17
18private:
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
6struct omap_bo;
7
8namespace kms
9{
10class OmapCard;
11
12class OmapFramebuffer : public Framebuffer
13{
14public:
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
41private:
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
3namespace kms {
4class PageFlipHandlerBase
5{
6public:
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
5namespace kms
6{
7struct 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
6namespace kms
7{
8constexpr uint32_t MakeFourCC(const char *fourcc)
9{
10 return fourcc[0] | (fourcc[1] << 8) | (fourcc[2] << 16) | (fourcc[3] << 24);
11}
12
13enum 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
37static inline PixelFormat FourCCToPixelFormat(const std::string& fourcc)
38{
39 return (PixelFormat)MakeFourCC(fourcc.c_str());
40}
41
42static 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
52struct PixelFormatPlaneInfo
53{
54 uint8_t bitspp;
55 uint8_t xsub;
56 uint8_t ysub;
57};
58
59struct PixelFormatInfo
60{
61 uint8_t num_planes;
62 struct PixelFormatPlaneInfo planes[4];
63};
64
65const 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
5namespace kms
6{
7
8enum class PlaneType
9{
10 Overlay = 1 << 0,
11 Primary = 1 << 1,
12 Cursor = 1 << 2,
13};
14
15struct PlanePriv;
16
17class Plane : public DrmPropObject
18{
19 friend class Card;
20public:
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;
36private:
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
7namespace kms
8{
9
10struct PropertyPriv;
11
12enum class PropertyType
13{
14 Range,
15 Enum,
16 Blob,
17 Bitmask,
18 Object,
19 SignedRange,
20};
21
22class Property : public DrmObject
23{
24 friend class Card;
25public:
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;
35private:
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
9namespace kms
10{
11
12enum class SyncPolarity
13{
14 Undefined,
15 Positive,
16 Negative,
17};
18
19struct 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
55struct 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
14struct _drmModeAtomicReq;
15typedef struct _drmModeAtomicReq* drmModeAtomicReqPtr;
16
17static inline drmModeAtomicReqPtr drmModeAtomicAlloc() { return 0; }
18static inline void drmModeAtomicFree(drmModeAtomicReqPtr) { }
19static inline int drmModeAtomicAddProperty(drmModeAtomicReqPtr, uint32_t, uint32_t, uint64_t) { return 0; }
20static inline int drmModeAtomicCommit(int, drmModeAtomicReqPtr, int, void*) { return 0; }
21
22#endif // DRM_CLIENT_CAP_ATOMIC
23
24using namespace std;
25
26namespace kms
27{
28AtomicReq::AtomicReq(Card& card)
29 : m_card(card)
30{
31 assert(card.has_atomic());
32 m_req = drmModeAtomicAlloc();
33}
34
35AtomicReq::~AtomicReq()
36{
37 drmModeAtomicFree(m_req);
38}
39
40void 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
47void AtomicReq::add(DrmPropObject* ob, Property *prop, uint64_t value)
48{
49 add(ob->id(), prop->id(), value);
50}
51
52void AtomicReq::add(kms::DrmPropObject* ob, const string& prop, uint64_t value)
53{
54 add(ob, ob->get_prop(prop), value);
55}
56
57void 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
63void 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
88int 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
98int 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
108int 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
6using namespace std;
7
8namespace kms
9{
10
11Blob::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
17Blob::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
29Blob::~Blob()
30{
31 if (m_created)
32 drmModeDestroyPropertyBlob(card().fd(), id());
33}
34
35vector<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
14using namespace std;
15
16namespace kms
17{
18
19Card::Card()
20 : Card("/dev/dri/card0")
21{
22}
23
24
25Card::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
122Card::~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
135void Card::drop_master()
136{
137 drmDropMaster(fd());
138}
139
140void Card::restore_modes()
141{
142 for (auto conn : get_connectors())
143 conn->restore_mode();
144}
145
146Connector* 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
156DrmObject* 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
164const 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
172Connector* Card::get_connector(uint32_t id) const { return dynamic_cast<Connector*>(get_object(id)); }
173Crtc* Card::get_crtc(uint32_t id) const { return dynamic_cast<Crtc*>(get_object(id)); }
174Encoder* Card::get_encoder(uint32_t id) const { return dynamic_cast<Encoder*>(get_object(id)); }
175Property* Card::get_prop(uint32_t id) const { return dynamic_cast<Property*>(get_object(id)); }
176Plane* Card::get_plane(uint32_t id) const { return dynamic_cast<Plane*>(get_object(id)); }
177
178std::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
209static 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
218void 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
227int 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
11using namespace std;
12
13namespace kms
14{
15
16#ifndef DRM_MODE_CONNECTOR_DPI
17#define DRM_MODE_CONNECTOR_DPI 17
18#endif
19
20static 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
41static 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
48static 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
59struct ConnectorPriv
60{
61 drmModeConnectorPtr drm_connector;
62};
63
64Connector::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
80Connector::~Connector()
81{
82 drmModeFreeConnector(m_priv->drm_connector);
83 delete m_priv;
84}
85
86void 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
101void 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
114void Connector::restore_mode()
115{
116 if (m_saved_crtc)
117 m_saved_crtc->restore_mode(this);
118}
119
120Videomode 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
129Videomode 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
153Videomode 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
192bool 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
198vector<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
213Crtc* 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
221uint32_t Connector::connector_type() const
222{
223 return m_priv->drm_connector->connector_type;
224}
225
226uint32_t Connector::connector_type_id() const
227{
228 return m_priv->drm_connector->connector_type_id;
229}
230
231uint32_t Connector::mmWidth() const
232{
233 return m_priv->drm_connector->mmWidth;
234}
235
236uint32_t Connector::mmHeight() const
237{
238 return m_priv->drm_connector->mmHeight;
239}
240
241uint32_t Connector::subpixel() const
242{
243 return m_priv->drm_connector->subpixel;
244}
245
246const string& Connector::subpixel_str() const
247{
248 return subpix_str.at(subpixel());
249}
250
251std::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
262std::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
10using namespace std;
11
12namespace kms
13{
14
15struct CrtcPriv
16{
17 drmModeCrtcPtr drm_crtc;
18};
19
20Crtc::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
28Crtc::~Crtc()
29{
30 drmModeFreeCrtc(m_priv->drm_crtc);
31 delete m_priv;
32}
33
34void 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
42void 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
50void 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
61int 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
83int 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
93int Crtc::disable_mode()
94{
95 return drmModeSetCrtc(card().fd(), id(), 0, 0, 0, 0, 0, 0);
96}
97
98static inline uint32_t conv(float x)
99{
100 // XXX fix the conversion for fractional part
101 return ((uint32_t)x) << 16;
102}
103
104int 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
113int 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
118Plane* 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
138int Crtc::page_flip(Framebuffer& fb, void *data)
139{
140 return drmModePageFlip(card().fd(), id(), fb.id(), DRM_MODE_PAGE_FLIP_EVENT, data);
141}
142
143uint32_t Crtc::buffer_id() const
144{
145 return m_priv->drm_crtc->buffer_id;
146}
147
148uint32_t Crtc::x() const
149{
150 return m_priv->drm_crtc->x;
151}
152
153uint32_t Crtc::y() const
154{
155 return m_priv->drm_crtc->y;
156}
157
158uint32_t Crtc::width() const
159{
160 return m_priv->drm_crtc->width;
161}
162
163uint32_t Crtc::height() const
164{
165 return m_priv->drm_crtc->height;
166}
167
168int Crtc::mode_valid() const
169{
170 return m_priv->drm_crtc->mode_valid;
171}
172
173Videomode Crtc::mode() const
174{
175 return drm_mode_to_video_mode(m_priv->drm_crtc->mode);
176}
177
178int 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
10using namespace std;
11
12namespace kms
13{
14
15DrmObject::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
20DrmObject::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
25DrmObject::~DrmObject()
26{
27
28}
29
30void 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
10using namespace std;
11
12namespace kms
13{
14
15DrmPropObject::DrmPropObject(Card& card, uint32_t object_type)
16 : DrmObject(card, object_type)
17{
18}
19
20DrmPropObject::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
26DrmPropObject::~DrmPropObject()
27{
28
29}
30
31void 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
48Property* 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
60uint64_t DrmPropObject::get_prop_value(uint32_t id) const
61{
62 return m_prop_values.at(id);
63}
64
65uint64_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
76unique_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
83int 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
88int 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
17using namespace std;
18
19namespace kms
20{
21
22DumbFramebuffer::DumbFramebuffer(Card &card, uint32_t width, uint32_t height, const string& fourcc)
23 :DumbFramebuffer(card, width, height, FourCCToPixelFormat(fourcc))
24{
25}
26
27DumbFramebuffer::DumbFramebuffer(Card& card, uint32_t width, uint32_t height, PixelFormat format)
28 :Framebuffer(card, width, height), m_format(format)
29{
30 Create();
31}
32
33DumbFramebuffer::~DumbFramebuffer()
34{
35 Destroy();
36}
37
38void 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
80void 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
101uint8_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
124int 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
11using namespace std;
12
13namespace kms
14{
15
16struct EncoderPriv
17{
18 drmModeEncoderPtr drm_encoder;
19};
20
21static 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
34Encoder::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
42Encoder::~Encoder()
43{
44 drmModeFreeEncoder(m_priv->drm_encoder);
45 delete m_priv;
46}
47
48void 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
56Crtc* 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
64vector<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
80const 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
10using namespace std;
11
12namespace kms
13{
14
15ExtFramebuffer::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
45ExtFramebuffer::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
82ExtFramebuffer::~ExtFramebuffer()
83{
84 drmModeRmFB(card().fd(), id());
85}
86
87uint8_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
105int 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
10using namespace std;
11
12namespace kms
13{
14
15Framebuffer::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
21Framebuffer::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
38void 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
48Framebuffer::~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
8namespace kms
9{
10Videomode 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
41drmModeModeInfo 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
6namespace kms
7{
8struct Videomode;
9
10Videomode drm_mode_to_video_mode(const drmModeModeInfo& drmmode);
11drmModeModeInfo 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
6using namespace std;
7
8namespace kms
9{
10
11static float CELL_GRAN = 8;
12static float CELL_GRAN_RND = round(CELL_GRAN);
13
14struct 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
27static 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
40static 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
53Videomode 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
7using namespace std;
8
9namespace kms
10{
11
12static 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
49const 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
54const 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
36namespace 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 */
52const 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
7namespace 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
23const 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),