mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	Compare commits
	
		
			519 commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
							 | 
						604fcdb1db | ||
| 
							 | 
						879243e370 | ||
| 
							 | 
						989cffe70d | ||
| 
							 | 
						3e08e3be4a | ||
| 
							 | 
						91f4890ec2 | ||
| 
							 | 
						74ce6c22a5 | ||
| 
							 | 
						0b58bddf13 | ||
| 
							 | 
						3d36ab9211 | ||
| 
							 | 
						d786e07899 | ||
| 
							 | 
						6d63871f05 | ||
| 
							 | 
						19c5d22beb | ||
| 
							 | 
						06275103f2 | ||
| 
							 | 
						03e7966650 | ||
| 
							 | 
						5529aae3e6 | ||
| 
							 | 
						6e1c8748ff | ||
| 
							 | 
						d8fb7adcf0 | ||
| 
							 | 
						c2d9ae2142 | ||
| 
							 | 
						6978509f64 | ||
| 
							 | 
						2252854297 | ||
| 
							 | 
						dde07b6840 | ||
| 
							 | 
						406aa5f7f5 | ||
| 
							 | 
						2ec4012559 | ||
| 
							 | 
						d039ad8da3 | ||
| 
							 | 
						3f0d338643 | ||
| 
							 | 
						60d72724cd | ||
| 
							 | 
						7cb3393e75 | ||
| 
							 | 
						26c1476827 | ||
| 
							 | 
						138210f01c | ||
| 
							 | 
						845a7a581d | ||
| 
							 | 
						108d94f798 | ||
| 
							 | 
						aaf82ee332 | ||
| 
							 | 
						d1c88e9497 | ||
| 
							 | 
						3e88a79e6f | ||
| 
							 | 
						b2d09cdee9 | ||
| 
							 | 
						35eba5f2fe | ||
| 
							 | 
						a91f96b391 | ||
| 
							 | 
						6fee3623e4 | ||
| 
							 | 
						7f6d66ea62 | ||
| 
							 | 
						54374b6fe6 | ||
| 
							 | 
						dd7f543189 | ||
| 
							 | 
						d7ae9a866b | ||
| 
							 | 
						462046ffdc | ||
| 
							 | 
						bd566225ea | ||
| 
							 | 
						b62c6878e1 | ||
| 
							 | 
						fd069ad4f2 | ||
| 
							 | 
						5e5842cb1a | ||
| 
							 | 
						cdd2c7e006 | ||
| 
							 | 
						905465b0fa | ||
| 
							 | 
						102a6bd415 | ||
| 
							 | 
						06aacb2a6f | ||
| 
							 | 
						0166fd9eb7 | ||
| 
							 | 
						423afc3fc9 | ||
| 
							 | 
						122310a2de | ||
| 
							 | 
						b799ffc6ae | ||
| 
							 | 
						e95117b700 | ||
| 
							 | 
						1a18e47efa | ||
| 
							 | 
						bbd9a49bdf | ||
| 
							 | 
						7bf5ff4c02 | ||
| 
							 | 
						b0c886ec77 | ||
| 
							 | 
						7431d840d0 | ||
| 
							 | 
						bb1f8673b3 | ||
| 
							 | 
						ad1b2f2819 | ||
| 
							 | 
						812675ba34 | ||
| 
							 | 
						7392b3313a | ||
| 
							 | 
						07e92fb868 | ||
| 
							 | 
						12316417b0 | ||
| 
							 | 
						dd3c63f5e6 | ||
| 
							 | 
						c8b7600adc | ||
| 
							 | 
						51a78cb0ed | ||
| 1beb25a1c8 | |||
| 
							 | 
						2f2c0dfcc6 | ||
| 
							 | 
						47a90d6f1a | ||
| 
							 | 
						db5e9ca04c | ||
| 
							 | 
						efb17980a8 | ||
| 
							 | 
						be5e266211 | ||
| 
							 | 
						80c7e0f772 | ||
| 
							 | 
						ccec4116b3 | ||
| 
							 | 
						d2007d7dc1 | ||
| 
							 | 
						a4eb2cff46 | ||
| 
							 | 
						eff620770c | ||
| 
							 | 
						f5dc6416f0 | ||
| 
							 | 
						c14aa1d0b8 | ||
| 
							 | 
						c39b3ce7a3 | ||
| 
							 | 
						f4327f52cf | ||
| 
							 | 
						6aa654b728 | ||
| 
							 | 
						31b78a4f3a | ||
| 
							 | 
						58c3680d96 | ||
| 
							 | 
						48bd1831fe | ||
| 
							 | 
						8c7041c4e8 | ||
| 
							 | 
						aecb867098 | ||
| 
							 | 
						bf40f396bf | ||
| 
							 | 
						2498036e67 | ||
| 
							 | 
						e76f8ac2b3 | ||
| 
							 | 
						6d8bb66f98 | ||
| 
							 | 
						f5e7caf599 | ||
| 
							 | 
						98af337175 | ||
| 
							 | 
						0c272a3842 | ||
| 
							 | 
						071773cb27 | ||
| 
							 | 
						ae85c31176 | ||
| 
							 | 
						fa1feb447f | ||
| 
							 | 
						a8144088df | ||
| 
							 | 
						3a51a5c623 | ||
| 
							 | 
						56d95c2ecb | ||
| 
							 | 
						ec422ac389 | ||
| 
							 | 
						7a1161438c | ||
| 
							 | 
						4efec11721 | ||
| 
							 | 
						8d1c6e42ac | ||
| 
							 | 
						b1a9dab03e | ||
| 
							 | 
						dd3d9be41e | ||
| 
							 | 
						c8d94000a6 | ||
| 
							 | 
						0ee0452af0 | ||
| 
							 | 
						f5a0992686 | ||
| 
							 | 
						7b6eec530c | ||
| 
							 | 
						b482e9089b | ||
| 
							 | 
						dc258b2237 | ||
| 
							 | 
						4470683591 | ||
| 
							 | 
						8430a1922d | ||
| 
							 | 
						f024d1b8c8 | ||
| 
							 | 
						e64de4d55f | ||
| 
							 | 
						f3524de980 | ||
| 
							 | 
						a5706e2fb9 | ||
| 
							 | 
						1df2274f6c | ||
| 
							 | 
						30c6efedf1 | ||
| 
							 | 
						2ea0e386c4 | ||
| 
							 | 
						a30c102163 | ||
| 
							 | 
						bfcb4211f6 | ||
| 
							 | 
						f10dd1da1c | ||
| 
							 | 
						97f6946c8d | ||
| 
							 | 
						74217a4d93 | ||
| 
							 | 
						3665b53e29 | ||
| 
							 | 
						9b97e2607d | ||
| 
							 | 
						d421538b4a | ||
| 
							 | 
						c6133f9912 | ||
| 
							 | 
						6204fc3278 | ||
| 
							 | 
						51d051497d | ||
| 
							 | 
						8713ac72fb | ||
| 
							 | 
						95b2771bfd | ||
| 
							 | 
						da820070f4 | ||
| 
							 | 
						b066fd6b5a | ||
| 
							 | 
						8fb4e4dabb | ||
| 
							 | 
						bb50c7a5a4 | ||
| 
							 | 
						221b37355f | ||
| 
							 | 
						37992cf3b8 | ||
| 
							 | 
						6c78225160 | ||
| 
							 | 
						83a5bdf5d5 | ||
| 
							 | 
						afe427d149 | ||
| 
							 | 
						a08acfcee0 | ||
| 
							 | 
						af43d3b9e7 | ||
| 
							 | 
						aaeffe9769 | ||
| 
							 | 
						fae4c5097d | ||
| 
							 | 
						170f7e0706 | ||
| 
							 | 
						2d5492c737 | ||
| 
							 | 
						536100488f | ||
| 
							 | 
						62c86fb975 | ||
| 
							 | 
						c2327248f8 | ||
| 
							 | 
						c9f0dbc159 | ||
| 
							 | 
						f04ef79f61 | ||
| 
							 | 
						13a62a23a2 | ||
| 
							 | 
						af34aaad53 | ||
| 
							 | 
						2420bfef0b | ||
| 
							 | 
						70add22e74 | ||
| 
							 | 
						f36f856cdb | ||
| 
							 | 
						aef4de2ced | ||
| 
							 | 
						e57dd9c5ef | ||
| 
							 | 
						d4e4c9f64b | ||
| 
							 | 
						22db307e4c | ||
| 
							 | 
						156d47c866 | ||
| 
							 | 
						80f33cd350 | ||
| 
							 | 
						7dd8fdf76c | ||
| 
							 | 
						648aee65ad | ||
| 
							 | 
						86976870bd | ||
| 
							 | 
						bd8454d3bc | ||
| 
							 | 
						e9450a9947 | ||
| 
							 | 
						78aaaaf7b6 | ||
| 
							 | 
						b9d3ee9a2c | ||
| 
							 | 
						7bf669fb5c | ||
| 
							 | 
						8dab5f838d | ||
| 
							 | 
						3ad4374a54 | ||
| 
							 | 
						ed2406621a | ||
| 
							 | 
						f8c639f19a | ||
| 
							 | 
						5fd43add1c | ||
| 
							 | 
						4277d8cfdc | ||
| 
							 | 
						867960d6f4 | ||
| 
							 | 
						d7527778bb | ||
| 
							 | 
						5dc73937ff | ||
| 
							 | 
						7161bcfabc | ||
| 
							 | 
						1e7baefe96 | ||
| 
							 | 
						9c9bf2efee | ||
| 
							 | 
						0bf0c55ad2 | ||
| 
							 | 
						c450991c4b | ||
| 
							 | 
						792bee9657 | ||
| 
							 | 
						5563d23b81 | ||
| 
							 | 
						709fc8fd8e | ||
| 
							 | 
						9c51424f8d | ||
| 
							 | 
						84fc6aaf5a | ||
| 
							 | 
						582f487b22 | ||
| 
							 | 
						5f65b1194c | ||
| 
							 | 
						fa6cd856e3 | ||
| 
							 | 
						95c85af87c | ||
| 
							 | 
						dcf38e3ea9 | ||
| 
							 | 
						ab4ed32c06 | ||
| 
							 | 
						6d4737a7f6 | ||
| 
							 | 
						0ab3c1d060 | ||
| 
							 | 
						10b8880fc7 | ||
| 
							 | 
						50537e2e6f | ||
| 
							 | 
						e11012a024 | ||
| 
							 | 
						7d076d0bc9 | ||
| 
							 | 
						156201fe71 | ||
| 
							 | 
						d8ad4809fc | ||
| 
							 | 
						420b60f203 | ||
| 
							 | 
						9dbf5b9f6b | ||
| 
							 | 
						99da6ccc87 | ||
| 
							 | 
						db2c907f93 | ||
| 
							 | 
						221bc5f6aa | ||
| 
							 | 
						128cd07e91 | ||
| 
							 | 
						ba7ac3efe5 | ||
| 
							 | 
						954dba3968 | ||
| 
							 | 
						50edd3a42d | ||
| 
							 | 
						31f9d6bb97 | ||
| 
							 | 
						94cb8e2bc7 | ||
| 
							 | 
						ca1f9f86e6 | ||
| 
							 | 
						08c74f36a9 | ||
| 
							 | 
						5175b6e94e | ||
| 
							 | 
						e752e3ec06 | ||
| 
							 | 
						a63e21d94c | ||
| 
							 | 
						3c76b93272 | ||
| 
							 | 
						3505079823 | ||
| 
							 | 
						a9542b9565 | ||
| 
							 | 
						602a00ec1f | ||
| 
							 | 
						66dfb7f49b | ||
| 
							 | 
						b13fe9b3a1 | ||
| 
							 | 
						35ff09a754 | ||
| 
							 | 
						90b5f0dde5 | ||
| 
							 | 
						e83b06e732 | ||
| 
							 | 
						c9d6339b60 | ||
| 
							 | 
						1380a48b4d | ||
| 
							 | 
						dc7dba8b1f | ||
| 
							 | 
						edd8df76d8 | ||
| 
							 | 
						16f607f008 | ||
| 
							 | 
						fef4f3637a | ||
| 
							 | 
						d305934ebe | ||
| 
							 | 
						714a0264a6 | ||
| 
							 | 
						a64e1a58b1 | ||
| 
							 | 
						83c5b15194 | ||
| 
							 | 
						a818251aec | ||
| 
							 | 
						0d056a0315 | ||
| 
							 | 
						639ca05d35 | ||
| 
							 | 
						c1eb053f5e | ||
| 
							 | 
						82223e451a | ||
| 
							 | 
						211eb9d60e | ||
| 
							 | 
						7d1f535e49 | ||
| 
							 | 
						9b55737cf5 | ||
| 
							 | 
						fa97f7f1f0 | ||
| 
							 | 
						1ee3ed4310 | ||
| 
							 | 
						1c2cb4c802 | ||
| 
							 | 
						4f6dd01e5a | ||
| 
							 | 
						980ac9e4c8 | ||
| 
							 | 
						b25f98d583 | ||
| 
							 | 
						f95270bb5e | ||
| 
							 | 
						c3224d4160 | ||
| 
							 | 
						e3596abc9a | ||
| 
							 | 
						9ab87167b5 | ||
| 
							 | 
						8f56f7ca43 | ||
| 
							 | 
						b03b05d2b3 | ||
| 
							 | 
						bcf8e467db | ||
| 
							 | 
						061aa1bd15 | ||
| 
							 | 
						6bb8bb1cb7 | ||
| 
							 | 
						82f9cd5310 | ||
| 
							 | 
						248e837cb3 | ||
| 
							 | 
						c0881bdc01 | ||
| 
							 | 
						08e14deeca | ||
| 
							 | 
						855b3fd607 | ||
| 
							 | 
						c24efad6df | ||
| 
							 | 
						4e4155ccbe | ||
| 
							 | 
						6712e774d4 | ||
| 
							 | 
						dadcbf65e6 | ||
| 
							 | 
						eb85831284 | ||
| 
							 | 
						a231bf7f62 | ||
| 
							 | 
						4a67628cb0 | ||
| 
							 | 
						62ecec6d53 | ||
| 
							 | 
						89000b7df0 | ||
| 
							 | 
						d5d650f9f6 | ||
| 
							 | 
						7963ba6a0d | ||
| 
							 | 
						5eed5d622d | ||
| 
							 | 
						38923826c3 | ||
| 
							 | 
						fa4d8bbad7 | ||
| 
							 | 
						6f6268988b | ||
| 
							 | 
						b908d865b1 | ||
| 
							 | 
						9fdffba170 | ||
| 
							 | 
						cfcf06b8b0 | ||
| 
							 | 
						24232e8e98 | ||
| 
							 | 
						b4ce0d8b39 | ||
| 
							 | 
						7cf8e80ffe | ||
| 
							 | 
						1c604207c6 | ||
| 
							 | 
						428279a319 | ||
| 
							 | 
						90530d43fe | ||
| 
							 | 
						be555a9a99 | ||
| 
							 | 
						c6de47d415 | ||
| 
							 | 
						bd3724aa26 | ||
| 
							 | 
						648c64b7e4 | ||
| 
							 | 
						41e2331843 | ||
| 
							 | 
						776f2c4e4d | ||
| 
							 | 
						b97106ddcb | ||
| 
							 | 
						2b4f30dc1d | ||
| 
							 | 
						546c5d000d | ||
| 
							 | 
						71943b3b1e | ||
| 
							 | 
						a7ebe7c026 | ||
| 
							 | 
						c7acfe906b | ||
| 
							 | 
						9649fbe443 | ||
| 
							 | 
						631e5be0d7 | ||
| 
							 | 
						be3d2b74cf | ||
| 
							 | 
						c6dd5e3c2e | ||
| 
							 | 
						2424b1ecdd | ||
| 
							 | 
						e21899037a | ||
| 
							 | 
						c0d4d7217b | ||
| 
							 | 
						3e651b4642 | ||
| 
							 | 
						9aca985865 | ||
| 
							 | 
						b2c3c371fc | ||
| 
							 | 
						0d6cc471e9 | ||
| 
							 | 
						24597bb971 | ||
| 
							 | 
						2ff95e5c97 | ||
| 
							 | 
						f233d25e86 | ||
| 
							 | 
						0b720ae5ea | ||
| 
							 | 
						85e2b662f1 | ||
| 
							 | 
						2c3053370c | ||
| 
							 | 
						e9a6b3b85d | ||
| 
							 | 
						ca29f43a54 | ||
| 
							 | 
						8e36040e88 | ||
| 
							 | 
						c3acef0dc0 | ||
| 
							 | 
						f440c60128 | ||
| 
							 | 
						0108506c77 | ||
| 
							 | 
						66ddd62e42 | ||
| 
							 | 
						b2bb111f03 | ||
| 
							 | 
						1dd05437bf | ||
| 
							 | 
						55f15d1abd | ||
| 
							 | 
						70d3635985 | ||
| 
							 | 
						014023c14f | ||
| 
							 | 
						c0945b6613 | ||
| 
							 | 
						4c4d74a564 | ||
| 
							 | 
						4ec1defb3e | ||
| 
							 | 
						baeecc8dbd | ||
| 
							 | 
						9e71c88467 | ||
| 
							 | 
						63fabecee2 | ||
| 
							 | 
						3f314bc183 | ||
| 
							 | 
						38fc4f2976 | ||
| 
							 | 
						81fa6c4b96 | ||
| 
							 | 
						cda6fdffac | ||
| 
							 | 
						2c098a3e45 | ||
| 
							 | 
						1f13bc72fe | ||
| 
							 | 
						0d728f96b7 | ||
| 
							 | 
						d6b47c3ab0 | ||
| 
							 | 
						8bb6935374 | ||
| 
							 | 
						c5d8f6d187 | ||
| 
							 | 
						3fdbfb0be8 | ||
| 
							 | 
						ea93dd5cc3 | ||
| 
							 | 
						3ca4bc8c09 | ||
| 
							 | 
						d835fa813f | ||
| 
							 | 
						ebab992b44 | ||
| 
							 | 
						c1ce983826 | ||
| 
							 | 
						1edd5e224f | ||
| 
							 | 
						0f255b46fc | ||
| 
							 | 
						3df1528a8f | ||
| 
							 | 
						1520be3c5c | ||
| 
							 | 
						3bbfae73ae | ||
| 
							 | 
						9351c78d70 | ||
| 
							 | 
						cf43a447cb | ||
| 
							 | 
						7717c92ed0 | ||
| 
							 | 
						4c74a8843a | ||
| 
							 | 
						e8e76dc295 | ||
| 
							 | 
						6006023a37 | ||
| 
							 | 
						e51ce333bc | ||
| 
							 | 
						0ba1982488 | ||
| 
							 | 
						da8f7a07ba | ||
| 
							 | 
						0d467ef9aa | ||
| 
							 | 
						527b77b445 | ||
| 
							 | 
						c87ab6465d | ||
| 
							 | 
						47fb00f66d | ||
| 
							 | 
						ba0cc8eb05 | ||
| 
							 | 
						7952658367 | ||
| 
							 | 
						3b3ed21e61 | ||
| 
							 | 
						402a862413 | ||
| 
							 | 
						1e949402b0 | ||
| 
							 | 
						785e340f01 | ||
| 
							 | 
						186bdc8da4 | ||
| 
							 | 
						514c4b4cce | ||
| 
							 | 
						8d8d5f5e94 | ||
| 
							 | 
						009515161b | ||
| 
							 | 
						f1b8937345 | ||
| 
							 | 
						b9f0b9c766 | ||
| 
							 | 
						831e7fc7ee | ||
| 
							 | 
						79e063035c | ||
| 
							 | 
						6202580b7b | ||
| 
							 | 
						502eb38d80 | ||
| 
							 | 
						fbafd8ed94 | ||
| 
							 | 
						9904f160af | ||
| 
							 | 
						b8418b7b91 | ||
| 
							 | 
						dd8f4913a4 | ||
| 
							 | 
						6ada67da9b | ||
| 
							 | 
						c9fe96102d | ||
| 
							 | 
						95d25d833f | ||
| 
							 | 
						7ce868bcf6 | ||
| 
							 | 
						ab118042ea | ||
| 
							 | 
						3da6fac1f2 | ||
| 
							 | 
						d55c175777 | ||
| 
							 | 
						a8d1e5273a | ||
| 
							 | 
						56d69320c7 | ||
| 
							 | 
						c752270be7 | ||
| 
							 | 
						7debaced03 | ||
| 
							 | 
						bf0cac12a3 | ||
| 
							 | 
						04525e6f82 | ||
| 
							 | 
						96ad414ec9 | ||
| 
							 | 
						9f7ab85718 | ||
| 
							 | 
						1a7981f7c9 | ||
| 
							 | 
						234d31f138 | ||
| 
							 | 
						beb9a9ad0a | ||
| 
							 | 
						0db4df4c8e | ||
| 
							 | 
						0d6284eb62 | ||
| 
							 | 
						d7223eae02 | ||
| 
							 | 
						3187479c07 | ||
| 
							 | 
						fa2abbeefb | ||
| 
							 | 
						a5aae69b2a | ||
| 
							 | 
						52afedadea | ||
| 
							 | 
						52dce29e06 | ||
| 
							 | 
						5432108846 | ||
| 
							 | 
						5f3b99bbed | ||
| 
							 | 
						1e03719361 | ||
| 
							 | 
						0bf642d246 | ||
| 
							 | 
						d2a5dbe104 | ||
| 
							 | 
						43554c1966 | ||
| 
							 | 
						cf93d31736 | ||
| 
							 | 
						bfcaa4bc44 | ||
| 
							 | 
						eebaca8dbf | ||
| 
							 | 
						62cc96b3a4 | ||
| 
							 | 
						098cb9b7a3 | ||
| 
							 | 
						8582b45c9e | ||
| 
							 | 
						3d2f09bace | ||
| 
							 | 
						b4f077a596 | ||
| 
							 | 
						3048fb3fc6 | ||
| 
							 | 
						5df2b34d2b | ||
| 
							 | 
						ccd4703207 | ||
| 
							 | 
						a0450d219f | ||
| 
							 | 
						270e6f4ebb | ||
| 
							 | 
						e88988e364 | ||
| 
							 | 
						310a5eb61c | ||
| 
							 | 
						08495d2596 | ||
| 
							 | 
						3103ea3af9 | ||
| 
							 | 
						ee21deb458 | ||
| 
							 | 
						baaec88e2f | ||
| 
							 | 
						4da4269d8f | ||
| 
							 | 
						5c98d1a04a | ||
| 
							 | 
						a1298580cc | ||
| 
							 | 
						515275ee72 | ||
| 
							 | 
						23202e192c | ||
| 
							 | 
						2463a4723e | ||
| 
							 | 
						291df10fe5 | ||
| 
							 | 
						235c8e922a | ||
| 
							 | 
						70c99460ca | ||
| 
							 | 
						4f1104654f | ||
| 
							 | 
						14e1987f50 | ||
| 
							 | 
						3e1358fec9 | ||
| 
							 | 
						147c5c37e3 | ||
| 
							 | 
						78dfa4f06d | ||
| 
							 | 
						c52e01e85f | ||
| 
							 | 
						6c8eabcecd | ||
| 
							 | 
						2c64f36e88 | ||
| 
							 | 
						e6dbe4580e | ||
| 
							 | 
						adf9d8b0be | ||
| 
							 | 
						e209fe2d05 | ||
| 
							 | 
						3cae2a2c01 | ||
| 
							 | 
						6214144735 | ||
| 
							 | 
						71cc47b859 | ||
| 
							 | 
						08e779bd85 | ||
| 
							 | 
						0a388a14f1 | ||
| 
							 | 
						20997df416 | ||
| 
							 | 
						df4a1d94e2 | ||
| 
							 | 
						1c7e1bcc28 | ||
| 
							 | 
						14446216f4 | ||
| 
							 | 
						1133bc15ce | ||
| 
							 | 
						66d96d244c | ||
| 
							 | 
						823a64bf7d | ||
| 
							 | 
						4b4ca11f6f | ||
| 
							 | 
						8730ca9661 | ||
| 
							 | 
						775817e278 | ||
| 
							 | 
						738bbf01ee | ||
| 
							 | 
						5f88635118 | ||
| 
							 | 
						9e9636f675 | ||
| 
							 | 
						850dd7a792 | ||
| 
							 | 
						c7035da5e2 | ||
| 
							 | 
						48f0902a36 | ||
| 
							 | 
						edb867bc05 | ||
| 
							 | 
						5552de65f8 | ||
| 
							 | 
						3067e45c2e | ||
| 
							 | 
						1ad42bea99 | ||
| 
							 | 
						d2374b3e4e | ||
| 
							 | 
						19ffbfe356 | ||
| 
							 | 
						a1635fdb76 | ||
| 
							 | 
						4481c6b243 | ||
| 
							 | 
						6261bd9684 | ||
| 
							 | 
						d400b4587a | ||
| 
							 | 
						42df9414fb | ||
| 
							 | 
						7e13dfdd4d | ||
| 
							 | 
						ceb4fcedca | ||
| 
							 | 
						f9199bb6d4 | ||
| 
							 | 
						5083efe18b | ||
| 
							 | 
						eb5312022a | ||
| 
							 | 
						aa1163e640 | ||
| 
							 | 
						de574ac098 | ||
| 
							 | 
						42673a2821 | ||
| 
							 | 
						cd2cf1bafb | ||
| 
							 | 
						f16a3c1180 | ||
| 
							 | 
						015bb8512e | ||
| 
							 | 
						7550e483ae | ||
| 
							 | 
						2a8a23c467 | ||
| 
							 | 
						179ed7c296 | ||
| 
							 | 
						22adc65586 | ||
| 
							 | 
						e17916d413 | ||
| 
							 | 
						d3b7e040af | ||
| 
							 | 
						5ecbd23c1d | ||
| 
							 | 
						b10516e1e8 | 
					 323 changed files with 13441 additions and 3617 deletions
				
			
		| 
						 | 
					@ -20,8 +20,13 @@ packages:
 | 
				
			||||||
  - xwayland-dev
 | 
					  - xwayland-dev
 | 
				
			||||||
  - libseat-dev
 | 
					  - libseat-dev
 | 
				
			||||||
  - hwdata-dev
 | 
					  - hwdata-dev
 | 
				
			||||||
 | 
					  # for docs
 | 
				
			||||||
 | 
					  - go
 | 
				
			||||||
 | 
					  - zip
 | 
				
			||||||
sources:
 | 
					sources:
 | 
				
			||||||
  - https://gitlab.freedesktop.org/wlroots/wlroots.git
 | 
					  - https://gitlab.freedesktop.org/wlroots/wlroots.git
 | 
				
			||||||
 | 
					artifacts:
 | 
				
			||||||
 | 
					  - public.zip
 | 
				
			||||||
tasks:
 | 
					tasks:
 | 
				
			||||||
  - setup: |
 | 
					  - setup: |
 | 
				
			||||||
      cd wlroots
 | 
					      cd wlroots
 | 
				
			||||||
| 
						 | 
					@ -37,3 +42,16 @@ tasks:
 | 
				
			||||||
  - tinywl: |
 | 
					  - tinywl: |
 | 
				
			||||||
      cd wlroots/tinywl
 | 
					      cd wlroots/tinywl
 | 
				
			||||||
      make
 | 
					      make
 | 
				
			||||||
 | 
					  - docs: |
 | 
				
			||||||
 | 
					      go install 'codeberg.org/emersion/gyosu@latest'
 | 
				
			||||||
 | 
					      include_dir="$(echo /usr/local/include/wlroots-*)"
 | 
				
			||||||
 | 
					      ~/go/bin/gyosu \
 | 
				
			||||||
 | 
					        -DWLR_USE_UNSTABLE \
 | 
				
			||||||
 | 
					        $(pkg-config --cflags-only-I $(basename "$include_dir")) \
 | 
				
			||||||
 | 
					        -Iwlroots/build/protocol/ \
 | 
				
			||||||
 | 
					        -fexported-symbols='wlr_*' -fexported-symbols='WLR_*' \
 | 
				
			||||||
 | 
					        -ffile-prefix-map="$include_dir/"= \
 | 
				
			||||||
 | 
					        -fsite-name=wlroots \
 | 
				
			||||||
 | 
					        -o public \
 | 
				
			||||||
 | 
					        "$include_dir/wlr/"
 | 
				
			||||||
 | 
					      zip -r ~/public.zip public/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,9 +41,10 @@ tasks:
 | 
				
			||||||
      cd wlroots/build-gcc/tinywl
 | 
					      cd wlroots/build-gcc/tinywl
 | 
				
			||||||
      sudo modprobe vkms
 | 
					      sudo modprobe vkms
 | 
				
			||||||
      udevadm settle
 | 
					      udevadm settle
 | 
				
			||||||
 | 
					      card="/dev/dri/$(ls /sys/devices/faux/vkms/drm/ | grep ^card)"
 | 
				
			||||||
      export WLR_BACKENDS=drm
 | 
					      export WLR_BACKENDS=drm
 | 
				
			||||||
      export WLR_RENDERER=pixman
 | 
					      export WLR_RENDERER=pixman
 | 
				
			||||||
      export WLR_DRM_DEVICES=/dev/dri/by-path/platform-vkms-card
 | 
					      export WLR_DRM_DEVICES="$card"
 | 
				
			||||||
      export UBSAN_OPTIONS=halt_on_error=1
 | 
					      export UBSAN_OPTIONS=halt_on_error=1
 | 
				
			||||||
      sudo chmod ugo+rw /dev/dri/by-path/platform-vkms-card
 | 
					      sudo chmod ugo+rw "$card"
 | 
				
			||||||
      sudo -E seatd-launch -- ./tinywl -s 'kill $PPID' || [ $? = 143 ]
 | 
					      sudo -E seatd-launch -- ./tinywl -s 'kill $PPID' || [ $? = 143 ]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,16 +23,15 @@ packages:
 | 
				
			||||||
  - x11-servers/xwayland
 | 
					  - x11-servers/xwayland
 | 
				
			||||||
  - sysutils/libdisplay-info
 | 
					  - sysutils/libdisplay-info
 | 
				
			||||||
  - sysutils/seatd
 | 
					  - sysutils/seatd
 | 
				
			||||||
  - gmake
 | 
					 | 
				
			||||||
  - hwdata
 | 
					  - hwdata
 | 
				
			||||||
sources:
 | 
					sources:
 | 
				
			||||||
  - https://gitlab.freedesktop.org/wlroots/wlroots.git
 | 
					  - https://gitlab.freedesktop.org/wlroots/wlroots.git
 | 
				
			||||||
tasks:
 | 
					tasks:
 | 
				
			||||||
  - wlroots: |
 | 
					  - wlroots: |
 | 
				
			||||||
      cd wlroots
 | 
					      cd wlroots
 | 
				
			||||||
      meson setup build --fatal-meson-warnings -Dauto_features=enabled
 | 
					      meson setup build --fatal-meson-warnings -Dauto_features=enabled -Dallocators=gbm
 | 
				
			||||||
      ninja -C build
 | 
					      ninja -C build
 | 
				
			||||||
      sudo ninja -C build install
 | 
					      sudo ninja -C build install
 | 
				
			||||||
  - tinywl: |
 | 
					  - tinywl: |
 | 
				
			||||||
      cd wlroots/tinywl
 | 
					      cd wlroots/tinywl
 | 
				
			||||||
      gmake
 | 
					      make
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1 +1,2 @@
 | 
				
			||||||
/subprojects/
 | 
					/subprojects/*
 | 
				
			||||||
 | 
					!/subprojects/*.wrap
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
include: https://git.sr.ht/~emersion/dalligi/blob/master/templates/multi.yml
 | 
					include: https://git.sr.ht/~emersion/dalligi/blob/master/templates/multi.yml
 | 
				
			||||||
alpine:
 | 
					alpine:
 | 
				
			||||||
  extends: .dalligi
 | 
					  extends: .dalligi
 | 
				
			||||||
 | 
					  pages: true
 | 
				
			||||||
archlinux:
 | 
					archlinux:
 | 
				
			||||||
  extends: .dalligi
 | 
					  extends: .dalligi
 | 
				
			||||||
freebsd:
 | 
					freebsd:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								.mailmap
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								.mailmap
									
										
									
									
									
								
							| 
						 | 
					@ -1 +1,2 @@
 | 
				
			||||||
Isaac Freund <mail@isaacfreund.com> <ifreund@ifreund.xyz>
 | 
					Isaac Freund <mail@isaacfreund.com> <ifreund@ifreund.xyz>
 | 
				
			||||||
 | 
					Kirill Primak <vyivel@eclair.cafe> <vyivel@posteo.net>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -213,6 +213,27 @@ reinitialized to be used again.
 | 
				
			||||||
it, and free the memory. Such functions should always be able to accept a NULL
 | 
					it, and free the memory. Such functions should always be able to accept a NULL
 | 
				
			||||||
pointer.
 | 
					pointer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If the object has signals, the destructor function must assert that their
 | 
				
			||||||
 | 
					listener lists are empty.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					void wlr_thing_init(struct wlr_thing *thing) {
 | 
				
			||||||
 | 
						*thing = (struct wlr_thing){
 | 
				
			||||||
 | 
							// ...
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_signal_init(&thing->events.destroy);
 | 
				
			||||||
 | 
						wl_signal_init(&thing->events.foo);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_thing_finish(struct wlr_thing *thing) {
 | 
				
			||||||
 | 
						wl_signal_emit_mutable(&thing->events.destroy, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(wl_list_empty(&thing->events.destroy.listener_list));
 | 
				
			||||||
 | 
						assert(wl_list_empty(&thing->events.foo.listener_list));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Error Codes
 | 
					### Error Codes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For functions not returning a value, they should return a (stdbool.h) bool to
 | 
					For functions not returning a value, they should return a (stdbool.h) bool to
 | 
				
			||||||
| 
						 | 
					@ -237,6 +258,13 @@ used and `#undef` them after.
 | 
				
			||||||
* Document the contents and container of a `struct wl_list` with a
 | 
					* Document the contents and container of a `struct wl_list` with a
 | 
				
			||||||
  `// content.link` and `// container.list` comment.
 | 
					  `// content.link` and `// container.list` comment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Private fields
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Wrap private fields of public structures with `struct { … } WLR_PRIVATE`. This
 | 
				
			||||||
 | 
					ensures that compositor authors don't use them by accident. Within wlroots
 | 
				
			||||||
 | 
					`WLR_PRIVATE` is expanded to nothing, so private fields are accessed in the same
 | 
				
			||||||
 | 
					way as public ones.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Safety
 | 
					### Safety
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Avoid string manipulation functions which don't take the size of the
 | 
					* Avoid string manipulation functions which don't take the size of the
 | 
				
			||||||
| 
						 | 
					@ -325,12 +353,14 @@ struct wlr_compositor {
 | 
				
			||||||
	struct wl_global *global;
 | 
						struct wl_global *global;
 | 
				
			||||||
	…
 | 
						…
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal new_surface;
 | 
							struct wl_signal new_surface;
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,4 @@
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
| 
						 | 
					@ -12,9 +11,6 @@
 | 
				
			||||||
#include <wlr/config.h>
 | 
					#include <wlr/config.h>
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "backend/backend.h"
 | 
					 | 
				
			||||||
#include "backend/multi.h"
 | 
					 | 
				
			||||||
#include "render/allocator/allocator.h"
 | 
					 | 
				
			||||||
#include "types/wlr_output.h"
 | 
					#include "types/wlr_output.h"
 | 
				
			||||||
#include "util/env.h"
 | 
					#include "util/env.h"
 | 
				
			||||||
#include "util/time.h"
 | 
					#include "util/time.h"
 | 
				
			||||||
| 
						 | 
					@ -50,6 +46,10 @@ void wlr_backend_init(struct wlr_backend *backend,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_backend_finish(struct wlr_backend *backend) {
 | 
					void wlr_backend_finish(struct wlr_backend *backend) {
 | 
				
			||||||
	wl_signal_emit_mutable(&backend->events.destroy, backend);
 | 
						wl_signal_emit_mutable(&backend->events.destroy, backend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(wl_list_empty(&backend->events.destroy.listener_list));
 | 
				
			||||||
 | 
						assert(wl_list_empty(&backend->events.new_input.listener_list));
 | 
				
			||||||
 | 
						assert(wl_list_empty(&backend->events.new_output.listener_list));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_backend_start(struct wlr_backend *backend) {
 | 
					bool wlr_backend_start(struct wlr_backend *backend) {
 | 
				
			||||||
| 
						 | 
					@ -121,14 +121,6 @@ int wlr_backend_get_drm_fd(struct wlr_backend *backend) {
 | 
				
			||||||
	return backend->impl->get_drm_fd(backend);
 | 
						return backend->impl->get_drm_fd(backend);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t backend_get_buffer_caps(struct wlr_backend *backend) {
 | 
					 | 
				
			||||||
	if (!backend->impl->get_buffer_caps) {
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return backend->impl->get_buffer_caps(backend);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static size_t parse_outputs_env(const char *name) {
 | 
					static size_t parse_outputs_env(const char *name) {
 | 
				
			||||||
	const char *outputs_str = getenv(name);
 | 
						const char *outputs_str = getenv(name);
 | 
				
			||||||
	if (outputs_str == NULL) {
 | 
						if (outputs_str == NULL) {
 | 
				
			||||||
| 
						 | 
					@ -493,5 +485,10 @@ bool wlr_backend_commit(struct wlr_backend *backend,
 | 
				
			||||||
		output_apply_commit(state->output, &state->base);
 | 
							output_apply_commit(state->output, &state->base);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (size_t i = 0; i < states_len; i++) {
 | 
				
			||||||
 | 
							const struct wlr_backend_output_state *state = &states[i];
 | 
				
			||||||
 | 
							output_send_commit_event(state->output, &state->base);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,16 @@
 | 
				
			||||||
#include <drm_fourcc.h>
 | 
					#include <drm_fourcc.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <wlr/render/drm_syncobj.h>
 | 
				
			||||||
 | 
					#include <wlr/util/box.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include <xf86drm.h>
 | 
					 | 
				
			||||||
#include <xf86drmMode.h>
 | 
					#include <xf86drmMode.h>
 | 
				
			||||||
#include "backend/drm/drm.h"
 | 
					#include "backend/drm/drm.h"
 | 
				
			||||||
#include "backend/drm/fb.h"
 | 
					#include "backend/drm/fb.h"
 | 
				
			||||||
#include "backend/drm/iface.h"
 | 
					#include "backend/drm/iface.h"
 | 
				
			||||||
#include "backend/drm/util.h"
 | 
					#include "backend/drm/util.h"
 | 
				
			||||||
 | 
					#include "render/color.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *atomic_commit_flags_str(uint32_t flags) {
 | 
					static char *atomic_commit_flags_str(uint32_t flags) {
 | 
				
			||||||
	const char *const l[] = {
 | 
						const char *const l[] = {
 | 
				
			||||||
| 
						 | 
					@ -152,18 +155,20 @@ static bool create_gamma_lut_blob(struct wlr_drm_backend *drm,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
 | 
					bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
 | 
				
			||||||
		int width, int height, const pixman_region32_t *damage, uint32_t *blob_id) {
 | 
							int width, int height, const pixman_region32_t *damage, uint32_t *blob_id) {
 | 
				
			||||||
	if (!pixman_region32_not_empty(damage)) {
 | 
					 | 
				
			||||||
		*blob_id = 0;
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pixman_region32_t clipped;
 | 
						pixman_region32_t clipped;
 | 
				
			||||||
	pixman_region32_init(&clipped);
 | 
						pixman_region32_init(&clipped);
 | 
				
			||||||
	pixman_region32_intersect_rect(&clipped, damage, 0, 0, width, height);
 | 
						pixman_region32_intersect_rect(&clipped, damage, 0, 0, width, height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int rects_len;
 | 
						int rects_len;
 | 
				
			||||||
	const pixman_box32_t *rects = pixman_region32_rectangles(&clipped, &rects_len);
 | 
						const pixman_box32_t *rects = pixman_region32_rectangles(&clipped, &rects_len);
 | 
				
			||||||
	int ret = drmModeCreatePropertyBlob(drm->fd, rects, sizeof(*rects) * rects_len, blob_id);
 | 
					
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						if (rects_len > 0) {
 | 
				
			||||||
 | 
							ret = drmModeCreatePropertyBlob(drm->fd, rects, sizeof(*rects) * rects_len, blob_id);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ret = 0;
 | 
				
			||||||
 | 
							*blob_id = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	pixman_region32_fini(&clipped);
 | 
						pixman_region32_fini(&clipped);
 | 
				
			||||||
	if (ret != 0) {
 | 
						if (ret != 0) {
 | 
				
			||||||
		wlr_log_errno(WLR_ERROR, "Failed to create FB_DAMAGE_CLIPS property blob");
 | 
							wlr_log_errno(WLR_ERROR, "Failed to create FB_DAMAGE_CLIPS property blob");
 | 
				
			||||||
| 
						 | 
					@ -173,6 +178,85 @@ bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) {
 | 
				
			||||||
 | 
						switch (tf) {
 | 
				
			||||||
 | 
						case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
 | 
				
			||||||
 | 
							abort(); // unsupported
 | 
				
			||||||
 | 
						case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
 | 
				
			||||||
 | 
							return 2;
 | 
				
			||||||
 | 
						case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
 | 
				
			||||||
 | 
							abort(); // unsupported
 | 
				
			||||||
 | 
						case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
 | 
				
			||||||
 | 
							abort(); // unsupported
 | 
				
			||||||
 | 
						case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
 | 
				
			||||||
 | 
							abort(); // unsupported
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						abort(); // unreachable
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint16_t convert_cta861_color_coord(double v) {
 | 
				
			||||||
 | 
						if (v < 0) {
 | 
				
			||||||
 | 
							v = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (v > 1) {
 | 
				
			||||||
 | 
							v = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return (uint16_t)round(v * 50000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool create_hdr_output_metadata_blob(struct wlr_drm_backend *drm,
 | 
				
			||||||
 | 
							const struct wlr_output_image_description *img_desc, uint32_t *blob_id) {
 | 
				
			||||||
 | 
						if (img_desc == NULL) {
 | 
				
			||||||
 | 
							*blob_id = 0;
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct hdr_output_metadata metadata = {
 | 
				
			||||||
 | 
							.metadata_type = 0,
 | 
				
			||||||
 | 
							.hdmi_metadata_type1 = {
 | 
				
			||||||
 | 
								.eotf = convert_cta861_eotf(img_desc->transfer_function),
 | 
				
			||||||
 | 
								.metadata_type = 0,
 | 
				
			||||||
 | 
								.display_primaries = {
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.red.x),
 | 
				
			||||||
 | 
										.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.red.y),
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.green.x),
 | 
				
			||||||
 | 
										.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.green.y),
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.blue.x),
 | 
				
			||||||
 | 
										.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.blue.y),
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								.white_point = {
 | 
				
			||||||
 | 
									.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.white.x),
 | 
				
			||||||
 | 
									.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.white.y),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								.max_display_mastering_luminance = img_desc->mastering_luminance.max,
 | 
				
			||||||
 | 
								.min_display_mastering_luminance = img_desc->mastering_luminance.min * 0.0001,
 | 
				
			||||||
 | 
								.max_cll = img_desc->max_cll,
 | 
				
			||||||
 | 
								.max_fall = img_desc->max_fall,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						if (drmModeCreatePropertyBlob(drm->fd, &metadata, sizeof(metadata), blob_id) != 0) {
 | 
				
			||||||
 | 
							wlr_log_errno(WLR_ERROR, "Failed to create HDR_OUTPUT_METADATA property");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint64_t convert_primaries_to_colorspace(uint32_t primaries) {
 | 
				
			||||||
 | 
						switch (primaries) {
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
 | 
							return 0; // Default
 | 
				
			||||||
 | 
						case WLR_COLOR_NAMED_PRIMARIES_BT2020:
 | 
				
			||||||
 | 
							return 9; // BT2020_RGB
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						abort(); // unreachable
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint64_t max_bpc_for_format(uint32_t format) {
 | 
					static uint64_t max_bpc_for_format(uint32_t format) {
 | 
				
			||||||
	switch (format) {
 | 
						switch (format) {
 | 
				
			||||||
	case DRM_FORMAT_XRGB2101010:
 | 
						case DRM_FORMAT_XRGB2101010:
 | 
				
			||||||
| 
						 | 
					@ -247,19 +331,25 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t gamma_lut = crtc->gamma_lut;
 | 
						uint32_t gamma_lut = crtc->gamma_lut;
 | 
				
			||||||
	if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
 | 
						if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
 | 
				
			||||||
 | 
							size_t dim = 0;
 | 
				
			||||||
 | 
							uint16_t *lut = NULL;
 | 
				
			||||||
 | 
							if (state->base->color_transform != NULL) {
 | 
				
			||||||
 | 
								struct wlr_color_transform_lut_3x1d *tr =
 | 
				
			||||||
 | 
									color_transform_lut_3x1d_from_base(state->base->color_transform);
 | 
				
			||||||
 | 
								dim = tr->dim;
 | 
				
			||||||
 | 
								lut = tr->lut_3x1d;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Fallback to legacy gamma interface when gamma properties are not
 | 
							// Fallback to legacy gamma interface when gamma properties are not
 | 
				
			||||||
		// available (can happen on older Intel GPUs that support gamma but not
 | 
							// available (can happen on older Intel GPUs that support gamma but not
 | 
				
			||||||
		// degamma).
 | 
							// degamma).
 | 
				
			||||||
		if (crtc->props.gamma_lut == 0) {
 | 
							if (crtc->props.gamma_lut == 0) {
 | 
				
			||||||
			if (!drm_legacy_crtc_set_gamma(drm, crtc,
 | 
								if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
 | 
				
			||||||
					state->base->gamma_lut_size,
 | 
					 | 
				
			||||||
					state->base->gamma_lut)) {
 | 
					 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			if (!create_gamma_lut_blob(drm, state->base->gamma_lut_size,
 | 
								if (!create_gamma_lut_blob(drm, dim, lut, &gamma_lut)) {
 | 
				
			||||||
					state->base->gamma_lut, &gamma_lut)) {
 | 
					 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -272,6 +362,15 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
 | 
				
			||||||
			state->primary_fb->wlr_buf->height, &state->base->damage, &fb_damage_clips);
 | 
								state->primary_fb->wlr_buf->height, &state->base->damage, &fb_damage_clips);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int in_fence_fd = -1;
 | 
				
			||||||
 | 
						if (state->wait_timeline != NULL) {
 | 
				
			||||||
 | 
							in_fence_fd = wlr_drm_syncobj_timeline_export_sync_file(state->wait_timeline,
 | 
				
			||||||
 | 
								state->wait_point);
 | 
				
			||||||
 | 
							if (in_fence_fd < 0) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool prev_vrr_enabled =
 | 
						bool prev_vrr_enabled =
 | 
				
			||||||
		output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
 | 
							output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
 | 
				
			||||||
	bool vrr_enabled = prev_vrr_enabled;
 | 
						bool vrr_enabled = prev_vrr_enabled;
 | 
				
			||||||
| 
						 | 
					@ -282,10 +381,25 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
 | 
				
			||||||
		vrr_enabled = state->base->adaptive_sync_enabled;
 | 
							vrr_enabled = state->base->adaptive_sync_enabled;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t colorspace = conn->colorspace;
 | 
				
			||||||
 | 
						if (state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
 | 
				
			||||||
 | 
							colorspace = convert_primaries_to_colorspace(
 | 
				
			||||||
 | 
								state->base->image_description ? state->base->image_description->primaries : 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t hdr_output_metadata = conn->hdr_output_metadata;
 | 
				
			||||||
 | 
						if ((state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
 | 
				
			||||||
 | 
								!create_hdr_output_metadata_blob(drm, state->base->image_description, &hdr_output_metadata)) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	state->mode_id = mode_id;
 | 
						state->mode_id = mode_id;
 | 
				
			||||||
	state->gamma_lut = gamma_lut;
 | 
						state->gamma_lut = gamma_lut;
 | 
				
			||||||
	state->fb_damage_clips = fb_damage_clips;
 | 
						state->fb_damage_clips = fb_damage_clips;
 | 
				
			||||||
 | 
						state->primary_in_fence_fd = in_fence_fd;
 | 
				
			||||||
	state->vrr_enabled = vrr_enabled;
 | 
						state->vrr_enabled = vrr_enabled;
 | 
				
			||||||
 | 
						state->colorspace = colorspace;
 | 
				
			||||||
 | 
						state->hdr_output_metadata = hdr_output_metadata;
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -300,11 +414,23 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
 | 
				
			||||||
	crtc->own_mode_id = true;
 | 
						crtc->own_mode_id = true;
 | 
				
			||||||
	commit_blob(drm, &crtc->mode_id, state->mode_id);
 | 
						commit_blob(drm, &crtc->mode_id, state->mode_id);
 | 
				
			||||||
	commit_blob(drm, &crtc->gamma_lut, state->gamma_lut);
 | 
						commit_blob(drm, &crtc->gamma_lut, state->gamma_lut);
 | 
				
			||||||
 | 
						commit_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->output.adaptive_sync_status = state->vrr_enabled ?
 | 
						conn->output.adaptive_sync_status = state->vrr_enabled ?
 | 
				
			||||||
		WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED : WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
 | 
							WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED : WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	destroy_blob(drm, state->fb_damage_clips);
 | 
						destroy_blob(drm, state->fb_damage_clips);
 | 
				
			||||||
 | 
						if (state->primary_in_fence_fd >= 0) {
 | 
				
			||||||
 | 
							close(state->primary_in_fence_fd);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (state->out_fence_fd >= 0) {
 | 
				
			||||||
 | 
							// TODO: error handling
 | 
				
			||||||
 | 
							wlr_drm_syncobj_timeline_import_sync_file(state->base->signal_timeline,
 | 
				
			||||||
 | 
								state->base->signal_point, state->out_fence_fd);
 | 
				
			||||||
 | 
							close(state->out_fence_fd);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn->colorspace = state->colorspace;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) {
 | 
					void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) {
 | 
				
			||||||
| 
						 | 
					@ -314,8 +440,15 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rollback_blob(drm, &crtc->mode_id, state->mode_id);
 | 
						rollback_blob(drm, &crtc->mode_id, state->mode_id);
 | 
				
			||||||
	rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut);
 | 
						rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut);
 | 
				
			||||||
 | 
						rollback_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	destroy_blob(drm, state->fb_damage_clips);
 | 
						destroy_blob(drm, state->fb_damage_clips);
 | 
				
			||||||
 | 
						if (state->primary_in_fence_fd >= 0) {
 | 
				
			||||||
 | 
							close(state->primary_in_fence_fd);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (state->out_fence_fd >= 0) {
 | 
				
			||||||
 | 
							close(state->out_fence_fd);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
 | 
					static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
 | 
				
			||||||
| 
						 | 
					@ -327,7 +460,8 @@ static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
 | 
					static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
 | 
				
			||||||
		struct wlr_drm_plane *plane, struct wlr_drm_fb *fb, uint32_t crtc_id,
 | 
							struct wlr_drm_plane *plane, struct wlr_drm_fb *fb, uint32_t crtc_id,
 | 
				
			||||||
		int32_t x, int32_t y) {
 | 
							const struct wlr_box *dst_box,
 | 
				
			||||||
 | 
							const struct wlr_fbox *src_box) {
 | 
				
			||||||
	uint32_t id = plane->id;
 | 
						uint32_t id = plane->id;
 | 
				
			||||||
	const struct wlr_drm_plane_props *props = &plane->props;
 | 
						const struct wlr_drm_plane_props *props = &plane->props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -337,28 +471,50 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t width = fb->wlr_buf->width;
 | 
					 | 
				
			||||||
	uint32_t height = fb->wlr_buf->height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// The src_* properties are in 16.16 fixed point
 | 
						// The src_* properties are in 16.16 fixed point
 | 
				
			||||||
	atomic_add(atom, id, props->src_x, 0);
 | 
						atomic_add(atom, id, props->src_x, src_box->x * (1 << 16));
 | 
				
			||||||
	atomic_add(atom, id, props->src_y, 0);
 | 
						atomic_add(atom, id, props->src_y, src_box->y * (1 << 16));
 | 
				
			||||||
	atomic_add(atom, id, props->src_w, (uint64_t)width << 16);
 | 
						atomic_add(atom, id, props->src_w, src_box->width * (1 << 16));
 | 
				
			||||||
	atomic_add(atom, id, props->src_h, (uint64_t)height << 16);
 | 
						atomic_add(atom, id, props->src_h, src_box->height * (1 << 16));
 | 
				
			||||||
	atomic_add(atom, id, props->crtc_w, width);
 | 
					 | 
				
			||||||
	atomic_add(atom, id, props->crtc_h, height);
 | 
					 | 
				
			||||||
	atomic_add(atom, id, props->fb_id, fb->id);
 | 
						atomic_add(atom, id, props->fb_id, fb->id);
 | 
				
			||||||
	atomic_add(atom, id, props->crtc_id, crtc_id);
 | 
						atomic_add(atom, id, props->crtc_id, crtc_id);
 | 
				
			||||||
	atomic_add(atom, id, props->crtc_x, (uint64_t)x);
 | 
						atomic_add(atom, id, props->crtc_x, dst_box->x);
 | 
				
			||||||
	atomic_add(atom, id, props->crtc_y, (uint64_t)y);
 | 
						atomic_add(atom, id, props->crtc_y, dst_box->y);
 | 
				
			||||||
 | 
						atomic_add(atom, id, props->crtc_w, dst_box->width);
 | 
				
			||||||
 | 
						atomic_add(atom, id, props->crtc_h, dst_box->height);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool supports_cursor_hotspots(const struct wlr_drm_plane* plane) {
 | 
					static bool supports_cursor_hotspots(const struct wlr_drm_plane *plane) {
 | 
				
			||||||
	return plane->props.hotspot_x && plane->props.hotspot_y;
 | 
						return plane->props.hotspot_x && plane->props.hotspot_y;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void set_plane_in_fence_fd(struct atomic *atom,
 | 
				
			||||||
 | 
							struct wlr_drm_plane *plane, int sync_file_fd) {
 | 
				
			||||||
 | 
						if (!plane->props.in_fence_fd) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Plane %"PRIu32 " is missing the IN_FENCE_FD property",
 | 
				
			||||||
 | 
								plane->id);
 | 
				
			||||||
 | 
							atom->failed = true;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						atomic_add(atom, plane->id, plane->props.in_fence_fd, sync_file_fd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void set_crtc_out_fence_ptr(struct atomic *atom, struct wlr_drm_crtc *crtc,
 | 
				
			||||||
 | 
							int *fd_ptr) {
 | 
				
			||||||
 | 
						if (!crtc->props.out_fence_ptr) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR,
 | 
				
			||||||
 | 
								"CRTC %"PRIu32" is missing the OUT_FENCE_PTR property",
 | 
				
			||||||
 | 
								crtc->id);
 | 
				
			||||||
 | 
							atom->failed = true;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						atomic_add(atom, crtc->id, crtc->props.out_fence_ptr, (uintptr_t)fd_ptr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void atomic_connector_add(struct atomic *atom,
 | 
					static void atomic_connector_add(struct atomic *atom,
 | 
				
			||||||
		const struct wlr_drm_connector_state *state, bool modeset) {
 | 
							struct wlr_drm_connector_state *state, bool modeset) {
 | 
				
			||||||
	struct wlr_drm_connector *conn = state->connector;
 | 
						struct wlr_drm_connector *conn = state->connector;
 | 
				
			||||||
	struct wlr_drm_backend *drm = conn->backend;
 | 
						struct wlr_drm_backend *drm = conn->backend;
 | 
				
			||||||
	struct wlr_drm_crtc *crtc = conn->crtc;
 | 
						struct wlr_drm_crtc *crtc = conn->crtc;
 | 
				
			||||||
| 
						 | 
					@ -376,6 +532,12 @@ static void atomic_connector_add(struct atomic *atom,
 | 
				
			||||||
	if (modeset && active && conn->props.max_bpc != 0 && conn->max_bpc_bounds[1] != 0) {
 | 
						if (modeset && active && conn->props.max_bpc != 0 && conn->max_bpc_bounds[1] != 0) {
 | 
				
			||||||
		atomic_add(atom, conn->id, conn->props.max_bpc, pick_max_bpc(conn, state->primary_fb));
 | 
							atomic_add(atom, conn->id, conn->props.max_bpc, pick_max_bpc(conn, state->primary_fb));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (conn->props.colorspace != 0) {
 | 
				
			||||||
 | 
							atomic_add(atom, conn->id, conn->props.colorspace, state->colorspace);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (conn->props.hdr_output_metadata != 0) {
 | 
				
			||||||
 | 
							atomic_add(atom, conn->id, conn->props.hdr_output_metadata, state->hdr_output_metadata);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	atomic_add(atom, crtc->id, crtc->props.mode_id, state->mode_id);
 | 
						atomic_add(atom, crtc->id, crtc->props.mode_id, state->mode_id);
 | 
				
			||||||
	atomic_add(atom, crtc->id, crtc->props.active, active);
 | 
						atomic_add(atom, crtc->id, crtc->props.active, active);
 | 
				
			||||||
	if (active) {
 | 
						if (active) {
 | 
				
			||||||
| 
						 | 
					@ -385,16 +547,33 @@ static void atomic_connector_add(struct atomic *atom,
 | 
				
			||||||
		if (crtc->props.vrr_enabled != 0) {
 | 
							if (crtc->props.vrr_enabled != 0) {
 | 
				
			||||||
			atomic_add(atom, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
 | 
								atomic_add(atom, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		set_plane_props(atom, drm, crtc->primary, state->primary_fb, crtc->id,
 | 
							set_plane_props(atom, drm, crtc->primary, state->primary_fb, crtc->id,
 | 
				
			||||||
			0, 0);
 | 
								&state->primary_viewport.dst_box, &state->primary_viewport.src_box);
 | 
				
			||||||
		if (crtc->primary->props.fb_damage_clips != 0) {
 | 
							if (crtc->primary->props.fb_damage_clips != 0) {
 | 
				
			||||||
			atomic_add(atom, crtc->primary->id,
 | 
								atomic_add(atom, crtc->primary->id,
 | 
				
			||||||
				crtc->primary->props.fb_damage_clips, state->fb_damage_clips);
 | 
									crtc->primary->props.fb_damage_clips, state->fb_damage_clips);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (state->primary_in_fence_fd >= 0) {
 | 
				
			||||||
 | 
								set_plane_in_fence_fd(atom, crtc->primary, state->primary_in_fence_fd);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
 | 
				
			||||||
 | 
								set_crtc_out_fence_ptr(atom, crtc, &state->out_fence_fd);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (crtc->cursor) {
 | 
							if (crtc->cursor) {
 | 
				
			||||||
			if (drm_connector_is_cursor_visible(conn)) {
 | 
								if (drm_connector_is_cursor_visible(conn)) {
 | 
				
			||||||
 | 
									struct wlr_fbox cursor_src = {
 | 
				
			||||||
 | 
										.width = state->cursor_fb->wlr_buf->width,
 | 
				
			||||||
 | 
										.height = state->cursor_fb->wlr_buf->height,
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
									struct wlr_box cursor_dst = {
 | 
				
			||||||
 | 
										.x = conn->cursor_x,
 | 
				
			||||||
 | 
										.y = conn->cursor_y,
 | 
				
			||||||
 | 
										.width = state->cursor_fb->wlr_buf->width,
 | 
				
			||||||
 | 
										.height = state->cursor_fb->wlr_buf->height,
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
				set_plane_props(atom, drm, crtc->cursor, state->cursor_fb,
 | 
									set_plane_props(atom, drm, crtc->cursor, state->cursor_fb,
 | 
				
			||||||
					crtc->id, conn->cursor_x, conn->cursor_y);
 | 
										crtc->id, &cursor_dst, &cursor_src);
 | 
				
			||||||
				if (supports_cursor_hotspots(crtc->cursor)) {
 | 
									if (supports_cursor_hotspots(crtc->cursor)) {
 | 
				
			||||||
					atomic_add(atom, crtc->cursor->id,
 | 
										atomic_add(atom, crtc->cursor->id,
 | 
				
			||||||
						crtc->cursor->props.hotspot_x, conn->cursor_hotspot_x);
 | 
											crtc->cursor->props.hotspot_x, conn->cursor_hotspot_x);
 | 
				
			||||||
| 
						 | 
					@ -437,7 +616,7 @@ static bool atomic_device_commit(struct wlr_drm_backend *drm,
 | 
				
			||||||
	if (state->modeset) {
 | 
						if (state->modeset) {
 | 
				
			||||||
		flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
 | 
							flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!test_only && state->nonblock) {
 | 
						if (state->nonblock) {
 | 
				
			||||||
		flags |= DRM_MODE_ATOMIC_NONBLOCK;
 | 
							flags |= DRM_MODE_ATOMIC_NONBLOCK;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -456,33 +635,6 @@ out:
 | 
				
			||||||
	return ok;
 | 
						return ok;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool drm_atomic_reset(struct wlr_drm_backend *drm) {
 | 
					 | 
				
			||||||
	struct atomic atom;
 | 
					 | 
				
			||||||
	atomic_begin(&atom);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (size_t i = 0; i < drm->num_crtcs; i++) {
 | 
					 | 
				
			||||||
		struct wlr_drm_crtc *crtc = &drm->crtcs[i];
 | 
					 | 
				
			||||||
		atomic_add(&atom, crtc->id, crtc->props.mode_id, 0);
 | 
					 | 
				
			||||||
		atomic_add(&atom, crtc->id, crtc->props.active, 0);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_drm_connector *conn;
 | 
					 | 
				
			||||||
	wl_list_for_each(conn, &drm->connectors, link) {
 | 
					 | 
				
			||||||
		atomic_add(&atom, conn->id, conn->props.crtc_id, 0);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (size_t i = 0; i < drm->num_planes; i++) {
 | 
					 | 
				
			||||||
		plane_disable(&atom, &drm->planes[i]);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
 | 
					 | 
				
			||||||
	bool ok = atomic_commit(&atom, drm, NULL, NULL, flags);
 | 
					 | 
				
			||||||
	atomic_finish(&atom);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ok;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const struct wlr_drm_interface atomic_iface = {
 | 
					const struct wlr_drm_interface atomic_iface = {
 | 
				
			||||||
	.commit = atomic_device_commit,
 | 
						.commit = atomic_device_commit,
 | 
				
			||||||
	.reset = drm_atomic_reset,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,8 @@
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <drm_fourcc.h>
 | 
					#include <drm_fourcc.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
#include <wlr/backend/interface.h>
 | 
					#include <wlr/backend/interface.h>
 | 
				
			||||||
#include <wlr/backend/session.h>
 | 
					#include <wlr/backend/session.h>
 | 
				
			||||||
| 
						 | 
					@ -13,6 +11,7 @@
 | 
				
			||||||
#include <xf86drm.h>
 | 
					#include <xf86drm.h>
 | 
				
			||||||
#include "backend/drm/drm.h"
 | 
					#include "backend/drm/drm.h"
 | 
				
			||||||
#include "backend/drm/fb.h"
 | 
					#include "backend/drm/fb.h"
 | 
				
			||||||
 | 
					#include "render/drm_format_set.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_backend *get_drm_backend_from_backend(
 | 
					struct wlr_drm_backend *get_drm_backend_from_backend(
 | 
				
			||||||
		struct wlr_backend *wlr_backend) {
 | 
							struct wlr_backend *wlr_backend) {
 | 
				
			||||||
| 
						 | 
					@ -53,7 +52,8 @@ static void backend_destroy(struct wlr_backend *backend) {
 | 
				
			||||||
	wl_list_remove(&drm->dev_change.link);
 | 
						wl_list_remove(&drm->dev_change.link);
 | 
				
			||||||
	wl_list_remove(&drm->dev_remove.link);
 | 
						wl_list_remove(&drm->dev_remove.link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (drm->parent) {
 | 
						if (drm->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
 | 
							wlr_drm_format_set_finish(&drm->mgpu_formats);
 | 
				
			||||||
		finish_drm_renderer(&drm->mgpu_renderer);
 | 
							finish_drm_renderer(&drm->mgpu_renderer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,10 +75,6 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
 | 
				
			||||||
	return drm->fd;
 | 
						return drm->fd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t backend_get_buffer_caps(struct wlr_backend *backend) {
 | 
					 | 
				
			||||||
	return WLR_BUFFER_CAP_DMABUF;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool backend_test(struct wlr_backend *backend,
 | 
					static bool backend_test(struct wlr_backend *backend,
 | 
				
			||||||
		const struct wlr_backend_output_state *states, size_t states_len) {
 | 
							const struct wlr_backend_output_state *states, size_t states_len) {
 | 
				
			||||||
	struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
 | 
						struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
 | 
				
			||||||
| 
						 | 
					@ -95,7 +91,6 @@ static const struct wlr_backend_impl backend_impl = {
 | 
				
			||||||
	.start = backend_start,
 | 
						.start = backend_start,
 | 
				
			||||||
	.destroy = backend_destroy,
 | 
						.destroy = backend_destroy,
 | 
				
			||||||
	.get_drm_fd = backend_get_drm_fd,
 | 
						.get_drm_fd = backend_get_drm_fd,
 | 
				
			||||||
	.get_buffer_caps = backend_get_buffer_caps,
 | 
					 | 
				
			||||||
	.test = backend_test,
 | 
						.test = backend_test,
 | 
				
			||||||
	.commit = backend_commit,
 | 
						.commit = backend_commit,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -117,11 +112,18 @@ static void handle_session_active(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	wlr_log(WLR_INFO, "DRM FD %s", session->active ? "resumed" : "paused");
 | 
						wlr_log(WLR_INFO, "DRM FD %s", session->active ? "resumed" : "paused");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!session->active) {
 | 
						if (!session->active) {
 | 
				
			||||||
 | 
							// Disconnect any active connectors so that the client will modeset and
 | 
				
			||||||
 | 
							// rerender when the session is activated again.
 | 
				
			||||||
 | 
							struct wlr_drm_connector *conn;
 | 
				
			||||||
 | 
							wl_list_for_each(conn, &drm->connectors, link) {
 | 
				
			||||||
 | 
								if (conn->status == DRM_MODE_CONNECTED) {
 | 
				
			||||||
 | 
									wlr_output_destroy(&conn->output);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	scan_drm_connectors(drm, NULL);
 | 
						scan_drm_connectors(drm, NULL);
 | 
				
			||||||
	restore_drm_device(drm);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_dev_change(struct wl_listener *listener, void *data) {
 | 
					static void handle_dev_change(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -165,6 +167,44 @@ static void handle_parent_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	backend_destroy(&drm->backend);
 | 
						backend_destroy(&drm->backend);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sanitize_mgpu_modifiers(struct wlr_drm_format_set *set) {
 | 
				
			||||||
 | 
						for (size_t idx = 0; idx < set->len; idx++) {
 | 
				
			||||||
 | 
							// Implicit modifiers are not well-defined across devices, so strip
 | 
				
			||||||
 | 
							// them from all formats in multi-gpu scenarios.
 | 
				
			||||||
 | 
							struct wlr_drm_format *fmt = &set->formats[idx];
 | 
				
			||||||
 | 
							wlr_drm_format_set_remove(set, fmt->format, DRM_FORMAT_MOD_INVALID);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool init_mgpu_renderer(struct wlr_drm_backend *drm) {
 | 
				
			||||||
 | 
						if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
 | 
				
			||||||
 | 
							wlr_log(WLR_INFO, "Failed to initialize mgpu blit renderer"
 | 
				
			||||||
 | 
								", falling back to scanning out from primary GPU");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (uint32_t plane_idx = 0; plane_idx < drm->num_planes; plane_idx++) {
 | 
				
			||||||
 | 
								struct wlr_drm_plane *plane = &drm->planes[plane_idx];
 | 
				
			||||||
 | 
								sanitize_mgpu_modifiers(&plane->formats);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// We'll perform a multi-GPU copy for all submitted buffers, we need
 | 
				
			||||||
 | 
						// to be able to texture from them
 | 
				
			||||||
 | 
						struct wlr_renderer *renderer = drm->mgpu_renderer.wlr_rend;
 | 
				
			||||||
 | 
						const struct wlr_drm_format_set *texture_formats =
 | 
				
			||||||
 | 
							wlr_renderer_get_texture_formats(renderer, WLR_BUFFER_CAP_DMABUF);
 | 
				
			||||||
 | 
						if (texture_formats == NULL) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_drm_format_set_copy(&drm->mgpu_formats, texture_formats);
 | 
				
			||||||
 | 
						sanitize_mgpu_modifiers(&drm->mgpu_formats);
 | 
				
			||||||
 | 
						drm->backend.features.timeline = drm->backend.features.timeline &&
 | 
				
			||||||
 | 
							drm->mgpu_renderer.wlr_rend->features.timeline;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
 | 
					struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
 | 
				
			||||||
		struct wlr_device *dev, struct wlr_backend *parent) {
 | 
							struct wlr_device *dev, struct wlr_backend *parent) {
 | 
				
			||||||
	assert(session && dev);
 | 
						assert(session && dev);
 | 
				
			||||||
| 
						 | 
					@ -192,6 +232,8 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wlr_backend_init(&drm->backend, &backend_impl);
 | 
						wlr_backend_init(&drm->backend, &backend_impl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						drm->backend.buffer_caps = WLR_BUFFER_CAP_DMABUF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm->session = session;
 | 
						drm->session = session;
 | 
				
			||||||
	wl_list_init(&drm->fbs);
 | 
						wl_list_init(&drm->fbs);
 | 
				
			||||||
	wl_list_init(&drm->connectors);
 | 
						wl_list_init(&drm->connectors);
 | 
				
			||||||
| 
						 | 
					@ -234,34 +276,8 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
 | 
				
			||||||
		goto error_event;
 | 
							goto error_event;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (drm->parent) {
 | 
						if (drm->parent && !init_mgpu_renderer(drm)) {
 | 
				
			||||||
		if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
 | 
							goto error_mgpu_renderer;
 | 
				
			||||||
			wlr_log(WLR_ERROR, "Failed to initialize renderer");
 | 
					 | 
				
			||||||
			goto error_resources;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// We'll perform a multi-GPU copy for all submitted buffers, we need
 | 
					 | 
				
			||||||
		// to be able to texture from them
 | 
					 | 
				
			||||||
		struct wlr_renderer *renderer = drm->mgpu_renderer.wlr_rend;
 | 
					 | 
				
			||||||
		const struct wlr_drm_format_set *texture_formats =
 | 
					 | 
				
			||||||
			wlr_renderer_get_texture_formats(renderer, WLR_BUFFER_CAP_DMABUF);
 | 
					 | 
				
			||||||
		if (texture_formats == NULL) {
 | 
					 | 
				
			||||||
			wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
 | 
					 | 
				
			||||||
			goto error_mgpu_renderer;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Forbid implicit modifiers, because their meaning changes from one
 | 
					 | 
				
			||||||
		// GPU to another.
 | 
					 | 
				
			||||||
		for (size_t i = 0; i < texture_formats->len; i++) {
 | 
					 | 
				
			||||||
			const struct wlr_drm_format *fmt = &texture_formats->formats[i];
 | 
					 | 
				
			||||||
			for (size_t j = 0; j < fmt->len; j++) {
 | 
					 | 
				
			||||||
				uint64_t mod = fmt->modifiers[j];
 | 
					 | 
				
			||||||
				if (mod == DRM_FORMAT_MOD_INVALID) {
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format, mod);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm->session_destroy.notify = handle_session_destroy;
 | 
						drm->session_destroy.notify = handle_session_destroy;
 | 
				
			||||||
| 
						 | 
					@ -271,7 +287,6 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error_mgpu_renderer:
 | 
					error_mgpu_renderer:
 | 
				
			||||||
	finish_drm_renderer(&drm->mgpu_renderer);
 | 
						finish_drm_renderer(&drm->mgpu_renderer);
 | 
				
			||||||
error_resources:
 | 
					 | 
				
			||||||
	finish_drm_resources(drm);
 | 
						finish_drm_resources(drm);
 | 
				
			||||||
error_event:
 | 
					error_event:
 | 
				
			||||||
	wl_list_remove(&drm->session_active.link);
 | 
						wl_list_remove(&drm->session_active.link);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <drm_fourcc.h>
 | 
					#include <drm_fourcc.h>
 | 
				
			||||||
#include <drm_mode.h>
 | 
					#include <drm_mode.h>
 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <inttypes.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
| 
						 | 
					@ -14,6 +13,7 @@
 | 
				
			||||||
#include <wayland-util.h>
 | 
					#include <wayland-util.h>
 | 
				
			||||||
#include <wlr/backend/interface.h>
 | 
					#include <wlr/backend/interface.h>
 | 
				
			||||||
#include <wlr/interfaces/wlr_output.h>
 | 
					#include <wlr/interfaces/wlr_output.h>
 | 
				
			||||||
 | 
					#include <wlr/render/drm_syncobj.h>
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/util/box.h>
 | 
					#include <wlr/util/box.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
| 
						 | 
					@ -24,9 +24,7 @@
 | 
				
			||||||
#include "backend/drm/fb.h"
 | 
					#include "backend/drm/fb.h"
 | 
				
			||||||
#include "backend/drm/iface.h"
 | 
					#include "backend/drm/iface.h"
 | 
				
			||||||
#include "backend/drm/util.h"
 | 
					#include "backend/drm/util.h"
 | 
				
			||||||
#include "render/pixel_format.h"
 | 
					#include "render/color.h"
 | 
				
			||||||
#include "render/drm_format_set.h"
 | 
					 | 
				
			||||||
#include "render/wlr_renderer.h"
 | 
					 | 
				
			||||||
#include "types/wlr_output.h"
 | 
					#include "types/wlr_output.h"
 | 
				
			||||||
#include "util/env.h"
 | 
					#include "util/env.h"
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
| 
						 | 
					@ -40,9 +38,12 @@ static const uint32_t COMMIT_OUTPUT_STATE =
 | 
				
			||||||
	WLR_OUTPUT_STATE_BUFFER |
 | 
						WLR_OUTPUT_STATE_BUFFER |
 | 
				
			||||||
	WLR_OUTPUT_STATE_MODE |
 | 
						WLR_OUTPUT_STATE_MODE |
 | 
				
			||||||
	WLR_OUTPUT_STATE_ENABLED |
 | 
						WLR_OUTPUT_STATE_ENABLED |
 | 
				
			||||||
	WLR_OUTPUT_STATE_GAMMA_LUT |
 | 
					 | 
				
			||||||
	WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED |
 | 
						WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED |
 | 
				
			||||||
	WLR_OUTPUT_STATE_LAYERS;
 | 
						WLR_OUTPUT_STATE_LAYERS |
 | 
				
			||||||
 | 
						WLR_OUTPUT_STATE_WAIT_TIMELINE |
 | 
				
			||||||
 | 
						WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
 | 
				
			||||||
 | 
						WLR_OUTPUT_STATE_COLOR_TRANSFORM |
 | 
				
			||||||
 | 
						WLR_OUTPUT_STATE_IMAGE_DESCRIPTION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const uint32_t SUPPORTED_OUTPUT_STATE =
 | 
					static const uint32_t SUPPORTED_OUTPUT_STATE =
 | 
				
			||||||
	WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
 | 
						WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
 | 
				
			||||||
| 
						 | 
					@ -121,6 +122,7 @@ bool check_drm_features(struct wlr_drm_backend *drm) {
 | 
				
			||||||
		drm->supports_tearing_page_flips = drmGetCap(drm->fd, DRM_CAP_ASYNC_PAGE_FLIP, &cap) == 0 && cap == 1;
 | 
							drm->supports_tearing_page_flips = drmGetCap(drm->fd, DRM_CAP_ASYNC_PAGE_FLIP, &cap) == 0 && cap == 1;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		drm->supports_tearing_page_flips = drmGetCap(drm->fd, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, &cap) == 0 && cap == 1;
 | 
							drm->supports_tearing_page_flips = drmGetCap(drm->fd, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, &cap) == 0 && cap == 1;
 | 
				
			||||||
 | 
							drm->backend.features.timeline = drmGetCap(drm->fd, DRM_CAP_SYNCOBJ_TIMELINE, &cap) == 0 && cap == 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (env_parse_bool("WLR_DRM_NO_MODIFIERS")) {
 | 
						if (env_parse_bool("WLR_DRM_NO_MODIFIERS")) {
 | 
				
			||||||
| 
						 | 
					@ -170,7 +172,7 @@ static bool init_plane(struct wlr_drm_backend *drm,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p->type = type;
 | 
						p->type = type;
 | 
				
			||||||
	p->id = drm_plane->plane_id;
 | 
						p->id = id;
 | 
				
			||||||
	p->props = props;
 | 
						p->props = props;
 | 
				
			||||||
	p->initial_crtc_id = drm_plane->crtc_id;
 | 
						p->initial_crtc_id = drm_plane->crtc_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -554,6 +556,7 @@ static void drm_connector_apply_commit(const struct wlr_drm_connector_state *sta
 | 
				
			||||||
	struct wlr_drm_crtc *crtc = conn->crtc;
 | 
						struct wlr_drm_crtc *crtc = conn->crtc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_fb_copy(&crtc->primary->queued_fb, state->primary_fb);
 | 
						drm_fb_copy(&crtc->primary->queued_fb, state->primary_fb);
 | 
				
			||||||
 | 
						crtc->primary->viewport = state->primary_viewport;
 | 
				
			||||||
	if (crtc->cursor != NULL) {
 | 
						if (crtc->cursor != NULL) {
 | 
				
			||||||
		drm_fb_copy(&crtc->cursor->queued_fb, state->cursor_fb);
 | 
							drm_fb_copy(&crtc->cursor->queued_fb, state->cursor_fb);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -577,6 +580,16 @@ static void drm_connector_apply_commit(const struct wlr_drm_connector_state *sta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		conn->cursor_enabled = false;
 | 
							conn->cursor_enabled = false;
 | 
				
			||||||
		conn->crtc = NULL;
 | 
							conn->crtc = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Legacy uAPI doesn't support requesting page-flip events when
 | 
				
			||||||
 | 
							// turning off a CRTC
 | 
				
			||||||
 | 
							if (page_flip != NULL && conn->backend->iface == &legacy_iface) {
 | 
				
			||||||
 | 
								drm_page_flip_pop(page_flip, crtc->id);
 | 
				
			||||||
 | 
								conn->pending_page_flip = NULL;
 | 
				
			||||||
 | 
								if (page_flip->connectors_len == 0) {
 | 
				
			||||||
 | 
									drm_page_flip_destroy(page_flip);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -632,6 +645,8 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
 | 
				
			||||||
		.connector = conn,
 | 
							.connector = conn,
 | 
				
			||||||
		.base = base,
 | 
							.base = base,
 | 
				
			||||||
		.active = output_pending_enabled(&conn->output, base),
 | 
							.active = output_pending_enabled(&conn->output, base),
 | 
				
			||||||
 | 
							.primary_in_fence_fd = -1,
 | 
				
			||||||
 | 
							.out_fence_fd = -1,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_output_mode *mode = conn->output.current_mode;
 | 
						struct wlr_output_mode *mode = conn->output.current_mode;
 | 
				
			||||||
| 
						 | 
					@ -641,7 +656,7 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (base->committed & WLR_OUTPUT_STATE_MODE) {
 | 
						if (base->committed & WLR_OUTPUT_STATE_MODE) {
 | 
				
			||||||
		switch (base->mode_type) {
 | 
							switch (base->mode_type) {
 | 
				
			||||||
		case WLR_OUTPUT_STATE_MODE_FIXED:;
 | 
							case WLR_OUTPUT_STATE_MODE_FIXED:
 | 
				
			||||||
			mode = base->mode;
 | 
								mode = base->mode;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case WLR_OUTPUT_STATE_MODE_CUSTOM:
 | 
							case WLR_OUTPUT_STATE_MODE_CUSTOM:
 | 
				
			||||||
| 
						 | 
					@ -668,8 +683,10 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
 | 
				
			||||||
		struct wlr_drm_plane *primary = conn->crtc->primary;
 | 
							struct wlr_drm_plane *primary = conn->crtc->primary;
 | 
				
			||||||
		if (primary->queued_fb != NULL) {
 | 
							if (primary->queued_fb != NULL) {
 | 
				
			||||||
			state->primary_fb = drm_fb_lock(primary->queued_fb);
 | 
								state->primary_fb = drm_fb_lock(primary->queued_fb);
 | 
				
			||||||
 | 
								state->primary_viewport = primary->viewport;
 | 
				
			||||||
		} else if (primary->current_fb != NULL) {
 | 
							} else if (primary->current_fb != NULL) {
 | 
				
			||||||
			state->primary_fb = drm_fb_lock(primary->current_fb);
 | 
								state->primary_fb = drm_fb_lock(primary->current_fb);
 | 
				
			||||||
 | 
								state->primary_viewport = primary->viewport;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (conn->cursor_enabled) {
 | 
							if (conn->cursor_enabled) {
 | 
				
			||||||
| 
						 | 
					@ -689,6 +706,7 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
 | 
				
			||||||
static void drm_connector_state_finish(struct wlr_drm_connector_state *state) {
 | 
					static void drm_connector_state_finish(struct wlr_drm_connector_state *state) {
 | 
				
			||||||
	drm_fb_clear(&state->primary_fb);
 | 
						drm_fb_clear(&state->primary_fb);
 | 
				
			||||||
	drm_fb_clear(&state->cursor_fb);
 | 
						drm_fb_clear(&state->cursor_fb);
 | 
				
			||||||
 | 
						wlr_drm_syncobj_timeline_unref(state->wait_timeline);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn,
 | 
					static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn,
 | 
				
			||||||
| 
						 | 
					@ -703,8 +721,16 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
 | 
				
			||||||
	struct wlr_drm_plane *plane = crtc->primary;
 | 
						struct wlr_drm_plane *plane = crtc->primary;
 | 
				
			||||||
	struct wlr_buffer *source_buf = state->base->buffer;
 | 
						struct wlr_buffer *source_buf = state->base->buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *wait_timeline = NULL;
 | 
				
			||||||
 | 
						uint64_t wait_point = 0;
 | 
				
			||||||
 | 
						if (state->base->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
 | 
				
			||||||
 | 
							wait_timeline = state->base->wait_timeline;
 | 
				
			||||||
 | 
							wait_point = state->base->wait_point;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						assert(state->wait_timeline == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_buffer *local_buf;
 | 
						struct wlr_buffer *local_buf;
 | 
				
			||||||
	if (drm->parent) {
 | 
						if (drm->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
		struct wlr_drm_format format = {0};
 | 
							struct wlr_drm_format format = {0};
 | 
				
			||||||
		if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
 | 
							if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
 | 
				
			||||||
			wlr_log(WLR_ERROR, "Failed to pick primary plane format");
 | 
								wlr_log(WLR_ERROR, "Failed to pick primary plane format");
 | 
				
			||||||
| 
						 | 
					@ -719,12 +745,23 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		local_buf = drm_surface_blit(&plane->mgpu_surf, source_buf);
 | 
							local_buf = drm_surface_blit(&plane->mgpu_surf, source_buf,
 | 
				
			||||||
 | 
								wait_timeline, wait_point);
 | 
				
			||||||
		if (local_buf == NULL) {
 | 
							if (local_buf == NULL) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (plane->mgpu_surf.timeline != NULL) {
 | 
				
			||||||
 | 
								state->wait_timeline = wlr_drm_syncobj_timeline_ref(plane->mgpu_surf.timeline);
 | 
				
			||||||
 | 
								state->wait_point = plane->mgpu_surf.point;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		local_buf = wlr_buffer_lock(source_buf);
 | 
							local_buf = wlr_buffer_lock(source_buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (wait_timeline != NULL) {
 | 
				
			||||||
 | 
								state->wait_timeline = wlr_drm_syncobj_timeline_ref(wait_timeline);
 | 
				
			||||||
 | 
								state->wait_point = wait_point;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool ok = drm_fb_import(&state->primary_fb, drm, local_buf,
 | 
						bool ok = drm_fb_import(&state->primary_fb, drm, local_buf,
 | 
				
			||||||
| 
						 | 
					@ -736,6 +773,9 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						output_state_get_buffer_src_box(state->base, &state->primary_viewport.src_box);
 | 
				
			||||||
 | 
						output_state_get_buffer_dst_box(state->base, &state->primary_viewport.dst_box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -744,7 +784,7 @@ static bool drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn,
 | 
				
			||||||
	struct wlr_drm_backend *drm = conn->backend;
 | 
						struct wlr_drm_backend *drm = conn->backend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_drm_crtc *crtc = conn->crtc;
 | 
						struct wlr_drm_crtc *crtc = conn->crtc;
 | 
				
			||||||
	if (!crtc || drm->parent) {
 | 
						if (!crtc || drm->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -786,13 +826,12 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) {
 | 
						if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled &&
 | 
				
			||||||
		if (output->current_mode == NULL &&
 | 
								output->width == 0 && output->height == 0 &&
 | 
				
			||||||
				!(state->committed & WLR_OUTPUT_STATE_MODE)) {
 | 
								!(state->committed & WLR_OUTPUT_STATE_MODE)) {
 | 
				
			||||||
			wlr_drm_conn_log(conn, WLR_DEBUG,
 | 
							wlr_drm_conn_log(conn, WLR_DEBUG,
 | 
				
			||||||
				"Can't enable an output without a mode");
 | 
								"Can't enable an output without a mode");
 | 
				
			||||||
			return false;
 | 
							return false;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
 | 
						if ((state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
 | 
				
			||||||
| 
						 | 
					@ -803,7 +842,36 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (test_only && conn->backend->parent) {
 | 
						if ((state->committed & WLR_OUTPUT_STATE_BUFFER) && conn->backend->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
 | 
							struct wlr_dmabuf_attributes dmabuf;
 | 
				
			||||||
 | 
							if (!wlr_buffer_get_dmabuf(state->buffer, &dmabuf)) {
 | 
				
			||||||
 | 
								wlr_drm_conn_log(conn, WLR_DEBUG, "Buffer is not a DMA-BUF");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!wlr_drm_format_set_has(&conn->backend->mgpu_formats, dmabuf.format, dmabuf.modifier)) {
 | 
				
			||||||
 | 
								wlr_drm_conn_log(conn, WLR_DEBUG,
 | 
				
			||||||
 | 
									"Buffer format 0x%"PRIX32" with modifier 0x%"PRIX64" cannot be "
 | 
				
			||||||
 | 
									"imported into multi-GPU renderer",
 | 
				
			||||||
 | 
									dmabuf.format, dmabuf.modifier);
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) && state->color_transform != NULL &&
 | 
				
			||||||
 | 
								state->color_transform->type != COLOR_TRANSFORM_LUT_3X1D) {
 | 
				
			||||||
 | 
							wlr_drm_conn_log(conn, WLR_DEBUG,
 | 
				
			||||||
 | 
								"Only 3x1D LUT color transforms are supported");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
 | 
				
			||||||
 | 
								conn->backend->iface != &atomic_iface) {
 | 
				
			||||||
 | 
							wlr_log(WLR_DEBUG, "Image descriptions are only supported by the atomic interface");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (test_only && conn->backend->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
		// If we're running as a secondary GPU, we can't perform an atomic
 | 
							// If we're running as a secondary GPU, we can't perform an atomic
 | 
				
			||||||
		// commit without blitting a buffer.
 | 
							// commit without blitting a buffer.
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
| 
						 | 
					@ -873,7 +941,7 @@ static bool drm_connector_commit_state(struct wlr_drm_connector *conn,
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (test_only && conn->backend->parent) {
 | 
						if (test_only && conn->backend->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
		// If we're running as a secondary GPU, we can't perform an atomic
 | 
							// If we're running as a secondary GPU, we can't perform an atomic
 | 
				
			||||||
		// commit without blitting a buffer.
 | 
							// commit without blitting a buffer.
 | 
				
			||||||
		ok = true;
 | 
							ok = true;
 | 
				
			||||||
| 
						 | 
					@ -1070,7 +1138,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct wlr_buffer *local_buf;
 | 
							struct wlr_buffer *local_buf;
 | 
				
			||||||
		if (drm->parent) {
 | 
							if (drm->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
			struct wlr_drm_format format = {0};
 | 
								struct wlr_drm_format format = {0};
 | 
				
			||||||
			if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
 | 
								if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
 | 
				
			||||||
				wlr_log(WLR_ERROR, "Failed to pick cursor plane format");
 | 
									wlr_log(WLR_ERROR, "Failed to pick cursor plane format");
 | 
				
			||||||
| 
						 | 
					@ -1084,7 +1152,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			local_buf = drm_surface_blit(&plane->mgpu_surf, buffer);
 | 
								local_buf = drm_surface_blit(&plane->mgpu_surf, buffer, NULL, 0);
 | 
				
			||||||
			if (local_buf == NULL) {
 | 
								if (local_buf == NULL) {
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -1104,7 +1172,6 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
 | 
				
			||||||
		conn->cursor_height = buffer->height;
 | 
							conn->cursor_height = buffer->height;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_output_update_needs_frame(output);
 | 
					 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1134,7 +1201,6 @@ static bool drm_connector_move_cursor(struct wlr_output *output,
 | 
				
			||||||
	conn->cursor_x = box.x;
 | 
						conn->cursor_x = box.x;
 | 
				
			||||||
	conn->cursor_y = box.y;
 | 
						conn->cursor_y = box.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_output_update_needs_frame(output);
 | 
					 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1157,6 +1223,8 @@ static void dealloc_crtc(struct wlr_drm_connector *conn);
 | 
				
			||||||
static void drm_connector_destroy_output(struct wlr_output *output) {
 | 
					static void drm_connector_destroy_output(struct wlr_output *output) {
 | 
				
			||||||
	struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
 | 
						struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_output_finish(output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dealloc_crtc(conn);
 | 
						dealloc_crtc(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->status = DRM_MODE_DISCONNECTED;
 | 
						conn->status = DRM_MODE_DISCONNECTED;
 | 
				
			||||||
| 
						 | 
					@ -1184,7 +1252,7 @@ static const struct wlr_drm_format_set *drm_connector_get_cursor_formats(
 | 
				
			||||||
	if (!plane) {
 | 
						if (!plane) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (conn->backend->parent) {
 | 
						if (conn->backend->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
		return &conn->backend->mgpu_formats;
 | 
							return &conn->backend->mgpu_formats;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &plane->formats;
 | 
						return &plane->formats;
 | 
				
			||||||
| 
						 | 
					@ -1213,7 +1281,7 @@ static const struct wlr_drm_format_set *drm_connector_get_primary_formats(
 | 
				
			||||||
	if (!drm_connector_alloc_crtc(conn)) {
 | 
						if (!drm_connector_alloc_crtc(conn)) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (conn->backend->parent) {
 | 
						if (conn->backend->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
		return &conn->backend->mgpu_formats;
 | 
							return &conn->backend->mgpu_formats;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &conn->crtc->primary->formats;
 | 
						return &conn->crtc->primary->formats;
 | 
				
			||||||
| 
						 | 
					@ -1350,7 +1418,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm,
 | 
				
			||||||
		++i;
 | 
							++i;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	match_obj(num_connectors, connector_constraints,
 | 
						match_connectors_with_crtcs(num_connectors, connector_constraints,
 | 
				
			||||||
		drm->num_crtcs, previous_match, new_match);
 | 
							drm->num_crtcs, previous_match, new_match);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Converts our crtc=>connector result into a connector=>crtc one.
 | 
						// Converts our crtc=>connector result into a connector=>crtc one.
 | 
				
			||||||
| 
						 | 
					@ -1478,14 +1546,14 @@ static struct wlr_drm_connector *create_drm_connector(struct wlr_drm_backend *dr
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const char *conn_name =
 | 
						const char *conn_type_name =
 | 
				
			||||||
		drmModeGetConnectorTypeName(drm_conn->connector_type);
 | 
							drmModeGetConnectorTypeName(drm_conn->connector_type);
 | 
				
			||||||
	if (conn_name == NULL) {
 | 
						if (conn_type_name == NULL) {
 | 
				
			||||||
		conn_name = "Unknown";
 | 
							conn_type_name = "Unknown";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(wlr_conn->name, sizeof(wlr_conn->name),
 | 
						snprintf(wlr_conn->name, sizeof(wlr_conn->name),
 | 
				
			||||||
		"%s-%"PRIu32, conn_name, drm_conn->connector_type_id);
 | 
							"%s-%"PRIu32, conn_type_name, drm_conn->connector_type_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_conn->possible_crtcs =
 | 
						wlr_conn->possible_crtcs =
 | 
				
			||||||
		drmModeConnectorGetPossibleCrtcs(drm->fd, drm_conn);
 | 
							drmModeConnectorGetPossibleCrtcs(drm->fd, drm_conn);
 | 
				
			||||||
| 
						 | 
					@ -1556,6 +1624,7 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_log(WLR_INFO, "Detected modes:");
 | 
						wlr_log(WLR_INFO, "Detected modes:");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool found_current_mode = false;
 | 
				
			||||||
	for (int i = 0; i < drm_conn->count_modes; ++i) {
 | 
						for (int i = 0; i < drm_conn->count_modes; ++i) {
 | 
				
			||||||
		if (drm_conn->modes[i].flags & DRM_MODE_FLAG_INTERLACE) {
 | 
							if (drm_conn->modes[i].flags & DRM_MODE_FLAG_INTERLACE) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
| 
						 | 
					@ -1574,14 +1643,7 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
 | 
				
			||||||
		if (current_modeinfo != NULL && memcmp(&mode->drm_mode,
 | 
							if (current_modeinfo != NULL && memcmp(&mode->drm_mode,
 | 
				
			||||||
				current_modeinfo, sizeof(*current_modeinfo)) == 0) {
 | 
									current_modeinfo, sizeof(*current_modeinfo)) == 0) {
 | 
				
			||||||
			wlr_output_state_set_mode(&state, &mode->wlr_mode);
 | 
								wlr_output_state_set_mode(&state, &mode->wlr_mode);
 | 
				
			||||||
 | 
								found_current_mode = true;
 | 
				
			||||||
			uint64_t mode_id = 0;
 | 
					 | 
				
			||||||
			get_drm_prop(drm->fd, wlr_conn->crtc->id,
 | 
					 | 
				
			||||||
				wlr_conn->crtc->props.mode_id, &mode_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			wlr_conn->crtc->own_mode_id = false;
 | 
					 | 
				
			||||||
			wlr_conn->crtc->mode_id = mode_id;
 | 
					 | 
				
			||||||
			wlr_conn->refresh = calculate_refresh_rate(current_modeinfo);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		wlr_log(WLR_INFO, "  %"PRId32"x%"PRId32" @ %.3f Hz %s",
 | 
							wlr_log(WLR_INFO, "  %"PRId32"x%"PRId32" @ %.3f Hz %s",
 | 
				
			||||||
| 
						 | 
					@ -1592,6 +1654,23 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
 | 
				
			||||||
		wl_list_insert(modes.prev, &mode->wlr_mode.link);
 | 
							wl_list_insert(modes.prev, &mode->wlr_mode.link);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (current_modeinfo != NULL) {
 | 
				
			||||||
 | 
							int32_t refresh = calculate_refresh_rate(current_modeinfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!found_current_mode) {
 | 
				
			||||||
 | 
								wlr_output_state_set_custom_mode(&state,
 | 
				
			||||||
 | 
									current_modeinfo->hdisplay, current_modeinfo->vdisplay, refresh);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint64_t mode_id = 0;
 | 
				
			||||||
 | 
							get_drm_prop(drm->fd, wlr_conn->crtc->id,
 | 
				
			||||||
 | 
								wlr_conn->crtc->props.mode_id, &mode_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wlr_conn->crtc->own_mode_id = false;
 | 
				
			||||||
 | 
							wlr_conn->crtc->mode_id = mode_id;
 | 
				
			||||||
 | 
							wlr_conn->refresh = refresh;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(current_modeinfo);
 | 
						free(current_modeinfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_output_init(output, &drm->backend, &output_impl, drm->session->event_loop, &state);
 | 
						wlr_output_init(output, &drm->backend, &output_impl, drm->session->event_loop, &state);
 | 
				
			||||||
| 
						 | 
					@ -1638,7 +1717,11 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
 | 
				
			||||||
	size_t edid_len = 0;
 | 
						size_t edid_len = 0;
 | 
				
			||||||
	uint8_t *edid = get_drm_prop_blob(drm->fd,
 | 
						uint8_t *edid = get_drm_prop_blob(drm->fd,
 | 
				
			||||||
		wlr_conn->id, wlr_conn->props.edid, &edid_len);
 | 
							wlr_conn->id, wlr_conn->props.edid, &edid_len);
 | 
				
			||||||
	parse_edid(wlr_conn, edid_len, edid);
 | 
						if (edid_len > 0) {
 | 
				
			||||||
 | 
							parse_edid(wlr_conn, edid_len, edid);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							wlr_log(WLR_DEBUG, "Connector has no EDID");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	free(edid);
 | 
						free(edid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *subconnector = NULL;
 | 
						char *subconnector = NULL;
 | 
				
			||||||
| 
						 | 
					@ -1704,6 +1787,10 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (wlr_conn && wlr_conn->lease) {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// If the hotplug event contains a connector ID, ignore any other
 | 
							// If the hotplug event contains a connector ID, ignore any other
 | 
				
			||||||
		// connector.
 | 
							// connector.
 | 
				
			||||||
		if (event != NULL && event->connector_id != 0 &&
 | 
							if (event != NULL && event->connector_id != 0 &&
 | 
				
			||||||
| 
						 | 
					@ -1781,8 +1868,6 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
 | 
				
			||||||
		destroy_drm_connector(conn);
 | 
							destroy_drm_connector(conn);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	realloc_crtcs(drm, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (size_t i = 0; i < new_outputs_len; ++i) {
 | 
						for (size_t i = 0; i < new_outputs_len; ++i) {
 | 
				
			||||||
		struct wlr_drm_connector *conn = new_outputs[i];
 | 
							struct wlr_drm_connector *conn = new_outputs[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1822,108 +1907,6 @@ void scan_drm_leases(struct wlr_drm_backend *drm) {
 | 
				
			||||||
	drmFree(list);
 | 
						drmFree(list);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void build_current_connector_state(struct wlr_output_state *state,
 | 
					 | 
				
			||||||
		struct wlr_drm_connector *conn) {
 | 
					 | 
				
			||||||
	bool enabled = conn->status != DRM_MODE_DISCONNECTED && conn->output.enabled;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_output_state_init(state);
 | 
					 | 
				
			||||||
	wlr_output_state_set_enabled(state, enabled);
 | 
					 | 
				
			||||||
	if (!enabled) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (conn->output.current_mode != NULL) {
 | 
					 | 
				
			||||||
		wlr_output_state_set_mode(state, conn->output.current_mode);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		wlr_output_state_set_custom_mode(state,
 | 
					 | 
				
			||||||
			conn->output.width, conn->output.height, conn->output.refresh);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Check whether we need to perform a full reset after a VT switch.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * If any connector or plane has a different CRTC, we need to perform a full
 | 
					 | 
				
			||||||
 * reset to restore our mapping. We couldn't avoid a full reset even if we
 | 
					 | 
				
			||||||
 * used a single KMS atomic commit to apply our state: the kernel rejects
 | 
					 | 
				
			||||||
 * commits which migrate a plane from one CRTC to another without going through
 | 
					 | 
				
			||||||
 * an intermediate state where the plane is disabled.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static bool skip_reset_for_restore(struct wlr_drm_backend *drm) {
 | 
					 | 
				
			||||||
	struct wlr_drm_connector *conn;
 | 
					 | 
				
			||||||
	wl_list_for_each(conn, &drm->connectors, link) {
 | 
					 | 
				
			||||||
		drmModeConnector *drm_conn = drmModeGetConnectorCurrent(drm->fd, conn->id);
 | 
					 | 
				
			||||||
		if (drm_conn == NULL) {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		struct wlr_drm_crtc *crtc = connector_get_current_crtc(conn, drm_conn);
 | 
					 | 
				
			||||||
		drmModeFreeConnector(drm_conn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (crtc != NULL && conn->crtc != crtc) {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (size_t i = 0; i < drm->num_planes; i++) {
 | 
					 | 
				
			||||||
		struct wlr_drm_plane *plane = &drm->planes[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		drmModePlane *drm_plane = drmModeGetPlane(drm->fd, plane->id);
 | 
					 | 
				
			||||||
		if (drm_plane == NULL) {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		uint32_t crtc_id = drm_plane->crtc_id;
 | 
					 | 
				
			||||||
		drmModeFreePlane(drm_plane);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		struct wlr_drm_crtc *crtc = NULL;
 | 
					 | 
				
			||||||
		for (size_t i = 0; i < drm->num_crtcs; i++) {
 | 
					 | 
				
			||||||
			if (drm->crtcs[i].id == crtc_id) {
 | 
					 | 
				
			||||||
				crtc = &drm->crtcs[i];
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (crtc == NULL) {
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bool ok = false;
 | 
					 | 
				
			||||||
		switch (plane->type) {
 | 
					 | 
				
			||||||
		case DRM_PLANE_TYPE_PRIMARY:
 | 
					 | 
				
			||||||
			ok = crtc->primary == plane;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case DRM_PLANE_TYPE_CURSOR:
 | 
					 | 
				
			||||||
			ok = crtc->cursor == plane;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (!ok) {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void restore_drm_device(struct wlr_drm_backend *drm) {
 | 
					 | 
				
			||||||
	// The previous DRM master leaves KMS in an undefined state. We need
 | 
					 | 
				
			||||||
	// to restore our own state, but be careful to avoid invalid
 | 
					 | 
				
			||||||
	// configurations. The connector/CRTC mapping may have changed, so
 | 
					 | 
				
			||||||
	// first disable all CRTCs, then light up the ones we were using
 | 
					 | 
				
			||||||
	// before the VT switch.
 | 
					 | 
				
			||||||
	// TODO: better use the atomic API to improve restoration after a VT switch
 | 
					 | 
				
			||||||
	if (!skip_reset_for_restore(drm) && !drm->iface->reset(drm)) {
 | 
					 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to reset state after VT switch");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_drm_connector *conn;
 | 
					 | 
				
			||||||
	wl_list_for_each(conn, &drm->connectors, link) {
 | 
					 | 
				
			||||||
		struct wlr_output_state state;
 | 
					 | 
				
			||||||
		build_current_connector_state(&state, conn);
 | 
					 | 
				
			||||||
		if (!drm_connector_commit_state(conn, &state, false)) {
 | 
					 | 
				
			||||||
			wlr_drm_conn_log(conn, WLR_ERROR, "Failed to restore state after VT switch");
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		wlr_output_state_finish(&state);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool commit_drm_device(struct wlr_drm_backend *drm,
 | 
					bool commit_drm_device(struct wlr_drm_backend *drm,
 | 
				
			||||||
		const struct wlr_backend_output_state *output_states, size_t output_states_len,
 | 
							const struct wlr_backend_output_state *output_states, size_t output_states_len,
 | 
				
			||||||
		bool test_only) {
 | 
							bool test_only) {
 | 
				
			||||||
| 
						 | 
					@ -1972,7 +1955,7 @@ bool commit_drm_device(struct wlr_drm_backend *drm,
 | 
				
			||||||
		modeset |= output_state->base.allow_reconfiguration;
 | 
							modeset |= output_state->base.allow_reconfiguration;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (test_only && drm->parent) {
 | 
						if (test_only && drm->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
		// If we're running as a secondary GPU, we can't perform an atomic
 | 
							// If we're running as a secondary GPU, we can't perform an atomic
 | 
				
			||||||
		// commit without blitting a buffer.
 | 
							// commit without blitting a buffer.
 | 
				
			||||||
		ok = true;
 | 
							ok = true;
 | 
				
			||||||
| 
						 | 
					@ -2050,20 +2033,19 @@ static void handle_page_flip(int fd, unsigned seq,
 | 
				
			||||||
	 * data between the GPUs, even if we were using the direct scanout
 | 
						 * data between the GPUs, even if we were using the direct scanout
 | 
				
			||||||
	 * interface.
 | 
						 * interface.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (!drm->parent) {
 | 
						if (!drm->mgpu_renderer.wlr_rend) {
 | 
				
			||||||
		present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
 | 
							present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct timespec present_time = {
 | 
					 | 
				
			||||||
		.tv_sec = tv_sec,
 | 
					 | 
				
			||||||
		.tv_nsec = tv_usec * 1000,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	struct wlr_output_event_present present_event = {
 | 
						struct wlr_output_event_present present_event = {
 | 
				
			||||||
		/* The DRM backend guarantees that the presentation event will be for
 | 
							/* The DRM backend guarantees that the presentation event will be for
 | 
				
			||||||
		 * the last submitted frame. */
 | 
							 * the last submitted frame. */
 | 
				
			||||||
		.commit_seq = conn->output.commit_seq,
 | 
							.commit_seq = conn->output.commit_seq,
 | 
				
			||||||
		.presented = drm->session->active,
 | 
							.presented = drm->session->active,
 | 
				
			||||||
		.when = &present_time,
 | 
							.when = {
 | 
				
			||||||
 | 
								.tv_sec = tv_sec,
 | 
				
			||||||
 | 
								.tv_nsec = tv_usec * 1000,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		.seq = seq,
 | 
							.seq = seq,
 | 
				
			||||||
		.refresh = mhz_to_nsec(conn->refresh),
 | 
							.refresh = mhz_to_nsec(conn->refresh),
 | 
				
			||||||
		.flags = present_flags,
 | 
							.flags = present_flags,
 | 
				
			||||||
| 
						 | 
					@ -2197,6 +2179,7 @@ struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs,
 | 
				
			||||||
				get_drm_connector_from_output(outputs[i]);
 | 
									get_drm_connector_from_output(outputs[i]);
 | 
				
			||||||
		conn->lease = lease;
 | 
							conn->lease = lease;
 | 
				
			||||||
		conn->crtc->lease = lease;
 | 
							conn->crtc->lease = lease;
 | 
				
			||||||
 | 
							disconnect_drm_connector(conn);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return lease;
 | 
						return lease;
 | 
				
			||||||
| 
						 | 
					@ -2219,6 +2202,8 @@ void drm_lease_destroy(struct wlr_drm_lease *lease) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_signal_emit_mutable(&lease->events.destroy, NULL);
 | 
						wl_signal_emit_mutable(&lease->events.destroy, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(wl_list_empty(&lease->events.destroy.listener_list));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_drm_connector *conn;
 | 
						struct wlr_drm_connector *conn;
 | 
				
			||||||
	wl_list_for_each(conn, &drm->connectors, link) {
 | 
						wl_list_for_each(conn, &drm->connectors, link) {
 | 
				
			||||||
		if (conn->lease == lease) {
 | 
							if (conn->lease == lease) {
 | 
				
			||||||
| 
						 | 
					@ -2233,4 +2218,5 @@ void drm_lease_destroy(struct wlr_drm_lease *lease) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(lease);
 | 
						free(lease);
 | 
				
			||||||
 | 
						scan_drm_connectors(drm, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,8 @@
 | 
				
			||||||
#include "backend/drm/fb.h"
 | 
					#include "backend/drm/fb.h"
 | 
				
			||||||
#include "backend/drm/iface.h"
 | 
					#include "backend/drm/iface.h"
 | 
				
			||||||
#include "backend/drm/util.h"
 | 
					#include "backend/drm/util.h"
 | 
				
			||||||
 | 
					#include "render/color.h"
 | 
				
			||||||
 | 
					#include "types/wlr_output.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool legacy_fb_props_match(struct wlr_drm_fb *fb1,
 | 
					static bool legacy_fb_props_match(struct wlr_drm_fb *fb1,
 | 
				
			||||||
		struct wlr_drm_fb *fb2) {
 | 
							struct wlr_drm_fb *fb2) {
 | 
				
			||||||
| 
						 | 
					@ -39,20 +41,41 @@ static bool legacy_crtc_test(const struct wlr_drm_connector_state *state,
 | 
				
			||||||
	struct wlr_drm_connector *conn = state->connector;
 | 
						struct wlr_drm_connector *conn = state->connector;
 | 
				
			||||||
	struct wlr_drm_crtc *crtc = conn->crtc;
 | 
						struct wlr_drm_crtc *crtc = conn->crtc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((state->base->committed & WLR_OUTPUT_STATE_BUFFER) && !modeset) {
 | 
						if (state->base->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
				
			||||||
		struct wlr_drm_fb *pending_fb = state->primary_fb;
 | 
							// If the size doesn't match, reject buffer (scaling is not supported)
 | 
				
			||||||
 | 
							int pending_width, pending_height;
 | 
				
			||||||
		struct wlr_drm_fb *prev_fb = crtc->primary->queued_fb;
 | 
							output_pending_resolution(&state->connector->output, state->base,
 | 
				
			||||||
		if (!prev_fb) {
 | 
								&pending_width, &pending_height);
 | 
				
			||||||
			prev_fb = crtc->primary->current_fb;
 | 
							if (state->base->buffer->width != pending_width ||
 | 
				
			||||||
 | 
									state->base->buffer->height != pending_height) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Source crop is also not supported
 | 
				
			||||||
 | 
							struct wlr_fbox src_box;
 | 
				
			||||||
 | 
							output_state_get_buffer_src_box(state->base, &src_box);
 | 
				
			||||||
 | 
							if (src_box.x != 0.0 || src_box.y != 0.0 ||
 | 
				
			||||||
 | 
									src_box.width != (double)state->base->buffer->width ||
 | 
				
			||||||
 | 
									src_box.height != (double)state->base->buffer->height) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG, "Source crop not supported in DRM-legacy output");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Legacy is only guaranteed to be able to display a FB if it's been
 | 
							if (!modeset) {
 | 
				
			||||||
		 * allocated the same way as the previous one. */
 | 
								struct wlr_drm_fb *pending_fb = state->primary_fb;
 | 
				
			||||||
		if (prev_fb != NULL && !legacy_fb_props_match(prev_fb, pending_fb)) {
 | 
					
 | 
				
			||||||
			wlr_drm_conn_log(conn, WLR_DEBUG,
 | 
								struct wlr_drm_fb *prev_fb = crtc->primary->queued_fb;
 | 
				
			||||||
				"Cannot change scan-out buffer parameters with legacy KMS API");
 | 
								if (!prev_fb) {
 | 
				
			||||||
			return false;
 | 
									prev_fb = crtc->primary->current_fb;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* Legacy is only guaranteed to be able to display a FB if it's been
 | 
				
			||||||
 | 
								* allocated the same way as the previous one. */
 | 
				
			||||||
 | 
								if (prev_fb != NULL && !legacy_fb_props_match(prev_fb, pending_fb)) {
 | 
				
			||||||
 | 
									wlr_drm_conn_log(conn, WLR_DEBUG,
 | 
				
			||||||
 | 
										"Cannot change scan-out buffer parameters with legacy KMS API");
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -102,9 +125,17 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
 | 
						if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
 | 
				
			||||||
		if (!drm_legacy_crtc_set_gamma(drm, crtc,
 | 
							size_t dim = 0;
 | 
				
			||||||
				state->base->gamma_lut_size, state->base->gamma_lut)) {
 | 
							uint16_t *lut = NULL;
 | 
				
			||||||
 | 
							if (state->base->color_transform != NULL) {
 | 
				
			||||||
 | 
								struct wlr_color_transform_lut_3x1d *tr =
 | 
				
			||||||
 | 
									color_transform_lut_3x1d_from_base(state->base->color_transform);
 | 
				
			||||||
 | 
								dim = tr->dim;
 | 
				
			||||||
 | 
								lut = tr->lut_3x1d;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -128,7 +159,7 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
 | 
				
			||||||
			state->base->adaptive_sync_enabled ? "enabled" : "disabled");
 | 
								state->base->adaptive_sync_enabled ? "enabled" : "disabled");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cursor != NULL && drm_connector_is_cursor_visible(conn)) {
 | 
						if (cursor != NULL && state->active && drm_connector_is_cursor_visible(conn)) {
 | 
				
			||||||
		struct wlr_drm_fb *cursor_fb = state->cursor_fb;
 | 
							struct wlr_drm_fb *cursor_fb = state->cursor_fb;
 | 
				
			||||||
		if (cursor_fb == NULL) {
 | 
							if (cursor_fb == NULL) {
 | 
				
			||||||
			wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to acquire cursor FB");
 | 
								wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to acquire cursor FB");
 | 
				
			||||||
| 
						 | 
					@ -170,7 +201,9 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (flags & DRM_MODE_PAGE_FLIP_EVENT) {
 | 
						// Legacy uAPI doesn't support requesting page-flip events when
 | 
				
			||||||
 | 
						// turning off a CRTC
 | 
				
			||||||
 | 
						if (state->active && (flags & DRM_MODE_PAGE_FLIP_EVENT)) {
 | 
				
			||||||
		if (drmModePageFlip(drm->fd, crtc->id, fb_id, flags, page_flip)) {
 | 
							if (drmModePageFlip(drm->fd, crtc->id, fb_id, flags, page_flip)) {
 | 
				
			||||||
			wlr_drm_conn_log_errno(conn, WLR_ERROR, "drmModePageFlip failed");
 | 
								wlr_drm_conn_log_errno(conn, WLR_ERROR, "drmModePageFlip failed");
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
| 
						 | 
					@ -248,20 +281,6 @@ bool drm_legacy_crtc_set_gamma(struct wlr_drm_backend *drm,
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool legacy_reset(struct wlr_drm_backend *drm) {
 | 
					 | 
				
			||||||
	bool ok = true;
 | 
					 | 
				
			||||||
	for (size_t i = 0; i < drm->num_crtcs; i++) {
 | 
					 | 
				
			||||||
		struct wlr_drm_crtc *crtc = &drm->crtcs[i];
 | 
					 | 
				
			||||||
		if (drmModeSetCrtc(drm->fd, crtc->id, 0, 0, 0, NULL, 0, NULL) != 0) {
 | 
					 | 
				
			||||||
			wlr_log_errno(WLR_ERROR, "Failed to disable CRTC %"PRIu32,
 | 
					 | 
				
			||||||
				crtc->id);
 | 
					 | 
				
			||||||
			ok = false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ok;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const struct wlr_drm_interface legacy_iface = {
 | 
					const struct wlr_drm_interface legacy_iface = {
 | 
				
			||||||
	.commit = legacy_commit,
 | 
						.commit = legacy_commit,
 | 
				
			||||||
	.reset = legacy_reset,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,12 +4,14 @@
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <wlr/util/box.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "backend/drm/drm.h"
 | 
					#include "backend/drm/drm.h"
 | 
				
			||||||
#include "backend/drm/fb.h"
 | 
					#include "backend/drm/fb.h"
 | 
				
			||||||
#include "backend/drm/iface.h"
 | 
					#include "backend/drm/iface.h"
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#include "types/wlr_output.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void log_handler(enum liftoff_log_priority priority, const char *fmt, va_list args) {
 | 
					static void log_handler(enum liftoff_log_priority priority, const char *fmt, va_list args) {
 | 
				
			||||||
	enum wlr_log_importance importance = WLR_SILENT;
 | 
						enum wlr_log_importance importance = WLR_SILENT;
 | 
				
			||||||
| 
						 | 
					@ -149,25 +151,23 @@ static bool add_prop(drmModeAtomicReq *req, uint32_t obj,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool set_plane_props(struct wlr_drm_plane *plane,
 | 
					static bool set_plane_props(struct wlr_drm_plane *plane,
 | 
				
			||||||
		struct liftoff_layer *layer, struct wlr_drm_fb *fb, int32_t x, int32_t y, uint64_t zpos) {
 | 
							struct liftoff_layer *layer, struct wlr_drm_fb *fb, uint64_t zpos,
 | 
				
			||||||
 | 
							const struct wlr_box *dst_box, const struct wlr_fbox *src_box) {
 | 
				
			||||||
	if (fb == NULL) {
 | 
						if (fb == NULL) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to acquire FB for plane %"PRIu32, plane->id);
 | 
							wlr_log(WLR_ERROR, "Failed to acquire FB for plane %"PRIu32, plane->id);
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t width = fb->wlr_buf->width;
 | 
						// The src_* properties are in 16.16 fixed point
 | 
				
			||||||
	uint32_t height = fb->wlr_buf->height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// The SRC_* properties are in 16.16 fixed point
 | 
					 | 
				
			||||||
	return liftoff_layer_set_property(layer, "zpos", zpos) == 0 &&
 | 
						return liftoff_layer_set_property(layer, "zpos", zpos) == 0 &&
 | 
				
			||||||
		liftoff_layer_set_property(layer, "SRC_X", 0) == 0 &&
 | 
							liftoff_layer_set_property(layer, "SRC_X", src_box->x * (1 << 16)) == 0 &&
 | 
				
			||||||
		liftoff_layer_set_property(layer, "SRC_Y", 0) == 0 &&
 | 
							liftoff_layer_set_property(layer, "SRC_Y", src_box->y * (1 << 16)) == 0 &&
 | 
				
			||||||
		liftoff_layer_set_property(layer, "SRC_W", (uint64_t)width << 16) == 0 &&
 | 
							liftoff_layer_set_property(layer, "SRC_W", src_box->width * (1 << 16)) == 0 &&
 | 
				
			||||||
		liftoff_layer_set_property(layer, "SRC_H", (uint64_t)height << 16) == 0 &&
 | 
							liftoff_layer_set_property(layer, "SRC_H", src_box->height * (1 << 16)) == 0 &&
 | 
				
			||||||
		liftoff_layer_set_property(layer, "CRTC_X", (uint64_t)x) == 0 &&
 | 
							liftoff_layer_set_property(layer, "CRTC_X", dst_box->x) == 0 &&
 | 
				
			||||||
		liftoff_layer_set_property(layer, "CRTC_Y", (uint64_t)y) == 0 &&
 | 
							liftoff_layer_set_property(layer, "CRTC_Y", dst_box->y) == 0 &&
 | 
				
			||||||
		liftoff_layer_set_property(layer, "CRTC_W", width) == 0 &&
 | 
							liftoff_layer_set_property(layer, "CRTC_W", dst_box->width) == 0 &&
 | 
				
			||||||
		liftoff_layer_set_property(layer, "CRTC_H", height) == 0 &&
 | 
							liftoff_layer_set_property(layer, "CRTC_H", dst_box->height) == 0 &&
 | 
				
			||||||
		liftoff_layer_set_property(layer, "FB_ID", fb->id) == 0;
 | 
							liftoff_layer_set_property(layer, "FB_ID", fb->id) == 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -331,14 +331,32 @@ static bool add_connector(drmModeAtomicReq *req,
 | 
				
			||||||
		if (crtc->props.vrr_enabled != 0) {
 | 
							if (crtc->props.vrr_enabled != 0) {
 | 
				
			||||||
			ok = ok && add_prop(req, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
 | 
								ok = ok && add_prop(req, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ok = ok &&
 | 
					
 | 
				
			||||||
			set_plane_props(crtc->primary, crtc->primary->liftoff_layer, state->primary_fb, 0, 0, 0) &&
 | 
							ok = ok && set_plane_props(crtc->primary,
 | 
				
			||||||
			set_plane_props(crtc->primary, crtc->liftoff_composition_layer, state->primary_fb, 0, 0, 0);
 | 
								crtc->primary->liftoff_layer, state->primary_fb, 0,
 | 
				
			||||||
 | 
								&state->primary_viewport.dst_box,
 | 
				
			||||||
 | 
								&state->primary_viewport.src_box);
 | 
				
			||||||
 | 
							ok = ok && set_plane_props(crtc->primary,
 | 
				
			||||||
 | 
								crtc->liftoff_composition_layer, state->primary_fb, 0,
 | 
				
			||||||
 | 
								&state->primary_viewport.dst_box,
 | 
				
			||||||
 | 
								&state->primary_viewport.src_box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		liftoff_layer_set_property(crtc->primary->liftoff_layer,
 | 
							liftoff_layer_set_property(crtc->primary->liftoff_layer,
 | 
				
			||||||
			"FB_DAMAGE_CLIPS", state->fb_damage_clips);
 | 
								"FB_DAMAGE_CLIPS", state->fb_damage_clips);
 | 
				
			||||||
		liftoff_layer_set_property(crtc->liftoff_composition_layer,
 | 
							liftoff_layer_set_property(crtc->liftoff_composition_layer,
 | 
				
			||||||
			"FB_DAMAGE_CLIPS", state->fb_damage_clips);
 | 
								"FB_DAMAGE_CLIPS", state->fb_damage_clips);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (state->primary_in_fence_fd >= 0) {
 | 
				
			||||||
 | 
								liftoff_layer_set_property(crtc->primary->liftoff_layer,
 | 
				
			||||||
 | 
									"IN_FENCE_FD", state->primary_in_fence_fd);
 | 
				
			||||||
 | 
								liftoff_layer_set_property(crtc->liftoff_composition_layer,
 | 
				
			||||||
 | 
									"IN_FENCE_FD", state->primary_in_fence_fd);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
 | 
				
			||||||
 | 
								ok = ok && add_prop(req, crtc->id, crtc->props.out_fence_ptr,
 | 
				
			||||||
 | 
									(uintptr_t)&state->out_fence_fd);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) {
 | 
							if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) {
 | 
				
			||||||
			for (size_t i = 0; i < state->base->layers_len; i++) {
 | 
								for (size_t i = 0; i < state->base->layers_len; i++) {
 | 
				
			||||||
				const struct wlr_output_layer_state *layer_state = &state->base->layers[i];
 | 
									const struct wlr_output_layer_state *layer_state = &state->base->layers[i];
 | 
				
			||||||
| 
						 | 
					@ -349,9 +367,19 @@ static bool add_connector(drmModeAtomicReq *req,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (crtc->cursor) {
 | 
							if (crtc->cursor) {
 | 
				
			||||||
			if (drm_connector_is_cursor_visible(conn)) {
 | 
								if (drm_connector_is_cursor_visible(conn)) {
 | 
				
			||||||
 | 
									struct wlr_fbox cursor_src = {
 | 
				
			||||||
 | 
										.width = state->cursor_fb->wlr_buf->width,
 | 
				
			||||||
 | 
										.height = state->cursor_fb->wlr_buf->height,
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
									struct wlr_box cursor_dst = {
 | 
				
			||||||
 | 
										.x = conn->cursor_x,
 | 
				
			||||||
 | 
										.y = conn->cursor_y,
 | 
				
			||||||
 | 
										.width = state->cursor_fb->wlr_buf->width,
 | 
				
			||||||
 | 
										.height = state->cursor_fb->wlr_buf->height,
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
				ok = ok && set_plane_props(crtc->cursor, crtc->cursor->liftoff_layer,
 | 
									ok = ok && set_plane_props(crtc->cursor, crtc->cursor->liftoff_layer,
 | 
				
			||||||
					state->cursor_fb, conn->cursor_x, conn->cursor_y,
 | 
										state->cursor_fb, wl_list_length(&crtc->layers) + 1,
 | 
				
			||||||
					wl_list_length(&crtc->layers) + 1);
 | 
										&cursor_dst, &cursor_src);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				ok = ok && disable_plane(crtc->cursor);
 | 
									ok = ok && disable_plane(crtc->cursor);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -397,7 +425,7 @@ static bool commit(struct wlr_drm_backend *drm,
 | 
				
			||||||
	if (state->modeset) {
 | 
						if (state->modeset) {
 | 
				
			||||||
		flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
 | 
							flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!test_only && state->nonblock) {
 | 
						if (state->nonblock) {
 | 
				
			||||||
		flags |= DRM_MODE_ATOMIC_NONBLOCK;
 | 
							flags |= DRM_MODE_ATOMIC_NONBLOCK;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -479,5 +507,4 @@ const struct wlr_drm_interface liftoff_iface = {
 | 
				
			||||||
	.init = init,
 | 
						.init = init,
 | 
				
			||||||
	.finish = finish,
 | 
						.finish = finish,
 | 
				
			||||||
	.commit = commit,
 | 
						.commit = commit,
 | 
				
			||||||
	.reset = drm_atomic_reset,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@ hwdata = dependency(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libdisplay_info = dependency(
 | 
					libdisplay_info = dependency(
 | 
				
			||||||
	'libdisplay-info',
 | 
						'libdisplay-info',
 | 
				
			||||||
 | 
						version: '>=0.2.0',
 | 
				
			||||||
	required: 'drm' in backends,
 | 
						required: 'drm' in backends,
 | 
				
			||||||
	fallback: 'libdisplay-info',
 | 
						fallback: 'libdisplay-info',
 | 
				
			||||||
	not_found_message: 'Required for the DRM backend.',
 | 
						not_found_message: 'Required for the DRM backend.',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
#include <stddef.h>
 | 
					#include <stddef.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include <xf86drm.h>
 | 
					#include <xf86drm.h>
 | 
				
			||||||
#include <xf86drmMode.h>
 | 
					#include <xf86drmMode.h>
 | 
				
			||||||
| 
						 | 
					@ -21,8 +22,10 @@ struct prop_info {
 | 
				
			||||||
static const struct prop_info connector_info[] = {
 | 
					static const struct prop_info connector_info[] = {
 | 
				
			||||||
#define INDEX(name) (offsetof(struct wlr_drm_connector_props, name) / sizeof(uint32_t))
 | 
					#define INDEX(name) (offsetof(struct wlr_drm_connector_props, name) / sizeof(uint32_t))
 | 
				
			||||||
	{ "CRTC_ID", INDEX(crtc_id) },
 | 
						{ "CRTC_ID", INDEX(crtc_id) },
 | 
				
			||||||
 | 
						{ "Colorspace", INDEX(colorspace) },
 | 
				
			||||||
	{ "DPMS", INDEX(dpms) },
 | 
						{ "DPMS", INDEX(dpms) },
 | 
				
			||||||
	{ "EDID", INDEX(edid) },
 | 
						{ "EDID", INDEX(edid) },
 | 
				
			||||||
 | 
						{ "HDR_OUTPUT_METADATA", INDEX(hdr_output_metadata) },
 | 
				
			||||||
	{ "PATH", INDEX(path) },
 | 
						{ "PATH", INDEX(path) },
 | 
				
			||||||
	{ "content type", INDEX(content_type) },
 | 
						{ "content type", INDEX(content_type) },
 | 
				
			||||||
	{ "link-status", INDEX(link_status) },
 | 
						{ "link-status", INDEX(link_status) },
 | 
				
			||||||
| 
						 | 
					@ -40,6 +43,7 @@ static const struct prop_info crtc_info[] = {
 | 
				
			||||||
	{ "GAMMA_LUT", INDEX(gamma_lut) },
 | 
						{ "GAMMA_LUT", INDEX(gamma_lut) },
 | 
				
			||||||
	{ "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) },
 | 
						{ "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) },
 | 
				
			||||||
	{ "MODE_ID", INDEX(mode_id) },
 | 
						{ "MODE_ID", INDEX(mode_id) },
 | 
				
			||||||
 | 
						{ "OUT_FENCE_PTR", INDEX(out_fence_ptr) },
 | 
				
			||||||
	{ "VRR_ENABLED", INDEX(vrr_enabled) },
 | 
						{ "VRR_ENABLED", INDEX(vrr_enabled) },
 | 
				
			||||||
#undef INDEX
 | 
					#undef INDEX
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -55,6 +59,7 @@ static const struct prop_info plane_info[] = {
 | 
				
			||||||
	{ "FB_ID", INDEX(fb_id) },
 | 
						{ "FB_ID", INDEX(fb_id) },
 | 
				
			||||||
	{ "HOTSPOT_X", INDEX(hotspot_x) },
 | 
						{ "HOTSPOT_X", INDEX(hotspot_x) },
 | 
				
			||||||
	{ "HOTSPOT_Y", INDEX(hotspot_y) },
 | 
						{ "HOTSPOT_Y", INDEX(hotspot_y) },
 | 
				
			||||||
 | 
						{ "IN_FENCE_FD", INDEX(in_fence_fd) },
 | 
				
			||||||
	{ "IN_FORMATS", INDEX(in_formats) },
 | 
						{ "IN_FORMATS", INDEX(in_formats) },
 | 
				
			||||||
	{ "SIZE_HINTS", INDEX(size_hints) },
 | 
						{ "SIZE_HINTS", INDEX(size_hints) },
 | 
				
			||||||
	{ "SRC_H", INDEX(src_h) },
 | 
						{ "SRC_H", INDEX(src_h) },
 | 
				
			||||||
| 
						 | 
					@ -77,14 +82,14 @@ static bool scan_properties(int fd, uint32_t id, uint32_t type, uint32_t *result
 | 
				
			||||||
		const struct prop_info *info, size_t info_len) {
 | 
							const struct prop_info *info, size_t info_len) {
 | 
				
			||||||
	drmModeObjectProperties *props = drmModeObjectGetProperties(fd, id, type);
 | 
						drmModeObjectProperties *props = drmModeObjectGetProperties(fd, id, type);
 | 
				
			||||||
	if (!props) {
 | 
						if (!props) {
 | 
				
			||||||
		wlr_log_errno(WLR_ERROR, "Failed to get DRM object properties");
 | 
							wlr_log_errno(WLR_ERROR, "Failed to get DRM object %" PRIu32 " properties", id);
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (uint32_t i = 0; i < props->count_props; ++i) {
 | 
						for (uint32_t i = 0; i < props->count_props; ++i) {
 | 
				
			||||||
		drmModePropertyRes *prop = drmModeGetProperty(fd, props->props[i]);
 | 
							drmModePropertyRes *prop = drmModeGetProperty(fd, props->props[i]);
 | 
				
			||||||
		if (!prop) {
 | 
							if (!prop) {
 | 
				
			||||||
			wlr_log_errno(WLR_ERROR, "Failed to get DRM object property");
 | 
								wlr_log_errno(WLR_ERROR, "Failed to get property %" PRIu32 " of DRM object %" PRIu32, props->props[i], id);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,31 +1,35 @@
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <drm_fourcc.h>
 | 
					#include <drm_fourcc.h>
 | 
				
			||||||
 | 
					#include <wlr/render/allocator.h>
 | 
				
			||||||
 | 
					#include <wlr/render/drm_syncobj.h>
 | 
				
			||||||
#include <wlr/render/swapchain.h>
 | 
					#include <wlr/render/swapchain.h>
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "backend/drm/drm.h"
 | 
					#include "backend/drm/drm.h"
 | 
				
			||||||
#include "backend/drm/fb.h"
 | 
					#include "backend/drm/fb.h"
 | 
				
			||||||
#include "backend/drm/renderer.h"
 | 
					#include "backend/drm/renderer.h"
 | 
				
			||||||
#include "backend/backend.h"
 | 
					 | 
				
			||||||
#include "render/drm_format_set.h"
 | 
					#include "render/drm_format_set.h"
 | 
				
			||||||
#include "render/allocator/allocator.h"
 | 
					 | 
				
			||||||
#include "render/pixel_format.h"
 | 
					#include "render/pixel_format.h"
 | 
				
			||||||
#include "render/wlr_renderer.h"
 | 
					#include "render/wlr_renderer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool init_drm_renderer(struct wlr_drm_backend *drm,
 | 
					bool init_drm_renderer(struct wlr_drm_backend *drm,
 | 
				
			||||||
		struct wlr_drm_renderer *renderer) {
 | 
							struct wlr_drm_renderer *renderer) {
 | 
				
			||||||
 | 
						wlr_log(WLR_DEBUG, "Creating multi-GPU renderer");
 | 
				
			||||||
	renderer->wlr_rend = renderer_autocreate_with_drm_fd(drm->fd);
 | 
						renderer->wlr_rend = renderer_autocreate_with_drm_fd(drm->fd);
 | 
				
			||||||
	if (!renderer->wlr_rend) {
 | 
						if (!renderer->wlr_rend) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to create renderer");
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (wlr_renderer_get_texture_formats(renderer->wlr_rend, WLR_BUFFER_CAP_DMABUF) == NULL) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Renderer did not support importing DMA-BUFs");
 | 
				
			||||||
 | 
							wlr_renderer_destroy(renderer->wlr_rend);
 | 
				
			||||||
 | 
							renderer->wlr_rend = NULL;
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t backend_caps = backend_get_buffer_caps(&drm->backend);
 | 
						renderer->allocator = wlr_allocator_autocreate(&drm->backend, renderer->wlr_rend);
 | 
				
			||||||
	renderer->allocator = allocator_autocreate_with_drm_fd(backend_caps,
 | 
					 | 
				
			||||||
		renderer->wlr_rend, drm->fd);
 | 
					 | 
				
			||||||
	if (renderer->allocator == NULL) {
 | 
						if (renderer->allocator == NULL) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to create allocator");
 | 
					 | 
				
			||||||
		wlr_renderer_destroy(renderer->wlr_rend);
 | 
							wlr_renderer_destroy(renderer->wlr_rend);
 | 
				
			||||||
 | 
							renderer->wlr_rend = NULL;
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,6 +50,7 @@ void finish_drm_surface(struct wlr_drm_surface *surf) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_drm_syncobj_timeline_unref(surf->timeline);
 | 
				
			||||||
	wlr_swapchain_destroy(surf->swapchain);
 | 
						wlr_swapchain_destroy(surf->swapchain);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*surf = (struct wlr_drm_surface){0};
 | 
						*surf = (struct wlr_drm_surface){0};
 | 
				
			||||||
| 
						 | 
					@ -68,13 +73,24 @@ bool init_drm_surface(struct wlr_drm_surface *surf,
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int drm_fd = wlr_renderer_get_drm_fd(renderer->wlr_rend);
 | 
				
			||||||
 | 
						if (renderer->wlr_rend->features.timeline && drm_fd >= 0) {
 | 
				
			||||||
 | 
							surf->timeline = wlr_drm_syncobj_timeline_create(drm_fd);
 | 
				
			||||||
 | 
							if (surf->timeline == NULL) {
 | 
				
			||||||
 | 
								finish_drm_surface(surf);
 | 
				
			||||||
 | 
								wlr_log(WLR_ERROR, "Failed to create DRM syncobj timeline");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	surf->renderer = renderer;
 | 
						surf->renderer = renderer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
 | 
					struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
 | 
				
			||||||
		struct wlr_buffer *buffer) {
 | 
							struct wlr_buffer *buffer,
 | 
				
			||||||
 | 
							struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
 | 
				
			||||||
	struct wlr_renderer *renderer = surf->renderer->wlr_rend;
 | 
						struct wlr_renderer *renderer = surf->renderer->wlr_rend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (surf->swapchain->width != buffer->width ||
 | 
						if (surf->swapchain->width != buffer->width ||
 | 
				
			||||||
| 
						 | 
					@ -89,13 +105,18 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_buffer *dst = wlr_swapchain_acquire(surf->swapchain, NULL);
 | 
						struct wlr_buffer *dst = wlr_swapchain_acquire(surf->swapchain);
 | 
				
			||||||
	if (!dst) {
 | 
						if (!dst) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to acquire multi-GPU swapchain buffer");
 | 
							wlr_log(WLR_ERROR, "Failed to acquire multi-GPU swapchain buffer");
 | 
				
			||||||
		goto error_tex;
 | 
							goto error_tex;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_render_pass *pass = wlr_renderer_begin_buffer_pass(renderer, dst, NULL);
 | 
						surf->point++;
 | 
				
			||||||
 | 
						const struct wlr_buffer_pass_options pass_options = {
 | 
				
			||||||
 | 
							.signal_timeline = surf->timeline,
 | 
				
			||||||
 | 
							.signal_point = surf->point,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						struct wlr_render_pass *pass = wlr_renderer_begin_buffer_pass(renderer, dst, &pass_options);
 | 
				
			||||||
	if (pass == NULL) {
 | 
						if (pass == NULL) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to begin render pass with multi-GPU destination buffer");
 | 
							wlr_log(WLR_ERROR, "Failed to begin render pass with multi-GPU destination buffer");
 | 
				
			||||||
		goto error_dst;
 | 
							goto error_dst;
 | 
				
			||||||
| 
						 | 
					@ -104,6 +125,8 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
 | 
				
			||||||
	wlr_render_pass_add_texture(pass, &(struct wlr_render_texture_options){
 | 
						wlr_render_pass_add_texture(pass, &(struct wlr_render_texture_options){
 | 
				
			||||||
		.texture = tex,
 | 
							.texture = tex,
 | 
				
			||||||
		.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
 | 
							.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
 | 
				
			||||||
 | 
							.wait_timeline = wait_timeline,
 | 
				
			||||||
 | 
							.wait_point = wait_point,
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
	if (!wlr_render_pass_submit(pass)) {
 | 
						if (!wlr_render_pass_submit(pass)) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to submit multi-GPU render pass");
 | 
							wlr_log(WLR_ERROR, "Failed to submit multi-GPU render pass");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,6 +83,17 @@ void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data)
 | 
				
			||||||
	output->model = di_info_get_model(info);
 | 
						output->model = di_info_get_model(info);
 | 
				
			||||||
	output->serial = di_info_get_serial(info);
 | 
						output->serial = di_info_get_serial(info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const struct di_supported_signal_colorimetry *colorimetry = di_info_get_supported_signal_colorimetry(info);
 | 
				
			||||||
 | 
						bool has_bt2020 = colorimetry->bt2020_cycc || colorimetry->bt2020_ycc || colorimetry->bt2020_rgb;
 | 
				
			||||||
 | 
						if (conn->props.colorspace != 0 && has_bt2020) {
 | 
				
			||||||
 | 
							output->supported_primaries |= WLR_COLOR_NAMED_PRIMARIES_BT2020;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const struct di_hdr_static_metadata *hdr_static_metadata = di_info_get_hdr_static_metadata(info);
 | 
				
			||||||
 | 
						if (conn->props.hdr_output_metadata != 0 && hdr_static_metadata->type1 && hdr_static_metadata->pq) {
 | 
				
			||||||
 | 
							output->supported_transfer_functions |= WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	di_info_destroy(info);
 | 
						di_info_destroy(info);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,9 +123,9 @@ static bool is_taken(size_t n, const uint32_t arr[static n], uint32_t key) {
 | 
				
			||||||
 * passing 12 arguments to a function.
 | 
					 * passing 12 arguments to a function.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct match_state {
 | 
					struct match_state {
 | 
				
			||||||
	const size_t num_objs;
 | 
						const size_t num_conns;
 | 
				
			||||||
	const uint32_t *restrict objs;
 | 
						const uint32_t *restrict conns;
 | 
				
			||||||
	const size_t num_res;
 | 
						const size_t num_crtcs;
 | 
				
			||||||
	size_t score;
 | 
						size_t score;
 | 
				
			||||||
	size_t replaced;
 | 
						size_t replaced;
 | 
				
			||||||
	uint32_t *restrict res;
 | 
						uint32_t *restrict res;
 | 
				
			||||||
| 
						 | 
					@ -123,27 +134,31 @@ struct match_state {
 | 
				
			||||||
	bool exit_early;
 | 
						bool exit_early;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/**
 | 
				
			||||||
 * skips: The number of SKIP elements encountered so far.
 | 
					 * Step to process a CRTC.
 | 
				
			||||||
 * score: The number of resources we've matched so far.
 | 
					 *
 | 
				
			||||||
 | 
					 * This is a naive implementation of maximum bipartite matching.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * score: The number of connectors we've matched so far.
 | 
				
			||||||
 * replaced: The number of changes from the original solution.
 | 
					 * replaced: The number of changes from the original solution.
 | 
				
			||||||
 * i: The index of the current element.
 | 
					 * crtc_index: The index of the current CRTC.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This tries to match a solution as close to st->orig as it can.
 | 
					 * This tries to match a solution as close to st->orig as it can.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns whether we've set a new best element with this solution.
 | 
					 * Returns whether we've set a new best element with this solution.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_t replaced, size_t i) {
 | 
					static bool match_connectors_with_crtcs_(struct match_state *st,
 | 
				
			||||||
 | 
							size_t score, size_t replaced, size_t crtc_index) {
 | 
				
			||||||
	// Finished
 | 
						// Finished
 | 
				
			||||||
	if (i >= st->num_res) {
 | 
						if (crtc_index >= st->num_crtcs) {
 | 
				
			||||||
		if (score > st->score ||
 | 
							if (score > st->score ||
 | 
				
			||||||
				(score == st->score && replaced < st->replaced)) {
 | 
									(score == st->score && replaced < st->replaced)) {
 | 
				
			||||||
			st->score = score;
 | 
								st->score = score;
 | 
				
			||||||
			st->replaced = replaced;
 | 
								st->replaced = replaced;
 | 
				
			||||||
			memcpy(st->best, st->res, sizeof(st->best[0]) * st->num_res);
 | 
								memcpy(st->best, st->res, sizeof(st->best[0]) * st->num_crtcs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			st->exit_early = (st->score == st->num_res - skips
 | 
								st->exit_early = (st->score == st->num_crtcs
 | 
				
			||||||
					|| st->score == st->num_objs)
 | 
										|| st->score == st->num_conns)
 | 
				
			||||||
					&& st->replaced == 0;
 | 
										&& st->replaced == 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
| 
						 | 
					@ -152,21 +167,16 @@ static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (st->orig[i] == SKIP) {
 | 
					 | 
				
			||||||
		st->res[i] = SKIP;
 | 
					 | 
				
			||||||
		return match_obj_(st, skips + 1, score, replaced, i + 1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool has_best = false;
 | 
						bool has_best = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Attempt to use the current solution first, to try and avoid
 | 
						 * Attempt to use the current solution first, to try and avoid
 | 
				
			||||||
	 * recalculating everything
 | 
						 * recalculating everything
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (st->orig[i] != UNMATCHED && !is_taken(i, st->res, st->orig[i])) {
 | 
						if (st->orig[crtc_index] != UNMATCHED && !is_taken(crtc_index, st->res, st->orig[crtc_index])) {
 | 
				
			||||||
		st->res[i] = st->orig[i];
 | 
							st->res[crtc_index] = st->orig[crtc_index];
 | 
				
			||||||
		size_t obj_score = st->objs[st->res[i]] != 0 ? 1 : 0;
 | 
							size_t crtc_score = st->conns[st->res[crtc_index]] != 0 ? 1 : 0;
 | 
				
			||||||
		if (match_obj_(st, skips, score + obj_score, replaced, i + 1)) {
 | 
							if (match_connectors_with_crtcs_(st, score + crtc_score, replaced, crtc_index + 1)) {
 | 
				
			||||||
			has_best = true;
 | 
								has_best = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -174,29 +184,29 @@ static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (st->orig[i] != UNMATCHED) {
 | 
						if (st->orig[crtc_index] != UNMATCHED) {
 | 
				
			||||||
		++replaced;
 | 
							++replaced;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (size_t candidate = 0; candidate < st->num_objs; ++candidate) {
 | 
						for (size_t candidate = 0; candidate < st->num_conns; ++candidate) {
 | 
				
			||||||
		// We tried this earlier
 | 
							// We tried this earlier
 | 
				
			||||||
		if (candidate == st->orig[i]) {
 | 
							if (candidate == st->orig[crtc_index]) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Not compatible
 | 
							// Not compatible
 | 
				
			||||||
		if (!(st->objs[candidate] & (1 << i))) {
 | 
							if (!(st->conns[candidate] & (1 << crtc_index))) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Already taken
 | 
							// Already taken
 | 
				
			||||||
		if (is_taken(i, st->res, candidate)) {
 | 
							if (is_taken(crtc_index, st->res, candidate)) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		st->res[i] = candidate;
 | 
							st->res[crtc_index] = candidate;
 | 
				
			||||||
		size_t obj_score = st->objs[candidate] != 0 ? 1 : 0;
 | 
							size_t crtc_score = st->conns[candidate] != 0 ? 1 : 0;
 | 
				
			||||||
		if (match_obj_(st, skips, score + obj_score, replaced, i + 1)) {
 | 
							if (match_connectors_with_crtcs_(st, score + crtc_score, replaced, crtc_index + 1)) {
 | 
				
			||||||
			has_best = true;
 | 
								has_best = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -205,37 +215,37 @@ static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Maybe this resource can't be matched
 | 
						// Maybe this CRTC can't be matched
 | 
				
			||||||
	st->res[i] = UNMATCHED;
 | 
						st->res[crtc_index] = UNMATCHED;
 | 
				
			||||||
	if (match_obj_(st, skips, score, replaced, i + 1)) {
 | 
						if (match_connectors_with_crtcs_(st, score, replaced, crtc_index + 1)) {
 | 
				
			||||||
		has_best = true;
 | 
							has_best = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return has_best;
 | 
						return has_best;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs],
 | 
					void match_connectors_with_crtcs(size_t num_conns,
 | 
				
			||||||
		size_t num_res, const uint32_t res[static restrict num_res],
 | 
							const uint32_t conns[static restrict num_conns],
 | 
				
			||||||
		uint32_t out[static restrict num_res]) {
 | 
							size_t num_crtcs, const uint32_t prev_crtcs[static restrict num_crtcs],
 | 
				
			||||||
	uint32_t solution[num_res];
 | 
							uint32_t new_crtcs[static restrict num_crtcs]) {
 | 
				
			||||||
	for (size_t i = 0; i < num_res; ++i) {
 | 
						uint32_t solution[num_crtcs];
 | 
				
			||||||
 | 
						for (size_t i = 0; i < num_crtcs; ++i) {
 | 
				
			||||||
		solution[i] = UNMATCHED;
 | 
							solution[i] = UNMATCHED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct match_state st = {
 | 
						struct match_state st = {
 | 
				
			||||||
		.num_objs = num_objs,
 | 
							.num_conns = num_conns,
 | 
				
			||||||
		.num_res = num_res,
 | 
							.num_crtcs = num_crtcs,
 | 
				
			||||||
		.score = 0,
 | 
							.score = 0,
 | 
				
			||||||
		.replaced = SIZE_MAX,
 | 
							.replaced = SIZE_MAX,
 | 
				
			||||||
		.objs = objs,
 | 
							.conns = conns,
 | 
				
			||||||
		.res = solution,
 | 
							.res = solution,
 | 
				
			||||||
		.best = out,
 | 
							.best = new_crtcs,
 | 
				
			||||||
		.orig = res,
 | 
							.orig = prev_crtcs,
 | 
				
			||||||
		.exit_early = false,
 | 
							.exit_early = false,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	match_obj_(&st, 0, 0, 0, 0);
 | 
						match_connectors_with_crtcs_(&st, 0, 0, 0);
 | 
				
			||||||
	return st.score;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void generate_cvt_mode(drmModeModeInfo *mode, int hdisplay, int vdisplay,
 | 
					void generate_cvt_mode(drmModeModeInfo *mode, int hdisplay, int vdisplay,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,16 +45,9 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
 | 
				
			||||||
	free(backend);
 | 
						free(backend);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t get_buffer_caps(struct wlr_backend *wlr_backend) {
 | 
					 | 
				
			||||||
	return WLR_BUFFER_CAP_DATA_PTR
 | 
					 | 
				
			||||||
		| WLR_BUFFER_CAP_DMABUF
 | 
					 | 
				
			||||||
		| WLR_BUFFER_CAP_SHM;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct wlr_backend_impl backend_impl = {
 | 
					static const struct wlr_backend_impl backend_impl = {
 | 
				
			||||||
	.start = backend_start,
 | 
						.start = backend_start,
 | 
				
			||||||
	.destroy = backend_destroy,
 | 
						.destroy = backend_destroy,
 | 
				
			||||||
	.get_buffer_caps = get_buffer_caps,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_event_loop_destroy(struct wl_listener *listener, void *data) {
 | 
					static void handle_event_loop_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
| 
						 | 
					@ -74,12 +67,17 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_event_loop *loop) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_backend_init(&backend->backend, &backend_impl);
 | 
						wlr_backend_init(&backend->backend, &backend_impl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						backend->backend.buffer_caps =
 | 
				
			||||||
 | 
							WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_SHM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	backend->event_loop = loop;
 | 
						backend->event_loop = loop;
 | 
				
			||||||
	wl_list_init(&backend->outputs);
 | 
						wl_list_init(&backend->outputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	backend->event_loop_destroy.notify = handle_event_loop_destroy;
 | 
						backend->event_loop_destroy.notify = handle_event_loop_destroy;
 | 
				
			||||||
	wl_event_loop_add_destroy_listener(loop, &backend->event_loop_destroy);
 | 
						wl_event_loop_add_destroy_listener(loop, &backend->event_loop_destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						backend->backend.features.timeline = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &backend->backend;
 | 
						return &backend->backend;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,9 +79,20 @@ static bool output_commit(struct wlr_output *wlr_output,
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool output_set_cursor(struct wlr_output *wlr_output,
 | 
				
			||||||
 | 
							struct wlr_buffer *buffer, int hotspot_x, int hotspot_y) {
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool output_move_cursor(struct wlr_output *wlr_output, int x, int y) {
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_destroy(struct wlr_output *wlr_output) {
 | 
					static void output_destroy(struct wlr_output *wlr_output) {
 | 
				
			||||||
	struct wlr_headless_output *output =
 | 
						struct wlr_headless_output *output = headless_output_from_output(wlr_output);
 | 
				
			||||||
		headless_output_from_output(wlr_output);
 | 
					
 | 
				
			||||||
 | 
						wlr_output_finish(wlr_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_remove(&output->link);
 | 
						wl_list_remove(&output->link);
 | 
				
			||||||
	wl_event_source_remove(output->frame_timer);
 | 
						wl_event_source_remove(output->frame_timer);
 | 
				
			||||||
	free(output);
 | 
						free(output);
 | 
				
			||||||
| 
						 | 
					@ -89,7 +100,10 @@ static void output_destroy(struct wlr_output *wlr_output) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct wlr_output_impl output_impl = {
 | 
					static const struct wlr_output_impl output_impl = {
 | 
				
			||||||
	.destroy = output_destroy,
 | 
						.destroy = output_destroy,
 | 
				
			||||||
 | 
						.test = output_test,
 | 
				
			||||||
	.commit = output_commit,
 | 
						.commit = output_commit,
 | 
				
			||||||
 | 
						.set_cursor = output_set_cursor,
 | 
				
			||||||
 | 
						.move_cursor = output_move_cursor,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_output_is_headless(struct wlr_output *wlr_output) {
 | 
					bool wlr_output_is_headless(struct wlr_output *wlr_output) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,25 +61,15 @@ void handle_pointer_button(struct libinput_event *event,
 | 
				
			||||||
		.time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)),
 | 
							.time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)),
 | 
				
			||||||
		.button = libinput_event_pointer_get_button(pevent),
 | 
							.button = libinput_event_pointer_get_button(pevent),
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	// Ignore events which aren't a seat-wide state change. For instance, if
 | 
					 | 
				
			||||||
	// the same button is pressed twice on the same seat, ignore the second
 | 
					 | 
				
			||||||
	// press.
 | 
					 | 
				
			||||||
	uint32_t seat_count = libinput_event_pointer_get_seat_button_count(pevent);
 | 
					 | 
				
			||||||
	switch (libinput_event_pointer_get_button_state(pevent)) {
 | 
						switch (libinput_event_pointer_get_button_state(pevent)) {
 | 
				
			||||||
	case LIBINPUT_BUTTON_STATE_PRESSED:
 | 
						case LIBINPUT_BUTTON_STATE_PRESSED:
 | 
				
			||||||
		wlr_event.state = WL_POINTER_BUTTON_STATE_PRESSED;
 | 
							wlr_event.state = WL_POINTER_BUTTON_STATE_PRESSED;
 | 
				
			||||||
		if (seat_count != 1) {
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case LIBINPUT_BUTTON_STATE_RELEASED:
 | 
						case LIBINPUT_BUTTON_STATE_RELEASED:
 | 
				
			||||||
		wlr_event.state = WL_POINTER_BUTTON_STATE_RELEASED;
 | 
							wlr_event.state = WL_POINTER_BUTTON_STATE_RELEASED;
 | 
				
			||||||
		if (seat_count != 0) {
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wl_signal_emit_mutable(&pointer->events.button, &wlr_event);
 | 
						wlr_pointer_notify_button(pointer, &wlr_event);
 | 
				
			||||||
	wl_signal_emit_mutable(&pointer->events.frame, pointer);
 | 
						wl_signal_emit_mutable(&pointer->events.frame, pointer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,6 +104,7 @@ void init_device_tablet_pad(struct wlr_libinput_input_device *dev) {
 | 
				
			||||||
	struct udev_device *udev = libinput_device_get_udev_device(handle);
 | 
						struct udev_device *udev = libinput_device_get_udev_device(handle);
 | 
				
			||||||
	char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *));
 | 
						char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *));
 | 
				
			||||||
	*dst = strdup(udev_device_get_syspath(udev));
 | 
						*dst = strdup(udev_device_get_syspath(udev));
 | 
				
			||||||
 | 
						udev_device_unref(udev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int groups = libinput_device_tablet_pad_get_num_mode_groups(handle);
 | 
						int groups = libinput_device_tablet_pad_get_num_mode_groups(handle);
 | 
				
			||||||
	for (int i = 0; i < groups; ++i) {
 | 
						for (int i = 0; i < groups; ++i) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
#include <wlr/interfaces/wlr_tablet_tool.h>
 | 
					#include <wlr/interfaces/wlr_tablet_tool.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "backend/libinput.h"
 | 
					#include "backend/libinput.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tablet_tool {
 | 
					struct tablet_tool {
 | 
				
			||||||
	struct wlr_tablet_tool wlr_tool;
 | 
						struct wlr_tablet_tool wlr_tool;
 | 
				
			||||||
| 
						 | 
					@ -36,6 +37,7 @@ void init_device_tablet(struct wlr_libinput_input_device *dev) {
 | 
				
			||||||
	struct udev_device *udev = libinput_device_get_udev_device(dev->handle);
 | 
						struct udev_device *udev = libinput_device_get_udev_device(dev->handle);
 | 
				
			||||||
	char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *));
 | 
						char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *));
 | 
				
			||||||
	*dst = strdup(udev_device_get_syspath(udev));
 | 
						*dst = strdup(udev_device_get_syspath(udev));
 | 
				
			||||||
 | 
						udev_device_unref(udev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_init(&dev->tablet_tools);
 | 
						wl_list_init(&dev->tablet_tools);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,6 @@
 | 
				
			||||||
#include <wlr/types/wlr_buffer.h>
 | 
					#include <wlr/types/wlr_buffer.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					#include <wlr/types/wlr_output.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "backend/backend.h"
 | 
					 | 
				
			||||||
#include "backend/multi.h"
 | 
					#include "backend/multi.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct subbackend_state {
 | 
					struct subbackend_state {
 | 
				
			||||||
| 
						 | 
					@ -52,6 +51,9 @@ static void multi_backend_destroy(struct wlr_backend *wlr_backend) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_backend_finish(wlr_backend);
 | 
						wlr_backend_finish(wlr_backend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(wl_list_empty(&backend->events.backend_add.listener_list));
 | 
				
			||||||
 | 
						assert(wl_list_empty(&backend->events.backend_remove.listener_list));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Some backends may depend on other backends, ie. destroying a backend may
 | 
						// Some backends may depend on other backends, ie. destroying a backend may
 | 
				
			||||||
	// also destroy other backends
 | 
						// also destroy other backends
 | 
				
			||||||
	while (!wl_list_empty(&backend->backends)) {
 | 
						while (!wl_list_empty(&backend->backends)) {
 | 
				
			||||||
| 
						 | 
					@ -76,28 +78,6 @@ static int multi_backend_get_drm_fd(struct wlr_backend *backend) {
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t multi_backend_get_buffer_caps(struct wlr_backend *backend) {
 | 
					 | 
				
			||||||
	struct wlr_multi_backend *multi = multi_backend_from_backend(backend);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (wl_list_empty(&multi->backends)) {
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t caps = WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF
 | 
					 | 
				
			||||||
			| WLR_BUFFER_CAP_SHM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct subbackend_state *sub;
 | 
					 | 
				
			||||||
	wl_list_for_each(sub, &multi->backends, link) {
 | 
					 | 
				
			||||||
		uint32_t backend_caps = backend_get_buffer_caps(sub->backend);
 | 
					 | 
				
			||||||
		if (backend_caps != 0) {
 | 
					 | 
				
			||||||
			// only count backend capable of presenting a buffer
 | 
					 | 
				
			||||||
			caps = caps & backend_caps;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return caps;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int compare_output_state_backend(const void *data_a, const void *data_b) {
 | 
					static int compare_output_state_backend(const void *data_a, const void *data_b) {
 | 
				
			||||||
	const struct wlr_backend_output_state *a = data_a;
 | 
						const struct wlr_backend_output_state *a = data_a;
 | 
				
			||||||
	const struct wlr_backend_output_state *b = data_b;
 | 
						const struct wlr_backend_output_state *b = data_b;
 | 
				
			||||||
| 
						 | 
					@ -126,22 +106,24 @@ static bool commit(struct wlr_backend *backend,
 | 
				
			||||||
	qsort(by_backend, states_len, sizeof(by_backend[0]), compare_output_state_backend);
 | 
						qsort(by_backend, states_len, sizeof(by_backend[0]), compare_output_state_backend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool ok = true;
 | 
						bool ok = true;
 | 
				
			||||||
	for (size_t i = 0; i < states_len; i++) {
 | 
						for (size_t i = 0; i < states_len;) {
 | 
				
			||||||
		struct wlr_backend *sub = by_backend[i].output->backend;
 | 
							struct wlr_backend *sub = by_backend[i].output->backend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		size_t j = i;
 | 
							size_t len = 1;
 | 
				
			||||||
		while (j < states_len && by_backend[j].output->backend == sub) {
 | 
							while (i + len < states_len &&
 | 
				
			||||||
			j++;
 | 
									by_backend[i + len].output->backend == sub) {
 | 
				
			||||||
 | 
								len++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (test_only) {
 | 
							if (test_only) {
 | 
				
			||||||
			ok = wlr_backend_test(sub, &by_backend[i], j - i);
 | 
								ok = wlr_backend_test(sub, &by_backend[i], len);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			ok = wlr_backend_commit(sub, &by_backend[i], j - i);
 | 
								ok = wlr_backend_commit(sub, &by_backend[i], len);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (!ok) {
 | 
							if (!ok) {
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							i += len;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(by_backend);
 | 
						free(by_backend);
 | 
				
			||||||
| 
						 | 
					@ -162,7 +144,6 @@ static const struct wlr_backend_impl backend_impl = {
 | 
				
			||||||
	.start = multi_backend_start,
 | 
						.start = multi_backend_start,
 | 
				
			||||||
	.destroy = multi_backend_destroy,
 | 
						.destroy = multi_backend_destroy,
 | 
				
			||||||
	.get_drm_fd = multi_backend_get_drm_fd,
 | 
						.get_drm_fd = multi_backend_get_drm_fd,
 | 
				
			||||||
	.get_buffer_caps = multi_backend_get_buffer_caps,
 | 
					 | 
				
			||||||
	.test = multi_backend_test,
 | 
						.test = multi_backend_test,
 | 
				
			||||||
	.commit = multi_backend_commit,
 | 
						.commit = multi_backend_commit,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -225,6 +206,33 @@ static struct subbackend_state *multi_backend_get_subbackend(struct wlr_multi_ba
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void multi_backend_refresh_features(struct wlr_multi_backend *multi) {
 | 
				
			||||||
 | 
						multi->backend.buffer_caps = 0;
 | 
				
			||||||
 | 
						multi->backend.features.timeline = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_buffer_cap = false;
 | 
				
			||||||
 | 
						uint32_t buffer_caps_intersection =
 | 
				
			||||||
 | 
							WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_SHM;
 | 
				
			||||||
 | 
						struct subbackend_state *sub = NULL;
 | 
				
			||||||
 | 
						wl_list_for_each(sub, &multi->backends, link) {
 | 
				
			||||||
 | 
							// Only take into account backends capable of presenting a buffer
 | 
				
			||||||
 | 
							if (sub->backend->buffer_caps != 0) {
 | 
				
			||||||
 | 
								has_buffer_cap = true;
 | 
				
			||||||
 | 
								buffer_caps_intersection &= sub->backend->buffer_caps;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// timeline is only applicable to backends that support DMABUFs
 | 
				
			||||||
 | 
							if (sub->backend->buffer_caps & WLR_BUFFER_CAP_DMABUF) {
 | 
				
			||||||
 | 
								multi->backend.features.timeline = multi->backend.features.timeline &&
 | 
				
			||||||
 | 
									sub->backend->features.timeline;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (has_buffer_cap) {
 | 
				
			||||||
 | 
							multi->backend.buffer_caps = buffer_caps_intersection;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_multi_backend_add(struct wlr_backend *_multi,
 | 
					bool wlr_multi_backend_add(struct wlr_backend *_multi,
 | 
				
			||||||
		struct wlr_backend *backend) {
 | 
							struct wlr_backend *backend) {
 | 
				
			||||||
	assert(_multi && backend);
 | 
						assert(_multi && backend);
 | 
				
			||||||
| 
						 | 
					@ -256,6 +264,7 @@ bool wlr_multi_backend_add(struct wlr_backend *_multi,
 | 
				
			||||||
	wl_signal_add(&backend->events.new_output, &sub->new_output);
 | 
						wl_signal_add(&backend->events.new_output, &sub->new_output);
 | 
				
			||||||
	sub->new_output.notify = new_output_reemit;
 | 
						sub->new_output.notify = new_output_reemit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						multi_backend_refresh_features(multi);
 | 
				
			||||||
	wl_signal_emit_mutable(&multi->events.backend_add, backend);
 | 
						wl_signal_emit_mutable(&multi->events.backend_add, backend);
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -270,6 +279,7 @@ void wlr_multi_backend_remove(struct wlr_backend *_multi,
 | 
				
			||||||
	if (sub) {
 | 
						if (sub) {
 | 
				
			||||||
		wl_signal_emit_mutable(&multi->events.backend_remove, backend);
 | 
							wl_signal_emit_mutable(&multi->events.backend_remove, backend);
 | 
				
			||||||
		subbackend_state_destroy(sub);
 | 
							subbackend_state_destroy(sub);
 | 
				
			||||||
 | 
							multi_backend_refresh_features(multi);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -191,32 +191,40 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) {
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_t devnum = udev_device_get_devnum(udev_dev);
 | 
				
			||||||
	if (strcmp(action, "add") == 0) {
 | 
						if (strcmp(action, "add") == 0) {
 | 
				
			||||||
 | 
							struct wlr_device *dev;
 | 
				
			||||||
 | 
							wl_list_for_each(dev, &session->devices, link) {
 | 
				
			||||||
 | 
								if (dev->dev == devnum) {
 | 
				
			||||||
 | 
									wlr_log(WLR_DEBUG, "Skipping duplicate device %s", sysname);
 | 
				
			||||||
 | 
									goto out;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		wlr_log(WLR_DEBUG, "DRM device %s added", sysname);
 | 
							wlr_log(WLR_DEBUG, "DRM device %s added", sysname);
 | 
				
			||||||
		struct wlr_session_add_event event = {
 | 
							struct wlr_session_add_event event = {
 | 
				
			||||||
			.path = devnode,
 | 
								.path = devnode,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
		wl_signal_emit_mutable(&session->events.add_drm_card, &event);
 | 
							wl_signal_emit_mutable(&session->events.add_drm_card, &event);
 | 
				
			||||||
	} else if (strcmp(action, "change") == 0 || strcmp(action, "remove") == 0) {
 | 
						} else if (strcmp(action, "change") == 0) {
 | 
				
			||||||
		dev_t devnum = udev_device_get_devnum(udev_dev);
 | 
					 | 
				
			||||||
		struct wlr_device *dev;
 | 
							struct wlr_device *dev;
 | 
				
			||||||
		wl_list_for_each(dev, &session->devices, link) {
 | 
							wl_list_for_each(dev, &session->devices, link) {
 | 
				
			||||||
			if (dev->dev != devnum) {
 | 
								if (dev->dev == devnum) {
 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (strcmp(action, "change") == 0) {
 | 
					 | 
				
			||||||
				wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
 | 
									wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
 | 
				
			||||||
				struct wlr_device_change_event event = {0};
 | 
									struct wlr_device_change_event event = {0};
 | 
				
			||||||
				read_udev_change_event(&event, udev_dev);
 | 
									read_udev_change_event(&event, udev_dev);
 | 
				
			||||||
				wl_signal_emit_mutable(&dev->events.change, &event);
 | 
									wl_signal_emit_mutable(&dev->events.change, &event);
 | 
				
			||||||
			} else if (strcmp(action, "remove") == 0) {
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (strcmp(action, "remove") == 0) {
 | 
				
			||||||
 | 
							struct wlr_device *dev;
 | 
				
			||||||
 | 
							wl_list_for_each(dev, &session->devices, link) {
 | 
				
			||||||
 | 
								if (dev->dev == devnum) {
 | 
				
			||||||
				wlr_log(WLR_DEBUG, "DRM device %s removed", sysname);
 | 
									wlr_log(WLR_DEBUG, "DRM device %s removed", sysname);
 | 
				
			||||||
				wl_signal_emit_mutable(&dev->events.remove, NULL);
 | 
									wl_signal_emit_mutable(&dev->events.remove, NULL);
 | 
				
			||||||
			} else {
 | 
									break;
 | 
				
			||||||
				assert(0);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -295,6 +303,11 @@ void wlr_session_destroy(struct wlr_session *session) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_signal_emit_mutable(&session->events.destroy, session);
 | 
						wl_signal_emit_mutable(&session->events.destroy, session);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(wl_list_empty(&session->events.active.listener_list));
 | 
				
			||||||
 | 
						assert(wl_list_empty(&session->events.add_drm_card.listener_list));
 | 
				
			||||||
 | 
						assert(wl_list_empty(&session->events.destroy.listener_list));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_remove(&session->event_loop_destroy.link);
 | 
						wl_list_remove(&session->event_loop_destroy.link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_event_source_remove(session->udev_event);
 | 
						wl_event_source_remove(session->udev_event);
 | 
				
			||||||
| 
						 | 
					@ -352,6 +365,13 @@ void wlr_session_close_file(struct wlr_session *session,
 | 
				
			||||||
	if (libseat_close_device(session->seat_handle, dev->device_id) == -1) {
 | 
						if (libseat_close_device(session->seat_handle, dev->device_id) == -1) {
 | 
				
			||||||
		wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id);
 | 
							wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(wl_list_empty(&dev->events.change.listener_list));
 | 
				
			||||||
 | 
						// TODO: assert that the "remove" listener list is empty as well. Listeners
 | 
				
			||||||
 | 
						// will typically call wlr_session_close_file() in response, and
 | 
				
			||||||
 | 
						// wl_signal_emit_mutable() installs two phantom listeners, so we'd count
 | 
				
			||||||
 | 
						// these two.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	close(dev->fd);
 | 
						close(dev->fd);
 | 
				
			||||||
	wl_list_remove(&dev->link);
 | 
						wl_list_remove(&dev->link);
 | 
				
			||||||
	free(dev);
 | 
						free(dev);
 | 
				
			||||||
| 
						 | 
					@ -499,8 +519,6 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool is_boot_vga = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const char *path = udev_list_entry_get_name(entry);
 | 
							const char *path = udev_list_entry_get_name(entry);
 | 
				
			||||||
		struct udev_device *dev = udev_device_new_from_syspath(session->udev, path);
 | 
							struct udev_device *dev = udev_device_new_from_syspath(session->udev, path);
 | 
				
			||||||
		if (!dev) {
 | 
							if (!dev) {
 | 
				
			||||||
| 
						 | 
					@ -516,14 +534,20 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// This is owned by 'dev', so we don't need to free it
 | 
							bool is_primary = false;
 | 
				
			||||||
		struct udev_device *pci =
 | 
							const char *boot_display = udev_device_get_sysattr_value(dev, "boot_display");
 | 
				
			||||||
			udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
 | 
							if (boot_display && strcmp(boot_display, "1") == 0) {
 | 
				
			||||||
 | 
							    is_primary = true;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// This is owned by 'dev', so we don't need to free it
 | 
				
			||||||
 | 
								struct udev_device *pci =
 | 
				
			||||||
 | 
									udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (pci) {
 | 
								if (pci) {
 | 
				
			||||||
			const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
 | 
									const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
 | 
				
			||||||
			if (id && strcmp(id, "1") == 0) {
 | 
									if (id && strcmp(id, "1") == 0) {
 | 
				
			||||||
				is_boot_vga = true;
 | 
										is_primary = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -537,7 +561,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
 | 
				
			||||||
		udev_device_unref(dev);
 | 
							udev_device_unref(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret[i] = wlr_dev;
 | 
							ret[i] = wlr_dev;
 | 
				
			||||||
		if (is_boot_vga) {
 | 
							if (is_primary) {
 | 
				
			||||||
			struct wlr_device *tmp = ret[0];
 | 
								struct wlr_device *tmp = ret[0];
 | 
				
			||||||
			ret[0] = ret[i];
 | 
								ret[0] = ret[i];
 | 
				
			||||||
			ret[i] = tmp;
 | 
								ret[i] = tmp;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "drm-client-protocol.h"
 | 
					#include "drm-client-protocol.h"
 | 
				
			||||||
#include "linux-dmabuf-v1-client-protocol.h"
 | 
					#include "linux-dmabuf-v1-client-protocol.h"
 | 
				
			||||||
 | 
					#include "linux-drm-syncobj-v1-client-protocol.h"
 | 
				
			||||||
#include "pointer-gestures-unstable-v1-client-protocol.h"
 | 
					#include "pointer-gestures-unstable-v1-client-protocol.h"
 | 
				
			||||||
#include "presentation-time-client-protocol.h"
 | 
					#include "presentation-time-client-protocol.h"
 | 
				
			||||||
#include "xdg-activation-v1-client-protocol.h"
 | 
					#include "xdg-activation-v1-client-protocol.h"
 | 
				
			||||||
| 
						 | 
					@ -54,14 +55,6 @@ struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *wlr_backe
 | 
				
			||||||
static int dispatch_events(int fd, uint32_t mask, void *data) {
 | 
					static int dispatch_events(int fd, uint32_t mask, void *data) {
 | 
				
			||||||
	struct wlr_wl_backend *wl = data;
 | 
						struct wlr_wl_backend *wl = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
 | 
					 | 
				
			||||||
		if (mask & WL_EVENT_ERROR) {
 | 
					 | 
				
			||||||
			wlr_log(WLR_ERROR, "Failed to read from remote Wayland display");
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		wlr_backend_destroy(&wl->backend);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int count = 0;
 | 
						int count = 0;
 | 
				
			||||||
	if (mask & WL_EVENT_READABLE) {
 | 
						if (mask & WL_EVENT_READABLE) {
 | 
				
			||||||
		count = wl_display_dispatch(wl->remote_display);
 | 
							count = wl_display_dispatch(wl->remote_display);
 | 
				
			||||||
| 
						 | 
					@ -74,6 +67,18 @@ static int dispatch_events(int fd, uint32_t mask, void *data) {
 | 
				
			||||||
		wl_display_flush(wl->remote_display);
 | 
							wl_display_flush(wl->remote_display);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Make sure we've consumed all data before disconnecting due to hangup,
 | 
				
			||||||
 | 
						// so that we process any wl_display.error events
 | 
				
			||||||
 | 
						if (!(mask & WL_EVENT_READABLE) && (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR))) {
 | 
				
			||||||
 | 
							if (mask & WL_EVENT_ERROR) {
 | 
				
			||||||
 | 
								wlr_log(WLR_ERROR, "Failed to read from remote Wayland display");
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG, "Disconnected from remote Wayland display");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							wlr_backend_destroy(&wl->backend);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (count < 0) {
 | 
						if (count < 0) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to dispatch remote Wayland display");
 | 
							wlr_log(WLR_ERROR, "Failed to dispatch remote Wayland display");
 | 
				
			||||||
		wlr_backend_destroy(&wl->backend);
 | 
							wlr_backend_destroy(&wl->backend);
 | 
				
			||||||
| 
						 | 
					@ -411,6 +416,9 @@ static void registry_global(void *data, struct wl_registry *registry,
 | 
				
			||||||
	} else if (strcmp(iface, wp_viewporter_interface.name) == 0) {
 | 
						} else if (strcmp(iface, wp_viewporter_interface.name) == 0) {
 | 
				
			||||||
		wl->viewporter = wl_registry_bind(registry, name,
 | 
							wl->viewporter = wl_registry_bind(registry, name,
 | 
				
			||||||
			&wp_viewporter_interface, 1);
 | 
								&wp_viewporter_interface, 1);
 | 
				
			||||||
 | 
						} else if (strcmp(iface, wp_linux_drm_syncobj_manager_v1_interface.name) == 0) {
 | 
				
			||||||
 | 
							wl->drm_syncobj_manager_v1 = wl_registry_bind(registry, name,
 | 
				
			||||||
 | 
								&wp_linux_drm_syncobj_manager_v1_interface, 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -484,6 +492,11 @@ static void backend_destroy(struct wlr_backend *backend) {
 | 
				
			||||||
		destroy_wl_buffer(buffer);
 | 
							destroy_wl_buffer(buffer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_wl_drm_syncobj_timeline *timeline, *tmp_timeline;
 | 
				
			||||||
 | 
						wl_list_for_each_safe(timeline, tmp_timeline, &wl->drm_syncobj_timelines, link) {
 | 
				
			||||||
 | 
							destroy_wl_drm_syncobj_timeline(timeline);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_backend_finish(backend);
 | 
						wlr_backend_finish(backend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_remove(&wl->event_loop_destroy.link);
 | 
						wl_list_remove(&wl->event_loop_destroy.link);
 | 
				
			||||||
| 
						 | 
					@ -518,6 +531,9 @@ static void backend_destroy(struct wlr_backend *backend) {
 | 
				
			||||||
	if (wl->zwp_linux_dmabuf_v1) {
 | 
						if (wl->zwp_linux_dmabuf_v1) {
 | 
				
			||||||
		zwp_linux_dmabuf_v1_destroy(wl->zwp_linux_dmabuf_v1);
 | 
							zwp_linux_dmabuf_v1_destroy(wl->zwp_linux_dmabuf_v1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (wl->drm_syncobj_manager_v1) {
 | 
				
			||||||
 | 
							wp_linux_drm_syncobj_manager_v1_destroy(wl->drm_syncobj_manager_v1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (wl->legacy_drm != NULL) {
 | 
						if (wl->legacy_drm != NULL) {
 | 
				
			||||||
		wl_drm_destroy(wl->legacy_drm);
 | 
							wl_drm_destroy(wl->legacy_drm);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -543,6 +559,7 @@ static void backend_destroy(struct wlr_backend *backend) {
 | 
				
			||||||
	wl_compositor_destroy(wl->compositor);
 | 
						wl_compositor_destroy(wl->compositor);
 | 
				
			||||||
	wl_registry_destroy(wl->registry);
 | 
						wl_registry_destroy(wl->registry);
 | 
				
			||||||
	wl_display_flush(wl->remote_display);
 | 
						wl_display_flush(wl->remote_display);
 | 
				
			||||||
 | 
						wl_event_queue_destroy(wl->busy_loop_queue);
 | 
				
			||||||
	if (wl->own_remote_display) {
 | 
						if (wl->own_remote_display) {
 | 
				
			||||||
		wl_display_disconnect(wl->remote_display);
 | 
							wl_display_disconnect(wl->remote_display);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -554,17 +571,10 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
 | 
				
			||||||
	return wl->drm_fd;
 | 
						return wl->drm_fd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t get_buffer_caps(struct wlr_backend *backend) {
 | 
					 | 
				
			||||||
	struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend);
 | 
					 | 
				
			||||||
	return (wl->zwp_linux_dmabuf_v1 ? WLR_BUFFER_CAP_DMABUF : 0)
 | 
					 | 
				
			||||||
		| (wl->shm ? WLR_BUFFER_CAP_SHM : 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct wlr_backend_impl backend_impl = {
 | 
					static const struct wlr_backend_impl backend_impl = {
 | 
				
			||||||
	.start = backend_start,
 | 
						.start = backend_start,
 | 
				
			||||||
	.destroy = backend_destroy,
 | 
						.destroy = backend_destroy,
 | 
				
			||||||
	.get_drm_fd = backend_get_drm_fd,
 | 
						.get_drm_fd = backend_get_drm_fd,
 | 
				
			||||||
	.get_buffer_caps = get_buffer_caps,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_backend_is_wl(struct wlr_backend *b) {
 | 
					bool wlr_backend_is_wl(struct wlr_backend *b) {
 | 
				
			||||||
| 
						 | 
					@ -592,6 +602,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
 | 
				
			||||||
	wl_list_init(&wl->outputs);
 | 
						wl_list_init(&wl->outputs);
 | 
				
			||||||
	wl_list_init(&wl->seats);
 | 
						wl_list_init(&wl->seats);
 | 
				
			||||||
	wl_list_init(&wl->buffers);
 | 
						wl_list_init(&wl->buffers);
 | 
				
			||||||
 | 
						wl_list_init(&wl->drm_syncobj_timelines);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (remote_display != NULL) {
 | 
						if (remote_display != NULL) {
 | 
				
			||||||
		wl->remote_display = remote_display;
 | 
							wl->remote_display = remote_display;
 | 
				
			||||||
| 
						 | 
					@ -604,10 +615,16 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
 | 
				
			||||||
		wl->own_remote_display = true;
 | 
							wl->own_remote_display = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl->busy_loop_queue = wl_display_create_queue(wl->remote_display);
 | 
				
			||||||
 | 
						if (wl->busy_loop_queue == NULL) {
 | 
				
			||||||
 | 
							wlr_log_errno(WLR_ERROR, "Could not create a Wayland event queue");
 | 
				
			||||||
 | 
							goto error_display;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl->registry = wl_display_get_registry(wl->remote_display);
 | 
						wl->registry = wl_display_get_registry(wl->remote_display);
 | 
				
			||||||
	if (!wl->registry) {
 | 
						if (!wl->registry) {
 | 
				
			||||||
		wlr_log_errno(WLR_ERROR, "Could not obtain reference to remote registry");
 | 
							wlr_log_errno(WLR_ERROR, "Could not obtain reference to remote registry");
 | 
				
			||||||
		goto error_display;
 | 
							goto error_queue;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wl_registry_add_listener(wl->registry, ®istry_listener, wl);
 | 
						wl_registry_add_listener(wl->registry, ®istry_listener, wl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -624,6 +641,8 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
 | 
				
			||||||
		goto error_registry;
 | 
							goto error_registry;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl->backend.features.timeline = wl->drm_syncobj_manager_v1 != NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_display_roundtrip(wl->remote_display); // process initial event bursts
 | 
						wl_display_roundtrip(wl->remote_display); // process initial event bursts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct zwp_linux_dmabuf_feedback_v1 *linux_dmabuf_feedback_v1 = NULL;
 | 
						struct zwp_linux_dmabuf_feedback_v1 *linux_dmabuf_feedback_v1 = NULL;
 | 
				
			||||||
| 
						 | 
					@ -657,6 +676,13 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
 | 
				
			||||||
		zwp_linux_dmabuf_feedback_v1_destroy(linux_dmabuf_feedback_v1);
 | 
							zwp_linux_dmabuf_feedback_v1_destroy(linux_dmabuf_feedback_v1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wl->zwp_linux_dmabuf_v1) {
 | 
				
			||||||
 | 
							wl->backend.buffer_caps |= WLR_BUFFER_CAP_DMABUF;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (wl->shm) {
 | 
				
			||||||
 | 
							wl->backend.buffer_caps |= WLR_BUFFER_CAP_SHM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int fd = wl_display_get_fd(wl->remote_display);
 | 
						int fd = wl_display_get_fd(wl->remote_display);
 | 
				
			||||||
	wl->remote_display_src = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
 | 
						wl->remote_display_src = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
 | 
				
			||||||
		dispatch_events, wl);
 | 
							dispatch_events, wl);
 | 
				
			||||||
| 
						 | 
					@ -700,6 +726,8 @@ error_registry:
 | 
				
			||||||
		xdg_wm_base_destroy(wl->xdg_wm_base);
 | 
							xdg_wm_base_destroy(wl->xdg_wm_base);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	wl_registry_destroy(wl->registry);
 | 
						wl_registry_destroy(wl->registry);
 | 
				
			||||||
 | 
					error_queue:
 | 
				
			||||||
 | 
						wl_event_queue_destroy(wl->busy_loop_queue);
 | 
				
			||||||
error_display:
 | 
					error_display:
 | 
				
			||||||
	if (wl->own_remote_display) {
 | 
						if (wl->own_remote_display) {
 | 
				
			||||||
		wl_display_disconnect(wl->remote_display);
 | 
							wl_display_disconnect(wl->remote_display);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
wayland_client = dependency('wayland-client',
 | 
					wayland_client = dependency('wayland-client',
 | 
				
			||||||
	fallback: 'wayland',
 | 
						kwargs: wayland_kwargs,
 | 
				
			||||||
	default_options: wayland_project_options,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
wlr_deps += wayland_client
 | 
					wlr_deps += wayland_client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +14,7 @@ wlr_files += files(
 | 
				
			||||||
client_protos = [
 | 
					client_protos = [
 | 
				
			||||||
	'drm',
 | 
						'drm',
 | 
				
			||||||
	'linux-dmabuf-v1',
 | 
						'linux-dmabuf-v1',
 | 
				
			||||||
 | 
						'linux-drm-syncobj-v1',
 | 
				
			||||||
	'pointer-gestures-unstable-v1',
 | 
						'pointer-gestures-unstable-v1',
 | 
				
			||||||
	'presentation-time',
 | 
						'presentation-time',
 | 
				
			||||||
	'relative-pointer-unstable-v1',
 | 
						'relative-pointer-unstable-v1',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@
 | 
				
			||||||
#include <wayland-client-protocol.h>
 | 
					#include <wayland-client-protocol.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wlr/interfaces/wlr_output.h>
 | 
					#include <wlr/interfaces/wlr_output.h>
 | 
				
			||||||
 | 
					#include <wlr/render/drm_syncobj.h>
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layer.h>
 | 
					#include <wlr/types/wlr_output_layer.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
| 
						 | 
					@ -20,6 +21,7 @@
 | 
				
			||||||
#include "types/wlr_output.h"
 | 
					#include "types/wlr_output.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "linux-dmabuf-v1-client-protocol.h"
 | 
					#include "linux-dmabuf-v1-client-protocol.h"
 | 
				
			||||||
 | 
					#include "linux-drm-syncobj-v1-client-protocol.h"
 | 
				
			||||||
#include "presentation-time-client-protocol.h"
 | 
					#include "presentation-time-client-protocol.h"
 | 
				
			||||||
#include "viewporter-client-protocol.h"
 | 
					#include "viewporter-client-protocol.h"
 | 
				
			||||||
#include "xdg-activation-v1-client-protocol.h"
 | 
					#include "xdg-activation-v1-client-protocol.h"
 | 
				
			||||||
| 
						 | 
					@ -31,7 +33,9 @@ static const uint32_t SUPPORTED_OUTPUT_STATE =
 | 
				
			||||||
	WLR_OUTPUT_STATE_BUFFER |
 | 
						WLR_OUTPUT_STATE_BUFFER |
 | 
				
			||||||
	WLR_OUTPUT_STATE_ENABLED |
 | 
						WLR_OUTPUT_STATE_ENABLED |
 | 
				
			||||||
	WLR_OUTPUT_STATE_MODE |
 | 
						WLR_OUTPUT_STATE_MODE |
 | 
				
			||||||
	WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
 | 
						WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED |
 | 
				
			||||||
 | 
						WLR_OUTPUT_STATE_WAIT_TIMELINE |
 | 
				
			||||||
 | 
						WLR_OUTPUT_STATE_SIGNAL_TIMELINE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static size_t last_output_num = 0;
 | 
					static size_t last_output_num = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,14 +98,13 @@ static void presentation_feedback_handle_presented(void *data,
 | 
				
			||||||
		uint32_t seq_hi, uint32_t seq_lo, uint32_t flags) {
 | 
							uint32_t seq_hi, uint32_t seq_lo, uint32_t flags) {
 | 
				
			||||||
	struct wlr_wl_presentation_feedback *feedback = data;
 | 
						struct wlr_wl_presentation_feedback *feedback = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct timespec t = {
 | 
					 | 
				
			||||||
		.tv_sec = ((uint64_t)tv_sec_hi << 32) | tv_sec_lo,
 | 
					 | 
				
			||||||
		.tv_nsec = tv_nsec,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	struct wlr_output_event_present event = {
 | 
						struct wlr_output_event_present event = {
 | 
				
			||||||
		.commit_seq = feedback->commit_seq,
 | 
							.commit_seq = feedback->commit_seq,
 | 
				
			||||||
		.presented = true,
 | 
							.presented = true,
 | 
				
			||||||
		.when = &t,
 | 
							.when = {
 | 
				
			||||||
 | 
								.tv_sec = ((uint64_t)tv_sec_hi << 32) | tv_sec_lo,
 | 
				
			||||||
 | 
								.tv_nsec = tv_nsec,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		.seq = ((uint64_t)seq_hi << 32) | seq_lo,
 | 
							.seq = ((uint64_t)seq_hi << 32) | seq_lo,
 | 
				
			||||||
		.refresh = refresh_ns,
 | 
							.refresh = refresh_ns,
 | 
				
			||||||
		.flags = flags,
 | 
							.flags = flags,
 | 
				
			||||||
| 
						 | 
					@ -131,6 +134,11 @@ static const struct wp_presentation_feedback_listener
 | 
				
			||||||
	.discarded = presentation_feedback_handle_discarded,
 | 
						.discarded = presentation_feedback_handle_discarded,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void buffer_remove_drm_syncobj_waiter(struct wlr_wl_buffer *buffer) {
 | 
				
			||||||
 | 
						wlr_drm_syncobj_timeline_waiter_finish(&buffer->drm_syncobj_waiter);
 | 
				
			||||||
 | 
						buffer->has_drm_syncobj_waiter = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
 | 
					void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
 | 
				
			||||||
	if (buffer == NULL) {
 | 
						if (buffer == NULL) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -138,22 +146,42 @@ void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
 | 
				
			||||||
	wl_list_remove(&buffer->buffer_destroy.link);
 | 
						wl_list_remove(&buffer->buffer_destroy.link);
 | 
				
			||||||
	wl_list_remove(&buffer->link);
 | 
						wl_list_remove(&buffer->link);
 | 
				
			||||||
	wl_buffer_destroy(buffer->wl_buffer);
 | 
						wl_buffer_destroy(buffer->wl_buffer);
 | 
				
			||||||
 | 
						if (buffer->has_drm_syncobj_waiter) {
 | 
				
			||||||
 | 
							buffer_remove_drm_syncobj_waiter(buffer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (!buffer->released) {
 | 
						if (!buffer->released) {
 | 
				
			||||||
		wlr_buffer_unlock(buffer->buffer);
 | 
							wlr_buffer_unlock(buffer->buffer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						wlr_drm_syncobj_timeline_unref(buffer->fallback_signal_timeline);
 | 
				
			||||||
	free(buffer);
 | 
						free(buffer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void buffer_release(struct wlr_wl_buffer *buffer) {
 | 
				
			||||||
 | 
						if (buffer->released) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buffer->released = true;
 | 
				
			||||||
 | 
						wlr_buffer_unlock(buffer->buffer); // might free buffer
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
 | 
					static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
 | 
				
			||||||
	struct wlr_wl_buffer *buffer = data;
 | 
						struct wlr_wl_buffer *buffer = data;
 | 
				
			||||||
	buffer->released = true;
 | 
						if (buffer->has_drm_syncobj_waiter) {
 | 
				
			||||||
	wlr_buffer_unlock(buffer->buffer); // might free buffer
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buffer_release(buffer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct wl_buffer_listener buffer_listener = {
 | 
					static const struct wl_buffer_listener buffer_listener = {
 | 
				
			||||||
	.release = buffer_handle_release,
 | 
						.release = buffer_handle_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void buffer_handle_drm_syncobj_ready(struct wlr_drm_syncobj_timeline_waiter *waiter) {
 | 
				
			||||||
 | 
						struct wlr_wl_buffer *buffer = wl_container_of(waiter, buffer, drm_syncobj_waiter);
 | 
				
			||||||
 | 
						buffer_remove_drm_syncobj_waiter(buffer);
 | 
				
			||||||
 | 
						buffer_release(buffer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void buffer_handle_buffer_destroy(struct wl_listener *listener,
 | 
					static void buffer_handle_buffer_destroy(struct wl_listener *listener,
 | 
				
			||||||
		void *data) {
 | 
							void *data) {
 | 
				
			||||||
	struct wlr_wl_buffer *buffer =
 | 
						struct wlr_wl_buffer *buffer =
 | 
				
			||||||
| 
						 | 
					@ -176,6 +204,30 @@ static bool test_buffer(struct wlr_wl_backend *wl,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dmabuf_listener_data {
 | 
				
			||||||
 | 
						struct wl_buffer *wl_buffer;
 | 
				
			||||||
 | 
						bool done;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dmabuf_handle_created(void *data_, struct zwp_linux_buffer_params_v1 *params,
 | 
				
			||||||
 | 
							struct wl_buffer *buffer) {
 | 
				
			||||||
 | 
						struct dmabuf_listener_data *data = data_;
 | 
				
			||||||
 | 
						data->wl_buffer = buffer;
 | 
				
			||||||
 | 
						data->done = true;
 | 
				
			||||||
 | 
						wlr_log(WLR_DEBUG, "DMA-BUF imported into parent Wayland compositor");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dmabuf_handle_failed(void *data_, struct zwp_linux_buffer_params_v1 *params) {
 | 
				
			||||||
 | 
						struct dmabuf_listener_data *data = data_;
 | 
				
			||||||
 | 
						data->done = true;
 | 
				
			||||||
 | 
						wlr_log(WLR_ERROR, "Failed to import DMA-BUF into parent Wayland compositor");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct zwp_linux_buffer_params_v1_listener dmabuf_listener = {
 | 
				
			||||||
 | 
						.created = dmabuf_handle_created,
 | 
				
			||||||
 | 
						.failed = dmabuf_handle_failed,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
 | 
					static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
 | 
				
			||||||
		struct wlr_dmabuf_attributes *dmabuf) {
 | 
							struct wlr_dmabuf_attributes *dmabuf) {
 | 
				
			||||||
	uint32_t modifier_hi = dmabuf->modifier >> 32;
 | 
						uint32_t modifier_hi = dmabuf->modifier >> 32;
 | 
				
			||||||
| 
						 | 
					@ -187,18 +239,35 @@ static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
 | 
				
			||||||
			dmabuf->offset[i], dmabuf->stride[i], modifier_hi, modifier_lo);
 | 
								dmabuf->offset[i], dmabuf->stride[i], modifier_hi, modifier_lo);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_buffer *wl_buffer = zwp_linux_buffer_params_v1_create_immed(
 | 
						struct dmabuf_listener_data data = {0};
 | 
				
			||||||
		params, dmabuf->width, dmabuf->height, dmabuf->format, 0);
 | 
						zwp_linux_buffer_params_v1_add_listener(params, &dmabuf_listener, &data);
 | 
				
			||||||
 | 
						zwp_linux_buffer_params_v1_create(params, dmabuf->width, dmabuf->height, dmabuf->format, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_event_queue *display_queue =
 | 
				
			||||||
 | 
							wl_proxy_get_queue((struct wl_proxy *)wl->remote_display);
 | 
				
			||||||
 | 
						wl_proxy_set_queue((struct wl_proxy *)params, wl->busy_loop_queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (!data.done) {
 | 
				
			||||||
 | 
							if (wl_display_dispatch_queue(wl->remote_display, wl->busy_loop_queue) < 0) {
 | 
				
			||||||
 | 
								wlr_log(WLR_ERROR, "wl_display_dispatch_queue() failed");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_buffer *buffer = data.wl_buffer;
 | 
				
			||||||
 | 
						if (buffer != NULL) {
 | 
				
			||||||
 | 
							wl_proxy_set_queue((struct wl_proxy *)buffer, display_queue);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	zwp_linux_buffer_params_v1_destroy(params);
 | 
						zwp_linux_buffer_params_v1_destroy(params);
 | 
				
			||||||
	// TODO: handle create() errors
 | 
						return buffer;
 | 
				
			||||||
	return wl_buffer;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wl_buffer *import_shm(struct wlr_wl_backend *wl,
 | 
					static struct wl_buffer *import_shm(struct wlr_wl_backend *wl,
 | 
				
			||||||
		struct wlr_shm_attributes *shm) {
 | 
							struct wlr_shm_attributes *shm) {
 | 
				
			||||||
	enum wl_shm_format wl_shm_format = convert_drm_format_to_wl_shm(shm->format);
 | 
						enum wl_shm_format wl_shm_format = convert_drm_format_to_wl_shm(shm->format);
 | 
				
			||||||
	uint32_t size = shm->stride * shm->height;
 | 
						uint32_t size = shm->stride * shm->height;
 | 
				
			||||||
	struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, shm->fd, size);
 | 
						struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, shm->fd, shm->offset + size);
 | 
				
			||||||
	if (pool == NULL) {
 | 
						if (pool == NULL) {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -262,6 +331,58 @@ static struct wlr_wl_buffer *get_or_create_wl_buffer(struct wlr_wl_backend *wl,
 | 
				
			||||||
	return create_wl_buffer(wl, wlr_buffer);
 | 
						return create_wl_buffer(wl, wlr_buffer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void destroy_wl_drm_syncobj_timeline(struct wlr_wl_drm_syncobj_timeline *timeline) {
 | 
				
			||||||
 | 
						wp_linux_drm_syncobj_timeline_v1_destroy(timeline->wl);
 | 
				
			||||||
 | 
						wlr_addon_finish(&timeline->addon);
 | 
				
			||||||
 | 
						wl_list_remove(&timeline->link);
 | 
				
			||||||
 | 
						free(timeline);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void drm_syncobj_timeline_addon_destroy(struct wlr_addon *addon) {
 | 
				
			||||||
 | 
						struct wlr_wl_drm_syncobj_timeline *timeline = wl_container_of(addon, timeline, addon);
 | 
				
			||||||
 | 
						destroy_wl_drm_syncobj_timeline(timeline);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct wlr_addon_interface drm_syncobj_timeline_addon_impl = {
 | 
				
			||||||
 | 
						.name = "wlr_wl_drm_syncobj_timeline",
 | 
				
			||||||
 | 
						.destroy = drm_syncobj_timeline_addon_destroy,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct wlr_wl_drm_syncobj_timeline *get_or_create_drm_syncobj_timeline(
 | 
				
			||||||
 | 
							struct wlr_wl_backend *wl, struct wlr_drm_syncobj_timeline *wlr_timeline) {
 | 
				
			||||||
 | 
						struct wlr_addon *addon =
 | 
				
			||||||
 | 
							wlr_addon_find(&wlr_timeline->addons, wl, &drm_syncobj_timeline_addon_impl);
 | 
				
			||||||
 | 
						if (addon != NULL) {
 | 
				
			||||||
 | 
							struct wlr_wl_drm_syncobj_timeline *timeline = wl_container_of(addon, timeline, addon);
 | 
				
			||||||
 | 
							return timeline;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_wl_drm_syncobj_timeline *timeline = calloc(1, sizeof(*timeline));
 | 
				
			||||||
 | 
						if (timeline == NULL) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						timeline->base = wlr_timeline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int fd = wlr_drm_syncobj_timeline_export(wlr_timeline);
 | 
				
			||||||
 | 
						if (fd < 0) {
 | 
				
			||||||
 | 
							free(timeline);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						timeline->wl = wp_linux_drm_syncobj_manager_v1_import_timeline(wl->drm_syncobj_manager_v1, fd);
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
						if (timeline->wl == NULL) {
 | 
				
			||||||
 | 
							free(timeline);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_addon_init(&timeline->addon, &wlr_timeline->addons, wl, &drm_syncobj_timeline_addon_impl);
 | 
				
			||||||
 | 
						wl_list_insert(&wl->drm_syncobj_timelines, &timeline->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return timeline;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool update_title(struct wlr_wl_output *output, const char *title) {
 | 
					static bool update_title(struct wlr_wl_output *output, const char *title) {
 | 
				
			||||||
	struct wlr_output *wlr_output = &output->wlr_output;
 | 
						struct wlr_output *wlr_output = &output->wlr_output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -301,6 +422,28 @@ static bool output_test(struct wlr_output *wlr_output,
 | 
				
			||||||
	struct wlr_wl_output *output =
 | 
						struct wlr_wl_output *output =
 | 
				
			||||||
		get_wl_output_from_output(wlr_output);
 | 
							get_wl_output_from_output(wlr_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
				
			||||||
 | 
							// If the size doesn't match, reject buffer (scaling is not currently
 | 
				
			||||||
 | 
							// supported but could be implemented with viewporter)
 | 
				
			||||||
 | 
							int pending_width, pending_height;
 | 
				
			||||||
 | 
							output_pending_resolution(wlr_output, state,
 | 
				
			||||||
 | 
								&pending_width, &pending_height);
 | 
				
			||||||
 | 
							if (state->buffer->width != pending_width ||
 | 
				
			||||||
 | 
									state->buffer->height != pending_height) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Source crop is also not currently supported
 | 
				
			||||||
 | 
							struct wlr_fbox src_box;
 | 
				
			||||||
 | 
							output_state_get_buffer_src_box(state, &src_box);
 | 
				
			||||||
 | 
							if (src_box.x != 0.0 || src_box.y != 0.0 ||
 | 
				
			||||||
 | 
									src_box.width != (double)state->buffer->width ||
 | 
				
			||||||
 | 
									src_box.height != (double)state->buffer->height) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG, "Source crop not supported in wayland output");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
 | 
						uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
 | 
				
			||||||
	if (unsupported != 0) {
 | 
						if (unsupported != 0) {
 | 
				
			||||||
		wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
 | 
							wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
 | 
				
			||||||
| 
						 | 
					@ -334,6 +477,21 @@ static bool output_test(struct wlr_output *wlr_output,
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) &&
 | 
				
			||||||
 | 
								!(state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE)) {
 | 
				
			||||||
 | 
							wlr_log(WLR_DEBUG, "Signal timeline requires a wait timeline");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) ||
 | 
				
			||||||
 | 
								(state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE)) {
 | 
				
			||||||
 | 
							struct wlr_dmabuf_attributes dmabuf;
 | 
				
			||||||
 | 
							if (!wlr_buffer_get_dmabuf(state->buffer, &dmabuf)) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG, "Wait/signal timelines require DMA-BUFs");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
 | 
						if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
 | 
				
			||||||
		// If we can't use a sub-surface for a layer, then we can't use a
 | 
							// If we can't use a sub-surface for a layer, then we can't use a
 | 
				
			||||||
		// sub-surface for any layer underneath
 | 
							// sub-surface for any layer underneath
 | 
				
			||||||
| 
						 | 
					@ -565,15 +723,15 @@ static const struct wl_callback_listener unmap_callback_listener = {
 | 
				
			||||||
	.done = unmap_callback_handle_done,
 | 
						.done = unmap_callback_handle_done,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool output_commit(struct wlr_output *wlr_output,
 | 
					static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output_state *state) {
 | 
				
			||||||
		const struct wlr_output_state *state) {
 | 
						struct wlr_wl_output *output = get_wl_output_from_output(wlr_output);
 | 
				
			||||||
	struct wlr_wl_output *output =
 | 
					 | 
				
			||||||
		get_wl_output_from_output(wlr_output);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!output_test(wlr_output, state)) {
 | 
						if (!output_test(wlr_output, state)) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_wl_backend *wl = output->backend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool pending_enabled = output_pending_enabled(wlr_output, state);
 | 
						bool pending_enabled = output_pending_enabled(wlr_output, state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (wlr_output->enabled && !pending_enabled) {
 | 
						if (wlr_output->enabled && !pending_enabled) {
 | 
				
			||||||
| 
						 | 
					@ -598,15 +756,28 @@ static bool output_commit(struct wlr_output *wlr_output,
 | 
				
			||||||
		wl_surface_commit(output->surface);
 | 
							wl_surface_commit(output->surface);
 | 
				
			||||||
		output->initialized = true;
 | 
							output->initialized = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		wl_display_flush(output->backend->remote_display);
 | 
							struct wl_event_queue *display_queue =
 | 
				
			||||||
 | 
								wl_proxy_get_queue((struct wl_proxy *)wl->remote_display);
 | 
				
			||||||
 | 
							wl_proxy_set_queue((struct wl_proxy *)output->xdg_surface, wl->busy_loop_queue);
 | 
				
			||||||
 | 
							wl_proxy_set_queue((struct wl_proxy *)output->xdg_toplevel, wl->busy_loop_queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wl_display_flush(wl->remote_display);
 | 
				
			||||||
		while (!output->configured) {
 | 
							while (!output->configured) {
 | 
				
			||||||
			if (wl_display_dispatch(output->backend->remote_display) == -1) {
 | 
								if (wl_display_dispatch_queue(wl->remote_display, wl->busy_loop_queue) == -1) {
 | 
				
			||||||
				wlr_log(WLR_ERROR, "wl_display_dispatch() failed");
 | 
									wlr_log(WLR_ERROR, "wl_display_dispatch_queue() failed");
 | 
				
			||||||
				return false;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wl_proxy_set_queue((struct wl_proxy *)output->xdg_surface, display_queue);
 | 
				
			||||||
 | 
							wl_proxy_set_queue((struct wl_proxy *)output->xdg_toplevel, display_queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!output->configured) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_wl_buffer *buffer = NULL;
 | 
				
			||||||
	if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
						if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
				
			||||||
		const pixman_region32_t *damage = NULL;
 | 
							const pixman_region32_t *damage = NULL;
 | 
				
			||||||
		if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
 | 
							if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
 | 
				
			||||||
| 
						 | 
					@ -614,8 +785,7 @@ static bool output_commit(struct wlr_output *wlr_output,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct wlr_buffer *wlr_buffer = state->buffer;
 | 
							struct wlr_buffer *wlr_buffer = state->buffer;
 | 
				
			||||||
		struct wlr_wl_buffer *buffer =
 | 
							buffer = get_or_create_wl_buffer(wl, wlr_buffer);
 | 
				
			||||||
			get_or_create_wl_buffer(output->backend, wlr_buffer);
 | 
					 | 
				
			||||||
		if (buffer == NULL) {
 | 
							if (buffer == NULL) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -624,6 +794,63 @@ static bool output_commit(struct wlr_output *wlr_output,
 | 
				
			||||||
		damage_surface(output->surface, damage);
 | 
							damage_surface(output->surface, damage);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
 | 
				
			||||||
 | 
							struct wlr_wl_drm_syncobj_timeline *wait_timeline =
 | 
				
			||||||
 | 
								get_or_create_drm_syncobj_timeline(wl, state->wait_timeline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct wlr_wl_drm_syncobj_timeline *signal_timeline;
 | 
				
			||||||
 | 
							uint64_t signal_point;
 | 
				
			||||||
 | 
							if (state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
 | 
				
			||||||
 | 
								signal_timeline = get_or_create_drm_syncobj_timeline(wl, state->signal_timeline);
 | 
				
			||||||
 | 
								signal_point = state->signal_point;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (buffer->fallback_signal_timeline == NULL) {
 | 
				
			||||||
 | 
									buffer->fallback_signal_timeline =
 | 
				
			||||||
 | 
										wlr_drm_syncobj_timeline_create(wl->drm_fd);
 | 
				
			||||||
 | 
									if (buffer->fallback_signal_timeline == NULL) {
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								signal_timeline =
 | 
				
			||||||
 | 
									get_or_create_drm_syncobj_timeline(wl, buffer->fallback_signal_timeline);
 | 
				
			||||||
 | 
								signal_point = ++buffer->fallback_signal_point;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (wait_timeline == NULL || signal_timeline == NULL) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (output->drm_syncobj_surface_v1 == NULL) {
 | 
				
			||||||
 | 
								output->drm_syncobj_surface_v1 = wp_linux_drm_syncobj_manager_v1_get_surface(
 | 
				
			||||||
 | 
									wl->drm_syncobj_manager_v1, output->surface);
 | 
				
			||||||
 | 
								if (output->drm_syncobj_surface_v1 == NULL) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint32_t wait_point_hi = state->wait_point >> 32;
 | 
				
			||||||
 | 
							uint32_t wait_point_lo = state->wait_point & UINT32_MAX;
 | 
				
			||||||
 | 
							uint32_t signal_point_hi = signal_point >> 32;
 | 
				
			||||||
 | 
							uint32_t signal_point_lo = signal_point & UINT32_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wp_linux_drm_syncobj_surface_v1_set_acquire_point(output->drm_syncobj_surface_v1,
 | 
				
			||||||
 | 
								wait_timeline->wl, wait_point_hi, wait_point_lo);
 | 
				
			||||||
 | 
							wp_linux_drm_syncobj_surface_v1_set_release_point(output->drm_syncobj_surface_v1,
 | 
				
			||||||
 | 
								signal_timeline->wl, signal_point_hi, signal_point_lo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!wlr_drm_syncobj_timeline_waiter_init(&buffer->drm_syncobj_waiter,
 | 
				
			||||||
 | 
									signal_timeline->base, signal_point, 0, wl->event_loop,
 | 
				
			||||||
 | 
									buffer_handle_drm_syncobj_ready)) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							buffer->has_drm_syncobj_waiter = true;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (output->drm_syncobj_surface_v1 != NULL) {
 | 
				
			||||||
 | 
								wp_linux_drm_syncobj_surface_v1_destroy(output->drm_syncobj_surface_v1);
 | 
				
			||||||
 | 
								output->drm_syncobj_surface_v1 = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((state->committed & WLR_OUTPUT_STATE_LAYERS) &&
 | 
						if ((state->committed & WLR_OUTPUT_STATE_LAYERS) &&
 | 
				
			||||||
			!commit_layers(output, state->layers, state->layers_len)) {
 | 
								!commit_layers(output, state->layers, state->layers_len)) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -637,9 +864,8 @@ static bool output_commit(struct wlr_output *wlr_output,
 | 
				
			||||||
		wl_callback_add_listener(output->frame_callback, &frame_listener, output);
 | 
							wl_callback_add_listener(output->frame_callback, &frame_listener, output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct wp_presentation_feedback *wp_feedback = NULL;
 | 
							struct wp_presentation_feedback *wp_feedback = NULL;
 | 
				
			||||||
		if (output->backend->presentation != NULL) {
 | 
							if (wl->presentation != NULL) {
 | 
				
			||||||
			wp_feedback = wp_presentation_feedback(output->backend->presentation,
 | 
								wp_feedback = wp_presentation_feedback(wl->presentation, output->surface);
 | 
				
			||||||
				output->surface);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (output->has_configure_serial) {
 | 
							if (output->has_configure_serial) {
 | 
				
			||||||
| 
						 | 
					@ -672,7 +898,7 @@ static bool output_commit(struct wlr_output *wlr_output,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_display_flush(output->backend->remote_display);
 | 
						wl_display_flush(wl->remote_display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -728,6 +954,8 @@ static void output_destroy(struct wlr_output *wlr_output) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_output_finish(wlr_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_remove(&output->link);
 | 
						wl_list_remove(&output->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (output->cursor.surface) {
 | 
						if (output->cursor.surface) {
 | 
				
			||||||
| 
						 | 
					@ -748,6 +976,9 @@ static void output_destroy(struct wlr_output *wlr_output) {
 | 
				
			||||||
		wl_callback_destroy(output->unmap_callback);
 | 
							wl_callback_destroy(output->unmap_callback);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (output->drm_syncobj_surface_v1) {
 | 
				
			||||||
 | 
							wp_linux_drm_syncobj_surface_v1_destroy(output->drm_syncobj_surface_v1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (output->zxdg_toplevel_decoration_v1) {
 | 
						if (output->zxdg_toplevel_decoration_v1) {
 | 
				
			||||||
		zxdg_toplevel_decoration_v1_destroy(output->zxdg_toplevel_decoration_v1);
 | 
							zxdg_toplevel_decoration_v1_destroy(output->zxdg_toplevel_decoration_v1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -824,6 +1055,12 @@ static void xdg_surface_handle_configure(void *data,
 | 
				
			||||||
	output->has_configure_serial = true;
 | 
						output->has_configure_serial = true;
 | 
				
			||||||
	output->configure_serial = serial;
 | 
						output->configure_serial = serial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!output->wlr_output.enabled) {
 | 
				
			||||||
 | 
							// We're waiting for a configure event after an initial commit to enable
 | 
				
			||||||
 | 
							// the output. Do not notify the compositor about the requested state.
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_output_state state;
 | 
						struct wlr_output_state state;
 | 
				
			||||||
	wlr_output_state_init(&state);
 | 
						wlr_output_state_init(&state);
 | 
				
			||||||
	wlr_output_state_set_custom_mode(&state, req_width, req_height, 0);
 | 
						wlr_output_state_set_custom_mode(&state, req_width, req_height, 0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,7 +112,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
 | 
				
			||||||
		.state = state,
 | 
							.state = state,
 | 
				
			||||||
		.time_msec = time,
 | 
							.time_msec = time,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	wl_signal_emit_mutable(&pointer->wlr_pointer.events.button, &event);
 | 
						wlr_pointer_notify_button(&pointer->wlr_pointer, &event);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
 | 
					static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,12 +27,14 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
 | 
				
			||||||
		uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
 | 
							uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
 | 
				
			||||||
	struct wlr_keyboard *keyboard = data;
 | 
						struct wlr_keyboard *keyboard = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int64_t time_msec = get_current_time_msec();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t *keycode_ptr;
 | 
						uint32_t *keycode_ptr;
 | 
				
			||||||
	wl_array_for_each(keycode_ptr, keys) {
 | 
						wl_array_for_each(keycode_ptr, keys) {
 | 
				
			||||||
		struct wlr_keyboard_key_event event = {
 | 
							struct wlr_keyboard_key_event event = {
 | 
				
			||||||
			.keycode = *keycode_ptr,
 | 
								.keycode = *keycode_ptr,
 | 
				
			||||||
			.state = WL_KEYBOARD_KEY_STATE_PRESSED,
 | 
								.state = WL_KEYBOARD_KEY_STATE_PRESSED,
 | 
				
			||||||
			.time_msec = get_current_time_msec(),
 | 
								.time_msec = time_msec,
 | 
				
			||||||
			.update_state = false,
 | 
								.update_state = false,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
		wlr_keyboard_notify_key(keyboard, &event);
 | 
							wlr_keyboard_notify_key(keyboard, &event);
 | 
				
			||||||
| 
						 | 
					@ -43,18 +45,12 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
 | 
				
			||||||
		uint32_t serial, struct wl_surface *surface) {
 | 
							uint32_t serial, struct wl_surface *surface) {
 | 
				
			||||||
	struct wlr_keyboard *keyboard = data;
 | 
						struct wlr_keyboard *keyboard = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t num_keycodes = keyboard->num_keycodes;
 | 
						int64_t time_msec = get_current_time_msec();
 | 
				
			||||||
	uint32_t pressed[num_keycodes + 1];
 | 
						while (keyboard->num_keycodes > 0) {
 | 
				
			||||||
	memcpy(pressed, keyboard->keycodes,
 | 
					 | 
				
			||||||
		num_keycodes * sizeof(uint32_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (size_t i = 0; i < num_keycodes; ++i) {
 | 
					 | 
				
			||||||
		uint32_t keycode = pressed[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		struct wlr_keyboard_key_event event = {
 | 
							struct wlr_keyboard_key_event event = {
 | 
				
			||||||
			.keycode = keycode,
 | 
								.keycode = keyboard->keycodes[keyboard->num_keycodes - 1],
 | 
				
			||||||
			.state = WL_KEYBOARD_KEY_STATE_RELEASED,
 | 
								.state = WL_KEYBOARD_KEY_STATE_RELEASED,
 | 
				
			||||||
			.time_msec = get_current_time_msec(),
 | 
								.time_msec = time_msec,
 | 
				
			||||||
			.update_state = false,
 | 
								.update_state = false,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
		wlr_keyboard_notify_key(keyboard, &event);
 | 
							wlr_keyboard_notify_key(keyboard, &event);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,17 +212,10 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
 | 
				
			||||||
	return x11->drm_fd;
 | 
						return x11->drm_fd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t get_buffer_caps(struct wlr_backend *backend) {
 | 
					 | 
				
			||||||
	struct wlr_x11_backend *x11 = get_x11_backend_from_backend(backend);
 | 
					 | 
				
			||||||
	return (x11->have_dri3 ? WLR_BUFFER_CAP_DMABUF : 0)
 | 
					 | 
				
			||||||
		| (x11->have_shm ? WLR_BUFFER_CAP_SHM : 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct wlr_backend_impl backend_impl = {
 | 
					static const struct wlr_backend_impl backend_impl = {
 | 
				
			||||||
	.start = backend_start,
 | 
						.start = backend_start,
 | 
				
			||||||
	.destroy = backend_destroy,
 | 
						.destroy = backend_destroy,
 | 
				
			||||||
	.get_drm_fd = backend_get_drm_fd,
 | 
						.get_drm_fd = backend_get_drm_fd,
 | 
				
			||||||
	.get_buffer_caps = get_buffer_caps,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_backend_is_x11(struct wlr_backend *backend) {
 | 
					bool wlr_backend_is_x11(struct wlr_backend *backend) {
 | 
				
			||||||
| 
						 | 
					@ -409,7 +402,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
 | 
				
			||||||
	wl_list_init(&x11->outputs);
 | 
						wl_list_init(&x11->outputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	x11->xcb = xcb_connect(x11_display, NULL);
 | 
						x11->xcb = xcb_connect(x11_display, NULL);
 | 
				
			||||||
	if (!x11->xcb || xcb_connection_has_error(x11->xcb)) {
 | 
						if (xcb_connection_has_error(x11->xcb)) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Failed to open xcb connection");
 | 
							wlr_log(WLR_ERROR, "Failed to open xcb connection");
 | 
				
			||||||
		goto error_x11;
 | 
							goto error_x11;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -512,7 +505,10 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
 | 
				
			||||||
		xcb_present_query_version(x11->xcb, 1, 2);
 | 
							xcb_present_query_version(x11->xcb, 1, 2);
 | 
				
			||||||
	xcb_present_query_version_reply_t *present_reply =
 | 
						xcb_present_query_version_reply_t *present_reply =
 | 
				
			||||||
		xcb_present_query_version_reply(x11->xcb, present_cookie, NULL);
 | 
							xcb_present_query_version_reply(x11->xcb, present_cookie, NULL);
 | 
				
			||||||
	if (!present_reply || present_reply->major_version < 1) {
 | 
						if (!present_reply) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Failed to query Present version");
 | 
				
			||||||
 | 
							goto error_display;
 | 
				
			||||||
 | 
						} else if (present_reply->major_version < 1) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "X11 does not support required Present version "
 | 
							wlr_log(WLR_ERROR, "X11 does not support required Present version "
 | 
				
			||||||
			"(has %"PRIu32".%"PRIu32", want 1.0)",
 | 
								"(has %"PRIu32".%"PRIu32", want 1.0)",
 | 
				
			||||||
			present_reply->major_version, present_reply->minor_version);
 | 
								present_reply->major_version, present_reply->minor_version);
 | 
				
			||||||
| 
						 | 
					@ -533,7 +529,10 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
 | 
				
			||||||
		xcb_xfixes_query_version(x11->xcb, 4, 0);
 | 
							xcb_xfixes_query_version(x11->xcb, 4, 0);
 | 
				
			||||||
	xcb_xfixes_query_version_reply_t *fixes_reply =
 | 
						xcb_xfixes_query_version_reply_t *fixes_reply =
 | 
				
			||||||
		xcb_xfixes_query_version_reply(x11->xcb, fixes_cookie, NULL);
 | 
							xcb_xfixes_query_version_reply(x11->xcb, fixes_cookie, NULL);
 | 
				
			||||||
	if (!fixes_reply || fixes_reply->major_version < 4) {
 | 
						if (!fixes_reply) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Failed to query Xfixes version");
 | 
				
			||||||
 | 
							goto error_display;
 | 
				
			||||||
 | 
						} else if (fixes_reply->major_version < 4) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "X11 does not support required Xfixes version "
 | 
							wlr_log(WLR_ERROR, "X11 does not support required Xfixes version "
 | 
				
			||||||
			"(has %"PRIu32".%"PRIu32", want 4.0)",
 | 
								"(has %"PRIu32".%"PRIu32", want 4.0)",
 | 
				
			||||||
			fixes_reply->major_version, fixes_reply->minor_version);
 | 
								fixes_reply->major_version, fixes_reply->minor_version);
 | 
				
			||||||
| 
						 | 
					@ -555,7 +554,10 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
 | 
				
			||||||
		xcb_input_xi_query_version(x11->xcb, 2, 0);
 | 
							xcb_input_xi_query_version(x11->xcb, 2, 0);
 | 
				
			||||||
	xcb_input_xi_query_version_reply_t *xi_reply =
 | 
						xcb_input_xi_query_version_reply_t *xi_reply =
 | 
				
			||||||
		xcb_input_xi_query_version_reply(x11->xcb, xi_cookie, NULL);
 | 
							xcb_input_xi_query_version_reply(x11->xcb, xi_cookie, NULL);
 | 
				
			||||||
	if (!xi_reply || xi_reply->major_version < 2) {
 | 
						if (!xi_reply) {
 | 
				
			||||||
 | 
							wlr_log(WLR_ERROR, "Failed to query Xinput version");
 | 
				
			||||||
 | 
							goto error_display;
 | 
				
			||||||
 | 
						} else if (xi_reply->major_version < 2) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "X11 does not support required Xinput version "
 | 
							wlr_log(WLR_ERROR, "X11 does not support required Xinput version "
 | 
				
			||||||
			"(has %"PRIu32".%"PRIu32", want 2.0)",
 | 
								"(has %"PRIu32".%"PRIu32", want 2.0)",
 | 
				
			||||||
			xi_reply->major_version, xi_reply->minor_version);
 | 
								xi_reply->major_version, xi_reply->minor_version);
 | 
				
			||||||
| 
						 | 
					@ -564,6 +566,13 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free(xi_reply);
 | 
						free(xi_reply);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (x11->have_dri3) {
 | 
				
			||||||
 | 
							x11->backend.buffer_caps |= WLR_BUFFER_CAP_DMABUF;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (x11->have_shm) {
 | 
				
			||||||
 | 
							x11->backend.buffer_caps |= WLR_BUFFER_CAP_SHM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int fd = xcb_get_file_descriptor(x11->xcb);
 | 
						int fd = xcb_get_file_descriptor(x11->xcb);
 | 
				
			||||||
	uint32_t events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP;
 | 
						uint32_t events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP;
 | 
				
			||||||
	x11->event_source = wl_event_loop_add_fd(loop, fd, events, x11_event, x11);
 | 
						x11->event_source = wl_event_loop_add_fd(loop, fd, events, x11_event, x11);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,7 @@ static void send_button_event(struct wlr_x11_output *output, uint32_t key,
 | 
				
			||||||
		.button = key,
 | 
							.button = key,
 | 
				
			||||||
		.state = st,
 | 
							.state = st,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	wl_signal_emit_mutable(&output->pointer.events.button, &ev);
 | 
						wlr_pointer_notify_button(&output->pointer, &ev);
 | 
				
			||||||
	wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer);
 | 
						wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,6 +94,8 @@ static void output_destroy(struct wlr_output *wlr_output) {
 | 
				
			||||||
	struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
 | 
						struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
 | 
				
			||||||
	struct wlr_x11_backend *x11 = output->x11;
 | 
						struct wlr_x11_backend *x11 = output->x11;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_output_finish(wlr_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pixman_region32_fini(&output->exposed);
 | 
						pixman_region32_fini(&output->exposed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_pointer_finish(&output->pointer);
 | 
						wlr_pointer_finish(&output->pointer);
 | 
				
			||||||
| 
						 | 
					@ -129,6 +131,27 @@ static bool output_test(struct wlr_output *wlr_output,
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
				
			||||||
 | 
							// If the size doesn't match, reject buffer (scaling is not supported)
 | 
				
			||||||
 | 
							int pending_width, pending_height;
 | 
				
			||||||
 | 
							output_pending_resolution(wlr_output, state,
 | 
				
			||||||
 | 
								&pending_width, &pending_height);
 | 
				
			||||||
 | 
							if (state->buffer->width != pending_width ||
 | 
				
			||||||
 | 
									state->buffer->height != pending_height) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Source crop is not supported
 | 
				
			||||||
 | 
							struct wlr_fbox src_box;
 | 
				
			||||||
 | 
							output_state_get_buffer_src_box(state, &src_box);
 | 
				
			||||||
 | 
							if (src_box.x != 0.0 || src_box.y != 0.0 ||
 | 
				
			||||||
 | 
									src_box.width != (double)state->buffer->width ||
 | 
				
			||||||
 | 
									src_box.height != (double)state->buffer->height) {
 | 
				
			||||||
 | 
								wlr_log(WLR_DEBUG, "Source crop not supported in X11 output");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// All we can do to influence adaptive sync on the X11 backend is set the
 | 
						// All we can do to influence adaptive sync on the X11 backend is set the
 | 
				
			||||||
	// _VARIABLE_REFRESH window property like mesa automatically does. We don't
 | 
						// _VARIABLE_REFRESH window property like mesa automatically does. We don't
 | 
				
			||||||
	// have any control beyond that, so we set the state to enabled on creating
 | 
						// have any control beyond that, so we set the state to enabled on creating
 | 
				
			||||||
| 
						 | 
					@ -747,9 +770,6 @@ void handle_x11_present_event(struct wlr_x11_backend *x11,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		output->last_msc = complete_notify->msc;
 | 
							output->last_msc = complete_notify->msc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct timespec t;
 | 
					 | 
				
			||||||
		timespec_from_nsec(&t, complete_notify->ust * 1000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		uint32_t flags = 0;
 | 
							uint32_t flags = 0;
 | 
				
			||||||
		if (complete_notify->mode == XCB_PRESENT_COMPLETE_MODE_FLIP) {
 | 
							if (complete_notify->mode == XCB_PRESENT_COMPLETE_MODE_FLIP) {
 | 
				
			||||||
			flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
 | 
								flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
 | 
				
			||||||
| 
						 | 
					@ -760,10 +780,10 @@ void handle_x11_present_event(struct wlr_x11_backend *x11,
 | 
				
			||||||
			.output = &output->wlr_output,
 | 
								.output = &output->wlr_output,
 | 
				
			||||||
			.commit_seq = complete_notify->serial,
 | 
								.commit_seq = complete_notify->serial,
 | 
				
			||||||
			.presented = presented,
 | 
								.presented = presented,
 | 
				
			||||||
			.when = &t,
 | 
					 | 
				
			||||||
			.seq = complete_notify->msc,
 | 
								.seq = complete_notify->msc,
 | 
				
			||||||
			.flags = flags,
 | 
								.flags = flags,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
							timespec_from_nsec(&present_event.when, complete_notify->ust * 1000);
 | 
				
			||||||
		wlr_output_send_present(&output->wlr_output, &present_event);
 | 
							wlr_output_send_present(&output->wlr_output, &present_event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		wlr_output_send_frame(&output->wlr_output);
 | 
							wlr_output_send_frame(&output->wlr_output);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,10 @@ wlroots reads these environment variables
 | 
				
			||||||
  renderers: gles2, pixman, vulkan)
 | 
					  renderers: gles2, pixman, vulkan)
 | 
				
			||||||
* *WLR_RENDER_DRM_DEVICE*: specifies the DRM node to use for
 | 
					* *WLR_RENDER_DRM_DEVICE*: specifies the DRM node to use for
 | 
				
			||||||
  hardware-accelerated renderers.
 | 
					  hardware-accelerated renderers.
 | 
				
			||||||
 | 
					* *WLR_RENDER_NO_EXPLICIT_SYNC*: set to 1 to disable explicit synchronization
 | 
				
			||||||
 | 
					  support in renderers.
 | 
				
			||||||
 | 
					* *WLR_RENDERER_FORCE_SOFTWARE*: set to 1 to force software rendering for GLES2
 | 
				
			||||||
 | 
					  and Vulkan
 | 
				
			||||||
* *WLR_EGL_NO_MODIFIERS*: set to 1 to disable format modifiers in EGL, this can
 | 
					* *WLR_EGL_NO_MODIFIERS*: set to 1 to disable format modifiers in EGL, this can
 | 
				
			||||||
  be used to understand and work around driver bugs.
 | 
					  be used to understand and work around driver bugs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@ struct cairo_buffer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void cairo_buffer_destroy(struct wlr_buffer *wlr_buffer) {
 | 
					static void cairo_buffer_destroy(struct wlr_buffer *wlr_buffer) {
 | 
				
			||||||
	struct cairo_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
 | 
						struct cairo_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
 | 
				
			||||||
 | 
						wlr_buffer_finish(wlr_buffer);
 | 
				
			||||||
	cairo_surface_destroy(buffer->surface);
 | 
						cairo_surface_destroy(buffer->surface);
 | 
				
			||||||
	free(buffer);
 | 
						free(buffer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,258 +0,0 @@
 | 
				
			||||||
#include <getopt.h>
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					 | 
				
			||||||
#include <wlr/backend.h>
 | 
					 | 
				
			||||||
#include <wlr/render/allocator.h>
 | 
					 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_compositor.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_fullscreen_shell_v1.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					 | 
				
			||||||
#include <wlr/util/box.h>
 | 
					 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					 | 
				
			||||||
#include <wlr/util/transform.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * A minimal fullscreen-shell server. It only supports rendering.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct fullscreen_server {
 | 
					 | 
				
			||||||
	struct wl_display *wl_display;
 | 
					 | 
				
			||||||
	struct wlr_backend *backend;
 | 
					 | 
				
			||||||
	struct wlr_renderer *renderer;
 | 
					 | 
				
			||||||
	struct wlr_allocator *allocator;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_fullscreen_shell_v1 *fullscreen_shell;
 | 
					 | 
				
			||||||
	struct wl_listener present_surface;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_output_layout *output_layout;
 | 
					 | 
				
			||||||
	struct wl_list outputs;
 | 
					 | 
				
			||||||
	struct wl_listener new_output;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct fullscreen_output {
 | 
					 | 
				
			||||||
	struct wl_list link;
 | 
					 | 
				
			||||||
	struct fullscreen_server *server;
 | 
					 | 
				
			||||||
	struct wlr_output *wlr_output;
 | 
					 | 
				
			||||||
	struct wlr_surface *surface;
 | 
					 | 
				
			||||||
	struct wl_listener surface_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_listener frame;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct render_data {
 | 
					 | 
				
			||||||
	struct wlr_output *output;
 | 
					 | 
				
			||||||
	struct wlr_render_pass *render_pass;
 | 
					 | 
				
			||||||
	struct timespec *when;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void render_surface(struct wlr_surface *surface,
 | 
					 | 
				
			||||||
		int sx, int sy, void *data) {
 | 
					 | 
				
			||||||
	struct render_data *rdata = data;
 | 
					 | 
				
			||||||
	struct wlr_output *output = rdata->output;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_texture *texture = wlr_surface_get_texture(surface);
 | 
					 | 
				
			||||||
	if (texture == NULL) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_box box = {
 | 
					 | 
				
			||||||
		.x = sx * output->scale,
 | 
					 | 
				
			||||||
		.y = sy * output->scale,
 | 
					 | 
				
			||||||
		.width = surface->current.width * output->scale,
 | 
					 | 
				
			||||||
		.height = surface->current.height * output->scale,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform);
 | 
					 | 
				
			||||||
	transform = wlr_output_transform_compose(transform, output->transform);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_render_pass_add_texture(rdata->render_pass, &(struct wlr_render_texture_options){
 | 
					 | 
				
			||||||
		.texture = texture,
 | 
					 | 
				
			||||||
		.dst_box = box,
 | 
					 | 
				
			||||||
		.transform = transform,
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_surface_send_frame_done(surface, rdata->when);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void output_handle_frame(struct wl_listener *listener, void *data) {
 | 
					 | 
				
			||||||
	struct fullscreen_output *output =
 | 
					 | 
				
			||||||
		wl_container_of(listener, output, frame);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct timespec now;
 | 
					 | 
				
			||||||
	clock_gettime(CLOCK_MONOTONIC, &now);
 | 
					 | 
				
			||||||
	int width, height;
 | 
					 | 
				
			||||||
	wlr_output_effective_resolution(output->wlr_output, &width, &height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_output_state state;
 | 
					 | 
				
			||||||
	wlr_output_state_init(&state);
 | 
					 | 
				
			||||||
	struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &state, NULL,
 | 
					 | 
				
			||||||
		NULL);
 | 
					 | 
				
			||||||
	if (pass == NULL) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
					 | 
				
			||||||
		.color = { 0.3, 0.3, 0.3, 1.0 },
 | 
					 | 
				
			||||||
		.box = { .width = width, .height = height },
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (output->surface != NULL) {
 | 
					 | 
				
			||||||
		struct render_data rdata = {
 | 
					 | 
				
			||||||
			.output = output->wlr_output,
 | 
					 | 
				
			||||||
			.render_pass = pass,
 | 
					 | 
				
			||||||
			.when = &now,
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		wlr_surface_for_each_surface(output->surface, render_surface, &rdata);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_render_pass_submit(pass);
 | 
					 | 
				
			||||||
	wlr_output_commit_state(output->wlr_output, &state);
 | 
					 | 
				
			||||||
	wlr_output_state_finish(&state);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void output_set_surface(struct fullscreen_output *output,
 | 
					 | 
				
			||||||
		struct wlr_surface *surface);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void output_handle_surface_destroy(struct wl_listener *listener,
 | 
					 | 
				
			||||||
		void *data) {
 | 
					 | 
				
			||||||
	struct fullscreen_output *output =
 | 
					 | 
				
			||||||
		wl_container_of(listener, output, surface_destroy);
 | 
					 | 
				
			||||||
	output_set_surface(output, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void output_set_surface(struct fullscreen_output *output,
 | 
					 | 
				
			||||||
		struct wlr_surface *surface) {
 | 
					 | 
				
			||||||
	if (output->surface == surface) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (output->surface != NULL) {
 | 
					 | 
				
			||||||
		wl_list_remove(&output->surface_destroy.link);
 | 
					 | 
				
			||||||
		output->surface = NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (surface != NULL) {
 | 
					 | 
				
			||||||
		output->surface_destroy.notify = output_handle_surface_destroy;
 | 
					 | 
				
			||||||
		wl_signal_add(&surface->events.destroy, &output->surface_destroy);
 | 
					 | 
				
			||||||
		output->surface = surface;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_log(WLR_DEBUG, "Presenting surface %p on output %s",
 | 
					 | 
				
			||||||
		surface, output->wlr_output->name);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_handle_new_output(struct wl_listener *listener, void *data) {
 | 
					 | 
				
			||||||
	struct fullscreen_server *server =
 | 
					 | 
				
			||||||
		wl_container_of(listener, server, new_output);
 | 
					 | 
				
			||||||
	struct wlr_output *wlr_output = data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_output_init_render(wlr_output, server->allocator, server->renderer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct fullscreen_output *output = calloc(1, sizeof(*output));
 | 
					 | 
				
			||||||
	output->wlr_output = wlr_output;
 | 
					 | 
				
			||||||
	output->server = server;
 | 
					 | 
				
			||||||
	output->frame.notify = output_handle_frame;
 | 
					 | 
				
			||||||
	wl_signal_add(&wlr_output->events.frame, &output->frame);
 | 
					 | 
				
			||||||
	wl_list_insert(&server->outputs, &output->link);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_output_layout_add_auto(server->output_layout, wlr_output);
 | 
					 | 
				
			||||||
	wlr_output_create_global(wlr_output, server->wl_display);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_output_state state;
 | 
					 | 
				
			||||||
	wlr_output_state_init(&state);
 | 
					 | 
				
			||||||
	wlr_output_state_set_enabled(&state, true);
 | 
					 | 
				
			||||||
	struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
 | 
					 | 
				
			||||||
	if (mode != NULL) {
 | 
					 | 
				
			||||||
		wlr_output_state_set_mode(&state, mode);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wlr_output_commit_state(wlr_output, &state);
 | 
					 | 
				
			||||||
	wlr_output_state_finish(&state);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void server_handle_present_surface(struct wl_listener *listener,
 | 
					 | 
				
			||||||
		void *data) {
 | 
					 | 
				
			||||||
	struct fullscreen_server *server =
 | 
					 | 
				
			||||||
		wl_container_of(listener, server, present_surface);
 | 
					 | 
				
			||||||
	struct wlr_fullscreen_shell_v1_present_surface_event *event = data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct fullscreen_output *output;
 | 
					 | 
				
			||||||
	wl_list_for_each(output, &server->outputs, link) {
 | 
					 | 
				
			||||||
		if (event->output == NULL || event->output == output->wlr_output) {
 | 
					 | 
				
			||||||
			output_set_surface(output, event->surface);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(int argc, char *argv[]) {
 | 
					 | 
				
			||||||
	wlr_log_init(WLR_DEBUG, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	char *startup_cmd = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int c;
 | 
					 | 
				
			||||||
	while ((c = getopt(argc, argv, "s:")) != -1) {
 | 
					 | 
				
			||||||
		switch (c) {
 | 
					 | 
				
			||||||
		case 's':
 | 
					 | 
				
			||||||
			startup_cmd = optarg;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			printf("usage: %s [-s startup-command]\n", argv[0]);
 | 
					 | 
				
			||||||
			return EXIT_FAILURE;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (optind < argc) {
 | 
					 | 
				
			||||||
		printf("usage: %s [-s startup-command]\n", argv[0]);
 | 
					 | 
				
			||||||
		return EXIT_FAILURE;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct fullscreen_server server = {0};
 | 
					 | 
				
			||||||
	server.wl_display = wl_display_create();
 | 
					 | 
				
			||||||
	server.backend = wlr_backend_autocreate(wl_display_get_event_loop(server.wl_display), NULL);
 | 
					 | 
				
			||||||
	server.renderer = wlr_renderer_autocreate(server.backend);
 | 
					 | 
				
			||||||
	wlr_renderer_init_wl_display(server.renderer, server.wl_display);
 | 
					 | 
				
			||||||
	server.allocator = wlr_allocator_autocreate(server.backend,
 | 
					 | 
				
			||||||
		server.renderer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_compositor_create(server.wl_display, 5, server.renderer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	server.output_layout = wlr_output_layout_create(server.wl_display);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_list_init(&server.outputs);
 | 
					 | 
				
			||||||
	server.new_output.notify = server_handle_new_output;
 | 
					 | 
				
			||||||
	wl_signal_add(&server.backend->events.new_output, &server.new_output);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	server.fullscreen_shell = wlr_fullscreen_shell_v1_create(server.wl_display);
 | 
					 | 
				
			||||||
	server.present_surface.notify = server_handle_present_surface;
 | 
					 | 
				
			||||||
	wl_signal_add(&server.fullscreen_shell->events.present_surface,
 | 
					 | 
				
			||||||
		&server.present_surface);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const char *socket = wl_display_add_socket_auto(server.wl_display);
 | 
					 | 
				
			||||||
	if (!socket) {
 | 
					 | 
				
			||||||
		wl_display_destroy(server.wl_display);
 | 
					 | 
				
			||||||
		return EXIT_FAILURE;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!wlr_backend_start(server.backend)) {
 | 
					 | 
				
			||||||
		wl_display_destroy(server.wl_display);
 | 
					 | 
				
			||||||
		return EXIT_FAILURE;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	setenv("WAYLAND_DISPLAY", socket, true);
 | 
					 | 
				
			||||||
	if (startup_cmd != NULL) {
 | 
					 | 
				
			||||||
		if (fork() == 0) {
 | 
					 | 
				
			||||||
			execl("/bin/sh", "/bin/sh", "-c", startup_cmd, (void *)NULL);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_log(WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s",
 | 
					 | 
				
			||||||
			socket);
 | 
					 | 
				
			||||||
	wl_display_run(server.wl_display);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wl_display_destroy_clients(server.wl_display);
 | 
					 | 
				
			||||||
	wl_display_destroy(server.wl_display);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -25,10 +25,6 @@ compositors = {
 | 
				
			||||||
	'output-layout': {
 | 
						'output-layout': {
 | 
				
			||||||
		'src': ['output-layout.c', 'cat.c'],
 | 
							'src': ['output-layout.c', 'cat.c'],
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	'fullscreen-shell': {
 | 
					 | 
				
			||||||
		'src': 'fullscreen-shell.c',
 | 
					 | 
				
			||||||
		'proto': ['fullscreen-shell-unstable-v1'],
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	'scene-graph': {
 | 
						'scene-graph': {
 | 
				
			||||||
		'src': 'scene-graph.c',
 | 
							'src': 'scene-graph.c',
 | 
				
			||||||
		'proto': ['xdg-shell'],
 | 
							'proto': ['xdg-shell'],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,9 +94,7 @@ static void output_handle_frame(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	int width, height;
 | 
						int width, height;
 | 
				
			||||||
	wlr_output_effective_resolution(output->wlr_output, &width, &height);
 | 
						wlr_output_effective_resolution(output->wlr_output, &width, &height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &output_state,
 | 
						struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &output_state, NULL);
 | 
				
			||||||
		NULL, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
						wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
				
			||||||
		.box = { .width = width, .height = height },
 | 
							.box = { .width = width, .height = height },
 | 
				
			||||||
		.color = { 0.3, 0.3, 0.3, 1 },
 | 
							.color = { 0.3, 0.3, 0.3, 1 },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -114,7 +114,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_output_state output_state;
 | 
						struct wlr_output_state output_state;
 | 
				
			||||||
	wlr_output_state_init(&output_state);
 | 
						wlr_output_state_init(&output_state);
 | 
				
			||||||
	struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
 | 
						struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
						wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
				
			||||||
		.box = { .width = wlr_output->width, .height = wlr_output->height },
 | 
							.box = { .width = wlr_output->width, .height = wlr_output->height },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -101,7 +101,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_output_state output_state;
 | 
						struct wlr_output_state output_state;
 | 
				
			||||||
	wlr_output_state_init(&output_state);
 | 
						wlr_output_state_init(&output_state);
 | 
				
			||||||
	struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
 | 
						struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
 | 
				
			||||||
	wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
						wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
				
			||||||
		.box = { .width = wlr_output->width, .height = wlr_output->height },
 | 
							.box = { .width = wlr_output->width, .height = wlr_output->height },
 | 
				
			||||||
		.color = {
 | 
							.color = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,7 +59,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_output_state output_state;
 | 
						struct wlr_output_state output_state;
 | 
				
			||||||
	wlr_output_state_init(&output_state);
 | 
						wlr_output_state_init(&output_state);
 | 
				
			||||||
	struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
 | 
						struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
						wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
				
			||||||
		.box = { .width = wlr_output->width, .height = wlr_output->height },
 | 
							.box = { .width = wlr_output->width, .height = wlr_output->height },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,7 +63,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_output_state state;
 | 
						struct wlr_output_state state;
 | 
				
			||||||
	wlr_output_state_init(&state);
 | 
						wlr_output_state_init(&state);
 | 
				
			||||||
	struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &state, NULL, NULL);
 | 
						struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &state, NULL);
 | 
				
			||||||
	wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
						wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
				
			||||||
		.box = { .width = wlr_output->width, .height = wlr_output->height },
 | 
							.box = { .width = wlr_output->width, .height = wlr_output->height },
 | 
				
			||||||
		.color = {
 | 
							.color = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +89,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_output_state output_state;
 | 
						struct wlr_output_state output_state;
 | 
				
			||||||
	wlr_output_state_init(&output_state);
 | 
						wlr_output_state_init(&output_state);
 | 
				
			||||||
	struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
 | 
						struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
						wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
				
			||||||
		.box = { .width = wlr_output->width, .height = wlr_output->height },
 | 
							.box = { .width = wlr_output->width, .height = wlr_output->height },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_output_state output_state;
 | 
						struct wlr_output_state output_state;
 | 
				
			||||||
	wlr_output_state_init(&output_state);
 | 
						wlr_output_state_init(&output_state);
 | 
				
			||||||
	struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
 | 
						struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
 | 
				
			||||||
	wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
						wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
 | 
				
			||||||
		.box = { .width = width, .height = height },
 | 
							.box = { .width = width, .height = height },
 | 
				
			||||||
		.color = { 0.25, 0.25, 0.25, 1 },
 | 
							.color = { 0.25, 0.25, 0.25, 1 },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +0,0 @@
 | 
				
			||||||
#ifndef BACKEND_WLR_BACKEND_H
 | 
					 | 
				
			||||||
#define BACKEND_WLR_BACKEND_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <wlr/backend.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Get the supported buffer capabilities.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This functions returns a bitfield of supported wlr_buffer_cap.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
uint32_t backend_get_buffer_caps(struct wlr_backend *backend);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,11 @@
 | 
				
			||||||
#include "backend/drm/properties.h"
 | 
					#include "backend/drm/properties.h"
 | 
				
			||||||
#include "backend/drm/renderer.h"
 | 
					#include "backend/drm/renderer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_drm_viewport {
 | 
				
			||||||
 | 
						struct wlr_fbox src_box;
 | 
				
			||||||
 | 
						struct wlr_box dst_box;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_plane {
 | 
					struct wlr_drm_plane {
 | 
				
			||||||
	uint32_t type;
 | 
						uint32_t type;
 | 
				
			||||||
	uint32_t id;
 | 
						uint32_t id;
 | 
				
			||||||
| 
						 | 
					@ -26,6 +31,8 @@ struct wlr_drm_plane {
 | 
				
			||||||
	struct wlr_drm_fb *queued_fb;
 | 
						struct wlr_drm_fb *queued_fb;
 | 
				
			||||||
	/* Buffer currently displayed on screen */
 | 
						/* Buffer currently displayed on screen */
 | 
				
			||||||
	struct wlr_drm_fb *current_fb;
 | 
						struct wlr_drm_fb *current_fb;
 | 
				
			||||||
 | 
						/* Viewport belonging to the last committed fb */
 | 
				
			||||||
 | 
						struct wlr_drm_viewport viewport;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_drm_format_set formats;
 | 
						struct wlr_drm_format_set formats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -139,13 +146,20 @@ struct wlr_drm_connector_state {
 | 
				
			||||||
	bool active;
 | 
						bool active;
 | 
				
			||||||
	drmModeModeInfo mode;
 | 
						drmModeModeInfo mode;
 | 
				
			||||||
	struct wlr_drm_fb *primary_fb;
 | 
						struct wlr_drm_fb *primary_fb;
 | 
				
			||||||
 | 
						struct wlr_drm_viewport primary_viewport;
 | 
				
			||||||
	struct wlr_drm_fb *cursor_fb;
 | 
						struct wlr_drm_fb *cursor_fb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *wait_timeline;
 | 
				
			||||||
 | 
						uint64_t wait_point;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// used by atomic
 | 
						// used by atomic
 | 
				
			||||||
	uint32_t mode_id;
 | 
						uint32_t mode_id;
 | 
				
			||||||
	uint32_t gamma_lut;
 | 
						uint32_t gamma_lut;
 | 
				
			||||||
	uint32_t fb_damage_clips;
 | 
						uint32_t fb_damage_clips;
 | 
				
			||||||
 | 
						int primary_in_fence_fd, out_fence_fd;
 | 
				
			||||||
	bool vrr_enabled;
 | 
						bool vrr_enabled;
 | 
				
			||||||
 | 
						uint32_t colorspace;
 | 
				
			||||||
 | 
						uint32_t hdr_output_metadata;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -200,6 +214,10 @@ struct wlr_drm_connector {
 | 
				
			||||||
	// Last committed page-flip
 | 
						// Last committed page-flip
 | 
				
			||||||
	struct wlr_drm_page_flip *pending_page_flip;
 | 
						struct wlr_drm_page_flip *pending_page_flip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Atomic modesetting only
 | 
				
			||||||
 | 
						uint32_t colorspace;
 | 
				
			||||||
 | 
						uint32_t hdr_output_metadata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int32_t refresh;
 | 
						int32_t refresh;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -213,7 +231,6 @@ void scan_drm_connectors(struct wlr_drm_backend *state,
 | 
				
			||||||
void scan_drm_leases(struct wlr_drm_backend *drm);
 | 
					void scan_drm_leases(struct wlr_drm_backend *drm);
 | 
				
			||||||
bool commit_drm_device(struct wlr_drm_backend *drm,
 | 
					bool commit_drm_device(struct wlr_drm_backend *drm,
 | 
				
			||||||
	const struct wlr_backend_output_state *states, size_t states_len, bool test_only);
 | 
						const struct wlr_backend_output_state *states, size_t states_len, bool test_only);
 | 
				
			||||||
void restore_drm_device(struct wlr_drm_backend *drm);
 | 
					 | 
				
			||||||
int handle_drm_event(int fd, uint32_t mask, void *data);
 | 
					int handle_drm_event(int fd, uint32_t mask, void *data);
 | 
				
			||||||
void destroy_drm_connector(struct wlr_drm_connector *conn);
 | 
					void destroy_drm_connector(struct wlr_drm_connector *conn);
 | 
				
			||||||
bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn);
 | 
					bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,10 @@
 | 
				
			||||||
#define BACKEND_DRM_FB_H
 | 
					#define BACKEND_DRM_FB_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <wlr/util/addon.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_drm_format_set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_fb {
 | 
					struct wlr_drm_fb {
 | 
				
			||||||
	struct wlr_buffer *wlr_buf;
 | 
						struct wlr_buffer *wlr_buf;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,8 +22,6 @@ struct wlr_drm_interface {
 | 
				
			||||||
	bool (*commit)(struct wlr_drm_backend *drm,
 | 
						bool (*commit)(struct wlr_drm_backend *drm,
 | 
				
			||||||
		const struct wlr_drm_device_state *state,
 | 
							const struct wlr_drm_device_state *state,
 | 
				
			||||||
		struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only);
 | 
							struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only);
 | 
				
			||||||
	// Turn off everything
 | 
					 | 
				
			||||||
	bool (*reset)(struct wlr_drm_backend *drm);
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const struct wlr_drm_interface atomic_iface;
 | 
					extern const struct wlr_drm_interface atomic_iface;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,8 @@ struct wlr_drm_connector_props {
 | 
				
			||||||
	// atomic-modesetting only
 | 
						// atomic-modesetting only
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t crtc_id;
 | 
						uint32_t crtc_id;
 | 
				
			||||||
 | 
						uint32_t colorspace;
 | 
				
			||||||
 | 
						uint32_t hdr_output_metadata;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_crtc_props {
 | 
					struct wlr_drm_crtc_props {
 | 
				
			||||||
| 
						 | 
					@ -38,6 +40,7 @@ struct wlr_drm_crtc_props {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t active;
 | 
						uint32_t active;
 | 
				
			||||||
	uint32_t mode_id;
 | 
						uint32_t mode_id;
 | 
				
			||||||
 | 
						uint32_t out_fence_ptr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_plane_props {
 | 
					struct wlr_drm_plane_props {
 | 
				
			||||||
| 
						 | 
					@ -61,6 +64,7 @@ struct wlr_drm_plane_props {
 | 
				
			||||||
	uint32_t fb_damage_clips;
 | 
						uint32_t fb_damage_clips;
 | 
				
			||||||
	uint32_t hotspot_x;
 | 
						uint32_t hotspot_x;
 | 
				
			||||||
	uint32_t hotspot_y;
 | 
						uint32_t hotspot_y;
 | 
				
			||||||
 | 
						uint32_t in_fence_fd;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool get_drm_connector_props(int fd, uint32_t id,
 | 
					bool get_drm_connector_props(int fd, uint32_t id,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,9 @@ struct wlr_drm_renderer {
 | 
				
			||||||
struct wlr_drm_surface {
 | 
					struct wlr_drm_surface {
 | 
				
			||||||
	struct wlr_drm_renderer *renderer;
 | 
						struct wlr_drm_renderer *renderer;
 | 
				
			||||||
	struct wlr_swapchain *swapchain;
 | 
						struct wlr_swapchain *swapchain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *timeline;
 | 
				
			||||||
 | 
						uint64_t point;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool init_drm_renderer(struct wlr_drm_backend *drm,
 | 
					bool init_drm_renderer(struct wlr_drm_backend *drm,
 | 
				
			||||||
| 
						 | 
					@ -32,7 +35,8 @@ bool init_drm_surface(struct wlr_drm_surface *surf,
 | 
				
			||||||
void finish_drm_surface(struct wlr_drm_surface *surf);
 | 
					void finish_drm_surface(struct wlr_drm_surface *surf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
 | 
					struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
 | 
				
			||||||
	struct wlr_buffer *buffer);
 | 
						struct wlr_buffer *buffer,
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool drm_plane_pick_render_format(struct wlr_drm_plane *plane,
 | 
					bool drm_plane_pick_render_format(struct wlr_drm_plane *plane,
 | 
				
			||||||
	struct wlr_drm_format *fmt, struct wlr_drm_renderer *renderer);
 | 
						struct wlr_drm_format *fmt, struct wlr_drm_renderer *renderer);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,26 +18,24 @@ const char *drm_connector_status_str(drmModeConnection status);
 | 
				
			||||||
void generate_cvt_mode(drmModeModeInfo *mode, int hdisplay, int vdisplay,
 | 
					void generate_cvt_mode(drmModeModeInfo *mode, int hdisplay, int vdisplay,
 | 
				
			||||||
	float vrefresh);
 | 
						float vrefresh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Part of match_obj
 | 
					// Part of match_connectors_with_crtcs
 | 
				
			||||||
enum {
 | 
					#define UNMATCHED ((uint32_t)-1)
 | 
				
			||||||
	UNMATCHED = (uint32_t)-1,
 | 
					 | 
				
			||||||
	SKIP = (uint32_t)-2,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/**
 | 
				
			||||||
 * Tries to match some DRM objects with some other DRM resource.
 | 
					 * Tries to match DRM connectors with DRM CRTCs.
 | 
				
			||||||
 * e.g. Match CRTCs with Encoders, CRTCs with Planes.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * objs contains a bit array which resources it can be matched with.
 | 
					 * conns contains an array of bitmasks describing compatible CRTCs. For
 | 
				
			||||||
 * e.g. Bit 0 set means can be matched with res[0]
 | 
					 * instance bit 0 set in an connector element means that it's compatible with
 | 
				
			||||||
 | 
					 * CRTC 0.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * res contains an index of which objs it is matched with or UNMATCHED.
 | 
					 * prev_crtcs contains connector indices each CRTC was previously matched with,
 | 
				
			||||||
 | 
					 * or UNMATCHED.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This solution is left in out.
 | 
					 * new_crtcs is populated with the new connector indices.
 | 
				
			||||||
 * Returns the total number of matched solutions.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs],
 | 
					void match_connectors_with_crtcs(size_t num_conns,
 | 
				
			||||||
		size_t num_res, const uint32_t res[static restrict num_res],
 | 
						const uint32_t conns[static restrict num_conns],
 | 
				
			||||||
		uint32_t out[static restrict num_res]);
 | 
						size_t num_crtcs, const uint32_t prev_crtcs[static restrict num_crtcs],
 | 
				
			||||||
 | 
						uint32_t new_crtcs[static restrict num_crtcs]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,8 +12,6 @@
 | 
				
			||||||
#include <wlr/types/wlr_tablet_tool.h>
 | 
					#include <wlr/types/wlr_tablet_tool.h>
 | 
				
			||||||
#include <wlr/types/wlr_touch.h>
 | 
					#include <wlr/types/wlr_touch.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_libinput_backend {
 | 
					struct wlr_libinput_backend {
 | 
				
			||||||
	struct wlr_backend backend;
 | 
						struct wlr_backend backend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@
 | 
				
			||||||
#include <wlr/types/wlr_tablet_tool.h>
 | 
					#include <wlr/types/wlr_tablet_tool.h>
 | 
				
			||||||
#include <wlr/types/wlr_touch.h>
 | 
					#include <wlr/types/wlr_touch.h>
 | 
				
			||||||
#include <wlr/render/drm_format_set.h>
 | 
					#include <wlr/render/drm_format_set.h>
 | 
				
			||||||
 | 
					#include <wlr/render/drm_syncobj.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_wl_backend {
 | 
					struct wlr_wl_backend {
 | 
				
			||||||
	struct wlr_backend backend;
 | 
						struct wlr_backend backend;
 | 
				
			||||||
| 
						 | 
					@ -21,6 +22,7 @@ struct wlr_wl_backend {
 | 
				
			||||||
	/* local state */
 | 
						/* local state */
 | 
				
			||||||
	bool started;
 | 
						bool started;
 | 
				
			||||||
	struct wl_event_loop *event_loop;
 | 
						struct wl_event_loop *event_loop;
 | 
				
			||||||
 | 
						struct wl_event_queue *busy_loop_queue;
 | 
				
			||||||
	struct wl_list outputs;
 | 
						struct wl_list outputs;
 | 
				
			||||||
	int drm_fd;
 | 
						int drm_fd;
 | 
				
			||||||
	struct wl_list buffers; // wlr_wl_buffer.link
 | 
						struct wl_list buffers; // wlr_wl_buffer.link
 | 
				
			||||||
| 
						 | 
					@ -40,6 +42,8 @@ struct wlr_wl_backend {
 | 
				
			||||||
	struct wp_presentation *presentation;
 | 
						struct wp_presentation *presentation;
 | 
				
			||||||
	struct wl_shm *shm;
 | 
						struct wl_shm *shm;
 | 
				
			||||||
	struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
 | 
						struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
 | 
				
			||||||
 | 
						struct wp_linux_drm_syncobj_manager_v1 *drm_syncobj_manager_v1;
 | 
				
			||||||
 | 
						struct wl_list drm_syncobj_timelines; // wlr_wl_drm_syncobj_timeline.link
 | 
				
			||||||
	struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1;
 | 
						struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1;
 | 
				
			||||||
	struct wl_list seats; // wlr_wl_seat.link
 | 
						struct wl_list seats; // wlr_wl_seat.link
 | 
				
			||||||
	struct zwp_tablet_manager_v2 *tablet_manager;
 | 
						struct zwp_tablet_manager_v2 *tablet_manager;
 | 
				
			||||||
| 
						 | 
					@ -58,6 +62,19 @@ struct wlr_wl_buffer {
 | 
				
			||||||
	bool released;
 | 
						bool released;
 | 
				
			||||||
	struct wl_list link; // wlr_wl_backend.buffers
 | 
						struct wl_list link; // wlr_wl_backend.buffers
 | 
				
			||||||
	struct wl_listener buffer_destroy;
 | 
						struct wl_listener buffer_destroy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_drm_syncobj_waiter;
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline_waiter drm_syncobj_waiter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *fallback_signal_timeline;
 | 
				
			||||||
 | 
						uint64_t fallback_signal_point;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_wl_drm_syncobj_timeline {
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *base;
 | 
				
			||||||
 | 
						struct wlr_addon addon;
 | 
				
			||||||
 | 
						struct wl_list link; // wlr_wl_backend.drm_syncobj_timelines
 | 
				
			||||||
 | 
						struct wp_linux_drm_syncobj_timeline_v1 *wl;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_wl_presentation_feedback {
 | 
					struct wlr_wl_presentation_feedback {
 | 
				
			||||||
| 
						 | 
					@ -88,6 +105,7 @@ struct wlr_wl_output {
 | 
				
			||||||
	struct xdg_surface *xdg_surface;
 | 
						struct xdg_surface *xdg_surface;
 | 
				
			||||||
	struct xdg_toplevel *xdg_toplevel;
 | 
						struct xdg_toplevel *xdg_toplevel;
 | 
				
			||||||
	struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
 | 
						struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
 | 
				
			||||||
 | 
						struct wp_linux_drm_syncobj_surface_v1 *drm_syncobj_surface_v1;
 | 
				
			||||||
	struct wl_list presentation_feedbacks;
 | 
						struct wl_list presentation_feedbacks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *title;
 | 
						char *title;
 | 
				
			||||||
| 
						 | 
					@ -190,6 +208,7 @@ bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl,
 | 
				
			||||||
	uint32_t global_name);
 | 
						uint32_t global_name);
 | 
				
			||||||
void destroy_wl_seat(struct wlr_wl_seat *seat);
 | 
					void destroy_wl_seat(struct wlr_wl_seat *seat);
 | 
				
			||||||
void destroy_wl_buffer(struct wlr_wl_buffer *buffer);
 | 
					void destroy_wl_buffer(struct wlr_wl_buffer *buffer);
 | 
				
			||||||
 | 
					void destroy_wl_drm_syncobj_timeline(struct wlr_wl_drm_syncobj_timeline *timeline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const struct wlr_pointer_impl wl_pointer_impl;
 | 
					extern const struct wlr_pointer_impl wl_pointer_impl;
 | 
				
			||||||
extern const struct wlr_tablet_pad_impl wl_tablet_pad_impl;
 | 
					extern const struct wlr_tablet_pad_impl wl_tablet_pad_impl;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +0,0 @@
 | 
				
			||||||
#ifndef RENDER_ALLOCATOR_ALLOCATOR_H
 | 
					 | 
				
			||||||
#define RENDER_ALLOCATOR_ALLOCATOR_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <wlr/render/allocator.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_allocator *allocator_autocreate_with_drm_fd(
 | 
					 | 
				
			||||||
	uint32_t backend_caps, struct wlr_renderer *renderer, int drm_fd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,9 @@
 | 
				
			||||||
#ifndef RENDER_ALLOCATOR_DRM_DUMB_H
 | 
					#ifndef RENDER_ALLOCATOR_DRM_DUMB_H
 | 
				
			||||||
#define RENDER_ALLOCATOR_DRM_DUMB_H
 | 
					#define RENDER_ALLOCATOR_DRM_DUMB_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wlr/render/allocator.h>
 | 
				
			||||||
#include <wlr/render/dmabuf.h>
 | 
					#include <wlr/render/dmabuf.h>
 | 
				
			||||||
#include <wlr/types/wlr_buffer.h>
 | 
					#include <wlr/types/wlr_buffer.h>
 | 
				
			||||||
#include "render/allocator/allocator.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_dumb_buffer {
 | 
					struct wlr_drm_dumb_buffer {
 | 
				
			||||||
	struct wlr_buffer base;
 | 
						struct wlr_buffer base;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,9 +2,9 @@
 | 
				
			||||||
#define RENDER_ALLOCATOR_GBM_H
 | 
					#define RENDER_ALLOCATOR_GBM_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <gbm.h>
 | 
					#include <gbm.h>
 | 
				
			||||||
 | 
					#include <wlr/render/allocator.h>
 | 
				
			||||||
#include <wlr/render/dmabuf.h>
 | 
					#include <wlr/render/dmabuf.h>
 | 
				
			||||||
#include <wlr/types/wlr_buffer.h>
 | 
					#include <wlr/types/wlr_buffer.h>
 | 
				
			||||||
#include "render/allocator/allocator.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_gbm_buffer {
 | 
					struct wlr_gbm_buffer {
 | 
				
			||||||
	struct wlr_buffer base;
 | 
						struct wlr_buffer base;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
#ifndef RENDER_ALLOCATOR_SHM_H
 | 
					#ifndef RENDER_ALLOCATOR_SHM_H
 | 
				
			||||||
#define RENDER_ALLOCATOR_SHM_H
 | 
					#define RENDER_ALLOCATOR_SHM_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wlr/render/allocator.h>
 | 
				
			||||||
#include <wlr/types/wlr_buffer.h>
 | 
					#include <wlr/types/wlr_buffer.h>
 | 
				
			||||||
#include "render/allocator/allocator.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_shm_buffer {
 | 
					struct wlr_shm_buffer {
 | 
				
			||||||
	struct wlr_buffer base;
 | 
						struct wlr_buffer base;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								include/render/allocator/udmabuf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								include/render/allocator/udmabuf.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					#ifndef RENDER_ALLOCATOR_UDMABUF_H
 | 
				
			||||||
 | 
					#define RENDER_ALLOCATOR_UDMABUF_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_buffer.h>
 | 
				
			||||||
 | 
					#include <wlr/render/allocator.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_udmabuf_buffer {
 | 
				
			||||||
 | 
						struct wlr_buffer base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t size;
 | 
				
			||||||
 | 
						struct wlr_shm_attributes shm;
 | 
				
			||||||
 | 
						struct wlr_dmabuf_attributes dmabuf;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_udmabuf_allocator {
 | 
				
			||||||
 | 
						struct wlr_allocator base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_allocator *wlr_udmabuf_allocator_create(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -2,30 +2,14 @@
 | 
				
			||||||
#define RENDER_COLOR_H
 | 
					#define RENDER_COLOR_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <wlr/render/color.h>
 | 
				
			||||||
#include <wlr/util/addon.h>
 | 
					#include <wlr/util/addon.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * The formula is approximated via a 3D look-up table. A 3D LUT is a
 | 
					 | 
				
			||||||
 * three-dimensional array where each element is an RGB triplet. The flat lut_3d
 | 
					 | 
				
			||||||
 * array has a length of dim_len³.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Color channel values in the range [0.0, 1.0] are mapped linearly to
 | 
					 | 
				
			||||||
 * 3D LUT indices such that 0.0 maps exactly to the first element and 1.0 maps
 | 
					 | 
				
			||||||
 * exactly to the last element in each dimension.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The offset of the RGB triplet given red, green and blue indices r_index,
 | 
					 | 
				
			||||||
 * g_index and b_index is:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *     offset = 3 * (r_index + dim_len * g_index + dim_len * dim_len * b_index)
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct wlr_color_transform_lut3d {
 | 
					 | 
				
			||||||
	float *lut_3d;
 | 
					 | 
				
			||||||
	size_t dim_len;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum wlr_color_transform_type {
 | 
					enum wlr_color_transform_type {
 | 
				
			||||||
	COLOR_TRANSFORM_SRGB,
 | 
						COLOR_TRANSFORM_INVERSE_EOTF,
 | 
				
			||||||
	COLOR_TRANSFORM_LUT_3D,
 | 
						COLOR_TRANSFORM_LCMS2,
 | 
				
			||||||
 | 
						COLOR_TRANSFORM_LUT_3X1D,
 | 
				
			||||||
 | 
						COLOR_TRANSFORM_PIPELINE,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_color_transform {
 | 
					struct wlr_color_transform {
 | 
				
			||||||
| 
						 | 
					@ -33,7 +17,84 @@ struct wlr_color_transform {
 | 
				
			||||||
	struct wlr_addon_set addons; // per-renderer helper state
 | 
						struct wlr_addon_set addons; // per-renderer helper state
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum wlr_color_transform_type type;
 | 
						enum wlr_color_transform_type type;
 | 
				
			||||||
	struct wlr_color_transform_lut3d lut3d;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_color_transform_inverse_eotf {
 | 
				
			||||||
 | 
						struct wlr_color_transform base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum wlr_color_transfer_function tf;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * The formula is approximated via three 1D look-up tables. The flat lut_3x1d
 | 
				
			||||||
 | 
					 * array has a length of 3 * dim.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The offset of a color value for a given channel and color index is:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *     offset = channel_index * dim + color_index
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_color_transform_lut_3x1d {
 | 
				
			||||||
 | 
						struct wlr_color_transform base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint16_t *lut_3x1d;
 | 
				
			||||||
 | 
						size_t dim;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_color_transform_pipeline {
 | 
				
			||||||
 | 
						struct wlr_color_transform base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_color_transform **transforms;
 | 
				
			||||||
 | 
						size_t len;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_color_transform_init(struct wlr_color_transform *tr,
 | 
				
			||||||
 | 
						enum wlr_color_transform_type type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get a struct wlr_color_transform_lcms2 from a generic struct wlr_color_transform.
 | 
				
			||||||
 | 
					 * Asserts that the base type is COLOR_TRANSFORM_LCMS2.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_color_transform_lcms2 *color_transform_lcms2_from_base(
 | 
				
			||||||
 | 
						struct wlr_color_transform *tr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void color_transform_lcms2_finish(struct wlr_color_transform_lcms2 *tr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Evaluate a LCMS2 color transform for a given RGB triplet.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void color_transform_lcms2_eval(struct wlr_color_transform_lcms2 *tr,
 | 
				
			||||||
 | 
						float out[static 3], const float in[static 3]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Gets a wlr_color_transform_inverse_eotf from a generic wlr_color_transform.
 | 
				
			||||||
 | 
					 * Asserts that the base type is COLOR_TRANSFORM_INVERSE_EOTF
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_base(
 | 
				
			||||||
 | 
						struct wlr_color_transform *tr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get a struct wlr_color_transform_lut_3x1d from a generic
 | 
				
			||||||
 | 
					 * struct wlr_color_transform. Asserts that the base type is
 | 
				
			||||||
 | 
					 * COLOR_TRANSFORM_LUT_3X1D.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
 | 
				
			||||||
 | 
						struct wlr_color_transform *tr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Obtain primaries values from a well-known primaries name.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_color_primaries_from_named(struct wlr_color_primaries *out,
 | 
				
			||||||
 | 
						enum wlr_color_named_primaries named);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Compute the matrix to convert RGB color values to CIE 1931 XYZ.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_color_primaries_to_xyz(const struct wlr_color_primaries *primaries, float matrix[static 9]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get default luminances for a transfer function.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_color_transfer_function_get_default_luminance(enum wlr_color_transfer_function tf,
 | 
				
			||||||
 | 
						struct wlr_color_luminances *lum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,10 @@ struct wlr_egl {
 | 
				
			||||||
		PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT;
 | 
							PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT;
 | 
				
			||||||
		PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
 | 
							PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
 | 
				
			||||||
		PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
 | 
							PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
 | 
				
			||||||
 | 
							PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR;
 | 
				
			||||||
 | 
							PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR;
 | 
				
			||||||
 | 
							PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID;
 | 
				
			||||||
 | 
							PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR;
 | 
				
			||||||
	} procs;
 | 
						} procs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool has_modifiers;
 | 
						bool has_modifiers;
 | 
				
			||||||
| 
						 | 
					@ -105,4 +109,12 @@ bool wlr_egl_make_current(struct wlr_egl *egl, struct wlr_egl_context *save_cont
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_egl_unset_current(struct wlr_egl *egl);
 | 
					bool wlr_egl_unset_current(struct wlr_egl *egl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EGLSyncKHR wlr_egl_create_sync(struct wlr_egl *egl, int fence_fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_egl_destroy_sync(struct wlr_egl *egl, EGLSyncKHR sync);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int wlr_egl_dup_fence_fd(struct wlr_egl *egl, EGLSyncKHR sync);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool wlr_egl_wait_sync(struct wlr_egl *egl, EGLSyncKHR sync);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,6 @@
 | 
				
			||||||
#include <GLES2/gl2ext.h>
 | 
					#include <GLES2/gl2ext.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <wlr/render/egl.h>
 | 
					#include <wlr/render/egl.h>
 | 
				
			||||||
#include <wlr/render/gles2.h>
 | 
					#include <wlr/render/gles2.h>
 | 
				
			||||||
| 
						 | 
					@ -138,6 +137,8 @@ struct wlr_gles2_render_pass {
 | 
				
			||||||
	float projection_matrix[9];
 | 
						float projection_matrix[9];
 | 
				
			||||||
	struct wlr_egl_context prev_ctx;
 | 
						struct wlr_egl_context prev_ctx;
 | 
				
			||||||
	struct wlr_gles2_render_timer *timer;
 | 
						struct wlr_gles2_render_timer *timer;
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *signal_timeline;
 | 
				
			||||||
 | 
						uint64_t signal_point;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer,
 | 
					bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer,
 | 
				
			||||||
| 
						 | 
					@ -169,6 +170,7 @@ void push_gles2_debug_(struct wlr_gles2_renderer *renderer,
 | 
				
			||||||
void pop_gles2_debug(struct wlr_gles2_renderer *renderer);
 | 
					void pop_gles2_debug(struct wlr_gles2_renderer *renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *buffer,
 | 
					struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *buffer,
 | 
				
			||||||
	struct wlr_egl_context *prev_ctx, struct wlr_gles2_render_timer *timer);
 | 
						struct wlr_egl_context *prev_ctx, struct wlr_gles2_render_timer *timer,
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *signal_timeline, uint64_t signal_point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
#include <vulkan/vulkan.h>
 | 
					#include <vulkan/vulkan.h>
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
#include <wlr/render/wlr_texture.h>
 | 
					#include <wlr/render/wlr_texture.h>
 | 
				
			||||||
 | 
					#include <wlr/render/color.h>
 | 
				
			||||||
#include <wlr/render/drm_format_set.h>
 | 
					#include <wlr/render/drm_format_set.h>
 | 
				
			||||||
#include <wlr/render/interface.h>
 | 
					#include <wlr/render/interface.h>
 | 
				
			||||||
#include <wlr/util/addon.h>
 | 
					#include <wlr/util/addon.h>
 | 
				
			||||||
| 
						 | 
					@ -40,6 +41,7 @@ struct wlr_vk_device {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int drm_fd;
 | 
						int drm_fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool sync_file_import_export;
 | 
				
			||||||
	bool implicit_sync_interop;
 | 
						bool implicit_sync_interop;
 | 
				
			||||||
	bool sampler_ycbcr_conversion;
 | 
						bool sampler_ycbcr_conversion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,6 +152,9 @@ struct wlr_vk_pipeline_layout {
 | 
				
			||||||
enum wlr_vk_texture_transform {
 | 
					enum wlr_vk_texture_transform {
 | 
				
			||||||
	WLR_VK_TEXTURE_TRANSFORM_IDENTITY = 0,
 | 
						WLR_VK_TEXTURE_TRANSFORM_IDENTITY = 0,
 | 
				
			||||||
	WLR_VK_TEXTURE_TRANSFORM_SRGB = 1,
 | 
						WLR_VK_TEXTURE_TRANSFORM_SRGB = 1,
 | 
				
			||||||
 | 
						WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2,
 | 
				
			||||||
 | 
						WLR_VK_TEXTURE_TRANSFORM_GAMMA22 = 3,
 | 
				
			||||||
 | 
						WLR_VK_TEXTURE_TRANSFORM_BT1886 = 4,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum wlr_vk_shader_source {
 | 
					enum wlr_vk_shader_source {
 | 
				
			||||||
| 
						 | 
					@ -160,8 +165,12 @@ enum wlr_vk_shader_source {
 | 
				
			||||||
// Constants used to pick the color transform for the blend-to-output
 | 
					// Constants used to pick the color transform for the blend-to-output
 | 
				
			||||||
// fragment shader. Must match those in shaders/output.frag
 | 
					// fragment shader. Must match those in shaders/output.frag
 | 
				
			||||||
enum wlr_vk_output_transform {
 | 
					enum wlr_vk_output_transform {
 | 
				
			||||||
	WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 0,
 | 
						WLR_VK_OUTPUT_TRANSFORM_IDENTITY = 0,
 | 
				
			||||||
	WLR_VK_OUTPUT_TRANSFORM_LUT3D = 1,
 | 
						WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 1,
 | 
				
			||||||
 | 
						WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ = 2,
 | 
				
			||||||
 | 
						WLR_VK_OUTPUT_TRANSFORM_LUT3D = 3,
 | 
				
			||||||
 | 
						WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22 = 4,
 | 
				
			||||||
 | 
						WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886 = 5,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_vk_pipeline_key {
 | 
					struct wlr_vk_pipeline_key {
 | 
				
			||||||
| 
						 | 
					@ -190,13 +199,24 @@ struct wlr_vk_render_format_setup {
 | 
				
			||||||
	bool use_blending_buffer;
 | 
						bool use_blending_buffer;
 | 
				
			||||||
	VkRenderPass render_pass;
 | 
						VkRenderPass render_pass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						VkPipeline output_pipe_identity;
 | 
				
			||||||
	VkPipeline output_pipe_srgb;
 | 
						VkPipeline output_pipe_srgb;
 | 
				
			||||||
 | 
						VkPipeline output_pipe_pq;
 | 
				
			||||||
	VkPipeline output_pipe_lut3d;
 | 
						VkPipeline output_pipe_lut3d;
 | 
				
			||||||
 | 
						VkPipeline output_pipe_gamma22;
 | 
				
			||||||
 | 
						VkPipeline output_pipe_bt1886;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_vk_renderer *renderer;
 | 
						struct wlr_vk_renderer *renderer;
 | 
				
			||||||
	struct wl_list pipelines; // struct wlr_vk_pipeline.link
 | 
						struct wl_list pipelines; // struct wlr_vk_pipeline.link
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Final output framebuffer and image view
 | 
				
			||||||
 | 
					struct wlr_vk_render_buffer_out {
 | 
				
			||||||
 | 
						VkImageView image_view;
 | 
				
			||||||
 | 
						VkFramebuffer framebuffer;
 | 
				
			||||||
 | 
						bool transitioned;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Renderer-internal represenation of an wlr_buffer imported for rendering.
 | 
					// Renderer-internal represenation of an wlr_buffer imported for rendering.
 | 
				
			||||||
struct wlr_vk_render_buffer {
 | 
					struct wlr_vk_render_buffer {
 | 
				
			||||||
	struct wlr_buffer *wlr_buffer;
 | 
						struct wlr_buffer *wlr_buffer;
 | 
				
			||||||
| 
						 | 
					@ -208,36 +228,40 @@ struct wlr_vk_render_buffer {
 | 
				
			||||||
	uint32_t mem_count;
 | 
						uint32_t mem_count;
 | 
				
			||||||
	VkImage image;
 | 
						VkImage image;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Framebuffer and image view for rendering directly onto the buffer image,
 | 
				
			||||||
 | 
						// without any color transform.
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wlr_vk_render_buffer_out out;
 | 
				
			||||||
 | 
							struct wlr_vk_render_format_setup *render_setup;
 | 
				
			||||||
 | 
						} linear;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Framebuffer and image view for rendering directly onto the buffer image.
 | 
						// Framebuffer and image view for rendering directly onto the buffer image.
 | 
				
			||||||
	// This requires that the image support an _SRGB VkFormat, and does
 | 
						// This requires that the image support an _SRGB VkFormat, and does
 | 
				
			||||||
	// not work with color transforms.
 | 
						// not work with color transforms.
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
 | 
							struct wlr_vk_render_buffer_out out;
 | 
				
			||||||
		struct wlr_vk_render_format_setup *render_setup;
 | 
							struct wlr_vk_render_format_setup *render_setup;
 | 
				
			||||||
		VkImageView image_view;
 | 
					 | 
				
			||||||
		VkFramebuffer framebuffer;
 | 
					 | 
				
			||||||
		bool transitioned;
 | 
					 | 
				
			||||||
	} srgb;
 | 
						} srgb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Framebuffer, image view, and blending image to render indirectly
 | 
						// Framebuffer, image view, and blending image to render indirectly
 | 
				
			||||||
	// onto the buffer image. This works for general image types and permits
 | 
						// onto the buffer image. This works for general image types and permits
 | 
				
			||||||
	// color transforms.
 | 
						// color transforms.
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
 | 
							struct wlr_vk_render_buffer_out out;
 | 
				
			||||||
		struct wlr_vk_render_format_setup *render_setup;
 | 
							struct wlr_vk_render_format_setup *render_setup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		VkImageView image_view;
 | 
					 | 
				
			||||||
		VkFramebuffer framebuffer;
 | 
					 | 
				
			||||||
		bool transitioned;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		VkImage blend_image;
 | 
							VkImage blend_image;
 | 
				
			||||||
		VkImageView blend_image_view;
 | 
							VkImageView blend_image_view;
 | 
				
			||||||
		VkDeviceMemory blend_memory;
 | 
							VkDeviceMemory blend_memory;
 | 
				
			||||||
		VkDescriptorSet blend_descriptor_set;
 | 
							VkDescriptorSet blend_descriptor_set;
 | 
				
			||||||
		struct wlr_vk_descriptor_pool *blend_attachment_pool;
 | 
							struct wlr_vk_descriptor_pool *blend_attachment_pool;
 | 
				
			||||||
		bool blend_transitioned;
 | 
							bool blend_transitioned;
 | 
				
			||||||
	} plain;
 | 
						} two_pass;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
					bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
				
			||||||
 | 
						const struct wlr_dmabuf_attributes *dmabuf, bool srgb);
 | 
				
			||||||
 | 
					bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
				
			||||||
	const struct wlr_dmabuf_attributes *dmabuf);
 | 
						const struct wlr_dmabuf_attributes *dmabuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_vk_command_buffer {
 | 
					struct wlr_vk_command_buffer {
 | 
				
			||||||
| 
						 | 
					@ -253,6 +277,8 @@ struct wlr_vk_command_buffer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// For DMA-BUF implicit sync interop, may be NULL
 | 
						// For DMA-BUF implicit sync interop, may be NULL
 | 
				
			||||||
	VkSemaphore binary_semaphore;
 | 
						VkSemaphore binary_semaphore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_array wait_semaphores; // VkSemaphore
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VULKAN_COMMAND_BUFFERS_CAP 64
 | 
					#define VULKAN_COMMAND_BUFFERS_CAP 64
 | 
				
			||||||
| 
						 | 
					@ -331,7 +357,15 @@ struct wlr_vk_vert_pcr_data {
 | 
				
			||||||
	float uv_size[2];
 | 
						float uv_size[2];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_vk_frag_texture_pcr_data {
 | 
				
			||||||
 | 
						float matrix[4][4]; // only a 3x3 subset is used
 | 
				
			||||||
 | 
						float alpha;
 | 
				
			||||||
 | 
						float luminance_multiplier;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_vk_frag_output_pcr_data {
 | 
					struct wlr_vk_frag_output_pcr_data {
 | 
				
			||||||
 | 
						float matrix[4][4]; // only a 3x3 subset is used
 | 
				
			||||||
 | 
						float luminance_multiplier;
 | 
				
			||||||
	float lut_3d_offset;
 | 
						float lut_3d_offset;
 | 
				
			||||||
	float lut_3d_scale;
 | 
						float lut_3d_scale;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -339,6 +373,7 @@ struct wlr_vk_frag_output_pcr_data {
 | 
				
			||||||
struct wlr_vk_texture_view {
 | 
					struct wlr_vk_texture_view {
 | 
				
			||||||
	struct wl_list link; // struct wlr_vk_texture.views
 | 
						struct wl_list link; // struct wlr_vk_texture.views
 | 
				
			||||||
	const struct wlr_vk_pipeline_layout *layout;
 | 
						const struct wlr_vk_pipeline_layout *layout;
 | 
				
			||||||
 | 
						bool srgb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	VkDescriptorSet ds;
 | 
						VkDescriptorSet ds;
 | 
				
			||||||
	VkImageView image_view;
 | 
						VkImageView image_view;
 | 
				
			||||||
| 
						 | 
					@ -353,7 +388,7 @@ struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout(
 | 
				
			||||||
	const struct wlr_vk_pipeline_layout_key *key);
 | 
						const struct wlr_vk_pipeline_layout_key *key);
 | 
				
			||||||
struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(
 | 
					struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(
 | 
				
			||||||
	struct wlr_vk_texture *texture,
 | 
						struct wlr_vk_texture *texture,
 | 
				
			||||||
	const struct wlr_vk_pipeline_layout *layout);
 | 
						const struct wlr_vk_pipeline_layout *layout, bool srgb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Creates a vulkan renderer for the given device.
 | 
					// Creates a vulkan renderer for the given device.
 | 
				
			||||||
struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev);
 | 
					struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev);
 | 
				
			||||||
| 
						 | 
					@ -367,17 +402,34 @@ VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer);
 | 
				
			||||||
// finished execution.
 | 
					// finished execution.
 | 
				
			||||||
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer);
 | 
					bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_vk_render_pass_texture {
 | 
				
			||||||
 | 
						struct wlr_vk_texture *texture;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *wait_timeline;
 | 
				
			||||||
 | 
						uint64_t wait_point;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_vk_render_pass {
 | 
					struct wlr_vk_render_pass {
 | 
				
			||||||
	struct wlr_render_pass base;
 | 
						struct wlr_render_pass base;
 | 
				
			||||||
	struct wlr_vk_renderer *renderer;
 | 
						struct wlr_vk_renderer *renderer;
 | 
				
			||||||
	struct wlr_vk_render_buffer *render_buffer;
 | 
						struct wlr_vk_render_buffer *render_buffer;
 | 
				
			||||||
 | 
						struct wlr_vk_render_buffer_out *render_buffer_out;
 | 
				
			||||||
 | 
						struct wlr_vk_render_format_setup *render_setup;
 | 
				
			||||||
	struct wlr_vk_command_buffer *command_buffer;
 | 
						struct wlr_vk_command_buffer *command_buffer;
 | 
				
			||||||
	struct rect_union updated_region;
 | 
						struct rect_union updated_region;
 | 
				
			||||||
	VkPipeline bound_pipeline;
 | 
						VkPipeline bound_pipeline;
 | 
				
			||||||
	float projection[9];
 | 
						float projection[9];
 | 
				
			||||||
	bool failed;
 | 
						bool failed;
 | 
				
			||||||
	bool srgb_pathway; // if false, rendering via intermediate blending buffer
 | 
						bool two_pass; // rendering via intermediate blending buffer
 | 
				
			||||||
	struct wlr_color_transform *color_transform;
 | 
						struct wlr_color_transform *color_transform;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_primaries;
 | 
				
			||||||
 | 
						struct wlr_color_primaries primaries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *signal_timeline;
 | 
				
			||||||
 | 
						uint64_t signal_point;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wl_array textures; // struct wlr_vk_render_pass_texture
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *renderer,
 | 
					struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *renderer,
 | 
				
			||||||
| 
						 | 
					@ -419,8 +471,10 @@ bool vulkan_wait_command_buffer(struct wlr_vk_command_buffer *cb,
 | 
				
			||||||
	struct wlr_vk_renderer *renderer);
 | 
						struct wlr_vk_renderer *renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool vulkan_sync_render_buffer(struct wlr_vk_renderer *renderer,
 | 
					bool vulkan_sync_render_buffer(struct wlr_vk_renderer *renderer,
 | 
				
			||||||
	struct wlr_vk_render_buffer *render_buffer, struct wlr_vk_command_buffer *cb);
 | 
						struct wlr_vk_render_buffer *render_buffer, struct wlr_vk_command_buffer *cb,
 | 
				
			||||||
bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture);
 | 
						struct wlr_drm_syncobj_timeline *signal_timeline, uint64_t signal_point);
 | 
				
			||||||
 | 
					bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture,
 | 
				
			||||||
 | 
						int sync_file_fds[static WLR_DMABUF_MAX_PLANES]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
 | 
					bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
 | 
				
			||||||
	VkFormat src_format, VkImage src_image,
 | 
						VkFormat src_format, VkImage src_image,
 | 
				
			||||||
| 
						 | 
					@ -436,13 +490,12 @@ struct wlr_vk_texture {
 | 
				
			||||||
	VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
 | 
						VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
 | 
				
			||||||
	VkImage image;
 | 
						VkImage image;
 | 
				
			||||||
	const struct wlr_vk_format *format;
 | 
						const struct wlr_vk_format *format;
 | 
				
			||||||
	enum wlr_vk_texture_transform transform;
 | 
					 | 
				
			||||||
	struct wlr_vk_command_buffer *last_used_cb; // to track when it can be destroyed
 | 
						struct wlr_vk_command_buffer *last_used_cb; // to track when it can be destroyed
 | 
				
			||||||
	bool dmabuf_imported;
 | 
						bool dmabuf_imported;
 | 
				
			||||||
	bool owned; // if dmabuf_imported: whether we have ownership of the image
 | 
						bool owned; // if dmabuf_imported: whether we have ownership of the image
 | 
				
			||||||
	bool transitioned; // if dma_imported: whether we transitioned it away from preinit
 | 
						bool transitioned; // if dma_imported: whether we transitioned it away from preinit
 | 
				
			||||||
	bool has_alpha; // whether the image is has alpha channel
 | 
						bool has_alpha; // whether the image is has alpha channel
 | 
				
			||||||
	bool using_mutable_srgb; // is this accessed through _SRGB format view
 | 
						bool using_mutable_srgb; // can be accessed through _SRGB format view
 | 
				
			||||||
	struct wl_list foreign_link; // wlr_vk_renderer.foreign_textures
 | 
						struct wl_list foreign_link; // wlr_vk_renderer.foreign_textures
 | 
				
			||||||
	struct wl_list destroy_link; // wlr_vk_command_buffer.destroy_textures
 | 
						struct wl_list destroy_link; // wlr_vk_command_buffer.destroy_textures
 | 
				
			||||||
	struct wl_list link; // wlr_vk_renderer.textures
 | 
						struct wl_list link; // wlr_vk_renderer.textures
 | 
				
			||||||
| 
						 | 
					@ -450,10 +503,8 @@ struct wlr_vk_texture {
 | 
				
			||||||
	// If imported from a wlr_buffer
 | 
						// If imported from a wlr_buffer
 | 
				
			||||||
	struct wlr_buffer *buffer;
 | 
						struct wlr_buffer *buffer;
 | 
				
			||||||
	struct wlr_addon buffer_addon;
 | 
						struct wlr_addon buffer_addon;
 | 
				
			||||||
	// For DMA-BUF implicit sync interop
 | 
					 | 
				
			||||||
	VkSemaphore foreign_semaphores[WLR_DMABUF_MAX_PLANES];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list views; // struct wlr_vk_texture_ds.link
 | 
						struct wl_list views; // struct wlr_vk_texture_view.link
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture);
 | 
					struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture);
 | 
				
			||||||
| 
						 | 
					@ -485,6 +536,7 @@ struct wlr_vk_shared_buffer {
 | 
				
			||||||
	VkDeviceSize buf_size;
 | 
						VkDeviceSize buf_size;
 | 
				
			||||||
	void *cpu_mapping;
 | 
						void *cpu_mapping;
 | 
				
			||||||
	struct wl_array allocs; // struct wlr_vk_allocation
 | 
						struct wl_array allocs; // struct wlr_vk_allocation
 | 
				
			||||||
 | 
						int64_t last_used_ms;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Suballocated range on a buffer.
 | 
					// Suballocated range on a buffer.
 | 
				
			||||||
| 
						 | 
					@ -500,6 +552,7 @@ struct wlr_vk_color_transform {
 | 
				
			||||||
	struct wl_list link; // wlr_vk_renderer, list of all color transforms
 | 
						struct wl_list link; // wlr_vk_renderer, list of all color transforms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
 | 
							size_t dim;
 | 
				
			||||||
		VkImage image;
 | 
							VkImage image;
 | 
				
			||||||
		VkImageView image_view;
 | 
							VkImageView image_view;
 | 
				
			||||||
		VkDeviceMemory memory;
 | 
							VkDeviceMemory memory;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@
 | 
				
			||||||
struct wlr_renderer *renderer_autocreate_with_drm_fd(int drm_fd);
 | 
					struct wlr_renderer *renderer_autocreate_with_drm_fd(int drm_fd);
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Get the supported render formats. Buffers allocated with a format from this
 | 
					 * Get the supported render formats. Buffers allocated with a format from this
 | 
				
			||||||
 * list may be attached via wlr_renderer_begin_with_buffer.
 | 
					 * list may be used with wlr_renderer_begin_buffer_pass().
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const struct wlr_drm_format_set *wlr_renderer_get_render_formats(
 | 
					const struct wlr_drm_format_set *wlr_renderer_get_render_formats(
 | 
				
			||||||
	struct wlr_renderer *renderer);
 | 
						struct wlr_renderer *renderer);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,15 +50,6 @@ struct wlr_dmabuf_buffer *dmabuf_buffer_create(
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool dmabuf_buffer_drop(struct wlr_dmabuf_buffer *buffer);
 | 
					bool dmabuf_buffer_drop(struct wlr_dmabuf_buffer *buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Check whether a buffer is fully opaque.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * When true is returned, the buffer is guaranteed to be fully opaque, but the
 | 
					 | 
				
			||||||
 * reverse is not true: false may be returned in cases where the buffer is fully
 | 
					 | 
				
			||||||
 * opaque.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool buffer_is_opaque(struct wlr_buffer *buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Creates a struct wlr_client_buffer from a given struct wlr_buffer by creating
 | 
					 * Creates a struct wlr_client_buffer from a given struct wlr_buffer by creating
 | 
				
			||||||
 * a texture from it, and copying its struct wl_resource.
 | 
					 * a texture from it, and copying its struct wl_resource.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +0,0 @@
 | 
				
			||||||
#ifndef TYPES_WLR_MATRIX_H
 | 
					 | 
				
			||||||
#define TYPES_WLR_MATRIX_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <wlr/types/wlr_matrix.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Writes a 2D orthographic projection matrix to mat of (width, height) with a
 | 
					 | 
				
			||||||
 * specified wl_output_transform.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Equivalent to glOrtho(0, width, 0, height, 1, -1) with the transform applied.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void matrix_projection(float mat[static 9], int width, int height,
 | 
					 | 
				
			||||||
	enum wl_output_transform transform);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,8 @@ void output_pending_resolution(struct wlr_output *output,
 | 
				
			||||||
	const struct wlr_output_state *state, int *width, int *height);
 | 
						const struct wlr_output_state *state, int *width, int *height);
 | 
				
			||||||
bool output_pending_enabled(struct wlr_output *output,
 | 
					bool output_pending_enabled(struct wlr_output *output,
 | 
				
			||||||
	const struct wlr_output_state *state);
 | 
						const struct wlr_output_state *state);
 | 
				
			||||||
 | 
					const struct wlr_output_image_description *output_pending_image_description(
 | 
				
			||||||
 | 
						struct wlr_output *output, const struct wlr_output_state *state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool output_pick_format(struct wlr_output *output,
 | 
					bool output_pick_format(struct wlr_output *output,
 | 
				
			||||||
	const struct wlr_drm_format_set *display_formats,
 | 
						const struct wlr_drm_format_set *display_formats,
 | 
				
			||||||
| 
						 | 
					@ -18,11 +20,18 @@ bool output_ensure_buffer(struct wlr_output *output,
 | 
				
			||||||
bool output_cursor_set_texture(struct wlr_output_cursor *cursor,
 | 
					bool output_cursor_set_texture(struct wlr_output_cursor *cursor,
 | 
				
			||||||
	struct wlr_texture *texture, bool own_texture, const struct wlr_fbox *src_box,
 | 
						struct wlr_texture *texture, bool own_texture, const struct wlr_fbox *src_box,
 | 
				
			||||||
	int dst_width, int dst_height, enum wl_output_transform transform,
 | 
						int dst_width, int dst_height, enum wl_output_transform transform,
 | 
				
			||||||
	int32_t hotspot_x, int32_t hotspot_y);
 | 
						int32_t hotspot_x, int32_t hotspot_y, struct wlr_drm_syncobj_timeline *wait_timeline,
 | 
				
			||||||
 | 
						uint64_t wait_point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_defer_present(struct wlr_output *output, struct wlr_output_event_present event);
 | 
					void output_defer_present(struct wlr_output *output, struct wlr_output_event_present event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool output_prepare_commit(struct wlr_output *output, const struct wlr_output_state *state);
 | 
					bool output_prepare_commit(struct wlr_output *output, const struct wlr_output_state *state);
 | 
				
			||||||
void output_apply_commit(struct wlr_output *output, const struct wlr_output_state *state);
 | 
					void output_apply_commit(struct wlr_output *output, const struct wlr_output_state *state);
 | 
				
			||||||
 | 
					void output_send_commit_event(struct wlr_output *output, const struct wlr_output_state *state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void output_state_get_buffer_src_box(const struct wlr_output_state *state,
 | 
				
			||||||
 | 
						struct wlr_fbox *out);
 | 
				
			||||||
 | 
					void output_state_get_buffer_dst_box(const struct wlr_output_state *state,
 | 
				
			||||||
 | 
						struct wlr_box *out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
#ifndef TYPES_WLR_REGION_H
 | 
					#ifndef TYPES_WLR_REGION_H
 | 
				
			||||||
#define TYPES_WLR_REGION_H
 | 
					#define TYPES_WLR_REGION_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wlr/types/wlr_region.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wl_client;
 | 
					struct wl_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
 | 
					struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void scene_node_get_size(struct wlr_scene_node *node, int *width, int *height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void scene_surface_set_clip(struct wlr_scene_surface *surface, struct wlr_box *clip);
 | 
					void scene_surface_set_clip(struct wlr_scene_surface *surface, struct wlr_box *clip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,5 @@
 | 
				
			||||||
/*
 | 
					#ifndef UTIL_MATRIX_H
 | 
				
			||||||
 * This is a deprecated interface of wlroots. It will be removed in a future
 | 
					#define UTIL_MATRIX_H
 | 
				
			||||||
 * version.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef WLR_TYPES_WLR_MATRIX_H
 | 
					 | 
				
			||||||
#define WLR_TYPES_WLR_MATRIX_H
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wayland-server-protocol.h>
 | 
					#include <wayland-server-protocol.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,17 +12,12 @@ void wlr_matrix_identity(float mat[static 9]);
 | 
				
			||||||
void wlr_matrix_multiply(float mat[static 9], const float a[static 9],
 | 
					void wlr_matrix_multiply(float mat[static 9], const float a[static 9],
 | 
				
			||||||
	const float b[static 9]);
 | 
						const float b[static 9]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_matrix_transpose(float mat[static 9], const float a[static 9]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Writes a 2D translation matrix to mat of magnitude (x, y) */
 | 
					/** Writes a 2D translation matrix to mat of magnitude (x, y) */
 | 
				
			||||||
void wlr_matrix_translate(float mat[static 9], float x, float y);
 | 
					void wlr_matrix_translate(float mat[static 9], float x, float y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Writes a 2D scale matrix to mat of magnitude (x, y) */
 | 
					/** Writes a 2D scale matrix to mat of magnitude (x, y) */
 | 
				
			||||||
void wlr_matrix_scale(float mat[static 9], float x, float y);
 | 
					void wlr_matrix_scale(float mat[static 9], float x, float y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Writes a 2D rotation matrix to mat at an angle of rad radians */
 | 
					 | 
				
			||||||
void wlr_matrix_rotate(float mat[static 9], float rad);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Writes a transformation matrix which applies the specified
 | 
					/** Writes a transformation matrix which applies the specified
 | 
				
			||||||
 *  wl_output_transform to mat */
 | 
					 *  wl_output_transform to mat */
 | 
				
			||||||
void wlr_matrix_transform(float mat[static 9],
 | 
					void wlr_matrix_transform(float mat[static 9],
 | 
				
			||||||
| 
						 | 
					@ -38,7 +28,22 @@ void wlr_matrix_transform(float mat[static 9],
 | 
				
			||||||
 *  rotation. The result is written to mat, which can be applied to each
 | 
					 *  rotation. The result is written to mat, which can be applied to each
 | 
				
			||||||
 *  coordinate of the box to get a new coordinate from [-1,1]. */
 | 
					 *  coordinate of the box to get a new coordinate from [-1,1]. */
 | 
				
			||||||
void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box,
 | 
					void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box,
 | 
				
			||||||
	enum wl_output_transform transform, float rotation,
 | 
						enum wl_output_transform transform, const float projection[static 9]);
 | 
				
			||||||
	const float projection[static 9]);
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Writes a 2D orthographic projection matrix to mat of (width, height) with a
 | 
				
			||||||
 | 
					 * specified wl_output_transform.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Equivalent to glOrtho(0, width, 0, height, 1, -1) with the transform applied.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void matrix_projection(float mat[static 9], int width, int height,
 | 
				
			||||||
 | 
						enum wl_output_transform transform);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Compute the inverse of a matrix.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The matrix needs to be inversible.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void matrix_invert(float out[static 9], float m[static 9]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										14
									
								
								include/util/mem.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								include/util/mem.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					#ifndef UTIL_MEM_H
 | 
				
			||||||
 | 
					#define UTIL_MEM_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Allocate a new block of memory and copy *src to it, then store the address
 | 
				
			||||||
 | 
					 * of the new allocation in *out.  Returns true if it worked, or false if
 | 
				
			||||||
 | 
					 * allocation failed.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool memdup(void *out, const void *src, size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // UTIL_MEM_H
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,8 @@
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const long NSEC_PER_SEC = 1000000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Get the current time, in milliseconds.
 | 
					 * Get the current time, in milliseconds.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,10 +25,21 @@ struct wlr_backend_output_state {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A backend provides a set of input and output devices.
 | 
					 * A backend provides a set of input and output devices.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Buffer capabilities and features can change over the lifetime of a backend,
 | 
				
			||||||
 | 
					 * for instance when a child backend is added to a multi-backend.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct wlr_backend {
 | 
					struct wlr_backend {
 | 
				
			||||||
	const struct wlr_backend_impl *impl;
 | 
						const struct wlr_backend_impl *impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Bitfield of supported buffer capabilities (see enum wlr_buffer_cap)
 | 
				
			||||||
 | 
						uint32_t buffer_caps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							// Whether wait/signal timelines are supported in output commits
 | 
				
			||||||
 | 
							bool timeline;
 | 
				
			||||||
 | 
						} features;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		/** Raised when destroyed */
 | 
							/** Raised when destroyed */
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
| 
						 | 
					@ -54,13 +65,12 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_event_loop *loop,
 | 
				
			||||||
	struct wlr_session **session_ptr);
 | 
						struct wlr_session **session_ptr);
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Start the backend. This may signal new_input or new_output immediately, but
 | 
					 * Start the backend. This may signal new_input or new_output immediately, but
 | 
				
			||||||
 * may also wait until the display's event loop begins. Returns false on
 | 
					 * may also wait until the event loop is started. Returns false on failure.
 | 
				
			||||||
 * failure.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool wlr_backend_start(struct wlr_backend *backend);
 | 
					bool wlr_backend_start(struct wlr_backend *backend);
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Destroy the backend and clean up all of its resources. Normally called
 | 
					 * Destroy the backend and clean up all of its resources. Normally called
 | 
				
			||||||
 * automatically when the struct wl_display is destroyed.
 | 
					 * automatically when the event loop is destroyed.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void wlr_backend_destroy(struct wlr_backend *backend);
 | 
					void wlr_backend_destroy(struct wlr_backend *backend);
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,6 @@ struct wlr_backend_impl {
 | 
				
			||||||
	bool (*start)(struct wlr_backend *backend);
 | 
						bool (*start)(struct wlr_backend *backend);
 | 
				
			||||||
	void (*destroy)(struct wlr_backend *backend);
 | 
						void (*destroy)(struct wlr_backend *backend);
 | 
				
			||||||
	int (*get_drm_fd)(struct wlr_backend *backend);
 | 
						int (*get_drm_fd)(struct wlr_backend *backend);
 | 
				
			||||||
	uint32_t (*get_buffer_caps)(struct wlr_backend *backend);
 | 
					 | 
				
			||||||
	bool (*test)(struct wlr_backend *backend,
 | 
						bool (*test)(struct wlr_backend *backend,
 | 
				
			||||||
		const struct wlr_backend_output_state *states, size_t states_len);
 | 
							const struct wlr_backend_output_state *states, size_t states_len);
 | 
				
			||||||
	bool (*commit)(struct wlr_backend *backend,
 | 
						bool (*commit)(struct wlr_backend *backend,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,11 +43,6 @@ struct wlr_session {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	bool active;
 | 
						bool active;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * 0 if virtual terminals are not supported
 | 
					 | 
				
			||||||
	 * i.e. seat != "seat0"
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	unsigned vtnr;
 | 
					 | 
				
			||||||
	char seat[256];
 | 
						char seat[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct udev *udev;
 | 
						struct udev *udev;
 | 
				
			||||||
| 
						 | 
					@ -60,13 +55,16 @@ struct wlr_session {
 | 
				
			||||||
	struct wl_list devices; // wlr_device.link
 | 
						struct wl_list devices; // wlr_device.link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_event_loop *event_loop;
 | 
						struct wl_event_loop *event_loop;
 | 
				
			||||||
	struct wl_listener event_loop_destroy;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal active;
 | 
							struct wl_signal active;
 | 
				
			||||||
		struct wl_signal add_drm_card; // struct wlr_session_add_event
 | 
							struct wl_signal add_drm_card; // struct wlr_session_add_event
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener event_loop_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_session_add_event {
 | 
					struct wlr_session_add_event {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,19 +1,76 @@
 | 
				
			||||||
#ifndef WLR_CONFIG_H
 | 
					#ifndef WLR_CONFIG_H
 | 
				
			||||||
#define WLR_CONFIG_H
 | 
					#define WLR_CONFIG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Whether the DRM backend is compile-time enabled. Equivalent to the
 | 
				
			||||||
 | 
					 * pkg-config "have_drm_backend" variable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Required for <wlr/backend/drm.h>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#mesondefine WLR_HAS_DRM_BACKEND
 | 
					#mesondefine WLR_HAS_DRM_BACKEND
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Whether the libinput backend is compile-time enabled. Equivalent to the
 | 
				
			||||||
 | 
					 * pkg-config "have_libinput_backend" vartiable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Required for <wlr/backend/libinput.h>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#mesondefine WLR_HAS_LIBINPUT_BACKEND
 | 
					#mesondefine WLR_HAS_LIBINPUT_BACKEND
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Whether the X11 backend is compile-time enabled. Equivalent to the
 | 
				
			||||||
 | 
					 * pkg-config "have_x11_backend" variable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Required for <wlr/backend/x11.h>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#mesondefine WLR_HAS_X11_BACKEND
 | 
					#mesondefine WLR_HAS_X11_BACKEND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Whether the GLES2 renderer is compile-time enabled. Equivalent to the
 | 
				
			||||||
 | 
					 * pkg-config "have_gles2_renderer" variable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Required for <wlr/render/gles2.h>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#mesondefine WLR_HAS_GLES2_RENDERER
 | 
					#mesondefine WLR_HAS_GLES2_RENDERER
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Whether the Vulkan renderer is compile-time enabled. Equivalent to the
 | 
				
			||||||
 | 
					 * pkg-config "have_vulkan_renderer" variable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Required for <wlr/render/vulkan.h>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#mesondefine WLR_HAS_VULKAN_RENDERER
 | 
					#mesondefine WLR_HAS_VULKAN_RENDERER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Whether the GBM allocator is compile-time enabled. Equivalent to the
 | 
				
			||||||
 | 
					 * pkg-config "have_gbm_allocator" variable.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#mesondefine WLR_HAS_GBM_ALLOCATOR
 | 
					#mesondefine WLR_HAS_GBM_ALLOCATOR
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Whether the udmabuf allocator is compile-time enabled. Equivalent to the
 | 
				
			||||||
 | 
					 * pkg-config "have_udmabuf_allocator" variable.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#mesondefine WLR_HAS_UDMABUF_ALLOCATOR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Whether Xwayland support is compile-time enabled. Equivalent to the
 | 
				
			||||||
 | 
					 * pkg-config "have_xwayland" variable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Required for <wlr/xwayland/…>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#mesondefine WLR_HAS_XWAYLAND
 | 
					#mesondefine WLR_HAS_XWAYLAND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Whether session support is compile-time enabled. Equivalent to the
 | 
				
			||||||
 | 
					 * pkg-config "have_session" variable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Required for <wlr/backend/session.h>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#mesondefine WLR_HAS_SESSION
 | 
					#mesondefine WLR_HAS_SESSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Whether traditional color management support is compile-time enabled.
 | 
				
			||||||
 | 
					 * Equivalent to the pkg-config "have_color_management" variable.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Required for ICC profile support in <wlr/render/color.h>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
#mesondefine WLR_HAS_COLOR_MANAGEMENT
 | 
					#mesondefine WLR_HAS_COLOR_MANAGEMENT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,11 @@ struct wlr_buffer_resource_interface {
 | 
				
			||||||
void wlr_buffer_init(struct wlr_buffer *buffer,
 | 
					void wlr_buffer_init(struct wlr_buffer *buffer,
 | 
				
			||||||
	const struct wlr_buffer_impl *impl, int width, int height);
 | 
						const struct wlr_buffer_impl *impl, int width, int height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Emit the destroy event and clean up common buffer state.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_buffer_finish(struct wlr_buffer *buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Allows the registration of a struct wl_resource implementation.
 | 
					 * Allows the registration of a struct wl_resource implementation.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										45
									
								
								include/wlr/interfaces/wlr_ext_image_capture_source_v1.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								include/wlr/interfaces/wlr_ext_image_capture_source_v1.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,45 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This an unstable interface of wlroots. No guarantees are made regarding the
 | 
				
			||||||
 | 
					 * future consistency of this API.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef WLR_USE_UNSTABLE
 | 
				
			||||||
 | 
					#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef WLR_INTERFACES_WLR_EXT_IMAGE_CAPTURE_SOURCE_V1_H
 | 
				
			||||||
 | 
					#define WLR_INTERFACES_WLR_EXT_IMAGE_CAPTURE_SOURCE_V1_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_ext_image_capture_source_v1.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_ext_image_copy_capture_frame_v1;
 | 
				
			||||||
 | 
					struct wlr_swapchain;
 | 
				
			||||||
 | 
					struct wlr_renderer;
 | 
				
			||||||
 | 
					struct wlr_seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_ext_image_capture_source_v1_interface {
 | 
				
			||||||
 | 
						// TODO: drop with_cursors flag
 | 
				
			||||||
 | 
						void (*start)(struct wlr_ext_image_capture_source_v1 *source, bool with_cursors);
 | 
				
			||||||
 | 
						void (*stop)(struct wlr_ext_image_capture_source_v1 *source);
 | 
				
			||||||
 | 
						void (*schedule_frame)(struct wlr_ext_image_capture_source_v1 *source);
 | 
				
			||||||
 | 
						void (*copy_frame)(struct wlr_ext_image_capture_source_v1 *source,
 | 
				
			||||||
 | 
							struct wlr_ext_image_copy_capture_frame_v1 *dst_frame,
 | 
				
			||||||
 | 
							struct wlr_ext_image_capture_source_v1_frame_event *frame_event);
 | 
				
			||||||
 | 
						struct wlr_ext_image_capture_source_v1_cursor *(*get_pointer_cursor)(
 | 
				
			||||||
 | 
							struct wlr_ext_image_capture_source_v1 *source, struct wlr_seat *seat);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_ext_image_capture_source_v1_init(struct wlr_ext_image_capture_source_v1 *source,
 | 
				
			||||||
 | 
							const struct wlr_ext_image_capture_source_v1_interface *impl);
 | 
				
			||||||
 | 
					void wlr_ext_image_capture_source_v1_finish(struct wlr_ext_image_capture_source_v1 *source);
 | 
				
			||||||
 | 
					bool wlr_ext_image_capture_source_v1_create_resource(struct wlr_ext_image_capture_source_v1 *source,
 | 
				
			||||||
 | 
						struct wl_client *client, uint32_t new_id);
 | 
				
			||||||
 | 
					bool wlr_ext_image_capture_source_v1_set_constraints_from_swapchain(
 | 
				
			||||||
 | 
						struct wlr_ext_image_capture_source_v1 *source,
 | 
				
			||||||
 | 
						struct wlr_swapchain *swapchain, struct wlr_renderer *renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_ext_image_capture_source_v1_cursor_init(struct wlr_ext_image_capture_source_v1_cursor *source_cursor,
 | 
				
			||||||
 | 
							const struct wlr_ext_image_capture_source_v1_interface *impl);
 | 
				
			||||||
 | 
					void wlr_ext_image_capture_source_v1_cursor_finish(struct wlr_ext_image_capture_source_v1_cursor *source_cursor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -108,6 +108,10 @@ struct wlr_output_impl {
 | 
				
			||||||
void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend,
 | 
					void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend,
 | 
				
			||||||
	const struct wlr_output_impl *impl, struct wl_event_loop *event_loop,
 | 
						const struct wlr_output_impl *impl, struct wl_event_loop *event_loop,
 | 
				
			||||||
	const struct wlr_output_state *state);
 | 
						const struct wlr_output_state *state);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Emit the destroy event and clean up common output state.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_output_finish(struct wlr_output *output);
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Notify compositors that they need to submit a new frame in order to apply
 | 
					 * Notify compositors that they need to submit a new frame in order to apply
 | 
				
			||||||
 * output changes.
 | 
					 * output changes.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,4 +19,7 @@ void wlr_pointer_init(struct wlr_pointer *pointer,
 | 
				
			||||||
		const struct wlr_pointer_impl *impl, const char *name);
 | 
							const struct wlr_pointer_impl *impl, const char *name);
 | 
				
			||||||
void wlr_pointer_finish(struct wlr_pointer *pointer);
 | 
					void wlr_pointer_finish(struct wlr_pointer *pointer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_pointer_notify_button(struct wlr_pointer *pointer,
 | 
				
			||||||
 | 
							struct wlr_pointer_button_event *event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,8 +10,100 @@
 | 
				
			||||||
#define WLR_RENDER_COLOR_H
 | 
					#define WLR_RENDER_COLOR_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Well-known color primaries.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum wlr_color_named_primaries {
 | 
				
			||||||
 | 
						WLR_COLOR_NAMED_PRIMARIES_SRGB = 1 << 0,
 | 
				
			||||||
 | 
						WLR_COLOR_NAMED_PRIMARIES_BT2020 = 1 << 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Well-known color transfer functions.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum wlr_color_transfer_function {
 | 
				
			||||||
 | 
						WLR_COLOR_TRANSFER_FUNCTION_SRGB = 1 << 0,
 | 
				
			||||||
 | 
						WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1,
 | 
				
			||||||
 | 
						WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2,
 | 
				
			||||||
 | 
						WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 = 1 << 3,
 | 
				
			||||||
 | 
						WLR_COLOR_TRANSFER_FUNCTION_BT1886 = 1 << 4,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Specifies alpha blending modes.  Note that premultiplied_electrical
 | 
				
			||||||
 | 
					 * is the default, so there is no "none" or "unset" value.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum wlr_alpha_mode {
 | 
				
			||||||
 | 
						WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL,
 | 
				
			||||||
 | 
						WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_OPTICAL,
 | 
				
			||||||
 | 
						WLR_COLOR_ALPHA_MODE_STRAIGHT,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Well-known color encodings, each representing a set of matrix coefficients
 | 
				
			||||||
 | 
					 * used to convert that particular YCbCr encoding to RGB.  NONE means the
 | 
				
			||||||
 | 
					 * value is unset or unknown.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum wlr_color_encoding {
 | 
				
			||||||
 | 
						WLR_COLOR_ENCODING_NONE,
 | 
				
			||||||
 | 
						WLR_COLOR_ENCODING_IDENTITY,
 | 
				
			||||||
 | 
						WLR_COLOR_ENCODING_BT709,
 | 
				
			||||||
 | 
						WLR_COLOR_ENCODING_FCC,
 | 
				
			||||||
 | 
						WLR_COLOR_ENCODING_BT601,
 | 
				
			||||||
 | 
						WLR_COLOR_ENCODING_SMPTE240,
 | 
				
			||||||
 | 
						WLR_COLOR_ENCODING_BT2020,
 | 
				
			||||||
 | 
						WLR_COLOR_ENCODING_BT2020_CL,
 | 
				
			||||||
 | 
						WLR_COLOR_ENCODING_ICTCP,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Specifies whether a particular color-encoding uses full- or limited-range
 | 
				
			||||||
 | 
					 * values.  NONE means the value is unset or unknown.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum wlr_color_range {
 | 
				
			||||||
 | 
						WLR_COLOR_RANGE_NONE,
 | 
				
			||||||
 | 
						WLR_COLOR_RANGE_LIMITED,
 | 
				
			||||||
 | 
						WLR_COLOR_RANGE_FULL,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Chroma sample locations, corresponding to Chroma420SampleLocType code
 | 
				
			||||||
 | 
					 * points in H.273.  NONE means the value is unset or unknown.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum wlr_color_chroma_location {
 | 
				
			||||||
 | 
						WLR_COLOR_CHROMA_LOCATION_NONE,
 | 
				
			||||||
 | 
						WLR_COLOR_CHROMA_LOCATION_TYPE0,
 | 
				
			||||||
 | 
						WLR_COLOR_CHROMA_LOCATION_TYPE1,
 | 
				
			||||||
 | 
						WLR_COLOR_CHROMA_LOCATION_TYPE2,
 | 
				
			||||||
 | 
						WLR_COLOR_CHROMA_LOCATION_TYPE3,
 | 
				
			||||||
 | 
						WLR_COLOR_CHROMA_LOCATION_TYPE4,
 | 
				
			||||||
 | 
						WLR_COLOR_CHROMA_LOCATION_TYPE5,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * CIE 1931 xy chromaticity coordinates.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_color_cie1931_xy {
 | 
				
			||||||
 | 
						float x, y;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Color primaries and white point describing a color volume.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_color_primaries {
 | 
				
			||||||
 | 
						struct wlr_color_cie1931_xy red, green, blue, white;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Luminance range and reference white luminance level, in cd/m².
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_color_luminances {
 | 
				
			||||||
 | 
						float min, max, reference;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A color transformation formula, which maps a linear color space with
 | 
					 * A color transformation formula, which maps a linear color space with
 | 
				
			||||||
 * sRGB primaries to an output color space.
 | 
					 * sRGB primaries to an output color space.
 | 
				
			||||||
| 
						 | 
					@ -36,15 +128,30 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
 | 
				
			||||||
	const void *data, size_t size);
 | 
						const void *data, size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Initialize a color transformation to apply sRGB encoding.
 | 
					 * Initialize a color transformation to apply EOTF⁻¹ encoding. Returns
 | 
				
			||||||
 * Returns NULL on failure.
 | 
					 * NULL on failure.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct wlr_color_transform *wlr_color_transform_init_srgb(void);
 | 
					struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
 | 
				
			||||||
 | 
						enum wlr_color_transfer_function tf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize a color transformation to apply three 1D look-up tables. dim
 | 
				
			||||||
 | 
					 * is the number of elements in each individual LUT. Returns NULL on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
 | 
				
			||||||
 | 
						const uint16_t *r, const uint16_t *g, const uint16_t *b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize a color transformation to apply a sequence of color transforms
 | 
				
			||||||
 | 
					 * one after another.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_color_transform *wlr_color_transform_init_pipeline(
 | 
				
			||||||
 | 
						struct wlr_color_transform **transforms, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Increase the reference count of the color transform by 1.
 | 
					 * Increase the reference count of the color transform by 1.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void wlr_color_transform_ref(struct wlr_color_transform *tr);
 | 
					struct wlr_color_transform *wlr_color_transform_ref(struct wlr_color_transform *tr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Reduce the reference count of the color transform by 1; freeing it and
 | 
					 * Reduce the reference count of the color transform by 1; freeing it and
 | 
				
			||||||
| 
						 | 
					@ -52,4 +159,10 @@ void wlr_color_transform_ref(struct wlr_color_transform *tr);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void wlr_color_transform_unref(struct wlr_color_transform *tr);
 | 
					void wlr_color_transform_unref(struct wlr_color_transform *tr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Evaluate a color transform for a given RGB triplet.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wlr_color_transform_eval(struct wlr_color_transform *tr,
 | 
				
			||||||
 | 
						float out[static 3], const float in[static 3]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,6 +69,9 @@ void wlr_drm_format_set_finish(struct wlr_drm_format_set *set);
 | 
				
			||||||
const struct wlr_drm_format *wlr_drm_format_set_get(
 | 
					const struct wlr_drm_format *wlr_drm_format_set_get(
 | 
				
			||||||
	const struct wlr_drm_format_set *set, uint32_t format);
 | 
						const struct wlr_drm_format_set *set, uint32_t format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool wlr_drm_format_set_remove(struct wlr_drm_format_set *set, uint32_t format,
 | 
				
			||||||
 | 
						uint64_t modifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set,
 | 
					bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set,
 | 
				
			||||||
	uint32_t format, uint64_t modifier);
 | 
						uint32_t format, uint64_t modifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
 | 
					#include <wlr/util/addon.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A synchronization timeline.
 | 
					 * A synchronization timeline.
 | 
				
			||||||
| 
						 | 
					@ -29,20 +30,24 @@ struct wlr_drm_syncobj_timeline {
 | 
				
			||||||
	int drm_fd;
 | 
						int drm_fd;
 | 
				
			||||||
	uint32_t handle;
 | 
						uint32_t handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// private state
 | 
						struct wlr_addon_set addons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t n_refs;
 | 
						struct {
 | 
				
			||||||
 | 
							size_t n_refs;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_drm_syncobj_timeline_waiter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void (*wlr_drm_syncobj_timeline_ready_callback)(
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline_waiter *waiter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_syncobj_timeline_waiter {
 | 
					struct wlr_drm_syncobj_timeline_waiter {
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal ready;
 | 
							int ev_fd;
 | 
				
			||||||
	} events;
 | 
							struct wl_event_source *event_source;
 | 
				
			||||||
 | 
							wlr_drm_syncobj_timeline_ready_callback callback;
 | 
				
			||||||
	// private state
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	int ev_fd;
 | 
					 | 
				
			||||||
	struct wl_event_source *event_source;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -62,6 +67,17 @@ struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_ref(struct wlr_drm_syn
 | 
				
			||||||
 * Unreference a synchronization timeline.
 | 
					 * Unreference a synchronization timeline.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void wlr_drm_syncobj_timeline_unref(struct wlr_drm_syncobj_timeline *timeline);
 | 
					void wlr_drm_syncobj_timeline_unref(struct wlr_drm_syncobj_timeline *timeline);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Export a drm_syncobj FD from a timeline.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int wlr_drm_syncobj_timeline_export(struct wlr_drm_syncobj_timeline *timeline);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Transfer a point from a timeline to another.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Both timelines must have been created with the same DRM FD.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_drm_syncobj_timeline_transfer(struct wlr_drm_syncobj_timeline *dst,
 | 
				
			||||||
 | 
						uint64_t dst_point, struct wlr_drm_syncobj_timeline *src, uint64_t src_point);
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Check if a timeline point has been signalled or has materialized.
 | 
					 * Check if a timeline point has been signalled or has materialized.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -78,10 +94,12 @@ bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
 | 
				
			||||||
 * Asynchronously wait for a timeline point.
 | 
					 * Asynchronously wait for a timeline point.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * See wlr_drm_syncobj_timeline_check() for a definition of flags.
 | 
					 * See wlr_drm_syncobj_timeline_check() for a definition of flags.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * A callback must be provided that will be invoked when the waiter has finished.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter *waiter,
 | 
					bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter *waiter,
 | 
				
			||||||
	struct wlr_drm_syncobj_timeline *timeline, uint64_t point, uint32_t flags,
 | 
						struct wlr_drm_syncobj_timeline *timeline, uint64_t point, uint32_t flags,
 | 
				
			||||||
	struct wl_event_loop *loop);
 | 
						struct wl_event_loop *loop, wlr_drm_syncobj_timeline_ready_callback callback);
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Cancel a timeline waiter.
 | 
					 * Cancel a timeline waiter.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include <pixman.h>
 | 
					#include <pixman.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
 | 
					#include <wlr/render/color.h>
 | 
				
			||||||
#include <wlr/util/box.h>
 | 
					#include <wlr/util/box.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_renderer;
 | 
					struct wlr_renderer;
 | 
				
			||||||
| 
						 | 
					@ -30,9 +31,23 @@ struct wlr_render_timer;
 | 
				
			||||||
struct wlr_buffer_pass_options {
 | 
					struct wlr_buffer_pass_options {
 | 
				
			||||||
	/* Timer to measure the duration of the render pass */
 | 
						/* Timer to measure the duration of the render pass */
 | 
				
			||||||
	struct wlr_render_timer *timer;
 | 
						struct wlr_render_timer *timer;
 | 
				
			||||||
	/* Color transform to apply to the output of the render pass,
 | 
						/* Color transform to apply to the output of the render pass.
 | 
				
			||||||
	 * leave NULL to indicate sRGB/no custom transform */
 | 
						 * Leave NULL to indicate the default transform (Gamma 2.2 encoding for
 | 
				
			||||||
 | 
						 * sRGB monitors) */
 | 
				
			||||||
	struct wlr_color_transform *color_transform;
 | 
						struct wlr_color_transform *color_transform;
 | 
				
			||||||
 | 
						/** Primaries describing the color volume of the destination buffer */
 | 
				
			||||||
 | 
						const struct wlr_color_primaries *primaries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Signal a timeline synchronization point when the render pass completes.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * When a compositor provides a signal timeline, the renderer may skip
 | 
				
			||||||
 | 
						 * implicit signal synchronization.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Support for this feature is advertised by features.timeline in
 | 
				
			||||||
 | 
						 * struct wlr_renderer.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *signal_timeline;
 | 
				
			||||||
 | 
						uint64_t signal_point;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -88,6 +103,21 @@ struct wlr_render_texture_options {
 | 
				
			||||||
	enum wlr_scale_filter_mode filter_mode;
 | 
						enum wlr_scale_filter_mode filter_mode;
 | 
				
			||||||
	/* Blend mode */
 | 
						/* Blend mode */
 | 
				
			||||||
	enum wlr_render_blend_mode blend_mode;
 | 
						enum wlr_render_blend_mode blend_mode;
 | 
				
			||||||
 | 
						/* Transfer function the source texture is encoded with */
 | 
				
			||||||
 | 
						enum wlr_color_transfer_function transfer_function;
 | 
				
			||||||
 | 
						/* Primaries describing the color volume of the source texture */
 | 
				
			||||||
 | 
						const struct wlr_color_primaries *primaries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Wait for a timeline synchronization point before texturing.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * When a compositor provides a wait timeline, the renderer may skip
 | 
				
			||||||
 | 
						 * implicit wait synchronization.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Support for this feature is advertised by features.timeline in
 | 
				
			||||||
 | 
						 * struct wlr_renderer.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct wlr_drm_syncobj_timeline *wait_timeline;
 | 
				
			||||||
 | 
						uint64_t wait_point;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,9 +10,10 @@
 | 
				
			||||||
struct wlr_swapchain_slot {
 | 
					struct wlr_swapchain_slot {
 | 
				
			||||||
	struct wlr_buffer *buffer;
 | 
						struct wlr_buffer *buffer;
 | 
				
			||||||
	bool acquired; // waiting for release
 | 
						bool acquired; // waiting for release
 | 
				
			||||||
	int age;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener release;
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener release;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_swapchain {
 | 
					struct wlr_swapchain {
 | 
				
			||||||
| 
						 | 
					@ -23,7 +24,9 @@ struct wlr_swapchain {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_swapchain_slot slots[WLR_SWAPCHAIN_CAP];
 | 
						struct wlr_swapchain_slot slots[WLR_SWAPCHAIN_CAP];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener allocator_destroy;
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener allocator_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_swapchain *wlr_swapchain_create(
 | 
					struct wlr_swapchain *wlr_swapchain_create(
 | 
				
			||||||
| 
						 | 
					@ -36,21 +39,12 @@ void wlr_swapchain_destroy(struct wlr_swapchain *swapchain);
 | 
				
			||||||
 * The returned buffer is locked. When the caller is done with it, they must
 | 
					 * The returned buffer is locked. When the caller is done with it, they must
 | 
				
			||||||
 * unlock it by calling wlr_buffer_unlock.
 | 
					 * unlock it by calling wlr_buffer_unlock.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain,
 | 
					struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain);
 | 
				
			||||||
	int *age);
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Returns true if this buffer has been created by this swapchain, and false
 | 
					 * Returns true if this buffer has been created by this swapchain, and false
 | 
				
			||||||
 * otherwise.
 | 
					 * otherwise.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool wlr_swapchain_has_buffer(struct wlr_swapchain *swapchain,
 | 
					bool wlr_swapchain_has_buffer(struct wlr_swapchain *swapchain,
 | 
				
			||||||
	struct wlr_buffer *buffer);
 | 
						struct wlr_buffer *buffer);
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Mark the buffer as submitted for presentation. This needs to be called by
 | 
					 | 
				
			||||||
 * swap chain users on frame boundaries.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * If the buffer hasn't been created via the swap chain, the call is ignored.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_swapchain_set_buffer_submitted(struct wlr_swapchain *swapchain,
 | 
					 | 
				
			||||||
	struct wlr_buffer *buffer);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,15 +41,25 @@ struct wlr_renderer {
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Whether color transforms are supported for input textures
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							bool input_color_transform;
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * Does the renderer support color transforms on its output?
 | 
							 * Does the renderer support color transforms on its output?
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		bool output_color_transform;
 | 
							bool output_color_transform;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Whether wait/signal timelines are supported.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * See struct wlr_drm_syncobj_timeline.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							bool timeline;
 | 
				
			||||||
	} features;
 | 
						} features;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// private state
 | 
						struct {
 | 
				
			||||||
 | 
							const struct wlr_renderer_impl *impl;
 | 
				
			||||||
	const struct wlr_renderer_impl *impl;
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,9 +20,9 @@ struct wlr_alpha_modifier_surface_v1_state {
 | 
				
			||||||
struct wlr_alpha_modifier_v1 {
 | 
					struct wlr_alpha_modifier_v1 {
 | 
				
			||||||
	struct wl_global *global;
 | 
						struct wl_global *global;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// private state
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_alpha_modifier_v1 *wlr_alpha_modifier_v1_create(struct wl_display *display);
 | 
					struct wlr_alpha_modifier_v1 *wlr_alpha_modifier_v1_create(struct wl_display *display);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,11 +17,15 @@
 | 
				
			||||||
struct wlr_buffer;
 | 
					struct wlr_buffer;
 | 
				
			||||||
struct wlr_renderer;
 | 
					struct wlr_renderer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Shared-memory attributes for a buffer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_shm_attributes {
 | 
					struct wlr_shm_attributes {
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
	uint32_t format;
 | 
						uint32_t format; // FourCC code, see DRM_FORMAT_* in <drm_fourcc.h>
 | 
				
			||||||
	int width, height, stride;
 | 
						int width, height;
 | 
				
			||||||
	off_t offset;
 | 
						int stride; // Number of bytes between consecutive pixel lines
 | 
				
			||||||
 | 
						off_t offset; // Offset in bytes of the first pixel in FD
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -105,6 +109,15 @@ bool wlr_buffer_get_shm(struct wlr_buffer *buffer,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct wlr_buffer *wlr_buffer_try_from_resource(struct wl_resource *resource);
 | 
					struct wlr_buffer *wlr_buffer_try_from_resource(struct wl_resource *resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Check whether a buffer is fully opaque.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * When true is returned, the buffer is guaranteed to be fully opaque, but the
 | 
				
			||||||
 | 
					 * reverse is not true: false may be returned in cases where the buffer is fully
 | 
				
			||||||
 | 
					 * opaque.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool wlr_buffer_is_opaque(struct wlr_buffer *buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Buffer data pointer access flags.
 | 
					 * Buffer data pointer access flags.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -130,6 +143,12 @@ enum wlr_buffer_data_ptr_access_flag {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool wlr_buffer_begin_data_ptr_access(struct wlr_buffer *buffer, uint32_t flags,
 | 
					bool wlr_buffer_begin_data_ptr_access(struct wlr_buffer *buffer, uint32_t flags,
 | 
				
			||||||
	void **data, uint32_t *format, size_t *stride);
 | 
						void **data, uint32_t *format, size_t *stride);
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Indicate that a pointer to a buffer's underlying memory will no longer be
 | 
				
			||||||
 | 
					 * used.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function must be called after wlr_buffer_begin_data_ptr_access().
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
void wlr_buffer_end_data_ptr_access(struct wlr_buffer *buffer);
 | 
					void wlr_buffer_end_data_ptr_access(struct wlr_buffer *buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -148,12 +167,12 @@ struct wlr_client_buffer {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct wlr_buffer *source;
 | 
						struct wlr_buffer *source;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// private state
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener source_destroy;
 | 
				
			||||||
 | 
							struct wl_listener renderer_destroy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener source_destroy;
 | 
							size_t n_ignore_locks;
 | 
				
			||||||
	struct wl_listener renderer_destroy;
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	size_t n_ignore_locks;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -162,4 +181,29 @@ struct wlr_client_buffer {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer);
 | 
					struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A single-pixel buffer.  Used by clients to draw solid-color rectangles.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_single_pixel_buffer_v1 {
 | 
				
			||||||
 | 
						struct wlr_buffer base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Full-scale for each component is UINT32_MAX
 | 
				
			||||||
 | 
						uint32_t r, g, b, a;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_resource *resource;
 | 
				
			||||||
 | 
							struct wl_listener release;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Packed little-endian DRM_FORMAT_ARGB8888. Used for data_ptr_access
 | 
				
			||||||
 | 
							uint8_t argb8888[4];
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * If the wlr_buffer is a wlr_single_pixel_buffer_v1 then unwrap it.
 | 
				
			||||||
 | 
					 * Otherwise, returns NULL.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wlr_single_pixel_buffer_v1 *wlr_single_pixel_buffer_v1_try_from_buffer(
 | 
				
			||||||
 | 
						struct wlr_buffer *buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										122
									
								
								include/wlr/types/wlr_color_management_v1.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								include/wlr/types/wlr_color_management_v1.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,122 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This an unstable interface of wlroots. No guarantees are made regarding the
 | 
				
			||||||
 | 
					 * future consistency of this API.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef WLR_USE_UNSTABLE
 | 
				
			||||||
 | 
					#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
 | 
				
			||||||
 | 
					#define WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
 | 
					#include <wayland-protocols/color-management-v1-enum.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wlr/render/color.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_image_description_v1_data {
 | 
				
			||||||
 | 
						uint32_t tf_named; // enum wp_color_manager_v1_transfer_function, zero if unset
 | 
				
			||||||
 | 
						uint32_t primaries_named; // enum wp_color_manager_v1_primaries, zero if unset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_mastering_display_primaries;
 | 
				
			||||||
 | 
						struct wlr_color_primaries mastering_display_primaries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool has_mastering_luminance;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							float min, max; // cd/m²
 | 
				
			||||||
 | 
						} mastering_luminance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t max_cll, max_fall; // cd/m², zero if unset
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_color_manager_v1_features {
 | 
				
			||||||
 | 
						bool icc_v2_v4;
 | 
				
			||||||
 | 
						bool parametric;
 | 
				
			||||||
 | 
						bool set_primaries;
 | 
				
			||||||
 | 
						bool set_tf_power;
 | 
				
			||||||
 | 
						bool set_luminances;
 | 
				
			||||||
 | 
						bool set_mastering_display_primaries;
 | 
				
			||||||
 | 
						bool extended_target_volume;
 | 
				
			||||||
 | 
						bool windows_scrgb;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_color_manager_v1_options {
 | 
				
			||||||
 | 
						struct wlr_color_manager_v1_features features;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const enum wp_color_manager_v1_render_intent *render_intents;
 | 
				
			||||||
 | 
						size_t render_intents_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const enum wp_color_manager_v1_transfer_function *transfer_functions;
 | 
				
			||||||
 | 
						size_t transfer_functions_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const enum wp_color_manager_v1_primaries *primaries;
 | 
				
			||||||
 | 
						size_t primaries_len;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_color_manager_v1 {
 | 
				
			||||||
 | 
						struct wl_global *global;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_signal destroy;
 | 
				
			||||||
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wlr_color_manager_v1_features features;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							enum wp_color_manager_v1_render_intent *render_intents;
 | 
				
			||||||
 | 
							size_t render_intents_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							enum wp_color_manager_v1_transfer_function *transfer_functions;
 | 
				
			||||||
 | 
							size_t transfer_functions_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							enum wp_color_manager_v1_primaries *primaries;
 | 
				
			||||||
 | 
							size_t primaries_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct wl_list outputs; // wlr_color_management_output_v1.link
 | 
				
			||||||
 | 
							struct wl_list surface_feedbacks; // wlr_color_management_surface_feedback_v1.link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint32_t last_image_desc_identity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_color_manager_v1 *wlr_color_manager_v1_create(struct wl_display *display,
 | 
				
			||||||
 | 
						uint32_t version, const struct wlr_color_manager_v1_options *options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct wlr_image_description_v1_data *
 | 
				
			||||||
 | 
					wlr_surface_get_image_description_v1_data(struct wlr_surface *surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_color_manager_v1_set_surface_preferred_image_description(
 | 
				
			||||||
 | 
						struct wlr_color_manager_v1 *manager, struct wlr_surface *surface,
 | 
				
			||||||
 | 
						const struct wlr_image_description_v1_data *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Convert a protocol transfer function to enum wlr_color_transfer_function.
 | 
				
			||||||
 | 
					 * Aborts if there is no matching wlroots entry.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum wlr_color_transfer_function
 | 
				
			||||||
 | 
					wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_function tf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Convert an enum wlr_color_transfer_function value into a protocol transfer function.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum wp_color_manager_v1_transfer_function
 | 
				
			||||||
 | 
					wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function tf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Convert a protocol named primaries to enum wlr_color_named_primaries.
 | 
				
			||||||
 | 
					 * Aborts if there is no matching wlroots entry.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum wlr_color_named_primaries
 | 
				
			||||||
 | 
					wlr_color_manager_v1_primaries_to_wlr(enum wp_color_manager_v1_primaries primaries);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Convert an enum wlr_color_named_primaries value into protocol primaries.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum wp_color_manager_v1_primaries
 | 
				
			||||||
 | 
					wlr_color_manager_v1_primaries_from_wlr(enum wlr_color_named_primaries primaries);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										93
									
								
								include/wlr/types/wlr_color_representation_v1.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								include/wlr/types/wlr_color_representation_v1.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,93 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This an unstable interface of wlroots. No guarantees are made regarding the
 | 
				
			||||||
 | 
					 * future consistency of this API.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef WLR_USE_UNSTABLE
 | 
				
			||||||
 | 
					#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
 | 
				
			||||||
 | 
					#define WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
 | 
					#include <wayland-protocols/color-representation-v1-enum.h>
 | 
				
			||||||
 | 
					#include <wlr/render/color.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Supported coefficients and range are always paired together
 | 
				
			||||||
 | 
					struct wlr_color_representation_v1_coeffs_and_range {
 | 
				
			||||||
 | 
						enum wp_color_representation_surface_v1_coefficients coeffs;
 | 
				
			||||||
 | 
						enum wp_color_representation_surface_v1_range range;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_color_representation_manager_v1 {
 | 
				
			||||||
 | 
						struct wl_global *global;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							// Manager is being destroyed
 | 
				
			||||||
 | 
							struct wl_signal destroy;
 | 
				
			||||||
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							enum wp_color_representation_surface_v1_alpha_mode
 | 
				
			||||||
 | 
								*supported_alpha_modes;
 | 
				
			||||||
 | 
							size_t supported_alpha_modes_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct wlr_color_representation_v1_coeffs_and_range
 | 
				
			||||||
 | 
								*supported_coeffs_and_ranges;
 | 
				
			||||||
 | 
							size_t supported_coeffs_and_ranges_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Options used when initialising a wlr_color_representation_manager_v1
 | 
				
			||||||
 | 
					struct wlr_color_representation_v1_options {
 | 
				
			||||||
 | 
						enum wp_color_representation_surface_v1_alpha_mode
 | 
				
			||||||
 | 
							*supported_alpha_modes;
 | 
				
			||||||
 | 
						size_t supported_alpha_modes_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const struct wlr_color_representation_v1_coeffs_and_range
 | 
				
			||||||
 | 
							*supported_coeffs_and_ranges;
 | 
				
			||||||
 | 
						size_t supported_coeffs_and_ranges_len;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_color_representation_manager_v1 *wlr_color_representation_manager_v1_create(
 | 
				
			||||||
 | 
							struct wl_display *display, uint32_t version,
 | 
				
			||||||
 | 
							const struct wlr_color_representation_v1_options *options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This is all the color-representation state which can be attached to a
 | 
				
			||||||
 | 
					// surface, double-buffered and made current on commit
 | 
				
			||||||
 | 
					struct wlr_color_representation_v1_surface_state {
 | 
				
			||||||
 | 
						// The enum premultiplied_electrical has value zero and is defined
 | 
				
			||||||
 | 
						// to be the default if unspecified.
 | 
				
			||||||
 | 
						enum wp_color_representation_surface_v1_alpha_mode alpha_mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If zero then indicates unset, otherwise values correspond to
 | 
				
			||||||
 | 
						// enum wp_color_representation_surface_v1_coefficients
 | 
				
			||||||
 | 
						uint32_t coefficients;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If zero then indicates unset, otherwise values correspond to
 | 
				
			||||||
 | 
						// enum wp_color_representation_surface_v1_range
 | 
				
			||||||
 | 
						uint32_t range;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If zero then indicates unset, otherwise values correspond to
 | 
				
			||||||
 | 
						// enum wp_color_representation_surface_v1_chroma_location
 | 
				
			||||||
 | 
						uint32_t chroma_location;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Get the current color representation state committed to a surface
 | 
				
			||||||
 | 
					const struct wlr_color_representation_v1_surface_state *wlr_color_representation_v1_get_surface_state(
 | 
				
			||||||
 | 
						struct wlr_surface *surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum wlr_alpha_mode wlr_color_representation_v1_alpha_mode_to_wlr(
 | 
				
			||||||
 | 
						enum wp_color_representation_surface_v1_alpha_mode wp_val);
 | 
				
			||||||
 | 
					enum wlr_color_encoding wlr_color_representation_v1_color_encoding_to_wlr(
 | 
				
			||||||
 | 
						enum wp_color_representation_surface_v1_coefficients wp_val);
 | 
				
			||||||
 | 
					enum wlr_color_range wlr_color_representation_v1_color_range_to_wlr(
 | 
				
			||||||
 | 
						enum wp_color_representation_surface_v1_range wp_val);
 | 
				
			||||||
 | 
					enum wlr_color_chroma_location wlr_color_representation_v1_chroma_location_to_wlr(
 | 
				
			||||||
 | 
						enum wp_color_representation_surface_v1_chroma_location wp_val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
 | 
				
			||||||
| 
						 | 
					@ -14,10 +14,11 @@
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					 | 
				
			||||||
#include <wlr/util/addon.h>
 | 
					#include <wlr/util/addon.h>
 | 
				
			||||||
#include <wlr/util/box.h>
 | 
					#include <wlr/util/box.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum wlr_surface_state_field {
 | 
					enum wlr_surface_state_field {
 | 
				
			||||||
	WLR_SURFACE_STATE_BUFFER = 1 << 0,
 | 
						WLR_SURFACE_STATE_BUFFER = 1 << 0,
 | 
				
			||||||
	WLR_SURFACE_STATE_SURFACE_DAMAGE = 1 << 1,
 | 
						WLR_SURFACE_STATE_SURFACE_DAMAGE = 1 << 1,
 | 
				
			||||||
| 
						 | 
					@ -97,6 +98,13 @@ struct wlr_surface_role {
 | 
				
			||||||
	 * such object exists.
 | 
						 * such object exists.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	void (*commit)(struct wlr_surface *surface);
 | 
						void (*commit)(struct wlr_surface *surface);
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Called when the surface is mapped. May be NULL.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * If the role is represented by an object, this is only called if
 | 
				
			||||||
 | 
						 * such object exists.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void (*map)(struct wlr_surface *surface);
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Called when the surface is unmapped. May be NULL.
 | 
						 * Called when the surface is unmapped. May be NULL.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
| 
						 | 
					@ -115,8 +123,11 @@ struct wlr_surface_output {
 | 
				
			||||||
	struct wlr_output *output;
 | 
						struct wlr_output *output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list link; // wlr_surface.current_outputs
 | 
						struct wl_list link; // wlr_surface.current_outputs
 | 
				
			||||||
	struct wl_listener bind;
 | 
					
 | 
				
			||||||
	struct wl_listener destroy;
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener bind;
 | 
				
			||||||
 | 
							struct wl_listener destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_surface {
 | 
					struct wlr_surface {
 | 
				
			||||||
| 
						 | 
					@ -180,28 +191,47 @@ struct wlr_surface {
 | 
				
			||||||
	struct wl_resource *role_resource;
 | 
						struct wl_resource *role_resource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Signals that the client has sent a wl_surface.commit request.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * The state to be committed can be accessed in wlr_surface.pending.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * The commit may not be applied immediately, in which case it's marked
 | 
				
			||||||
 | 
							 * as "cached" and put into a queue. See wlr_surface_lock_pending().
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		struct wl_signal client_commit;
 | 
							struct wl_signal client_commit;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Signals that a commit has been applied.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * The new state can be accessed in wlr_surface.current.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		struct wl_signal commit;
 | 
							struct wl_signal commit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * The `map` event signals that the surface has a non-null buffer
 | 
							 * Signals that the surface has a non-null buffer committed and is
 | 
				
			||||||
		 * committed and is ready to be displayed.
 | 
							 * ready to be displayed.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		struct wl_signal map;
 | 
							struct wl_signal map;
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * The `unmap` event signals that the surface shouldn't be displayed
 | 
							 * Signals that the surface shouldn't be displayed anymore. This can
 | 
				
			||||||
		 * anymore. This can happen when a null buffer is committed,
 | 
							 * happen when a null buffer is committed, the associated role object
 | 
				
			||||||
		 * the associated role object is destroyed, or when the role-specific
 | 
							 * is destroyed, or when the role-specific conditions for the surface
 | 
				
			||||||
		 * conditions for the surface to be mapped no longer apply.
 | 
							 * to be mapped no longer apply.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		struct wl_signal unmap;
 | 
							struct wl_signal unmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
 | 
							 * Signals that a new child sub-surface has been added.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
		 * Note: unlike other new_* signals, new_subsurface is emitted when
 | 
							 * Note: unlike other new_* signals, new_subsurface is emitted when
 | 
				
			||||||
		 * the subsurface is added to the parent surface's current state,
 | 
							 * the subsurface is added to the parent surface's current state,
 | 
				
			||||||
		 * not when the object is created.
 | 
							 * not when the object is created.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		struct wl_signal new_subsurface; // struct wlr_subsurface
 | 
							struct wl_signal new_subsurface; // struct wlr_subsurface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Signals that the surface is being destroyed.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -210,33 +240,33 @@ struct wlr_surface {
 | 
				
			||||||
	struct wlr_addon_set addons;
 | 
						struct wlr_addon_set addons;
 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// private state
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_listener role_resource_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		int32_t scale;
 | 
							struct wl_listener role_resource_destroy;
 | 
				
			||||||
		enum wl_output_transform transform;
 | 
					 | 
				
			||||||
		int width, height;
 | 
					 | 
				
			||||||
		int buffer_width, buffer_height;
 | 
					 | 
				
			||||||
	} previous;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool unmap_commit;
 | 
							struct {
 | 
				
			||||||
 | 
								int32_t scale;
 | 
				
			||||||
 | 
								enum wl_output_transform transform;
 | 
				
			||||||
 | 
								int width, height;
 | 
				
			||||||
 | 
								int buffer_width, buffer_height;
 | 
				
			||||||
 | 
							} previous;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool opaque;
 | 
							bool unmap_commit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool handling_commit;
 | 
							bool opaque;
 | 
				
			||||||
	bool pending_rejected;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int32_t preferred_buffer_scale;
 | 
							bool handling_commit;
 | 
				
			||||||
	bool preferred_buffer_transform_sent;
 | 
							bool pending_rejected;
 | 
				
			||||||
	enum wl_output_transform preferred_buffer_transform;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list synced; // wlr_surface_synced.link
 | 
							int32_t preferred_buffer_scale;
 | 
				
			||||||
	size_t synced_len;
 | 
							bool preferred_buffer_transform_sent;
 | 
				
			||||||
 | 
							enum wl_output_transform preferred_buffer_transform;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_resource *pending_buffer_resource;
 | 
							struct wl_list synced; // wlr_surface_synced.link
 | 
				
			||||||
	struct wl_listener pending_buffer_resource_destroy;
 | 
							size_t synced_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct wl_resource *pending_buffer_resource;
 | 
				
			||||||
 | 
							struct wl_listener pending_buffer_resource_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_renderer;
 | 
					struct wlr_renderer;
 | 
				
			||||||
| 
						 | 
					@ -245,13 +275,15 @@ struct wlr_compositor {
 | 
				
			||||||
	struct wl_global *global;
 | 
						struct wl_global *global;
 | 
				
			||||||
	struct wlr_renderer *renderer; // may be NULL
 | 
						struct wlr_renderer *renderer; // may be NULL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
					 | 
				
			||||||
	struct wl_listener renderer_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal new_surface;
 | 
							struct wl_signal new_surface;
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
 | 
							struct wl_listener renderer_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface,
 | 
					typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface,
 | 
				
			||||||
| 
						 | 
					@ -381,7 +413,7 @@ void wlr_surface_send_frame_done(struct wlr_surface *surface,
 | 
				
			||||||
 * surface coordinates.
 | 
					 * surface coordinates.
 | 
				
			||||||
 * X and y may be negative, if there are subsurfaces with negative position.
 | 
					 * X and y may be negative, if there are subsurfaces with negative position.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box);
 | 
					void wlr_surface_get_extents(struct wlr_surface *surface, struct wlr_box *box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Get the struct wlr_surface corresponding to a wl_surface resource.
 | 
					 * Get the struct wlr_surface corresponding to a wl_surface resource.
 | 
				
			||||||
| 
						 | 
					@ -453,6 +485,8 @@ void wlr_surface_set_preferred_buffer_scale(struct wlr_surface *surface,
 | 
				
			||||||
void wlr_surface_set_preferred_buffer_transform(struct wlr_surface *surface,
 | 
					void wlr_surface_set_preferred_buffer_transform(struct wlr_surface *surface,
 | 
				
			||||||
	enum wl_output_transform transform);
 | 
						enum wl_output_transform transform);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_surface_synced;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Implementation for struct wlr_surface_synced.
 | 
					 * Implementation for struct wlr_surface_synced.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -469,6 +503,11 @@ struct wlr_surface_synced_impl {
 | 
				
			||||||
	void (*finish_state)(void *state);
 | 
						void (*finish_state)(void *state);
 | 
				
			||||||
	// Move a state. If NULL, memcpy() is used.
 | 
						// Move a state. If NULL, memcpy() is used.
 | 
				
			||||||
	void (*move_state)(void *dst, void *src);
 | 
						void (*move_state)(void *dst, void *src);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Called when the state is committed. If NULL, this is a no-op.
 | 
				
			||||||
 | 
						// If an object is a surface role object which has state synchronized with
 | 
				
			||||||
 | 
						// the surface state, the role commit hook should be preferred over this.
 | 
				
			||||||
 | 
						void (*commit)(struct wlr_surface_synced *synced);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@
 | 
				
			||||||
#define WLR_TYPES_WLR_CONTENT_TYPE_V1_H
 | 
					#define WLR_TYPES_WLR_CONTENT_TYPE_V1_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
#include "content-type-v1-protocol.h"
 | 
					#include <wayland-protocols/content-type-v1-enum.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_surface;
 | 
					struct wlr_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,9 +23,9 @@ struct wlr_content_type_manager_v1 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// private state
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_content_type_manager_v1 *wlr_content_type_manager_v1_create(
 | 
					struct wlr_content_type_manager_v1 *wlr_content_type_manager_v1_create(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,9 +11,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
#include <wlr/types/wlr_output_layout.h>
 | 
					#include <wlr/types/wlr_output_layout.h>
 | 
				
			||||||
#include <wlr/types/wlr_output.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_input_device;
 | 
					struct wlr_input_device;
 | 
				
			||||||
 | 
					struct wlr_surface;
 | 
				
			||||||
struct wlr_xcursor_manager;
 | 
					struct wlr_xcursor_manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@
 | 
				
			||||||
#define WLR_TYPES_WLR_CURSOR_SHAPE_V1_H
 | 
					#define WLR_TYPES_WLR_CURSOR_SHAPE_V1_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
#include "cursor-shape-v1-protocol.h"
 | 
					#include <wayland-protocols/cursor-shape-v1-enum.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Manager for the cursor-shape-v1 protocol.
 | 
					 * Manager for the cursor-shape-v1 protocol.
 | 
				
			||||||
| 
						 | 
					@ -28,9 +28,9 @@ struct wlr_cursor_shape_manager_v1 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// private state
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum wlr_cursor_shape_manager_v1_device_type {
 | 
					enum wlr_cursor_shape_manager_v1_device_type {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,32 +15,27 @@
 | 
				
			||||||
#include <pixman.h>
 | 
					#include <pixman.h>
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* For triple buffering, a history of two frames is required. */
 | 
					 | 
				
			||||||
#define WLR_DAMAGE_RING_PREVIOUS_LEN 2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wlr_box;
 | 
					struct wlr_box;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_damage_ring_buffer {
 | 
					struct wlr_damage_ring_buffer {
 | 
				
			||||||
	struct wlr_buffer *buffer;
 | 
						struct wlr_buffer *buffer;
 | 
				
			||||||
	struct wl_listener destroy;
 | 
					 | 
				
			||||||
	pixman_region32_t damage;
 | 
						pixman_region32_t damage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_damage_ring *ring;
 | 
						struct wlr_damage_ring *ring;
 | 
				
			||||||
	struct wl_list link; // wlr_damage_ring.buffers
 | 
						struct wl_list link; // wlr_damage_ring.buffers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_damage_ring {
 | 
					struct wlr_damage_ring {
 | 
				
			||||||
	int32_t width, height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Difference between the current buffer and the previous one
 | 
						// Difference between the current buffer and the previous one
 | 
				
			||||||
	pixman_region32_t current;
 | 
						pixman_region32_t current;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// private state
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_list buffers; // wlr_damage_ring_buffer.link
 | 
				
			||||||
	pixman_region32_t previous[WLR_DAMAGE_RING_PREVIOUS_LEN];
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
	size_t previous_idx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_list buffers; // wlr_damage_ring_buffer.link
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wlr_damage_ring_init(struct wlr_damage_ring *ring);
 | 
					void wlr_damage_ring_init(struct wlr_damage_ring *ring);
 | 
				
			||||||
| 
						 | 
					@ -48,30 +43,17 @@ void wlr_damage_ring_init(struct wlr_damage_ring *ring);
 | 
				
			||||||
void wlr_damage_ring_finish(struct wlr_damage_ring *ring);
 | 
					void wlr_damage_ring_finish(struct wlr_damage_ring *ring);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Set ring bounds and damage the ring fully.
 | 
					 * Add a region to the current damage. The region must be in the buffer-local
 | 
				
			||||||
 *
 | 
					 * coordinate space.
 | 
				
			||||||
 * Next time damage will be added, it will be cropped to the ring bounds.
 | 
					 | 
				
			||||||
 * If at least one of the dimensions is 0, bounds are removed.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * By default, a damage ring doesn't have bounds.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void wlr_damage_ring_set_bounds(struct wlr_damage_ring *ring,
 | 
					void wlr_damage_ring_add(struct wlr_damage_ring *ring,
 | 
				
			||||||
	int32_t width, int32_t height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Add a region to the current damage.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns true if the region intersects the ring bounds, false otherwise.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool wlr_damage_ring_add(struct wlr_damage_ring *ring,
 | 
					 | 
				
			||||||
	const pixman_region32_t *damage);
 | 
						const pixman_region32_t *damage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Add a box to the current damage.
 | 
					 * Add a box to the current damage. The box must be in the buffer-local
 | 
				
			||||||
 *
 | 
					 * coordinate space.
 | 
				
			||||||
 * Returns true if the box intersects the ring bounds, false otherwise.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
 | 
					void wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
 | 
				
			||||||
	const struct wlr_box *box);
 | 
						const struct wlr_box *box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -79,20 +61,6 @@ bool wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring);
 | 
					void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Rotate the damage ring. This needs to be called after using the accumulated
 | 
					 | 
				
			||||||
 * damage, e.g. after rendering to an output's back buffer.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_damage_ring_rotate(struct wlr_damage_ring *ring);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Get accumulated damage, which is the difference between the current buffer
 | 
					 | 
				
			||||||
 * and the buffer with age of buffer_age; in context of rendering, this is
 | 
					 | 
				
			||||||
 * the region that needs to be redrawn.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
 | 
					 | 
				
			||||||
	int buffer_age, pixman_region32_t *damage);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Get accumulated buffer damage and rotate the damage ring.
 | 
					 * Get accumulated buffer damage and rotate the damage ring.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -102,6 +70,8 @@ void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Users should damage the ring if an error occurs while rendering or
 | 
					 * Users should damage the ring if an error occurs while rendering or
 | 
				
			||||||
 * submitting the new buffer to the backend.
 | 
					 * submitting the new buffer to the backend.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The returned damage will be in the buffer-local coordinate space.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void wlr_damage_ring_rotate_buffer(struct wlr_damage_ring *ring,
 | 
					void wlr_damage_ring_rotate_buffer(struct wlr_damage_ring *ring,
 | 
				
			||||||
	struct wlr_buffer *buffer, pixman_region32_t *damage);
 | 
						struct wlr_buffer *buffer, pixman_region32_t *damage);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,12 @@
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
#include <wlr/types/wlr_seat.h>
 | 
					#include <wlr/types/wlr_seat.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Deprecated: this protocol is legacy and superseded by ext-data-control-v1.
 | 
				
			||||||
 | 
					 * The implementation will be dropped in a future wlroots version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Consider using `wlr_ext_data_control_manager_v1` as a replacement.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct wlr_data_control_manager_v1 {
 | 
					struct wlr_data_control_manager_v1 {
 | 
				
			||||||
	struct wl_global *global;
 | 
						struct wl_global *global;
 | 
				
			||||||
	struct wl_list devices; // wlr_data_control_device_v1.link
 | 
						struct wl_list devices; // wlr_data_control_device_v1.link
 | 
				
			||||||
| 
						 | 
					@ -21,7 +27,9 @@ struct wlr_data_control_manager_v1 {
 | 
				
			||||||
		struct wl_signal new_device; // wlr_data_control_device_v1
 | 
							struct wl_signal new_device; // wlr_data_control_device_v1
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_data_control_device_v1 {
 | 
					struct wlr_data_control_device_v1 {
 | 
				
			||||||
| 
						 | 
					@ -33,9 +41,11 @@ struct wlr_data_control_device_v1 {
 | 
				
			||||||
	struct wl_resource *selection_offer_resource; // current selection offer
 | 
						struct wl_resource *selection_offer_resource; // current selection offer
 | 
				
			||||||
	struct wl_resource *primary_selection_offer_resource; // current primary selection offer
 | 
						struct wl_resource *primary_selection_offer_resource; // current primary selection offer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener seat_destroy;
 | 
						struct {
 | 
				
			||||||
	struct wl_listener seat_set_selection;
 | 
							struct wl_listener seat_destroy;
 | 
				
			||||||
	struct wl_listener seat_set_primary_selection;
 | 
							struct wl_listener seat_set_selection;
 | 
				
			||||||
 | 
							struct wl_listener seat_set_primary_selection;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_data_control_manager_v1 *wlr_data_control_manager_v1_create(
 | 
					struct wlr_data_control_manager_v1 *wlr_data_control_manager_v1_create(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,13 +16,15 @@ struct wlr_data_device_manager {
 | 
				
			||||||
	struct wl_global *global;
 | 
						struct wl_global *global;
 | 
				
			||||||
	struct wl_list data_sources;
 | 
						struct wl_list data_sources;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum wlr_data_offer_type {
 | 
					enum wlr_data_offer_type {
 | 
				
			||||||
| 
						 | 
					@ -40,7 +42,9 @@ struct wlr_data_offer {
 | 
				
			||||||
	enum wl_data_device_manager_dnd_action preferred_action;
 | 
						enum wl_data_device_manager_dnd_action preferred_action;
 | 
				
			||||||
	bool in_ask;
 | 
						bool in_ask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener source_destroy;
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener source_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -89,9 +93,11 @@ struct wlr_drag_icon {
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener surface_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener surface_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum wlr_drag_grab_type {
 | 
					enum wlr_drag_grab_type {
 | 
				
			||||||
| 
						 | 
					@ -124,11 +130,14 @@ struct wlr_drag {
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener source_destroy;
 | 
					 | 
				
			||||||
	struct wl_listener seat_client_destroy;
 | 
					 | 
				
			||||||
	struct wl_listener icon_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener source_destroy;
 | 
				
			||||||
 | 
							struct wl_listener seat_client_destroy;
 | 
				
			||||||
 | 
							struct wl_listener focus_destroy;
 | 
				
			||||||
 | 
							struct wl_listener icon_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drag_motion_event {
 | 
					struct wlr_drag_motion_event {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,9 @@ struct wlr_drm_buffer {
 | 
				
			||||||
	struct wl_resource *resource; // can be NULL if the client destroyed it
 | 
						struct wl_resource *resource; // can be NULL if the client destroyed it
 | 
				
			||||||
	struct wlr_dmabuf_attributes dmabuf;
 | 
						struct wlr_dmabuf_attributes dmabuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener release;
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener release;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -40,12 +42,12 @@ struct wlr_drm {
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// private state
 | 
						struct {
 | 
				
			||||||
 | 
							char *node_name;
 | 
				
			||||||
 | 
							struct wlr_drm_format_set formats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *node_name;
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
	struct wlr_drm_format_set formats;
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_buffer *wlr_drm_buffer_try_from_resource(
 | 
					struct wlr_drm_buffer *wlr_drm_buffer_try_from_resource(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,9 +18,10 @@ struct wlr_drm_lease_v1_manager {
 | 
				
			||||||
	struct wl_list devices; // wlr_drm_lease_device_v1.link
 | 
						struct wl_list devices; // wlr_drm_lease_device_v1.link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_display *display;
 | 
						struct wl_display *display;
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_signal destroy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * Upon receiving this signal, call
 | 
							 * Upon receiving this signal, call
 | 
				
			||||||
		 * wlr_drm_lease_device_v1_grant_lease_request() to grant a lease of the
 | 
							 * wlr_drm_lease_device_v1_grant_lease_request() to grant a lease of the
 | 
				
			||||||
| 
						 | 
					@ -29,6 +30,10 @@ struct wlr_drm_lease_v1_manager {
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		struct wl_signal request;
 | 
							struct wl_signal request;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_lease_device_v1 {
 | 
					struct wlr_drm_lease_device_v1 {
 | 
				
			||||||
| 
						 | 
					@ -43,9 +48,11 @@ struct wlr_drm_lease_device_v1 {
 | 
				
			||||||
	struct wl_list requests; // wlr_drm_lease_request_v1.link
 | 
						struct wl_list requests; // wlr_drm_lease_request_v1.link
 | 
				
			||||||
	struct wl_list link; // wlr_drm_lease_v1_manager.devices
 | 
						struct wl_list link; // wlr_drm_lease_v1_manager.devices
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener backend_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener backend_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_lease_v1;
 | 
					struct wlr_drm_lease_v1;
 | 
				
			||||||
| 
						 | 
					@ -55,12 +62,12 @@ struct wlr_drm_lease_connector_v1 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_output *output;
 | 
						struct wlr_output *output;
 | 
				
			||||||
	struct wlr_drm_lease_device_v1 *device;
 | 
						struct wlr_drm_lease_device_v1 *device;
 | 
				
			||||||
	/** NULL if no client is currently leasing this connector */
 | 
					 | 
				
			||||||
	struct wlr_drm_lease_v1 *active_lease;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_listener destroy;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list link; // wlr_drm_lease_device_v1.connectors
 | 
						struct wl_list link; // wlr_drm_lease_device_v1.connectors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_drm_lease_request_v1 {
 | 
					struct wlr_drm_lease_request_v1 {
 | 
				
			||||||
| 
						 | 
					@ -84,14 +91,13 @@ struct wlr_drm_lease_v1 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_drm_lease_device_v1 *device;
 | 
						struct wlr_drm_lease_device_v1 *device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_drm_lease_connector_v1 **connectors;
 | 
					 | 
				
			||||||
	size_t n_connectors;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wl_list link; // wlr_drm_lease_device_v1.leases
 | 
						struct wl_list link; // wlr_drm_lease_device_v1.leases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,11 +17,13 @@ struct wlr_export_dmabuf_manager_v1 {
 | 
				
			||||||
	struct wl_global *global;
 | 
						struct wl_global *global;
 | 
				
			||||||
	struct wl_list frames; // wlr_export_dmabuf_frame_v1.link
 | 
						struct wl_list frames; // wlr_export_dmabuf_frame_v1.link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_export_dmabuf_frame_v1 {
 | 
					struct wlr_export_dmabuf_frame_v1 {
 | 
				
			||||||
| 
						 | 
					@ -33,8 +35,10 @@ struct wlr_export_dmabuf_frame_v1 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool cursor_locked;
 | 
						bool cursor_locked;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener output_commit;
 | 
						struct {
 | 
				
			||||||
	struct wl_listener output_destroy;
 | 
							struct wl_listener output_commit;
 | 
				
			||||||
 | 
							struct wl_listener output_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create(
 | 
					struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										51
									
								
								include/wlr/types/wlr_ext_data_control_v1.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								include/wlr/types/wlr_ext_data_control_v1.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This an unstable interface of wlroots. No guarantees are made regarding the
 | 
				
			||||||
 | 
					 * future consistency of this API.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef WLR_USE_UNSTABLE
 | 
				
			||||||
 | 
					#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef WLR_TYPES_WLR_EXT_DATA_CONTROL_V1_H
 | 
				
			||||||
 | 
					#define WLR_TYPES_WLR_EXT_DATA_CONTROL_V1_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_seat.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_ext_data_control_manager_v1 {
 | 
				
			||||||
 | 
						struct wl_global *global;
 | 
				
			||||||
 | 
						struct wl_list devices; // wlr_ext_data_control_device_v1.link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_signal destroy;
 | 
				
			||||||
 | 
							struct wl_signal new_device; // wlr_ext_data_control_device_v1
 | 
				
			||||||
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_ext_data_control_device_v1 {
 | 
				
			||||||
 | 
						struct wl_resource *resource;
 | 
				
			||||||
 | 
						struct wlr_ext_data_control_manager_v1 *manager;
 | 
				
			||||||
 | 
						struct wl_list link; // wlr_ext_data_control_manager_v1.devices
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_seat *seat;
 | 
				
			||||||
 | 
						struct wl_resource *selection_offer_resource; // current selection offer
 | 
				
			||||||
 | 
						struct wl_resource *primary_selection_offer_resource; // current primary selection offer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener seat_destroy;
 | 
				
			||||||
 | 
							struct wl_listener seat_set_selection;
 | 
				
			||||||
 | 
							struct wl_listener seat_set_primary_selection;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_ext_data_control_manager_v1 *wlr_ext_data_control_manager_v1_create(
 | 
				
			||||||
 | 
						struct wl_display *display, uint32_t version);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_ext_data_control_device_v1_destroy(
 | 
				
			||||||
 | 
						struct wlr_ext_data_control_device_v1 *device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -16,13 +16,15 @@ struct wlr_ext_foreign_toplevel_list_v1 {
 | 
				
			||||||
	struct wl_list resources; // wl_resource_get_link()
 | 
						struct wl_list resources; // wl_resource_get_link()
 | 
				
			||||||
	struct wl_list toplevels; // ext_foreign_toplevel_handle_v1.link
 | 
						struct wl_list toplevels; // ext_foreign_toplevel_handle_v1.link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_listener display_destroy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
	} events;
 | 
						} events;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_listener display_destroy;
 | 
				
			||||||
 | 
						} WLR_PRIVATE;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_ext_foreign_toplevel_handle_v1 {
 | 
					struct wlr_ext_foreign_toplevel_handle_v1 {
 | 
				
			||||||
| 
						 | 
					@ -64,4 +66,7 @@ void wlr_ext_foreign_toplevel_handle_v1_update_state(
 | 
				
			||||||
	struct wlr_ext_foreign_toplevel_handle_v1 *toplevel,
 | 
						struct wlr_ext_foreign_toplevel_handle_v1 *toplevel,
 | 
				
			||||||
	const struct wlr_ext_foreign_toplevel_handle_v1_state *state);
 | 
						const struct wlr_ext_foreign_toplevel_handle_v1_state *state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wlr_ext_foreign_toplevel_handle_v1 *wlr_ext_foreign_toplevel_handle_v1_from_resource(
 | 
				
			||||||
 | 
						struct wl_resource *resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue