All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Paul <seanpaul@chromium.org>
To: Alexandru-Cosmin Gheorghe <Alexandru-Cosmin.Gheorghe@arm.com>
Cc: ayan.halder@arm.com, liviu.dudau@arm.com,
	dri-devel@lists.freedesktop.org, nd@arm.com
Subject: Re: [PATCH hwc v2 17/18] drm_hwcomposer: Flatten scene synchronously
Date: Wed, 18 Apr 2018 10:49:27 -0400	[thread overview]
Message-ID: <20180418144927.GY73214@art_vandelay> (raw)
In-Reply-To: <20180418111403.GE10633@e114479-lin.cambridge.arm.com>

On Wed, Apr 18, 2018 at 12:14:03PM +0100, Alexandru-Cosmin Gheorghe wrote:
> On Tue, Apr 17, 2018 at 01:47:46PM -0400, Sean Paul wrote:
> > On Wed, Apr 11, 2018 at 04:22:28PM +0100, Alexandru Gheorghe wrote:
> > > Flatten scene on the same CRTC as the one driving the display.
> > > The active composition is played back to the display with a buffer
> > > attached to the writeback connector.
> > > Then we build a composition that has only one plane enabled and that
> > > uses the result of the writeback as the input.
> > > 
> > > Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com>
> > > ---
> > >  drmdisplaycompositor.cpp | 203 +++++++++++++++++++++++++++++++++++++++++++++--
> > >  drmdisplaycompositor.h   |   7 +-
> > >  2 files changed, 204 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
> > > index e535e8a..cb670e6 100644
> > > --- a/drmdisplaycompositor.cpp
> > > +++ b/drmdisplaycompositor.cpp
> > > @@ -36,6 +36,7 @@
> > >  #include "drmplane.h"
> > >  #include "drmresources.h"
> > >  #include "glworker.h"
> > > +static const uint32_t kWaitWritebackFence = 100;  // ms
> > >  
> > >  namespace android {
> > >  
> > > @@ -523,7 +524,9 @@ int DrmDisplayCompositor::PrepareFrame(DrmDisplayComposition *display_comp) {
> > >  }
> > >  
> > >  int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
> > > -                                      bool test_only) {
> > > +                                      bool test_only,
> > > +                                      DrmDisplayComposition *writeback_comp,
> > > +                                      DrmConnector *writeback_conn) {
> > >    ATRACE_CALL();
> > >  
> > >    int ret = 0;
> > > @@ -532,6 +535,7 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
> > >    std::vector<DrmCompositionPlane> &comp_planes =
> > >        display_comp->composition_planes();
> > >    uint64_t out_fences[drm_->crtcs().size()];
> > > +  int writeback_fence = -1;
> > >  
> > >    DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
> > >    if (!connector) {
> > > @@ -550,9 +554,37 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
> > >      return -ENOMEM;
> > >    }
> > >  
> > > +  if (writeback_comp != NULL) {
> > > +    if (writeback_conn == NULL)
> > > +      return -EINVAL;
> > > +    if (writeback_conn->writeback_fb_id().id() == 0 ||
> > > +        writeback_conn->writeback_out_fence().id() == 0) {
> > > +      ALOGE("Writeback properties don't exit");
> > > +      return -EINVAL;
> > > +    }
> > > +    if (writeback_comp->layers().size() != 1) {
> > > +      ALOGE("Invalid number of layers for writeback composition");
> > > +      return -EINVAL;
> > > +    }
> > > +    ret = drmModeAtomicAddProperty(
> > > +        pset, writeback_conn->id(), writeback_conn->writeback_fb_id().id(),
> > > +        writeback_comp->layers().back().buffer->fb_id);
> > > +    if (ret < 0) {
> > > +      ALOGE("Failed to add writeback_fb_id");
> > > +      return ret;
> > > +    }
> > > +    ret = drmModeAtomicAddProperty(pset, writeback_conn->id(),
> > > +                                   writeback_conn->writeback_out_fence().id(),
> > > +                                   (uint64_t)&writeback_fence);
> > 
> > Upcasting int to u64 isn't a great idea, please go the other way (as we do with
> > out_fences).
> 
> Genuinely curious about this, why does it make a difference I'm
> upcasting the address not the int itself.

Right, for some reason I had inserted a * inside the parens with my head. Please
ignore :)

