From 519103565c1b182014dea93c58917bf7e5a35fcb Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 20 Aug 2009 15:28:13 -0700 Subject: [PATCH] glamor: Create FBOs for pixmaps. --- glamor/glamor.c | 64 ++++++++++++++++++++++- glamor/glamor_core.c | 107 ++++++++++++++++++-------------------- glamor/glamor_fillspans.c | 8 --- glamor/glamor_getspans.c | 51 +++++++++--------- glamor/glamor_priv.h | 11 ++++ 5 files changed, 148 insertions(+), 93 deletions(-) diff --git a/glamor/glamor.c b/glamor/glamor.c index 0aa9db83b..7b81abab2 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -40,6 +40,8 @@ static int glamor_screen_private_key_index; DevPrivateKey glamor_screen_private_key = &glamor_screen_private_key_index; +static int glamor_pixmap_private_key_index; +DevPrivateKey glamor_pixmap_private_key = &glamor_pixmap_private_key_index; /** * glamor_get_drawable_pixmap() returns a backing pixmap for a given drawable. @@ -63,9 +65,57 @@ glamor_get_drawable_pixmap(DrawablePtr drawable) static PixmapPtr glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth, - unsigned int usage_hint) + unsigned int usage) { - return fbCreatePixmap(screen, w, h, depth, usage_hint); + PixmapPtr pixmap; + glamor_pixmap_private *pixmap_priv; + GLenum format; + + if (w > 32767 || h > 32767) + return NullPixmap; + + pixmap = fbCreatePixmap (screen, 0, 0, depth, usage); + pixmap_priv = glamor_get_pixmap_private(pixmap); + + if (w == 0 || h == 0) + return pixmap; + + /* We should probably take advantage of ARB_fbo's allowance of GL_ALPHA. + * FBOs, which EXT_fbo forgot to do. + */ + switch (depth) { + case 24: + format = GL_RGB; + break; + default: + format = GL_RGBA; + break; + } + + /* Create the texture used to store the pixmap's data. */ + glGenTextures(1, &pixmap_priv->tex); + glBindTexture(GL_TEXTURE_2D, pixmap_priv->tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, + format, GL_UNSIGNED_BYTE, NULL); + + /* Create a framebuffer object wrapping the texture so that we can render + * to it. + */ + glGenFramebuffersEXT(1, &pixmap_priv->fb); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, pixmap_priv->fb); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, + pixmap_priv->tex, + 0); + + screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, + (w * pixmap->drawable.bitsPerPixel + 7) / 8, + NULL); + + return pixmap; } static Bool @@ -96,9 +146,19 @@ glamor_init(ScreenPtr screen) return FALSE; dixSetPrivate(&screen->devPrivates, glamor_screen_private_key, glamor_priv); + if (!dixRequestPrivate(glamor_pixmap_private_key, + sizeof(glamor_pixmap_private))) { + LogMessage(X_WARNING, + "glamor%d: Failed to allocate pixmap private\n", + screen->myNum); + } glewInit(); + if (!GLEW_EXT_framebuffer_object) { + ErrorF("GL_EXT_framebuffer_object required\n"); + goto fail; + } if (!GLEW_ARB_shader_objects) { ErrorF("GL_ARB_shader_objects required\n"); goto fail; diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c index c8b331a18..ffccd3e12 100644 --- a/glamor/glamor_core.c +++ b/glamor/glamor_core.c @@ -42,17 +42,28 @@ Bool glamor_set_destination_pixmap(PixmapPtr pixmap) { - ScreenPtr screen = pixmap->drawable.pScreen; - PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); + glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); - if (pixmap != screen_pixmap) { - ErrorF("stubbed drawing to non-screen pixmap\n"); + if (pixmap_priv == NULL) { + ErrorF("no pixmap priv?"); return FALSE; } + if (pixmap_priv->fb == 0) { + ScreenPtr screen = pixmap->drawable.pScreen; + PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); + + if (pixmap != screen_pixmap) { + ErrorF("No FBO\n"); + return FALSE; + } + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, pixmap_priv->fb); + glViewport(0, 0, - screen_pixmap->drawable.width, - screen_pixmap->drawable.height); + pixmap->drawable.width, + pixmap->drawable.height); return TRUE; } @@ -75,10 +86,18 @@ void glamor_set_transform_for_pixmap(PixmapPtr pixmap, glamor_transform_uniforms *uniform_locations) { + ScreenPtr screen = pixmap->drawable.pScreen; + PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); + glUniform1fARB(uniform_locations->x_bias, -pixmap->drawable.width / 2.0f); glUniform1fARB(uniform_locations->x_scale, 2.0f / pixmap->drawable.width); glUniform1fARB(uniform_locations->y_bias, -pixmap->drawable.height / 2.0f); - glUniform1fARB(uniform_locations->y_scale, -2.0f / pixmap->drawable.height); + if (pixmap == screen_pixmap) + glUniform1fARB(uniform_locations->y_scale, + -2.0f / pixmap->drawable.height); + else + glUniform1fARB(uniform_locations->y_scale, + 2.0f / pixmap->drawable.height); } GLint @@ -176,53 +195,38 @@ static void glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y, int w, int h, int leftPad, int format, char *bits) { - ScreenPtr screen = drawable->pScreen; - PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); - PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(drawable); - - if (screen_pixmap != dest_pixmap) { - fbPutImage(drawable, gc, depth, x, y, w, h, leftPad, format, bits); - } else { - ErrorF("stub put_image\n"); - } + ErrorF("stub put_image\n"); } static void glamor_set_spans(DrawablePtr drawable, GCPtr gc, char *src, DDXPointPtr points, int *widths, int n, int sorted) { - ScreenPtr screen = drawable->pScreen; - PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(drawable); + GLenum format, type; + int i; - if (screen_pixmap != dest_pixmap) { - fbSetSpans(drawable, gc, src, points, widths, n, sorted); - } else { - GLenum format, type; - int i; + switch (drawable->depth) { + case 24: + case 32: + format = GL_BGRA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + default: + ErrorF("Unknown setspans depth %d\n", drawable->depth); + return; + } - switch (drawable->depth) { - case 24: - case 32: - format = GL_BGRA; - type = GL_UNSIGNED_INT_8_8_8_8_REV; - break; - default: - ErrorF("Unknown setspans depth %d\n", drawable->depth); - return; - } - - if (!glamor_set_destination_pixmap(dest_pixmap)) - return; - for (i = 0; i < n; i++) { - glRasterPos2i(points[i].x - dest_pixmap->screen_x, - points[i].y - dest_pixmap->screen_y); - glDrawPixels(widths[i], - 1, - format, type, - src); - src += PixmapBytePad(widths[i], drawable->depth); - } + if (!glamor_set_destination_pixmap(dest_pixmap)) + return; + for (i = 0; i < n; i++) { + glRasterPos2i(points[i].x - dest_pixmap->screen_x, + points[i].y - dest_pixmap->screen_y); + glDrawPixels(widths[i], + 1, + format, type, + src); + src += PixmapBytePad(widths[i], drawable->depth); } } @@ -235,9 +239,6 @@ static void glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n, DDXPointPtr points) { - ScreenPtr screen = drawable->pScreen; - PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); - PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(drawable); xRectangle *rects; int x1, x2, y1, y2; int i; @@ -245,10 +246,7 @@ glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n, /* Don't try to do wide lines or non-solid fill style. */ if (gc->lineWidth != 0 || gc->lineStyle != LineSolid || gc->fillStyle != FillSolid) { - if (dest_pixmap != screen_pixmap) - fbPolyLine(drawable, gc, mode, n, points); - else - ErrorF("stub poly_line\n"); + ErrorF("stub poly_line\n"); return; } @@ -267,10 +265,7 @@ glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n, if (x1 != x2 && y1 != y2) { xfree(rects); - if (dest_pixmap != screen_pixmap) - fbPolyLine(drawable, gc, mode, n, points); - else - ErrorF("stub poly_line\n"); + ErrorF("stub poly_line\n"); return; } diff --git a/glamor/glamor_fillspans.c b/glamor/glamor_fillspans.c index b0b704fd9..120e3467d 100644 --- a/glamor/glamor_fillspans.c +++ b/glamor/glamor_fillspans.c @@ -44,14 +44,6 @@ glamor_fill_spans(DrawablePtr drawable, int extentX1, extentX2, extentY1, extentY2; int fullX1, fullX2, fullY1; int partX1, partX2; - ScreenPtr screen = drawable->pScreen; - PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); - PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(drawable); - - if (dest_pixmap != screen_pixmap) { - fbFillSpans(drawable, gc, n, points, widths, sorted); - return; - } extents = REGION_EXTENTS(gc->pScreen, clip); extentX1 = extents->x1; diff --git a/glamor/glamor_getspans.c b/glamor/glamor_getspans.c index b10a29dcd..8466208d7 100644 --- a/glamor/glamor_getspans.c +++ b/glamor/glamor_getspans.c @@ -39,36 +39,33 @@ glamor_get_spans(DrawablePtr drawable, int count, char *dst) { - ScreenPtr screen = drawable->pScreen; - PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); + GLenum format, type; + int i; - if (screen_pixmap != pixmap) { + switch (drawable->depth) { + case 24: + case 32: + format = GL_BGRA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + default: + ErrorF("Unknown getspans depth %d\n", drawable->depth); + return; + } + + if (!glamor_set_destination_pixmap(pixmap)) { fbGetSpans(drawable, wmax, points, widths, count, dst); return; - } else { - GLenum format, type; - int i; - switch (drawable->depth) { - case 24: - case 32: - format = GL_BGRA; - type = GL_UNSIGNED_INT_8_8_8_8_REV; - break; - default: - ErrorF("Unknown getspans depth %d\n", drawable->depth); - return; - } - if (!glamor_set_destination_pixmap(pixmap)) - return; - for (i = 0; i < count; i++) { - glReadPixels(points[i].x - pixmap->screen_x, - points[i].y - pixmap->screen_y, - widths[i], - 1, - format, type, - dst); - dst += PixmapBytePad(widths[i], drawable->depth); - } + } + + for (i = 0; i < count; i++) { + glReadPixels(points[i].x - pixmap->screen_x, + points[i].y - pixmap->screen_y, + widths[i], + 1, + format, type, + dst); + dst += PixmapBytePad(widths[i], drawable->depth); } } diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index 016a404bc..6d08b00c6 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -50,13 +50,24 @@ typedef struct glamor_screen_private { glamor_transform_uniforms solid_transform; } glamor_screen_private; +typedef struct glamor_pixmap_private { + GLuint tex; + GLuint fb; +} glamor_pixmap_private; + extern DevPrivateKey glamor_screen_private_key; +extern DevPrivateKey glamor_pixmap_private_key; static inline glamor_screen_private * glamor_get_screen_private(ScreenPtr screen) { return (glamor_screen_private *)dixLookupPrivate(&screen->devPrivates, glamor_screen_private_key); } +static inline glamor_pixmap_private * +glamor_get_pixmap_private(PixmapPtr pixmap) +{ + return dixLookupPrivate(&pixmap->devPrivates, glamor_pixmap_private_key); +} /* glamor.c */ PixmapPtr glamor_get_drawable_pixmap(DrawablePtr drawable);