From c4343dfa0a2b40d46d3feb14f1df9fae0fd4a214 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 22 Sep 2009 12:08:19 -0700 Subject: [PATCH] glamor: Add prepare/finishaccess code based on UXA. --- glamor/glamor.c | 12 +++ glamor/glamor_core.c | 245 ++++++++++++++++++++++++++++++++++++++++++- glamor/glamor_priv.h | 14 +++ 3 files changed, 269 insertions(+), 2 deletions(-) diff --git a/glamor/glamor.c b/glamor/glamor.c index 71c8ab20f..507a19be4 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -177,6 +177,10 @@ glamor_init(ScreenPtr screen) ErrorF("GL_ARB_vertex_shader required\n"); goto fail; } + if (!GLEW_ARB_pixel_buffer_object) { + ErrorF("GL_ARB_pixel_buffer_object required\n"); + goto fail; + } if (!RegisterBlockAndWakeupHandlers(glamor_block_handler, glamor_wakeup_handler, @@ -199,6 +203,12 @@ glamor_init(ScreenPtr screen) glamor_priv->saved_get_image = screen->GetImage; screen->GetImage = miGetImage; + glamor_priv->saved_change_window_attributes = screen->ChangeWindowAttributes; + screen->ChangeWindowAttributes = glamor_change_window_attributes; + + glamor_priv->saved_bitmap_to_region = screen->BitmapToRegion; + screen->BitmapToRegion = glamor_bitmap_to_region; + #ifdef RENDER glamor_priv->saved_composite = ps->Composite; ps->Composite = glamor_composite; @@ -231,6 +241,8 @@ glamor_fini(ScreenPtr screen) screen->CreatePixmap = glamor_priv->saved_create_pixmap; screen->DestroyPixmap = glamor_priv->saved_destroy_pixmap; screen->GetSpans = glamor_priv->saved_get_spans; + screen->ChangeWindowAttributes = glamor_priv->saved_change_window_attributes; + screen->BitmapToRegion = glamor_priv->saved_bitmap_to_region; #ifdef RENDER ps->Composite = glamor_priv->saved_composite; #endif diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c index c31e23ced..3c98b5cb0 100644 --- a/glamor/glamor_core.c +++ b/glamor/glamor_core.c @@ -260,6 +260,129 @@ glamor_get_color_4f_from_pixel(PixmapPtr pixmap, unsigned long fg_pixel, } } +Bool +glamor_prepare_access(DrawablePtr drawable, glamor_access_t access) +{ + PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); + glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); + unsigned int stride; + GLenum format, type; + + if (pixmap_priv == NULL) + return TRUE; + + if (pixmap_priv->fb == 0) { + ScreenPtr screen = pixmap->drawable.pScreen; + PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); + + if (pixmap != screen_pixmap) + return TRUE; + } + + stride = PixmapBytePad(drawable->width, drawable->depth); + + switch (drawable->depth) { + case 1: + format = GL_COLOR_INDEX; + type = GL_BITMAP; + break; + case 8: + format = GL_ALPHA; + type = GL_UNSIGNED_BYTE; + break; + case 24: + format = GL_RGB; + type = GL_UNSIGNED_BYTE; + break; + case 32: + format = GL_BGRA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + default: + ErrorF("Unknown prepareaccess depth %d\n", drawable->depth); + return FALSE; + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, pixmap_priv->fb); + glGenBuffersARB(1, &pixmap_priv->pbo); + glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, pixmap_priv->pbo); + glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, stride * drawable->height, + NULL, GL_DYNAMIC_DRAW_ARB); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ROW_LENGTH, stride * 8 / + pixmap->drawable.bitsPerPixel); + + glReadPixels(0, 0, + pixmap->drawable.width, pixmap->drawable.height, + format, type, 0); + + pixmap->devPrivate.ptr = glMapBufferARB(GL_PIXEL_PACK_BUFFER_EXT, + GL_READ_WRITE_ARB); + + return TRUE; +} + +void +glamor_finish_access(DrawablePtr drawable) +{ + PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); + glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); + unsigned int stride; + GLenum format, type; + + if (pixmap_priv == NULL) + return; + + if (pixmap_priv->fb == 0) { + ScreenPtr screen = pixmap->drawable.pScreen; + PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); + + if (pixmap != screen_pixmap) + return; + } + + glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0); + glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pixmap_priv->pbo); + glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT); + pixmap->devPrivate.ptr = NULL; + + stride = PixmapBytePad(drawable->width, drawable->depth); + + switch (drawable->depth) { + case 1: + format = GL_COLOR_INDEX; + type = GL_BITMAP; + break; + case 8: + format = GL_ALPHA; + type = GL_UNSIGNED_BYTE; + break; + case 24: + format = GL_RGB; + type = GL_UNSIGNED_BYTE; + break; + case 32: + format = GL_BGRA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + default: + ErrorF("Unknown finishaccess depth %d\n", drawable->depth); + return; + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, pixmap_priv->fb); + glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pixmap_priv->pbo); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride * 8 / + pixmap->drawable.bitsPerPixel); + + glRasterPos2i(0, 0); + glDrawPixels(pixmap->drawable.width, pixmap->drawable.height, + format, type, 0); + glDeleteBuffersARB(1, &pixmap_priv->pbo); + glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0); +} + void glamor_stipple(PixmapPtr pixmap, PixmapPtr stipple, int x, int y, int width, int height, @@ -364,13 +487,78 @@ GCOps glamor_gc_ops = { }; /** - * exaValidateGC() sets the ops to EXA's implementations, which may be + * uxa_validate_gc() sets the ops to glamor's implementations, which may be * accelerated or may sync the card and fall back to fb. */ static void glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable) { - fbValidateGC(gc, changes, drawable); + /* fbValidateGC will do direct access to pixmaps if the tiling has changed. + * Preempt fbValidateGC by doing its work and masking the change out, so + * that we can do the Prepare/finish_access. + */ +#ifdef FB_24_32BIT + if ((changes & GCTile) && fbGetRotatedPixmap(gc)) { + gc->pScreen->DestroyPixmap(fbGetRotatedPixmap(gc)); + fbGetRotatedPixmap(gc) = 0; + } + + if (gc->fillStyle == FillTiled) { + PixmapPtr old_tile, new_tile; + + old_tile = gc->tile.pixmap; + if (old_tile->drawable.bitsPerPixel != drawable->bitsPerPixel) { + new_tile = fbGetRotatedPixmap(gc); + if (!new_tile || + new_tile ->drawable.bitsPerPixel != drawable->bitsPerPixel) + { + if (new_tile) + gc->pScreen->DestroyPixmap(new_tile); + /* fb24_32ReformatTile will do direct access of a newly- + * allocated pixmap. + */ + if (glamor_prepare_access(&old_tile->drawable, + GLAMOR_ACCESS_RO)) { + new_tile = fb24_32ReformatTile(old_tile, + drawable->bitsPerPixel); + glamor_finish_access(&old_tile->drawable); + } + } + if (new_tile) { + fbGetRotatedPixmap(gc) = old_tile; + gc->tile.pixmap = new_tile; + changes |= GCTile; + } + } + } +#endif + if (changes & GCTile) { + if (!gc->tileIsPixel && FbEvenTile(gc->tile.pixmap->drawable.width * + drawable->bitsPerPixel)) + { + if (glamor_prepare_access(&gc->tile.pixmap->drawable, + GLAMOR_ACCESS_RW)) { + fbPadPixmap(gc->tile.pixmap); + glamor_finish_access(&gc->tile.pixmap->drawable); + } + } + /* Mask out the GCTile change notification, now that we've done FB's + * job for it. + */ + changes &= ~GCTile; + } + + if (changes & GCStipple && gc->stipple) { + /* We can't inline stipple handling like we do for GCTile because + * it sets fbgc privates. + */ + if (glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RW)) { + fbValidateGC(gc, changes, drawable); + glamor_finish_access(&gc->stipple->drawable); + } + } else { + fbValidateGC(gc, changes, drawable); + } gc->ops = &glamor_gc_ops; } @@ -399,3 +587,56 @@ glamor_create_gc(GCPtr gc) return TRUE; } + +Bool +glamor_prepare_access_window(WindowPtr window) +{ + if (window->backgroundState == BackgroundPixmap) { + if (!glamor_prepare_access(&window->background.pixmap->drawable, + GLAMOR_ACCESS_RO)) + return FALSE; + } + + if (window->borderIsPixel == FALSE) { + if (!glamor_prepare_access(&window->border.pixmap->drawable, + GLAMOR_ACCESS_RO)) { + if (window->backgroundState == BackgroundPixmap) + glamor_finish_access(&window->background.pixmap->drawable); + return FALSE; + } + } + return TRUE; +} + +void +glamor_finish_access_window(WindowPtr window) +{ + if (window->backgroundState == BackgroundPixmap) + glamor_finish_access(&window->background.pixmap->drawable); + + if (window->borderIsPixel == FALSE) + glamor_finish_access(&window->border.pixmap->drawable); +} + +Bool +glamor_change_window_attributes(WindowPtr window, unsigned long mask) +{ + Bool ret; + + if (!glamor_prepare_access_window(window)) + return FALSE; + ret = fbChangeWindowAttributes(window, mask); + glamor_finish_access_window(window); + return ret; +} + +RegionPtr +glamor_bitmap_to_region(PixmapPtr pixmap) +{ + RegionPtr ret; + if (!glamor_prepare_access(&pixmap->drawable, GLAMOR_ACCESS_RO)) + return NULL; + ret = fbPixmapToRegion(pixmap); + glamor_finish_access(&pixmap->drawable); + return ret; +} diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index 93a0115e1..81bb035f5 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -31,6 +31,11 @@ #include "glamor.h" #include +typedef enum glamor_access { + GLAMOR_ACCESS_RO, + GLAMOR_ACCESS_RW, +} glamor_access_t; + typedef struct glamor_transform_uniforms { GLint x_bias; GLint x_scale; @@ -55,6 +60,8 @@ typedef struct glamor_screen_private { GetImageProcPtr saved_get_image; CompositeProcPtr saved_composite; TrapezoidsProcPtr saved_trapezoids; + ChangeWindowAttributesProcPtr saved_change_window_attributes; + BitmapToRegionProcPtr saved_bitmap_to_region; /* glamor_solid */ GLint solid_prog; @@ -78,6 +85,7 @@ typedef struct glamor_screen_private { typedef struct glamor_pixmap_private { GLuint tex; GLuint fb; + GLuint pbo; } glamor_pixmap_private; extern DevPrivateKey glamor_screen_private_key; @@ -117,6 +125,10 @@ RegionPtr glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc, int srcx, int srcy, int width, int height, int dstx, int dsty); /* glamor_core.c */ +Bool glamor_prepare_access(DrawablePtr drawable, glamor_access_t access); +void glamor_finish_access(DrawablePtr drawable); +Bool glamor_prepare_access_window(WindowPtr window); +void glamor_finish_access_window(WindowPtr window); Bool glamor_create_gc(GCPtr gc); void glamor_stipple(PixmapPtr pixmap, PixmapPtr stipple, int x, int y, int width, int height, @@ -134,6 +146,8 @@ void glamor_get_transform_uniform_locations(GLint prog, glamor_transform_uniforms *uniform_locations); void glamor_set_transform_for_pixmap(PixmapPtr pixmap, glamor_transform_uniforms *uniform_locations); +Bool glamor_change_window_attributes(WindowPtr pWin, unsigned long mask); +RegionPtr glamor_bitmap_to_region(PixmapPtr pixmap); /* glamor_fill.c */ void glamor_fill(DrawablePtr drawable,