xserver-multidpi/glamor/glamor_pixmap.c
Zhigang Gong 4c27ca4700 gles2: Fixed the compilation problem and some bugs.
Previous patch doesn't set the offset to zero for GLESv2
path. Now fix it.

This patch also fix a minor problem in pixmap uploading
preparation. If the revert is not REVERT_NORMAL, then we
don't need to prepare a fbo for it. As current mesa i965
gles2 driver doesn't support to set a A8 texture as a fbo
target, we must fix this problem. As some A1/A8 picture
need to be uploaded, this is the only place a A8 texture
may be attached to a fbo.

This patch also enable the shader gradient for GLESv2.
The reason we disable it before is that some glsl linker
doesn't support link different objects which have cross
reference. Now we don't have that problem.

Signed-off-by: Zhigang Gong <zhigang.gong@linux.intel.com>
2013-12-18 11:23:53 -08:00

1436 lines
40 KiB
C

/*
* Copyright © 2001 Keith Packard
* Copyright © 2008 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
* Zhigang Gong <zhigang.gong@linux.intel.com>
*
*/
#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;
}
void
glamor_pixmap_init(ScreenPtr screen)
{
}
void
glamor_pixmap_fini(ScreenPtr screen)
{
}
void
glamor_set_destination_pixmap_fbo(glamor_pixmap_fbo * fbo, int x0, int y0, int width, int height)
{
glamor_gl_dispatch *dispatch = glamor_get_dispatch(fbo->glamor_priv);
dispatch->glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
#ifndef GLAMOR_GLES2
dispatch->glMatrixMode(GL_PROJECTION);
dispatch->glLoadIdentity();
dispatch->glMatrixMode(GL_MODELVIEW);
dispatch->glLoadIdentity();
#endif
dispatch->glViewport(x0, y0,
width, height);
glamor_put_dispatch(fbo->glamor_priv);
}
void
glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private * pixmap_priv)
{
int w,h;
PIXMAP_PRIV_GET_ACTUAL_SIZE(pixmap_priv, w, h);
glamor_set_destination_pixmap_fbo(pixmap_priv->base.fbo, 0, 0,
w, h);
}
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;
}
Bool
glamor_set_alu(struct glamor_gl_dispatch *dispatch, unsigned char alu)
{
#ifndef GLAMOR_GLES2
if (alu == GXcopy) {
dispatch->glDisable(GL_COLOR_LOGIC_OP);
return TRUE;
}
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:
glamor_fallback("unsupported alu %x\n", alu);
return FALSE;
}
#else
if (alu != GXcopy)
return FALSE;
#endif
return TRUE;
}
static void *
_glamor_color_convert_a1_a8(void *src_bits, void *dst_bits, int w, int h, int stride, int revert)
{
PictFormatShort dst_format, src_format;
pixman_image_t *dst_image;
pixman_image_t *src_image;
int src_stride;
if (revert == REVERT_UPLOADING_A1) {
src_format = PICT_a1;
dst_format = PICT_a8;
src_stride = PixmapBytePad(w, 1);
} else {
dst_format = PICT_a1;
src_format = PICT_a8;
src_stride = (((w * 8 + 7) / 8) + 3) & ~3;
}
dst_image = pixman_image_create_bits(dst_format,
w, h,
dst_bits,
stride);
if (dst_image == NULL) {
return NULL;
}
src_image = pixman_image_create_bits(src_format,
w, h,
src_bits,
src_stride);
if (src_image == NULL) {
pixman_image_unref(dst_image);
return NULL;
}
pixman_image_composite(PictOpSrc, src_image, NULL, dst_image,
0, 0, 0, 0, 0, 0,
w,h);
pixman_image_unref(src_image);
pixman_image_unref(dst_image);
return dst_bits;
}
#define ADJUST_BITS(d, src_bits, dst_bits) (((dst_bits) == (src_bits)) ? (d) : \
(((dst_bits) > (src_bits)) ? \
(((d) << ((dst_bits) - (src_bits))) \
+ (( 1 << ((dst_bits) - (src_bits))) >> 1)) \
: ((d) >> ((src_bits) - (dst_bits)))))
#define GLAMOR_DO_CONVERT(src, dst, no_alpha, swap, \
a_shift_src, a_bits_src, \
b_shift_src, b_bits_src, \
g_shift_src, g_bits_src, \
r_shift_src, r_bits_src, \
a_shift, a_bits, \
b_shift, b_bits, \
g_shift, g_bits, \
r_shift, r_bits) \
{ \
typeof(src) a,b,g,r; \
typeof(src) a_mask_src, b_mask_src, g_mask_src, r_mask_src;\
a_mask_src = (((1 << (a_bits_src)) - 1) << a_shift_src);\
b_mask_src = (((1 << (b_bits_src)) - 1) << b_shift_src);\
g_mask_src = (((1 << (g_bits_src)) - 1) << g_shift_src);\
r_mask_src = (((1 << (r_bits_src)) - 1) << r_shift_src);\
if (no_alpha) \
a = (a_mask_src) >> (a_shift_src); \
else \
a = ((src) & (a_mask_src)) >> (a_shift_src); \
b = ((src) & (b_mask_src)) >> (b_shift_src); \
g = ((src) & (g_mask_src)) >> (g_shift_src); \
r = ((src) & (r_mask_src)) >> (r_shift_src); \
a = ADJUST_BITS(a, a_bits_src, a_bits); \
b = ADJUST_BITS(b, b_bits_src, b_bits); \
g = ADJUST_BITS(g, g_bits_src, g_bits); \
r = ADJUST_BITS(r, r_bits_src, r_bits); \
if (swap == 0) \
(*dst) = ((a) << (a_shift)) | ((b) << (b_shift)) | ((g) << (g_shift)) | ((r) << (r_shift)); \
else \
(*dst) = ((a) << (a_shift)) | ((r) << (b_shift)) | ((g) << (g_shift)) | ((b) << (r_shift)); \
}
static void *
_glamor_color_revert_x2b10g10r10(void *src_bits, void *dst_bits, int w, int h, int stride, int no_alpha, int revert, int swap_rb)
{
int x,y;
unsigned int *words, *saved_words, *source_words;
int swap = !(swap_rb == SWAP_NONE_DOWNLOADING || swap_rb == SWAP_NONE_UPLOADING);
source_words = src_bits;
words = dst_bits;
saved_words = words;
for (y = 0; y < h; y++)
{
DEBUGF("Line %d : ", y);
for (x = 0; x < w; x++)
{
unsigned int pixel = source_words[x];
if (revert == REVERT_DOWNLOADING_2_10_10_10)
GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
24, 8, 16, 8, 8, 8, 0, 8,
30, 2, 20, 10, 10, 10, 0, 10)
else
GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
30, 2, 20, 10, 10, 10, 0, 10,
24, 8, 16, 8, 8, 8, 0, 8);
DEBUGF("%x:%x ", pixel, words[x]);
}
DEBUGF("\n");
words += stride / sizeof(*words);
source_words += stride / sizeof(*words);
}
DEBUGF("\n");
return saved_words;
}
static void *
_glamor_color_revert_x1b5g5r5(void *src_bits, void *dst_bits, int w, int h, int stride, int no_alpha, int revert, int swap_rb)
{
int x,y;
unsigned short *words, *saved_words, *source_words;
int swap = !(swap_rb == SWAP_NONE_DOWNLOADING || swap_rb == SWAP_NONE_UPLOADING);
words = dst_bits;
source_words = src_bits;
saved_words = words;
for (y = 0; y < h; y++)
{
DEBUGF("Line %d : ", y);
for (x = 0; x < w; x++)
{
unsigned short pixel = source_words[x];
if (revert == REVERT_DOWNLOADING_1_5_5_5)
GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
0, 1, 1, 5, 6, 5, 11, 5,
15, 1, 10, 5, 5, 5, 0, 5)
else
GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
15, 1, 10, 5, 5, 5, 0, 5,
0, 1, 1, 5, 6, 5, 11, 5);
DEBUGF("%04x:%04x ", pixel, words[x]);
}
DEBUGF("\n");
words += stride / sizeof(*words);
source_words += stride / sizeof(*words);
}
DEBUGF("\n");
return saved_words;
}
/*
* This function is to convert an unsupported color format to/from a
* supported GL format.
* Here are the current scenarios:
*
* @no_alpha:
* If it is set, then we need to wire the alpha value to 1.
* @revert:
REVERT_DOWNLOADING_A1 : convert an Alpha8 buffer to a A1 buffer.
REVERT_UPLOADING_A1 : convert an A1 buffer to an Alpha8 buffer
REVERT_DOWNLOADING_2_10_10_10 : convert r10G10b10X2 to X2B10G10R10
REVERT_UPLOADING_2_10_10_10 : convert X2B10G10R10 to R10G10B10X2
REVERT_DOWNLOADING_1_5_5_5 : convert B5G5R5X1 to X1R5G5B5
REVERT_UPLOADING_1_5_5_5 : convert X1R5G5B5 to B5G5R5X1
@swap_rb: if we have the swap_rb set, then we need to swap the R and B's position.
*
*/
static void *
glamor_color_convert_to_bits(void *src_bits, void *dst_bits, int w, int h, int stride, int no_alpha, int revert, int swap_rb)
{
if (revert == REVERT_DOWNLOADING_A1 || revert == REVERT_UPLOADING_A1) {
return _glamor_color_convert_a1_a8(src_bits, dst_bits, w, h, stride, revert);
} else if (revert == REVERT_DOWNLOADING_2_10_10_10 || revert == REVERT_UPLOADING_2_10_10_10) {
return _glamor_color_revert_x2b10g10r10(src_bits, dst_bits, w, h, stride, no_alpha, revert, swap_rb);
} else if (revert == REVERT_DOWNLOADING_1_5_5_5 || revert == REVERT_UPLOADING_1_5_5_5) {
return _glamor_color_revert_x1b5g5r5(src_bits, dst_bits, w, h, stride, no_alpha, revert, swap_rb);
} else
ErrorF("convert a non-supported mode %x.\n", revert);
return NULL;
}
/**
* 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, unsigned int *tex,
GLenum format,
GLenum type,
int x, int y, int w, int h,
void *bits, int pbo)
{
glamor_screen_private *glamor_priv =
glamor_get_screen_private(pixmap->drawable.pScreen);
glamor_gl_dispatch *dispatch;
int non_sub = 0;
unsigned int iformat = 0;
dispatch = glamor_get_dispatch(glamor_priv);
if (*tex == 0) {
dispatch->glGenTextures(1, tex);
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
gl_iformat_for_depth(pixmap->drawable.depth, &iformat);
else
iformat = format;
non_sub = 1;
assert(x == 0 && y == 0);
}
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->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
if (bits == NULL)
dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
pbo);
if (non_sub)
dispatch->glTexImage2D(GL_TEXTURE_2D,
0, iformat, w, h, 0,
format, type,
bits);
else
dispatch->glTexSubImage2D(GL_TEXTURE_2D,
0, x, y, w, h,
format, type,
bits);
if (bits == NULL)
dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glamor_put_dispatch(glamor_priv);
}
static Bool
_glamor_upload_bits_to_pixmap_texture(PixmapPtr pixmap, GLenum format, GLenum type,
int no_alpha, int revert,
int swap_rb, int x, int y, int w, int h,
int stride, void* bits, int pbo)
{
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;
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 = 0;
int need_flip;
int need_free_bits = 0;
need_flip = !glamor_priv->yInverted;
if (bits == NULL)
goto ready_to_upload;
if (revert > REVERT_NORMAL) {
/* XXX if we are restoring the pixmap, then we may not need to allocate
* new buffer */
void *converted_bits;
if (pixmap->drawable.depth == 1)
stride = (((w * 8 + 7) / 8) + 3) & ~3;
converted_bits = malloc(h * stride);
if (converted_bits == NULL)
return FALSE;
bits = glamor_color_convert_to_bits(bits, converted_bits, w, h,
stride,
no_alpha, revert, swap_rb);
if (bits == NULL) {
ErrorF("Failed to convert pixmap no_alpha %d,"
"revert mode %d, swap mode %d\n", no_alpha, revert, swap_rb);
return FALSE;
}
no_alpha = 0;
revert = REVERT_NONE;
swap_rb = SWAP_NONE_UPLOADING;
need_free_bits = TRUE;
}
ready_to_upload:
/* Try fast path firstly, upload the pixmap to the texture attached
* to the fbo directly. */
if (no_alpha == 0
&& revert == REVERT_NONE
&& swap_rb == SWAP_NONE_UPLOADING
&& !need_flip
#ifdef WALKAROUND_LARGE_TEXTURE_MAP
&& pixmap_priv->type != GLAMOR_TEXTURE_LARGE
#endif
) {
int fbo_x_off, fbo_y_off;
assert(pixmap_priv->base.fbo->tex);
pixmap_priv_get_fbo_off(pixmap_priv, &fbo_x_off, &fbo_y_off);
assert(x + fbo_x_off >= 0 && y + fbo_y_off >= 0);
assert(x + fbo_x_off + w <= pixmap_priv->base.fbo->width);
assert(y + fbo_y_off + h <= pixmap_priv->base.fbo->height);
__glamor_upload_pixmap_to_texture(pixmap, &pixmap_priv->base.fbo->tex,
format, type,
x + fbo_x_off, y + fbo_y_off, w, h,
bits, pbo);
return TRUE;
}
if (need_flip)
ptexcoords = texcoords;
else
ptexcoords = texcoords_inv;
pixmap_priv_get_dest_scale(pixmap_priv, &dst_xscale, &dst_yscale);
glamor_set_normalize_vcoords(pixmap_priv, dst_xscale,
dst_yscale,
x, y,
x + w, y + h,
glamor_priv->yInverted,
vertices);
/* Slow path, we need to flip y or wire alpha to 1. */
dispatch = glamor_get_dispatch(glamor_priv);
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);
__glamor_upload_pixmap_to_texture(pixmap, &tex,
format, type,
0, 0, w, h,
bits, pbo);
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_revert[no_alpha],
revert);
dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],
swap_rb);
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);
glamor_put_dispatch(glamor_priv);
if (need_free_bits)
free(bits);
return TRUE;
}
/*
* 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, GLenum format, int no_alpha, int revert, int swap_rb)
{
int flag = 0;
glamor_pixmap_private *pixmap_priv;
glamor_screen_private *glamor_priv;
glamor_pixmap_fbo *fbo;
GLenum iformat;
pixmap_priv = glamor_get_pixmap_private(pixmap);
glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
if (pixmap_priv->base.gl_fbo)
return 0;
if (pixmap_priv->base.fbo
&& (pixmap_priv->base.fbo->width < pixmap->drawable.width
|| pixmap_priv->base.fbo->height < pixmap->drawable.height)) {
fbo = glamor_pixmap_detach_fbo(pixmap_priv);
glamor_destroy_fbo(fbo);
}
if (pixmap_priv->base.fbo && pixmap_priv->base.fbo->fb)
return 0;
if (!(no_alpha
|| (revert == REVERT_NORMAL)
|| (swap_rb != SWAP_NONE_UPLOADING)
|| !glamor_priv->yInverted)) {
/* We don't need a fbo, a simple texture uploading should work. */
flag = GLAMOR_CREATE_FBO_NO_FBO;
}
if ((flag == GLAMOR_CREATE_FBO_NO_FBO
&& pixmap_priv->base.fbo && pixmap_priv->base.fbo->tex)
|| (flag == 0
&& pixmap_priv->base.fbo && pixmap_priv->base.fbo->fb))
return 0;
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
gl_iformat_for_depth(pixmap->drawable.depth, &iformat);
else
iformat = format;
if (!glamor_pixmap_ensure_fbo(pixmap, iformat, flag))
return -1;
return 0;
}
/*
* upload sub region to a large region.
* */
static void
glamor_put_bits(char *dst_bits, int dst_stride, char *src_bits,
int src_stride, int bpp,
int x, int y, int w, int h)
{
int j;
int byte_per_pixel;
byte_per_pixel = bpp / 8;
src_bits += y * src_stride + (x * byte_per_pixel);
for(j = y; j < y + h; j++)
{
memcpy(dst_bits, src_bits, w * byte_per_pixel);
src_bits += src_stride;
dst_bits += dst_stride;
}
}
/*
* download sub region from a large region.
*/
static void
glamor_get_bits(char *dst_bits, int dst_stride, char *src_bits,
int src_stride, int bpp,
int x, int y, int w, int h)
{
int j;
int byte_per_pixel;
byte_per_pixel = bpp / 8;
dst_bits += y * dst_stride + x * byte_per_pixel;
for(j = y; j < y + h; j++)
{
memcpy(dst_bits, src_bits, w * byte_per_pixel);
src_bits += src_stride;
dst_bits += dst_stride;
}
}
Bool
glamor_upload_sub_pixmap_to_texture(PixmapPtr pixmap, int x, int y, int w, int h,
int stride, void *bits, int pbo)
{
GLenum format, type;
int no_alpha, revert, swap_rb;
glamor_pixmap_private *pixmap_priv;
Bool force_clip;
if (glamor_get_tex_format_type_from_pixmap(pixmap,
&format,
&type,
&no_alpha,
&revert,
&swap_rb, 1)) {
glamor_fallback("Unknown pixmap depth %d.\n",
pixmap->drawable.depth);
return TRUE;
}
if (glamor_pixmap_upload_prepare(pixmap, format, no_alpha, revert, swap_rb))
return FALSE;
pixmap_priv = glamor_get_pixmap_private(pixmap);
force_clip = pixmap_priv->base.glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP
&& !glamor_check_fbo_size(pixmap_priv->base.glamor_priv, w, h);
if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE || force_clip) {
RegionRec region;
BoxRec box;
int n_region;
glamor_pixmap_clipped_regions *clipped_regions;
void *sub_bits;
int i,j;
sub_bits = malloc(h * stride);
if (sub_bits == NULL)
return FALSE;
box.x1 = x;
box.y1 = y;
box.x2 = x + w;
box.y2 = y + h;
RegionInitBoxes(&region, &box, 1);
if (!force_clip)
clipped_regions = glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0, 0, 0);
else
clipped_regions = glamor_compute_clipped_regions_ext(pixmap_priv, &region, &n_region,
pixmap_priv->base.glamor_priv->max_fbo_size,
pixmap_priv->base.glamor_priv->max_fbo_size, 0, 0);
DEBUGF("prepare upload %dx%d to a large pixmap %p\n", w, h, pixmap);
for(i = 0; i < n_region; i++)
{
BoxPtr boxes;
int nbox;
int temp_stride;
void *temp_bits;
assert(pbo == 0);
SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
boxes = RegionRects(clipped_regions[i].region);
nbox = RegionNumRects(clipped_regions[i].region);
DEBUGF("split to %d boxes\n", nbox);
for(j = 0; j < nbox; j++)
{
temp_stride = PixmapBytePad(boxes[j].x2 - boxes[j].x1,
pixmap->drawable.depth);
if (boxes[j].x1 == x && temp_stride == stride) {
temp_bits = (char*)bits + (boxes[j].y1 - y) * stride;
} else {
temp_bits = sub_bits;
glamor_put_bits(temp_bits, temp_stride, bits, stride,
pixmap->drawable.bitsPerPixel,
boxes[j].x1 - x, boxes[j].y1 - y,
boxes[j].x2 - boxes[j].x1,
boxes[j].y2 - boxes[j].y1);
}
DEBUGF("upload x %d y %d w %d h %d temp stride %d \n",
boxes[j].x1 - x, boxes[j].y1 - y,
boxes[j].x2 - boxes[j].x1,
boxes[j].y2 - boxes[j].y1, temp_stride);
if (_glamor_upload_bits_to_pixmap_texture(pixmap, format, type, no_alpha,
revert, swap_rb, boxes[j].x1, boxes[j].y1,
boxes[j].x2 - boxes[j].x1,
boxes[j].y2 - boxes[j].y1,
temp_stride, temp_bits, pbo) == FALSE) {
RegionUninit(&region);
free(sub_bits);
assert(0);
return FALSE;
}
}
RegionDestroy(clipped_regions[i].region);
}
free(sub_bits);
free(clipped_regions);
RegionUninit(&region);
return TRUE;
} else
return _glamor_upload_bits_to_pixmap_texture(pixmap, format, type, no_alpha, revert, swap_rb,
x, y, w, h, stride, bits, pbo);
}
enum glamor_pixmap_status
glamor_upload_pixmap_to_texture(PixmapPtr pixmap)
{
glamor_pixmap_private *pixmap_priv;
void *data;
int pbo;
int ret;
pixmap_priv = glamor_get_pixmap_private(pixmap);
if ((pixmap_priv->base.fbo)
&& (pixmap_priv->base.fbo->pbo_valid)) {
data = NULL;
pbo = pixmap_priv->base.fbo->pbo;
} else {
data = pixmap->devPrivate.ptr;
pbo = 0;
}
if (glamor_upload_sub_pixmap_to_texture(pixmap, 0, 0,
pixmap->drawable.width,
pixmap->drawable.height,
pixmap->devKind,
data, pbo))
ret = GLAMOR_UPLOAD_DONE;
else
ret = GLAMOR_UPLOAD_FAILED;
return ret;
}
void
glamor_restore_pixmap_to_texture(PixmapPtr pixmap)
{
if (glamor_upload_pixmap_to_texture(pixmap) != GLAMOR_UPLOAD_DONE)
LogMessage(X_WARNING, "Failed to restore pixmap to texture.\n");
}
/*
* 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.
* */
glamor_pixmap_fbo *
glamor_es2_pixmap_read_prepare(PixmapPtr source, int x, int y, int w, int h, GLenum format,
GLenum type, int no_alpha, int revert, int swap_rb)
{
glamor_pixmap_private *source_priv;
glamor_screen_private *glamor_priv;
ScreenPtr screen;
glamor_pixmap_fbo *temp_fbo;
glamor_gl_dispatch *dispatch;
float temp_xscale, temp_yscale, source_xscale, source_yscale;
static float vertices[8];
static float texcoords[8];
screen = source->drawable.pScreen;
glamor_priv = glamor_get_screen_private(screen);
source_priv = glamor_get_pixmap_private(source);
temp_fbo = glamor_create_fbo(glamor_priv,
w, h,
format,
0);
if (temp_fbo == NULL)
return NULL;
dispatch = glamor_get_dispatch(glamor_priv);
temp_xscale = 1.0 / w;
temp_yscale = 1.0 / h;
glamor_set_normalize_vcoords((struct glamor_pixmap_private*)NULL,temp_xscale,
temp_yscale,
0, 0,
w, h,
glamor_priv->yInverted,
vertices);
dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
GL_FALSE, 2 * sizeof(float),
vertices);
dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
pixmap_priv_get_scale(source_priv, &source_xscale, &source_yscale);
glamor_set_normalize_tcoords(source_priv, source_xscale,
source_yscale,
x, y,
x + w, y + h,
glamor_priv->yInverted,
texcoords);
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->base.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_fbo(temp_fbo, 0, 0, w, h);
dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
dispatch->glUniform1i(glamor_priv->
finish_access_revert[no_alpha],
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);
glamor_put_dispatch(glamor_priv);
return temp_fbo;
}
/*
* Download a sub region of pixmap to a specified memory region.
* The pixmap must have a valid FBO, otherwise return a NULL.
* */
static void *
_glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, GLenum format,
GLenum type, int no_alpha,
int revert, int swap_rb,
int x, int y, int w, int h,
int stride, void *bits, int pbo, glamor_access_t access)
{
glamor_pixmap_private *pixmap_priv;
GLenum gl_access = 0, gl_usage = 0;
void *data, *read;
ScreenPtr screen;
glamor_screen_private *glamor_priv =
glamor_get_screen_private(pixmap->drawable.pScreen);
glamor_gl_dispatch *dispatch;
glamor_pixmap_fbo *temp_fbo = NULL;
int need_post_conversion = 0;
int need_free_data = 0;
int fbo_x_off, fbo_y_off;
data = bits;
screen = pixmap->drawable.pScreen;
pixmap_priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
return NULL;
switch (access) {
case GLAMOR_ACCESS_RO:
gl_access = GL_READ_ONLY;
gl_usage = GL_STREAM_READ;
break;
case GLAMOR_ACCESS_WO:
return bits;
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);
}
glamor_set_destination_pixmap_priv_nc(pixmap_priv);
need_post_conversion = (revert > REVERT_NORMAL);
if (need_post_conversion) {
if (pixmap->drawable.depth == 1) {
int temp_stride;
temp_stride = (((w * 8 + 7) / 8) + 3) & ~3;
data = malloc(temp_stride * h);
if (data == NULL)
return NULL;
need_free_data = 1;
}
}
pixmap_priv_get_fbo_off(pixmap_priv, &fbo_x_off, &fbo_y_off);
if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
&& !need_post_conversion
&& (swap_rb != SWAP_NONE_DOWNLOADING || revert != REVERT_NONE)) {
if (!(temp_fbo = glamor_es2_pixmap_read_prepare(pixmap, x, y, w, h,
format, type, no_alpha,
revert, swap_rb))) {
free(data);
return NULL;
}
x = 0;
y = 0;
fbo_x_off = 0;
fbo_y_off = 0;
}
dispatch = glamor_get_dispatch(glamor_priv);
dispatch->glPixelStorei(GL_PACK_ALIGNMENT, 4);
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 && data == NULL) {
assert(pbo > 0);
dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
stride *
h,
NULL, gl_usage);
}
dispatch->glReadPixels(x + fbo_x_off, y + fbo_y_off, w, h, format, type, data);
if (!glamor_priv->yInverted) {
assert(glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP);
dispatch->glPixelStorei(GL_PACK_INVERT_MESA, 0);
}
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && bits == NULL) {
bits = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
gl_access);
dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
} else {
unsigned int temp_pbo;
int yy;
dispatch = glamor_get_dispatch(glamor_priv);
dispatch->glGenBuffers(1, &temp_pbo);
dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER,
temp_pbo);
dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
stride *
h,
NULL, GL_STREAM_READ);
dispatch->glReadPixels(x + fbo_x_off, y + fbo_y_off, w, h,
format, type, 0);
read = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
GL_READ_ONLY);
for (yy = 0; yy < pixmap->drawable.height; yy++)
memcpy((char*)data + yy * stride,
(char*)read + (h - yy - 1) * stride, stride);
dispatch->glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
dispatch->glDeleteBuffers(1, &temp_pbo);
}
dispatch->glBindFramebuffer(GL_FRAMEBUFFER, 0);
glamor_put_dispatch(glamor_priv);
if (need_post_conversion) {
/* As OpenGL desktop version never enters here.
* Don't need to consider if the pbo is valid.*/
bits = glamor_color_convert_to_bits(data, bits,
w, h,
stride,
no_alpha,
revert, swap_rb);
}
if (temp_fbo != NULL)
glamor_destroy_fbo(temp_fbo);
if (need_free_data)
free(data);
return bits;
}
void *
glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
int stride, void *bits, int pbo, glamor_access_t access)
{
GLenum format, type;
int no_alpha, revert, swap_rb;
glamor_pixmap_private *pixmap_priv;
Bool force_clip;
if (glamor_get_tex_format_type_from_pixmap(pixmap,
&format,
&type,
&no_alpha,
&revert,
&swap_rb, 0)) {
glamor_fallback("Unknown pixmap depth %d.\n",
pixmap->drawable.depth);
return NULL;
}
pixmap_priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
return NULL;
force_clip = pixmap_priv->base.glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP
&& !glamor_check_fbo_size(pixmap_priv->base.glamor_priv, w, h);
if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE || force_clip) {
RegionRec region;
BoxRec box;
int n_region;
glamor_pixmap_clipped_regions *clipped_regions;
void *sub_bits;
int i,j;
sub_bits = malloc(h * stride);
if (sub_bits == NULL)
return FALSE;
box.x1 = x;
box.y1 = y;
box.x2 = x + w;
box.y2 = y + h;
RegionInitBoxes(&region, &box, 1);
if (!force_clip)
clipped_regions = glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0, 0, 0);
else
clipped_regions = glamor_compute_clipped_regions_ext(pixmap_priv, &region, &n_region,
pixmap_priv->base.glamor_priv->max_fbo_size,
pixmap_priv->base.glamor_priv->max_fbo_size, 0, 0);
DEBUGF("start download large pixmap %p %dx%d \n", pixmap, w, h);
for(i = 0; i < n_region; i++)
{
BoxPtr boxes;
int nbox;
int temp_stride;
void *temp_bits;
assert(pbo == 0);
SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
boxes = RegionRects(clipped_regions[i].region);
nbox = RegionNumRects(clipped_regions[i].region);
for(j = 0; j < nbox; j++)
{
temp_stride = PixmapBytePad(boxes[j].x2 - boxes[j].x1,
pixmap->drawable.depth);
if (boxes[j].x1 == x && temp_stride == stride) {
temp_bits = (char*)bits + (boxes[j].y1 - y) * stride;
} else {
temp_bits = sub_bits;
}
DEBUGF("download x %d y %d w %d h %d temp stride %d \n",
boxes[j].x1, boxes[j].y1,
boxes[j].x2 - boxes[j].x1,
boxes[j].y2 - boxes[j].y1, temp_stride);
/* For large pixmap, we don't support pbo currently.*/
assert(pbo == 0);
if (_glamor_download_sub_pixmap_to_cpu(pixmap, format, type, no_alpha,
revert, swap_rb, boxes[j].x1, boxes[j].y1,
boxes[j].x2 - boxes[j].x1,
boxes[j].y2 - boxes[j].y1,
temp_stride, temp_bits, pbo, access) == FALSE) {
RegionUninit(&region);
free(sub_bits);
assert(0);
return NULL;
}
if (boxes[j].x1 != x || temp_stride != stride)
glamor_get_bits(bits, stride, temp_bits, temp_stride,
pixmap->drawable.bitsPerPixel,
boxes[j].x1 - x , boxes[j].y1 - y,
boxes[j].x2 - boxes[j].x1,
boxes[j].y2 - boxes[j].y1);
}
RegionDestroy(clipped_regions[i].region);
}
free(sub_bits);
free(clipped_regions);
RegionUninit(&region);
return bits;
} else
return _glamor_download_sub_pixmap_to_cpu(pixmap, format, type, no_alpha, revert, swap_rb,
x, y, w, h, stride,
bits, pbo, access);
}
/**
* 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;
void *data = NULL, *dst;
ScreenPtr screen;
glamor_screen_private *glamor_priv =
glamor_get_screen_private(pixmap->drawable.pScreen);
glamor_gl_dispatch *dispatch;
int pbo = 0;
screen = pixmap->drawable.pScreen;
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
return TRUE;
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;
if (access == GLAMOR_ACCESS_WO
|| glamor_priv->gl_flavor == GLAMOR_GL_ES2
|| (!glamor_priv->has_pack_invert && !glamor_priv->yInverted)
|| pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
data = malloc(stride * pixmap->drawable.height);
} else {
dispatch = glamor_get_dispatch(glamor_priv);
if (pixmap_priv->base.fbo->pbo == 0)
dispatch->glGenBuffers(1,
&pixmap_priv->base.fbo->pbo);
glamor_put_dispatch(glamor_priv);
pbo = pixmap_priv->base.fbo->pbo;
}
if (pixmap_priv->type == GLAMOR_TEXTURE_DRM) {
stride = PixmapBytePad(pixmap->drawable.width, pixmap->drawable.depth);
pixmap_priv->base.drm_stride = pixmap->devKind;
pixmap->devKind = stride;
}
dst = glamor_download_sub_pixmap_to_cpu(pixmap, 0, 0,
pixmap->drawable.width,
pixmap->drawable.height,
pixmap->devKind,
data, pbo, access);
if (!dst) {
if (data)
free(data);
return FALSE;
}
if (pbo != 0)
pixmap_priv->base.fbo->pbo_valid = 1;
pixmap_priv->base.gl_fbo = GLAMOR_FBO_DOWNLOADED;
pixmap->devPrivate.ptr = dst;
return TRUE;
}
/* fixup a fbo to the exact size as the pixmap. */
/* XXX LARGE 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->base.pixmap->drawable;
if (!GLAMOR_PIXMAP_FBO_NOT_EAXCT_SIZE(pixmap_priv))
return TRUE;
old_fbo = pixmap_priv->base.fbo;
glamor_priv = pixmap_priv->base.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->base.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->base.pixmap, 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;
}
/*
* 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 (x < 0 || y < 0)
return NULL;
w = (x + w) > pixmap->drawable.width ? (pixmap->drawable.width - x) : w;
h = (y + h) > pixmap->drawable.height ? (pixmap->drawable.height - y) : h;
if (access == GLAMOR_ACCESS_WO) {
sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU);
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 || pixmap_priv->type == GLAMOR_TEXTURE_LARGE)
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->base.fbo ? sub_pixmap_priv->base.fbo->pbo : 0): 0;
if (pixmap_priv->base.is_picture) {
sub_pixmap_priv->base.picture = pixmap_priv->base.picture;
sub_pixmap_priv->base.is_picture = pixmap_priv->base.is_picture;
}
if (pbo)
data = NULL;
else
data = sub_pixmap->devPrivate.ptr;
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->base.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->drawable, 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;
}
void
glamor_put_sub_pixmap(PixmapPtr sub_pixmap, PixmapPtr pixmap, int x, int y, int w, int h, glamor_access_t access)
{
void *bits;
int pbo;
glamor_pixmap_private *sub_pixmap_priv;
if (access != GLAMOR_ACCESS_RO) {
sub_pixmap_priv = glamor_get_pixmap_private(sub_pixmap);
if (sub_pixmap_priv->base.fbo
&& sub_pixmap_priv->base.fbo->pbo_valid) {
bits = NULL;
pbo = sub_pixmap_priv->base.fbo->pbo;
} else {
bits = sub_pixmap->devPrivate.ptr;
pbo = 0;
}
assert(x >= 0 && y >= 0);
w = (w > sub_pixmap->drawable.width) ? sub_pixmap->drawable.width : w;
h = (h > sub_pixmap->drawable.height) ? sub_pixmap->drawable.height : h;
glamor_upload_sub_pixmap_to_texture(pixmap, x, y, w, h, sub_pixmap->devKind, bits, pbo);
}
glamor_destroy_pixmap(sub_pixmap);
}