> More, the kernel does this s32 __user *fence_ptr = u64_to_user_ptr(val);
> To be completly fair it should have been int32_t.
> 
> 
> > 
> > > +    if (ret < 0) {
> > > +      ALOGE("Failed to add writeback_out_fence");
> > > +      return ret;
> > > +    }
> > > +  }
> > 
> > This would be more readable if it was split off into a function.
> > 
> > >    if (crtc->out_fence_ptr_property().id() != 0) {
> > > -    ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->out_fence_ptr_property().id(),
> > > -                                   (uint64_t) &out_fences[crtc->pipe()]);
> > > +    ret = drmModeAtomicAddProperty(pset, crtc->id(),
> > > +                                   crtc->out_fence_ptr_property().id(),
> > > +                                   (uint64_t)&out_fences[crtc->pipe()]);
> > >      if (ret < 0) {
> > >        ALOGE("Failed to add OUT_FENCE_PTR property to pset: %d", ret);
> > >        drmModeAtomicFree(pset);
> > > @@ -580,6 +612,15 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
> > >      }
> > >    }
> > >  
> > > +  if (writeback_conn != NULL) {
> > > +    ret = drmModeAtomicAddProperty(pset, writeback_conn->id(),
> > > +                                   writeback_conn->crtc_id_property().id(),
> > > +                                   crtc->id());
> > > +    if (ret < 0) {
> > > +      ALOGE("Failed to  attach writeback");
> > > +    }
> > > +  }
> > 
> > Can you do this above with the rest of the writeback properties?
> > 
> > > +
> > >    for (DrmCompositionPlane &comp_plane : comp_planes) {
> > >      DrmPlane *plane = comp_plane.plane();
> > >      DrmCrtc *crtc = comp_plane.crtc();
> > > @@ -729,8 +770,18 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
> > >  
> > >    if (!ret) {
> > >      uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
> > > -    if (test_only)
> > > +    if (test_only) {
> > >        flags |= DRM_MODE_ATOMIC_TEST_ONLY;
> > > +    } else {
> > > +      if (writeback_comp != NULL) {
> > > +        if (!CountdownExpired() && active_composition_) {
> > 
> > Given that we're holding the lock throughout this function, can't you just
> > abort at the start?
> 
> Yes, we could/should.
> 
> > 
> > > +          ALOGE("Writeback composition not needed, abort commit");
> > > +          drmModeAtomicFree(pset);
> > > +          return -EINVAL;
> > > +        };
> > > +        flags |= DRM_MODE_ATOMIC_NONBLOCK;
> > 
> > I'm guessing this is the cause of the active_composition race you're fixing
> > earlier in the series? Could you please pull this out and squash it into that
> > patch as a "Use non-blocking commits" standalone? It might be useful for
> > testing, and this is something that's substantial enough to warrant the
> > additional visibility of its own patch.
> 
> Not really, that race could happen  even without non blocking. The
> current implementation is:
> 1. Commit
> 2. lock.
> 3. Set active_composition
> 4. Unlock.
> 
> With two threads there is no guarantee active_composition will contain
> what it's been comitted.
> 

Makes sense, thanks for laying it out.

Sean
> 
> > 
> > > +      }
> > > +    }
> > >  
> > >      ret = drmModeAtomicCommit(drm_->fd(), pset, flags, drm_);
> > >      if (ret) {
> > > @@ -769,6 +820,13 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
> > >    if (crtc->out_fence_ptr_property().id()) {
> > >      display_comp->set_out_fence((int) out_fences[crtc->pipe()]);
> > >    }
> > > +  if (writeback_fence >= 0) {
> > > +    if (writeback_comp->layers().size() != 1) {
> > > +      ALOGE("Invalid numbers of layer for writeback_comp");
> > > +      return -EINVAL;
> > > +    }
> > 
> > You already test this above?
> > 
> > > +    writeback_comp->layers()[0].acquire_fence.Set(writeback_fence);
> > > +  }
> > >  
> > >    return ret;
> > >  }
> > > @@ -837,6 +895,8 @@ void DrmDisplayCompositor::ApplyFrame(
> > >        if (active_composition_)
> > >          active_composition_->SignalCompositionDone();
> > >        active_composition_.swap(composition);
> > > +      flatten_countdown_ = FLATTEN_COUNTDOWN_INIT;
> > > +      vsync_worker_.VSyncControl(!writeback);
> > >      }
> > >    }
> > >  
> > > @@ -913,8 +973,141 @@ int DrmDisplayCompositor::ApplyComposition(
> > >    return ret;
> > >  }
> > >  
> > > +int DrmDisplayCompositor::WritebackComposite(DrmDisplayComposition *src,
> > > +                                             DrmDisplayComposition *dst,
> > > +                                             DrmConnector *writeback_conn) {
> > > +  int ret = 0;
> > > +  if (src == NULL || dst == NULL)
> > > +    return -EINVAL;
> > > +  std::vector<DrmCompositionPlane> &src_planes = src->composition_planes();
> > > +  DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kPrecomp, NULL,
> > > +                                    src->crtc());
> > > +  for (DrmCompositionPlane &comp_plane : src_planes) {
> > > +    if (comp_plane.plane() == NULL) {
> > > +      ALOGE("Skipping squash all because of NULL plane");
> > > +      ret = -EINVAL;
> > > +    }
> > > +    if (!squashed_comp.plane() &&
> > > +        comp_plane.plane()->type() == DRM_PLANE_TYPE_PRIMARY)
> > > +      squashed_comp.set_plane(comp_plane.plane());
> > > +    else
> > > +      dst->AddPlaneDisable(comp_plane.plane());
> > > +  }
> > > +
> > > +  DrmFramebuffer *writeback_fb = NULL;
> > > +  AutoLock lock(&lock_, __FUNCTION__);
> > > +  if ((ret = lock.Lock()))
> > 
> > Same comments regarding assignment in a conditional.
> > 
> > > +    return ret;
> > > +  writeback_fb = &framebuffers_[framebuffer_index_];
> > > +  framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
> > > +  ret = PrepareFramebuffer(*writeback_fb, dst, mode_.mode.h_display(),
> > > +                           mode_.mode.v_display());
> > > +  if (ret) {
> > > +    ALOGE("Failed to prepare destination buffer");
> > > +    return ret;
> > > +  }
> > > +  lock.Unlock();
> > > +  ret = CommitFrame(src, true, dst, writeback_conn);
> > > +  if (ret) {
> > > +    ALOGE("Atomic check failed");
> > > +    return ret;
> > > +  }
> > > +  if ((ret = lock.Lock()))
> > 
> > All of these locks and unlocks are going to cause races, as mentioned below,
> > please re-evaluate.
> > 
> > > +    return ret;
> > > +  if (!CountdownExpired() && active_composition_) {
> > > +    ALOGE("Writeback composition not needed abort");
> > > +    return -EINVAL;
> > > +  }
> > > +  ret = CommitFrame(src, false, dst, writeback_conn);
> > > +  lock.Unlock();
> > > +  if (ret || dst->layers().size() != 1) {
> > > +    ALOGE("Failed to flatten scene using writeback");
> > > +    return -EINVAL;
> > > +  }
> > > +  squashed_comp.source_layers().push_back(0);
> > > +  ret =
> > > +      sync_wait(dst->layers()[0].acquire_fence.Release(), kWaitWritebackFence);
> > 
> > line break
> > 
> > > +  if (ret) {
> > > +    ALOGE("Failed to wait on writeback fence");
> > > +    return ret;
> > > +  }
> > > +  ret = dst->AddPlaneComposition(std::move(squashed_comp));
> > > +  if (ret) {
> > > +    ALOGE("Failed to add flatten scene");
> > > +    return ret;
> > > +  }
> > > +  ret = dst->FinalizeComposition();
> > > +  if (ret) {
> > > +    ALOGE("Failed to finalize composition");
> > > +    return ret;
> > > +  }
> > > +  return 0;
> > > +}
> > > +
> > > +int DrmDisplayCompositor::FlattenSynchronously(DrmConnector *writeback_conn) {
> > > +  if (writeback_conn->display() != display_) {
> > > +    ALOGE("Cannot flatten synchronously on different display");
> > > +    return -EINVAL;
> > > +  }
> > 
> > You check this right before calling, so this isn't needed.
> > 
> > > +  ALOGI("FlattenSynchronously using the same display");
> > 
> > I think you should downgrade this log level.
> > 
> > > +  int ret = 0;
> > > +  /* Flattened composition with only one layer that is built
> > > +   * using the writeback connector
> > > +   */
> > > +  std::unique_ptr<DrmDisplayComposition> writeback_comp =
> > > +      CreateInitializedComposition();
> > > +  /* Copy of the active_composition_, we need a copy because
> > > +   * if we use the active composition we have to hold the lock
> > > +   * for the entire sequence of flattening.
> > > +   */
> > > +  std::unique_ptr<DrmDisplayComposition> copy_comp =
> > > +      CreateInitializedComposition();
> > > +
> > > +  if (!copy_comp || !writeback_comp)
> > > +    return -EINVAL;
> > > +  AutoLock lock(&lock_, __FUNCTION__);
> > > +  if ((ret = lock.Lock()))
> > 
> > Assignments in if statements make me nervous. Since you don't need the
> > declaration above, just do:
> > 
> >   int ret = lock.Lock();
> >   if (ret)
> > 
> > > +    return ret;
> > > +  if (CountdownExpired()) {
> > > +    ret = copy_comp->CopyLayers(active_composition_.get());
> > > +    if (ret)
> > > +      return ret;
> > > +    copy_comp->CopyCompPlanes(active_composition_.get());
> > > +  } else {
> > > +    return -EINVAL;
> > > +  }
> > 
> >   if (!CountdownExpired())
> >     return -EINVAL;
> > 
> >   ret = copy_comp->CopyLayers(active_composition_.get());
> >   if (ret)
> >     return ret;
> >   copy_comp->CopyCompPlanes(active_composition_.get());
> > 
> > 
> > > +  lock.Unlock();
> > 
> > Just hold the lock through WritebackComposite(), and consider creating a
> > ApplyFrameLocked() to hold it through ApplyFrame(). You should be able to reduce
> > the number of times you have to check CountdownExpired() (or remove it)
> > significantly by just consistently locking things.
> > 
> > > +  ret =
> > > +      WritebackComposite(copy_comp.get(), writeback_comp.get(), writeback_conn);
> > > +  if (ret) {
> > > +    ALOGE("Failed to prepare writebackScene");
> > > +    return ret;
> > > +  }
> > > +
> > > +  ApplyFrame(std::move(writeback_comp), 0, true);
> > > +  return 0;
> > > +}
> > > +
> > >  int DrmDisplayCompositor::FlattenScene() {
> > > -  return -EINVAL;
> > > +  DrmConnector *writeback_conn =
> > > +      drm_->resource_manager()->AvailableWritebackConnector(display_);
> > > +  if (!active_composition_ || !writeback_conn)
> > > +    return -EINVAL;
> > > +  std::vector<DrmCompositionPlane> &src_planes =
> > > +      active_composition_->composition_planes();
> > > +  size_t src_planes_with_layer = std::count_if(
> > > +      src_planes.begin(), src_planes.end(), [](DrmCompositionPlane &p) {
> > > +        return p.type() != DrmCompositionPlane::Type::kDisable;
> > > +      });
> > > +
> > > +  if (src_planes_with_layer <= 1)
> > > +    return -EALREADY;
> > > +
> > > +  if (writeback_conn->display() == display_) {
> > > +    return FlattenSynchronously(writeback_conn);
> > > +  }
> > > +
> > > +  return 0;
> > >  }
> > >  
> > >  int DrmDisplayCompositor::SquashAll() {
> > > diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
> > > index 26201b9..4cc4a5e 100644
> > > --- a/drmdisplaycompositor.h
> > > +++ b/drmdisplaycompositor.h
> > > @@ -125,7 +125,9 @@ class DrmDisplayCompositor {
> > >    int ApplySquash(DrmDisplayComposition *display_comp);
> > >    int ApplyPreComposite(DrmDisplayComposition *display_comp);
> > >    int PrepareFrame(DrmDisplayComposition *display_comp);
> > > -  int CommitFrame(DrmDisplayComposition *display_comp, bool test_only);
> > > +  int CommitFrame(DrmDisplayComposition *display_comp, bool test_only,
> > > +                  DrmDisplayComposition *writeback_comp = NULL,
> > > +                  DrmConnector *writeback_conn = NULL);
> > >    int SquashFrame(DrmDisplayComposition *src, DrmDisplayComposition *dst);
> > >    int ApplyDpms(DrmDisplayComposition *display_comp);
> > >    int DisablePlanes(DrmDisplayComposition *display_comp);
> > > @@ -134,7 +136,10 @@ class DrmDisplayCompositor {
> > >    void ApplyFrame(std::unique_ptr<DrmDisplayComposition> composition,
> > >                    int status, bool writeback = false);
> > >    int FlattenScene();
> > > +  int FlattenSynchronously(DrmConnector *writeback_conn);
> > 
> > Can we come up with a better name than Synchonrous/Asynchronous? Or at the very
> > least comment on what that means?
> > 
> > >  
> > > +  int WritebackComposite(DrmDisplayComposition *src, DrmDisplayComposition *dst,
> > > +                         DrmConnector *writeback_conn);
> > >    bool CountdownExpired() const;
> > >  
> > >    std::tuple<int, uint32_t> CreateModeBlob(const DrmMode &mode);
> > > -- 
> > > 2.7.4
> > > 
> > 
> > -- 
> > Sean Paul, Software Engineer, Google / Chromium OS
> 
> -- 
> Cheers,
> Alex G

-- 
Sean Paul, Software Engineer, Google / Chromium OS
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2018-04-18 14:49 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-11 15:22 [PATCH hwc v2 00/18] Add scene flattening support Alexandru Gheorghe
2018-04-11 15:22 ` [PATCH hwc v2 01/18] drm_hwcomposer: vsyncworker: Fix uninitialized enabled_ field Alexandru Gheorghe
2018-04-16 10:30   ` Robert Foss
2018-04-16 12:18     ` Alexandru-Cosmin Gheorghe
2018-04-17 13:45       ` Sean Paul
2018-04-17 14:09         ` Alexandru-Cosmin Gheorghe
2018-04-11 15:22 ` [PATCH hwc v2 02/18] drm_hwcomposer: vsyncworker: Fix deadlock on exit path Alexandru Gheorghe
2018-04-16 10:31   ` Robert Foss
2018-04-16 19:25   ` Sean Paul
2018-04-17 13:32     ` Alexandru-Cosmin Gheorghe
2018-04-11 15:22 ` [PATCH hwc v2 03/18] drm_hwcomposer: drmeventlistener: Set nl_pid to 0 Alexandru Gheorghe
2018-04-16 10:32   ` Robert Foss
2018-04-11 15:22 ` [PATCH hwc v2 04/18] drm_hwcomposer: Add resource manager class Alexandru Gheorghe
2018-04-17 15:33   ` Sean Paul
2018-04-17 16:08     ` Robert Foss
2018-04-18 10:12       ` Alexandru-Cosmin Gheorghe
2018-04-18 10:14         ` Robert Foss
2018-04-11 15:22 ` [PATCH hwc v2 05/18] drm_hwcomposer: Enable resource manager support Alexandru Gheorghe
2018-04-16 19:54   ` Sean Paul
2018-04-17 13:43     ` Alexandru-Cosmin Gheorghe
2018-04-17 14:22       ` Sean Paul
2018-04-17 14:26   ` Sean Paul
2018-04-11 15:22 ` [PATCH hwc v2 06/18] drm_hwcomposer: Add writeback connector support Alexandru Gheorghe
2018-04-16 19:59   ` Sean Paul
2018-04-17 13:46     ` Alexandru-Cosmin Gheorghe
2018-04-11 15:22 ` [PATCH hwc v2 07/18] drm_hwcomposer: Add display field to Drmencoder Alexandru Gheorghe
2018-04-16 20:02   ` Sean Paul
2018-04-17 13:49     ` Alexandru-Cosmin Gheorghe
2018-04-11 15:22 ` [PATCH hwc v2 08/18] drm_hwcomposer: Parse and store possible_clones information Alexandru Gheorghe
2018-04-16 20:19   ` Sean Paul
2018-04-17 14:03     ` Alexandru-Cosmin Gheorghe
2018-04-11 15:22 ` [PATCH hwc v2 09/18] drm_hwcomposer: Handle writeback connectors Alexandru Gheorghe
2018-04-17 15:45   ` Sean Paul
2018-04-11 15:22 ` [PATCH hwc v2 10/18] drm_hwcomposer: hwcutils: Add function for cloning a DrmHwcLayer Alexandru Gheorghe
2018-04-17 16:14   ` Sean Paul
2018-04-18 10:22     ` Alexandru-Cosmin Gheorghe
2018-04-11 15:22 ` [PATCH hwc v2 11/18] drm_hwcomposer: Add utility functions to copy displaycomposition internals Alexandru Gheorghe
2018-04-17 16:34   ` Sean Paul
2018-04-11 15:22 ` [PATCH hwc v2 12/18] drm_hwcomposer: Add utility function to create an initialized composition Alexandru Gheorghe
2018-04-17 16:37   ` Sean Paul
2018-04-18 10:29     ` Alexandru-Cosmin Gheorghe
2018-04-11 15:22 ` [PATCH hwc v2 13/18] drm_hwcomposer: Pass buffer sizes to Prepareframebuffer Alexandru Gheorghe
2018-04-17 16:51   ` Sean Paul
2018-04-11 15:22 ` [PATCH hwc v2 14/18] drm_hwcomposer: Fix race in ApplyFrame Alexandru Gheorghe
2018-04-17 17:02   ` Sean Paul
2018-04-18 10:43     ` Alexandru-Cosmin Gheorghe
2018-04-11 15:22 ` [PATCH hwc v2 15/18] drm_hwcomposer: Add worker to trigger scene flattenning Alexandru Gheorghe
2018-04-17 17:07   ` Sean Paul
2018-04-11 15:22 ` [PATCH hwc v2 16/18] drm_hwcomposer: Find writeback connector for scene flattening Alexandru Gheorghe
2018-04-17 17:15   ` Sean Paul
2018-04-11 15:22 ` [PATCH hwc v2 17/18] drm_hwcomposer: Flatten scene synchronously Alexandru Gheorghe
2018-04-17 17:47   ` Sean Paul
2018-04-18 11:14     ` Alexandru-Cosmin Gheorghe
2018-04-18 14:49       ` Sean Paul [this message]
2018-04-11 15:22 ` [PATCH hwc v2 18/18] drm_hwcomposer: Flatten scene asynchronously Alexandru Gheorghe
2018-04-12 23:18 ` [PATCH hwc v2 00/18] Add scene flattening support John Stultz
2018-04-13  9:52   ` Alexandru-Cosmin Gheorghe
2018-04-13 12:48     ` Alexandru-Cosmin Gheorghe
2018-04-18 17:21       ` John Stultz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180418144927.GY73214@art_vandelay \
    --to=seanpaul@chromium.org \
    --cc=Alexandru-Cosmin.Gheorghe@arm.com \
    --cc=ayan.halder@arm.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=liviu.dudau@arm.com \
    --cc=nd@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.