[Mesa-dev] [PATCH V2 09/11] GLX/DRI3: Add Gpu offloading support.
Axel Davy
axel.davy at ens.fr
Wed May 28 20:22:03 PDT 2014
Signed-off-by: Axel Davy <axel.davy at 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
More information about the mesa-dev
mailing list