modetest.c 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491
  1. /*
  2. * DRM based mode setting test program
  3. * Copyright 2008 Tungsten Graphics
  4. * Jakob Bornecrantz <jakob@tungstengraphics.com>
  5. * Copyright 2008 Intel Corporation
  6. * Jesse Barnes <jesse.barnes@intel.com>
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a
  9. * copy of this software and associated documentation files (the "Software"),
  10. * to deal in the Software without restriction, including without limitation
  11. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12. * and/or sell copies of the Software, and to permit persons to whom the
  13. * Software is furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  24. * IN THE SOFTWARE.
  25. */
  26. /*
  27. * This fairly simple test program dumps output in a similar format to the
  28. * "xrandr" tool everyone knows & loves. It's necessarily slightly different
  29. * since the kernel separates outputs into encoder and connector structures,
  30. * each with their own unique ID. The program also allows test testing of the
  31. * memory management and mode setting APIs by allowing the user to specify a
  32. * connector and mode to use for mode setting. If all works as expected, a
  33. * blue background should be painted on the monitor attached to the specified
  34. * connector after the selected mode is set.
  35. *
  36. * TODO: use cairo to write the mode info on the selected output once
  37. * the mode has been programmed, along with possible test patterns.
  38. */
  39. #include <assert.h>
  40. #include <ctype.h>
  41. #include <stdbool.h>
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <stdint.h>
  45. #include <inttypes.h>
  46. #include <unistd.h>
  47. #include <string.h>
  48. #include <strings.h>
  49. #include <errno.h>
  50. #include <poll.h>
  51. #include <sys/time.h>
  52. #if HAVE_SYS_SELECT_H
  53. #include <sys/select.h>
  54. #endif
  55. #include <math.h>
  56. #include "xf86drm.h"
  57. #include "xf86drmMode.h"
  58. #include "drm_fourcc.h"
  59. #include "util/common.h"
  60. #include "util/format.h"
  61. #include "util/kms.h"
  62. #include "util/pattern.h"
  63. #include "buffers.h"
  64. #include "cursor.h"
  65. static enum util_fill_pattern primary_fill = UTIL_PATTERN_SMPTE;
  66. static enum util_fill_pattern secondary_fill = UTIL_PATTERN_TILES;
  67. static unsigned long pattern_seed = 0;
  68. static drmModeModeInfo user_mode;
  69. struct crtc {
  70. drmModeCrtc *crtc;
  71. drmModeObjectProperties *props;
  72. drmModePropertyRes **props_info;
  73. drmModeModeInfo *mode;
  74. };
  75. struct encoder {
  76. drmModeEncoder *encoder;
  77. };
  78. struct connector {
  79. drmModeConnector *connector;
  80. drmModeObjectProperties *props;
  81. drmModePropertyRes **props_info;
  82. char *name;
  83. };
  84. struct fb {
  85. drmModeFB *fb;
  86. };
  87. struct plane {
  88. drmModePlane *plane;
  89. drmModeObjectProperties *props;
  90. drmModePropertyRes **props_info;
  91. };
  92. struct resources {
  93. struct crtc *crtcs;
  94. int count_crtcs;
  95. struct encoder *encoders;
  96. int count_encoders;
  97. struct connector *connectors;
  98. int count_connectors;
  99. struct fb *fbs;
  100. int count_fbs;
  101. struct plane *planes;
  102. uint32_t count_planes;
  103. };
  104. struct device {
  105. int fd;
  106. struct resources *resources;
  107. struct {
  108. unsigned int width;
  109. unsigned int height;
  110. unsigned int fb_id;
  111. struct bo *bo;
  112. struct bo *cursor_bo;
  113. } mode;
  114. int use_atomic;
  115. drmModeAtomicReq *req;
  116. int32_t writeback_fence_fd;
  117. };
  118. static inline int64_t U642I64(uint64_t val)
  119. {
  120. return (int64_t)*((int64_t *)&val);
  121. }
  122. static float mode_vrefresh(drmModeModeInfo *mode)
  123. {
  124. unsigned int num, den;
  125. num = mode->clock;
  126. den = mode->htotal * mode->vtotal;
  127. if (mode->flags & DRM_MODE_FLAG_INTERLACE)
  128. num *= 2;
  129. if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
  130. den *= 2;
  131. if (mode->vscan > 1)
  132. den *= mode->vscan;
  133. return num * 1000.00 / den;
  134. }
  135. #define bit_name_fn(res) \
  136. const char * res##_str(int type) { \
  137. unsigned int i; \
  138. const char *sep = ""; \
  139. for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
  140. if (type & (1 << i)) { \
  141. printf("%s%s", sep, res##_names[i]); \
  142. sep = ", "; \
  143. } \
  144. } \
  145. return NULL; \
  146. }
  147. static const char *mode_type_names[] = {
  148. "builtin",
  149. "clock_c",
  150. "crtc_c",
  151. "preferred",
  152. "default",
  153. "userdef",
  154. "driver",
  155. };
  156. static bit_name_fn(mode_type)
  157. static const char *mode_flag_names[] = {
  158. "phsync",
  159. "nhsync",
  160. "pvsync",
  161. "nvsync",
  162. "interlace",
  163. "dblscan",
  164. "csync",
  165. "pcsync",
  166. "ncsync",
  167. "hskew",
  168. "bcast",
  169. "pixmux",
  170. "dblclk",
  171. "clkdiv2"
  172. };
  173. static bit_name_fn(mode_flag)
  174. static void dump_fourcc(uint32_t fourcc)
  175. {
  176. char *name = drmGetFormatName(fourcc);
  177. printf(" %s", name);
  178. free(name);
  179. }
  180. static void dump_encoders(struct device *dev)
  181. {
  182. drmModeEncoder *encoder;
  183. int i;
  184. printf("Encoders:\n");
  185. printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
  186. for (i = 0; i < dev->resources->count_encoders; i++) {
  187. encoder = dev->resources->encoders[i].encoder;
  188. if (!encoder)
  189. continue;
  190. printf("%d\t%d\t%s\t0x%08x\t0x%08x\n",
  191. encoder->encoder_id,
  192. encoder->crtc_id,
  193. util_lookup_encoder_type_name(encoder->encoder_type),
  194. encoder->possible_crtcs,
  195. encoder->possible_clones);
  196. }
  197. printf("\n");
  198. }
  199. static void dump_mode(drmModeModeInfo *mode, int index)
  200. {
  201. printf(" #%i %s %.2f %d %d %d %d %d %d %d %d %d",
  202. index,
  203. mode->name,
  204. mode_vrefresh(mode),
  205. mode->hdisplay,
  206. mode->hsync_start,
  207. mode->hsync_end,
  208. mode->htotal,
  209. mode->vdisplay,
  210. mode->vsync_start,
  211. mode->vsync_end,
  212. mode->vtotal,
  213. mode->clock);
  214. printf(" flags: ");
  215. mode_flag_str(mode->flags);
  216. printf("; type: ");
  217. mode_type_str(mode->type);
  218. printf("\n");
  219. }
  220. static void dump_blob(struct device *dev, uint32_t blob_id)
  221. {
  222. uint32_t i;
  223. unsigned char *blob_data;
  224. drmModePropertyBlobPtr blob;
  225. blob = drmModeGetPropertyBlob(dev->fd, blob_id);
  226. if (!blob) {
  227. printf("\n");
  228. return;
  229. }
  230. blob_data = blob->data;
  231. for (i = 0; i < blob->length; i++) {
  232. if (i % 16 == 0)
  233. printf("\n\t\t\t");
  234. printf("%.2hhx", blob_data[i]);
  235. }
  236. printf("\n");
  237. drmModeFreePropertyBlob(blob);
  238. }
  239. static const char *modifier_to_string(uint64_t modifier)
  240. {
  241. static char mod_string[4096];
  242. char *modifier_name = drmGetFormatModifierName(modifier);
  243. char *vendor_name = drmGetFormatModifierVendor(modifier);
  244. memset(mod_string, 0x00, sizeof(mod_string));
  245. if (!modifier_name) {
  246. if (vendor_name)
  247. snprintf(mod_string, sizeof(mod_string), "%s_%s",
  248. vendor_name, "UNKNOWN_MODIFIER");
  249. else
  250. snprintf(mod_string, sizeof(mod_string), "%s_%s",
  251. "UNKNOWN_VENDOR", "UNKNOWN_MODIFIER");
  252. /* safe, as free is no-op for NULL */
  253. free(vendor_name);
  254. return mod_string;
  255. }
  256. if (modifier == DRM_FORMAT_MOD_LINEAR) {
  257. snprintf(mod_string, sizeof(mod_string), "%s", modifier_name);
  258. free(modifier_name);
  259. free(vendor_name);
  260. return mod_string;
  261. }
  262. snprintf(mod_string, sizeof(mod_string), "%s_%s",
  263. vendor_name, modifier_name);
  264. free(modifier_name);
  265. free(vendor_name);
  266. return mod_string;
  267. }
  268. static void dump_in_formats(struct device *dev, uint32_t blob_id)
  269. {
  270. drmModeFormatModifierIterator iter = {0};
  271. drmModePropertyBlobPtr blob;
  272. uint32_t fmt = 0;
  273. printf("\t\tin_formats blob decoded:\n");
  274. blob = drmModeGetPropertyBlob(dev->fd, blob_id);
  275. if (!blob) {
  276. printf("\n");
  277. return;
  278. }
  279. while (drmModeFormatModifierBlobIterNext(blob, &iter)) {
  280. if (!fmt || fmt != iter.fmt) {
  281. printf("%s\t\t\t", !fmt ? "" : "\n");
  282. fmt = iter.fmt;
  283. dump_fourcc(fmt);
  284. printf(": ");
  285. }
  286. printf(" %s(0x%"PRIx64")", modifier_to_string(iter.mod), iter.mod);
  287. }
  288. printf("\n");
  289. drmModeFreePropertyBlob(blob);
  290. }
  291. static void dump_prop(struct device *dev, drmModePropertyPtr prop,
  292. uint32_t prop_id, uint64_t value)
  293. {
  294. int i;
  295. printf("\t%d", prop_id);
  296. if (!prop) {
  297. printf("\n");
  298. return;
  299. }
  300. printf(" %s:\n", prop->name);
  301. printf("\t\tflags:");
  302. if (prop->flags & DRM_MODE_PROP_PENDING)
  303. printf(" pending");
  304. if (prop->flags & DRM_MODE_PROP_IMMUTABLE)
  305. printf(" immutable");
  306. if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
  307. printf(" signed range");
  308. if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE))
  309. printf(" range");
  310. if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM))
  311. printf(" enum");
  312. if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK))
  313. printf(" bitmask");
  314. if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
  315. printf(" blob");
  316. if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT))
  317. printf(" object");
  318. printf("\n");
  319. if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) {
  320. printf("\t\tvalues:");
  321. for (i = 0; i < prop->count_values; i++)
  322. printf(" %"PRId64, U642I64(prop->values[i]));
  323. printf("\n");
  324. }
  325. if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) {
  326. printf("\t\tvalues:");
  327. for (i = 0; i < prop->count_values; i++)
  328. printf(" %"PRIu64, prop->values[i]);
  329. printf("\n");
  330. }
  331. if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) {
  332. printf("\t\tenums:");
  333. for (i = 0; i < prop->count_enums; i++)
  334. printf(" %s=%"PRIu64, prop->enums[i].name,
  335. (uint64_t)prop->enums[i].value);
  336. printf("\n");
  337. } else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
  338. printf("\t\tvalues:");
  339. for (i = 0; i < prop->count_enums; i++)
  340. printf(" %s=0x%llx", prop->enums[i].name,
  341. (1LL << prop->enums[i].value));
  342. printf("\n");
  343. } else {
  344. assert(prop->count_enums == 0);
  345. }
  346. if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) {
  347. printf("\t\tblobs:\n");
  348. for (i = 0; i < prop->count_blobs; i++)
  349. dump_blob(dev, prop->blob_ids[i]);
  350. printf("\n");
  351. } else {
  352. assert(prop->count_blobs == 0);
  353. }
  354. printf("\t\tvalue:");
  355. if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
  356. dump_blob(dev, value);
  357. else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
  358. printf(" %"PRId64"\n", value);
  359. else
  360. printf(" %"PRIu64"\n", value);
  361. if (strcmp(prop->name, "IN_FORMATS") == 0)
  362. dump_in_formats(dev, value);
  363. }
  364. static void dump_connectors(struct device *dev)
  365. {
  366. int i, j;
  367. printf("Connectors:\n");
  368. printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n");
  369. for (i = 0; i < dev->resources->count_connectors; i++) {
  370. struct connector *_connector = &dev->resources->connectors[i];
  371. drmModeConnector *connector = _connector->connector;
  372. if (!connector)
  373. continue;
  374. printf("%d\t%d\t%s\t%-15s\t%dx%d\t\t%d\t",
  375. connector->connector_id,
  376. connector->encoder_id,
  377. util_lookup_connector_status_name(connector->connection),
  378. _connector->name,
  379. connector->mmWidth, connector->mmHeight,
  380. connector->count_modes);
  381. for (j = 0; j < connector->count_encoders; j++)
  382. printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]);
  383. printf("\n");
  384. if (connector->count_modes) {
  385. printf(" modes:\n");
  386. printf("\tindex name refresh (Hz) hdisp hss hse htot vdisp "
  387. "vss vse vtot\n");
  388. for (j = 0; j < connector->count_modes; j++)
  389. dump_mode(&connector->modes[j], j);
  390. }
  391. if (_connector->props) {
  392. printf(" props:\n");
  393. for (j = 0; j < (int)_connector->props->count_props; j++)
  394. dump_prop(dev, _connector->props_info[j],
  395. _connector->props->props[j],
  396. _connector->props->prop_values[j]);
  397. }
  398. }
  399. printf("\n");
  400. }
  401. static void dump_crtcs(struct device *dev)
  402. {
  403. int i;
  404. uint32_t j;
  405. printf("CRTCs:\n");
  406. printf("id\tfb\tpos\tsize\n");
  407. for (i = 0; i < dev->resources->count_crtcs; i++) {
  408. struct crtc *_crtc = &dev->resources->crtcs[i];
  409. drmModeCrtc *crtc = _crtc->crtc;
  410. if (!crtc)
  411. continue;
  412. printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
  413. crtc->crtc_id,
  414. crtc->buffer_id,
  415. crtc->x, crtc->y,
  416. crtc->width, crtc->height);
  417. dump_mode(&crtc->mode, 0);
  418. if (_crtc->props) {
  419. printf(" props:\n");
  420. for (j = 0; j < _crtc->props->count_props; j++)
  421. dump_prop(dev, _crtc->props_info[j],
  422. _crtc->props->props[j],
  423. _crtc->props->prop_values[j]);
  424. } else {
  425. printf(" no properties found\n");
  426. }
  427. }
  428. printf("\n");
  429. }
  430. static void dump_framebuffers(struct device *dev)
  431. {
  432. drmModeFB *fb;
  433. int i;
  434. printf("Frame buffers:\n");
  435. printf("id\tsize\tpitch\n");
  436. for (i = 0; i < dev->resources->count_fbs; i++) {
  437. fb = dev->resources->fbs[i].fb;
  438. if (!fb)
  439. continue;
  440. printf("%u\t(%ux%u)\t%u\n",
  441. fb->fb_id,
  442. fb->width, fb->height,
  443. fb->pitch);
  444. }
  445. printf("\n");
  446. }
  447. static void dump_planes(struct device *dev)
  448. {
  449. unsigned int i, j;
  450. printf("Planes:\n");
  451. printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");
  452. for (i = 0; i < dev->resources->count_planes; i++) {
  453. struct plane *plane = &dev->resources->planes[i];
  454. drmModePlane *ovr = plane->plane;
  455. if (!ovr)
  456. continue;
  457. printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n",
  458. ovr->plane_id, ovr->crtc_id, ovr->fb_id,
  459. ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
  460. ovr->gamma_size, ovr->possible_crtcs);
  461. if (!ovr->count_formats)
  462. continue;
  463. printf(" formats:");
  464. for (j = 0; j < ovr->count_formats; j++)
  465. dump_fourcc(ovr->formats[j]);
  466. printf("\n");
  467. if (plane->props) {
  468. printf(" props:\n");
  469. for (j = 0; j < plane->props->count_props; j++)
  470. dump_prop(dev, plane->props_info[j],
  471. plane->props->props[j],
  472. plane->props->prop_values[j]);
  473. } else {
  474. printf(" no properties found\n");
  475. }
  476. }
  477. printf("\n");
  478. return;
  479. }
  480. static void free_resources(struct resources *res)
  481. {
  482. int i;
  483. if (!res)
  484. return;
  485. #define free_resource(_res, type, Type) \
  486. do { \
  487. if (!(_res)->type##s) \
  488. break; \
  489. for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \
  490. if (!(_res)->type##s[i].type) \
  491. break; \
  492. drmModeFree##Type((_res)->type##s[i].type); \
  493. } \
  494. free((_res)->type##s); \
  495. } while (0)
  496. #define free_properties(_res, type) \
  497. do { \
  498. for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \
  499. unsigned int j; \
  500. for (j = 0; j < res->type##s[i].props->count_props; ++j)\
  501. drmModeFreeProperty(res->type##s[i].props_info[j]);\
  502. free(res->type##s[i].props_info); \
  503. drmModeFreeObjectProperties(res->type##s[i].props); \
  504. } \
  505. } while (0)
  506. free_properties(res, plane);
  507. free_resource(res, plane, Plane);
  508. free_properties(res, connector);
  509. free_properties(res, crtc);
  510. for (i = 0; i < res->count_connectors; i++)
  511. free(res->connectors[i].name);
  512. free_resource(res, fb, FB);
  513. free_resource(res, connector, Connector);
  514. free_resource(res, encoder, Encoder);
  515. free_resource(res, crtc, Crtc);
  516. free(res);
  517. }
  518. static struct resources *get_resources(struct device *dev)
  519. {
  520. drmModeRes *_res;
  521. drmModePlaneRes *plane_res;
  522. struct resources *res;
  523. int i;
  524. res = calloc(1, sizeof(*res));
  525. if (res == 0)
  526. return NULL;
  527. drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
  528. _res = drmModeGetResources(dev->fd);
  529. if (!_res) {
  530. fprintf(stderr, "drmModeGetResources failed: %s\n",
  531. strerror(errno));
  532. free(res);
  533. return NULL;
  534. }
  535. res->count_crtcs = _res->count_crtcs;
  536. res->count_encoders = _res->count_encoders;
  537. res->count_connectors = _res->count_connectors;
  538. res->count_fbs = _res->count_fbs;
  539. res->crtcs = calloc(res->count_crtcs, sizeof(*res->crtcs));
  540. res->encoders = calloc(res->count_encoders, sizeof(*res->encoders));
  541. res->connectors = calloc(res->count_connectors, sizeof(*res->connectors));
  542. res->fbs = calloc(res->count_fbs, sizeof(*res->fbs));
  543. if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) {
  544. drmModeFreeResources(_res);
  545. goto error;
  546. }
  547. #define get_resource(_res, __res, type, Type) \
  548. do { \
  549. for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \
  550. uint32_t type##id = (__res)->type##s[i]; \
  551. (_res)->type##s[i].type = \
  552. drmModeGet##Type(dev->fd, type##id); \
  553. if (!(_res)->type##s[i].type) \
  554. fprintf(stderr, "could not get %s %i: %s\n", \
  555. #type, type##id, \
  556. strerror(errno)); \
  557. } \
  558. } while (0)
  559. get_resource(res, _res, crtc, Crtc);
  560. get_resource(res, _res, encoder, Encoder);
  561. get_resource(res, _res, connector, Connector);
  562. get_resource(res, _res, fb, FB);
  563. drmModeFreeResources(_res);
  564. /* Set the name of all connectors based on the type name and the per-type ID. */
  565. for (i = 0; i < res->count_connectors; i++) {
  566. struct connector *connector = &res->connectors[i];
  567. drmModeConnector *conn = connector->connector;
  568. int num;
  569. num = asprintf(&connector->name, "%s-%u",
  570. drmModeGetConnectorTypeName(conn->connector_type),
  571. conn->connector_type_id);
  572. if (num < 0)
  573. goto error;
  574. }
  575. #define get_properties(_res, type, Type) \
  576. do { \
  577. for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \
  578. struct type *obj = &res->type##s[i]; \
  579. unsigned int j; \
  580. obj->props = \
  581. drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \
  582. DRM_MODE_OBJECT_##Type); \
  583. if (!obj->props) { \
  584. fprintf(stderr, \
  585. "could not get %s %i properties: %s\n", \
  586. #type, obj->type->type##_id, \
  587. strerror(errno)); \
  588. continue; \
  589. } \
  590. obj->props_info = calloc(obj->props->count_props, \
  591. sizeof(*obj->props_info)); \
  592. if (!obj->props_info) \
  593. continue; \
  594. for (j = 0; j < obj->props->count_props; ++j) \
  595. obj->props_info[j] = \
  596. drmModeGetProperty(dev->fd, obj->props->props[j]); \
  597. } \
  598. } while (0)
  599. get_properties(res, crtc, CRTC);
  600. get_properties(res, connector, CONNECTOR);
  601. for (i = 0; i < res->count_crtcs; ++i)
  602. res->crtcs[i].mode = &res->crtcs[i].crtc->mode;
  603. plane_res = drmModeGetPlaneResources(dev->fd);
  604. if (!plane_res) {
  605. fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
  606. strerror(errno));
  607. return res;
  608. }
  609. res->count_planes = plane_res->count_planes;
  610. res->planes = calloc(res->count_planes, sizeof(*res->planes));
  611. if (!res->planes) {
  612. drmModeFreePlaneResources(plane_res);
  613. goto error;
  614. }
  615. get_resource(res, plane_res, plane, Plane);
  616. drmModeFreePlaneResources(plane_res);
  617. get_properties(res, plane, PLANE);
  618. return res;
  619. error:
  620. free_resources(res);
  621. return NULL;
  622. }
  623. static struct crtc *get_crtc_by_id(struct device *dev, uint32_t id)
  624. {
  625. int i;
  626. for (i = 0; i < dev->resources->count_crtcs; ++i) {
  627. drmModeCrtc *crtc = dev->resources->crtcs[i].crtc;
  628. if (crtc && crtc->crtc_id == id)
  629. return &dev->resources->crtcs[i];
  630. }
  631. return NULL;
  632. }
  633. static uint32_t get_crtc_mask(struct device *dev, struct crtc *crtc)
  634. {
  635. unsigned int i;
  636. for (i = 0; i < (unsigned int)dev->resources->count_crtcs; i++) {
  637. if (crtc->crtc->crtc_id == dev->resources->crtcs[i].crtc->crtc_id)
  638. return 1 << i;
  639. }
  640. /* Unreachable: crtc->crtc is one of resources->crtcs[] */
  641. /* Don't return zero or static analysers will complain */
  642. abort();
  643. return 0;
  644. }
  645. static drmModeConnector *get_connector_by_name(struct device *dev, const char *name)
  646. {
  647. struct connector *connector;
  648. int i;
  649. for (i = 0; i < dev->resources->count_connectors; i++) {
  650. connector = &dev->resources->connectors[i];
  651. if (strcmp(connector->name, name) == 0)
  652. return connector->connector;
  653. }
  654. return NULL;
  655. }
  656. static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id)
  657. {
  658. drmModeConnector *connector;
  659. int i;
  660. for (i = 0; i < dev->resources->count_connectors; i++) {
  661. connector = dev->resources->connectors[i].connector;
  662. if (connector && connector->connector_id == id)
  663. return connector;
  664. }
  665. return NULL;
  666. }
  667. static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id)
  668. {
  669. drmModeEncoder *encoder;
  670. int i;
  671. for (i = 0; i < dev->resources->count_encoders; i++) {
  672. encoder = dev->resources->encoders[i].encoder;
  673. if (encoder && encoder->encoder_id == id)
  674. return encoder;
  675. }
  676. return NULL;
  677. }
  678. /* -----------------------------------------------------------------------------
  679. * Pipes and planes
  680. */
  681. /*
  682. * Mode setting with the kernel interfaces is a bit of a chore.
  683. * First you have to find the connector in question and make sure the
  684. * requested mode is available.
  685. * Then you need to find the encoder attached to that connector so you
  686. * can bind it with a free crtc.
  687. */
  688. struct pipe_arg {
  689. const char **cons;
  690. uint32_t *con_ids;
  691. unsigned int num_cons;
  692. uint32_t crtc_id;
  693. char mode_str[64];
  694. char format_str[8]; /* need to leave room for "_BE" and terminating \0 */
  695. float vrefresh;
  696. unsigned int fourcc;
  697. drmModeModeInfo *mode;
  698. struct crtc *crtc;
  699. unsigned int fb_id[2], current_fb_id;
  700. struct timeval start;
  701. unsigned int out_fb_id;
  702. struct bo *out_bo;
  703. int swap_count;
  704. };
  705. struct plane_arg {
  706. uint32_t plane_id; /* the id of plane to use */
  707. uint32_t crtc_id; /* the id of CRTC to bind to */
  708. bool has_position;
  709. int32_t x, y;
  710. uint32_t w, h;
  711. double scale;
  712. unsigned int fb_id;
  713. unsigned int old_fb_id;
  714. struct bo *bo;
  715. struct bo *old_bo;
  716. char format_str[8]; /* need to leave room for "_BE" and terminating \0 */
  717. unsigned int fourcc;
  718. };
  719. static drmModeModeInfo *
  720. connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str,
  721. const float vrefresh)
  722. {
  723. drmModeConnector *connector;
  724. drmModeModeInfo *mode;
  725. int i;
  726. connector = get_connector_by_id(dev, con_id);
  727. if (!connector)
  728. return NULL;
  729. if (strchr(mode_str, ',')) {
  730. i = sscanf(mode_str, "%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu",
  731. &user_mode.hdisplay, &user_mode.hsync_start,
  732. &user_mode.hsync_end, &user_mode.htotal,
  733. &user_mode.vdisplay, &user_mode.vsync_start,
  734. &user_mode.vsync_end, &user_mode.vtotal);
  735. if (i == 8) {
  736. user_mode.clock = roundf(user_mode.htotal * user_mode.vtotal * vrefresh / 1000);
  737. user_mode.vrefresh = roundf(vrefresh);
  738. snprintf(user_mode.name, sizeof(user_mode.name), "custom%dx%d", user_mode.hdisplay, user_mode.vdisplay);
  739. return &user_mode;
  740. }
  741. }
  742. if (!connector->count_modes)
  743. return NULL;
  744. /* Pick by Index */
  745. if (mode_str[0] == '#') {
  746. int index = atoi(mode_str + 1);
  747. if (index >= connector->count_modes || index < 0)
  748. return NULL;
  749. return &connector->modes[index];
  750. }
  751. /* Pick by Name */
  752. for (i = 0; i < connector->count_modes; i++) {
  753. mode = &connector->modes[i];
  754. if (!strcmp(mode->name, mode_str)) {
  755. /* If the vertical refresh frequency is not specified
  756. * then return the first mode that match with the name.
  757. * Else, return the mode that match the name and
  758. * the specified vertical refresh frequency.
  759. */
  760. if (vrefresh == 0)
  761. return mode;
  762. else if (fabs(mode_vrefresh(mode) - vrefresh) < 0.005)
  763. return mode;
  764. }
  765. }
  766. return NULL;
  767. }
  768. static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe)
  769. {
  770. uint32_t possible_crtcs = ~0;
  771. uint32_t active_crtcs = 0;
  772. unsigned int crtc_idx;
  773. unsigned int i;
  774. int j;
  775. for (i = 0; i < pipe->num_cons; ++i) {
  776. uint32_t crtcs_for_connector = 0;
  777. drmModeConnector *connector;
  778. drmModeEncoder *encoder;
  779. struct crtc *crtc;
  780. connector = get_connector_by_id(dev, pipe->con_ids[i]);
  781. if (!connector)
  782. return NULL;
  783. for (j = 0; j < connector->count_encoders; ++j) {
  784. encoder = get_encoder_by_id(dev, connector->encoders[j]);
  785. if (!encoder)
  786. continue;
  787. crtcs_for_connector |= encoder->possible_crtcs;
  788. crtc = get_crtc_by_id(dev, encoder->crtc_id);
  789. if (!crtc)
  790. continue;
  791. active_crtcs |= get_crtc_mask(dev, crtc);
  792. }
  793. possible_crtcs &= crtcs_for_connector;
  794. }
  795. if (!possible_crtcs)
  796. return NULL;
  797. /* Return the first possible and active CRTC if one exists, or the first
  798. * possible CRTC otherwise.
  799. */
  800. if (possible_crtcs & active_crtcs)
  801. crtc_idx = ffs(possible_crtcs & active_crtcs);
  802. else
  803. crtc_idx = ffs(possible_crtcs);
  804. return &dev->resources->crtcs[crtc_idx - 1];
  805. }
  806. static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe)
  807. {
  808. drmModeModeInfo *mode = NULL;
  809. int i;
  810. pipe->mode = NULL;
  811. for (i = 0; i < (int)pipe->num_cons; i++) {
  812. mode = connector_find_mode(dev, pipe->con_ids[i],
  813. pipe->mode_str, pipe->vrefresh);
  814. if (mode == NULL) {
  815. if (pipe->vrefresh)
  816. fprintf(stderr,
  817. "failed to find mode "
  818. "\"%s-%.2fHz\" for connector %s\n",
  819. pipe->mode_str, pipe->vrefresh, pipe->cons[i]);
  820. else
  821. fprintf(stderr,
  822. "failed to find mode \"%s\" for connector %s\n",
  823. pipe->mode_str, pipe->cons[i]);
  824. return -EINVAL;
  825. }
  826. }
  827. /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise
  828. * locate a CRTC that can be attached to all the connectors.
  829. */
  830. if (pipe->crtc_id != (uint32_t)-1) {
  831. pipe->crtc = get_crtc_by_id(dev, pipe->crtc_id);
  832. } else {
  833. pipe->crtc = pipe_find_crtc(dev, pipe);
  834. pipe->crtc_id = pipe->crtc->crtc->crtc_id;
  835. }
  836. if (!pipe->crtc) {
  837. fprintf(stderr, "failed to find CRTC for pipe\n");
  838. return -EINVAL;
  839. }
  840. pipe->mode = mode;
  841. pipe->crtc->mode = mode;
  842. return 0;
  843. }
  844. /* -----------------------------------------------------------------------------
  845. * Properties
  846. */
  847. struct property_arg {
  848. uint32_t obj_id;
  849. uint32_t obj_type;
  850. char name[DRM_PROP_NAME_LEN+1];
  851. uint32_t prop_id;
  852. uint64_t value;
  853. bool optional;
  854. };
  855. static bool set_property(struct device *dev, struct property_arg *p)
  856. {
  857. drmModeObjectProperties *props = NULL;
  858. drmModePropertyRes **props_info = NULL;
  859. const char *obj_type;
  860. int ret;
  861. int i;
  862. p->obj_type = 0;
  863. p->prop_id = 0;
  864. #define find_object(_res, type, Type) \
  865. do { \
  866. for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \
  867. struct type *obj = &(_res)->type##s[i]; \
  868. if (obj->type->type##_id != p->obj_id) \
  869. continue; \
  870. p->obj_type = DRM_MODE_OBJECT_##Type; \
  871. obj_type = #Type; \
  872. props = obj->props; \
  873. props_info = obj->props_info; \
  874. } \
  875. } while(0) \
  876. find_object(dev->resources, crtc, CRTC);
  877. if (p->obj_type == 0)
  878. find_object(dev->resources, connector, CONNECTOR);
  879. if (p->obj_type == 0)
  880. find_object(dev->resources, plane, PLANE);
  881. if (p->obj_type == 0) {
  882. fprintf(stderr, "Object %i not found, can't set property\n",
  883. p->obj_id);
  884. return false;
  885. }
  886. if (!props) {
  887. fprintf(stderr, "%s %i has no properties\n",
  888. obj_type, p->obj_id);
  889. return false;
  890. }
  891. for (i = 0; i < (int)props->count_props; ++i) {
  892. if (!props_info[i])
  893. continue;
  894. if (strcmp(props_info[i]->name, p->name) == 0)
  895. break;
  896. }
  897. if (i == (int)props->count_props) {
  898. if (!p->optional)
  899. fprintf(stderr, "%s %i has no %s property\n",
  900. obj_type, p->obj_id, p->name);
  901. return false;
  902. }
  903. p->prop_id = props->props[i];
  904. if (!dev->use_atomic)
  905. ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type,
  906. p->prop_id, p->value);
  907. else
  908. ret = drmModeAtomicAddProperty(dev->req, p->obj_id, p->prop_id, p->value);
  909. if (ret < 0)
  910. fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n",
  911. obj_type, p->obj_id, p->name, p->value, strerror(-ret));
  912. return true;
  913. }
  914. /* -------------------------------------------------------------------------- */
  915. static void
  916. page_flip_handler(int fd, unsigned int frame,
  917. unsigned int sec, unsigned int usec, void *data)
  918. {
  919. struct pipe_arg *pipe;
  920. unsigned int new_fb_id;
  921. struct timeval end;
  922. double t;
  923. pipe = data;
  924. if (pipe->current_fb_id == pipe->fb_id[0])
  925. new_fb_id = pipe->fb_id[1];
  926. else
  927. new_fb_id = pipe->fb_id[0];
  928. drmModePageFlip(fd, pipe->crtc_id, new_fb_id,
  929. DRM_MODE_PAGE_FLIP_EVENT, pipe);
  930. pipe->current_fb_id = new_fb_id;
  931. pipe->swap_count++;
  932. if (pipe->swap_count == 60) {
  933. gettimeofday(&end, NULL);
  934. t = end.tv_sec + end.tv_usec * 1e-6 -
  935. (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6);
  936. fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t);
  937. pipe->swap_count = 0;
  938. pipe->start = end;
  939. }
  940. }
  941. static bool format_support(const drmModePlanePtr ovr, uint32_t fmt)
  942. {
  943. unsigned int i;
  944. for (i = 0; i < ovr->count_formats; ++i) {
  945. if (ovr->formats[i] == fmt)
  946. return true;
  947. }
  948. return false;
  949. }
  950. static void add_property(struct device *dev, uint32_t obj_id,
  951. const char *name, uint64_t value)
  952. {
  953. struct property_arg p;
  954. p.obj_id = obj_id;
  955. strcpy(p.name, name);
  956. p.value = value;
  957. set_property(dev, &p);
  958. }
  959. static bool add_property_optional(struct device *dev, uint32_t obj_id,
  960. const char *name, uint64_t value)
  961. {
  962. struct property_arg p;
  963. p.obj_id = obj_id;
  964. strcpy(p.name, name);
  965. p.value = value;
  966. p.optional = true;
  967. return set_property(dev, &p);
  968. }
  969. static void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc)
  970. {
  971. unsigned blob_id = 0;
  972. const struct util_format_info *info;
  973. /* TODO: support 1024-sized LUTs, when the use-case arises */
  974. struct drm_color_lut gamma_lut[256];
  975. int i, ret;
  976. info = util_format_info_find(fourcc);
  977. if (info->ncolors) {
  978. memset(gamma_lut, 0, sizeof(gamma_lut));
  979. /* TODO: Add index support for more patterns */
  980. util_smpte_fill_lut(info->ncolors, gamma_lut);
  981. drmModeCreatePropertyBlob(dev->fd, gamma_lut, sizeof(gamma_lut), &blob_id);
  982. } else {
  983. /*
  984. * Initialize gamma_lut to a linear table for the legacy API below.
  985. * The modern property API resets to a linear/pass-thru table if blob_id
  986. * is 0, hence no PropertyBlob is created here.
  987. */
  988. for (i = 0; i < 256; i++) {
  989. gamma_lut[i].red =
  990. gamma_lut[i].green =
  991. gamma_lut[i].blue = i << 8;
  992. }
  993. }
  994. add_property_optional(dev, crtc_id, "DEGAMMA_LUT", 0);
  995. add_property_optional(dev, crtc_id, "CTM", 0);
  996. if (!add_property_optional(dev, crtc_id, "GAMMA_LUT", blob_id)) {
  997. /* If we can't add the GAMMA_LUT property, try the legacy API. */
  998. uint16_t r[256], g[256], b[256];
  999. for (i = 0; i < 256; i++) {
  1000. r[i] = gamma_lut[i].red;
  1001. g[i] = gamma_lut[i].green;
  1002. b[i] = gamma_lut[i].blue;
  1003. }
  1004. ret = drmModeCrtcSetGamma(dev->fd, crtc_id, 256, r, g, b);
  1005. if (ret && errno != ENOSYS)
  1006. fprintf(stderr, "failed to set gamma: %s\n", strerror(errno));
  1007. }
  1008. }
  1009. static int
  1010. bo_fb_create(int fd, unsigned int fourcc, const uint32_t w, const uint32_t h,
  1011. enum util_fill_pattern pat, struct bo **out_bo, unsigned int *out_fb_id)
  1012. {
  1013. uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
  1014. struct bo *bo;
  1015. unsigned int fb_id;
  1016. bo = bo_create(fd, fourcc, w, h, handles, pitches, offsets, pat, pattern_seed);
  1017. if (bo == NULL)
  1018. return -1;
  1019. if (drmModeAddFB2(fd, w, h, fourcc, handles, pitches, offsets, &fb_id, 0)) {
  1020. fprintf(stderr, "failed to add fb (%ux%u): %s\n", w, h, strerror(errno));
  1021. bo_destroy(bo);
  1022. return -1;
  1023. }
  1024. *out_bo = bo;
  1025. *out_fb_id = fb_id;
  1026. return 0;
  1027. }
  1028. static int atomic_set_plane(struct device *dev, struct plane_arg *p,
  1029. int pattern, bool update)
  1030. {
  1031. struct bo *plane_bo;
  1032. int crtc_x, crtc_y, crtc_w, crtc_h;
  1033. struct crtc *crtc = NULL;
  1034. unsigned int old_fb_id;
  1035. /* Find an unused plane which can be connected to our CRTC. Find the
  1036. * CRTC index first, then iterate over available planes.
  1037. */
  1038. crtc = get_crtc_by_id(dev, p->crtc_id);
  1039. if (!crtc) {
  1040. fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
  1041. return -1;
  1042. }
  1043. if (!update)
  1044. fprintf(stderr, "testing %dx%d@%s on plane %u, crtc %u\n",
  1045. p->w, p->h, p->format_str, p->plane_id, p->crtc_id);
  1046. plane_bo = p->old_bo;
  1047. p->old_bo = p->bo;
  1048. if (!plane_bo) {
  1049. if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h,
  1050. pattern, &plane_bo, &p->fb_id))
  1051. return -1;
  1052. }
  1053. p->bo = plane_bo;
  1054. old_fb_id = p->fb_id;
  1055. p->old_fb_id = old_fb_id;
  1056. crtc_w = p->w * p->scale;
  1057. crtc_h = p->h * p->scale;
  1058. if (!p->has_position) {
  1059. /* Default to the middle of the screen */
  1060. crtc_x = (crtc->mode->hdisplay - crtc_w) / 2;
  1061. crtc_y = (crtc->mode->vdisplay - crtc_h) / 2;
  1062. } else {
  1063. crtc_x = p->x;
  1064. crtc_y = p->y;
  1065. }
  1066. add_property(dev, p->plane_id, "FB_ID", p->fb_id);
  1067. add_property(dev, p->plane_id, "CRTC_ID", p->crtc_id);
  1068. add_property(dev, p->plane_id, "SRC_X", 0);
  1069. add_property(dev, p->plane_id, "SRC_Y", 0);
  1070. add_property(dev, p->plane_id, "SRC_W", p->w << 16);
  1071. add_property(dev, p->plane_id, "SRC_H", p->h << 16);
  1072. add_property(dev, p->plane_id, "CRTC_X", crtc_x);
  1073. add_property(dev, p->plane_id, "CRTC_Y", crtc_y);
  1074. add_property(dev, p->plane_id, "CRTC_W", crtc_w);
  1075. add_property(dev, p->plane_id, "CRTC_H", crtc_h);
  1076. return 0;
  1077. }
  1078. static int set_plane(struct device *dev, struct plane_arg *p)
  1079. {
  1080. drmModePlane *ovr;
  1081. uint32_t plane_id;
  1082. int crtc_x, crtc_y, crtc_w, crtc_h;
  1083. struct crtc *crtc = NULL;
  1084. unsigned int i, crtc_mask;
  1085. /* Find an unused plane which can be connected to our CRTC. Find the
  1086. * CRTC index first, then iterate over available planes.
  1087. */
  1088. crtc = get_crtc_by_id(dev, p->crtc_id);
  1089. if (!crtc) {
  1090. fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
  1091. return -1;
  1092. }
  1093. crtc_mask = get_crtc_mask(dev, crtc);
  1094. plane_id = p->plane_id;
  1095. for (i = 0; i < dev->resources->count_planes; i++) {
  1096. ovr = dev->resources->planes[i].plane;
  1097. if (!ovr)
  1098. continue;
  1099. if (plane_id && plane_id != ovr->plane_id)
  1100. continue;
  1101. if (!format_support(ovr, p->fourcc))
  1102. continue;
  1103. if ((ovr->possible_crtcs & crtc_mask) &&
  1104. (ovr->crtc_id == 0 || ovr->crtc_id == p->crtc_id)) {
  1105. plane_id = ovr->plane_id;
  1106. break;
  1107. }
  1108. }
  1109. if (i == dev->resources->count_planes) {
  1110. fprintf(stderr, "no unused plane available for CRTC %u\n",
  1111. p->crtc_id);
  1112. return -1;
  1113. }
  1114. fprintf(stderr, "testing %dx%d@%s overlay plane %u\n",
  1115. p->w, p->h, p->format_str, plane_id);
  1116. /* just use single plane format for now.. */
  1117. if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h,
  1118. secondary_fill, &p->bo, &p->fb_id))
  1119. return -1;
  1120. crtc_w = p->w * p->scale;
  1121. crtc_h = p->h * p->scale;
  1122. if (!p->has_position) {
  1123. /* Default to the middle of the screen */
  1124. crtc_x = (crtc->mode->hdisplay - crtc_w) / 2;
  1125. crtc_y = (crtc->mode->vdisplay - crtc_h) / 2;
  1126. } else {
  1127. crtc_x = p->x;
  1128. crtc_y = p->y;
  1129. }
  1130. /* note src coords (last 4 args) are in Q16 format */
  1131. if (drmModeSetPlane(dev->fd, plane_id, p->crtc_id, p->fb_id,
  1132. 0, crtc_x, crtc_y, crtc_w, crtc_h,
  1133. 0, 0, p->w << 16, p->h << 16)) {
  1134. fprintf(stderr, "failed to enable plane: %s\n",
  1135. strerror(errno));
  1136. return -1;
  1137. }
  1138. ovr->crtc_id = p->crtc_id;
  1139. return 0;
  1140. }
  1141. static void atomic_set_planes(struct device *dev, struct plane_arg *p,
  1142. unsigned int count, bool update)
  1143. {
  1144. unsigned int i, pattern = primary_fill;
  1145. /* set up planes */
  1146. for (i = 0; i < count; i++) {
  1147. if (i > 0)
  1148. pattern = secondary_fill;
  1149. else
  1150. set_gamma(dev, p[i].crtc_id, p[i].fourcc);
  1151. if (atomic_set_plane(dev, &p[i], pattern, update))
  1152. return;
  1153. }
  1154. }
  1155. static void
  1156. atomic_test_page_flip(struct device *dev, struct pipe_arg *pipe_args,
  1157. struct plane_arg *plane_args, unsigned int plane_count)
  1158. {
  1159. int ret;
  1160. gettimeofday(&pipe_args->start, NULL);
  1161. pipe_args->swap_count = 0;
  1162. while (true) {
  1163. drmModeAtomicFree(dev->req);
  1164. dev->req = drmModeAtomicAlloc();
  1165. atomic_set_planes(dev, plane_args, plane_count, true);
  1166. ret = drmModeAtomicCommit(dev->fd, dev->req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
  1167. if (ret) {
  1168. fprintf(stderr, "Atomic Commit failed [2]\n");
  1169. return;
  1170. }
  1171. pipe_args->swap_count++;
  1172. if (pipe_args->swap_count == 60) {
  1173. struct timeval end;
  1174. double t;
  1175. gettimeofday(&end, NULL);
  1176. t = end.tv_sec + end.tv_usec * 1e-6 -
  1177. (pipe_args->start.tv_sec + pipe_args->start.tv_usec * 1e-6);
  1178. fprintf(stderr, "freq: %.02fHz\n", pipe_args->swap_count / t);
  1179. pipe_args->swap_count = 0;
  1180. pipe_args->start = end;
  1181. }
  1182. }
  1183. }
  1184. static void atomic_clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
  1185. {
  1186. unsigned int i;
  1187. for (i = 0; i < count; i++) {
  1188. add_property(dev, p[i].plane_id, "FB_ID", 0);
  1189. add_property(dev, p[i].plane_id, "CRTC_ID", 0);
  1190. add_property(dev, p[i].plane_id, "SRC_X", 0);
  1191. add_property(dev, p[i].plane_id, "SRC_Y", 0);
  1192. add_property(dev, p[i].plane_id, "SRC_W", 0);
  1193. add_property(dev, p[i].plane_id, "SRC_H", 0);
  1194. add_property(dev, p[i].plane_id, "CRTC_X", 0);
  1195. add_property(dev, p[i].plane_id, "CRTC_Y", 0);
  1196. add_property(dev, p[i].plane_id, "CRTC_W", 0);
  1197. add_property(dev, p[i].plane_id, "CRTC_H", 0);
  1198. }
  1199. }
  1200. static void atomic_clear_FB(struct device *dev, struct plane_arg *p, unsigned int count)
  1201. {
  1202. unsigned int i;
  1203. for (i = 0; i < count; i++) {
  1204. if (p[i].fb_id) {
  1205. drmModeRmFB(dev->fd, p[i].fb_id);
  1206. p[i].fb_id = 0;
  1207. }
  1208. if (p[i].old_fb_id) {
  1209. drmModeRmFB(dev->fd, p[i].old_fb_id);
  1210. p[i].old_fb_id = 0;
  1211. }
  1212. if (p[i].bo) {
  1213. bo_destroy(p[i].bo);
  1214. p[i].bo = NULL;
  1215. }
  1216. if (p[i].old_bo) {
  1217. bo_destroy(p[i].old_bo);
  1218. p[i].old_bo = NULL;
  1219. }
  1220. }
  1221. }
  1222. static void clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
  1223. {
  1224. unsigned int i;
  1225. for (i = 0; i < count; i++) {
  1226. if (p[i].fb_id)
  1227. drmModeRmFB(dev->fd, p[i].fb_id);
  1228. if (p[i].bo)
  1229. bo_destroy(p[i].bo);
  1230. }
  1231. }
  1232. static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe)
  1233. {
  1234. drmModeConnector *connector;
  1235. unsigned int i;
  1236. uint32_t id;
  1237. char *endp;
  1238. for (i = 0; i < pipe->num_cons; i++) {
  1239. id = strtoul(pipe->cons[i], &endp, 10);
  1240. if (endp == pipe->cons[i]) {
  1241. connector = get_connector_by_name(dev, pipe->cons[i]);
  1242. if (!connector) {
  1243. fprintf(stderr, "no connector named '%s'\n",
  1244. pipe->cons[i]);
  1245. return -ENODEV;
  1246. }
  1247. id = connector->connector_id;
  1248. }
  1249. pipe->con_ids[i] = id;
  1250. }
  1251. return 0;
  1252. }
  1253. static bool pipe_has_writeback_connector(struct device *dev, struct pipe_arg *pipes,
  1254. unsigned int count)
  1255. {
  1256. drmModeConnector *connector;
  1257. unsigned int i, j;
  1258. for (j = 0; j < count; j++) {
  1259. struct pipe_arg *pipe = &pipes[j];
  1260. for (i = 0; i < pipe->num_cons; i++) {
  1261. connector = get_connector_by_id(dev, pipe->con_ids[i]);
  1262. if (connector && connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
  1263. return true;
  1264. }
  1265. }
  1266. return false;
  1267. }
  1268. static int pipe_attempt_connector(struct device *dev, drmModeConnector *con,
  1269. struct pipe_arg *pipe)
  1270. {
  1271. char *con_str;
  1272. int i;
  1273. con_str = calloc(8, sizeof(char));
  1274. if (!con_str)
  1275. return -1;
  1276. sprintf(con_str, "%d", con->connector_id);
  1277. strcpy(pipe->format_str, "XR24");
  1278. pipe->fourcc = util_format_fourcc(pipe->format_str);
  1279. pipe->num_cons = 1;
  1280. pipe->con_ids = calloc(1, sizeof(*pipe->con_ids));
  1281. pipe->cons = calloc(1, sizeof(*pipe->cons));
  1282. if (!pipe->con_ids || !pipe->cons)
  1283. goto free_con_str;
  1284. pipe->con_ids[0] = con->connector_id;
  1285. pipe->cons[0] = (const char*)con_str;
  1286. pipe->crtc = pipe_find_crtc(dev, pipe);
  1287. if (!pipe->crtc)
  1288. goto free_all;
  1289. pipe->crtc_id = pipe->crtc->crtc->crtc_id;
  1290. /* Return the first mode if no preferred. */
  1291. pipe->mode = &con->modes[0];
  1292. for (i = 0; i < con->count_modes; i++) {
  1293. drmModeModeInfo *current_mode = &con->modes[i];
  1294. if (current_mode->type & DRM_MODE_TYPE_PREFERRED) {
  1295. pipe->mode = current_mode;
  1296. break;
  1297. }
  1298. }
  1299. sprintf(pipe->mode_str, "%dx%d", pipe->mode->hdisplay, pipe->mode->vdisplay);
  1300. return 0;
  1301. free_all:
  1302. free(pipe->cons);
  1303. free(pipe->con_ids);
  1304. free_con_str:
  1305. free(con_str);
  1306. return -1;
  1307. }
  1308. static int pipe_find_preferred(struct device *dev, struct pipe_arg **out_pipes)
  1309. {
  1310. struct pipe_arg *pipes;
  1311. struct resources *res = dev->resources;
  1312. drmModeConnector *con = NULL;
  1313. int i, connected = 0, attempted = 0;
  1314. for (i = 0; i < res->count_connectors; i++) {
  1315. con = res->connectors[i].connector;
  1316. if (!con || con->connection != DRM_MODE_CONNECTED ||
  1317. con->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
  1318. continue;
  1319. connected++;
  1320. }
  1321. if (!connected) {
  1322. printf("no connected connector!\n");
  1323. return 0;
  1324. }
  1325. pipes = calloc(connected, sizeof(struct pipe_arg));
  1326. if (!pipes)
  1327. return 0;
  1328. for (i = 0; i < res->count_connectors && attempted < connected; i++) {
  1329. con = res->connectors[i].connector;
  1330. if (!con || con->connection != DRM_MODE_CONNECTED)
  1331. continue;
  1332. if (pipe_attempt_connector(dev, con, &pipes[attempted]) < 0) {
  1333. printf("failed fetching preferred mode for connector\n");
  1334. continue;
  1335. }
  1336. attempted++;
  1337. }
  1338. *out_pipes = pipes;
  1339. return attempted;
  1340. }
  1341. static struct plane *get_primary_plane_by_crtc(struct device *dev, struct crtc *crtc)
  1342. {
  1343. unsigned int i;
  1344. for (i = 0; i < dev->resources->count_planes; i++) {
  1345. struct plane *plane = &dev->resources->planes[i];
  1346. drmModePlane *ovr = plane->plane;
  1347. if (!ovr)
  1348. continue;
  1349. // XXX: add is_primary_plane and (?) format checks
  1350. if (ovr->possible_crtcs & get_crtc_mask(dev, crtc))
  1351. return plane;
  1352. }
  1353. return NULL;
  1354. }
  1355. static unsigned int set_mode(struct device *dev, struct pipe_arg **pipe_args, unsigned int count)
  1356. {
  1357. unsigned int i, j;
  1358. int ret, x = 0;
  1359. int preferred = count == 0;
  1360. struct pipe_arg *pipes;
  1361. if (preferred) {
  1362. count = pipe_find_preferred(dev, pipe_args);
  1363. if (!count) {
  1364. fprintf(stderr, "can't find any preferred connector/mode.\n");
  1365. return 0;
  1366. }
  1367. pipes = *pipe_args;
  1368. } else {
  1369. pipes = *pipe_args;
  1370. for (i = 0; i < count; i++) {
  1371. struct pipe_arg *pipe = &pipes[i];
  1372. ret = pipe_resolve_connectors(dev, pipe);
  1373. if (ret < 0)
  1374. return 0;
  1375. ret = pipe_find_crtc_and_mode(dev, pipe);
  1376. if (ret < 0)
  1377. continue;
  1378. }
  1379. }
  1380. if (!dev->use_atomic) {
  1381. for (i = 0; i < count; i++) {
  1382. struct pipe_arg *pipe = &pipes[i];
  1383. if (pipe->mode == NULL)
  1384. continue;
  1385. if (!preferred) {
  1386. dev->mode.width += pipe->mode->hdisplay;
  1387. if (dev->mode.height < pipe->mode->vdisplay)
  1388. dev->mode.height = pipe->mode->vdisplay;
  1389. } else {
  1390. /* XXX: Use a clone mode, more like atomic. We could do per
  1391. * connector bo/fb, so we don't have the stretched image.
  1392. */
  1393. if (dev->mode.width < pipe->mode->hdisplay)
  1394. dev->mode.width = pipe->mode->hdisplay;
  1395. if (dev->mode.height < pipe->mode->vdisplay)
  1396. dev->mode.height = pipe->mode->vdisplay;
  1397. }
  1398. }
  1399. if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height,
  1400. primary_fill, &dev->mode.bo, &dev->mode.fb_id))
  1401. return 0;
  1402. }
  1403. for (i = 0; i < count; i++) {
  1404. struct pipe_arg *pipe = &pipes[i];
  1405. uint32_t blob_id;
  1406. if (pipe->mode == NULL)
  1407. continue;
  1408. printf("setting mode %s-%.2fHz on connectors ",
  1409. pipe->mode->name, mode_vrefresh(pipe->mode));
  1410. for (j = 0; j < pipe->num_cons; ++j) {
  1411. printf("%s, ", pipe->cons[j]);
  1412. if (dev->use_atomic)
  1413. add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc_id);
  1414. }
  1415. printf("crtc %d\n", pipe->crtc_id);
  1416. if (!dev->use_atomic) {
  1417. ret = drmModeSetCrtc(dev->fd, pipe->crtc_id, dev->mode.fb_id,
  1418. x, 0, pipe->con_ids, pipe->num_cons,
  1419. pipe->mode);
  1420. /* XXX: Actually check if this is needed */
  1421. drmModeDirtyFB(dev->fd, dev->mode.fb_id, NULL, 0);
  1422. if (!preferred)
  1423. x += pipe->mode->hdisplay;
  1424. if (ret) {
  1425. fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
  1426. return 0;
  1427. }
  1428. set_gamma(dev, pipe->crtc_id, pipe->fourcc);
  1429. } else {
  1430. drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id);
  1431. add_property(dev, pipe->crtc_id, "MODE_ID", blob_id);
  1432. add_property(dev, pipe->crtc_id, "ACTIVE", 1);
  1433. /* By default atomic modeset does not set a primary plane, shrug */
  1434. if (preferred) {
  1435. struct plane *plane = get_primary_plane_by_crtc(dev, pipe->crtc);
  1436. struct plane_arg plane_args = {
  1437. .plane_id = plane->plane->plane_id,
  1438. .crtc_id = pipe->crtc_id,
  1439. .w = pipe->mode->hdisplay,
  1440. .h = pipe->mode->vdisplay,
  1441. .scale = 1.0,
  1442. .format_str = "XR24",
  1443. .fourcc = util_format_fourcc(pipe->format_str),
  1444. };
  1445. atomic_set_planes(dev, &plane_args, 1, false);
  1446. }
  1447. }
  1448. }
  1449. return count;
  1450. }
  1451. static void writeback_config(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  1452. {
  1453. drmModeConnector *connector;
  1454. unsigned int i, j;
  1455. for (j = 0; j < count; j++) {
  1456. struct pipe_arg *pipe = &pipes[j];
  1457. for (i = 0; i < pipe->num_cons; i++) {
  1458. connector = get_connector_by_id(dev, pipe->con_ids[i]);
  1459. if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) {
  1460. if (!pipe->mode) {
  1461. fprintf(stderr, "no mode for writeback\n");
  1462. return;
  1463. }
  1464. bo_fb_create(dev->fd, pipes[j].fourcc,
  1465. pipe->mode->hdisplay, pipe->mode->vdisplay,
  1466. UTIL_PATTERN_PLAIN,
  1467. &pipe->out_bo, &pipe->out_fb_id);
  1468. add_property(dev, pipe->con_ids[i], "WRITEBACK_FB_ID",
  1469. pipe->out_fb_id);
  1470. add_property(dev, pipe->con_ids[i], "WRITEBACK_OUT_FENCE_PTR",
  1471. (uintptr_t)(&dev->writeback_fence_fd));
  1472. }
  1473. }
  1474. }
  1475. }
  1476. static int poll_writeback_fence(int fd, int timeout)
  1477. {
  1478. struct pollfd fds = { fd, POLLIN };
  1479. int ret;
  1480. do {
  1481. ret = poll(&fds, 1, timeout);
  1482. if (ret > 0) {
  1483. if (fds.revents & (POLLERR | POLLNVAL))
  1484. return -EINVAL;
  1485. return 0;
  1486. } else if (ret == 0) {
  1487. return -ETIMEDOUT;
  1488. } else {
  1489. ret = -errno;
  1490. if (ret == -EINTR || ret == -EAGAIN)
  1491. continue;
  1492. return ret;
  1493. }
  1494. } while (1);
  1495. }
  1496. static void dump_output_fb(struct device *dev, struct pipe_arg *pipes, char *dump_path,
  1497. unsigned int count)
  1498. {
  1499. drmModeConnector *connector;
  1500. unsigned int i, j;
  1501. for (j = 0; j < count; j++) {
  1502. struct pipe_arg *pipe = &pipes[j];
  1503. for (i = 0; i < pipe->num_cons; i++) {
  1504. connector = get_connector_by_id(dev, pipe->con_ids[i]);
  1505. if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
  1506. bo_dump(pipe->out_bo, dump_path);
  1507. }
  1508. }
  1509. }
  1510. static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  1511. {
  1512. unsigned int i;
  1513. unsigned int j;
  1514. for (i = 0; i < count; i++) {
  1515. struct pipe_arg *pipe = &pipes[i];
  1516. if (pipe->mode == NULL)
  1517. continue;
  1518. for (j = 0; j < pipe->num_cons; ++j)
  1519. add_property(dev, pipe->con_ids[j], "CRTC_ID",0);
  1520. add_property(dev, pipe->crtc_id, "MODE_ID", 0);
  1521. add_property(dev, pipe->crtc_id, "ACTIVE", 0);
  1522. }
  1523. }
  1524. static void clear_mode(struct device *dev)
  1525. {
  1526. if (dev->mode.fb_id)
  1527. drmModeRmFB(dev->fd, dev->mode.fb_id);
  1528. if (dev->mode.bo)
  1529. bo_destroy(dev->mode.bo);
  1530. }
  1531. static void set_planes(struct device *dev, struct plane_arg *p, unsigned int count)
  1532. {
  1533. unsigned int i;
  1534. /* set up planes/overlays */
  1535. for (i = 0; i < count; i++)
  1536. if (set_plane(dev, &p[i]))
  1537. return;
  1538. }
  1539. static void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  1540. {
  1541. uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
  1542. uint32_t cw = 64;
  1543. uint32_t ch = 64;
  1544. struct bo *bo;
  1545. uint64_t value;
  1546. unsigned int i;
  1547. int ret;
  1548. ret = drmGetCap(dev->fd, DRM_CAP_CURSOR_WIDTH, &value);
  1549. if (!ret)
  1550. cw = value;
  1551. ret = drmGetCap(dev->fd, DRM_CAP_CURSOR_HEIGHT, &value);
  1552. if (!ret)
  1553. ch = value;
  1554. /* create cursor bo.. just using PATTERN_PLAIN as it has
  1555. * translucent alpha
  1556. */
  1557. bo = bo_create(dev->fd, DRM_FORMAT_ARGB8888, cw, ch, handles, pitches,
  1558. offsets, UTIL_PATTERN_PLAIN, pattern_seed);
  1559. if (bo == NULL)
  1560. return;
  1561. dev->mode.cursor_bo = bo;
  1562. for (i = 0; i < count; i++) {
  1563. struct pipe_arg *pipe = &pipes[i];
  1564. ret = cursor_init(dev->fd, handles[0],
  1565. pipe->crtc_id,
  1566. pipe->mode->hdisplay, pipe->mode->vdisplay,
  1567. cw, ch);
  1568. if (ret) {
  1569. fprintf(stderr, "failed to init cursor for CRTC[%u]\n",
  1570. pipe->crtc_id);
  1571. return;
  1572. }
  1573. }
  1574. cursor_start();
  1575. }
  1576. static void clear_cursors(struct device *dev)
  1577. {
  1578. cursor_stop();
  1579. if (dev->mode.cursor_bo)
  1580. bo_destroy(dev->mode.cursor_bo);
  1581. }
  1582. static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  1583. {
  1584. unsigned int other_fb_id;
  1585. struct bo *other_bo;
  1586. drmEventContext evctx;
  1587. unsigned int i;
  1588. int ret;
  1589. if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height,
  1590. UTIL_PATTERN_PLAIN, &other_bo, &other_fb_id))
  1591. return;
  1592. for (i = 0; i < count; i++) {
  1593. struct pipe_arg *pipe = &pipes[i];
  1594. if (pipe->mode == NULL)
  1595. continue;
  1596. ret = drmModePageFlip(dev->fd, pipe->crtc_id,
  1597. other_fb_id, DRM_MODE_PAGE_FLIP_EVENT,
  1598. pipe);
  1599. if (ret) {
  1600. fprintf(stderr, "failed to page flip: %s\n", strerror(errno));
  1601. goto err_rmfb;
  1602. }
  1603. gettimeofday(&pipe->start, NULL);
  1604. pipe->swap_count = 0;
  1605. pipe->fb_id[0] = dev->mode.fb_id;
  1606. pipe->fb_id[1] = other_fb_id;
  1607. pipe->current_fb_id = other_fb_id;
  1608. }
  1609. memset(&evctx, 0, sizeof evctx);
  1610. evctx.version = DRM_EVENT_CONTEXT_VERSION;
  1611. evctx.vblank_handler = NULL;
  1612. evctx.page_flip_handler = page_flip_handler;
  1613. while (1) {
  1614. #if 0
  1615. struct pollfd pfd[2];
  1616. pfd[0].fd = 0;
  1617. pfd[0].events = POLLIN;
  1618. pfd[1].fd = fd;
  1619. pfd[1].events = POLLIN;
  1620. if (poll(pfd, 2, -1) < 0) {
  1621. fprintf(stderr, "poll error\n");
  1622. break;
  1623. }
  1624. if (pfd[0].revents)
  1625. break;
  1626. #else
  1627. struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
  1628. fd_set fds;
  1629. FD_ZERO(&fds);
  1630. FD_SET(0, &fds);
  1631. FD_SET(dev->fd, &fds);
  1632. ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout);
  1633. if (ret <= 0) {
  1634. fprintf(stderr, "select timed out or error (ret %d)\n",
  1635. ret);
  1636. continue;
  1637. } else if (FD_ISSET(0, &fds)) {
  1638. break;
  1639. }
  1640. #endif
  1641. drmHandleEvent(dev->fd, &evctx);
  1642. }
  1643. err_rmfb:
  1644. drmModeRmFB(dev->fd, other_fb_id);
  1645. bo_destroy(other_bo);
  1646. }
  1647. #define min(a, b) ((a) < (b) ? (a) : (b))
  1648. static int parse_connector(struct pipe_arg *pipe, const char *arg)
  1649. {
  1650. unsigned int len;
  1651. unsigned int i;
  1652. const char *p;
  1653. const char *endp;
  1654. char *endp_tok;
  1655. pipe->vrefresh = 0;
  1656. pipe->crtc_id = (uint32_t)-1;
  1657. strcpy(pipe->format_str, "XR24");
  1658. /* Count the number of connectors and allocate them. */
  1659. pipe->num_cons = 1;
  1660. for (p = arg; *p && *p != ':' && *p != '@'; ++p) {
  1661. if (*p == ',')
  1662. pipe->num_cons++;
  1663. }
  1664. pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids));
  1665. pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons));
  1666. if (pipe->con_ids == NULL || pipe->cons == NULL)
  1667. return -1;
  1668. /* Parse the connectors. */
  1669. for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) {
  1670. endp = strpbrk(p, ",@:");
  1671. if (!endp)
  1672. break;
  1673. pipe->cons[i] = strndup(p, endp - p);
  1674. if (*endp != ',')
  1675. break;
  1676. }
  1677. if (i != pipe->num_cons - 1)
  1678. return -1;
  1679. /* Parse the remaining parameters. */
  1680. if (!endp)
  1681. return -1;
  1682. if (*endp == '@') {
  1683. arg = endp + 1;
  1684. pipe->crtc_id = strtoul(arg, &endp_tok, 10);
  1685. endp = endp_tok;
  1686. }
  1687. if (*endp != ':')
  1688. return -1;
  1689. arg = endp + 1;
  1690. /* Search for the vertical refresh or the format. */
  1691. p = strpbrk(arg, "-@");
  1692. if (p == NULL)
  1693. p = arg + strlen(arg);
  1694. len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg));
  1695. strncpy(pipe->mode_str, arg, len);
  1696. pipe->mode_str[len] = '\0';
  1697. if (*p == '-') {
  1698. pipe->vrefresh = strtof(p + 1, &endp_tok);
  1699. p = endp_tok;
  1700. }
  1701. if (*p == '@') {
  1702. len = sizeof(pipe->format_str) - 1;
  1703. strncpy(pipe->format_str, p + 1, len);
  1704. pipe->format_str[len] = '\0';
  1705. }
  1706. pipe->fourcc = util_format_fourcc(pipe->format_str);
  1707. if (pipe->fourcc == 0) {
  1708. fprintf(stderr, "unknown format %s\n", pipe->format_str);
  1709. return -1;
  1710. }
  1711. return 0;
  1712. }
  1713. static int parse_plane(struct plane_arg *plane, const char *p)
  1714. {
  1715. unsigned int len;
  1716. char *end;
  1717. plane->plane_id = strtoul(p, &end, 10);
  1718. if (*end != '@')
  1719. return -EINVAL;
  1720. p = end + 1;
  1721. plane->crtc_id = strtoul(p, &end, 10);
  1722. if (*end != ':')
  1723. return -EINVAL;
  1724. p = end + 1;
  1725. plane->w = strtoul(p, &end, 10);
  1726. if (*end != 'x')
  1727. return -EINVAL;
  1728. p = end + 1;
  1729. plane->h = strtoul(p, &end, 10);
  1730. if (*end == '+' || *end == '-') {
  1731. plane->x = strtol(end, &end, 10);
  1732. if (*end != '+' && *end != '-')
  1733. return -EINVAL;
  1734. plane->y = strtol(end, &end, 10);
  1735. plane->has_position = true;
  1736. }
  1737. if (*end == '*') {
  1738. p = end + 1;
  1739. plane->scale = strtod(p, &end);
  1740. if (plane->scale <= 0.0)
  1741. return -EINVAL;
  1742. } else {
  1743. plane->scale = 1.0;
  1744. }
  1745. if (*end == '@') {
  1746. len = sizeof(plane->format_str) - 1;
  1747. strncpy(plane->format_str, end + 1, len);
  1748. plane->format_str[len] = '\0';
  1749. } else {
  1750. strcpy(plane->format_str, "XR24");
  1751. }
  1752. plane->fourcc = util_format_fourcc(plane->format_str);
  1753. if (plane->fourcc == 0) {
  1754. fprintf(stderr, "unknown format %s\n", plane->format_str);
  1755. return -EINVAL;
  1756. }
  1757. return 0;
  1758. }
  1759. static int parse_property(struct property_arg *p, const char *arg)
  1760. {
  1761. if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3)
  1762. return -1;
  1763. p->obj_type = 0;
  1764. p->name[DRM_PROP_NAME_LEN] = '\0';
  1765. return 0;
  1766. }
  1767. static void parse_fill_patterns(char *arg)
  1768. {
  1769. char *fill = strtok(arg, ",");
  1770. if (!fill)
  1771. return;
  1772. primary_fill = util_pattern_enum(fill);
  1773. fill = strtok(NULL, ",");
  1774. if (!fill)
  1775. return;
  1776. secondary_fill = util_pattern_enum(fill);
  1777. }
  1778. static void parse_seed(const char *arg)
  1779. {
  1780. unsigned long seed;
  1781. char *rest;
  1782. seed = strtoul(arg, &rest, 10);
  1783. if (arg != rest)
  1784. pattern_seed = seed;
  1785. }
  1786. static void usage(char *name)
  1787. {
  1788. fprintf(stderr, "usage: %s [-acDdefMoPpsCvrw]\n", name);
  1789. fprintf(stderr, "\n Query options:\n\n");
  1790. fprintf(stderr, "\t-c\tlist connectors\n");
  1791. fprintf(stderr, "\t-e\tlist encoders\n");
  1792. fprintf(stderr, "\t-f\tlist framebuffers\n");
  1793. fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n");
  1794. fprintf(stderr, "\n Test options:\n\n");
  1795. fprintf(stderr, "\t-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane, see 'plane-topology'\n");
  1796. fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:mode[@<format>]\tset a mode, see 'mode-topology'\n");
  1797. fprintf(stderr, "\t\twhere mode can be specified as:\n");
  1798. fprintf(stderr, "\t\t<hdisp>x<vdisp>[-<vrefresh>]\n");
  1799. fprintf(stderr, "\t\t<hdisp>,<hss>,<hse>,<htot>,<vdisp>,<vss>,<vse>,<vtot>-<vrefresh>\n");
  1800. fprintf(stderr, "\t\t#<mode index>\n");
  1801. fprintf(stderr, "\t-C\ttest hw cursor\n");
  1802. fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
  1803. fprintf(stderr, "\t-r\tset the preferred mode for all connectors\n");
  1804. fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property, see 'property'\n");
  1805. fprintf(stderr, "\t-a \tuse atomic API\n");
  1806. fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n");
  1807. fprintf(stderr, "\t-S <random seed>\tspecify seed of noise patterns\n");
  1808. fprintf(stderr, "\t-o <desired file path> \t Dump writeback output buffer to file\n");
  1809. fprintf(stderr, "\n Generic options:\n\n");
  1810. fprintf(stderr, "\t-d\tdrop master after mode set\n");
  1811. fprintf(stderr, "\t-M module\tuse the given driver\n");
  1812. fprintf(stderr, "\t-D device\tuse the given device\n");
  1813. fprintf(stderr, "\n\tDefault is to dump all info.\n");
  1814. fprintf(stderr, "\n");
  1815. fprintf(stderr, "Plane Topology is defined as:\n");
  1816. fprintf(stderr, "\tplane-topology\t::= plane-id '@' crtc-id ':' width 'x' height ( <plane-offsets> )? ;\n");
  1817. fprintf(stderr, "\tplane-offsets\t::= '+' x-offset '+' y-offset ( <plane-scale> )? ;\n");
  1818. fprintf(stderr, "\tplane-scale\t::= '*' scale ( <plane-format> )? ;\n");
  1819. fprintf(stderr, "\tplane-format\t::= '@' format ;\n");
  1820. fprintf(stderr, "\n");
  1821. fprintf(stderr, "Mode Topology is defined as:\n");
  1822. fprintf(stderr, "\tmode-topology\t::= connector-id ( ',' connector-id )* ( '@' crtc-id )? ':' <mode-selection> ( '@' format )? ;\n");
  1823. fprintf(stderr, "\tmode-selection\t::= <indexed-mode> | <named-mode> | <custom-mode> ;\n");
  1824. fprintf(stderr, "\tindexed-mode\t::= '#' mode-index ;\n");
  1825. fprintf(stderr, "\tnamed-mode\t::= width 'x' height ( '-' vrefresh )? ;\n");
  1826. fprintf(stderr, "\tcustom-mode\t::= hdisplay ',' hsyncstart ',' hsyncend ',' htotal ',' vdisplay ',' vsyncstart ',' vsyncend ',' vtotal '-' vrefresh ;\n");
  1827. fprintf(stderr, "\n");
  1828. fprintf(stderr, "Property is defined as:\n");
  1829. fprintf(stderr, "\tproperty\t::= object-id ':' property-name ':' value ;\n");
  1830. exit(0);
  1831. }
  1832. static char optstr[] = "acdD:efF:M:P:ps:Cvrw:o:S:";
  1833. int main(int argc, char **argv)
  1834. {
  1835. struct device dev;
  1836. int c;
  1837. int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0;
  1838. int drop_master = 0;
  1839. int test_vsync = 0;
  1840. int test_cursor = 0;
  1841. int set_preferred = 0;
  1842. int use_atomic = 0;
  1843. char *device = NULL;
  1844. char *module = NULL;
  1845. unsigned int i;
  1846. unsigned int count = 0, plane_count = 0;
  1847. unsigned int prop_count = 0;
  1848. struct pipe_arg *pipe_args = NULL;
  1849. struct plane_arg *plane_args = NULL;
  1850. struct property_arg *prop_args = NULL;
  1851. unsigned int args = 0;
  1852. int ret;
  1853. char *dump_path = NULL;
  1854. memset(&dev, 0, sizeof dev);
  1855. opterr = 0;
  1856. while ((c = getopt(argc, argv, optstr)) != -1) {
  1857. args++;
  1858. switch (c) {
  1859. case 'a':
  1860. use_atomic = 1;
  1861. /* Preserve the default behaviour of dumping all information. */
  1862. args--;
  1863. break;
  1864. case 'c':
  1865. connectors = 1;
  1866. break;
  1867. case 'D':
  1868. device = optarg;
  1869. /* Preserve the default behaviour of dumping all information. */
  1870. args--;
  1871. break;
  1872. case 'd':
  1873. drop_master = 1;
  1874. break;
  1875. case 'e':
  1876. encoders = 1;
  1877. break;
  1878. case 'f':
  1879. framebuffers = 1;
  1880. break;
  1881. case 'F':
  1882. parse_fill_patterns(optarg);
  1883. break;
  1884. case 'M':
  1885. module = optarg;
  1886. /* Preserve the default behaviour of dumping all information. */
  1887. args--;
  1888. break;
  1889. case 'o':
  1890. dump_path = optarg;
  1891. break;
  1892. case 'P':
  1893. plane_args = realloc(plane_args,
  1894. (plane_count + 1) * sizeof *plane_args);
  1895. if (plane_args == NULL) {
  1896. fprintf(stderr, "memory allocation failed\n");
  1897. return 1;
  1898. }
  1899. memset(&plane_args[plane_count], 0, sizeof(*plane_args));
  1900. if (parse_plane(&plane_args[plane_count], optarg) < 0)
  1901. usage(argv[0]);
  1902. plane_count++;
  1903. break;
  1904. case 'p':
  1905. crtcs = 1;
  1906. planes = 1;
  1907. break;
  1908. case 's':
  1909. pipe_args = realloc(pipe_args,
  1910. (count + 1) * sizeof *pipe_args);
  1911. if (pipe_args == NULL) {
  1912. fprintf(stderr, "memory allocation failed\n");
  1913. return 1;
  1914. }
  1915. memset(&pipe_args[count], 0, sizeof(*pipe_args));
  1916. if (parse_connector(&pipe_args[count], optarg) < 0)
  1917. usage(argv[0]);
  1918. count++;
  1919. break;
  1920. case 'S':
  1921. parse_seed(optarg);
  1922. break;
  1923. case 'C':
  1924. test_cursor = 1;
  1925. break;
  1926. case 'v':
  1927. test_vsync = 1;
  1928. break;
  1929. case 'r':
  1930. set_preferred = 1;
  1931. break;
  1932. case 'w':
  1933. prop_args = realloc(prop_args,
  1934. (prop_count + 1) * sizeof *prop_args);
  1935. if (prop_args == NULL) {
  1936. fprintf(stderr, "memory allocation failed\n");
  1937. return 1;
  1938. }
  1939. memset(&prop_args[prop_count], 0, sizeof(*prop_args));
  1940. if (parse_property(&prop_args[prop_count], optarg) < 0)
  1941. usage(argv[0]);
  1942. prop_count++;
  1943. break;
  1944. default:
  1945. usage(argv[0]);
  1946. break;
  1947. }
  1948. }
  1949. /* Dump all the details when no* arguments are provided. */
  1950. if (!args)
  1951. encoders = connectors = crtcs = planes = framebuffers = 1;
  1952. if (test_vsync && !count && !set_preferred) {
  1953. fprintf(stderr, "page flipping requires at least one -s or -r option.\n");
  1954. return -1;
  1955. }
  1956. if (set_preferred && count) {
  1957. fprintf(stderr, "cannot use -r (preferred) when -s (mode) is set\n");
  1958. return -1;
  1959. }
  1960. dev.fd = util_open(device, module);
  1961. if (dev.fd < 0)
  1962. return -1;
  1963. if (use_atomic) {
  1964. ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
  1965. drmSetClientCap(dev.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
  1966. if (ret) {
  1967. fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno));
  1968. drmClose(dev.fd);
  1969. return -1;
  1970. }
  1971. }
  1972. dev.use_atomic = use_atomic;
  1973. dev.resources = get_resources(&dev);
  1974. if (!dev.resources) {
  1975. drmClose(dev.fd);
  1976. return 1;
  1977. }
  1978. #define dump_resource(dev, res) if (res) dump_##res(dev)
  1979. dump_resource(&dev, encoders);
  1980. dump_resource(&dev, connectors);
  1981. dump_resource(&dev, crtcs);
  1982. dump_resource(&dev, planes);
  1983. dump_resource(&dev, framebuffers);
  1984. if (dev.use_atomic)
  1985. dev.req = drmModeAtomicAlloc();
  1986. for (i = 0; i < prop_count; ++i)
  1987. set_property(&dev, &prop_args[i]);
  1988. if (dev.use_atomic) {
  1989. if (set_preferred || (count && plane_count)) {
  1990. uint64_t cap = 0;
  1991. ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
  1992. if (ret || cap == 0) {
  1993. fprintf(stderr, "driver doesn't support the dumb buffer API\n");
  1994. return 1;
  1995. }
  1996. if (set_preferred || count)
  1997. count = set_mode(&dev, &pipe_args, count);
  1998. if (dump_path) {
  1999. if (!pipe_has_writeback_connector(&dev, pipe_args, count)) {
  2000. fprintf(stderr, "No writeback connector found, can not dump.\n");
  2001. return 1;
  2002. }
  2003. writeback_config(&dev, pipe_args, count);
  2004. }
  2005. if (plane_count)
  2006. atomic_set_planes(&dev, plane_args, plane_count, false);
  2007. ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
  2008. if (ret) {
  2009. fprintf(stderr, "Atomic Commit failed [1]\n");
  2010. return 1;
  2011. }
  2012. /*
  2013. * Since only writeback connectors have an output fb, this should only be
  2014. * called for writeback.
  2015. */
  2016. if (dump_path) {
  2017. ret = poll_writeback_fence(dev.writeback_fence_fd, 1000);
  2018. if (ret)
  2019. fprintf(stderr, "Poll for writeback error: %d. Skipping Dump.\n",
  2020. ret);
  2021. dump_output_fb(&dev, pipe_args, dump_path, count);
  2022. }
  2023. if (test_vsync)
  2024. atomic_test_page_flip(&dev, pipe_args, plane_args, plane_count);
  2025. if (drop_master)
  2026. drmDropMaster(dev.fd);
  2027. getchar();
  2028. drmModeAtomicFree(dev.req);
  2029. dev.req = drmModeAtomicAlloc();
  2030. /* XXX: properly teardown the preferred mode/plane state */
  2031. if (plane_count)
  2032. atomic_clear_planes(&dev, plane_args, plane_count);
  2033. if (count)
  2034. atomic_clear_mode(&dev, pipe_args, count);
  2035. }
  2036. ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
  2037. if (ret)
  2038. fprintf(stderr, "Atomic Commit failed\n");
  2039. if (count && plane_count)
  2040. atomic_clear_FB(&dev, plane_args, plane_count);
  2041. drmModeAtomicFree(dev.req);
  2042. } else {
  2043. if (dump_path) {
  2044. fprintf(stderr, "writeback / dump is only supported in atomic mode\n");
  2045. return 1;
  2046. }
  2047. if (set_preferred || count || plane_count) {
  2048. uint64_t cap = 0;
  2049. ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
  2050. if (ret || cap == 0) {
  2051. fprintf(stderr, "driver doesn't support the dumb buffer API\n");
  2052. return 1;
  2053. }
  2054. if (set_preferred || count)
  2055. count = set_mode(&dev, &pipe_args, count);
  2056. if (plane_count)
  2057. set_planes(&dev, plane_args, plane_count);
  2058. if (test_cursor)
  2059. set_cursors(&dev, pipe_args, count);
  2060. if (test_vsync)
  2061. test_page_flip(&dev, pipe_args, count);
  2062. if (drop_master)
  2063. drmDropMaster(dev.fd);
  2064. getchar();
  2065. if (test_cursor)
  2066. clear_cursors(&dev);
  2067. if (plane_count)
  2068. clear_planes(&dev, plane_args, plane_count);
  2069. if (set_preferred || count)
  2070. clear_mode(&dev);
  2071. }
  2072. }
  2073. free_resources(dev.resources);
  2074. drmClose(dev.fd);
  2075. return 0;
  2076. }