From patchwork Wed Jul 2 21:28:07 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Packard X-Patchwork-Id: 4468031 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id C2BCF9F26C for ; Wed, 2 Jul 2014 21:28:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id BAD052037F for ; Wed, 2 Jul 2014 21:28:23 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 9AE152024F for ; Wed, 2 Jul 2014 21:28:22 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5A0B86E418; Wed, 2 Jul 2014 14:28:21 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from keithp.com (home.keithp.com [63.227.221.253]) by gabe.freedesktop.org (Postfix) with ESMTP id AB7686E418; Wed, 2 Jul 2014 14:28:19 -0700 (PDT) Received: from localhost (localhost [127.0.0.1]) by keithp.com (Postfix) with ESMTP id 68CA47600F6; Wed, 2 Jul 2014 14:28:19 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at keithp.com Received: from keithp.com ([127.0.0.1]) by localhost (keithp.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id oXZ7pcveF35Y; Wed, 2 Jul 2014 14:28:15 -0700 (PDT) Received: by keithp.com (Postfix, from userid 1033) id F15AB7600F0; Wed, 2 Jul 2014 14:28:14 -0700 (PDT) Received: from hiro.keithp.com (localhost [127.0.0.1]) by keithp.com (Postfix) with ESMTP id CD7D67600EB; Wed, 2 Jul 2014 14:28:14 -0700 (PDT) Received: by hiro.keithp.com (Postfix, from userid 1001) id 6F7B77420D9; Wed, 2 Jul 2014 14:28:14 -0700 (PDT) From: Keith Packard To: mesa-dev@lists.freedesktop.org Subject: [PATCH] glx/dri3: Use four buffers until X driver supports async flips Date: Wed, 2 Jul 2014 14:28:07 -0700 Message-Id: <1404336487-7627-1-git-send-email-keithp@keithp.com> X-Mailer: git-send-email 2.0.0.rc4 Cc: dri-devel@lists.freedesktop.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP A driver which doesn't have async flip support will queue up flips without any way to replace them afterwards. This means we've got a scanout buffer pinned as soon as we schedule a flip and so we need another buffer to keep from stalling. When vblank_mode=0, if there are only three buffers we do: current scanout buffer = 0 at MSC 0 Render frame 1 to buffer 1 PresentPixmap for buffer 1 at MSC 1 This is sitting down in the kernel waiting for vblank to become the next scanout buffer Render frame 2 to buffer 2 PresentPixmap for buffer 2 at MSC 1 This cannot be displayed at MSC 1 because the kernel doesn't have any way to replace buffer 1 as the pending scanout buffer. So, best case this will get displayed at MSC 2. Now we block after this, waiting for one of the three buffers to become idle. We can't use buffer 0 because it is the scanout buffer. We can't use buffer 1 because it's sitting in the kernel waiting to become the next scanout buffer and we can't use buffer 2 because that's the most recent frame which will become the next scanout buffer if the application doesn't manage to generate another complete frame by MSC 2. With four buffers, we get: current scanout buffer = 0 at MSC 0 Render frame 1 to buffer 1 PresentPixmap for buffer 1 at MSC 1 This is sitting down in the kernel waiting for vblank to become the next scanout buffer Render frame 2 to buffer 2 PresentPixmap for buffer 2 at MSC 1 This cannot be displayed at MSC 1 because the kernel doesn't have any way to replace buffer 1 as the pending scanout buffer. So, best case this will get displayed at MSC 2. The X server will queue this swap until buffer 1 becomes the scanout buffer. Render frame 3 to buffer 3 PresentPixmap for buffer 3 at MSC 1 As soon as the X server sees this, it will replace the pending buffer 2 swap with this swap and release buffer 2 back to the application Render frame 4 to buffer 2 PresentPixmap for buffer 2 at MSC 1 Now we're in a steady state, flipping between buffer 2 and 3 waiting for one of them to be queued to the kernel. ... current scanout buffer = 1 at MSC 1 Now buffer 0 is free and (e.g.) buffer 2 is queued in the kernel to be the scanout buffer at MSC 2 Render frames, flipping between buffer 0 and 3 When the system can replace a queued buffer, and we update Present to take advantage of that, we can use three buffers and get: current scanout buffer = 0 at MSC 0 Render frame 1 to buffer 1 PresentPixmap for buffer 1 at MSC 1 This is sitting waiting for vblank to become the next scanout buffer Render frame 2 to buffer 2 PresentPixmap for buffer 2 at MSC 1 Queue this for display at MSC 1 1. There are three possible results: 1) We're still before MSC 1. Buffer 1 is released, buffer 2 is queued waiting for MSC 1. 2) We're now after MSC 1. Buffer 0 was released at MSC 1. Buffer 1 is the current scanout buffer. a) If the user asked for a tearing update, we swap scanout from buffer 1 to buffer 2 and release buffer 1. b) If the user asked for non-tearing update, we queue buffer 2 for the MSC 2. In all three cases, we have a buffer released (call it 'n'), ready to receive the next frame. Render frame 3 to buffer n PresentPixmap for buffer n If we're still before MSC 1, then we'll ask to present at MSC 1. Otherwise, we'll ask to present at MSC 2. Present already does this if the driver offers async flips, however it does this by waiting for the right vblank event and sending an async flip right at that point. I've hacked the intel driver to offer this, but I get tearing at the top of the screen. I think this is because flips are always done from within the ring, and so the latency between the vblank event and the async flip happening can cause tearing at the top of the screen. That's why I'm keying the need for the extra buffer on the lack of 2D driver support for async flips. Signed-off-by: Keith Packard Acked-by: Jason Ekstrand Tested-by: Dylan Baker --- src/glx/dri3_glx.c | 20 +++++++++++++++++++- src/glx/dri3_priv.h | 6 +++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c index e3fc4de..753b8d8 100644 --- a/src/glx/dri3_glx.c +++ b/src/glx/dri3_glx.c @@ -271,8 +271,11 @@ static void dri3_update_num_back(struct dri3_drawable *priv) { priv->num_back = 1; - if (priv->flipping) + if (priv->flipping) { + if (!priv->is_pixmap && !(priv->present_capabilities & XCB_PRESENT_CAPABILITY_ASYNC)) + priv->num_back++; priv->num_back++; + } if (priv->swap_interval == 0) priv->num_back++; } @@ -976,6 +979,9 @@ dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate) xcb_get_geometry_reply_t *geom_reply; xcb_void_cookie_t cookie; xcb_generic_error_t *error; + xcb_present_query_capabilities_cookie_t present_capabilities_cookie; + xcb_present_query_capabilities_reply_t *present_capabilities_reply; + /* Try to select for input on the window. * @@ -994,6 +1000,8 @@ dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate) XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY| XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); + present_capabilities_cookie = xcb_present_query_capabilities(c, priv->base.xDrawable); + /* Create an XCB event queue to hold present events outside of the usual * application event queue */ @@ -1023,6 +1031,16 @@ dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate) error = xcb_request_check(c, cookie); + present_capabilities_reply = xcb_present_query_capabilities_reply(c, + present_capabilities_cookie, + NULL); + + if (present_capabilities_reply) { + priv->present_capabilities = present_capabilities_reply->capabilities; + free(present_capabilities_reply); + } else + priv->present_capabilities = 0; + if (error) { if (error->error_code != BadWindow) { free(error); diff --git a/src/glx/dri3_priv.h b/src/glx/dri3_priv.h index c0e35ee..742db60 100644 --- a/src/glx/dri3_priv.h +++ b/src/glx/dri3_priv.h @@ -147,7 +147,7 @@ struct dri3_context __DRIcontext *driContext; }; -#define DRI3_MAX_BACK 3 +#define DRI3_MAX_BACK 4 #define DRI3_BACK_ID(i) (i) #define DRI3_FRONT_ID (DRI3_MAX_BACK) @@ -172,6 +172,10 @@ struct dri3_drawable { uint8_t is_pixmap; uint8_t flipping; + /* Present extension capabilities + */ + uint32_t present_capabilities; + /* SBC numbers are tracked by using the serial numbers * in the present request and complete events */