0041-null_platform-add-support-for-explicit-synchronisati.patch 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. From ced3b5d803cd044526672c8458029b5a6519b86a Mon Sep 17 00:00:00 2001
  2. From: Silvestrs Timofejevs <silvestrs.timofejevs@imgtec.com>
  3. Date: Mon, 2 Sep 2019 09:32:01 +0100
  4. Subject: [PATCH] null_platform: add support for explicit synchronisation
  5. This change adds support for the 'in' fence, the 'out' fence will
  6. potentially be added in subsequent optimisation changes.
  7. Explicit synchronisation KMS 'in' and 'out' properties have been first
  8. added in Linux kernel 4.10 as an additional feature to the atomic mode
  9. setting.
  10. 9626014258a5957ff120b3987ee72decdbe0c798 - 'in' property
  11. beaf5af48034c9e2ebb8b2b1fb12dc4d8aeba99e - 'out' property
  12. Unlike many other features - it doesn't have an in kernel capability
  13. flag, so the support for it can be tested in the following way:
  14. KMS creates an additional set of properties when the version of kernel
  15. is new enough to support it ('in' and 'out' fence properties). When
  16. the user-space requests all the properties from the kernel via
  17. drmModeObjectGetProperties it is possible to determine whether the
  18. required property is supported by the kernel or not.
  19. The explicit synchronisation is used when available, otherwise the
  20. implicit sync model is used instead. If explicit synchronisation is
  21. available but 'in' fence failed to attach in KMS, the system falls
  22. back to the implicit synchronisation model.
  23. egl_dri2.c already creates the GPU 'out' fence that is then used by
  24. the null_platform as KMS 'in' fence. null_platform takes owenership of
  25. this fence fd during the swap buffers operation, at which point the
  26. fence fd is no longer available to be used outside of null_platform.
  27. EGL_LOG_LEVEL=debug should give some useful information in case of
  28. explicit synchronisation failure. As mentioned above, this failure
  29. will result in implicit synchronisation being used instead.
  30. Change-Id: Ib9c4a0bc3ea1b21192ee37909d7580d6b7b366ec
  31. ---
  32. src/egl/drivers/dri2/egl_dri2.h | 2 +
  33. src/egl/drivers/dri2/platform_null.c | 77 +++++++++++++++++++++++++++-
  34. 2 files changed, 77 insertions(+), 2 deletions(-)
  35. diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
  36. index 64d60ed..eb6e455 100644
  37. --- a/src/egl/drivers/dri2/egl_dri2.h
  38. +++ b/src/egl/drivers/dri2/egl_dri2.h
  39. @@ -106,6 +106,7 @@ struct wl_buffer;
  40. #ifdef HAVE_NULL_PLATFORM
  41. struct display_output {
  42. bool in_use;
  43. + bool in_fence_supported;
  44. uint32_t connector_id;
  45. drmModePropertyRes **connector_prop_res;
  46. uint32_t crtc_id;
  47. @@ -338,6 +339,7 @@ struct swap_queue_elem
  48. uint32_t swap_interval;
  49. uint32_t back_id;
  50. uint32_t fb_id;
  51. + int kms_in_fence_fd;
  52. };
  53. enum {
  54. diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c
  55. index 5b7c1ec..d36dc0c 100644
  56. --- a/src/egl/drivers/dri2/platform_null.c
  57. +++ b/src/egl/drivers/dri2/platform_null.c
  58. @@ -401,6 +401,9 @@ display_output_atomic_init(int fd, struct display_output *output)
  59. if (!output->atomic_state)
  60. goto err_destroy_mode_prop_blob;
  61. + if (property_id_get_for_name(plane_prop_res, "IN_FENCE_FD"))
  62. + output->in_fence_supported = true;
  63. +
  64. output->connector_prop_res = connector_prop_res;
  65. output->crtc_prop_res = crtc_prop_res;
  66. output->plane_prop_res = plane_prop_res;
  67. @@ -418,6 +421,53 @@ err_free_connector_prop_res:
  68. return false;
  69. }
  70. +static void
  71. +display_output_atomic_add_in_fence(struct display_output *output,
  72. + int kms_in_fence_fd)
  73. +{
  74. + const struct object_property obj_sync_props[] = {
  75. + object_property_set_named(output, plane, "IN_FENCE_FD", kms_in_fence_fd),
  76. + };
  77. + int err;
  78. +
  79. + /* Explicit synchronisation is not being used */
  80. + if (kms_in_fence_fd < 0)
  81. + return;
  82. +
  83. + err = atomic_state_add_object_properties(output->atomic_state,
  84. + obj_sync_props,
  85. + ARRAY_SIZE(obj_sync_props));
  86. + if (err)
  87. + _eglLog(_EGL_DEBUG, "%s: failed to add props ERR = %d", __func__, err);
  88. +}
  89. +
  90. +static void
  91. +atomic_claim_in_fence_fd(struct dri2_egl_surface *dri2_surf,
  92. + struct swap_queue_elem *swap_data)
  93. +{
  94. + /* Explicit synchronisation is not being used */
  95. + if (!dri2_surf->enable_out_fence)
  96. + return;
  97. +
  98. + if (dri2_surf->out_fence_fd < 0) {
  99. + _eglLog(_EGL_DEBUG, "%s: missing 'in' fence", __func__);
  100. + return;
  101. + }
  102. +
  103. + /* Take ownership of the fd */
  104. + swap_data->kms_in_fence_fd = dri2_surf->out_fence_fd;
  105. + dri2_surf->out_fence_fd = -1;
  106. +}
  107. +
  108. +static void
  109. +atomic_relinquish_in_fence_fd(struct dri2_egl_surface *dri2_surf,
  110. + struct swap_queue_elem *swap_data)
  111. +{
  112. + /* KMS is now in control of the fence (post drmModeAtomicCommit) */
  113. + close(swap_data->kms_in_fence_fd);
  114. + swap_data->kms_in_fence_fd = -1;
  115. +}
  116. +
  117. static int
  118. display_output_atomic_flip(int fd, struct display_output *output, uint32_t fb_id,
  119. uint32_t flags, void *flip_data)
  120. @@ -425,6 +475,8 @@ display_output_atomic_flip(int fd, struct display_output *output, uint32_t fb_id
  121. const struct object_property obj_props[] = {
  122. object_property_set_named(output, plane, "FB_ID", fb_id),
  123. };
  124. + struct dri2_egl_surface *dri2_surf = flip_data;
  125. + struct swap_queue_elem *swap_data = dri2_surf->swap_data;
  126. int err;
  127. /* Reset atomic state */
  128. @@ -435,13 +487,19 @@ display_output_atomic_flip(int fd, struct display_output *output, uint32_t fb_id
  129. if (err)
  130. return err;
  131. + display_output_atomic_add_in_fence(output, swap_data->kms_in_fence_fd);
  132. +
  133. /*
  134. * Don't block - like drmModePageFlip, drmModeAtomicCommit will return
  135. * -EBUSY if the commit can't be queued in the kernel.
  136. */
  137. flags |= DRM_MODE_ATOMIC_NONBLOCK;
  138. - return drmModeAtomicCommit(fd, output->atomic_state, flags, flip_data);
  139. + err = drmModeAtomicCommit(fd, output->atomic_state, flags, flip_data);
  140. +
  141. + atomic_relinquish_in_fence_fd(dri2_surf, swap_data);
  142. +
  143. + return err;
  144. }
  145. static int
  146. @@ -489,6 +547,8 @@ swap_enqueue_data(struct dri2_egl_surface *dri2_surf, uint32_t back_id,
  147. swap_data->fb_id = dri2_surf->back->fb_id;
  148. swap_data->back_id = back_id;
  149. + atomic_claim_in_fence_fd(dri2_surf, swap_data);
  150. +
  151. dri2_surf->swap_queue_idx_tail++;
  152. dri2_surf->swap_queue_idx_tail %= ARRAY_SIZE(dri2_surf->swap_queue);
  153. @@ -1025,11 +1085,21 @@ err_unlock:
  154. return false;
  155. }
  156. +static void surface_swap_queue_init(struct dri2_egl_surface *dri2_surf)
  157. +{
  158. + struct swap_queue_elem *swap_queue = &dri2_surf->swap_queue[0];
  159. + const int num_el = ARRAY_SIZE(dri2_surf->swap_queue);
  160. +
  161. + for (int i = 0; i < num_el; i++)
  162. + swap_queue[i].kms_in_fence_fd = -1;
  163. +}
  164. +
  165. static _EGLSurface *
  166. create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type,
  167. const EGLint *attrib_list)
  168. {
  169. struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  170. + struct display_output *output = &dri2_dpy->output;
  171. struct dri2_egl_config *dri2_config = dri2_egl_config(config);
  172. struct dri2_egl_surface *dri2_surf;
  173. const __DRIconfig *dri_config;
  174. @@ -1043,7 +1113,8 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type,
  175. }
  176. surf = &dri2_surf->base;
  177. - if (!dri2_init_surface(surf, disp, type, config, attrib_list, false, NULL))
  178. + if (!dri2_init_surface(surf, disp, type, config, attrib_list,
  179. + output->in_fence_supported, NULL))
  180. goto err_free_surface;
  181. dri_config = dri2_get_dri_config(dri2_config, type,
  182. @@ -1066,6 +1137,8 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type,
  183. dri2_surf->format = dri2_null_formats[format_idx].dri_image_format;
  184. + surface_swap_queue_init(dri2_surf);
  185. +
  186. return surf;
  187. err_free_surface: