glamor_core.c 13.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*
 * 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>
 *
 */

/** @file glamor_core.c
 *
 * This file covers core X rendering in glamor.
 */

#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

#include <stdlib.h>

#include "glamor_priv.h"

42
43
44
const Bool
glamor_get_drawable_location(const DrawablePtr drawable)
{
45
46
47
48
49
50
51
52
53
54
  PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
  glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
  glamor_screen_private *glamor_priv =
    glamor_get_screen_private(drawable->pScreen);
  if (pixmap_priv == NULL || pixmap_priv->gl_fbo == 0)
    return 'm';
  if (pixmap_priv->fb == glamor_priv->screen_fbo)
    return 's';
  else
    return 'f';
55
56
}

57

58
59
60
61
void
glamor_get_transform_uniform_locations(GLint prog,
				       glamor_transform_uniforms *uniform_locations)
{
62
63
64
65
  uniform_locations->x_bias = glGetUniformLocation(prog, "x_bias");
  uniform_locations->x_scale = glGetUniformLocation(prog, "x_scale");
  uniform_locations->y_bias = glGetUniformLocation(prog, "y_bias");
  uniform_locations->y_scale = glGetUniformLocation(prog, "y_scale");
66
}
67

68
69
70
71
72
73
74
75
/* We don't use a full matrix for our transformations because it's
 * wasteful when all we want is to rescale to NDC and possibly do a flip
 * if it's the front buffer.
 */
void
glamor_set_transform_for_pixmap(PixmapPtr pixmap,
				glamor_transform_uniforms *uniform_locations)
{
76
77
78
79
  glUniform1f(uniform_locations->x_bias, -pixmap->drawable.width / 2.0f);
  glUniform1f(uniform_locations->x_scale, 2.0f / pixmap->drawable.width);
  glUniform1f(uniform_locations->y_bias, -pixmap->drawable.height / 2.0f);
  glUniform1f(uniform_locations->y_scale, -2.0f / pixmap->drawable.height);
80
81
82
83
84
}

GLint
glamor_compile_glsl_prog(GLenum type, const char *source)
{
85
86
87
  GLint ok;
  GLint prog;

88
89
90
  prog = glCreateShader(type);
  glShaderSource(prog, 1, (const GLchar **)&source, NULL);
  glCompileShader(prog);
91
  glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
92
93
94
95
  if (!ok) {
    GLchar *info;
    GLint size;

96
    glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
97
98
    info = malloc(size);

99
    glGetShaderInfoLog(prog, size, NULL, info);
100
101
102
103
104
105
106
107
    ErrorF("Failed to compile %s: %s\n",
	   type == GL_FRAGMENT_SHADER ? "FS" : "VS",
	   info);
    ErrorF("Program source:\n%s", source);
    FatalError("GLSL compile failure\n");
  }

  return prog;
108
109
110
}

void
111
glamor_link_glsl_prog(GLint prog)
112
{
113
114
115
  GLint ok;

  glLinkProgram(prog);
116
  glGetProgramiv(prog, GL_LINK_STATUS, &ok);
117
118
119
120
  if (!ok) {
    GLchar *info;
    GLint size;

121
    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
122
123
    info = malloc(size);

124
    glGetProgramInfoLog(prog, size, NULL, info);
125
126
127
128
    ErrorF("Failed to link: %s\n",
	   info);
    FatalError("GLSL link failure\n");
  }
129
130
}

131

132
133
134
Bool
glamor_prepare_access(DrawablePtr drawable, glamor_access_t access)
{
135
  PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
136

137
  return glamor_download_pixmap_to_cpu(pixmap, access);
138
139
}

