summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/glx/dri3_glx.c218
-rw-r--r--src/glx/dri3_priv.h2
2 files changed, 188 insertions, 32 deletions
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
index 3092bc1e991..e3fc4def86e 100644
--- a/src/glx/dri3_glx.c
+++ b/src/glx/dri3_glx.c
@@ -596,22 +596,44 @@ 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);
+ struct dri3_buffer *back;
- unsigned flags;
+ unsigned flags = __DRI2_FLUSH_DRAWABLE;
/* Check we have the right attachments */
if (!priv->have_back || priv->is_pixmap)
return;
- flags = __DRI2_FLUSH_DRAWABLE;
if (flush)
flags |= __DRI2_FLUSH_CONTEXT;
dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
+ back = dri3_back_buffer(priv);
y = priv->height - y - height;
+ if (psc->is_different_gpu && (&pcp->base != &dummyContext) && pcp->base.psc == &psc->base) {
+ /* 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, __BLIT_FLAG_FLUSH);
+ /* 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, __BLIT_FLAG_FLUSH);
+ }
+
dri3_fence_reset(c, back);
dri3_copy_area(c,
dri3_back_buffer(priv)->pixmap,
@@ -622,7 +644,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 +677,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->base != &dummyContext) && pcp->base.psc == &psc->base)
+ psc->image->blitImage(pcp->driContext,
+ front->image,
+ front->linear_buffer,
+ 0, 0, front->width,
+ front->height,
+ 0, 0, front->width,
+ front->height, 0);
}
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->base != &dummyContext) && pcp->base.psc == &psc->base)
+ psc->image->blitImage(pcp->driContext,
+ front->linear_buffer,
+ front->image,
+ 0, 0, front->width,
+ front->height,
+ 0, 0, front->width,
+ front->height, __BLIT_FLAG_FLUSH);
+ dri3_copy_drawable(priv, priv->base.xDrawable, front->pixmap);
}
/**
@@ -741,6 +800,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 +829,47 @@ 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_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 +900,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 +929,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 +1206,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 +1244,24 @@ 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->base != &dummyContext) && pcp->base.psc == &psc->base) {
+ psc->image->blitImage(pcp->driContext,
+ new_buffer->image,
+ buffer->image,
+ 0, 0, priv->width,
+ priv->height,
+ 0, 0, priv->width,
+ priv->height, 0);
+ }
dri3_free_render_buffer(priv, buffer);
}
break;
@@ -1173,6 +1273,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->base != &dummyContext) && pcp->base.psc == &psc->base) {
+ 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, 0);
+ }
break;
}
buffer = new_buffer;
@@ -1235,6 +1346,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 +1364,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 +1406,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) {
@@ -1327,6 +1447,7 @@ 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;
@@ -1340,6 +1461,26 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
back = priv->buffers[DRI3_BACK_ID(priv->cur_back)];
+ 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, __BLIT_FLAG_FLUSH);
+ /* 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, __BLIT_FLAG_FLUSH);
+ }
+
dri3_flush_present_events(priv);
if (back && !priv->is_pixmap) {
@@ -1376,7 +1517,7 @@ 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,
back->pixmap,
@@ -1592,7 +1733,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");
}
@@ -1676,6 +1822,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);
@@ -1735,9 +1883,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 689488641a1..c0e35ee4bbf 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;
};