Mark ab/7061308 as merged in stage.

Bug: 180401296
Merged-In: Ie0f77abf4416296aef54b2519f5ec1db072b4fe9
Change-Id: I1142f68e04f3581b3fe39e9f83018ef5f10ff689
diff --git a/.gitignore b/.gitignore
index 0d16660..35f030e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,5 @@
 py/__pycache__
 *.pyc
 meson.build.user
+subprojects/packagecache/
+subprojects/pybind11-*/
diff --git a/.gitmodules b/.gitmodules
index 6ac367e..e69de29 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +0,0 @@
-[submodule "ext/pybind11"]
-	path = ext/pybind11
-	url = https://github.com/pybind/pybind11.git
-[submodule "ext/fmt"]
-	path = ext/fmt
-	url = https://github.com/fmtlib/fmt.git
diff --git a/.travis.yml b/.travis.yml
index a487fc3..b311750 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -24,6 +24,7 @@
       - libevdev-dev
       - meson
       - ninja-build
+      - libfmt-dev
 
 # Need MYCC and MYCXX as travis overwrites CC and CXX
 
diff --git a/Android.bp b/Android.bp
index 100ff92..10dc301 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,6 +12,38 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["external_libkmsxx_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+// See: http://go/android-license-faq
+license {
+    name: "external_libkmsxx_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-BSD",
+        "SPDX-license-identifier-MIT",
+        "SPDX-license-identifier-MPL",
+        "SPDX-license-identifier-MPL-2.0",
+    ],
+    license_text: [
+        "LICENSE",
+    ],
+}
+
 cc_library_shared {
     name: "libkmsxx",
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 100644
index 8af9b9c..0000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1,100 +0,0 @@
-cmake_minimum_required(VERSION 2.8)
-project(kms++)
-
-include(LTO.cmake)
-
-set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
-
-include(CheckCXXCompilerFlag)
-
-IF(NOT CMAKE_BUILD_TYPE)
-    message(STATUS "Setting build type to 'Release' as none was specified.")
-    SET(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
-    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
-ENDIF()
-
-string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
-
-option(BUILD_SHARED_LIBS "Build shared libs" FALSE)
-option(TREAT_WARNINGS_AS_ERRORS "Treat warnings as errors" FALSE)
-
-set(KMSXX_ENABLE_PYTHON ON CACHE BOOL "Enable Python wrappers")
-set(KMSXX_PYTHON_VERSION "python3" CACHE STRING "Python pkgconfig package")
-
-set(KMSXX_ENABLE_KMSCUBE OFF CACHE BOOL "Enable kmscube")
-
-set(KMSXX_ENABLE_THREADING ON CACHE BOOL "Enable threading for parallelized drawing")
-set(KMSXX_ENABLE_LIBDRMOMAP ON CACHE BOOL "Enable OMAP-specific extensions")
-
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wno-unused-parameter")
-
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wno-unused-parameter")
-
-if (CMAKE_COMPILER_IS_GNUCC)
-    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
-        # GCC 4.x seems to warn too much
-        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-field-initializers")
-    endif()
-endif()
-
-# HACK: cmake always adds "-rdynamic", this removes it
-SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
-SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
-
-set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
-
-if (TREAT_WARNINGS_AS_ERRORS)
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
-endif()
-
-# static link libc
-# set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
-
-check_lto()
-
-if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
-    if (LTO_WORKS)
-        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto")
-        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
-        set(CMAKE_AR "${LTO_AR}")
-        set(CMAKE_RANLIB "${LTO_RANLIB}")
-    endif()
-endif()
-
-find_package(PkgConfig REQUIRED)
-pkg_check_modules(LIBDRM libdrm>=2.4.71 REQUIRED)
-
-if (KMSXX_ENABLE_LIBDRMOMAP)
-    pkg_check_modules(LIBDRM_OMAP libdrm_omap)
-else()
-    set(LIBDRM_OMAP_FOUND FALSE)
-endif()
-
-if(LIBDRM_OMAP_FOUND)
-    add_definitions(-DHAS_LIBDRM_OMAP)
-endif()
-
-pkg_check_modules(LIBEVDEV libevdev)
-
-enable_testing()
-
-add_subdirectory(kms++)
-add_subdirectory(kms++util)
-add_subdirectory(utils)
-
-add_subdirectory(ext/fmt)
-
-if(KMSXX_ENABLE_KMSCUBE)
-	add_subdirectory(kmscube)
-endif()
-
-if(KMSXX_ENABLE_PYTHON)
-        add_subdirectory(py)
-endif()
-
-add_custom_target(docs SOURCES "README.md")
diff --git a/LTO.cmake b/LTO.cmake
deleted file mode 100644
index 9a18d77..0000000
--- a/LTO.cmake
+++ /dev/null
@@ -1,32 +0,0 @@
-function(check_lto)
-    if (DEFINED LTO_WORKS)
-        return()
-    endif()
-
-    set(LTO_WORKS FALSE CACHE INTERNAL "LTO works")
-
-    CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
-
-    if (NOT HAS_LTO_FLAG)
-        return()
-    endif()
-
-    find_program(LTO_AR NAMES "${CMAKE_C_COMPILER}-ar" gcc-ar)
-    find_program(LTO_RANLIB NAMES "${CMAKE_C_COMPILER}-ranlib" gcc-ranlib)
-
-    if (NOT LTO_AR OR NOT LTO_RANLIB)
-        return()
-    endif()
-
-    EXECUTE_PROCESS(COMMAND "${LTO_AR}" --version RESULT_VARIABLE ret OUTPUT_QUIET ERROR_QUIET)
-    if (ret)
-        return()
-    endif()
-
-    EXECUTE_PROCESS(COMMAND "${LTO_RANLIB}" --version RESULT_VARIABLE ret OUTPUT_QUIET ERROR_QUIET)
-    if (ret)
-        return()
-    endif()
-
-    set(LTO_WORKS TRUE CACHE INTERNAL "LTO works")
-endfunction()
diff --git a/METADATA b/METADATA
index eea008e..f2c8934 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@
     type: GIT
     value: "https://github.com/tomba/kmsxx"
   }
-  version: "6fa8696774c4bda4bb7e3efabd7e1e58a899f5c1"
+  version: "b12aab5d4bb45e77934d9838576a817bc8defe4b"
   license_type: RECIPROCAL
   last_upgrade_date {
-    year: 2020
-    month: 12
-    day: 1
+    year: 2021
+    month: 1
+    day: 5
   }
 }