140
141
142
void
glamor_init_finish_access_shaders(ScreenPtr screen)
{
143
144
  glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
  const char *vs_source =
145
146
147
148
149
150
151
152
153
    "attribute vec4 v_position;\n"
    "attribute vec4 v_texcoord0;\n"
    "varying vec2 source_texture;\n"
    "void main()\n"
    "{\n"
    "	gl_Position = v_position;\n"
    "	source_texture = v_texcoord0.xy;\n"
    "}\n";

154
  const char *fs_source =
155
156
157
158
159
160
161
    "varying vec2 source_texture;\n"
    "uniform sampler2D sampler;\n"
    "void main()\n"
    "{\n"
    "	gl_FragColor = texture2D(sampler, source_texture);\n"
    "}\n";
    
162
  const char *set_alpha_source =
163
164
165
166
167
168
    "varying vec2 source_texture;\n"
    "uniform sampler2D sampler;\n"
    "void main()\n"
    "{\n"
    " gl_FragColor = vec4(texture2D(sampler, source_texture).rgb, 1);\n"
    "}\n";
169
170
  GLint fs_prog, vs_prog, avs_prog, set_alpha_prog;
  GLint sampler_uniform_location;
171

172
173
  glamor_priv->finish_access_prog[0] = glCreateProgram();
  glamor_priv->finish_access_prog[1] = glCreateProgram();
174

Zhigang Gong's avatar
Zhigang Gong committed
175
176
177
178
179
180
  vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_source);
  fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_source);
  glAttachShader(glamor_priv->finish_access_prog[0], vs_prog);
  glAttachShader(glamor_priv->finish_access_prog[0], fs_prog);

  avs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_source);
181
  set_alpha_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, set_alpha_source);
Zhigang Gong's avatar
Zhigang Gong committed
182
  glAttachShader(glamor_priv->finish_access_prog[1], avs_prog);
183
  glAttachShader(glamor_priv->finish_access_prog[1], set_alpha_prog);
184

185
186
  glBindAttribLocation(glamor_priv->finish_access_prog[0], GLAMOR_VERTEX_POS, "v_position");
  glBindAttribLocation(glamor_priv->finish_access_prog[0], GLAMOR_VERTEX_SOURCE, "v_texcoord0");
187
  glamor_link_glsl_prog(glamor_priv->finish_access_prog[0]);
188

189
190
191
  glBindAttribLocation(glamor_priv->finish_access_prog[1], GLAMOR_VERTEX_POS, "v_position");
  glBindAttribLocation(glamor_priv->finish_access_prog[1], GLAMOR_VERTEX_SOURCE, "v_texcoord0");
  glamor_link_glsl_prog(glamor_priv->finish_access_prog[1]);
192

Zhigang Gong's avatar
Zhigang Gong committed
193
194
195
196
197
198
199
200
201
202
203
  sampler_uniform_location =
    glGetUniformLocation(glamor_priv->finish_access_prog[0], "sampler");
  glUseProgram(glamor_priv->finish_access_prog[0]);
  glUniform1i(sampler_uniform_location, 0);
  glUseProgram(0);

  sampler_uniform_location =
    glGetUniformLocation(glamor_priv->finish_access_prog[1], "sampler");
  glUseProgram(glamor_priv->finish_access_prog[1]);
  glUniform1i(sampler_uniform_location, 0);
  glUseProgram(0);
204
205
206
207
208
}

void
glamor_finish_access(DrawablePtr drawable)
{
209
210
  PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
  glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
211
  glamor_screen_private *glamor_priv = glamor_get_screen_private(drawable->pScreen);
212
213
214
215
216
217
218
219
220
    
  if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
    return;

  if ( pixmap_priv->access_mode != GLAMOR_ACCESS_RO) {
    glamor_restore_pixmap_to_texture(pixmap);
  }

  if (pixmap_priv->pbo != 0 && pixmap_priv->pbo_valid) {
221
222
223
    assert(glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP);
    glBindBuffer (GL_PIXEL_PACK_BUFFER, 0);
    glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
224
    pixmap_priv->pbo_valid = FALSE;
225
    glDeleteBuffers(1, &pixmap_priv->pbo);
226
227
228
229
230
231
    pixmap_priv->pbo = 0;
  } else
    free(pixmap->devPrivate.ptr);

  pixmap->devPrivate.ptr = NULL;
}
232

233

234
235
236
237
238
239
240
241
242
243
244
/**
 * Calls uxa_prepare_access with UXA_PREPARE_SRC for the tile, if that is the
 * current fill style.
 *
 * Solid doesn't use an extra pixmap source, so we don't worry about them.
 * Stippled/OpaqueStippled are 1bpp and can be in fb, so we should worry
 * about them.
 */
