diff options
Diffstat (limited to 'xorg-server/glamor/glamor_putimage.c')
-rw-r--r-- | xorg-server/glamor/glamor_putimage.c | 363 |
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); +} + |