diff --git a/ext/fmt b/ext/fmt
deleted file mode 160000
index 7512a55..0000000
--- a/ext/fmt
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 7512a55aa3ae309587ca89668ef9ec4074a51a1f
diff --git a/ext/pybind11 b/ext/pybind11
deleted file mode 160000
index 9a19306..0000000
--- a/ext/pybind11
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 9a19306fbf30642ca331d0ec88e7da54a96860f9
diff --git a/kms++/CMakeLists.txt b/kms++/CMakeLists.txt
deleted file mode 100644
index 6e21fa5..0000000
--- a/kms++/CMakeLists.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-include_directories(${LIBDRM_INCLUDE_DIRS})
-link_directories(${LIBDRM_LIBRARY_DIRS})
-
-include_directories(${LIBDRM_OMAP_INCLUDE_DIRS})
-link_directories(${LIBDRM_OMAP_LIBRARY_DIRS})
-
-file(GLOB SRCS "src/*.cpp" "src/*.h")
-file(GLOB PUB_HDRS "inc/kms++/*.h")
-
-if(LIBDRM_OMAP_FOUND)
-    file(GLOB OMAP_SRCS "src/omap/*.cpp" "src/omap/*.h")
-    file(GLOB OMAP_PUB_HDRS "inc/kms++/omap/*.h")
-
-    set(SRCS ${SRCS} ${OMAP_SRCS})
-    set(PUB_HDRS ${PUB_HDRS} ${OMAP_PUB_HDRS})
-endif()
-
-add_library(kms++ ${SRCS} ${PUB_HDRS})
-
-target_include_directories(kms++ PUBLIC
-    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
-    $<INSTALL_INTERFACE:include>
-    PRIVATE src)
-
-target_link_libraries(kms++ ${LIBDRM_LIBRARIES} ${LIBDRM_OMAP_LIBRARIES} fmt::fmt-header-only)
-
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/kms++.pc.in ${CMAKE_CURRENT_BINARY_DIR}/kms++.pc @ONLY)
-
-# Set a dummy SOVERSION just to avoid having a naked .so file in the filesystem.
-# This version number doesn't make any promise about API/ABI stability.
-set_target_properties(kms++ PROPERTIES
-    PUBLIC_HEADER "${PUB_HDRS}"
-    SOVERSION 0)
-
-install(TARGETS kms++
-    LIBRARY DESTINATION lib
-    ARCHIVE DESTINATION lib
-    PUBLIC_HEADER DESTINATION include/kms++)
-
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kms++.pc
-    DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
diff --git a/kms++/inc/kms++/crtc.h b/kms++/inc/kms++/crtc.h
index 1ba8a07..cf64a86 100644
--- a/kms++/inc/kms++/crtc.h
+++ b/kms++/inc/kms++/crtc.h
@@ -39,7 +39,8 @@
 	uint32_t height() const;
 	int mode_valid() const;
 	Videomode mode() const;