Bool
glamor_prepare_access_gc(GCPtr gc)
{
245
  if (gc->stipple) {
246
247
    if (!glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RO))
      return FALSE;
248
  }
249
250
251
252
253
254
  if (gc->fillStyle == FillTiled) {
    if (!glamor_prepare_access (&gc->tile.pixmap->drawable,
				GLAMOR_ACCESS_RO)) {
      if (gc->stipple)
	glamor_finish_access(&gc->stipple->drawable);
      return FALSE;
255
    }
256
257
  }
  return TRUE;
258
259
260
261
262
263
264
265
}

/**
 * Finishes access to the tile in the GC, if used.
 */
void
glamor_finish_access_gc(GCPtr gc)
{
266
267
268
269
  if (gc->fillStyle == FillTiled)
    glamor_finish_access(&gc->tile.pixmap->drawable);
  if (gc->stipple)
    glamor_finish_access(&gc->stipple->drawable);
270
}
271

272
Bool
273
274
275
276
277
278
glamor_stipple(PixmapPtr pixmap, PixmapPtr stipple,
	       int x, int y, int width, int height,
	       unsigned char alu, unsigned long planemask,
	       unsigned long fg_pixel, unsigned long bg_pixel,
	       int stipple_x, int stipple_y)
{
279
280
  glamor_fallback("stubbed out stipple depth %d\n", pixmap->drawable.depth);
  return FALSE;
281
282
}

283
GCOps glamor_gc_ops = {
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  .FillSpans = glamor_fill_spans,
  .SetSpans = glamor_set_spans,
  .PutImage = glamor_put_image,
  .CopyArea = glamor_copy_area,
  .CopyPlane = miCopyPlane,
  .PolyPoint = miPolyPoint,
  .Polylines = glamor_poly_lines,
  .PolySegment = miPolySegment,
  .PolyRectangle = miPolyRectangle,
  .PolyArc = miPolyArc,
  .FillPolygon = miFillPolygon,
  .PolyFillRect = glamor_poly_fill_rect,
  .PolyFillArc = miPolyFillArc,
  .PolyText8 = miPolyText8,
  .PolyText16 = miPolyText16,
  .ImageText8 = miImageText8,
  .ImageText16 = miImageText16,
  .ImageGlyphBlt = miImageGlyphBlt,
  .PolyGlyphBlt = miPolyGlyphBlt,
  .PushPixels = miPushPixels,
304
305
306
};

/**
307
 * uxa_validate_gc() sets the ops to glamor's implementations, which may be
308
309
310
311
312
 * accelerated or may sync the card and fall back to fb.
 */
