aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/glamor/glamor_putimage.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/glamor/glamor_putimage.c')
-rw-r--r--xorg-server/glamor/glamor_putimage.c363
1 files changed, 363 insertions, 0 deletions
diff --git a/xorg-server/glamor/glamor_putimage.c b/xorg-server/glamor/glamor_putimage.c
new file mode 100644
index 000000000..99f7ac6f5
--- /dev/null
+++ b/xorg-server/glamor/glamor_putimage.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright © 2009 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>
+ *
+ */
+
+
+/** @file glamor_putaimge.c
+ *
+ * XPutImage implementation
+ */
+#include "glamor_priv.h"
+
+void
+glamor_init_putimage_shaders(ScreenPtr screen)
+{
+#if 0
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ const char *xybitmap_vs =
+ "uniform float x_bias;\n" "uniform float x_scale;\n"
+ "uniform float y_bias;\n" "uniform float y_scale;\n"
+ "varying vec2 bitmap_coords;\n" "void main()\n" "{\n"
+ " gl_Position = vec4((gl_Vertex.x + x_bias) * x_scale,\n"
+ " (gl_Vertex.y + y_bias) * y_scale,\n"
+ " 0,\n"
+ " 1);\n"
+ " bitmap_coords = gl_MultiTexCoord0.xy;\n" "}\n";
+ const char *xybitmap_fs =
+ "uniform vec4 fg, bg;\n" "varying vec2 bitmap_coords;\n"
+ "uniform sampler2D bitmap_sampler;\n" "void main()\n" "{\n"
+ " float bitmap_value = texture2D(bitmap_sampler,\n"
+ " bitmap_coords).x;\n"
+ " gl_FragColor = mix(bg, fg, bitmap_value);\n" "}\n";
+ GLint fs_prog, vs_prog, prog;
+ GLint sampler_uniform_location;
+
+ if (!GLEW_ARB_fragment_shader)
+ return;
+
+ prog = dispatch->glCreateProgram();
+ vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, xybitmap_vs);
+ fs_prog =
+ glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, xybitmap_fs);
+ dispatch->glAttachShader(prog, vs_prog);
+ dispatch->glAttachShader(prog, fs_prog);
+ glamor_link_glsl_prog(prog);
+
+ dispatch->glUseProgram(prog);
+ sampler_uniform_location =
+ dispatch->glGetUniformLocation(prog, "bitmap_sampler");
+ dispatch->glUniform1i(sampler_uniform_location, 0);
+
+ glamor_priv->put_image_xybitmap_fg_uniform_location =
+ dispatch->glGetUniformLocation(prog, "fg");
+ glamor_priv->put_image_xybitmap_bg_uniform_location =
+ dispatch->glGetUniformLocation(prog, "bg");
+ glamor_get_transform_uniform_locations(prog,
+ &glamor_priv->put_image_xybitmap_transform);
+ glamor_priv->put_image_xybitmap_prog = prog;
+ dispatch->glUseProgram(0);
+#endif
+}
+
+
+/* Do an XYBitmap putimage. The bits are byte-aligned rows of bitmap
+ * data (where each row starts at a bit index of left_pad), and the
+ * destination gets filled with the gc's fg color where the bitmap is set
+ * and the bg color where the bitmap is unset.
+ *
+ * Implement this by passing the bitmap right through to GL, and sampling
+ * it to choose between fg and bg in the fragment shader. The driver may
+ * be exploding the bitmap up to be an 8-bit alpha texture, in which
+ * case we might be better off just doing the fg/bg choosing in the CPU
+ * and just draw the resulting texture to the destination.
+ */
+#if 0
+
+static int
+y_flip(PixmapPtr pixmap, int y)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
+
+ if (pixmap == screen_pixmap)
+ return (pixmap->drawable.height - 1) - y;
+ else
+ return y;
+}
+
+
+static void
+glamor_put_image_xybitmap(DrawablePtr drawable, GCPtr gc,
+ int x, int y, int w, int h, int left_pad,
+ int image_format, char *bits)
+{
+ ScreenPtr screen = drawable->pScreen;
+ PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ float fg[4], bg[4];
+ GLuint tex;
+ unsigned int stride = PixmapBytePad(1, w + left_pad);
+ RegionPtr clip;
+ BoxPtr box;
+ int nbox;
+ float dest_coords[8];
+ const float bitmap_coords[8] = {
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 1.0, 1.0,
+ 0.0, 1.0,
+ };
+ GLfloat xscale, yscale;
+ glamor_pixmap_private *pixmap_priv;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ pixmap_priv_get_scale(pixmap_priv, &xscale, &yscale);
+
+ glamor_set_normalize_vcoords(xscale, yscale,
+ x, y,
+ x + w, y + h,
+ glamor_priv->yInverted, dest_coords);
+
+ glamor_fallback("glamor_put_image_xybitmap: disabled\n");
+ goto fail;
+
+ if (glamor_priv->put_image_xybitmap_prog == 0) {
+ ErrorF("no program for xybitmap putimage\n");
+ goto fail;
+ }
+
+ glamor_set_alu(gc->alu);
+ if (!glamor_set_planemask(pixmap, gc->planemask))
+ goto fail;
+
+ dispatch->glUseProgram(glamor_priv->put_image_xybitmap_prog);
+
+ glamor_get_color_4f_from_pixel(pixmap, gc->fgPixel, fg);
+ dispatch->glUniform4fv
+ (glamor_priv->put_image_xybitmap_fg_uniform_location, 1, fg);
+ glamor_get_color_4f_from_pixel(pixmap, gc->bgPixel, bg);
+ dispatch->glUniform4fv
+ (glamor_priv->put_image_xybitmap_bg_uniform_location, 1, bg);
+
+ dispatch->glGenTextures(1, &tex);
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glEnable(GL_TEXTURE_2D);
+ 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, 1);
+ dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, stride * 8);
+ dispatch->glPixelStorei(GL_UNPACK_SKIP_PIXELS, left_pad);
+ dispatch->glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA,
+ w, h, 0, GL_COLOR_INDEX, GL_BITMAP, bits);
+ dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ dispatch->glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+
+ /* Now that we've set up our bitmap texture and the shader, shove
+ * the destination rectangle through the cliprects and run the
+ * shader on the resulting fragments.
+ */
+ dispatch->glVertexPointer(2, GL_FLOAT, 0, dest_coords);
+ dispatch->glEnableClientState(GL_VERTEX_ARRAY);
+ dispatch->glClientActiveTexture(GL_TEXTURE0);
+ dispatch->glTexCoordPointer(2, GL_FLOAT, 0, bitmap_coords);
+ dispatch->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ dispatch->glEnable(GL_SCISSOR_TEST);
+ clip = fbGetCompositeClip(gc);
+ for (nbox = REGION_NUM_RECTS(clip),
+ box = REGION_RECTS(clip); nbox--; box++) {
+ int x1 = x;
+ int y1 = y;
+ int x2 = x + w;
+ int y2 = y + h;
+
+ if (x1 < box->x1)
+ x1 = box->x1;
+ if (y1 < box->y1)
+ y1 = box->y1;
+ if (x2 > box->x2)
+ x2 = box->x2;
+ if (y2 > box->y2)
+ y2 = box->y2;
+ if (x1 >= x2 || y1 >= y2)
+ continue;
+
+ dispatch->glScissor(box->x1,
+ y_flip(pixmap, box->y1),
+ box->x2 - box->x1, box->y2 - box->y1);
+ dispatch->glDrawArrays(GL_QUADS, 0, 4);
+ }
+
+ dispatch->glDisable(GL_SCISSOR_TEST);
+ glamor_set_alu(GXcopy);
+ glamor_set_planemask(pixmap, ~0);
+ dispatch->glDeleteTextures(1, &tex);
+ dispatch->glDisable(GL_TEXTURE_2D);
+ dispatch->glDisableClientState(GL_VERTEX_ARRAY);
+ dispatch->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ return;
+ glamor_set_alu(GXcopy);
+ glamor_set_planemask(pixmap, ~0);
+ glamor_fallback(": to %p (%c)\n",
+ drawable, glamor_get_drawable_location(drawable));
+fail:
+ if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW)) {
+ fbPutImage(drawable, gc, 1, x, y, w, h, left_pad, XYBitmap,
+ bits);
+ glamor_finish_access(drawable, GLAMOR_ACCESS_RW);
+ }
+}
+#endif
+
+void
+glamor_fini_putimage_shaders(ScreenPtr screen)
+{
+}
+
+
+static Bool
+_glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
+ int w, int h, int left_pad, int image_format, char *bits, Bool fallback)
+{
+ PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_pixmap_private *pixmap_priv =
+ glamor_get_pixmap_private(pixmap);
+ RegionPtr clip;
+ int x_off, y_off;
+ Bool ret = FALSE;
+ PixmapPtr temp_pixmap, sub_pixmap;
+ glamor_pixmap_private *temp_pixmap_priv;
+ BoxRec box;
+
+ glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off);
+ clip = fbGetCompositeClip(gc);
+ if (image_format == XYBitmap) {
+ assert(depth == 1);
+ goto fail;
+ }
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
+ glamor_fallback("has no fbo.\n");
+ goto fail;
+ }
+
+ if (image_format != ZPixmap) {
+ glamor_fallback("non-ZPixmap\n");
+ goto fail;
+ }
+
+ if (!glamor_set_planemask(pixmap, gc->planemask)) {
+ goto fail;
+ }
+ /* create a temporary pixmap and upload the bits to that
+ * pixmap, then apply clip copy it to the destination pixmap.*/
+ box.x1 = x + drawable->x;
+ box.y1 = y + drawable->y;
+ box.x2 = x + w + drawable->x;
+ box.y2 = y + h + drawable->y;
+
+ if ((clip != NULL && RegionContainsRect(clip, &box) != rgnIN)
+ || gc->alu != GXcopy) {
+ temp_pixmap = glamor_create_pixmap(drawable->pScreen, w, h, depth, 0);
+ if (temp_pixmap == NULL)
+ goto fail;
+
+ temp_pixmap_priv = glamor_get_pixmap_private(temp_pixmap);
+
+ if (GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv)) {
+ temp_pixmap_priv->base.picture = pixmap_priv->base.picture;
+ temp_pixmap_priv->base.is_picture = pixmap_priv->base.is_picture;
+ }
+
+ glamor_upload_sub_pixmap_to_texture(temp_pixmap, 0, 0, w, h,
+ pixmap->devKind, bits, 0);
+
+ glamor_copy_area(&temp_pixmap->drawable, drawable, gc, 0, 0, w, h, x, y);
+ glamor_destroy_pixmap(temp_pixmap);
+ } else
+ glamor_upload_sub_pixmap_to_texture(pixmap, x + drawable->x + x_off, y + drawable->y + y_off,
+ w, h, PixmapBytePad(w, depth), bits, 0);
+ ret = TRUE;
+ goto done;
+
+fail:
+ glamor_set_planemask(pixmap, ~0);
+
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(&pixmap->drawable))
+ goto done;
+
+ glamor_fallback("to %p (%c)\n",
+ drawable, glamor_get_drawable_location(drawable));
+
+ sub_pixmap = glamor_get_sub_pixmap(pixmap, x + x_off + drawable->x,
+ y + y_off + drawable->y, w, h,
+ GLAMOR_ACCESS_RW);
+ if (sub_pixmap) {
+ if (clip != NULL)
+ pixman_region_translate (clip, -x - drawable->x, -y - drawable->y);
+
+ fbPutImage(&sub_pixmap->drawable, gc, depth, 0, 0, w, h,
+ left_pad, image_format, bits);
+
+ glamor_put_sub_pixmap(sub_pixmap, pixmap,
+ x + x_off + drawable->x,
+ y + y_off + drawable->y,
+ w, h, GLAMOR_ACCESS_RW);
+ if (clip != NULL)
+ pixman_region_translate (clip, x + drawable->x, y + drawable->y);
+ } else
+ fbPutImage(drawable, gc, depth, x, y, w, h,
+ left_pad, image_format, bits);
+ ret = TRUE;
+
+done:
+ return ret;
+}
+
+void
+glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
+ int w, int h, int left_pad, int image_format, char *bits)
+{
+ _glamor_put_image(drawable, gc, depth, x, y, w, h,
+ left_pad, image_format, bits, TRUE);
+}
+
+Bool
+glamor_put_image_nf(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
+ int w, int h, int left_pad, int image_format, char *bits)
+{
+ return _glamor_put_image(drawable, gc, depth, x, y, w, h,
+ left_pad, image_format, bits, FALSE);
+}
+