-	int gamma_size() const;
+	int legacy_gamma_size() const;
+	void legacy_gamma_set(std::vector<std::tuple<uint16_t, uint16_t, uint16_t>> v);
 
 private:
 	Crtc(Card& card, uint32_t id, uint32_t idx);
diff --git a/kms++/kms++.pc.in b/kms++/kms++.pc.in
deleted file mode 100644
index 60b5974..0000000
--- a/kms++/kms++.pc.in
+++ /dev/null
@@ -1,10 +0,0 @@
-prefix=@CMAKE_INSTALL_PREFIX@
-exec_prefix=@CMAKE_INSTALL_PREFIX@
-libdir=@CMAKE_INSTALL_PREFIX@/lib
-includedir=@CMAKE_INSTALL_PREFIX@/include
-
-Name: kms++
-Description: C++ library for Linux kernel mode setting
-Version: 0.0.0
-Libs: -L${libdir} -lkms++
-Cflags: -I${includedir}
diff --git a/kms++/src/atomicreq.cpp b/kms++/src/atomicreq.cpp
index e01d7c2..1ef4f7d 100644
--- a/kms++/src/atomicreq.cpp
+++ b/kms++/src/atomicreq.cpp
@@ -62,7 +62,12 @@
 
 void AtomicReq::add(kms::DrmPropObject* ob, const string& prop, uint64_t value)
 {
-	add(ob, ob->get_prop(prop), value);
+	Property* p = ob->get_prop(prop);
+
+	if (!p)
+		throw runtime_error("Property not found");
+
+	add(ob, p, value);
 }
 
 void AtomicReq::add(kms::DrmPropObject* ob, const map<string, uint64_t>& values)
diff --git a/kms++/src/crtc.cpp b/kms++/src/crtc.cpp
index 6dc4333..1c1888f 100644
--- a/kms++/src/crtc.cpp
+++ b/kms++/src/crtc.cpp
@@ -173,9 +173,25 @@
 	return drm_mode_to_video_mode(m_priv->drm_crtc->mode);
 }
 
-int Crtc::gamma_size() const
+int Crtc::legacy_gamma_size() const
 {
 	return m_priv->drm_crtc->gamma_size;
 }
 
+void Crtc::legacy_gamma_set(vector<tuple<uint16_t, uint16_t, uint16_t>> v)
+{
+	uint32_t len = v.size();
+	uint16_t red[len];
+	uint16_t green[len];
+	uint16_t blue[len];
+
+	for (uint32_t i = 0; i < len; ++i) {
+		red[i] = get<0>(v[i]);
+		green[i] = get<1>(v[i]);
+		blue[i] = get<2>(v[i]);
+	}
+
+	drmModeCrtcSetGamma(card().fd(), id(), len, red, green, blue);
+}
+
 } // namespace kms
