Signed-off-by: Axel Davy <axel.d...@ens.fr> --- src/glx/dri3_glx.c | 235 +++++++++++++++++++++++++++++++++++++++++++--------- src/glx/dri3_priv.h | 2 + 2 files changed, 200 insertions(+), 37 deletions(-)
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c index 3d8a662..54030bb 100644 --- a/src/glx/dri3_glx.c +++ b/src/glx/dri3_glx.c @@ -596,6 +596,7 @@ dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y, { struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; struct dri3_screen *psc = (struct dri3_screen *) pdraw->psc; + struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext(); xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); struct dri3_buffer *back = dri3_back_buffer(priv); @@ -605,6 +606,30 @@ dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y, if (!priv->have_back || priv->is_pixmap) return; + /* When on a different gpu than the server, we use blitImage + * for the copies. Do the needed copies before flushing. + */ + if (psc->is_different_gpu && pcp && pcp->driContext) { + /* Update the linear buffer part of the back buffer + * for the dri3_copy_area operation + */ + psc->image->blitImage(pcp->driContext, + back->linear_buffer, + back->image, + 0, 0, back->width, + back->height, + 0, 0, back->width, + back->height); + /* We use blitImage to update our fake front, + */ + if (priv->have_fake_front) + psc->image->blitImage(pcp->driContext, + dri3_fake_front_buffer(priv)->image, + back->image, + x, y, width, height, + x, y, width, height); + } + flags = __DRI2_FLUSH_DRAWABLE; if (flush) flags |= __DRI2_FLUSH_CONTEXT; @@ -622,7 +647,7 @@ dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y, /* Refresh the fake front (if present) after we just damaged the real * front. */ - if (priv->have_fake_front) { + if (priv->have_fake_front && !psc->is_different_gpu) { dri3_fence_reset(c, dri3_fake_front_buffer(priv)); dri3_copy_area(c, dri3_back_buffer(priv)->pixmap, @@ -655,25 +680,62 @@ dri3_copy_drawable(struct dri3_drawable *priv, Drawable dest, Drawable src) static void dri3_wait_x(struct glx_context *gc) { + struct dri3_context *pcp = (struct dri3_context *) gc; struct dri3_drawable *priv = (struct dri3_drawable *) GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); + struct dri3_screen *psc; + struct dri3_buffer *front; if (priv == NULL || !priv->have_fake_front) return; - dri3_copy_drawable(priv, dri3_fake_front_buffer(priv)->pixmap, priv->base.xDrawable); + psc = (struct dri3_screen *) priv->base.psc; + front = dri3_fake_front_buffer(priv); + + dri3_copy_drawable(priv, front->pixmap, priv->base.xDrawable); + + /* In the psc->is_different_gpu case, the linear buffer has been updated, + * but not yet the tiled buffer. + * Copy back to the tiled buffer we use for rendering. + * Note that we don't need flushing. + */ + if (psc->is_different_gpu && pcp->driContext) + psc->image->blitImage(pcp->driContext, + front->image, + front->linear_buffer, + 0, 0, front->width, + front->height, + 0, 0, front->width, + front->height); } static void dri3_wait_gl(struct glx_context *gc) { + struct dri3_context *pcp = (struct dri3_context *) gc; struct dri3_drawable *priv = (struct dri3_drawable *) GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); + struct dri3_screen *psc; + struct dri3_buffer *front; if (priv == NULL || !priv->have_fake_front) return; - dri3_copy_drawable(priv, priv->base.xDrawable, dri3_fake_front_buffer(priv)->pixmap); + psc = (struct dri3_screen *) priv->base.psc; + front = dri3_fake_front_buffer(priv); + + /* In the psc->is_different_gpu case, we update the linear_buffer + * before updating the real front. + */ + if (psc->is_different_gpu && pcp->driContext) + psc->image->blitImage(pcp->driContext, + front->linear_buffer, + front->image, + 0, 0, front->width, + front->height, + 0, 0, front->width, + front->height); + dri3_copy_drawable(priv, priv->base.xDrawable, front->pixmap); } /** @@ -741,6 +803,7 @@ dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw, struct dri3_screen *psc = (struct dri3_screen *) glx_screen; Display *dpy = glx_screen->dpy; struct dri3_buffer *buffer; + __DRIimage *pixmap_buffer; xcb_connection_t *c = XGetXCBConnection(dpy); xcb_pixmap_t pixmap; xcb_sync_fence_t sync_fence; @@ -769,24 +832,48 @@ dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw, if (!buffer->cpp) goto no_image; - buffer->image = (*psc->image->createImage) (psc->driScreen, - width, height, - format, - __DRI_IMAGE_USE_SHARE|__DRI_IMAGE_USE_SCANOUT, - buffer); - - - if (!buffer->image) - goto no_image; + if (!psc->is_different_gpu) { + buffer->image = (*psc->image->createImage) (psc->driScreen, + width, height, + format, + __DRI_IMAGE_USE_SHARE | + __DRI_IMAGE_USE_SCANOUT, + buffer); + pixmap_buffer = buffer->image; + + if (!buffer->image) + goto no_image; + } else { + buffer->image = (*psc->image->createImage) (psc->driScreen, + width, height, + format, + 0, + buffer); + + if (!buffer->image) + goto no_image; + + buffer->linear_buffer = (*psc->image->createImage) (psc->driScreen, + width, height, + format, + __DRI_IMAGE_USE_SHARE | + __DRI_IMAGE_USE_SCANOUT | + __DRI_IMAGE_USE_LINEAR, + buffer); + pixmap_buffer = buffer->linear_buffer; + + if (!buffer->linear_buffer) + goto no_linear_buffer; + } /* X wants the stride, so ask the image for it */ - if (!(*psc->image->queryImage)(buffer->image, __DRI_IMAGE_ATTRIB_STRIDE, &stride)) + if (!(*psc->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE, &stride)) goto no_buffer_attrib; buffer->pitch = stride; - if (!(*psc->image->queryImage)(buffer->image, __DRI_IMAGE_ATTRIB_FD, &buffer_fd)) + if (!(*psc->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD, &buffer_fd)) goto no_buffer_attrib; xcb_dri3_pixmap_from_buffer(c, @@ -817,7 +904,10 @@ dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw, return buffer; no_buffer_attrib: - (*psc->image->destroyImage)(buffer->image); + (*psc->image->destroyImage)(pixmap_buffer); +no_linear_buffer: + if (psc->is_different_gpu) + (*psc->image->destroyImage)(buffer->image); no_image: free(buffer); no_buffer: @@ -843,6 +933,8 @@ dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer) xcb_sync_destroy_fence(c, buffer->sync_fence); xshmfence_unmap_shm(buffer->shm_fence); (*psc->image->destroyImage)(buffer->image); + if (buffer->linear_buffer) + (*psc->image->destroyImage)(buffer->linear_buffer); free(buffer); } @@ -1118,7 +1210,9 @@ dri3_get_buffer(__DRIdrawable *driDrawable, enum dri3_buffer_type buffer_type, void *loaderPrivate) { + struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext(); struct dri3_drawable *priv = loaderPrivate; + struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); struct dri3_buffer *buffer; int buf_id; @@ -1154,14 +1248,25 @@ dri3_get_buffer(__DRIdrawable *driDrawable, switch (buffer_type) { case dri3_buffer_back: if (buffer) { - dri3_fence_reset(c, new_buffer); - dri3_fence_await(c, buffer); - dri3_copy_area(c, - buffer->pixmap, - new_buffer->pixmap, - dri3_drawable_gc(priv), - 0, 0, 0, 0, priv->width, priv->height); + if (!buffer->linear_buffer) { + dri3_fence_reset(c, new_buffer); + dri3_fence_await(c, buffer); + dri3_copy_area(c, + buffer->pixmap, + new_buffer->pixmap, + dri3_drawable_gc(priv), + 0, 0, 0, 0, priv->width, priv->height); dri3_fence_trigger(c, new_buffer); + } else if (pcp && pcp->driContext) { + /*The pcp check is important. Sometimes pcp->driContext is NULL.*/ + psc->image->blitImage(pcp->driContext, + new_buffer->image, + buffer->image, + 0, 0, priv->width, + priv->height, + 0, 0, priv->width, + priv->height); + } dri3_free_render_buffer(priv, buffer); } break; @@ -1173,6 +1278,17 @@ dri3_get_buffer(__DRIdrawable *driDrawable, dri3_drawable_gc(priv), 0, 0, 0, 0, priv->width, priv->height); dri3_fence_trigger(c, new_buffer); + + if (new_buffer->linear_buffer && pcp && pcp->driContext) { + dri3_fence_await(c, new_buffer); + psc->image->blitImage(pcp->driContext, + new_buffer->image, + new_buffer->linear_buffer, + 0, 0, priv->width, + priv->height, + 0, 0, priv->width, + priv->height); + } break; } buffer = new_buffer; @@ -1235,6 +1351,7 @@ dri3_get_buffers(__DRIdrawable *driDrawable, struct __DRIimageList *buffers) { struct dri3_drawable *priv = loaderPrivate; + struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; struct dri3_buffer *front, *back; buffers->image_mask = 0; @@ -1252,7 +1369,15 @@ dri3_get_buffers(__DRIdrawable *driDrawable, buffer_mask |= __DRI_IMAGE_BUFFER_FRONT; if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { - if (priv->is_pixmap) + /* All pixmaps are owned by the server gpu. + * When we use a different gpu, we can't use the pixmap + * as buffer since it is potentially tiled a way + * our device can't understand. In this case, use + * a fake front buffer. Hopefully the pixmap + * content will get synced with the fake front + * buffer. + */ + if (priv->is_pixmap && !psc->is_different_gpu) front = dri3_get_pixmap_buffer(driDrawable, format, dri3_buffer_front, @@ -1286,7 +1411,7 @@ dri3_get_buffers(__DRIdrawable *driDrawable, if (front) { buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; buffers->front = front->image; - priv->have_fake_front = !priv->is_pixmap; + priv->have_fake_front = psc->is_different_gpu || !priv->is_pixmap; } if (back) { @@ -1322,22 +1447,45 @@ static int64_t dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, int64_t remainder, Bool flush) { + struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext(); struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; Display *dpy = priv->base.psc->dpy; xcb_connection_t *c = XGetXCBConnection(dpy); int buf_id = DRI3_BACK_ID(priv->cur_back); + struct dri3_buffer *back = priv->buffers[buf_id]; int64_t ret = 0; + unsigned flags; + + if (psc->is_different_gpu && back) { + /* Update the linear buffer before presenting the pixmap */ + psc->image->blitImage(pcp->driContext, + back->linear_buffer, + back->image, + 0, 0, back->width, + back->height, + 0, 0, back->width, + back->height); + /* Update the fake front */ + if (priv->have_fake_front) + psc->image->blitImage(pcp->driContext, + priv->buffers[DRI3_FRONT_ID]->image, + back->image, + 0, 0, priv->width, + priv->height, + 0, 0, priv->width, + priv->height); + } - unsigned flags = __DRI2_FLUSH_DRAWABLE; + flags = __DRI2_FLUSH_DRAWABLE; if (flush) flags |= __DRI2_FLUSH_CONTEXT; dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER); dri3_flush_present_events(priv); - if (priv->buffers[buf_id] && !priv->is_pixmap) { - dri3_fence_reset(c, priv->buffers[buf_id]); + if (back && !priv->is_pixmap) { + dri3_fence_reset(c, back); /* Compute when we want the frame shown by taking the last known successful * MSC and adding in a swap interval for each outstanding swap request @@ -1346,11 +1494,11 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, if (target_msc == 0) target_msc = priv->msc + priv->swap_interval * (priv->send_sbc - priv->recv_sbc); - priv->buffers[buf_id]->busy = 1; - priv->buffers[buf_id]->last_swap = priv->send_sbc; + back->busy = 1; + back->last_swap = priv->send_sbc; xcb_present_pixmap(c, priv->base.xDrawable, - priv->buffers[buf_id]->pixmap, + back->pixmap, (uint32_t) priv->send_sbc, 0, /* valid */ 0, /* update */ @@ -1358,7 +1506,7 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 0, /* y_off */ None, /* target_crtc */ None, - priv->buffers[buf_id]->sync_fence, + back->sync_fence, XCB_PRESENT_OPTION_NONE, target_msc, divisor, @@ -1370,10 +1518,10 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, * to reset the fence and make future users block until * the X server is done copying the bits */ - if (priv->have_fake_front) { + if (priv->have_fake_front && !psc->is_different_gpu) { dri3_fence_reset(c, priv->buffers[DRI3_FRONT_ID]); dri3_copy_area(c, - priv->buffers[buf_id]->pixmap, + back->pixmap, priv->buffers[DRI3_FRONT_ID]->pixmap, dri3_drawable_gc(priv), 0, 0, 0, 0, priv->width, priv->height); @@ -1584,7 +1732,12 @@ dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv, "GLX_EXT_create_context_es2_profile"); for (i = 0; extensions[i]; i++) { - if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { + /* when on a different gpu than the server, the server pixmaps + * can have a tiling mode we can't read. Thus we can't create + * a texture from them. + */ + if (!psc->is_different_gpu && + (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); } @@ -1665,6 +1818,8 @@ dri3_create_screen(int screen, struct glx_display * priv) return NULL; } + + psc->fd = loader_get_user_preferred_fd(psc->fd, &psc->is_different_gpu); deviceName = NULL; driverName = loader_get_driver_for_fd(psc->fd, 0); @@ -1731,9 +1886,15 @@ dri3_create_screen(int screen, struct glx_display * priv) goto handle_error; } - if (!psc->texBuffer || psc->texBuffer->base.version < 2 || - !psc->texBuffer->setTexBuffer2) - { + if (psc->is_different_gpu && psc->image->base.version < 9) { + ErrorMessageF("Different GPU, but image extension version 9 or later not found\n"); + goto handle_error; + } + + if (!psc->is_different_gpu && ( + !psc->texBuffer || psc->texBuffer->base.version < 2 || + !psc->texBuffer->setTexBuffer2 + )) { ErrorMessageF("Version 2 or later of texBuffer extension not found\n"); goto handle_error; } diff --git a/src/glx/dri3_priv.h b/src/glx/dri3_priv.h index 6894886..c0e35ee 100644 --- a/src/glx/dri3_priv.h +++ b/src/glx/dri3_priv.h @@ -72,6 +72,7 @@ enum dri3_buffer_type { struct dri3_buffer { __DRIimage *image; + __DRIimage *linear_buffer; uint32_t pixmap; /* Synchronization between the client and X server is done using an @@ -135,6 +136,7 @@ struct dri3_screen { void *driver; int fd; + int is_different_gpu; Bool show_fps; }; -- 1.9.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev