diff options
-rw-r--r-- | src/gallium/state_trackers/egl/x11/native_dri2.c | 312 |
1 files changed, 182 insertions, 130 deletions
diff --git a/src/gallium/state_trackers/egl/x11/native_dri2.c b/src/gallium/state_trackers/egl/x11/native_dri2.c index 5f2fd412604..dbd1a64992d 100644 --- a/src/gallium/state_trackers/egl/x11/native_dri2.c +++ b/src/gallium/state_trackers/egl/x11/native_dri2.c @@ -62,10 +62,15 @@ struct dri2_surface { enum pipe_format color_format; struct dri2_display *dri2dpy; - struct pipe_texture *pbuffer_textures[NUM_NATIVE_ATTACHMENTS]; - boolean have_back, have_fake; - int width, height; unsigned int sequence_number; + int width, height; + struct pipe_texture *textures[NUM_NATIVE_ATTACHMENTS]; + uint valid_mask; + + boolean have_back, have_fake; + + struct x11_drawable_buffer *last_xbufs; + int last_num_xbufs; }; struct dri2_config { @@ -90,110 +95,24 @@ dri2_config(const struct native_config *nconf) return (struct dri2_config *) nconf; } -static boolean -dri2_surface_flush_frontbuffer(struct native_surface *nsurf) -{ - struct dri2_surface *dri2surf = dri2_surface(nsurf); - struct dri2_display *dri2dpy = dri2surf->dri2dpy; - - /* pbuffer is private */ - if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER) - return TRUE; - - /* copy to real front buffer */ - if (dri2surf->have_fake) - x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, - 0, 0, dri2surf->width, dri2surf->height, - DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); - - return TRUE; -} - -static boolean -dri2_surface_swap_buffers(struct native_surface *nsurf) -{ - struct dri2_surface *dri2surf = dri2_surface(nsurf); - struct dri2_display *dri2dpy = dri2surf->dri2dpy; - - /* pbuffer is private */ - if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER) - return TRUE; - - /* copy to front buffer */ - if (dri2surf->have_back) - x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, - 0, 0, dri2surf->width, dri2surf->height, - DRI2BufferBackLeft, DRI2BufferFrontLeft); - - /* and update fake front buffer */ - if (dri2surf->have_fake) - x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, - 0, 0, dri2surf->width, dri2surf->height, - DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); - - return TRUE; -} - -static boolean -dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask, - unsigned int *seq_num, struct pipe_texture **textures, - int *width, int *height) +/** + * Get the buffers from the server. + */ +static void +dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask) { struct dri2_surface *dri2surf = dri2_surface(nsurf); struct dri2_display *dri2dpy = dri2surf->dri2dpy; unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS]; - struct pipe_texture templ; - struct x11_drawable_buffer *xbufs; int num_ins, num_outs, att, i; - - if (attachment_mask) { - memset(&templ, 0, sizeof(templ)); - templ.target = PIPE_TEXTURE_2D; - templ.last_level = 0; - templ.width0 = dri2surf->width; - templ.height0 = dri2surf->height; - templ.depth0 = 1; - templ.format = dri2surf->color_format; - templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; - - if (textures) - memset(textures, 0, sizeof(*textures) * NUM_NATIVE_ATTACHMENTS); - } - - /* create textures for pbuffer */ - if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER) { - struct pipe_screen *screen = dri2dpy->base.screen; - - for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { - struct pipe_texture *ptex = dri2surf->pbuffer_textures[att]; - - /* delay the allocation */ - if (!native_attachment_mask_test(attachment_mask, att)) - continue; - - if (!ptex) { - ptex = screen->texture_create(screen, &templ); - dri2surf->pbuffer_textures[att] = ptex; - } - - if (textures) - pipe_texture_reference(&textures[att], ptex); - } - - if (seq_num) - *seq_num = dri2surf->sequence_number; - if (width) - *width = dri2surf->width; - if (height) - *height = dri2surf->height; - - return TRUE; - } + struct x11_drawable_buffer *xbufs; + struct pipe_texture templ; + uint valid_mask; /* prepare the attachments */ num_ins = 0; for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { - if (native_attachment_mask_test(attachment_mask, att)) { + if (native_attachment_mask_test(buffer_mask, att)) { unsigned int dri2att; switch (att) { @@ -220,27 +139,39 @@ dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask, } } - dri2surf->have_back = FALSE; - dri2surf->have_fake = FALSE; - - /* remember old geometry */ - templ.width0 = dri2surf->width; - templ.height0 = dri2surf->height; - xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable, &dri2surf->width, &dri2surf->height, dri2atts, FALSE, num_ins, &num_outs); - if (!xbufs) - return FALSE; - - if (templ.width0 != dri2surf->width || templ.height0 != dri2surf->height) { - /* are there cases where the buffers change and the geometry doesn't? */ - dri2surf->sequence_number++; - templ.width0 = dri2surf->width; - templ.height0 = dri2surf->height; + /* we should be able to do better... */ + if (xbufs && dri2surf->last_num_xbufs == num_outs && + memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) { + free(xbufs); + return; } + /* free the old buffers */ + for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) + pipe_texture_reference(&dri2surf->textures[i], NULL); + dri2surf->valid_mask = 0x0; + dri2surf->sequence_number++; + + dri2surf->have_back = FALSE; + dri2surf->have_fake = FALSE; + + if (!xbufs) + return; + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.last_level = 0; + templ.width0 = dri2surf->width; + templ.height0 = dri2surf->height; + templ.depth0 = 1; + templ.format = dri2surf->color_format; + templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; + + valid_mask = 0x0; for (i = 0; i < num_outs; i++) { struct x11_drawable_buffer *xbuf = &xbufs[i]; const char *desc; @@ -266,33 +197,151 @@ dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask, break; } - if (!desc || !native_attachment_mask_test(attachment_mask, natt) || - (textures && textures[natt])) { + if (!desc || dri2surf->textures[natt]) { if (!desc) _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment); - else if (!native_attachment_mask_test(attachment_mask, natt)) - _eglLog(_EGL_WARNING, "unexpected buffer %d", xbuf->attachment); else _eglLog(_EGL_WARNING, "both real and fake front buffers are listed"); continue; } - if (textures) { - struct pipe_texture *ptex = - dri2dpy->api->texture_from_shared_handle(dri2dpy->api, - dri2dpy->base.screen, &templ, - desc, xbuf->pitch, xbuf->name); - if (ptex) { - /* the caller owns the textures */ - textures[natt] = ptex; + dri2surf->textures[natt] = + dri2dpy->api->texture_from_shared_handle(dri2dpy->api, + dri2dpy->base.screen, &templ, desc, xbuf->pitch, xbuf->name); + if (dri2surf->textures[natt]) + valid_mask |= 1 << natt; + } + + if (dri2surf->last_xbufs) + free(dri2surf->last_xbufs); + dri2surf->last_xbufs = xbufs; + dri2surf->last_num_xbufs = num_outs; + + dri2surf->valid_mask = valid_mask; +} + +/** + * Update the buffers of the surface. This is a slow function due to the + * round-trip to the server. + */ +static boolean +dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask) +{ + struct dri2_surface *dri2surf = dri2_surface(nsurf); + struct dri2_display *dri2dpy = dri2surf->dri2dpy; + + /* create textures for pbuffer */ + if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER) { + struct pipe_screen *screen = dri2dpy->base.screen; + struct pipe_texture templ; + uint new_valid = 0x0; + int att; + + buffer_mask &= ~dri2surf->valid_mask; + if (!buffer_mask) + return TRUE; + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.last_level = 0; + templ.width0 = dri2surf->width; + templ.height0 = dri2surf->height; + templ.depth0 = 1; + templ.format = dri2surf->color_format; + templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; + + for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { + if (native_attachment_mask_test(buffer_mask, att)) { + assert(!dri2surf->textures[att]); + + dri2surf->textures[att] = screen->texture_create(screen, &templ); + if (!dri2surf->textures[att]) + break; + + new_valid |= 1 << att; + if (new_valid == buffer_mask) + break; } } + dri2surf->valid_mask |= new_valid; + /* no need to update sequence number */ } + else { + dri2_surface_get_buffers(&dri2surf->base, buffer_mask); + } + + return ((dri2surf->valid_mask & buffer_mask) == buffer_mask); +} + +static boolean +dri2_surface_flush_frontbuffer(struct native_surface *nsurf) +{ + struct dri2_surface *dri2surf = dri2_surface(nsurf); + struct dri2_display *dri2dpy = dri2surf->dri2dpy; - free(xbufs); + /* pbuffer is private */ + if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER) + return TRUE; + + /* copy to real front buffer */ + if (dri2surf->have_fake) + x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, + 0, 0, dri2surf->width, dri2surf->height, + DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); + + return TRUE; +} + +static boolean +dri2_surface_swap_buffers(struct native_surface *nsurf) +{ + struct dri2_surface *dri2surf = dri2_surface(nsurf); + struct dri2_display *dri2dpy = dri2surf->dri2dpy; + + /* pbuffer is private */ + if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER) + return TRUE; + + /* copy to front buffer */ + if (dri2surf->have_back) + x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, + 0, 0, dri2surf->width, dri2surf->height, + DRI2BufferBackLeft, DRI2BufferFrontLeft); + + /* and update fake front buffer */ + if (dri2surf->have_fake) + x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, + 0, 0, dri2surf->width, dri2surf->height, + DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); + + return TRUE; +} + +static boolean +dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask, + unsigned int *seq_num, struct pipe_texture **textures, + int *width, int *height) +{ + struct dri2_surface *dri2surf = dri2_surface(nsurf); + + if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask)) + return FALSE; if (seq_num) *seq_num = dri2surf->sequence_number; + + if (textures) { + int att; + for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { + if (native_attachment_mask_test(attachment_mask, att)) { + struct pipe_texture *ptex = dri2surf->textures[att]; + + textures[att] = NULL; + pipe_texture_reference(&textures[att], ptex); + } + } + } + if (width) *width = dri2surf->width; if (height) @@ -320,8 +369,11 @@ dri2_surface_destroy(struct native_surface *nsurf) struct dri2_surface *dri2surf = dri2_surface(nsurf); int i; + if (dri2surf->last_xbufs) + free(dri2surf->last_xbufs); + for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) { - struct pipe_texture *ptex = dri2surf->pbuffer_textures[i]; + struct pipe_texture *ptex = dri2surf->textures[i]; pipe_texture_reference(&ptex, NULL); } @@ -345,9 +397,6 @@ dri2_display_create_surface(struct native_display *ndpy, if (!dri2surf) return NULL; - if (drawable) - x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE); - dri2surf->dri2dpy = dri2dpy; dri2surf->type = type; dri2surf->drawable = drawable; @@ -359,6 +408,9 @@ dri2_display_create_surface(struct native_display *ndpy, dri2surf->base.validate = dri2_surface_validate; dri2surf->base.wait = dri2_surface_wait; + if (drawable) + x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE); + return dri2surf; } |