static void
glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
{
313
314
315
316
  /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
   * Preempt fbValidateGC by doing its work and masking the change out, so
   * that we can do the Prepare/finish_access.
   */
317
#ifdef FB_24_32BIT
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  if ((changes & GCTile) && fbGetRotatedPixmap(gc)) {
    gc->pScreen->DestroyPixmap(fbGetRotatedPixmap(gc));
    fbGetRotatedPixmap(gc) = 0;
  }

  if (gc->fillStyle == FillTiled) {
    PixmapPtr old_tile, new_tile;

    old_tile = gc->tile.pixmap;
    if (old_tile->drawable.bitsPerPixel != drawable->bitsPerPixel) {
      new_tile = fbGetRotatedPixmap(gc);
      if (!new_tile ||
	  new_tile ->drawable.bitsPerPixel != drawable->bitsPerPixel)
	{
	  if (new_tile)
	    gc->pScreen->DestroyPixmap(new_tile);
	  /* fb24_32ReformatTile will do direct access of a newly-
	   * allocated pixmap.
	   */
337
338
	  glamor_fallback("GC %p tile FB_24_32 transformat %p.\n", gc, old_tile);

339
340
341
342
343
344
	  if (glamor_prepare_access(&old_tile->drawable,
				    GLAMOR_ACCESS_RO)) {
	    new_tile = fb24_32ReformatTile(old_tile,
					   drawable->bitsPerPixel);
	    glamor_finish_access(&old_tile->drawable);
	  }
345
	}
346
347
348
349
350
      if (new_tile) {
	fbGetRotatedPixmap(gc) = old_tile;
	gc->tile.pixmap = new_tile;
	changes |= GCTile;
      }
351
    }
352
  }
353
#endif
354
  if (changes & GCTile) {
355
356
357
358
359
360
361
362
    if (!gc->tileIsPixel) {
      glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(gc->tile.pixmap);
      if ((!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
         && FbEvenTile(gc->tile.pixmap->drawable.width *
	  			       drawable->bitsPerPixel))
        {
	  glamor_fallback("GC %p tile changed %p.\n", gc, gc->tile.pixmap);
	  if (glamor_prepare_access(&gc->tile.pixmap->drawable,
363
364
365
				  GLAMOR_ACCESS_RW)) {
	  fbPadPixmap(gc->tile.pixmap);
	  glamor_finish_access(&gc->tile.pixmap->drawable);
366
367
368
	  }
        }
    }
369
370
371
372
373
    /* Mask out the GCTile change notification, now that we've done FB's
     * job for it.
     */
    changes &= ~GCTile;
  }
374

375
376
377
378
379
380
381
  if (changes & GCStipple && gc->stipple) {
    /* We can't inline stipple handling like we do for GCTile because
     * it sets fbgc privates.
     */
    if (glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RW)) {
      fbValidateGC(gc, changes, drawable);
      glamor_finish_access(&gc->stipple->drawable);
382
    }
383
384
385
  } else {
    fbValidateGC(gc, changes, drawable);
  }
386

387
  gc->ops = &glamor_gc_ops;
388
389
390
}

static GCFuncs glamor_gc_funcs = {
391
392
393
394
395
396
397
  glamor_validate_gc,
  miChangeGC,
  miCopyGC,
  miDestroyGC,
  miChangeClip,
  miDestroyClip,
  miCopyClip
398
399
400
401
402
403
404
405
406
};

/**
 * exaCreateGC makes a new GC and hooks up its funcs handler, so that
 * exaValidateGC() will get called.
 */
int
glamor_create_gc(GCPtr gc)
{
407
408
  if (!fbCreateGC(gc))
    return FALSE;
409

410
  gc->funcs = &glamor_gc_funcs;
411

412
  return TRUE;
413
}
414
415
416
417
418

RegionPtr
glamor_bitmap_to_region(PixmapPtr pixmap)
{
  RegionPtr ret;
419
  glamor_fallback("pixmap %p \n", pixmap);
420
421
422
423
424
425
  if (!glamor_prepare_access(&pixmap->drawable, GLAMOR_ACCESS_RO))
    return NULL;
  ret = fbPixmapToRegion(pixmap);
  glamor_finish_access(&pixmap->drawable);
  return ret;
}
Zhigang Gong's avatar
Zhigang Gong committed
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

/* Borrow from cairo. */
Bool
glamor_gl_has_extension(char *extension)
{
  const char *gl_extensions;
  char *pext;
  int  ext_len;
  ext_len = strlen(extension);
 
  gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
  pext = (char*)gl_extensions;
 
  if (pext == NULL || extension == NULL)
    return FALSE;

  while((pext = strstr(pext, extension)) != NULL) {
    if (pext[ext_len] == ' ' || pext[ext_len] == '\0')
      return TRUE;
    pext += ext_len;
  }
  return FALSE;
}

int
glamor_gl_get_version (void)
{
    int major, minor;
    const char *version = (const char *) glGetString (GL_VERSION);
    const char *dot = version == NULL ? NULL : strchr (version, '.');
    const char *major_start = dot;

    /* Sanity check */
    if (dot == NULL || dot == version || *(dot + 1) == '\0') {
        major = 0;
        minor = 0;
    } else {
        /* Find the start of the major version in the string */
        while (major_start > version && *major_start != ' ')
            --major_start;
        major = strtol (major_start, NULL, 10);
        minor = strtol (dot + 1, NULL, 10);
    }

    return GLAMOR_GL_VERSION_ENCODE (major, minor);
}