fallback_optimize: Prepare for downloading/uploading subregion.

Introduced two function glamor_get_sub_pixmap/glamor_put_sub_pixmap,
can easily used to get and put sub region of a big textured pixmap.
And it can use pbo if possible.

To support download a big textured pixmap's sub region to another
pixmap's pbo, we introduce a new type of pixmap GLAMOR_MEMORY_MAP.
This type of pixmap has a valid devPrivate.ptr pointer, and that
pointer points to a pbo mapped address.

Now, we are ready to refine those
glamor_prepare_access/glamor_finish_access pairs.

Signed-off-by: Zhigang Gong <zhigang.gong@linux.intel.com>
This commit is contained in:
Zhigang Gong 2012-04-09 20:16:07 +08:00 committed by Eric Anholt
parent d9dfc3d795
commit cea0fe3e1f
5 changed files with 272 additions and 88 deletions

View File

@ -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;

View File

@ -51,6 +51,7 @@
*/
typedef enum glamor_pixmap_type {
GLAMOR_MEMORY,
GLAMOR_MEMORY_MAP,
GLAMOR_TEXTURE_DRM,
GLAMOR_SEPARATE_TEXTURE,
GLAMOR_DRM_ONLY,

View File

@ -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

View File

@ -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);
}

View File

@ -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.