diff --git a/glamor/glamor.c b/glamor/glamor.c index 8fc3b0534..9b1d425ea 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -155,6 +155,9 @@ glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth, } glamor_set_pixmap_private(pixmap, pixmap_priv); + if (usage == GLAMOR_CREATE_PIXMAP_MAP) + type = GLAMOR_MEMORY_MAP; + pixmap_priv->container = pixmap; pixmap_priv->glamor_priv = glamor_priv; pixmap_priv->type = type; diff --git a/glamor/glamor.h b/glamor/glamor.h index 4a4e9bdcb..c608ed855 100644 --- a/glamor/glamor.h +++ b/glamor/glamor.h @@ -51,6 +51,7 @@ */ typedef enum glamor_pixmap_type { GLAMOR_MEMORY, + GLAMOR_MEMORY_MAP, GLAMOR_TEXTURE_DRM, GLAMOR_SEPARATE_TEXTURE, GLAMOR_DRM_ONLY, diff --git a/glamor/glamor_fbo.c b/glamor/glamor_fbo.c index b15450a6d..e9612bd7f 100644 --- a/glamor/glamor_fbo.c +++ b/glamor/glamor_fbo.c @@ -132,7 +132,6 @@ glamor_purge_fbo(glamor_pixmap_fbo *fbo) free(fbo); } - static void glamor_pixmap_fbo_cache_put(glamor_pixmap_fbo *fbo) { @@ -165,6 +164,55 @@ glamor_pixmap_fbo_cache_put(glamor_pixmap_fbo *fbo) #endif } +static void +glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo) +{ + glamor_gl_dispatch *dispatch; + int status; + + dispatch = glamor_get_dispatch(fbo->glamor_priv); + + if (fbo->fb == 0) + dispatch->glGenFramebuffers(1, &fbo->fb); + assert(fbo->tex != 0); + dispatch->glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb); + dispatch->glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, fbo->tex, + 0); + status = dispatch->glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + const char *str; + switch (status) { + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + str = "incomplete attachment"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + str = "incomplete/missing attachment"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + str = "incomplete draw buffer"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + str = "incomplete read buffer"; + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + str = "unsupported"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: + str = "incomplete multiple"; + break; + default: + str = "unknown error"; + break; + } + + FatalError("destination is framebuffer incomplete: %s [%#x]\n", + str, status); + } + glamor_put_dispatch(fbo->glamor_priv); +} + glamor_pixmap_fbo * glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv, int w, int h, GLenum format, GLint tex, int flag) @@ -183,9 +231,18 @@ glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv, fbo->format = format; fbo->glamor_priv = glamor_priv; + if (flag == GLAMOR_CREATE_PIXMAP_MAP) { + glamor_gl_dispatch *dispatch; + dispatch = glamor_get_dispatch(glamor_priv); + dispatch->glGenBuffers(1, &fbo->pbo); + glamor_put_dispatch(glamor_priv); + goto done; + } + if (flag != GLAMOR_CREATE_FBO_NO_FBO) glamor_pixmap_ensure_fb(fbo); +done: return fbo; } @@ -331,6 +388,28 @@ glamor_destroy_tex_obj(glamor_pixmap_fbo * tex_obj) glamor_pixmap_fbo_cache_put(tex_obj); } +int +_glamor_create_tex(glamor_screen_private *glamor_priv, + int w, int h, GLenum format) +{ + glamor_gl_dispatch *dispatch; + int tex; + + dispatch = glamor_get_dispatch(glamor_priv); + dispatch->glGenTextures(1, &tex); + dispatch->glBindTexture(GL_TEXTURE_2D, tex); + dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_NEAREST); + dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_NEAREST); + dispatch->glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, + GL_UNSIGNED_BYTE, NULL); + glamor_put_dispatch(glamor_priv); + return tex; +} + + + glamor_pixmap_fbo * glamor_create_fbo(glamor_screen_private *glamor_priv, int w, int h, @@ -339,7 +418,7 @@ glamor_create_fbo(glamor_screen_private *glamor_priv, { glamor_gl_dispatch *dispatch; glamor_pixmap_fbo *fbo; - GLint tex; + GLint tex = 0; int cache_flag; if (!glamor_check_fbo_size(glamor_priv, w, h)) @@ -348,6 +427,9 @@ glamor_create_fbo(glamor_screen_private *glamor_priv, if (flag == GLAMOR_CREATE_FBO_NO_FBO) goto new_fbo; + if (flag == GLAMOR_CREATE_PIXMAP_MAP) + goto no_tex; + if (flag == GLAMOR_CREATE_PIXMAP_FIXUP) cache_flag = GLAMOR_CACHE_EXACT_SIZE; else @@ -358,18 +440,9 @@ glamor_create_fbo(glamor_screen_private *glamor_priv, if (fbo) return fbo; new_fbo: - dispatch = glamor_get_dispatch(glamor_priv); - dispatch->glGenTextures(1, &tex); - dispatch->glBindTexture(GL_TEXTURE_2D, tex); - dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_NEAREST); - dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - GL_NEAREST); - dispatch->glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, - GL_UNSIGNED_BYTE, NULL); - + tex = _glamor_create_tex(glamor_priv, w, h, format); +no_tex: fbo = glamor_create_fbo_from_tex(glamor_priv, w, h, format, tex, flag); - glamor_put_dispatch(glamor_priv); return fbo; } @@ -424,12 +497,47 @@ glamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo) /* XXX For the Xephyr only, may be broken now.*/ pixmap_priv->gl_tex = 0; } + case GLAMOR_MEMORY_MAP: pixmap->devPrivate.ptr = NULL; break; default: break; } } + + +Bool +glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag) +{ + glamor_screen_private *glamor_priv; + glamor_pixmap_private *pixmap_priv; + glamor_pixmap_fbo *fbo; + + glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen); + pixmap_priv = glamor_get_pixmap_private(pixmap); + if (pixmap_priv == NULL || pixmap_priv->fbo == NULL) { + + fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width, + pixmap->drawable.height, + format, + flag); + if (fbo == NULL) + return FALSE; + + glamor_pixmap_attach_fbo(pixmap, fbo); + } else { + /* We do have a fbo, but it may lack of fb or tex. */ + if (pixmap_priv->fbo->tex) + pixmap_priv->fbo->tex = _glamor_create_tex(glamor_priv, pixmap->drawable.width, + pixmap->drawable.height, format); + + if (flag != GLAMOR_CREATE_FBO_NO_FBO && pixmap_priv->fbo->fb == 0) + glamor_pixmap_ensure_fb(pixmap_priv->fbo); + } + + pixmap_priv = glamor_get_pixmap_private(pixmap); + return TRUE; +} /* * XXX how to handle those pending OPs. * By default, pending OP is disabled. Maybe we will give up the pending diff --git a/glamor/glamor_pixmap.c b/glamor/glamor_pixmap.c index 02b311a97..82002d7d8 100644 --- a/glamor/glamor_pixmap.c +++ b/glamor/glamor_pixmap.c @@ -622,54 +622,6 @@ _glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format, pixmap->devPrivate.ptr); } -void -glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo) -{ - glamor_gl_dispatch *dispatch; - int status; - - dispatch = glamor_get_dispatch(fbo->glamor_priv); - - if (fbo->fb == 0) - dispatch->glGenFramebuffers(1, &fbo->fb); - assert(fbo->tex != 0); - dispatch->glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb); - dispatch->glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, fbo->tex, - 0); - status = dispatch->glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - const char *str; - switch (status) { - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - str = "incomplete attachment"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - str = "incomplete/missing attachment"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - str = "incomplete draw buffer"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - str = "incomplete read buffer"; - break; - case GL_FRAMEBUFFER_UNSUPPORTED: - str = "unsupported"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - str = "incomplete multiple"; - break; - default: - str = "unknown error"; - break; - } - - FatalError("destination is framebuffer incomplete: %s [%#x]\n", - str, status); - } - glamor_put_dispatch(fbo->glamor_priv); -} /* * Prepare to upload a pixmap to texture memory. @@ -681,7 +633,7 @@ glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo) static int glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, int revert, int swap_rb) { - int flag; + int flag = 0; glamor_pixmap_private *pixmap_priv; glamor_screen_private *glamor_priv; glamor_pixmap_fbo *fbo; @@ -696,36 +648,38 @@ glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, int || !glamor_priv->yInverted)) { /* We don't need a fbo, a simple texture uploading should work. */ - if (pixmap_priv && pixmap_priv->fbo) - return 0; flag = GLAMOR_CREATE_FBO_NO_FBO; - } else { - - if (GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) - return 0; - flag = 0; } + if ((flag == 0 && pixmap_priv && pixmap_priv->fbo && pixmap_priv->fbo->tex) + || (flag != 0 && pixmap_priv && pixmap_priv->fbo && pixmap_priv->fbo->fb)) + return 0; + if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) gl_iformat_for_depth(pixmap->drawable.depth, &iformat); else iformat = format; + if (pixmap_priv == NULL || pixmap_priv->fbo == NULL) { - fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width, - pixmap->drawable.height, - iformat, - flag); - if (fbo == NULL) { - glamor_fallback - ("upload failed, depth %d x %d @depth %d \n", - pixmap->drawable.width, pixmap->drawable.height, - pixmap->drawable.depth); - return -1; + fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width, + pixmap->drawable.height, + iformat, + flag); + if (fbo == NULL) { + glamor_fallback + ("upload failed, depth %d x %d @depth %d \n", + pixmap->drawable.width, pixmap->drawable.height, + pixmap->drawable.depth); + return -1; + } + + glamor_pixmap_attach_fbo(pixmap, fbo); + } else { + /* We do have a fbo, but it may lack of fb or tex. */ + glamor_pixmap_ensure_fbo(pixmap, iformat, flag); } - glamor_pixmap_attach_fbo(pixmap, fbo); - return 0; } @@ -1173,3 +1127,110 @@ fail: return ret; } + +/* + * We may use this function to reduce a large pixmap to a small sub + * pixmap. Two scenarios currently: + * 1. When fallback a large textured pixmap to CPU but we do need to + * do rendering within a small sub region, then we can just get a + * sub region. + * + * 2. When uploading a large pixmap to texture but we only need to + * use part of the source/mask picture. As glTexImage2D will be more + * efficient to upload a contingent region rather than a sub block + * in a large buffer. We use this function to gather the sub region + * to a contingent sub pixmap. + * + * The sub-pixmap must have the same format as the source pixmap. + * + * */ +PixmapPtr +glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y, int w, int h, glamor_access_t access) +{ + glamor_screen_private *glamor_priv; + PixmapPtr sub_pixmap; + glamor_pixmap_private *sub_pixmap_priv, *pixmap_priv; + void *data; + int pbo; + int flag; + + if (access == GLAMOR_ACCESS_WO) { + sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h, + pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU); + ErrorF("WO\n"); + return sub_pixmap; + } + + glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen); + pixmap_priv = glamor_get_pixmap_private(pixmap); + + if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) + return NULL; + + if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) + flag = GLAMOR_CREATE_PIXMAP_CPU; + else + flag = GLAMOR_CREATE_PIXMAP_MAP; + + sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h, + pixmap->drawable.depth, flag); + + if (sub_pixmap == NULL) + return NULL; + + sub_pixmap_priv = glamor_get_pixmap_private(sub_pixmap); + pbo = sub_pixmap_priv ? (sub_pixmap_priv->fbo ? sub_pixmap_priv->fbo->pbo : 0): 0; + + if (pbo) + data = NULL; + else { + data = sub_pixmap->devPrivate.ptr; + assert(flag != GLAMOR_CREATE_PIXMAP_MAP); + } + data = glamor_download_sub_pixmap_to_cpu(pixmap, x, y, w, h, sub_pixmap->devKind, + data, pbo, access); + if (pbo) { + assert(sub_pixmap->devPrivate.ptr == NULL); + sub_pixmap->devPrivate.ptr = data; + sub_pixmap_priv->fbo->pbo_valid = 1; + } +#if 0 + struct pixman_box16 box; + PixmapPtr new_sub_pixmap; + int dx, dy; + box.x1 = 0; + box.y1 = 0; + box.x2 = w; + box.y2 = h; + + dx = x; + dy = y; + + new_sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h, + pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU); + glamor_copy_n_to_n(&pixmap->drawable, &new_sub_pixmap, NULL, &box, 1, dx, dy, 0, 0, 0, NULL); + glamor_compare_pixmaps(new_sub_pixmap, sub_pixmap, 0, 0, w, h, 1, 1); +#endif + + return sub_pixmap; +} + +PixmapPtr +glamor_put_sub_pixmap(PixmapPtr sub_pixmap, PixmapPtr pixmap, int x, int y, int w, int h, glamor_access_t access) +{ + struct pixman_box16 box; + int dx, dy; + box.x1 = x; + box.y1 = y; + box.x2 = x + w; + box.y2 = y + h; + + dx = -(x); + dy = -(y); + + glamor_copy_n_to_n(&sub_pixmap->drawable, + &pixmap->drawable, + NULL, &box, 1, dx, dy, + 0, 0, 0, NULL); + glamor_destroy_pixmap(sub_pixmap); +} diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index 3e13ef8e2..8a6beeea9 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -145,8 +145,8 @@ enum glamor_gl_flavor { #define GLAMOR_CREATE_PIXMAP_CPU 0x100 #define GLAMOR_CREATE_PIXMAP_FIXUP 0x101 - #define GLAMOR_CREATE_FBO_NO_FBO 0x103 +#define GLAMOR_CREATE_PIXMAP_MAP 0x104 #define GLAMOR_CREATE_TEXTURE_EXACT_SIZE 0x104 @@ -615,15 +615,16 @@ Bool glamor_download_pixmap_to_cpu(PixmapPtr pixmap, * must be 1. **/ void glamor_restore_pixmap_to_texture(PixmapPtr pixmap); + /** - * Ensure to have a fbo has a valid/complete glfbo. + * According to the flag, + * if the flag is GLAMOR_CREATE_FBO_NO_FBO then just ensure + * the fbo has a valid texture. Otherwise, it will ensure + * the fbo has valid texture and attach to a valid fb. * If the fbo already has a valid glfbo then do nothing. - * Otherwise, it will generate a new glfbo, and bind - * the fbo's texture to the glfbo. - * The fbo must has a valid texture before call this - * API, othersie, it will trigger a assert. */ -void glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo); +Bool +glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag); /** * Upload a pixmap to gl texture. Used by dynamic pixmap @@ -633,6 +634,16 @@ void glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo); enum glamor_pixmap_status glamor_upload_pixmap_to_texture(PixmapPtr pixmap); + +PixmapPtr +glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y, + int w, int h, glamor_access_t access); + +PixmapPtr +glamor_put_sub_pixmap(PixmapPtr sub_pixmap, PixmapPtr pixmap, int x, int y, + int w, int h, glamor_access_t access); + + /** * Upload a picture to gl texture. Similar to the * glamor_upload_pixmap_to_texture. Used in rendering.