diff --git a/kms++util/CMakeLists.txt b/kms++util/CMakeLists.txt
deleted file mode 100644
index 0bfb56b..0000000
--- a/kms++util/CMakeLists.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-file(GLOB SRCS "src/*.cpp" "src/*.h")
-file(GLOB PUB_HDRS "inc/kms++util/*.h")
-add_library(kms++util ${SRCS} ${PUB_HDRS})
-
-target_include_directories(kms++util PUBLIC
-    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
-    $<INSTALL_INTERFACE:include>
-    PRIVATE src)
-
-target_link_libraries(kms++util kms++)
-
-if (KMSXX_ENABLE_THREADING)
-    target_link_libraries(kms++util pthread)
-    add_definitions(-DHAS_PTHREAD)
-endif()
-
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/kms++util.pc.in ${CMAKE_CURRENT_BINARY_DIR}/kms++util.pc @ONLY)
-
-# Set a dummy SOVERSION just to avoid havig a naked .so file in the filesystem.
-# This version number doesn't make any promise about API/ABI stability.
-set_target_properties(kms++util PROPERTIES
-    PUBLIC_HEADER "${PUB_HDRS}"
-    SOVERSION 0)
-
-install(TARGETS kms++util
-    LIBRARY DESTINATION lib
-    ARCHIVE DESTINATION lib
-    PUBLIC_HEADER DESTINATION include/kms++util)
-
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kms++util.pc
-    DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
diff --git a/kms++util/kms++util.pc.in b/kms++util/kms++util.pc.in
deleted file mode 100644
index b90df89..0000000
--- a/kms++util/kms++util.pc.in
+++ /dev/null
@@ -1,11 +0,0 @@
-prefix=@CMAKE_INSTALL_PREFIX@
-exec_prefix=@CMAKE_INSTALL_PREFIX@
-libdir=@CMAKE_INSTALL_PREFIX@/lib
-includedir=@CMAKE_INSTALL_PREFIX@/include
-
-Name: kms++
-Description: C++ library for Linux kernel mode setting
-Version: 0.0.0
-Requires: kms++
-Libs: -L${libdir} -lkms++util
-Cflags: -I${includedir}
diff --git a/kmscube/CMakeLists.txt b/kmscube/CMakeLists.txt
deleted file mode 100644
index 9df43c0..0000000
--- a/kmscube/CMakeLists.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-
-pkg_check_modules(GLESv2 glesv2 REQUIRED)
-pkg_check_modules(EGL egl REQUIRED)
-pkg_check_modules(GBM gbm REQUIRED)
-pkg_check_modules(X11 x11 REQUIRED)
-pkg_check_modules(XCB xcb REQUIRED)
-pkg_check_modules(X11XCB x11-xcb REQUIRED)
-pkg_check_modules(WL wayland-client REQUIRED)
-pkg_check_modules(WL_EGL wayland-egl REQUIRED)
-
-
-include_directories(
-    ${LIBDRM_INCLUDE_DIRS}
-    ${GLESv2_INCLUDE_DIRS}
-    ${EGL_INCLUDE_DIRS}
-    ${GBM_INCLUDE_DIRS}
-    ${X11_INCLUDE_DIRS}
-    ${XCB_INCLUDE_DIRS}
-    ${X11XCB_INCLUDE_DIRS}
-)
-
-link_directories(
-    ${LIBDRM_LIBRARY_DIRS}
-    ${GLESv2_LIBRARY_DIRS}
-    ${EGL_LIBRARY_DIRS}
-    ${GBM_LIBRARY_DIRS}
-    ${X11_LIBRARY_DIRS}
-    ${XCB_LIBRARY_DIRS}
-    ${X11XCB_LIBRARY_DIRS}
-)
-
-add_executable (kmscube cube.cpp cube.h cube-egl.cpp cube-egl.h cube-gles2.cpp cube-gles2.h
-    cube-null.cpp cube-gbm.cpp cube-x11.cpp cube-wl.cpp
-    esTransform.cpp esTransform.h)
-target_link_libraries(kmscube kms++ kms++util
-    ${LIBDRM_LIBRARIES}
-    ${GLESv2_LIBRARIES}
-    ${EGL_LIBRARIES}
-    ${GBM_LIBRARIES}
-    ${X11_LIBRARIES}
-    ${XCB_LIBRARIES}
-    ${X11XCB_LIBRARIES}
-    ${WL_LIBRARIES}
-    ${WL_EGL_LIBRARIES}
-)
diff --git a/meson.build b/meson.build
index 9652009..cdc8cab 100644
--- a/meson.build
+++ b/meson.build
@@ -31,19 +31,17 @@
 
 add_global_link_arguments(link_arguments, language : 'cpp')
 
