Home | History | Annotate | Line # | Download | only in glamor
      1 /*
      2  * Copyright  2001 Keith Packard
      3  * Copyright  2008 Intel Corporation
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     22  * IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Eric Anholt <eric (at) anholt.net>
     26  *
     27  */
     28 
     29 /** @file glamor_core.c
     30  *
     31  * This file covers core X rendering in glamor.
     32  */
     33 
     34 #include <stdlib.h>
     35 
     36 #include "glamor_priv.h"
     37 
     38 Bool
     39 glamor_get_drawable_location(const DrawablePtr drawable)
     40 {
     41     PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
     42     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
     43 
     44     if (pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED)
     45         return 'm';
     46     else
     47         return 'f';
     48 }
     49 
     50 GLint
     51 glamor_compile_glsl_prog(GLenum type, const char *source)
     52 {
     53     GLint ok;
     54     GLint prog;
     55 
     56     prog = glCreateShader(type);
     57     glShaderSource(prog, 1, (const GLchar **) &source, NULL);
     58     glCompileShader(prog);
     59     glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
     60     if (!ok) {
     61         GLchar *info;
     62         GLint size;
     63 
     64         glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
     65         info = malloc(size);
     66         if (info) {
     67             glGetShaderInfoLog(prog, size, NULL, info);
     68             ErrorF("Failed to compile %s: %s\n",
     69                    type == GL_FRAGMENT_SHADER ? "FS" : "VS", info);
     70             ErrorF("Program source:\n%s", source);
     71             free(info);
     72         }
     73         else
     74             ErrorF("Failed to get shader compilation info.\n");
     75         FatalError("GLSL compile failure\n");
     76     }
     77 
     78     return prog;
     79 }
     80 
     81 Bool
     82 glamor_link_glsl_prog(ScreenPtr screen, GLint prog, const char *format, ...)
     83 {
     84     GLint ok;
     85     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
     86 
     87     if (glamor_priv->has_khr_debug) {
     88         char *label;
     89         va_list va;
     90 
     91         va_start(va, format);
     92         XNFvasprintf(&label, format, va);
     93         glObjectLabel(GL_PROGRAM, prog, -1, label);
     94         free(label);
     95         va_end(va);
     96     }
     97 
     98     glLinkProgram(prog);
     99     glGetProgramiv(prog, GL_LINK_STATUS, &ok);
    100     if (!ok) {
    101         GLchar *info;
    102         GLint size;
    103 
    104         glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
    105         info = malloc(size);
    106 
    107         glGetProgramInfoLog(prog, size, NULL, info);
    108         ErrorF("Failed to link: %s\n", info);
    109         return FALSE;
    110     }
    111     return TRUE;
    112 }
    113 
    114 
    115 static GCOps glamor_gc_ops = {
    116     .FillSpans = glamor_fill_spans,
    117     .SetSpans = glamor_set_spans,
    118     .PutImage = glamor_put_image,
    119     .CopyArea = glamor_copy_area,
    120     .CopyPlane = glamor_copy_plane,
    121     .PolyPoint = glamor_poly_point,
    122     .Polylines = glamor_poly_lines,
    123     .PolySegment = glamor_poly_segment,
    124     .PolyRectangle = miPolyRectangle,
    125     .PolyArc = miPolyArc,
    126     .FillPolygon = miFillPolygon,
    127     .PolyFillRect = glamor_poly_fill_rect,
    128     .PolyFillArc = miPolyFillArc,
    129     .PolyText8 = glamor_poly_text8,
    130     .PolyText16 = glamor_poly_text16,
    131     .ImageText8 = glamor_image_text8,
    132     .ImageText16 = glamor_image_text16,
    133     .ImageGlyphBlt = miImageGlyphBlt,
    134     .PolyGlyphBlt = glamor_poly_glyph_blt,
    135     .PushPixels = glamor_push_pixels,
    136 };
    137 
    138 /*
    139  * When the stipple is changed or drawn to, invalidate any
    140  * cached copy
    141  */
    142 static void
    143 glamor_invalidate_stipple(GCPtr gc)
    144 {
    145     glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
    146 
    147     if (gc_priv->stipple) {
    148         if (gc_priv->stipple_damage)
    149             DamageUnregister(gc_priv->stipple_damage);
    150         glamor_destroy_pixmap(gc_priv->stipple);
    151         gc_priv->stipple = NULL;
    152     }
    153 }
    154 
    155 static void
    156 glamor_stipple_damage_report(DamagePtr damage, RegionPtr region,
    157                              void *closure)
    158 {
    159     GCPtr       gc = closure;
    160 
    161     glamor_invalidate_stipple(gc);
    162 }
    163 
    164 static void
    165 glamor_stipple_damage_destroy(DamagePtr damage, void *closure)
    166 {
    167     GCPtr               gc = closure;
    168     glamor_gc_private   *gc_priv = glamor_get_gc_private(gc);
    169 
    170     gc_priv->stipple_damage = NULL;
    171     glamor_invalidate_stipple(gc);
    172 }
    173 
    174 void
    175 glamor_track_stipple(GCPtr gc)
    176 {
    177     if (gc->stipple) {
    178         glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
    179 
    180         if (!gc_priv->stipple_damage)
    181             gc_priv->stipple_damage = DamageCreate(glamor_stipple_damage_report,
    182                                                    glamor_stipple_damage_destroy,
    183                                                    DamageReportNonEmpty,
    184                                                    TRUE, gc->pScreen, gc);
    185         if (gc_priv->stipple_damage)
    186             DamageRegister(&gc->stipple->drawable, gc_priv->stipple_damage);
    187     }
    188 }
    189 
    190 /**
    191  * uxa_validate_gc() sets the ops to glamor's implementations, which may be
    192  * accelerated or may sync the card and fall back to fb.
    193  */
    194 void
    195 glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
    196 {
    197     /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
    198      * Preempt fbValidateGC by doing its work and masking the change out, so
    199      * that we can do the Prepare/finish_access.
    200      */
    201     if (changes & GCTile) {
    202         if (!gc->tileIsPixel) {
    203             assert(gc->tile.pixmap != NullPixmap);
    204 
    205             glamor_pixmap_private *pixmap_priv =
    206                 glamor_get_pixmap_private(gc->tile.pixmap);
    207             if ((!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
    208                 && FbEvenTile(gc->tile.pixmap->drawable.width *
    209                               drawable->bitsPerPixel)) {
    210                 glamor_fallback
    211                     ("GC %p tile changed %p.\n", gc, gc->tile.pixmap);
    212                 if (glamor_prepare_access
    213                     (&gc->tile.pixmap->drawable, GLAMOR_ACCESS_RW)) {
    214                     fbPadPixmap(gc->tile.pixmap);
    215                     glamor_finish_access(&gc->tile.pixmap->drawable);
    216                 }
    217             }
    218         }
    219         /* Mask out the GCTile change notification, now that we've done FB's
    220          * job for it.
    221          */
    222         changes &= ~GCTile;
    223     }
    224 
    225     if (changes & GCStipple)
    226         glamor_invalidate_stipple(gc);
    227 
    228     if (changes & GCStipple && gc->stipple) {
    229         /* We can't inline stipple handling like we do for GCTile because
    230          * it sets fbgc privates.
    231          */
    232         if (glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RW)) {
    233             fbValidateGC(gc, changes, drawable);
    234             glamor_finish_access(&gc->stipple->drawable);
    235         }
    236     }
    237     else {
    238         fbValidateGC(gc, changes, drawable);
    239     }
    240 
    241     if (changes & GCDashList) {
    242         glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
    243 
    244         if (gc_priv->dash) {
    245             glamor_destroy_pixmap(gc_priv->dash);
    246             gc_priv->dash = NULL;
    247         }
    248     }
    249 
    250     gc->ops = &glamor_gc_ops;
    251 }
    252 
    253 void
    254 glamor_destroy_gc(GCPtr gc)
    255 {
    256     glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
    257 
    258     if (gc_priv->dash) {
    259         glamor_destroy_pixmap(gc_priv->dash);
    260         gc_priv->dash = NULL;
    261     }
    262     glamor_invalidate_stipple(gc);
    263     if (gc_priv->stipple_damage)
    264         DamageDestroy(gc_priv->stipple_damage);
    265     miDestroyGC(gc);
    266 }
    267 
    268 static GCFuncs glamor_gc_funcs = {
    269     glamor_validate_gc,
    270     miChangeGC,
    271     miCopyGC,
    272     glamor_destroy_gc,
    273     miChangeClip,
    274     miDestroyClip,
    275     miCopyClip
    276 };
    277 
    278 /**
    279  * exaCreateGC makes a new GC and hooks up its funcs handler, so that
    280  * exaValidateGC() will get called.
    281  */
    282 int
    283 glamor_create_gc(GCPtr gc)
    284 {
    285     glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
    286 
    287     gc_priv->dash = NULL;
    288     gc_priv->stipple = NULL;
    289     if (!fbCreateGC(gc))
    290         return FALSE;
    291 
    292     gc->funcs = &glamor_gc_funcs;
    293 
    294     return TRUE;
    295 }
    296 
    297 RegionPtr
    298 glamor_bitmap_to_region(PixmapPtr pixmap)
    299 {
    300     RegionPtr ret;
    301 
    302     glamor_fallback("pixmap %p \n", pixmap);
    303     if (!glamor_prepare_access(&pixmap->drawable, GLAMOR_ACCESS_RO))
    304         return NULL;
    305     ret = fbPixmapToRegion(pixmap);
    306     glamor_finish_access(&pixmap->drawable);
    307     return ret;
    308 }
    309 
    310