39d9e6c693
We add a new gl_fbo status GLAMOR_FBO_DOWNLOADED to indicate the fbo was already downloaded to CPU. Then latter the access to this pixmap will be treated as pure CPU access. In glamor, if we fallback to DDX/fbXXX, then we fallback everything currently. We don't support to jump into glamor acceleration layer between a prepare_access/finish_access. Actually, fbCopyPlane is such a function which may call to acceleration function within it. Then we must mark the downloaded pixmap to another state rather than a normal fbo textured pixmap, and then stick to use it as a in-memory pixmap. Signed-off-by: Zhigang Gong <zhigang.gong@linux.intel.com> Tested-by: Peng Li <peng.li@intel.com>
868 lines
23 KiB
C
868 lines
23 KiB
C
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "glamor_priv.h"
|
|
/**
|
|
* Sets the offsets to add to coordinates to make them address the same bits in
|
|
* the backing drawable. These coordinates are nonzero only for redirected
|
|
* windows.
|
|
*/
|
|
void
|
|
glamor_get_drawable_deltas(DrawablePtr drawable, PixmapPtr pixmap,
|
|
int *x, int *y)
|
|
{
|
|
#ifdef COMPOSITE
|
|
if (drawable->type == DRAWABLE_WINDOW) {
|
|
*x = -pixmap->screen_x;
|
|
*y = -pixmap->screen_y;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
*x = 0;
|
|
*y = 0;
|
|
}
|
|
|
|
|
|
static void
|
|
_glamor_pixmap_validate_filling(glamor_screen_private * glamor_priv,
|
|
glamor_pixmap_private * pixmap_priv)
|
|
{
|
|
glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
|
|
GLfloat vertices[8];
|
|
dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
|
|
GL_FALSE, 2 * sizeof(float),
|
|
vertices);
|
|
dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
|
|
dispatch->glUseProgram(glamor_priv->solid_prog);
|
|
dispatch->glUniform4fv(glamor_priv->solid_color_uniform_location,
|
|
1, pixmap_priv->pending_op.fill.color4fv);
|
|
vertices[0] = -1;
|
|
vertices[1] = -1;
|
|
vertices[2] = 1;
|
|
vertices[3] = -1;
|
|
vertices[4] = 1;
|
|
vertices[5] = 1;
|
|
vertices[6] = -1;
|
|
vertices[7] = 1;
|
|
dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
|
|
dispatch->glUseProgram(0);
|
|
pixmap_priv->pending_op.type = GLAMOR_PENDING_NONE;
|
|
}
|
|
|
|
|
|
glamor_pixmap_validate_function_t pixmap_validate_funcs[] = {
|
|
NULL,
|
|
_glamor_pixmap_validate_filling
|
|
};
|
|
|
|
void
|
|
glamor_pixmap_init(ScreenPtr screen)
|
|
{
|
|
glamor_screen_private *glamor_priv;
|
|
|
|
glamor_priv = glamor_get_screen_private(screen);
|
|
glamor_priv->pixmap_validate_funcs = pixmap_validate_funcs;
|
|
}
|
|
|
|
void
|
|
glamor_pixmap_fini(ScreenPtr screen)
|
|
{
|
|
}
|
|
|
|
void
|
|
glamor_validate_pixmap(PixmapPtr pixmap)
|
|
{
|
|
glamor_pixmap_validate_function_t validate_op;
|
|
glamor_screen_private *glamor_priv =
|
|
glamor_get_screen_private(pixmap->drawable.pScreen);
|
|
glamor_pixmap_private *pixmap_priv =
|
|
glamor_get_pixmap_private(pixmap);
|
|
|
|
validate_op =
|
|
glamor_priv->pixmap_validate_funcs[pixmap_priv->
|
|
pending_op.type];
|
|
if (validate_op) {
|
|
(*validate_op) (glamor_priv, pixmap_priv);
|
|
}
|
|
}
|
|
|
|
void
|
|
glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private * pixmap_priv)
|
|
{
|
|
glamor_gl_dispatch *dispatch = &pixmap_priv->glamor_priv->dispatch;
|
|
dispatch->glBindFramebuffer(GL_FRAMEBUFFER, pixmap_priv->fbo->fb);
|
|
#ifndef GLAMOR_GLES2
|
|
dispatch->glMatrixMode(GL_PROJECTION);
|
|
dispatch->glLoadIdentity();
|
|
dispatch->glMatrixMode(GL_MODELVIEW);
|
|
dispatch->glLoadIdentity();
|
|
#endif
|
|
dispatch->glViewport(0, 0,
|
|
pixmap_priv->fbo->width,
|
|
pixmap_priv->fbo->height);
|
|
|
|
}
|
|
|
|
int
|
|
glamor_set_destination_pixmap_priv(glamor_pixmap_private * pixmap_priv)
|
|
{
|
|
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
|
|
return -1;
|
|
|
|
glamor_set_destination_pixmap_priv_nc(pixmap_priv);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
glamor_set_destination_pixmap(PixmapPtr pixmap)
|
|
{
|
|
int err;
|
|
glamor_pixmap_private *pixmap_priv =
|
|
glamor_get_pixmap_private(pixmap);
|
|
|
|
err = glamor_set_destination_pixmap_priv(pixmap_priv);
|
|
return err;
|
|
}
|
|
|
|
Bool
|
|
glamor_set_planemask(PixmapPtr pixmap, unsigned long planemask)
|
|
{
|
|
if (glamor_pm_is_solid(&pixmap->drawable, planemask)) {
|
|
return GL_TRUE;
|
|
}
|
|
|
|
glamor_fallback("unsupported planemask %lx\n", planemask);
|
|
return GL_FALSE;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
glamor_set_alu(struct glamor_gl_dispatch *dispatch, unsigned char alu)
|
|
{
|
|
#ifndef GLAMOR_GLES2
|
|
if (alu == GXcopy) {
|
|
dispatch->glDisable(GL_COLOR_LOGIC_OP);
|
|
return;
|
|
}
|
|
dispatch->glEnable(GL_COLOR_LOGIC_OP);
|
|
switch (alu) {
|
|
case GXclear:
|
|
dispatch->glLogicOp(GL_CLEAR);
|
|
break;
|
|
case GXand:
|
|
dispatch->glLogicOp(GL_AND);
|
|
break;
|
|
case GXandReverse:
|
|
dispatch->glLogicOp(GL_AND_REVERSE);
|
|
break;
|
|
case GXandInverted:
|
|
dispatch->glLogicOp(GL_AND_INVERTED);
|
|
break;
|
|
case GXnoop:
|
|
dispatch->glLogicOp(GL_NOOP);
|
|
break;
|
|
case GXxor:
|
|
dispatch->glLogicOp(GL_XOR);
|
|
break;
|
|
case GXor:
|
|
dispatch->glLogicOp(GL_OR);
|
|
break;
|
|
case GXnor:
|
|
dispatch->glLogicOp(GL_NOR);
|
|
break;
|
|
case GXequiv:
|
|
dispatch->glLogicOp(GL_EQUIV);
|
|
break;
|
|
case GXinvert:
|
|
dispatch->glLogicOp(GL_INVERT);
|
|
break;
|
|
case GXorReverse:
|
|
dispatch->glLogicOp(GL_OR_REVERSE);
|
|
break;
|
|
case GXcopyInverted:
|
|
dispatch->glLogicOp(GL_COPY_INVERTED);
|
|
break;
|
|
case GXorInverted:
|
|
dispatch->glLogicOp(GL_OR_INVERTED);
|
|
break;
|
|
case GXnand:
|
|
dispatch->glLogicOp(GL_NAND);
|
|
break;
|
|
case GXset:
|
|
dispatch->glLogicOp(GL_SET);
|
|
break;
|
|
default:
|
|
FatalError("unknown logic op\n");
|
|
}
|
|
#else
|
|
if (alu != GXcopy)
|
|
ErrorF("unsupported alu %x \n", alu);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Upload pixmap to a specified texture.
|
|
* This texture may not be the one attached to it.
|
|
**/
|
|
int in_restore = 0;
|
|
static void
|
|
__glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format,
|
|
GLenum type, GLuint tex, int sub)
|
|
{
|
|
glamor_pixmap_private *pixmap_priv =
|
|
glamor_get_pixmap_private(pixmap);
|
|
glamor_screen_private *glamor_priv =
|
|
glamor_get_screen_private(pixmap->drawable.pScreen);
|
|
glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
|
|
unsigned int stride, row_length;
|
|
void *texels;
|
|
GLenum iformat;
|
|
|
|
if (glamor_priv->gl_flavor == GLAMOR_GL_ES2)
|
|
iformat = format;
|
|
else
|
|
gl_iformat_for_depth(pixmap->drawable.depth, &iformat);
|
|
|
|
stride = pixmap->devKind;
|
|
row_length = (stride * 8) / pixmap->drawable.bitsPerPixel;
|
|
|
|
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);
|
|
|
|
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
|
|
dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
|
dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
|
|
} else {
|
|
dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
|
}
|
|
|
|
if (pixmap_priv->fbo->pbo && pixmap_priv->fbo->pbo_valid) {
|
|
texels = NULL;
|
|
dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
|
|
pixmap_priv->fbo->pbo);
|
|
} else
|
|
texels = pixmap->devPrivate.ptr;
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
/*
|
|
* Load texture from the pixmap's data pointer and then
|
|
* draw the texture to the fbo, and flip the y axis.
|
|
* */
|
|
|
|
static void
|
|
_glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format,
|
|
GLenum type, int no_alpha, int no_revert,
|
|
int flip)
|
|
{
|
|
|
|
glamor_pixmap_private *pixmap_priv =
|
|
glamor_get_pixmap_private(pixmap);
|
|
glamor_screen_private *glamor_priv =
|
|
glamor_get_screen_private(pixmap->drawable.pScreen);
|
|
glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
|
|
static float vertices[8];
|
|
static float texcoords[8] = { 0, 1,
|
|
1, 1,
|
|
1, 0,
|
|
0, 0
|
|
};
|
|
static float texcoords_inv[8] = { 0, 0,
|
|
1, 0,
|
|
1, 1,
|
|
0, 1
|
|
};
|
|
float *ptexcoords;
|
|
float dst_xscale, dst_yscale;
|
|
GLuint tex;
|
|
int need_flip;
|
|
|
|
if (!pixmap_priv)
|
|
return;
|
|
need_flip = (flip && !glamor_priv->yInverted);
|
|
|
|
glamor_debug_output(GLAMOR_DEBUG_TEXTURE_DYNAMIC_UPLOAD,
|
|
"Uploading pixmap %p %dx%d depth%d.\n",
|
|
pixmap,
|
|
pixmap->drawable.width,
|
|
pixmap->drawable.height,
|
|
pixmap->drawable.depth);
|
|
|
|
/* Try fast path firstly, upload the pixmap to the texture attached
|
|
* 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, 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),
|
|
vertices);
|
|
dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
|
|
dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
|
|
GL_FALSE, 2 * sizeof(float),
|
|
ptexcoords);
|
|
dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
|
|
|
|
glamor_set_destination_pixmap_priv_nc(pixmap_priv);
|
|
dispatch->glGenTextures(1, &tex);
|
|
|
|
__glamor_upload_pixmap_to_texture(pixmap, format, type, tex, 0);
|
|
dispatch->glActiveTexture(GL_TEXTURE0);
|
|
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);
|
|
#ifndef GLAMOR_GLES2
|
|
dispatch->glEnable(GL_TEXTURE_2D);
|
|
#endif
|
|
dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
|
|
dispatch->glUniform1i(glamor_priv->
|
|
finish_access_no_revert[no_alpha],
|
|
no_revert);
|
|
dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],
|
|
0);
|
|
|
|
dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
#ifndef GLAMOR_GLES2
|
|
dispatch->glDisable(GL_TEXTURE_2D);
|
|
#endif
|
|
dispatch->glUseProgram(0);
|
|
dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
|
|
dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
|
|
dispatch->glDeleteTextures(1, &tex);
|
|
dispatch->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
}
|
|
|
|
void
|
|
glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo)
|
|
{
|
|
int status;
|
|
glamor_gl_dispatch *dispatch = &fbo->glamor_priv->dispatch;
|
|
|
|
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;
|
|
}
|
|
|
|
LogMessageVerb(X_INFO, 0,
|
|
"destination is framebuffer incomplete: %s [%#x]\n",
|
|
str, status);
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Prepare to upload a pixmap to texture memory.
|
|
* no_alpha equals 1 means the format needs to wire alpha to 1.
|
|
* Two condtion need to setup a fbo for a pixmap
|
|
* 1. !yInverted, we need to do flip if we are not yInverted.
|
|
* 2. no_alpha != 0, we need to wire the alpha.
|
|
* */
|
|
static int
|
|
glamor_pixmap_upload_prepare(PixmapPtr pixmap, int no_alpha, int no_revert)
|
|
{
|
|
int flag;
|
|
glamor_pixmap_private *pixmap_priv;
|
|
glamor_screen_private *glamor_priv;
|
|
GLenum format;
|
|
glamor_pixmap_fbo *fbo;
|
|
|
|
pixmap_priv = glamor_get_pixmap_private(pixmap);
|
|
glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
|
|
|
|
if (!(no_alpha || !no_revert || !glamor_priv->yInverted)) {
|
|
|
|
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;
|
|
}
|
|
|
|
fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width,
|
|
pixmap->drawable.height,
|
|
pixmap->drawable.depth,
|
|
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);
|
|
|
|
return 0;
|
|
}
|
|
|
|
enum glamor_pixmap_status
|
|
glamor_upload_pixmap_to_texture(PixmapPtr pixmap)
|
|
{
|
|
GLenum format, type;
|
|
int no_alpha, no_revert;
|
|
|
|
if (glamor_get_tex_format_type_from_pixmap(pixmap,
|
|
&format,
|
|
&type, &no_alpha,
|
|
&no_revert)) {
|
|
glamor_fallback("Unknown pixmap depth %d.\n",
|
|
pixmap->drawable.depth);
|
|
return GLAMOR_UPLOAD_FAILED;
|
|
}
|
|
if (glamor_pixmap_upload_prepare(pixmap, no_alpha, no_revert))
|
|
return GLAMOR_UPLOAD_FAILED;
|
|
_glamor_upload_pixmap_to_texture(pixmap, format, type, no_alpha,
|
|
no_revert, 1);
|
|
return GLAMOR_UPLOAD_DONE;
|
|
}
|
|
|
|
#if 0
|
|
enum glamor_pixmap_status
|
|
glamor_upload_pixmap_to_texure_from_data(PixmapPtr pixmap, void *data)
|
|
{
|
|
enum glamor_pixmap_status upload_status;
|
|
glamor_pixmap_private *pixmap_priv =
|
|
glamor_get_pixmap_private(pixmap);
|
|
|
|
assert(pixmap_priv->pbo_valid == 0);
|
|
assert(pixmap->devPrivate.ptr == NULL);
|
|
pixmap->devPrivate.ptr = data;
|
|
upload_status = glamor_upload_pixmap_to_texture(pixmap);
|
|
pixmap->devPrivate.ptr = NULL;
|
|
return upload_status;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
glamor_restore_pixmap_to_texture(PixmapPtr pixmap)
|
|
{
|
|
GLenum format, type;
|
|
int no_alpha, no_revert;
|
|
|
|
if (glamor_get_tex_format_type_from_pixmap(pixmap,
|
|
&format,
|
|
&type, &no_alpha,
|
|
&no_revert)) {
|
|
ErrorF("Unknown pixmap depth %d.\n",
|
|
pixmap->drawable.depth);
|
|
assert(0);
|
|
}
|
|
|
|
in_restore = 1;
|
|
_glamor_upload_pixmap_to_texture(pixmap, format, type, no_alpha,
|
|
no_revert, 1);
|
|
in_restore = 0;
|
|
}
|
|
|
|
/*
|
|
* as gles2 only support a very small set of color format and
|
|
* type when do glReadPixel,
|
|
* Before we use glReadPixels to get back a textured pixmap,
|
|
* Use shader to convert it to a supported format and thus
|
|
* get a new temporary pixmap returned.
|
|
* */
|
|
|
|
PixmapPtr
|
|
glamor_es2_pixmap_read_prepare(PixmapPtr source, GLenum * format,
|
|
GLenum * type, int no_alpha, int no_revert)
|
|
{
|
|
glamor_pixmap_private *source_priv;
|
|
glamor_screen_private *glamor_priv;
|
|
ScreenPtr screen;
|
|
PixmapPtr temp_pixmap;
|
|
glamor_pixmap_private *temp_pixmap_priv;
|
|
glamor_gl_dispatch *dispatch;
|
|
static float vertices[8] = { -1, -1,
|
|
1, -1,
|
|
1, 1,
|
|
-1, 1
|
|
};
|
|
static float texcoords[8] = { 0, 0,
|
|
1, 0,
|
|
1, 1,
|
|
0, 1
|
|
};
|
|
|
|
int swap_rb = 0;
|
|
|
|
screen = source->drawable.pScreen;
|
|
|
|
glamor_priv = glamor_get_screen_private(screen);
|
|
source_priv = glamor_get_pixmap_private(source);
|
|
dispatch = &glamor_priv->dispatch;
|
|
if (*format == GL_BGRA) {
|
|
*format = GL_RGBA;
|
|
swap_rb = 1;
|
|
}
|
|
|
|
|
|
temp_pixmap = glamor_create_pixmap (screen,
|
|
source->drawable.width,
|
|
source->drawable.height,
|
|
source->drawable.depth, 0);
|
|
|
|
temp_pixmap_priv = glamor_get_pixmap_private(temp_pixmap);
|
|
|
|
dispatch->glBindTexture(GL_TEXTURE_2D, temp_pixmap_priv->fbo->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,
|
|
source->drawable.width,
|
|
source->drawable.height, 0, *format, *type,
|
|
NULL);
|
|
|
|
dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
|
|
GL_FALSE, 2 * sizeof(float),
|
|
vertices);
|
|
dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
|
|
|
|
dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
|
|
GL_FALSE, 2 * sizeof(float),
|
|
texcoords);
|
|
dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
|
|
|
|
dispatch->glActiveTexture(GL_TEXTURE0);
|
|
dispatch->glBindTexture(GL_TEXTURE_2D, source_priv->fbo->tex);
|
|
dispatch->glTexParameteri(GL_TEXTURE_2D,
|
|
GL_TEXTURE_MIN_FILTER,
|
|
GL_NEAREST);
|
|
dispatch->glTexParameteri(GL_TEXTURE_2D,
|
|
GL_TEXTURE_MAG_FILTER,
|
|
GL_NEAREST);
|
|
|
|
glamor_set_destination_pixmap_priv_nc(temp_pixmap_priv);
|
|
|
|
dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
|
|
dispatch->glUniform1i(glamor_priv->
|
|
finish_access_no_revert[no_alpha],
|
|
no_revert);
|
|
dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],
|
|
swap_rb);
|
|
|
|
dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
|
|
dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
|
|
dispatch->glUseProgram(0);
|
|
return temp_pixmap;
|
|
}
|
|
|
|
|
|
/**
|
|
* Move a pixmap to CPU memory.
|
|
* The input data is the pixmap's fbo.
|
|
* The output data is at pixmap->devPrivate.ptr. We always use pbo
|
|
* to read the fbo and then map it to va. If possible, we will use
|
|
* it directly as devPrivate.ptr.
|
|
* If successfully download a fbo to cpu then return TRUE.
|
|
* Otherwise return FALSE.
|
|
**/
|
|
Bool
|
|
glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
|
|
{
|
|
glamor_pixmap_private *pixmap_priv =
|
|
glamor_get_pixmap_private(pixmap);
|
|
unsigned int stride, row_length, y;
|
|
GLenum format, type, gl_access, gl_usage;
|
|
int no_alpha, no_revert;
|
|
uint8_t *data = NULL, *read;
|
|
PixmapPtr temp_pixmap = NULL;
|
|
ScreenPtr screen;
|
|
glamor_screen_private *glamor_priv =
|
|
glamor_get_screen_private(pixmap->drawable.pScreen);
|
|
glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
|
|
|
|
screen = pixmap->drawable.pScreen;
|
|
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
|
|
return TRUE;
|
|
if (glamor_get_tex_format_type_from_pixmap(pixmap,
|
|
&format,
|
|
&type, &no_alpha,
|
|
&no_revert)) {
|
|
ErrorF("Unknown pixmap depth %d.\n",
|
|
pixmap->drawable.depth);
|
|
assert(0); // Should never happen.
|
|
return FALSE;
|
|
}
|
|
|
|
glamor_debug_output(GLAMOR_DEBUG_TEXTURE_DOWNLOAD,
|
|
"Downloading pixmap %p %dx%d depth%d\n",
|
|
pixmap,
|
|
pixmap->drawable.width,
|
|
pixmap->drawable.height,
|
|
pixmap->drawable.depth);
|
|
|
|
stride = pixmap->devKind;
|
|
|
|
glamor_set_destination_pixmap_priv_nc(pixmap_priv);
|
|
/* XXX we may don't need to validate it on GPU here,
|
|
* we can just validate it on CPU. */
|
|
glamor_validate_pixmap(pixmap);
|
|
|
|
if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
|
|
&& (!glamor_tex_format_is_readable(format) || !no_revert)) {
|
|
temp_pixmap =
|
|
glamor_es2_pixmap_read_prepare(pixmap, &format,
|
|
&type, no_alpha,
|
|
no_revert);
|
|
}
|
|
switch (access) {
|
|
case GLAMOR_ACCESS_RO:
|
|
gl_access = GL_READ_ONLY;
|
|
gl_usage = GL_STREAM_READ;
|
|
break;
|
|
case GLAMOR_ACCESS_WO:
|
|
data = malloc(stride * pixmap->drawable.height);
|
|
goto done;
|
|
break;
|
|
case GLAMOR_ACCESS_RW:
|
|
gl_access = GL_READ_WRITE;
|
|
gl_usage = GL_DYNAMIC_DRAW;
|
|
break;
|
|
default:
|
|
ErrorF("Glamor: Invalid access code. %d\n", access);
|
|
assert(0);
|
|
}
|
|
if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
|
|
data = malloc(stride * pixmap->drawable.height);
|
|
}
|
|
row_length = (stride * 8) / pixmap->drawable.bitsPerPixel;
|
|
|
|
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
|
|
dispatch->glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
|
dispatch->glPixelStorei(GL_PACK_ROW_LENGTH, row_length);
|
|
} else {
|
|
dispatch->glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
|
// dispatch->glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
|
}
|
|
if (glamor_priv->has_pack_invert || glamor_priv->yInverted) {
|
|
|
|
if (!glamor_priv->yInverted) {
|
|
assert(glamor_priv->gl_flavor ==
|
|
GLAMOR_GL_DESKTOP);
|
|
dispatch->glPixelStorei(GL_PACK_INVERT_MESA, 1);
|
|
}
|
|
|
|
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
|
|
if (pixmap_priv->fbo->pbo == 0)
|
|
dispatch->glGenBuffers(1,
|
|
&pixmap_priv->fbo->pbo);
|
|
dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER,
|
|
pixmap_priv->fbo->pbo);
|
|
dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
|
|
stride *
|
|
pixmap->drawable.height,
|
|
NULL, gl_usage);
|
|
dispatch->glReadPixels(0, 0, row_length,
|
|
pixmap->drawable.height,
|
|
format, type, 0);
|
|
data = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
|
|
gl_access);
|
|
pixmap_priv->fbo->pbo_valid = TRUE;
|
|
|
|
if (!glamor_priv->yInverted) {
|
|
assert(glamor_priv->gl_flavor ==
|
|
GLAMOR_GL_DESKTOP);
|
|
dispatch->glPixelStorei
|
|
(GL_PACK_INVERT_MESA, 0);
|
|
}
|
|
dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
|
|
|
} else {
|
|
if (type == GL_UNSIGNED_SHORT_1_5_5_5_REV)
|
|
type = GL_UNSIGNED_SHORT_5_5_5_1;
|
|
dispatch->glReadPixels(0, 0,
|
|
pixmap->drawable.width,
|
|
pixmap->drawable.height,
|
|
format, type, data);
|
|
}
|
|
} else {
|
|
data = malloc(stride * pixmap->drawable.height);
|
|
assert(data);
|
|
if (access != GLAMOR_ACCESS_WO) {
|
|
if (pixmap_priv->fbo->pbo == 0)
|
|
dispatch->glGenBuffers(1,
|
|
&pixmap_priv->fbo->pbo);
|
|
dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER,
|
|
pixmap_priv->fbo->pbo);
|
|
dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
|
|
stride *
|
|
pixmap->drawable.height,
|
|
NULL, GL_STREAM_READ);
|
|
dispatch->glReadPixels(0, 0, row_length,
|
|
pixmap->drawable.height,
|
|
format, type, 0);
|
|
read = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
|
|
GL_READ_ONLY);
|
|
|
|
for (y = 0; y < pixmap->drawable.height; y++)
|
|
memcpy(data + y * stride,
|
|
read + (pixmap->drawable.height -
|
|
y - 1) * stride, stride);
|
|
dispatch->glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
|
dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
|
pixmap_priv->fbo->pbo_valid = FALSE;
|
|
dispatch->glDeleteBuffers(1, &pixmap_priv->fbo->pbo);
|
|
pixmap_priv->fbo->pbo = 0;
|
|
}
|
|
}
|
|
|
|
dispatch->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
done:
|
|
|
|
pixmap_priv->gl_fbo = GLAMOR_FBO_DOWNLOADED;
|
|
pixmap->devPrivate.ptr = data;
|
|
|
|
if (temp_pixmap)
|
|
glamor_destroy_pixmap(temp_pixmap);
|
|
|
|
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;
|
|
}
|