-libfmt_includes = include_directories('ext/fmt/include')
-libfmt_dep = declare_dependency(include_directories : libfmt_includes,
-                                compile_args : '-DFMT_HEADER_ONLY')
-
-pybind11_includes = include_directories('ext/pybind11/include')
-pybind11_dep = declare_dependency(include_directories : pybind11_includes)
+libfmt_dep = dependency('fmt')
 
 libdrmomap_dep = dependency('libdrm_omap', required : get_option('omap'))
 
 subdir('kms++')
 
-if get_option('utils')
+if get_option('libutils')
     subdir('kms++util')
+endif
+
+if get_option('utils')
     subdir('utils')
 endif
 
diff --git a/meson_options.txt b/meson_options.txt
index cd854ab..d18988b 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,5 +1,20 @@
-option('kmscube', type : 'boolean', value : false)
-option('pykms', type : 'feature', value : 'auto')
-option('omap', type : 'feature', value : 'auto')
-option('static-libc', type : 'boolean', value : false)
-option('utils', type : 'boolean', value : true)
+option('omap', type : 'feature', value : 'auto',
+       description : 'Build omapdrm extensions')
+
+option('static-libc', type : 'boolean', value : false,
+       description : 'Build with -static-libgcc -static-libstdc++')
+
+option('libutils', type : 'boolean', value : true,
+       description : 'Build kms++utils library')
+
+option('utils', type : 'boolean', value : true,
+       description : 'Build an assortment of kms++ utils and tests')
+
+option('pykms', type : 'feature', value : 'auto',
+       description : 'Build python bindings')
+
+option('system-pybind11', type : 'feature', value : 'auto',
+       description : 'Use pybind11 from the system or from meson subproject')
+
+option('kmscube', type : 'boolean', value : false,
+       description : 'Build kmscube test application')
diff --git a/py/CMakeLists.txt b/py/CMakeLists.txt
deleted file mode 100644
index 77f19b4..0000000
--- a/py/CMakeLists.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-add_subdirectory(pykms)
-add_subdirectory(tests)
diff --git a/py/pykms/CMakeLists.txt b/py/pykms/CMakeLists.txt
deleted file mode 100644
index 505c0c3..0000000
--- a/py/pykms/CMakeLists.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-include_directories(${LIBDRM_INCLUDE_DIRS})
-link_directories(${LIBDRM_LIBRARY_DIRS})
-
-pkg_search_module(PYTHON REQUIRED ${KMSXX_PYTHON_VERSION})
-include_directories(${PYTHON_INCLUDE_DIRS})
-
-if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
-endif()
-
-include_directories(${PROJECT_SOURCE_DIR}/ext/pybind11/include)
-
-set(SRCS pykms.cpp pykmsbase.cpp pykmsutil.cpp pyvid.cpp)
-
-if(LIBDRM_OMAP_FOUND)
-    set(SRCS ${SRCS} pykmsomap.cpp)
-endif()
-
-add_library(pykms SHARED ${SRCS})
-target_link_libraries(pykms kms++ kms++util ${LIBDRM_LIBRARIES})
-
-# Don't add a 'lib' prefix to the shared library
-set_target_properties(pykms PROPERTIES PREFIX "")
-set_target_properties(pykms PROPERTIES LIBRARY_OUTPUT_DIRECTORY "")
-
-configure_file(__init__.py __init__.py COPYONLY)
-
-set(PY_DESTDIR lib/python${PYTHON_VERSION}/site-packages/pykms)
-install(FILES __init__.py DESTINATION ${PY_DESTDIR})
-install(TARGETS pykms DESTINATION ${PY_DESTDIR})
diff --git a/py/pykms/meson.build b/py/pykms/meson.build
index 518040b..b29cd9f 100644
--- a/py/pykms/meson.build
+++ b/py/pykms/meson.build
@@ -4,6 +4,15 @@
     subdir_done()
 endif
 
