static Bool glamor_copy_n_to_n_fbo_blit(DrawablePtr src, DrawablePtr dst, GCPtr gc, BoxPtr box, int nbox, int dx, int dy) { ScreenPtr screen = dst->pScreen; PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst); PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src); glamor_pixmap_private *src_pixmap_priv, *dst_pixmap_priv; glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); glamor_gl_dispatch *dispatch; int dst_x_off, dst_y_off, src_x_off, src_y_off, i; int fbo_x_off, fbo_y_off; int src_fbo_x_off, src_fbo_y_off; if (!glamor_priv->has_fbo_blit) { glamor_delayed_fallback(screen, "no EXT_framebuffer_blit\n"); return FALSE; } src_pixmap_priv = glamor_get_pixmap_private(src_pixmap); dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap); if (gc) { if (gc->alu != GXcopy) { glamor_delayed_fallback(screen, "non-copy ALU\n"); return FALSE; } } if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)) { glamor_delayed_fallback(screen, "no src fbo\n"); return FALSE; } if (glamor_set_destination_pixmap(dst_pixmap)) return FALSE; pixmap_priv_get_fbo_off(dst_pixmap_priv, &fbo_x_off, &fbo_y_off); pixmap_priv_get_fbo_off(src_pixmap_priv, &src_fbo_x_off, &src_fbo_y_off); dispatch = glamor_get_dispatch(glamor_priv); dispatch->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, src_pixmap_priv->base.fbo->fb); glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off, &dst_y_off); glamor_get_drawable_deltas(src, src_pixmap, &src_x_off, &src_y_off); dst_x_off += fbo_x_off; dst_y_off += fbo_y_off; src_y_off += dy + src_fbo_y_off; src_x_off += src_fbo_x_off; for (i = 0; i < nbox; i++) { if (glamor_priv->yInverted) { dispatch->glBlitFramebuffer((box[i].x1 + dx + src_x_off), (box[i].y1 + src_y_off), (box[i].x2 + dx + src_x_off), (box[i].y2 + src_y_off), (box[i].x1 + dst_x_off), (box[i].y1 + dst_y_off), (box[i].x2 + dst_x_off), (box[i].y2 + dst_y_off), GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { int flip_dst_y1 = dst_pixmap->drawable.height - (box[i].y2 + dst_y_off); int flip_dst_y2 = dst_pixmap->drawable.height - (box[i].y1 + dst_y_off); int flip_src_y1 = src_pixmap->drawable.height - (box[i].y2 + src_y_off); int flip_src_y2 = src_pixmap->drawable.height - (box[i].y1 + src_y_off); dispatch->glBlitFramebuffer(box[i].x1 + dx + src_x_off, flip_src_y1, box[i].x2 + dx + src_x_off, flip_src_y2, box[i].x1 + dst_x_off, flip_dst_y1, box[i].x2 + dst_x_off, flip_dst_y2, GL_COLOR_BUFFER_BIT, GL_NEAREST); } } glamor_put_dispatch(glamor_priv); glamor_priv->state = BLIT_STATE; return TRUE; }
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) { ScreenPtr screen = pixmap->drawable.pScreen; glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); glamor_screen_private *glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen); static float vertices[8]; 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_free_bits = 0; 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 = xallocarray(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) { free(converted_bits); 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 #ifdef WALKAROUND_LARGE_TEXTURE_MAP && glamor_pixmap_priv_is_small(pixmap_priv) #endif ) { int fbo_x_off, fbo_y_off; assert(pixmap_priv->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->fbo->width); assert(y + fbo_y_off + h <= pixmap_priv->fbo->height); __glamor_upload_pixmap_to_texture(pixmap, &pixmap_priv->fbo->tex, format, type, x + fbo_x_off, y + fbo_y_off, w, h, bits, pbo); } else { ptexcoords = texcoords_inv; pixmap_priv_get_dest_scale(pixmap, pixmap_priv, &dst_xscale, &dst_yscale); glamor_set_normalize_vcoords(pixmap_priv, dst_xscale, dst_yscale, x, y, x + w, y + h, vertices); /* Slow path, we need to flip y or wire alpha to 1. */ glamor_make_current(glamor_priv); glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), vertices); glEnableVertexAttribArray(GLAMOR_VERTEX_POS); glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), ptexcoords); glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE); glamor_set_destination_pixmap_priv_nc(glamor_priv, pixmap, pixmap_priv); glamor_set_alu(screen, GXcopy); __glamor_upload_pixmap_to_texture(pixmap, &tex, format, type, 0, 0, w, h, bits, pbo); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glUseProgram(glamor_priv->finish_access_prog[no_alpha]); glUniform1i(glamor_priv->finish_access_revert[no_alpha], revert); glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha], swap_rb); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableVertexAttribArray(GLAMOR_VERTEX_POS); glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); glDeleteTextures(1, &tex); glBindFramebuffer(GL_FRAMEBUFFER, 0); } if (need_free_bits) free(bits); return TRUE; }