diff --git a/glamor/glamor.c b/glamor/glamor.c index 9b9d82304..6e843f437 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -164,7 +164,7 @@ glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth, if (w == 0 || h == 0) return pixmap; - fbo = glamor_create_fbo(glamor_priv, w, h, depth, 0); + fbo = glamor_create_fbo(glamor_priv, w, h, depth, usage); if (fbo == NULL) { fbDestroyPixmap(pixmap); diff --git a/glamor/glamor_fbo.c b/glamor/glamor_fbo.c index 97ba33c1c..9b6a05ef0 100644 --- a/glamor/glamor_fbo.c +++ b/glamor/glamor_fbo.c @@ -90,7 +90,7 @@ glamor_pixmap_fbo_cache_get(glamor_screen_private *glamor_priv, [cache_hbucket(h)]; if (flag != GLAMOR_CACHE_EXACT_SIZE) { list_for_each_entry(fbo_entry, cache, list) { - if (fbo_entry->width == w && fbo_entry->height == h) { + if (fbo_entry->width >= w && fbo_entry->height >= h) { DEBUGF("Request w %d h %d \n", w, h); DEBUGF("got cache entry %p w %d h %d fbo %d tex %d\n", @@ -263,7 +263,7 @@ glamor_create_fbo(glamor_screen_private *glamor_priv, gl_iformat_for_depth(depth, &format); fbo = glamor_pixmap_fbo_cache_get(glamor_priv, w, h, - format, GLAMOR_CACHE_EXACT_SIZE); + format, cache_flag); if (fbo) return fbo; diff --git a/glamor/glamor_pixmap.c b/glamor/glamor_pixmap.c index f001962e7..2020e2145 100644 --- a/glamor/glamor_pixmap.c +++ b/glamor/glamor_pixmap.c @@ -216,7 +216,7 @@ glamor_set_alu(struct glamor_gl_dispatch *dispatch, unsigned char alu) int in_restore = 0; static void __glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format, - GLenum type, GLuint tex) + GLenum type, GLuint tex, int sub) { glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); @@ -255,12 +255,19 @@ __glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format, } else texels = pixmap->devPrivate.ptr; - dispatch->glTexImage2D(GL_TEXTURE_2D, - 0, - iformat, - pixmap->drawable.width, - pixmap->drawable.height, 0, format, type, - texels); + if (sub) + dispatch->glTexSubImage2D(GL_TEXTURE_2D, + 0,0,0, + pixmap->drawable.width, + pixmap->drawable.height, format, type, + texels); + else + dispatch->glTexImage2D(GL_TEXTURE_2D, + 0, + iformat, + pixmap->drawable.width, + pixmap->drawable.height, 0, format, type, + texels); } @@ -280,11 +287,7 @@ _glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format, glamor_screen_private *glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen); glamor_gl_dispatch *dispatch = &glamor_priv->dispatch; - static float vertices[8] = { -1, -1, - 1, -1, - 1, 1, - -1, 1 - }; + static float vertices[8]; static float texcoords[8] = { 0, 1, 1, 1, 1, 0, @@ -296,7 +299,7 @@ _glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format, 0, 1 }; float *ptexcoords; - + float dst_xscale, dst_yscale; GLuint tex; int need_flip; @@ -315,16 +318,23 @@ _glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format, * to the fbo directly. */ if (no_alpha == 0 && no_revert == 1 && !need_flip) { __glamor_upload_pixmap_to_texture(pixmap, format, type, - pixmap_priv->fbo->tex); + pixmap_priv->fbo->tex, 1); return; } - if (need_flip) ptexcoords = texcoords; else ptexcoords = texcoords_inv; + pixmap_priv_get_scale(pixmap_priv, &dst_xscale, &dst_yscale); + glamor_set_normalize_vcoords(dst_xscale, + dst_yscale, + 0, 0, + pixmap->drawable.width, pixmap->drawable.height, + glamor_priv->yInverted, + vertices); + /* Slow path, we need to flip y or wire alpha to 1. */ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), @@ -338,7 +348,7 @@ _glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format, glamor_set_destination_pixmap_priv_nc(pixmap_priv); dispatch->glGenTextures(1, &tex); - __glamor_upload_pixmap_to_texture(pixmap, format, type, tex); + __glamor_upload_pixmap_to_texture(pixmap, format, type, tex, 0); dispatch->glActiveTexture(GL_TEXTURE0); dispatch->glBindTexture(GL_TEXTURE_2D, tex); @@ -791,3 +801,66 @@ glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access) return TRUE; } + +/* fixup a fbo to the exact size as the pixmap. */ +Bool +glamor_fixup_pixmap_priv(ScreenPtr screen, glamor_pixmap_private *pixmap_priv) +{ + glamor_screen_private *glamor_priv; + glamor_pixmap_fbo *old_fbo; + glamor_pixmap_fbo *new_fbo = NULL; + PixmapPtr scratch = NULL; + glamor_pixmap_private *scratch_priv; + DrawablePtr drawable; + GCPtr gc = NULL; + int ret = FALSE; + + drawable = &pixmap_priv->container->drawable; + + if (pixmap_priv->container->drawable.width == pixmap_priv->fbo->width + && pixmap_priv->container->drawable.height == pixmap_priv->fbo->height) + return TRUE; + + old_fbo = pixmap_priv->fbo; + glamor_priv = pixmap_priv->glamor_priv; + + if (!old_fbo) + return FALSE; + + gc = GetScratchGC(drawable->depth, screen); + if (!gc) + goto fail; + + scratch = glamor_create_pixmap(screen, drawable->width, drawable->height, + drawable->depth, + GLAMOR_CREATE_PIXMAP_FIXUP); + + scratch_priv = glamor_get_pixmap_private(scratch); + + if (!scratch_priv || !scratch_priv->fbo) + goto fail; + + ValidateGC(&scratch->drawable, gc); + glamor_copy_area(drawable, + &scratch->drawable, + gc, 0, 0, + drawable->width, drawable->height, + 0, 0); + old_fbo = glamor_pixmap_detach_fbo(pixmap_priv); + new_fbo = glamor_pixmap_detach_fbo(scratch_priv); + glamor_pixmap_attach_fbo(pixmap_priv->container, new_fbo); + glamor_pixmap_attach_fbo(scratch, old_fbo); + + DEBUGF("old %dx%d type %d\n", + drawable->width, drawable->height, pixmap_priv->type); + DEBUGF("copy tex %d %dx%d to tex %d %dx%d \n", + old_fbo->tex, old_fbo->width, old_fbo->height, new_fbo->tex, new_fbo->width, new_fbo->height); + ret = TRUE; +fail: + if (gc) + FreeScratchGC(gc); + if (scratch) + glamor_destroy_pixmap(scratch); + + return ret; +} diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index 31f9c93ca..66e47c662 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -594,6 +594,10 @@ void glamor_destroy_picture(PicturePtr picture); enum glamor_pixmap_status glamor_upload_picture_to_texture(PicturePtr picture); +/* fixup a fbo to the exact size as the pixmap. */ +Bool +glamor_fixup_pixmap_priv(ScreenPtr screen, glamor_pixmap_private *pixmap_priv); + void glamor_picture_format_fixup(PicturePtr picture, glamor_pixmap_private * pixmap_priv); diff --git a/glamor/glamor_render.c b/glamor/glamor_render.c index 19ed22e55..03f7e3207 100644 --- a/glamor/glamor_render.c +++ b/glamor/glamor_render.c @@ -342,7 +342,6 @@ glamor_fini_composite_shaders(ScreenPtr screen) dispatch->glDeleteBuffers(1, &glamor_priv->vbo); dispatch->glDeleteBuffers(1, &glamor_priv->ebo); - for(i = 0; i < SHADER_SOURCE_COUNT; i++) for(j = 0; j < SHADER_MASK_COUNT; j++) for(k = 0; k < SHADER_IN_COUNT; k++) @@ -408,6 +407,33 @@ glamor_set_composite_op(ScreenPtr screen, return TRUE; } +static void +glamor_composite_texture_fixup(ScreenPtr screen, + PicturePtr picture, + glamor_pixmap_private * pixmap_priv) +{ + glamor_screen_private *glamor_priv = + glamor_get_screen_private(screen); + glamor_gl_dispatch *dispatch = &glamor_priv->dispatch; + Bool has_repeat; + int width, height; + + if (picture->repeatType == RepeatNone) + has_repeat = FALSE; + else + has_repeat = TRUE; + + if (has_repeat + && ( (pixmap_priv->container->drawable.width != pixmap_priv->fbo->width) + || (pixmap_priv->container->drawable.height != pixmap_priv->fbo->height))) { + /* Currently, we can't support repeat on partial texture, now redirect it + * to an exact size fbo. */ + DEBUGF("prepare to fixup texture \n"); + if (!glamor_fixup_pixmap_priv(screen, pixmap_priv)) + ErrorF("Failed to fixup a unmatch size of repeat picture. \n"); + } +} + static void glamor_set_composite_texture(ScreenPtr screen, int unit, PicturePtr picture, @@ -979,6 +1005,12 @@ glamor_composite_with_shader(CARD8 op, } } #endif + + if (key.source != SHADER_SOURCE_SOLID) + glamor_composite_texture_fixup(screen, source, source_pixmap_priv); + if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID) + glamor_composite_texture_fixup(screen, mask, mask_pixmap_priv); + glamor_set_destination_pixmap_priv_nc(dest_pixmap_priv); glamor_validate_pixmap(dest_pixmap); if (!glamor_set_composite_op(screen, op, dest, mask)) { diff --git a/glamor/glamor_tile.c b/glamor/glamor_tile.c index 7e0e6acb3..4ff4fa15f 100644 --- a/glamor/glamor_tile.c +++ b/glamor/glamor_tile.c @@ -127,8 +127,10 @@ glamor_tile(PixmapPtr pixmap, PixmapPtr tile, if (((tile_x != 0) && (tile_x + width > tile->drawable.width)) || ((tile_y != 0) && (tile_y + height > tile->drawable.height))) { + /* XXX We can recreate a new pixmap here to avoid partial tiling. */ goto fail; } + if (glamor_priv->tile_prog == 0) { glamor_fallback("Tiling unsupported\n"); goto fail; @@ -148,6 +150,15 @@ glamor_tile(PixmapPtr pixmap, PixmapPtr tile, glamor_fallback("unsupported planemask %lx\n", planemask); goto fail; } + + if (src_pixmap_priv->fbo->width != tile->drawable.width + || src_pixmap_priv->fbo->height != tile->drawable.height) { + if (!glamor_fixup_pixmap_priv(screen, src_pixmap_priv)) { + glamor_fallback("Failed to create a fixup pixmap for partial tiling. \n"); + goto fail; + } + } + if (alu != GXcopy) { glamor_set_destination_pixmap_priv_nc(src_pixmap_priv); glamor_validate_pixmap(tile);