+if get_option('system-pybind11').enabled()
+    pybind11_dep = dependency('pybind11')
+elif get_option('system-pybind11').disabled()
+    pybind11_proj = subproject('pybind11')
+    pybind11_dep = pybind11_proj.get_variable('pybind11_dep')
+else
+    pybind11_dep = dependency('pybind11', fallback : ['pybind11', 'pybind11_dep'])
+endif
+
 pykms_sources = files([
     'pykmsbase.cpp',
     'pykms.cpp',
diff --git a/py/pykms/pykmsbase.cpp b/py/pykms/pykmsbase.cpp
index 43c2dfd..a963843 100644
--- a/py/pykms/pykmsbase.cpp
+++ b/py/pykms/pykmsbase.cpp
@@ -96,7 +96,9 @@
 		.def_property_readonly("mode", &Crtc::mode)
 		.def_property_readonly("mode_valid", &Crtc::mode_valid)
 		.def("__repr__", [](const Crtc& o) { return "<pykms.Crtc " + to_string(o.id()) + ">"; })
-		.def("refresh", &Crtc::refresh);
+		.def("refresh", &Crtc::refresh)
+		.def("legacy_gamma_size", &Crtc::legacy_gamma_size)
+		.def("legacy_gamma_set", &Crtc::legacy_gamma_set);
 
 	py::class_<Encoder, DrmPropObject, unique_ptr<Encoder, py::nodelete>>(m, "Encoder")
 		.def("refresh", &Encoder::refresh);
diff --git a/py/tests/CMakeLists.txt b/py/tests/CMakeLists.txt
deleted file mode 100644
index a670ed9..0000000
--- a/py/tests/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-file(GLOB PY_SRCS "*.py")
-add_custom_target(pyextras SOURCES ${PY_SRCS})
-
-add_test(NAME pytest COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/functest.py")
-set_property(TEST pytest PROPERTY
-        ENVIRONMENT "PYTHONPATH=." "LD_LIBRARY_PATH=."
-)
diff --git a/py/tests/gamma.py b/py/tests/gamma.py
index 5969b82..03499bc 100755
--- a/py/tests/gamma.py
+++ b/py/tests/gamma.py
@@ -1,14 +1,16 @@
 #!/usr/bin/python3
 
 import pykms
+import argparse
 
-# This hack makes drm initialize the fbcon, setting up the default connector
-card = pykms.Card()
-card = 0
+parser = argparse.ArgumentParser()
+parser.add_argument("-c", "--connector", default="")
+parser.add_argument("-l", "--legacy", action="store_true", default=False)
+args = parser.parse_args()
 
 card = pykms.Card()
 res = pykms.ResourceManager(card)
-conn = res.reserve_connector()
+conn = res.reserve_connector(args.connector)
 crtc = res.reserve_crtc(conn)
 mode = conn.get_default_mode()
 
@@ -17,24 +19,76 @@
 
 crtc.set_mode(conn, fb, mode)
 
-len=256
-arr = bytearray(len*2*4)
-view = memoryview(arr).cast("H")
+use_legacy = args.legacy
 
-for i in range(len):
-    g = round(65535 * pow(i / float(len), 1 / 2.2))
+if not use_legacy:
+	prop = crtc.get_prop("GAMMA_LUT")
 
-    view[i * 4 + 0] = g
-    view[i * 4 + 1] = g
-    view[i * 4 + 2] = g
-    view[i * 4 + 3] = 0
+	if not prop:
+		prop = crtc.get_prop("DEGAMMA_LUT")
 
-gamma = pykms.Blob(card, arr);
+		if not prop:
+			print("No gamma property found")
+			exit(-1)
+		else:
+			print("Using DEGAMMA_LUT for gamma")
 
-crtc.set_prop("GAMMA_LUT", gamma.id)
+
+def legacy_gamma_set():
+	len = crtc.legacy_gamma_size()
+
+	table = []
+
+	for i in range(len):
+	    g = round(65535 * pow(i / float(len), 1 / 2.2))
+	    table.append((g, g, g))
+
+	crtc.legacy_gamma_set(table)
+
+def legacy_gamma_clear():
+	len = crtc.legacy_gamma_size()
+
+	table = []
+
+	for i in range(len):
+	    g = round(65535 * (i / float(len)))
+	    table.append((g, g, g))
+
+	crtc.legacy_gamma_set(table)
+
+def gamma_set():
+	len=256
+	arr = bytearray(len*2*4)
+	view = memoryview(arr).cast("H")
+
+	for i in range(len):
+	    g = round(65535 * pow(i / float(len), 1 / 2.2))
+
+	    view[i * 4 + 0] = g
+	    view[i * 4 + 1] = g
+	    view[i * 4 + 2] = g
+	    view[i * 4 + 3] = 0
+
+	gamma = pykms.Blob(card, arr);
+
+	crtc.set_prop(prop, gamma.id)
+
+
+def gamma_clear():
+	crtc.set_prop(prop, 0)
+
+input("press enter to apply gamma\n")
+
+if use_legacy:
+	legacy_gamma_set()
+else:
+	gamma_set()
 
 input("press enter to remove gamma\n")
 
-crtc.set_prop("GAMMA_LUT", 0)
+if use_legacy:
+	legacy_gamma_clear()
+else:
+	gamma_clear()
 
 input("press enter to exit\n")
diff --git a/subprojects/pybind11.wrap b/subprojects/pybind11.wrap
new file mode 100644
index 0000000..38bc5f3
--- /dev/null
+++ b/subprojects/pybind11.wrap
@@ -0,0 +1,12 @@
+[wrap-file]
+directory = pybind11-2.6.0
+source_url = https://github.com/pybind/pybind11/archive/v2.6.0.zip
+source_filename = pybind11-2.6.0.zip
+source_hash = c2ed3fc84db08f40a36ce1d03331624ed6977497b35dfed36a1423396928559a
+patch_url = https://wrapdb.mesonbuild.com/v1/projects/pybind11/2.6.0/1/get_zip
+patch_filename = pybind11-2.6.0-1-wrap.zip
+patch_hash = dd52c46ccfdbca06b6967e89c9981408c6a3f4ed3d50c32b809f392b4ac5b0d2
+
+[provide]
+pybind11 = pybind11_dep
+
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
deleted file mode 100644
index d28527a..0000000
--- a/utils/CMakeLists.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-include_directories(${LIBDRM_INCLUDE_DIRS})
-link_directories(${LIBDRM_LIBRARY_DIRS})
-
-include_directories(${LIBEVDEV_INCLUDE_DIRS})
-link_directories(${LIBEVDEV_LIBRARY_DIRS})
-
-add_executable (kmstest kmstest.cpp)
-target_link_libraries(kmstest kms++ kms++util ${LIBDRM_LIBRARIES})
-
-add_executable (kmsview kmsview.cpp)
-target_link_libraries(kmsview kms++ kms++util ${LIBDRM_LIBRARIES})
-
-add_executable (kmsprint kmsprint.cpp)
-target_link_libraries(kmsprint kms++ kms++util ${LIBDRM_LIBRARIES})
-
-add_executable (fbtest fbtest.cpp)
-target_link_libraries(fbtest kms++util)
-
-add_executable (kmscapture kmscapture.cpp)
-target_link_libraries(kmscapture kms++ kms++util ${LIBDRM_LIBRARIES})
-
-add_executable (kmsblank kmsblank.cpp)
-target_link_libraries(kmsblank kms++ kms++util ${LIBDRM_LIBRARIES})
-
-if(LIBEVDEV_FOUND)
-    add_executable (kmstouch kmstouch.cpp)
-    target_link_libraries(kmstouch kms++ kms++util ${LIBDRM_LIBRARIES} ${LIBEVDEV_LIBRARIES})
-endif()
-
-add_executable (omap-wbcap omap-wbcap.cpp)
-target_link_libraries(omap-wbcap kms++ kms++util ${LIBDRM_LIBRARIES})
-
-add_executable (omap-wbm2m omap-wbm2m.cpp)
-target_link_libraries(omap-wbm2m kms++ kms++util ${LIBDRM_LIBRARIES})
-
-install(TARGETS kmstest kmsprint fbtest
-    DESTINATION bin)