xorg-server-21.1.4/ 0000755 0001750 0001750 00000000000 14263273407 011073 5 0000000 0000000 xorg-server-21.1.4/test-driver 0000755 0001750 0001750 00000011127 14263273355 013215 0000000 0000000 #! /bin/sh
# test-driver - basic testsuite driver script.
scriptversion=2018-03-07.03; # UTC
# Copyright (C) 2011-2020 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to or send patches to
# .
# Make unconditional expansion of undefined variables an error. This
# helps a lot in preventing typo-related bugs.
set -u
usage_error ()
{
echo "$0: $*" >&2
print_usage >&2
exit 2
}
print_usage ()
{
cat <$log_file 2>&1
estatus=$?
if test $enable_hard_errors = no && test $estatus -eq 99; then
tweaked_estatus=1
else
tweaked_estatus=$estatus
fi
case $tweaked_estatus:$expect_failure in
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
0:*) col=$grn res=PASS recheck=no gcopy=no;;
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
esac
# Report the test outcome and exit status in the logs, so that one can
# know whether the test passed or failed simply by looking at the '.log'
# file, without the need of also peaking into the corresponding '.trs'
# file (automake bug#11814).
echo "$res $test_name (exit status: $estatus)" >>$log_file
# Report outcome to console.
echo "${col}${res}${std}: $test_name"
# Register the test result, and other relevant metadata.
echo ":test-result: $res" > $trs_file
echo ":global-test-result: $res" >> $trs_file
echo ":recheck: $recheck" >> $trs_file
echo ":copy-in-global-log: $gcopy" >> $trs_file
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
xorg-server-21.1.4/glamor/ 0000755 0001750 0001750 00000000000 14263273405 012352 5 0000000 0000000 xorg-server-21.1.4/glamor/glamor_transfer.c 0000644 0001750 0001750 00000017060 14263273335 015631 0000000 0000000 /*
* Copyright © 2014 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "glamor_priv.h"
#include "glamor_transfer.h"
/*
* Write a region of bits into a pixmap
*/
void
glamor_upload_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox,
int dx_src, int dy_src,
int dx_dst, int dy_dst,
uint8_t *bits, uint32_t byte_stride)
{
ScreenPtr screen = pixmap->drawable.pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
int box_index;
int bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3;
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
glamor_make_current(glamor_priv);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
if (glamor_priv->has_unpack_subimage)
glPixelStorei(GL_UNPACK_ROW_LENGTH, byte_stride / bytes_per_pixel);
glamor_pixmap_loop(priv, box_index) {
BoxPtr box = glamor_pixmap_box_at(priv, box_index);
glamor_pixmap_fbo *fbo = glamor_pixmap_fbo_at(priv, box_index);
BoxPtr boxes = in_boxes;
int nbox = in_nbox;
glamor_bind_texture(glamor_priv, GL_TEXTURE0, fbo, TRUE);
while (nbox--) {
/* compute drawable coordinates */
int x1 = MAX(boxes->x1 + dx_dst, box->x1);
int x2 = MIN(boxes->x2 + dx_dst, box->x2);
int y1 = MAX(boxes->y1 + dy_dst, box->y1);
int y2 = MIN(boxes->y2 + dy_dst, box->y2);
size_t ofs = (y1 - dy_dst + dy_src) * byte_stride;
ofs += (x1 - dx_dst + dx_src) * bytes_per_pixel;
boxes++;
if (x2 <= x1 || y2 <= y1)
continue;
if (glamor_priv->has_unpack_subimage ||
x2 - x1 == byte_stride / bytes_per_pixel) {
glTexSubImage2D(GL_TEXTURE_2D, 0,
x1 - box->x1, y1 - box->y1,
x2 - x1, y2 - y1,
f->format, f->type,
bits + ofs);
} else {
for (; y1 < y2; y1++, ofs += byte_stride)
glTexSubImage2D(GL_TEXTURE_2D, 0,
x1 - box->x1, y1 - box->y1,
x2 - x1, 1,
f->format, f->type,
bits + ofs);
}
}
}
if (glamor_priv->has_unpack_subimage)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
/*
* Upload a region of data
*/
void
glamor_upload_region(PixmapPtr pixmap, RegionPtr region,
int region_x, int region_y,
uint8_t *bits, uint32_t byte_stride)
{
glamor_upload_boxes(pixmap, RegionRects(region), RegionNumRects(region),
-region_x, -region_y,
0, 0,
bits, byte_stride);
}
/*
* Take the data in the pixmap and stuff it back into the FBO
*/
void
glamor_upload_pixmap(PixmapPtr pixmap)
{
BoxRec box;
box.x1 = 0;
box.x2 = pixmap->drawable.width;
box.y1 = 0;
box.y2 = pixmap->drawable.height;
glamor_upload_boxes(pixmap, &box, 1, 0, 0, 0, 0,
pixmap->devPrivate.ptr, pixmap->devKind);
}
/*
* Read stuff from the pixmap FBOs and write to memory
*/
void
glamor_download_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox,
int dx_src, int dy_src,
int dx_dst, int dy_dst,
uint8_t *bits, uint32_t byte_stride)
{
ScreenPtr screen = pixmap->drawable.pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
int box_index;
int bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3;
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
glamor_make_current(glamor_priv);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
if (glamor_priv->has_pack_subimage)
glPixelStorei(GL_PACK_ROW_LENGTH, byte_stride / bytes_per_pixel);
glamor_pixmap_loop(priv, box_index) {
BoxPtr box = glamor_pixmap_box_at(priv, box_index);
glamor_pixmap_fbo *fbo = glamor_pixmap_fbo_at(priv, box_index);
BoxPtr boxes = in_boxes;
int nbox = in_nbox;
/* This should not be called on GLAMOR_FBO_NO_FBO-allocated pixmaps. */
assert(fbo->fb);
glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
while (nbox--) {
/* compute drawable coordinates */
int x1 = MAX(boxes->x1 + dx_src, box->x1);
int x2 = MIN(boxes->x2 + dx_src, box->x2);
int y1 = MAX(boxes->y1 + dy_src, box->y1);
int y2 = MIN(boxes->y2 + dy_src, box->y2);
size_t ofs = (y1 - dy_src + dy_dst) * byte_stride;
ofs += (x1 - dx_src + dx_dst) * bytes_per_pixel;
boxes++;
if (x2 <= x1 || y2 <= y1)
continue;
if (glamor_priv->has_pack_subimage ||
x2 - x1 == byte_stride / bytes_per_pixel) {
glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, y2 - y1, f->format, f->type, bits + ofs);
} else {
for (; y1 < y2; y1++, ofs += byte_stride)
glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, 1, f->format, f->type, bits + ofs);
}
}
}
if (glamor_priv->has_pack_subimage)
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
}
/*
* Read data from the pixmap FBO
*/
void
glamor_download_rect(PixmapPtr pixmap, int x, int y, int w, int h, uint8_t *bits)
{
BoxRec box;
box.x1 = x;
box.x2 = x + w;
box.y1 = y;
box.y2 = y + h;
glamor_download_boxes(pixmap, &box, 1, 0, 0, -x, -y,
bits, PixmapBytePad(w, pixmap->drawable.depth));
}
/*
* Pull the data from the FBO down to the pixmap
*/
void
glamor_download_pixmap(PixmapPtr pixmap)
{
BoxRec box;
box.x1 = 0;
box.x2 = pixmap->drawable.width;
box.y1 = 0;
box.y2 = pixmap->drawable.height;
glamor_download_boxes(pixmap, &box, 1, 0, 0, 0, 0,
pixmap->devPrivate.ptr, pixmap->devKind);
}
xorg-server-21.1.4/glamor/glamor_render.c 0000644 0001750 0001750 00000176633 14263273335 015300 0000000 0000000 /*
* 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
* Zhigang Gong
* Junyan He
*
*/
/** @file glamor_render.c
*
* Render acceleration implementation
*/
#include "glamor_priv.h"
#include "mipict.h"
#include "fbpict.h"
#if 0
//#define DEBUGF(str, ...) do {} while(0)
#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
//#define DEBUGRegionPrint(x) do {} while (0)
#define DEBUGRegionPrint RegionPrint
#endif
static struct blendinfo composite_op_info[] = {
[PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
[PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
[PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
[PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
[PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
[PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
[PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
[PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
[PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
[PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
[PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
[PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
[PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
};
#define RepeatFix 10
static GLuint
glamor_create_composite_fs(struct shader_key *key)
{
const char *repeat_define =
"#define RepeatNone 0\n"
"#define RepeatNormal 1\n"
"#define RepeatPad 2\n"
"#define RepeatReflect 3\n"
"#define RepeatFix 10\n"
"uniform int source_repeat_mode;\n"
"uniform int mask_repeat_mode;\n";
const char *relocate_texture =
"vec2 rel_tex_coord(vec2 texture, vec4 wh, int repeat) \n"
"{\n"
" vec2 rel_tex; \n"
" rel_tex = texture * wh.xy; \n"
" if (repeat == RepeatFix + RepeatNone)\n"
" return rel_tex; \n"
" else if (repeat == RepeatFix + RepeatNormal) \n"
" rel_tex = floor(rel_tex) + (fract(rel_tex) / wh.xy); \n"
" else if (repeat == RepeatFix + RepeatPad) { \n"
" if (rel_tex.x >= 1.0) \n"
" rel_tex.x = 1.0 - wh.z * wh.x / 2.; \n"
" else if (rel_tex.x < 0.0) \n"
" rel_tex.x = 0.0; \n"
" if (rel_tex.y >= 1.0) \n"
" rel_tex.y = 1.0 - wh.w * wh.y / 2.; \n"
" else if (rel_tex.y < 0.0) \n"
" rel_tex.y = 0.0; \n"
" rel_tex = rel_tex / wh.xy; \n"
" } else if (repeat == RepeatFix + RepeatReflect) {\n"
" if ((1.0 - mod(abs(floor(rel_tex.x)), 2.0)) < 0.001)\n"
" rel_tex.x = 2.0 - (1.0 - fract(rel_tex.x)) / wh.x;\n"
" else \n"
" rel_tex.x = fract(rel_tex.x) / wh.x;\n"
" if ((1.0 - mod(abs(floor(rel_tex.y)), 2.0)) < 0.001)\n"
" rel_tex.y = 2.0 - (1.0 - fract(rel_tex.y)) / wh.y;\n"
" else \n"
" rel_tex.y = fract(rel_tex.y) / wh.y;\n"
" } \n"
" return rel_tex; \n"
"}\n";
/* The texture and the pixmap size is not match eaxctly, so can't sample it directly.
* rel_sampler will recalculate the texture coords.*/
const char *rel_sampler =
" vec4 rel_sampler_rgba(sampler2D tex_image, vec2 tex, vec4 wh, int repeat)\n"
"{\n"
" if (repeat >= RepeatFix) {\n"
" tex = rel_tex_coord(tex, wh, repeat);\n"
" if (repeat == RepeatFix + RepeatNone) {\n"
" if (tex.x < 0.0 || tex.x >= 1.0 || \n"
" tex.y < 0.0 || tex.y >= 1.0)\n"
" return vec4(0.0, 0.0, 0.0, 0.0);\n"
" tex = (fract(tex) / wh.xy);\n"
" }\n"
" }\n"
" return texture2D(tex_image, tex);\n"
"}\n"
" vec4 rel_sampler_rgbx(sampler2D tex_image, vec2 tex, vec4 wh, int repeat)\n"
"{\n"
" if (repeat >= RepeatFix) {\n"
" tex = rel_tex_coord(tex, wh, repeat);\n"
" if (repeat == RepeatFix + RepeatNone) {\n"
" if (tex.x < 0.0 || tex.x >= 1.0 || \n"
" tex.y < 0.0 || tex.y >= 1.0)\n"
" return vec4(0.0, 0.0, 0.0, 0.0);\n"
" tex = (fract(tex) / wh.xy);\n"
" }\n"
" }\n"
" return vec4(texture2D(tex_image, tex).rgb, 1.0);\n"
"}\n";
const char *source_solid_fetch =
"uniform vec4 source;\n"
"vec4 get_source()\n"
"{\n"
" return source;\n"
"}\n";
const char *source_alpha_pixmap_fetch =
"varying vec2 source_texture;\n"
"uniform sampler2D source_sampler;\n"
"uniform vec4 source_wh;"
"vec4 get_source()\n"
"{\n"
" return rel_sampler_rgba(source_sampler, source_texture,\n"
" source_wh, source_repeat_mode);\n"
"}\n";
const char *source_pixmap_fetch =
"varying vec2 source_texture;\n"
"uniform sampler2D source_sampler;\n"
"uniform vec4 source_wh;\n"
"vec4 get_source()\n"
"{\n"
" return rel_sampler_rgbx(source_sampler, source_texture,\n"
" source_wh, source_repeat_mode);\n"
"}\n";
const char *mask_none =
"vec4 get_mask()\n"
"{\n"
" return vec4(0.0, 0.0, 0.0, 1.0);\n"
"}\n";
const char *mask_solid_fetch =
"uniform vec4 mask;\n"
"vec4 get_mask()\n"
"{\n"
" return mask;\n"
"}\n";
const char *mask_alpha_pixmap_fetch =
"varying vec2 mask_texture;\n"
"uniform sampler2D mask_sampler;\n"
"uniform vec4 mask_wh;\n"
"vec4 get_mask()\n"
"{\n"
" return rel_sampler_rgba(mask_sampler, mask_texture,\n"
" mask_wh, mask_repeat_mode);\n"
"}\n";
const char *mask_pixmap_fetch =
"varying vec2 mask_texture;\n"
"uniform sampler2D mask_sampler;\n"
"uniform vec4 mask_wh;\n"
"vec4 get_mask()\n"
"{\n"
" return rel_sampler_rgbx(mask_sampler, mask_texture,\n"
" mask_wh, mask_repeat_mode);\n"
"}\n";
const char *dest_swizzle_default =
"vec4 dest_swizzle(vec4 color)\n"
"{"
" return color;"
"}";
const char *dest_swizzle_alpha_to_red =
"vec4 dest_swizzle(vec4 color)\n"
"{"
" float undef;\n"
" return vec4(color.a, undef, undef, undef);"
"}";
const char *in_normal =
"void main()\n"
"{\n"
" gl_FragColor = dest_swizzle(get_source() * get_mask().a);\n"
"}\n";
const char *in_ca_source =
"void main()\n"
"{\n"
" gl_FragColor = dest_swizzle(get_source() * get_mask());\n"
"}\n";
const char *in_ca_alpha =
"void main()\n"
"{\n"
" gl_FragColor = dest_swizzle(get_source().a * get_mask());\n"
"}\n";
const char *in_ca_dual_blend =
"out vec4 color0;\n"
"out vec4 color1;\n"
"void main()\n"
"{\n"
" color0 = dest_swizzle(get_source() * get_mask());\n"
" color1 = dest_swizzle(get_source().a * get_mask());\n"
"}\n";
const char *header_ca_dual_blend =
"#version 130\n";
char *source;
const char *source_fetch;
const char *mask_fetch = "";
const char *in;
const char *header;
const char *header_norm = "";
const char *dest_swizzle;
GLuint prog;
switch (key->source) {
case SHADER_SOURCE_SOLID:
source_fetch = source_solid_fetch;
break;
case SHADER_SOURCE_TEXTURE_ALPHA:
source_fetch = source_alpha_pixmap_fetch;
break;
case SHADER_SOURCE_TEXTURE:
source_fetch = source_pixmap_fetch;
break;
default:
FatalError("Bad composite shader source");
}
switch (key->mask) {
case SHADER_MASK_NONE:
mask_fetch = mask_none;
break;
case SHADER_MASK_SOLID:
mask_fetch = mask_solid_fetch;
break;
case SHADER_MASK_TEXTURE_ALPHA:
mask_fetch = mask_alpha_pixmap_fetch;
break;
case SHADER_MASK_TEXTURE:
mask_fetch = mask_pixmap_fetch;
break;
default:
FatalError("Bad composite shader mask");
}
/* If we're storing to an a8 texture but our texture format is
* GL_RED because of a core context, then we need to make sure to
* put the alpha into the red channel.
*/
switch (key->dest_swizzle) {
case SHADER_DEST_SWIZZLE_DEFAULT:
dest_swizzle = dest_swizzle_default;
break;
case SHADER_DEST_SWIZZLE_ALPHA_TO_RED:
dest_swizzle = dest_swizzle_alpha_to_red;
break;
default:
FatalError("Bad composite shader dest swizzle");
}
header = header_norm;
switch (key->in) {
case glamor_program_alpha_normal:
in = in_normal;
break;
case glamor_program_alpha_ca_first:
in = in_ca_source;
break;
case glamor_program_alpha_ca_second:
in = in_ca_alpha;
break;
case glamor_program_alpha_dual_blend:
in = in_ca_dual_blend;
header = header_ca_dual_blend;
break;
default:
FatalError("Bad composite IN type");
}
XNFasprintf(&source,
"%s"
GLAMOR_DEFAULT_PRECISION
"%s%s%s%s%s%s%s", header, repeat_define, relocate_texture,
rel_sampler, source_fetch, mask_fetch, dest_swizzle, in);
prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, source);
free(source);
return prog;
}
static GLuint
glamor_create_composite_vs(struct shader_key *key)
{
const char *main_opening =
"attribute vec4 v_position;\n"
"attribute vec4 v_texcoord0;\n"
"attribute vec4 v_texcoord1;\n"
"varying vec2 source_texture;\n"
"varying vec2 mask_texture;\n"
"void main()\n"
"{\n"
" gl_Position = v_position;\n";
const char *source_coords = " source_texture = v_texcoord0.xy;\n";
const char *mask_coords = " mask_texture = v_texcoord1.xy;\n";
const char *main_closing = "}\n";
const char *source_coords_setup = "";
const char *mask_coords_setup = "";
char *source;
GLuint prog;
if (key->source != SHADER_SOURCE_SOLID)
source_coords_setup = source_coords;
if (key->mask != SHADER_MASK_NONE && key->mask != SHADER_MASK_SOLID)
mask_coords_setup = mask_coords;
XNFasprintf(&source,
"%s%s%s%s",
main_opening,
source_coords_setup, mask_coords_setup, main_closing);
prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, source);
free(source);
return prog;
}
static void
glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key,
glamor_composite_shader *shader)
{
GLuint vs, fs, prog;
GLint source_sampler_uniform_location, mask_sampler_uniform_location;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_make_current(glamor_priv);
vs = glamor_create_composite_vs(key);
if (vs == 0)
return;
fs = glamor_create_composite_fs(key);
if (fs == 0)
return;
prog = glCreateProgram();
glAttachShader(prog, vs);
glAttachShader(prog, fs);
glBindAttribLocation(prog, GLAMOR_VERTEX_POS, "v_position");
glBindAttribLocation(prog, GLAMOR_VERTEX_SOURCE, "v_texcoord0");
glBindAttribLocation(prog, GLAMOR_VERTEX_MASK, "v_texcoord1");
if (key->in == glamor_program_alpha_dual_blend) {
glBindFragDataLocationIndexed(prog, 0, 0, "color0");
glBindFragDataLocationIndexed(prog, 0, 1, "color1");
}
glamor_link_glsl_prog(screen, prog, "composite");
shader->prog = prog;
glUseProgram(prog);
if (key->source == SHADER_SOURCE_SOLID) {
shader->source_uniform_location = glGetUniformLocation(prog, "source");
}
else {
source_sampler_uniform_location =
glGetUniformLocation(prog, "source_sampler");
glUniform1i(source_sampler_uniform_location, 0);
shader->source_wh = glGetUniformLocation(prog, "source_wh");
shader->source_repeat_mode =
glGetUniformLocation(prog, "source_repeat_mode");
}
if (key->mask != SHADER_MASK_NONE) {
if (key->mask == SHADER_MASK_SOLID) {
shader->mask_uniform_location = glGetUniformLocation(prog, "mask");
}
else {
mask_sampler_uniform_location =
glGetUniformLocation(prog, "mask_sampler");
glUniform1i(mask_sampler_uniform_location, 1);
shader->mask_wh = glGetUniformLocation(prog, "mask_wh");
shader->mask_repeat_mode =
glGetUniformLocation(prog, "mask_repeat_mode");
}
}
}
static glamor_composite_shader *
glamor_lookup_composite_shader(ScreenPtr screen, struct
shader_key
*key)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_composite_shader *shader;
shader = &glamor_priv->composite_shader[key->source][key->mask][key->in][key->dest_swizzle];
if (shader->prog == 0)
glamor_create_composite_shader(screen, key, shader);
return shader;
}
static GLenum
glamor_translate_blend_alpha_to_red(GLenum blend)
{
switch (blend) {
case GL_SRC_ALPHA:
return GL_SRC_COLOR;
case GL_DST_ALPHA:
return GL_DST_COLOR;
case GL_ONE_MINUS_SRC_ALPHA:
return GL_ONE_MINUS_SRC_COLOR;
case GL_ONE_MINUS_DST_ALPHA:
return GL_ONE_MINUS_DST_COLOR;
default:
return blend;
}
}
static Bool
glamor_set_composite_op(ScreenPtr screen,
CARD8 op, struct blendinfo *op_info_result,
PicturePtr dest, PicturePtr mask,
enum ca_state ca_state,
struct shader_key *key)
{
GLenum source_blend, dest_blend;
struct blendinfo *op_info;
if (op >= ARRAY_SIZE(composite_op_info)) {
glamor_fallback("unsupported render op %d \n", op);
return GL_FALSE;
}
op_info = &composite_op_info[op];
source_blend = op_info->source_blend;
dest_blend = op_info->dest_blend;
/* If there's no dst alpha channel, adjust the blend op so that we'll treat
* it as always 1.
*/
if (PICT_FORMAT_A(dest->format) == 0 && op_info->dest_alpha) {
if (source_blend == GL_DST_ALPHA)
source_blend = GL_ONE;
else if (source_blend == GL_ONE_MINUS_DST_ALPHA)
source_blend = GL_ZERO;
}
/* Set up the source alpha value for blending in component alpha mode. */
if (ca_state == CA_DUAL_BLEND) {
switch (dest_blend) {
case GL_SRC_ALPHA:
dest_blend = GL_SRC1_COLOR;
break;
case GL_ONE_MINUS_SRC_ALPHA:
dest_blend = GL_ONE_MINUS_SRC1_COLOR;
break;
}
} else if (mask && mask->componentAlpha
&& PICT_FORMAT_RGB(mask->format) != 0 && op_info->source_alpha) {
switch (dest_blend) {
case GL_SRC_ALPHA:
dest_blend = GL_SRC_COLOR;
break;
case GL_ONE_MINUS_SRC_ALPHA:
dest_blend = GL_ONE_MINUS_SRC_COLOR;
break;
}
}
/* If we're outputting our alpha to the red channel, then any
* reads of alpha for blending need to come from the red channel.
*/
if (key->dest_swizzle == SHADER_DEST_SWIZZLE_ALPHA_TO_RED) {
source_blend = glamor_translate_blend_alpha_to_red(source_blend);
dest_blend = glamor_translate_blend_alpha_to_red(dest_blend);
}
op_info_result->source_blend = source_blend;
op_info_result->dest_blend = dest_blend;
op_info_result->source_alpha = op_info->source_alpha;
op_info_result->dest_alpha = op_info->dest_alpha;
return TRUE;
}
static void
glamor_set_composite_texture(glamor_screen_private *glamor_priv, int unit,
PicturePtr picture,
PixmapPtr pixmap,
GLuint wh_location, GLuint repeat_location,
glamor_pixmap_private *dest_priv)
{
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
glamor_pixmap_fbo *fbo = pixmap_priv->fbo;
float wh[4];
int repeat_type;
glamor_make_current(glamor_priv);
/* The red channel swizzling doesn't depend on whether we're using
* 'fbo' as source or mask as we must have the same answer in case
* the same fbo is being used for both. That means the mask
* channel will sometimes get red bits in the R channel, and
* sometimes get zero bits in the R channel, which is harmless.
*/
glamor_bind_texture(glamor_priv, GL_TEXTURE0 + unit, fbo,
dest_priv->fbo->is_red);
repeat_type = picture->repeatType;
switch (picture->repeatType) {
case RepeatNone:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
break;
case RepeatNormal:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
break;
case RepeatPad:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
break;
case RepeatReflect:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
break;
}
switch (picture->filter) {
default:
case PictFilterFast:
case PictFilterNearest:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case PictFilterGood:
case PictFilterBest:
case PictFilterBilinear:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
}
/* Handle RepeatNone in the shader when the source is missing the
* alpha channel, as GL will return an alpha for 1 if the texture
* is RGB (no alpha), which we use for 16bpp textures.
*/
if (glamor_pixmap_priv_is_large(pixmap_priv) ||
(!PICT_FORMAT_A(picture->format) &&
repeat_type == RepeatNone && picture->transform)) {
glamor_pixmap_fbo_fix_wh_ratio(wh, pixmap, pixmap_priv);
glUniform4fv(wh_location, 1, wh);
repeat_type += RepeatFix;
}
glUniform1i(repeat_location, repeat_type);
}
static void
glamor_set_composite_solid(float *color, GLint uniform_location)
{
glUniform4fv(uniform_location, 1, color);
}
static char
glamor_get_picture_location(PicturePtr picture)
{
if (picture == NULL)
return ' ';
if (picture->pDrawable == NULL) {
switch (picture->pSourcePict->type) {
case SourcePictTypeSolidFill:
return 'c';
case SourcePictTypeLinear:
return 'l';
case SourcePictTypeRadial:
return 'r';
default:
return '?';
}
}
return glamor_get_drawable_location(picture->pDrawable);
}
static void *
glamor_setup_composite_vbo(ScreenPtr screen, int n_verts)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
int vert_size;
char *vbo_offset;
float *vb;
glamor_priv->render_nr_quads = 0;
glamor_priv->vb_stride = 2 * sizeof(float);
if (glamor_priv->has_source_coords)
glamor_priv->vb_stride += 2 * sizeof(float);
if (glamor_priv->has_mask_coords)
glamor_priv->vb_stride += 2 * sizeof(float);
vert_size = n_verts * glamor_priv->vb_stride;
glamor_make_current(glamor_priv);
vb = glamor_get_vbo_space(screen, vert_size, &vbo_offset);
glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE,
glamor_priv->vb_stride, vbo_offset);
glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
if (glamor_priv->has_source_coords) {
glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
GL_FLOAT, GL_FALSE,
glamor_priv->vb_stride,
vbo_offset + 2 * sizeof(float));
glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
}
if (glamor_priv->has_mask_coords) {
glVertexAttribPointer(GLAMOR_VERTEX_MASK, 2, GL_FLOAT, GL_FALSE,
glamor_priv->vb_stride,
vbo_offset + (glamor_priv->has_source_coords ?
4 : 2) * sizeof(float));
glEnableVertexAttribArray(GLAMOR_VERTEX_MASK);
}
return vb;
}
static void
glamor_flush_composite_rects(ScreenPtr screen)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_make_current(glamor_priv);
if (!glamor_priv->render_nr_quads)
return;
glamor_glDrawArrays_GL_QUADS(glamor_priv, glamor_priv->render_nr_quads);
}
static const int pict_format_combine_tab[][3] = {
{PICT_TYPE_ARGB, PICT_TYPE_A, PICT_TYPE_ARGB},
{PICT_TYPE_ABGR, PICT_TYPE_A, PICT_TYPE_ABGR},
};
static Bool
combine_pict_format(PictFormatShort * des, const PictFormatShort src,
const PictFormatShort mask, glamor_program_alpha in_ca)
{
PictFormatShort new_vis;
int src_type, mask_type, src_bpp;
int i;
if (src == mask) {
*des = src;
return TRUE;
}
src_bpp = PICT_FORMAT_BPP(src);
assert(src_bpp == PICT_FORMAT_BPP(mask));
new_vis = PICT_FORMAT_VIS(src) | PICT_FORMAT_VIS(mask);
switch (in_ca) {
case glamor_program_alpha_normal:
src_type = PICT_FORMAT_TYPE(src);
mask_type = PICT_TYPE_A;
break;
case glamor_program_alpha_ca_first:
src_type = PICT_FORMAT_TYPE(src);
mask_type = PICT_FORMAT_TYPE(mask);
break;
case glamor_program_alpha_ca_second:
src_type = PICT_TYPE_A;
mask_type = PICT_FORMAT_TYPE(mask);
break;
case glamor_program_alpha_dual_blend:
src_type = PICT_FORMAT_TYPE(src);
mask_type = PICT_FORMAT_TYPE(mask);
break;
default:
return FALSE;
}
if (src_type == mask_type) {
*des = PICT_VISFORMAT(src_bpp, src_type, new_vis);
return TRUE;
}
for (i = 0; i < ARRAY_SIZE(pict_format_combine_tab); i++) {
if ((src_type == pict_format_combine_tab[i][0]
&& mask_type == pict_format_combine_tab[i][1])
|| (src_type == pict_format_combine_tab[i][1]
&& mask_type == pict_format_combine_tab[i][0])) {
*des = PICT_VISFORMAT(src_bpp, pict_format_combine_tab[i]
[2], new_vis);
return TRUE;
}
}
return FALSE;
}
static void
glamor_set_normalize_tcoords_generic(PixmapPtr pixmap,
glamor_pixmap_private *priv,
int repeat_type,
float *matrix,
float xscale, float yscale,
int x1, int y1, int x2, int y2,
float *texcoords,
int stride)
{
if (!matrix && repeat_type == RepeatNone)
glamor_set_normalize_tcoords_ext(priv, xscale, yscale,
x1, y1,
x2, y2, texcoords, stride);
else if (matrix && repeat_type == RepeatNone)
glamor_set_transformed_normalize_tcoords_ext(priv, matrix, xscale,
yscale, x1, y1,
x2, y2,
texcoords, stride);
else if (!matrix && repeat_type != RepeatNone)
glamor_set_repeat_normalize_tcoords_ext(pixmap, priv, repeat_type,
xscale, yscale,
x1, y1,
x2, y2,
texcoords, stride);
else if (matrix && repeat_type != RepeatNone)
glamor_set_repeat_transformed_normalize_tcoords_ext(pixmap, priv, repeat_type,
matrix, xscale,
yscale, x1, y1, x2,
y2,
texcoords, stride);
}
/**
* Returns whether the general composite path supports this picture
* format for a pixmap that is permanently stored in an FBO (as
* opposed to the dynamic upload path).
*
* We could support many more formats by using GL_ARB_texture_view to
* parse the same bits as different formats. For now, we only support
* tweaking whether we sample the alpha bits, or just force them to 1.
*/
static Bool
glamor_render_format_is_supported(PicturePtr picture)
{
PictFormatShort storage_format;
glamor_screen_private *glamor_priv;
struct glamor_format *f;
/* Source-only pictures should always work */
if (!picture->pDrawable)
return TRUE;
glamor_priv = glamor_get_screen_private(picture->pDrawable->pScreen);
f = &glamor_priv->formats[picture->pDrawable->depth];
if (!f->rendering_supported)
return FALSE;
storage_format = f->render_format;
switch (picture->format) {
case PICT_a2r10g10b10:
return storage_format == PICT_x2r10g10b10;
case PICT_a8r8g8b8:
case PICT_x8r8g8b8:
return storage_format == PICT_a8r8g8b8 || storage_format == PICT_x8r8g8b8;
case PICT_a1r5g5b5:
return storage_format == PICT_x1r5g5b5;
default:
return picture->format == storage_format;
}
}
static Bool
glamor_composite_choose_shader(CARD8 op,
PicturePtr source,
PicturePtr mask,
PicturePtr dest,
PixmapPtr source_pixmap,
PixmapPtr mask_pixmap,
PixmapPtr dest_pixmap,
glamor_pixmap_private *source_pixmap_priv,
glamor_pixmap_private *mask_pixmap_priv,
glamor_pixmap_private *dest_pixmap_priv,
struct shader_key *s_key,
glamor_composite_shader ** shader,
struct blendinfo *op_info,
PictFormatShort *psaved_source_format,
enum ca_state ca_state)
{
ScreenPtr screen = dest->pDrawable->pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
Bool source_needs_upload = FALSE;
Bool mask_needs_upload = FALSE;
PictFormatShort saved_source_format = 0;
struct shader_key key;
GLfloat source_solid_color[4];
GLfloat mask_solid_color[4];
Bool ret = FALSE;
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
glamor_fallback("dest has no fbo.\n");
goto fail;
}
if (!glamor_render_format_is_supported(dest)) {
glamor_fallback("Unsupported dest picture format.\n");
goto fail;
}
memset(&key, 0, sizeof(key));
if (!source) {
key.source = SHADER_SOURCE_SOLID;
source_solid_color[0] = 0.0;
source_solid_color[1] = 0.0;
source_solid_color[2] = 0.0;
source_solid_color[3] = 0.0;
}
else if (!source->pDrawable) {
SourcePictPtr sp = source->pSourcePict;
if (sp->type == SourcePictTypeSolidFill) {
key.source = SHADER_SOURCE_SOLID;
glamor_get_rgba_from_color(&sp->solidFill.fullcolor,
source_solid_color);
}
else
goto fail;
}
else {
if (PICT_FORMAT_A(source->format))
key.source = SHADER_SOURCE_TEXTURE_ALPHA;
else
key.source = SHADER_SOURCE_TEXTURE;
}
if (mask) {
if (!mask->pDrawable) {
SourcePictPtr sp = mask->pSourcePict;
if (sp->type == SourcePictTypeSolidFill) {
key.mask = SHADER_MASK_SOLID;
glamor_get_rgba_from_color(&sp->solidFill.fullcolor,
mask_solid_color);
}
else
goto fail;
}
else {
if (PICT_FORMAT_A(mask->format))
key.mask = SHADER_MASK_TEXTURE_ALPHA;
else
key.mask = SHADER_MASK_TEXTURE;
}
if (!mask->componentAlpha) {
key.in = glamor_program_alpha_normal;
}
else {
if (op == PictOpClear)
key.mask = SHADER_MASK_NONE;
else if (glamor_priv->has_dual_blend)
key.in = glamor_program_alpha_dual_blend;
else if (op == PictOpSrc || op == PictOpAdd
|| op == PictOpIn || op == PictOpOut
|| op == PictOpOverReverse)
key.in = glamor_program_alpha_ca_second;
else if (op == PictOpOutReverse || op == PictOpInReverse) {
key.in = glamor_program_alpha_ca_first;
}
else {
glamor_fallback("Unsupported component alpha op: %d\n", op);
goto fail;
}
}
}
else {
key.mask = SHADER_MASK_NONE;
}
if (dest_pixmap->drawable.bitsPerPixel <= 8 &&
glamor_priv->formats[8].format == GL_RED) {
key.dest_swizzle = SHADER_DEST_SWIZZLE_ALPHA_TO_RED;
} else {
key.dest_swizzle = SHADER_DEST_SWIZZLE_DEFAULT;
}
if (source && source->alphaMap) {
glamor_fallback("source alphaMap\n");
goto fail;
}
if (mask && mask->alphaMap) {
glamor_fallback("mask alphaMap\n");
goto fail;
}
if (key.source == SHADER_SOURCE_TEXTURE ||
key.source == SHADER_SOURCE_TEXTURE_ALPHA) {
if (source_pixmap == dest_pixmap) {
/* XXX source and the dest share the same texture.
* Does it need special handle? */
glamor_fallback("source == dest\n");
}
if (source_pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED) {
source_needs_upload = TRUE;
}
}
if (key.mask == SHADER_MASK_TEXTURE ||
key.mask == SHADER_MASK_TEXTURE_ALPHA) {
if (mask_pixmap == dest_pixmap) {
glamor_fallback("mask == dest\n");
goto fail;
}
if (mask_pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED) {
mask_needs_upload = TRUE;
}
}
if (source_needs_upload && mask_needs_upload
&& source_pixmap == mask_pixmap) {
if (source->format != mask->format) {
saved_source_format = source->format;
if (!combine_pict_format(&source->format, source->format,
mask->format, key.in)) {
glamor_fallback("combine source %x mask %x failed.\n",
source->format, mask->format);
goto fail;
}
/* XXX
* By default, glamor_upload_picture_to_texture will wire alpha to 1
* if one picture doesn't have alpha. So we don't do that again in
* rendering function. But here is a special case, as source and
* mask share the same texture but may have different formats. For
* example, source doesn't have alpha, but mask has alpha. Then the
* texture will have the alpha value for the mask. And will not wire
* to 1 for the source. In this case, we have to use different shader
* to wire the source's alpha to 1.
*
* But this may cause a potential problem if the source's repeat mode
* is REPEAT_NONE, and if the source is smaller than the dest, then
* for the region not covered by the source may be painted incorrectly.
* because we wire the alpha to 1.
*
**/
if (!PICT_FORMAT_A(saved_source_format)
&& PICT_FORMAT_A(mask->format))
key.source = SHADER_SOURCE_TEXTURE;
if (!PICT_FORMAT_A(mask->format)
&& PICT_FORMAT_A(saved_source_format))
key.mask = SHADER_MASK_TEXTURE;
}
if (!glamor_upload_picture_to_texture(source)) {
glamor_fallback("Failed to upload source texture.\n");
goto fail;
}
mask_needs_upload = FALSE;
}
else {
if (source_needs_upload) {
if (!glamor_upload_picture_to_texture(source)) {
glamor_fallback("Failed to upload source texture.\n");
goto fail;
}
} else {
if (source && !glamor_render_format_is_supported(source)) {
glamor_fallback("Unsupported source picture format.\n");
goto fail;
}
}
if (mask_needs_upload) {
if (!glamor_upload_picture_to_texture(mask)) {
glamor_fallback("Failed to upload mask texture.\n");
goto fail;
}
} else if (mask) {
if (!glamor_render_format_is_supported(mask)) {
glamor_fallback("Unsupported mask picture format.\n");
goto fail;
}
}
}
/* If the source and mask are two differently-formatted views of
* the same pixmap bits, and the pixmap was already uploaded (so
* the dynamic code above doesn't apply), then fall back to
* software. We should use texture views to fix this properly.
*/
if (source_pixmap && source_pixmap == mask_pixmap &&
source->format != mask->format) {
goto fail;
}
if (!glamor_set_composite_op(screen, op, op_info, dest, mask, ca_state,
&key)) {
goto fail;
}
*shader = glamor_lookup_composite_shader(screen, &key);
if ((*shader)->prog == 0) {
glamor_fallback("no shader program for this render acccel mode\n");
goto fail;
}
if (key.source == SHADER_SOURCE_SOLID)
memcpy(&(*shader)->source_solid_color[0],
source_solid_color, 4 * sizeof(float));
else {
(*shader)->source_pixmap = source_pixmap;
(*shader)->source = source;
}
if (key.mask == SHADER_MASK_SOLID)
memcpy(&(*shader)->mask_solid_color[0],
mask_solid_color, 4 * sizeof(float));
else {
(*shader)->mask_pixmap = mask_pixmap;
(*shader)->mask = mask;
}
ret = TRUE;
memcpy(s_key, &key, sizeof(key));
*psaved_source_format = saved_source_format;
goto done;
fail:
if (saved_source_format)
source->format = saved_source_format;
done:
return ret;
}
static void
glamor_composite_set_shader_blend(glamor_screen_private *glamor_priv,
glamor_pixmap_private *dest_priv,
struct shader_key *key,
glamor_composite_shader *shader,
struct blendinfo *op_info)
{
glamor_make_current(glamor_priv);
glUseProgram(shader->prog);
if (key->source == SHADER_SOURCE_SOLID) {
glamor_set_composite_solid(shader->source_solid_color,
shader->source_uniform_location);
}
else {
glamor_set_composite_texture(glamor_priv, 0,
shader->source,
shader->source_pixmap, shader->source_wh,
shader->source_repeat_mode,
dest_priv);
}
if (key->mask != SHADER_MASK_NONE) {
if (key->mask == SHADER_MASK_SOLID) {
glamor_set_composite_solid(shader->mask_solid_color,
shader->mask_uniform_location);
}
else {
glamor_set_composite_texture(glamor_priv, 1,
shader->mask,
shader->mask_pixmap, shader->mask_wh,
shader->mask_repeat_mode,
dest_priv);
}
}
if (!glamor_priv->is_gles)
glDisable(GL_COLOR_LOGIC_OP);
if (op_info->source_blend == GL_ONE && op_info->dest_blend == GL_ZERO) {
glDisable(GL_BLEND);
}
else {
glEnable(GL_BLEND);
glBlendFunc(op_info->source_blend, op_info->dest_blend);
}
}
static Bool
glamor_composite_with_shader(CARD8 op,
PicturePtr source,
PicturePtr mask,
PicturePtr dest,
PixmapPtr source_pixmap,
PixmapPtr mask_pixmap,
PixmapPtr dest_pixmap,
glamor_pixmap_private *source_pixmap_priv,
glamor_pixmap_private *mask_pixmap_priv,
glamor_pixmap_private *dest_pixmap_priv,
int nrect, glamor_composite_rect_t *rects,
enum ca_state ca_state)
{
ScreenPtr screen = dest->pDrawable->pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
GLfloat dst_xscale, dst_yscale;
GLfloat mask_xscale = 1, mask_yscale = 1, src_xscale = 1, src_yscale = 1;
struct shader_key key, key_ca;
int dest_x_off, dest_y_off;
int source_x_off, source_y_off;
int mask_x_off, mask_y_off;
PictFormatShort saved_source_format = 0;
float src_matrix[9], mask_matrix[9];
float *psrc_matrix = NULL, *pmask_matrix = NULL;
int nrect_max;
Bool ret = FALSE;
glamor_composite_shader *shader = NULL, *shader_ca = NULL;
struct blendinfo op_info, op_info_ca;
if (!glamor_composite_choose_shader(op, source, mask, dest,
source_pixmap, mask_pixmap, dest_pixmap,
source_pixmap_priv, mask_pixmap_priv,
dest_pixmap_priv,
&key, &shader, &op_info,
&saved_source_format, ca_state)) {
glamor_fallback("glamor_composite_choose_shader failed\n");
goto fail;
}
if (ca_state == CA_TWO_PASS) {
if (!glamor_composite_choose_shader(PictOpAdd, source, mask, dest,
source_pixmap, mask_pixmap, dest_pixmap,
source_pixmap_priv,
mask_pixmap_priv, dest_pixmap_priv,
&key_ca, &shader_ca, &op_info_ca,
&saved_source_format, ca_state)) {
glamor_fallback("glamor_composite_choose_shader failed\n");
goto fail;
}
}
glamor_make_current(glamor_priv);
glamor_set_destination_pixmap_priv_nc(glamor_priv, dest_pixmap, dest_pixmap_priv);
glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, &key, shader, &op_info);
glamor_set_alu(screen, GXcopy);
glamor_priv->has_source_coords = key.source != SHADER_SOURCE_SOLID;
glamor_priv->has_mask_coords = (key.mask != SHADER_MASK_NONE &&
key.mask != SHADER_MASK_SOLID);
dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable);
dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
glamor_get_drawable_deltas(dest->pDrawable, dest_pixmap,
&dest_x_off, &dest_y_off);
pixmap_priv_get_dest_scale(dest_pixmap, dest_pixmap_priv, &dst_xscale, &dst_yscale);
if (glamor_priv->has_source_coords) {
glamor_get_drawable_deltas(source->pDrawable,
source_pixmap, &source_x_off, &source_y_off);
pixmap_priv_get_scale(source_pixmap_priv, &src_xscale, &src_yscale);
if (source->transform) {
psrc_matrix = src_matrix;
glamor_picture_get_matrixf(source, psrc_matrix);
}
}
if (glamor_priv->has_mask_coords) {
glamor_get_drawable_deltas(mask->pDrawable, mask_pixmap,
&mask_x_off, &mask_y_off);
pixmap_priv_get_scale(mask_pixmap_priv, &mask_xscale, &mask_yscale);
if (mask->transform) {
pmask_matrix = mask_matrix;
glamor_picture_get_matrixf(mask, pmask_matrix);
}
}
nrect_max = MIN(nrect, GLAMOR_COMPOSITE_VBO_VERT_CNT / 4);
if (nrect < 100) {
BoxRec bounds = glamor_start_rendering_bounds();
for (int i = 0; i < nrect; i++) {
BoxRec box = {
.x1 = rects[i].x_dst,
.y1 = rects[i].y_dst,
.x2 = rects[i].x_dst + rects[i].width,
.y2 = rects[i].y_dst + rects[i].height,
};
glamor_bounds_union_box(&bounds, &box);
}
if (bounds.x1 >= bounds.x2 || bounds.y1 >= bounds.y2)
goto disable_va;
glEnable(GL_SCISSOR_TEST);
glScissor(bounds.x1 + dest_x_off,
bounds.y1 + dest_y_off,
bounds.x2 - bounds.x1,
bounds.y2 - bounds.y1);
}
while (nrect) {
int mrect, rect_processed;
int vb_stride;
float *vertices;
mrect = nrect > nrect_max ? nrect_max : nrect;
vertices = glamor_setup_composite_vbo(screen, mrect * 4);
rect_processed = mrect;
vb_stride = glamor_priv->vb_stride / sizeof(float);
while (mrect--) {
INT16 x_source;
INT16 y_source;
INT16 x_mask;
INT16 y_mask;
INT16 x_dest;
INT16 y_dest;
CARD16 width;
CARD16 height;
x_dest = rects->x_dst + dest_x_off;
y_dest = rects->y_dst + dest_y_off;
x_source = rects->x_src + source_x_off;
y_source = rects->y_src + source_y_off;
x_mask = rects->x_mask + mask_x_off;
y_mask = rects->y_mask + mask_y_off;
width = rects->width;
height = rects->height;
DEBUGF
("dest(%d,%d) source(%d %d) mask (%d %d), width %d height %d \n",
x_dest, y_dest, x_source, y_source, x_mask, y_mask, width,
height);
glamor_set_normalize_vcoords_ext(dest_pixmap_priv, dst_xscale,
dst_yscale, x_dest, y_dest,
x_dest + width, y_dest + height,
vertices,
vb_stride);
vertices += 2;
if (key.source != SHADER_SOURCE_SOLID) {
glamor_set_normalize_tcoords_generic(source_pixmap,
source_pixmap_priv,
source->repeatType,
psrc_matrix, src_xscale,
src_yscale, x_source,
y_source, x_source + width,
y_source + height,
vertices, vb_stride);
vertices += 2;
}
if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID) {
glamor_set_normalize_tcoords_generic(mask_pixmap,
mask_pixmap_priv,
mask->repeatType,
pmask_matrix, mask_xscale,
mask_yscale, x_mask,
y_mask, x_mask + width,
y_mask + height,
vertices, vb_stride);
vertices += 2;
}
glamor_priv->render_nr_quads++;
rects++;
/* We've incremented by one of our 4 verts, now do the other 3. */
vertices += 3 * vb_stride;
}
glamor_put_vbo_space(screen);
glamor_flush_composite_rects(screen);
nrect -= rect_processed;
if (ca_state == CA_TWO_PASS) {
glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv,
&key_ca, shader_ca, &op_info_ca);
glamor_flush_composite_rects(screen);
if (nrect)
glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv,
&key, shader, &op_info);
}
}
glDisable(GL_SCISSOR_TEST);
disable_va:
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
glDisableVertexAttribArray(GLAMOR_VERTEX_MASK);
glDisable(GL_BLEND);
DEBUGF("finish rendering.\n");
if (saved_source_format)
source->format = saved_source_format;
ret = TRUE;
fail:
if (mask_pixmap && glamor_pixmap_is_memory(mask_pixmap))
glamor_pixmap_destroy_fbo(mask_pixmap);
if (source_pixmap && glamor_pixmap_is_memory(source_pixmap))
glamor_pixmap_destroy_fbo(source_pixmap);
return ret;
}
static PicturePtr
glamor_convert_gradient_picture(ScreenPtr screen,
PicturePtr source,
int x_source,
int y_source, int width, int height)
{
PixmapPtr pixmap;
PicturePtr dst = NULL;
int error;
PictFormatPtr pFormat;
PictFormatShort format;
if (source->pDrawable) {
pFormat = source->pFormat;
format = pFormat->format;
} else {
format = PICT_a8r8g8b8;
pFormat = PictureMatchFormat(screen, 32, format);
}
if (!source->pDrawable) {
if (source->pSourcePict->type == SourcePictTypeLinear) {
dst = glamor_generate_linear_gradient_picture(screen,
source, x_source,
y_source, width,
height, format);
}
else if (source->pSourcePict->type == SourcePictTypeRadial) {
dst = glamor_generate_radial_gradient_picture(screen,
source, x_source,
y_source, width,
height, format);
}
if (dst) {
return dst;
}
}
pixmap = glamor_create_pixmap(screen,
width,
height,
PIXMAN_FORMAT_DEPTH(format),
GLAMOR_CREATE_PIXMAP_CPU);
if (!pixmap)
return NULL;
dst = CreatePicture(0,
&pixmap->drawable, pFormat, 0, 0, serverClient, &error);
glamor_destroy_pixmap(pixmap);
if (!dst)
return NULL;
ValidatePicture(dst);
fbComposite(PictOpSrc, source, NULL, dst, x_source, y_source,
0, 0, 0, 0, width, height);
return dst;
}
Bool
glamor_composite_clipped_region(CARD8 op,
PicturePtr source,
PicturePtr mask,
PicturePtr dest,
PixmapPtr source_pixmap,
PixmapPtr mask_pixmap,
PixmapPtr dest_pixmap,
RegionPtr region,
int x_source,
int y_source,
int x_mask, int y_mask, int x_dest, int y_dest)
{
glamor_pixmap_private *source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
glamor_pixmap_private *mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
glamor_pixmap_private *dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
glamor_screen_private *glamor_priv = glamor_get_screen_private(dest_pixmap->drawable.pScreen);
ScreenPtr screen = dest->pDrawable->pScreen;
PicturePtr temp_src = source, temp_mask = mask;
PixmapPtr temp_src_pixmap = source_pixmap;
PixmapPtr temp_mask_pixmap = mask_pixmap;
glamor_pixmap_private *temp_src_priv = source_pixmap_priv;
glamor_pixmap_private *temp_mask_priv = mask_pixmap_priv;
int x_temp_src, y_temp_src, x_temp_mask, y_temp_mask;
BoxPtr extent;
glamor_composite_rect_t rect[10];
glamor_composite_rect_t *prect = rect;
int prect_size = ARRAY_SIZE(rect);
int ok = FALSE;
int i;
int width;
int height;
BoxPtr box;
int nbox;
enum ca_state ca_state = CA_NONE;
extent = RegionExtents(region);
box = RegionRects(region);
nbox = RegionNumRects(region);
width = extent->x2 - extent->x1;
height = extent->y2 - extent->y1;
x_temp_src = x_source;
y_temp_src = y_source;
x_temp_mask = x_mask;
y_temp_mask = y_mask;
DEBUGF("clipped (%d %d) (%d %d) (%d %d) width %d height %d \n",
x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height);
/* Is the composite operation equivalent to a copy? */
if (source &&
!mask && !source->alphaMap && !dest->alphaMap
&& source->pDrawable && !source->transform
/* CopyArea is only defined with matching depths. */
&& dest->pDrawable->depth == source->pDrawable->depth
&& ((op == PictOpSrc
&& (source->format == dest->format
|| (PICT_FORMAT_COLOR(dest->format)
&& PICT_FORMAT_COLOR(source->format)
&& dest->format == PICT_FORMAT(PICT_FORMAT_BPP(source->format),
PICT_FORMAT_TYPE(source->format),
0,
PICT_FORMAT_R(source->format),
PICT_FORMAT_G(source->format),
PICT_FORMAT_B(source->format)))))
|| (op == PictOpOver
&& source->format == dest->format
&& !PICT_FORMAT_A(source->format)))
&& x_source >= 0 && y_source >= 0
&& (x_source + width) <= source->pDrawable->width
&& (y_source + height) <= source->pDrawable->height) {
x_source += source->pDrawable->x;
y_source += source->pDrawable->y;
x_dest += dest->pDrawable->x;
y_dest += dest->pDrawable->y;
glamor_copy(source->pDrawable, dest->pDrawable, NULL,
box, nbox, x_source - x_dest,
y_source - y_dest, FALSE, FALSE, 0, NULL);
ok = TRUE;
goto out;
}
/* XXX is it possible source mask have non-zero drawable.x/y? */
if (source
&& ((!source->pDrawable
&& (source->pSourcePict->type != SourcePictTypeSolidFill))
|| (source->pDrawable
&& !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv)
&& (source_pixmap->drawable.width != width
|| source_pixmap->drawable.height != height)))) {
temp_src =
glamor_convert_gradient_picture(screen, source,
extent->x1 + x_source - x_dest - dest->pDrawable->x,
extent->y1 + y_source - y_dest - dest->pDrawable->y,
width, height);
if (!temp_src) {
temp_src = source;
goto out;
}
temp_src_pixmap = (PixmapPtr) (temp_src->pDrawable);
temp_src_priv = glamor_get_pixmap_private(temp_src_pixmap);
x_temp_src = -extent->x1 + x_dest + dest->pDrawable->x;
y_temp_src = -extent->y1 + y_dest + dest->pDrawable->y;
}
if (mask
&&
((!mask->pDrawable
&& (mask->pSourcePict->type != SourcePictTypeSolidFill))
|| (mask->pDrawable && !GLAMOR_PIXMAP_PRIV_HAS_FBO(mask_pixmap_priv)
&& (mask_pixmap->drawable.width != width
|| mask_pixmap->drawable.height != height)))) {
/* XXX if mask->pDrawable is the same as source->pDrawable, we have an opportunity
* to do reduce one conversion. */
temp_mask =
glamor_convert_gradient_picture(screen, mask,
extent->x1 + x_mask - x_dest - dest->pDrawable->x,
extent->y1 + y_mask - y_dest - dest->pDrawable->y,
width, height);
if (!temp_mask) {
temp_mask = mask;
goto out;
}
temp_mask_pixmap = (PixmapPtr) (temp_mask->pDrawable);
temp_mask_priv = glamor_get_pixmap_private(temp_mask_pixmap);
x_temp_mask = -extent->x1 + x_dest + dest->pDrawable->x;
y_temp_mask = -extent->y1 + y_dest + dest->pDrawable->y;
}
if (mask && mask->componentAlpha) {
if (glamor_priv->has_dual_blend) {
ca_state = CA_DUAL_BLEND;
} else {
if (op == PictOpOver) {
if (glamor_pixmap_is_memory(mask_pixmap)) {
glamor_fallback("two pass not supported on memory pximaps\n");
goto out;
}
ca_state = CA_TWO_PASS;
op = PictOpOutReverse;
}
}
}
if (temp_src_pixmap == dest_pixmap) {
glamor_fallback("source and dest pixmaps are the same\n");
goto out;
}
if (temp_mask_pixmap == dest_pixmap) {
glamor_fallback("mask and dest pixmaps are the same\n");
goto out;
}
x_dest += dest->pDrawable->x;
y_dest += dest->pDrawable->y;
if (temp_src && temp_src->pDrawable) {
x_temp_src += temp_src->pDrawable->x;
y_temp_src += temp_src->pDrawable->y;
}
if (temp_mask && temp_mask->pDrawable) {
x_temp_mask += temp_mask->pDrawable->x;
y_temp_mask += temp_mask->pDrawable->y;
}
if (nbox > ARRAY_SIZE(rect)) {
prect = calloc(nbox, sizeof(*prect));
if (prect)
prect_size = nbox;
else {
prect = rect;
prect_size = ARRAY_SIZE(rect);
}
}
while (nbox) {
int box_cnt;
box_cnt = nbox > prect_size ? prect_size : nbox;
for (i = 0; i < box_cnt; i++) {
prect[i].x_src = box[i].x1 + x_temp_src - x_dest;
prect[i].y_src = box[i].y1 + y_temp_src - y_dest;
prect[i].x_mask = box[i].x1 + x_temp_mask - x_dest;
prect[i].y_mask = box[i].y1 + y_temp_mask - y_dest;
prect[i].x_dst = box[i].x1;
prect[i].y_dst = box[i].y1;
prect[i].width = box[i].x2 - box[i].x1;
prect[i].height = box[i].y2 - box[i].y1;
DEBUGF("dest %d %d \n", prect[i].x_dst, prect[i].y_dst);
}
ok = glamor_composite_with_shader(op, temp_src, temp_mask, dest,
temp_src_pixmap, temp_mask_pixmap, dest_pixmap,
temp_src_priv, temp_mask_priv,
dest_pixmap_priv,
box_cnt, prect, ca_state);
if (!ok)
break;
nbox -= box_cnt;
box += box_cnt;
}
if (prect != rect)
free(prect);
out:
if (temp_src != source)
FreePicture(temp_src, 0);
if (temp_mask != mask)
FreePicture(temp_mask, 0);
return ok;
}
void
glamor_composite(CARD8 op,
PicturePtr source,
PicturePtr mask,
PicturePtr dest,
INT16 x_source,
INT16 y_source,
INT16 x_mask,
INT16 y_mask,
INT16 x_dest, INT16 y_dest, CARD16 width, CARD16 height)
{
ScreenPtr screen = dest->pDrawable->pScreen;
PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable);
PixmapPtr source_pixmap = NULL, mask_pixmap = NULL;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
RegionRec region;
BoxPtr extent;
int nbox, ok = FALSE;
int force_clip = 0;
if (source->pDrawable) {
source_pixmap = glamor_get_drawable_pixmap(source->pDrawable);
if (glamor_pixmap_drm_only(source_pixmap))
goto fail;
}
if (mask && mask->pDrawable) {
mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable);
if (glamor_pixmap_drm_only(mask_pixmap))
goto fail;
}
DEBUGF
("source pixmap %p (%d %d) mask(%d %d) dest(%d %d) width %d height %d \n",
source_pixmap, x_source, y_source, x_mask, y_mask, x_dest, y_dest,
width, height);
if (!glamor_pixmap_has_fbo(dest_pixmap))
goto fail;
if (op >= ARRAY_SIZE(composite_op_info)) {
glamor_fallback("Unsupported composite op %x\n", op);
goto fail;
}
if (mask && mask->componentAlpha && !glamor_priv->has_dual_blend) {
if (op == PictOpAtop
|| op == PictOpAtopReverse
|| op == PictOpXor || op >= PictOpSaturate) {
glamor_fallback("glamor_composite(): component alpha op %x\n", op);
goto fail;
}
}
if ((source && source->filter >= PictFilterConvolution)
|| (mask && mask->filter >= PictFilterConvolution)) {
glamor_fallback("glamor_composite(): unsupported filter\n");
goto fail;
}
if (!miComputeCompositeRegion(®ion,
source, mask, dest,
x_source +
(source_pixmap ? source->pDrawable->x : 0),
y_source +
(source_pixmap ? source->pDrawable->y : 0),
x_mask +
(mask_pixmap ? mask->pDrawable->x : 0),
y_mask +
(mask_pixmap ? mask->pDrawable->y : 0),
x_dest + dest->pDrawable->x,
y_dest + dest->pDrawable->y, width, height)) {
return;
}
nbox = REGION_NUM_RECTS(®ion);
DEBUGF("first clipped when compositing.\n");
DEBUGRegionPrint(®ion);
extent = RegionExtents(®ion);
if (nbox == 0)
return;
/* If destination is not a large pixmap, but the region is larger
* than texture size limitation, and source or mask is memory pixmap,
* then there may be need to load a large memory pixmap to a
* texture, and this is not permitted. Then we force to clip the
* destination and make sure latter will not upload a large memory
* pixmap. */
if (!glamor_check_fbo_size(glamor_priv,
extent->x2 - extent->x1, extent->y2 - extent->y1)
&& glamor_pixmap_is_large(dest_pixmap)
&& ((source_pixmap
&& (glamor_pixmap_is_memory(source_pixmap) ||
source->repeatType == RepeatPad))
|| (mask_pixmap &&
(glamor_pixmap_is_memory(mask_pixmap) ||
mask->repeatType == RepeatPad))
|| (!source_pixmap &&
(source->pSourcePict->type != SourcePictTypeSolidFill))
|| (!mask_pixmap && mask &&
mask->pSourcePict->type != SourcePictTypeSolidFill)))
force_clip = 1;
if (force_clip || glamor_pixmap_is_large(dest_pixmap)
|| (source_pixmap
&& glamor_pixmap_is_large(source_pixmap))
|| (mask_pixmap && glamor_pixmap_is_large(mask_pixmap)))
ok = glamor_composite_largepixmap_region(op,
source, mask, dest,
source_pixmap,
mask_pixmap,
dest_pixmap,
®ion, force_clip,
x_source, y_source,
x_mask, y_mask,
x_dest, y_dest, width, height);
else
ok = glamor_composite_clipped_region(op, source,
mask, dest,
source_pixmap,
mask_pixmap,
dest_pixmap,
®ion,
x_source, y_source,
x_mask, y_mask, x_dest, y_dest);
REGION_UNINIT(dest->pDrawable->pScreen, ®ion);
if (ok)
return;
fail:
glamor_fallback
("from picts %p:%p %dx%d / %p:%p %d x %d (%c,%c) to pict %p:%p %dx%d (%c)\n",
source, source->pDrawable,
source->pDrawable ? source->pDrawable->width : 0,
source->pDrawable ? source->pDrawable->height : 0, mask,
(!mask) ? NULL : mask->pDrawable,
(!mask || !mask->pDrawable) ? 0 : mask->pDrawable->width,
(!mask || !mask->pDrawable) ? 0 : mask->pDrawable->height,
glamor_get_picture_location(source),
glamor_get_picture_location(mask),
dest, dest->pDrawable,
dest->pDrawable->width, dest->pDrawable->height,
glamor_get_picture_location(dest));
if (glamor_prepare_access_picture_box(dest, GLAMOR_ACCESS_RW,
x_dest, y_dest, width, height) &&
glamor_prepare_access_picture_box(source, GLAMOR_ACCESS_RO,
x_source, y_source, width, height) &&
glamor_prepare_access_picture_box(mask, GLAMOR_ACCESS_RO,
x_mask, y_mask, width, height))
{
fbComposite(op,
source, mask, dest,
x_source, y_source,
x_mask, y_mask, x_dest, y_dest, width, height);
}
glamor_finish_access_picture(mask);
glamor_finish_access_picture(source);
glamor_finish_access_picture(dest);
}
xorg-server-21.1.4/glamor/glamor_eglmodule.c 0000644 0001750 0001750 00000003741 14263273335 015763 0000000 0000000 /*
* Copyright (C) 1998 The XFree86 Project, Inc. All Rights Reserved.
*
* 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 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
* XFREE86 PROJECT 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.
*
* Except as contained in this notice, the name of the XFree86 Project shall
* not be used in advertising or otherwise to promote the sale, use or other
* dealings in this Software without prior written authorization from the
* XFree86 Project.
*
* Authors:
* Zhigang Gong
*/
#include "dix-config.h"
#include
#define GLAMOR_FOR_XORG
#include
#include "glamor.h"
static XF86ModuleVersionInfo VersRec = {
GLAMOR_EGL_MODULE_NAME,
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XORG_VERSION_CURRENT,
1, 0, 1, /* version */
ABI_CLASS_ANSIC, /* Only need the ansic layer */
ABI_ANSIC_VERSION,
MOD_CLASS_NONE,
{0, 0, 0, 0} /* signature, to be patched into the file by a tool */
};
_X_EXPORT XF86ModuleData glamoreglModuleData = { &VersRec, NULL, NULL };
xorg-server-21.1.4/glamor/glamor_image.c 0000644 0001750 0001750 00000012525 14263273335 015070 0000000 0000000 /*
* Copyright © 2014 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "glamor_priv.h"
#include "glamor_transfer.h"
#include "glamor_transform.h"
/*
* PutImage. Only does ZPixmap right now as other formats are quite a bit harder
*/
static Bool
glamor_put_image_gl(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
int w, int h, int leftPad, int format, char *bits)
{
ScreenPtr screen = drawable->pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *pixmap_priv;
uint32_t byte_stride = PixmapBytePad(w, drawable->depth);
RegionRec region;
BoxRec box;
int off_x, off_y;
pixmap_priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
return FALSE;
if (gc->alu != GXcopy)
goto bail;
if (!glamor_pm_is_solid(gc->depth, gc->planemask))
goto bail;
if (format == XYPixmap && drawable->depth == 1 && leftPad == 0)
format = ZPixmap;
if (format != ZPixmap)
goto bail;
x += drawable->x;
y += drawable->y;
box.x1 = x;
box.y1 = y;
box.x2 = box.x1 + w;
box.y2 = box.y1 + h;
RegionInit(®ion, &box, 1);
RegionIntersect(®ion, ®ion, gc->pCompositeClip);
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
if (off_x || off_y) {
x += off_x;
y += off_y;
RegionTranslate(®ion, off_x, off_y);
}
glamor_make_current(glamor_priv);
glamor_upload_region(pixmap, ®ion, x, y, (uint8_t *) bits, byte_stride);
RegionUninit(®ion);
return TRUE;
bail:
return FALSE;
}
static void
glamor_put_image_bail(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
int w, int h, int leftPad, int format, char *bits)
{
if (glamor_prepare_access_box(drawable, GLAMOR_ACCESS_RW, x, y, w, h))
fbPutImage(drawable, gc, depth, x, y, w, h, leftPad, format, bits);
glamor_finish_access(drawable);
}
void
glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
int w, int h, int leftPad, int format, char *bits)
{
if (glamor_put_image_gl(drawable, gc, depth, x, y, w, h, leftPad, format, bits))
return;
glamor_put_image_bail(drawable, gc, depth, x, y, w, h, leftPad, format, bits);
}
static Bool
glamor_get_image_gl(DrawablePtr drawable, int x, int y, int w, int h,
unsigned int format, unsigned long plane_mask, char *d)
{
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *pixmap_priv;
uint32_t byte_stride = PixmapBytePad(w, drawable->depth);
BoxRec box;
int off_x, off_y;
pixmap_priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
goto bail;
if (format != ZPixmap)
goto bail;
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
box.x1 = x;
box.x2 = x + w;
box.y1 = y;
box.y2 = y + h;
glamor_download_boxes(pixmap, &box, 1,
drawable->x + off_x, drawable->y + off_y,
-x, -y,
(uint8_t *) d, byte_stride);
if (!glamor_pm_is_solid(drawable->depth, plane_mask)) {
FbStip pm = fbReplicatePixel(plane_mask, drawable->bitsPerPixel);
FbStip *dst = (void *)d;
uint32_t dstStride = byte_stride / sizeof(FbStip);
for (int i = 0; i < dstStride * h; i++)
dst[i] &= pm;
}
return TRUE;
bail:
return FALSE;
}
static void
glamor_get_image_bail(DrawablePtr drawable, int x, int y, int w, int h,
unsigned int format, unsigned long plane_mask, char *d)
{
if (glamor_prepare_access_box(drawable, GLAMOR_ACCESS_RO, x, y, w, h))
fbGetImage(drawable, x, y, w, h, format, plane_mask, d);
glamor_finish_access(drawable);
}
void
glamor_get_image(DrawablePtr drawable, int x, int y, int w, int h,
unsigned int format, unsigned long plane_mask, char *d)
{
if (glamor_get_image_gl(drawable, x, y, w, h, format, plane_mask, d))
return;
glamor_get_image_bail(drawable, x, y, w, h, format, plane_mask, d);
}
xorg-server-21.1.4/glamor/glamor_compositerects.c 0000644 0001750 0001750 00000020731 14263273335 017047 0000000 0000000 /*
* 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:
* Zhigang Gong
*
* original author is Chris Wilson at sna.
*
*/
#include "glamor_priv.h"
#include "mipict.h"
#include "damage.h"
/** @file glamor_compositerects.
*
* compositeRects acceleration implementation
*/
static int16_t
bound(int16_t a, uint16_t b)
{
int v = (int) a + (int) b;
if (v > MAXSHORT)
return MAXSHORT;
return v;
}
static Bool
_pixman_region_init_clipped_rectangles(pixman_region16_t * region,
unsigned int num_rects,
xRectangle *rects,
int tx, int ty, BoxPtr extents)
{
pixman_box16_t stack_boxes[64], *boxes = stack_boxes;
pixman_bool_t ret;
unsigned int i, j;
if (num_rects > ARRAY_SIZE(stack_boxes)) {
boxes = xallocarray(num_rects, sizeof(pixman_box16_t));
if (boxes == NULL)
return FALSE;
}
for (i = j = 0; i < num_rects; i++) {
boxes[j].x1 = rects[i].x + tx;
if (boxes[j].x1 < extents->x1)
boxes[j].x1 = extents->x1;
boxes[j].y1 = rects[i].y + ty;
if (boxes[j].y1 < extents->y1)
boxes[j].y1 = extents->y1;
boxes[j].x2 = bound(rects[i].x + tx, rects[i].width);
if (boxes[j].x2 > extents->x2)
boxes[j].x2 = extents->x2;
boxes[j].y2 = bound(rects[i].y + ty, rects[i].height);
if (boxes[j].y2 > extents->y2)
boxes[j].y2 = extents->y2;
if (boxes[j].x2 > boxes[j].x1 && boxes[j].y2 > boxes[j].y1)
j++;
}
ret = FALSE;
if (j)
ret = pixman_region_init_rects(region, boxes, j);
if (boxes != stack_boxes)
free(boxes);
DEBUGF("%s: nrects=%d, region=(%d, %d), (%d, %d) x %d\n",
__FUNCTION__, num_rects,
region->extents.x1, region->extents.y1,
region->extents.x2, region->extents.y2, j);
return ret;
}
void
glamor_composite_rectangles(CARD8 op,
PicturePtr dst,
xRenderColor * color,
int num_rects, xRectangle *rects)
{
PixmapPtr pixmap;
struct glamor_pixmap_private *priv;
pixman_region16_t region;
pixman_box16_t *boxes;
int num_boxes;
PicturePtr source = NULL;
Bool need_free_region = FALSE;
DEBUGF("%s(op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n",
__FUNCTION__, op,
(color->alpha >> 8 << 24) |
(color->red >> 8 << 16) |
(color->green >> 8 << 8) |
(color->blue >> 8 << 0),
num_rects, rects[0].x, rects[0].y, rects[0].width, rects[0].height);
if (!num_rects)
return;
if (RegionNil(dst->pCompositeClip)) {
DEBUGF("%s: empty clip, skipping\n", __FUNCTION__);
return;
}
if ((color->red | color->green | color->blue | color->alpha) <= 0x00ff) {
switch (op) {
case PictOpOver:
case PictOpOutReverse:
case PictOpAdd:
return;
case PictOpInReverse:
case PictOpSrc:
op = PictOpClear;
break;
case PictOpAtopReverse:
op = PictOpOut;
break;
case PictOpXor:
op = PictOpOverReverse;
break;
}
}
if (color->alpha <= 0x00ff) {
switch (op) {
case PictOpOver:
case PictOpOutReverse:
return;
case PictOpInReverse:
op = PictOpClear;
break;
case PictOpAtopReverse:
op = PictOpOut;
break;
case PictOpXor:
op = PictOpOverReverse;
break;
}
}
else if (color->alpha >= 0xff00) {
switch (op) {
case PictOpOver:
op = PictOpSrc;
break;
case PictOpInReverse:
return;
case PictOpOutReverse:
op = PictOpClear;
break;
case PictOpAtopReverse:
op = PictOpOverReverse;
break;
case PictOpXor:
op = PictOpOut;
break;
}
}
DEBUGF("%s: converted to op %d\n", __FUNCTION__, op);
if (!_pixman_region_init_clipped_rectangles(®ion,
num_rects, rects,
dst->pDrawable->x,
dst->pDrawable->y,
&dst->pCompositeClip->extents))
{
DEBUGF("%s: allocation failed for region\n", __FUNCTION__);
return;
}
pixmap = glamor_get_drawable_pixmap(dst->pDrawable);
priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
goto fallback;
if (dst->alphaMap) {
DEBUGF("%s: fallback, dst has an alpha-map\n", __FUNCTION__);
goto fallback;
}
need_free_region = TRUE;
DEBUGF("%s: drawable extents (%d, %d),(%d, %d) x %d\n",
__FUNCTION__,
RegionExtents(®ion)->x1, RegionExtents(®ion)->y1,
RegionExtents(®ion)->x2, RegionExtents(®ion)->y2,
RegionNumRects(®ion));
if (dst->pCompositeClip->data &&
(!pixman_region_intersect(®ion, ®ion, dst->pCompositeClip) ||
RegionNil(®ion))) {
DEBUGF("%s: zero-intersection between rectangles and clip\n",
__FUNCTION__);
pixman_region_fini(®ion);
return;
}
DEBUGF("%s: clipped extents (%d, %d),(%d, %d) x %d\n",
__FUNCTION__,
RegionExtents(®ion)->x1, RegionExtents(®ion)->y1,
RegionExtents(®ion)->x2, RegionExtents(®ion)->y2,
RegionNumRects(®ion));
boxes = pixman_region_rectangles(®ion, &num_boxes);
if (op == PictOpSrc || op == PictOpClear) {
CARD32 pixel;
int dst_x, dst_y;
glamor_get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y);
pixman_region_translate(®ion, dst_x, dst_y);
DEBUGF("%s: pixmap +(%d, %d) extents (%d, %d),(%d, %d)\n",
__FUNCTION__, dst_x, dst_y,
RegionExtents(®ion)->x1, RegionExtents(®ion)->y1,
RegionExtents(®ion)->x2, RegionExtents(®ion)->y2);
if (op == PictOpClear)
pixel = 0;
else
miRenderColorToPixel(dst->pFormat, color, &pixel);
glamor_solid_boxes(pixmap, boxes, num_boxes, pixel);
goto done;
}
else {
if (_X_LIKELY(glamor_pixmap_priv_is_small(priv))) {
int error;
source = CreateSolidPicture(0, color, &error);
if (!source)
goto done;
if (glamor_composite_clipped_region(op, source,
NULL, dst,
NULL, NULL, pixmap,
®ion, 0, 0, 0, 0, 0, 0))
goto done;
}
}
fallback:
miCompositeRects(op, dst, color, num_rects, rects);
done:
/* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must
* manually append the damaged regions ourselves.
*/
DamageRegionAppend(&pixmap->drawable, ®ion);
DamageRegionProcessPending(&pixmap->drawable);
if (need_free_region)
pixman_region_fini(®ion);
if (source)
FreePicture(source, 0);
return;
}
xorg-server-21.1.4/glamor/glamor_prepare.c 0000644 0001750 0001750 00000022567 14263273335 015453 0000000 0000000 /*
* Copyright © 2014 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "glamor_priv.h"
#include "glamor_prepare.h"
#include "glamor_transfer.h"
/*
* Make a pixmap ready to draw with fb by
* creating a PBO large enough for the whole object
* and downloading all of the FBOs into it.
*/
static Bool
glamor_prep_pixmap_box(PixmapPtr pixmap, glamor_access_t access, BoxPtr box)
{
ScreenPtr screen = pixmap->drawable.pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
int gl_access, gl_usage;
RegionRec region;
if (priv->type == GLAMOR_DRM_ONLY)
return FALSE;
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
return TRUE;
glamor_make_current(glamor_priv);
RegionInit(®ion, box, 1);
/* See if it's already mapped */
if (pixmap->devPrivate.ptr) {
/*
* Someone else has mapped this pixmap;
* we'll assume that it's directly mapped
* by a lower level driver
*/
if (!priv->prepared)
return TRUE;
/* In X, multiple Drawables can be stored in the same Pixmap (such as
* each individual window in a non-composited screen pixmap, or the
* reparented window contents inside the window-manager-decorated window
* pixmap on a composited screen).
*
* As a result, when doing a series of mappings for a fallback, we may
* need to add more boxes to the set of data we've downloaded, as we go.
*/
RegionSubtract(®ion, ®ion, &priv->prepare_region);
if (!RegionNotEmpty(®ion))
return TRUE;
if (access == GLAMOR_ACCESS_RW)
FatalError("attempt to remap buffer as writable");
if (priv->pbo) {
glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
pixmap->devPrivate.ptr = NULL;
}
} else {
RegionInit(&priv->prepare_region, box, 1);
if (glamor_priv->has_rw_pbo) {
if (priv->pbo == 0)
glGenBuffers(1, &priv->pbo);
gl_usage = GL_STREAM_READ;
glamor_priv->suppress_gl_out_of_memory_logging = true;
glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
glBufferData(GL_PIXEL_PACK_BUFFER,
pixmap->devKind * pixmap->drawable.height, NULL,
gl_usage);
glamor_priv->suppress_gl_out_of_memory_logging = false;
if (glGetError() == GL_OUT_OF_MEMORY) {
if (!glamor_priv->logged_any_pbo_allocation_failure) {
LogMessageVerb(X_WARNING, 0, "glamor: Failed to allocate %d "
"bytes PBO due to GL_OUT_OF_MEMORY.\n",
pixmap->devKind * pixmap->drawable.height);
glamor_priv->logged_any_pbo_allocation_failure = true;
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glDeleteBuffers(1, &priv->pbo);
priv->pbo = 0;
}
}
if (!priv->pbo) {
pixmap->devPrivate.ptr = xallocarray(pixmap->devKind,
pixmap->drawable.height);
if (!pixmap->devPrivate.ptr)
return FALSE;
}
priv->map_access = access;
}
glamor_download_boxes(pixmap, RegionRects(®ion), RegionNumRects(®ion),
0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
RegionUninit(®ion);
if (priv->pbo) {
if (priv->map_access == GLAMOR_ACCESS_RW)
gl_access = GL_READ_WRITE;
else
gl_access = GL_READ_ONLY;
pixmap->devPrivate.ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, gl_access);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
priv->prepared = TRUE;
return TRUE;
}
/*
* When we're done with the drawable, unmap the PBO, reupload
* if we were writing to it and then unbind it to release the memory
*/
static void
glamor_fini_pixmap(PixmapPtr pixmap)
{
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
return;
if (!priv->prepared)
return;
if (priv->pbo) {
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, priv->pbo);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
pixmap->devPrivate.ptr = NULL;
}
if (priv->map_access == GLAMOR_ACCESS_RW) {
glamor_upload_boxes(pixmap,
RegionRects(&priv->prepare_region),
RegionNumRects(&priv->prepare_region),
0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
}
RegionUninit(&priv->prepare_region);
if (priv->pbo) {
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glDeleteBuffers(1, &priv->pbo);
priv->pbo = 0;
} else {
free(pixmap->devPrivate.ptr);
pixmap->devPrivate.ptr = NULL;
}
priv->prepared = FALSE;
}
Bool
glamor_prepare_access(DrawablePtr drawable, glamor_access_t access)
{
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
BoxRec box;
int off_x, off_y;
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
box.x1 = drawable->x + off_x;
box.x2 = box.x1 + drawable->width;
box.y1 = drawable->y + off_y;
box.y2 = box.y1 + drawable->height;
return glamor_prep_pixmap_box(pixmap, access, &box);
}
Bool
glamor_prepare_access_box(DrawablePtr drawable, glamor_access_t access,
int x, int y, int w, int h)
{
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
BoxRec box;
int off_x, off_y;
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
box.x1 = drawable->x + x + off_x;
box.x2 = box.x1 + w;
box.y1 = drawable->y + y + off_y;
box.y2 = box.y1 + h;
return glamor_prep_pixmap_box(pixmap, access, &box);
}
void
glamor_finish_access(DrawablePtr drawable)
{
glamor_fini_pixmap(glamor_get_drawable_pixmap(drawable));
}
/*
* Make a picture ready to use with fb.
*/
Bool
glamor_prepare_access_picture(PicturePtr picture, glamor_access_t access)
{
if (!picture || !picture->pDrawable)
return TRUE;
return glamor_prepare_access(picture->pDrawable, access);
}
Bool
glamor_prepare_access_picture_box(PicturePtr picture, glamor_access_t access,
int x, int y, int w, int h)
{
if (!picture || !picture->pDrawable)
return TRUE;
/* If a transform is set, we don't know what the bounds is on the
* source, so just prepare the whole pixmap. XXX: We could
* potentially work out where in the source would be sampled based
* on the transform, and we don't need do do this for destination
* pixmaps at all.
*/
if (picture->transform) {
return glamor_prepare_access_box(picture->pDrawable, access,
0, 0,
picture->pDrawable->width,
picture->pDrawable->height);
} else {
return glamor_prepare_access_box(picture->pDrawable, access,
x, y, w, h);
}
}
void
glamor_finish_access_picture(PicturePtr picture)
{
if (!picture || !picture->pDrawable)
return;
glamor_finish_access(picture->pDrawable);
}
/*
* Make a GC ready to use with fb. This just
* means making sure the appropriate fill pixmap is
* in CPU memory again
*/
Bool
glamor_prepare_access_gc(GCPtr gc)
{
switch (gc->fillStyle) {
case FillTiled:
return glamor_prepare_access(&gc->tile.pixmap->drawable,
GLAMOR_ACCESS_RO);
case FillStippled:
case FillOpaqueStippled:
return glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RO);
}
return TRUE;
}
/*
* Free any temporary CPU pixmaps for the GC
*/
void
glamor_finish_access_gc(GCPtr gc)
{
switch (gc->fillStyle) {
case FillTiled:
glamor_finish_access(&gc->tile.pixmap->drawable);
break;
case FillStippled:
case FillOpaqueStippled:
glamor_finish_access(&gc->stipple->drawable);
break;
}
}
xorg-server-21.1.4/glamor/glamor_fbo.c 0000644 0001750 0001750 00000026175 14263273335 014562 0000000 0000000 /*
* Copyright © 2009 Intel Corporation
* Copyright © 1998 Keith Packard
*
* 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:
* Zhigang Gong
*
*/
#include
#include "glamor_priv.h"
void
glamor_destroy_fbo(glamor_screen_private *glamor_priv,
glamor_pixmap_fbo *fbo)
{
glamor_make_current(glamor_priv);
if (fbo->fb)
glDeleteFramebuffers(1, &fbo->fb);
if (fbo->tex)
glDeleteTextures(1, &fbo->tex);
free(fbo);
}
static int
glamor_pixmap_ensure_fb(glamor_screen_private *glamor_priv,
glamor_pixmap_fbo *fbo)
{
int status, err = 0;
glamor_make_current(glamor_priv);
if (fbo->fb == 0)
glGenFramebuffers(1, &fbo->fb);
assert(fbo->tex != 0);
glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, fbo->tex, 0);
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
const char *str;
switch (status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
str = "incomplete attachment";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
str = "incomplete/missing attachment";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
str = "incomplete draw buffer";
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
str = "incomplete read buffer";
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
str = "unsupported";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
str = "incomplete multiple";
break;
default:
str = "unknown error";
break;
}
glamor_fallback("glamor: Failed to create fbo, %s\n", str);
err = -1;
}
return err;
}
glamor_pixmap_fbo *
glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
PixmapPtr pixmap, int w, int h, GLint tex, int flag)
{
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
glamor_pixmap_fbo *fbo;
fbo = calloc(1, sizeof(*fbo));
if (fbo == NULL)
return NULL;
fbo->tex = tex;
fbo->width = w;
fbo->height = h;
fbo->is_red = f->format == GL_RED;
if (flag != GLAMOR_CREATE_FBO_NO_FBO) {
if (glamor_pixmap_ensure_fb(glamor_priv, fbo) != 0) {
glamor_destroy_fbo(glamor_priv, fbo);
fbo = NULL;
}
}
return fbo;
}
static int
_glamor_create_tex(glamor_screen_private *glamor_priv,
PixmapPtr pixmap, int w, int h)
{
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
unsigned int tex;
glamor_make_current(glamor_priv);
glGenTextures(1, &tex);
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);
if (f->format == GL_RED)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
glamor_priv->suppress_gl_out_of_memory_logging = true;
glTexImage2D(GL_TEXTURE_2D, 0, f->internalformat, w, h, 0,
f->format, f->type, NULL);
glamor_priv->suppress_gl_out_of_memory_logging = false;
if (glGetError() == GL_OUT_OF_MEMORY) {
if (!glamor_priv->logged_any_fbo_allocation_failure) {
LogMessageVerb(X_WARNING, 0, "glamor: Failed to allocate %dx%d "
"FBO due to GL_OUT_OF_MEMORY.\n", w, h);
LogMessageVerb(X_WARNING, 0,
"glamor: Expect reduced performance.\n");
glamor_priv->logged_any_fbo_allocation_failure = true;
}
glDeleteTextures(1, &tex);
return 0;
}
return tex;
}
glamor_pixmap_fbo *
glamor_create_fbo(glamor_screen_private *glamor_priv,
PixmapPtr pixmap, int w, int h, int flag)
{
GLint tex = _glamor_create_tex(glamor_priv, pixmap, w, h);
if (!tex) /* Texture creation failed due to GL_OUT_OF_MEMORY */
return NULL;
return glamor_create_fbo_from_tex(glamor_priv, pixmap, w, h,
tex, flag);
}
/**
* Create storage for the w * h region, using FBOs of the GL's maximum
* supported size.
*/
glamor_pixmap_fbo *
glamor_create_fbo_array(glamor_screen_private *glamor_priv,
PixmapPtr pixmap, int flag,
int block_w, int block_h,
glamor_pixmap_private *priv)
{
int w = pixmap->drawable.width;
int h = pixmap->drawable.height;
int block_wcnt;
int block_hcnt;
glamor_pixmap_fbo **fbo_array;
BoxPtr box_array;
int i, j;
priv->block_w = block_w;
priv->block_h = block_h;
block_wcnt = (w + block_w - 1) / block_w;
block_hcnt = (h + block_h - 1) / block_h;
box_array = calloc(block_wcnt * block_hcnt, sizeof(box_array[0]));
if (box_array == NULL)
return NULL;
fbo_array = calloc(block_wcnt * block_hcnt, sizeof(glamor_pixmap_fbo *));
if (fbo_array == NULL) {
free(box_array);
return FALSE;
}
for (i = 0; i < block_hcnt; i++) {
int block_y1, block_y2;
int fbo_w, fbo_h;
block_y1 = i * block_h;
block_y2 = (block_y1 + block_h) > h ? h : (block_y1 + block_h);
fbo_h = block_y2 - block_y1;
for (j = 0; j < block_wcnt; j++) {
box_array[i * block_wcnt + j].x1 = j * block_w;
box_array[i * block_wcnt + j].y1 = block_y1;
box_array[i * block_wcnt + j].x2 =
(j + 1) * block_w > w ? w : (j + 1) * block_w;
box_array[i * block_wcnt + j].y2 = block_y2;
fbo_w =
box_array[i * block_wcnt + j].x2 - box_array[i * block_wcnt +
j].x1;
fbo_array[i * block_wcnt + j] = glamor_create_fbo(glamor_priv,
pixmap,
fbo_w, fbo_h,
GLAMOR_CREATE_PIXMAP_FIXUP);
if (fbo_array[i * block_wcnt + j] == NULL)
goto cleanup;
}
}
priv->box = box_array[0];
priv->box_array = box_array;
priv->fbo_array = fbo_array;
priv->block_wcnt = block_wcnt;
priv->block_hcnt = block_hcnt;
return fbo_array[0];
cleanup:
for (i = 0; i < block_wcnt * block_hcnt; i++)
if (fbo_array[i])
glamor_destroy_fbo(glamor_priv, fbo_array[i]);
free(box_array);
free(fbo_array);
return NULL;
}
void
glamor_pixmap_clear_fbo(glamor_screen_private *glamor_priv, glamor_pixmap_fbo *fbo,
const struct glamor_format *pixmap_format)
{
glamor_make_current(glamor_priv);
assert(fbo->fb != 0 && fbo->tex != 0);
if (glamor_priv->has_clear_texture) {
glClearTexImage(fbo->tex, 0, pixmap_format->format, pixmap_format->type, NULL);
}
else {
glamor_set_destination_pixmap_fbo(glamor_priv, fbo, 0, 0, fbo->width, fbo->height);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
}
}
glamor_pixmap_fbo *
glamor_pixmap_detach_fbo(glamor_pixmap_private *pixmap_priv)
{
glamor_pixmap_fbo *fbo;
if (pixmap_priv == NULL)
return NULL;
fbo = pixmap_priv->fbo;
if (fbo == NULL)
return NULL;
pixmap_priv->fbo = NULL;
return fbo;
}
/* The pixmap must not be attached to another fbo. */
void
glamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo)
{
glamor_pixmap_private *pixmap_priv;
pixmap_priv = glamor_get_pixmap_private(pixmap);
if (pixmap_priv->fbo)
return;
pixmap_priv->fbo = fbo;
switch (pixmap_priv->type) {
case GLAMOR_TEXTURE_ONLY:
case GLAMOR_TEXTURE_DRM:
pixmap_priv->gl_fbo = GLAMOR_FBO_NORMAL;
pixmap->devPrivate.ptr = NULL;
default:
break;
}
}
void
glamor_pixmap_destroy_fbo(PixmapPtr pixmap)
{
ScreenPtr screen = pixmap->drawable.pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
glamor_pixmap_fbo *fbo;
if (glamor_pixmap_priv_is_large(priv)) {
int i;
for (i = 0; i < priv->block_wcnt * priv->block_hcnt; i++)
glamor_destroy_fbo(glamor_priv, priv->fbo_array[i]);
free(priv->fbo_array);
priv->fbo_array = NULL;
}
else {
fbo = glamor_pixmap_detach_fbo(priv);
if (fbo)
glamor_destroy_fbo(glamor_priv, fbo);
}
}
Bool
glamor_pixmap_ensure_fbo(PixmapPtr pixmap, int flag)
{
glamor_screen_private *glamor_priv;
glamor_pixmap_private *pixmap_priv;
glamor_pixmap_fbo *fbo;
glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
pixmap_priv = glamor_get_pixmap_private(pixmap);
if (pixmap_priv->fbo == NULL) {
fbo = glamor_create_fbo(glamor_priv, pixmap, pixmap->drawable.width,
pixmap->drawable.height, flag);
if (fbo == NULL)
return FALSE;
glamor_pixmap_attach_fbo(pixmap, fbo);
}
else {
/* We do have a fbo, but it may lack of fb or tex. */
if (!pixmap_priv->fbo->tex)
pixmap_priv->fbo->tex =
_glamor_create_tex(glamor_priv, pixmap, pixmap->drawable.width,
pixmap->drawable.height);
if (flag != GLAMOR_CREATE_FBO_NO_FBO && pixmap_priv->fbo->fb == 0)
if (glamor_pixmap_ensure_fb(glamor_priv, pixmap_priv->fbo) != 0)
return FALSE;
}
return TRUE;
}
_X_EXPORT void
glamor_pixmap_exchange_fbos(PixmapPtr front, PixmapPtr back)
{
glamor_pixmap_private *front_priv, *back_priv;
glamor_pixmap_fbo *temp_fbo;
front_priv = glamor_get_pixmap_private(front);
back_priv = glamor_get_pixmap_private(back);
temp_fbo = front_priv->fbo;
front_priv->fbo = back_priv->fbo;
back_priv->fbo = temp_fbo;
}
xorg-server-21.1.4/glamor/glamor.h 0000644 0001750 0001750 00000041711 14263273335 013732 0000000 0000000 /*
* 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
* Zhigang Gong
*
*/
#ifndef GLAMOR_H
#define GLAMOR_H
#include
#include
#include
#include
#include
#include
#ifdef GLAMOR_FOR_XORG
#include
#endif
struct glamor_context;
struct gbm_bo;
struct gbm_device;
/*
* glamor_pixmap_type : glamor pixmap's type.
* @MEMORY: pixmap is in memory.
* @TEXTURE_DRM: pixmap is in a texture created from a DRM buffer.
* @SEPARATE_TEXTURE: The texture is created from a DRM buffer, but
* the format is incompatible, so this type of pixmap
* will never fallback to DDX layer.
* @DRM_ONLY: pixmap is in a external DRM buffer.
* @TEXTURE_ONLY: pixmap is in an internal texture.
*/
typedef enum glamor_pixmap_type {
GLAMOR_MEMORY = 0, /* Newly calloc()ed pixmaps are memory. */
GLAMOR_TEXTURE_DRM,
GLAMOR_DRM_ONLY,
GLAMOR_TEXTURE_ONLY,
} glamor_pixmap_type_t;
typedef Bool (*GetDrawableModifiersFuncPtr) (DrawablePtr draw,
uint32_t format,
uint32_t *num_modifiers,
uint64_t **modifiers);
#define GLAMOR_EGL_EXTERNAL_BUFFER 3
#define GLAMOR_USE_EGL_SCREEN (1 << 0)
#define GLAMOR_NO_DRI3 (1 << 1)
#define GLAMOR_VALID_FLAGS (GLAMOR_USE_EGL_SCREEN \
| GLAMOR_NO_DRI3)
/* until we need geometry shaders GL3.1 should suffice. */
#define GLAMOR_GL_CORE_VER_MAJOR 3
#define GLAMOR_GL_CORE_VER_MINOR 1
/* @glamor_init: Initialize glamor internal data structure.
*
* @screen: Current screen pointer.
* @flags: Please refer the flags description above.
*
* @GLAMOR_USE_EGL_SCREEN:
* If you are using EGL layer, then please set this bit
* on, otherwise, clear it.
*
* @GLAMOR_NO_DRI3
* Disable the built-in DRI3 support
*
* This function initializes necessary internal data structure
* for glamor. And before calling into this function, the OpenGL
* environment should be ready. Should be called before any real
* glamor rendering or texture allocation functions. And should
* be called after the DDX's screen initialization or at the last
* step of the DDX's screen initialization.
*/
extern _X_EXPORT Bool glamor_init(ScreenPtr screen, unsigned int flags);
extern _X_EXPORT void glamor_fini(ScreenPtr screen);
/* This function is used to free the glamor private screen's
* resources. If the DDX driver is not set GLAMOR_USE_SCREEN,
* then, DDX need to call this function at proper stage, if
* it is the xorg DDX driver,then it should be called at free
* screen stage not the close screen stage. The reason is after
* call to this function, the xorg DDX may need to destroy the
* screen pixmap which must be a glamor pixmap and requires
* the internal data structure still exist at that time.
* Otherwise, the glamor internal structure will not be freed.*/
extern _X_EXPORT Bool glamor_close_screen(ScreenPtr screen);
extern _X_EXPORT uint32_t glamor_get_pixmap_texture(PixmapPtr pixmap);
extern _X_EXPORT Bool glamor_set_pixmap_texture(PixmapPtr pixmap,
unsigned int tex);
extern _X_EXPORT void glamor_set_pixmap_type(PixmapPtr pixmap,
glamor_pixmap_type_t type);
extern _X_EXPORT void glamor_clear_pixmap(PixmapPtr pixmap);
extern _X_EXPORT void glamor_block_handler(ScreenPtr screen);
extern _X_EXPORT PixmapPtr glamor_create_pixmap(ScreenPtr screen, int w, int h,
int depth, unsigned int usage);
extern _X_EXPORT Bool glamor_destroy_pixmap(PixmapPtr pixmap);
#define GLAMOR_CREATE_PIXMAP_CPU 0x100
#define GLAMOR_CREATE_PIXMAP_FIXUP 0x101
#define GLAMOR_CREATE_FBO_NO_FBO 0x103
#define GLAMOR_CREATE_NO_LARGE 0x105
#define GLAMOR_CREATE_PIXMAP_NO_TEXTURE 0x106
#define GLAMOR_CREATE_FORMAT_CBCR 0x107
/* @glamor_egl_exchange_buffers: Exchange the underlying buffers(KHR image,fbo).
*
* @front: front pixmap.
* @back: back pixmap.
*
* Used by the DRI2 page flip. This function will exchange the KHR images and
* fbos of the two pixmaps.
* */
extern _X_EXPORT void glamor_egl_exchange_buffers(PixmapPtr front,
PixmapPtr back);
extern _X_EXPORT void glamor_pixmap_exchange_fbos(PixmapPtr front,
PixmapPtr back);
/* The DDX is not supposed to call these four functions */
extern _X_EXPORT void glamor_enable_dri3(ScreenPtr screen);
extern _X_EXPORT int glamor_egl_fds_from_pixmap(ScreenPtr, PixmapPtr, int *,
uint32_t *, uint32_t *,
uint64_t *);
extern _X_EXPORT int glamor_egl_fd_name_from_pixmap(ScreenPtr, PixmapPtr,
CARD16 *, CARD32 *);
extern _X_EXPORT struct gbm_device *glamor_egl_get_gbm_device(ScreenPtr screen);
extern _X_EXPORT int glamor_egl_fd_from_pixmap(ScreenPtr, PixmapPtr, CARD16 *, CARD32 *);
/* @glamor_supports_pixmap_import_export: Returns whether
* glamor_fds_from_pixmap(), glamor_name_from_pixmap(), and
* glamor_pixmap_from_fds() are supported.
*
* @screen: Current screen pointer.
*
* To have DRI3 support enabled, glamor and glamor_egl need to be
* initialized. glamor also has to be compiled with gbm support.
*
* The EGL layer needs to have the following extensions working:
*
* .EGL_KHR_surfaceless_context
* */
extern _X_EXPORT Bool glamor_supports_pixmap_import_export(ScreenPtr screen);
/* @glamor_fds_from_pixmap: Get a dma-buf fd from a pixmap.
*
* @screen: Current screen pointer.
* @pixmap: The pixmap from which we want the fd.
* @fds, @strides, @offsets: Pointers to fill info of each plane.
* @modifier: Pointer to fill the modifier of the buffer.
*
* the pixmap and the buffer associated by the fds will share the same
* content. The caller is responsible to close the returned file descriptors.
* Returns the number of planes, -1 on error.
* */
extern _X_EXPORT int glamor_fds_from_pixmap(ScreenPtr screen,
PixmapPtr pixmap,
int *fds,
uint32_t *strides, uint32_t *offsets,
uint64_t *modifier);
/* @glamor_fd_from_pixmap: Get a dma-buf fd from a pixmap.
*
* @screen: Current screen pointer.
* @pixmap: The pixmap from which we want the fd.
* @stride, @size: Pointers to fill the stride and size of the
* buffer associated to the fd.
*
* the pixmap and the buffer associated by the fd will share the same
* content.
* Returns the fd on success, -1 on error.
* */
extern _X_EXPORT int glamor_fd_from_pixmap(ScreenPtr screen,
PixmapPtr pixmap,
CARD16 *stride, CARD32 *size);
/* @glamor_shareable_fd_from_pixmap: Get a dma-buf fd suitable for sharing
* with other GPUs from a pixmap.
*
* @screen: Current screen pointer.
* @pixmap: The pixmap from which we want the fd.
* @stride, @size: Pointers to fill the stride and size of the
* buffer associated to the fd.
*
* The returned fd will point to a buffer which is suitable for sharing
* across GPUs (not using GPU specific tiling).
* The pixmap and the buffer associated by the fd will share the same
* content.
* The pixmap's stride may be modified by this function.
* Returns the fd on success, -1 on error.
* */
extern _X_EXPORT int glamor_shareable_fd_from_pixmap(ScreenPtr screen,
PixmapPtr pixmap,
CARD16 *stride,
CARD32 *size);
/**
* @glamor_name_from_pixmap: Gets a gem name from a pixmap.
*
* @pixmap: The pixmap from which we want the gem name.
*
* the pixmap and the buffer associated by the gem name will share the
* same content. This function can be used by the DDX to support DRI2,
* and needs the same set of buffer export GL extensions as DRI3
* support.
*
* Returns the name on success, -1 on error.
* */
extern _X_EXPORT int glamor_name_from_pixmap(PixmapPtr pixmap,
CARD16 *stride, CARD32 *size);
/* @glamor_gbm_bo_from_pixmap: Get a GBM bo from a pixmap.
*
* @screen: Current screen pointer.
* @pixmap: The pixmap from which we want the fd.
* @stride, @size: Pointers to fill the stride and size of the
* buffer associated to the fd.
*
* the pixmap and the buffer represented by the gbm_bo will share the same
* content.
*
* Returns the gbm_bo on success, NULL on error.
* */
extern _X_EXPORT struct gbm_bo *glamor_gbm_bo_from_pixmap(ScreenPtr screen,
PixmapPtr pixmap);
/* @glamor_pixmap_from_fds: Creates a pixmap to wrap a dma-buf fds.
*
* @screen: Current screen pointer.
* @num_fds: Number of fds to import
* @fds: The dma-buf fds to import.
* @width: The width of the buffers.
* @height: The height of the buffers.
* @stride: The stride of the buffers.
* @depth: The depth of the buffers.
* @bpp: The bpp of the buffers.
* @modifier: The modifier of the buffers.
*
* Returns a valid pixmap if the import succeeded, else NULL.
* */
extern _X_EXPORT PixmapPtr glamor_pixmap_from_fds(ScreenPtr screen,
CARD8 num_fds,
const int *fds,
CARD16 width,
CARD16 height,
const CARD32 *strides,
const CARD32 *offsets,
CARD8 depth,
CARD8 bpp,
uint64_t modifier);
/* @glamor_pixmap_from_fd: Creates a pixmap to wrap a dma-buf fd.
*
* @screen: Current screen pointer.
* @fd: The dma-buf fd to import.
* @width: The width of the buffer.
* @height: The height of the buffer.
* @stride: The stride of the buffer.
* @depth: The depth of the buffer.
* @bpp: The bpp of the buffer.
*
* Returns a valid pixmap if the import succeeded, else NULL.
* */
extern _X_EXPORT PixmapPtr glamor_pixmap_from_fd(ScreenPtr screen,
int fd,
CARD16 width,
CARD16 height,
CARD16 stride,
CARD8 depth,
CARD8 bpp);
/* @glamor_back_pixmap_from_fd: Backs an existing pixmap with a dma-buf fd.
*
* @pixmap: Pixmap to change backing for
* @fd: The dma-buf fd to import.
* @width: The width of the buffer.
* @height: The height of the buffer.
* @stride: The stride of the buffer.
* @depth: The depth of the buffer.
* @bpp: The number of bpp of the buffer.
*
* Returns TRUE if successful, FALSE on failure.
* */
extern _X_EXPORT Bool glamor_back_pixmap_from_fd(PixmapPtr pixmap,
int fd,
CARD16 width,
CARD16 height,
CARD16 stride,
CARD8 depth,
CARD8 bpp);
extern _X_EXPORT Bool glamor_get_formats(ScreenPtr screen,
CARD32 *num_formats,
CARD32 **formats);
extern _X_EXPORT Bool glamor_get_modifiers(ScreenPtr screen,
uint32_t format,
uint32_t *num_modifiers,
uint64_t **modifiers);
extern _X_EXPORT Bool glamor_get_drawable_modifiers(DrawablePtr draw,
uint32_t format,
uint32_t *num_modifiers,
uint64_t **modifiers);
extern _X_EXPORT void glamor_set_drawable_modifiers_func(ScreenPtr screen,
GetDrawableModifiersFuncPtr func);
#ifdef GLAMOR_FOR_XORG
#define GLAMOR_EGL_MODULE_NAME "glamoregl"
/* @glamor_egl_init: Initialize EGL environment.
*
* @scrn: Current screen info pointer.
* @fd: Current drm fd.
*
* This function creates and initializes EGL contexts.
* Should be called from DDX's preInit function.
* Return TRUE if success, otherwise return FALSE.
* */
extern _X_EXPORT Bool glamor_egl_init(ScrnInfoPtr scrn, int fd);
extern _X_EXPORT Bool glamor_egl_init_textured_pixmap(ScreenPtr screen);
/* @glamor_egl_create_textured_screen: Create textured screen pixmap.
*
* @screen: screen pointer to be processed.
* @handle: screen pixmap's BO handle.
* @stride: screen pixmap's stride in bytes.
*
* This function is similar with the create_textured_pixmap. As the
* screen pixmap is a special, we handle it separately in this function.
*/
extern _X_EXPORT Bool glamor_egl_create_textured_screen(ScreenPtr screen,
int handle, int stride);
/* Obsolete entrypoint, temporarily left here for API compatibility
* for xf86-video-ati.
*/
#define glamor_egl_create_textured_screen_ext(a, b, c, d) \
glamor_egl_create_textured_screen(a, b, c)
/*
* @glamor_egl_create_textured_pixmap: Try to create a textured pixmap from
* a BO handle.
*
* @pixmap: The pixmap need to be processed.
* @handle: The BO's handle attached to this pixmap at DDX layer.
* @stride: Stride in bytes for this pixmap.
*
* This function try to create a texture from the handle and attach
* the texture to the pixmap , thus glamor can render to this pixmap
* as well. Return true if successful, otherwise return FALSE.
*/
extern _X_EXPORT Bool glamor_egl_create_textured_pixmap(PixmapPtr pixmap,
int handle, int stride);
/*
* @glamor_egl_create_textured_pixmap_from_bo: Try to create a textured pixmap
* from a gbm_bo.
*
* @pixmap: The pixmap need to be processed.
* @bo: a pointer on a gbm_bo structure attached to this pixmap at DDX layer.
*
* This function is similar to glamor_egl_create_textured_pixmap.
*/
extern _X_EXPORT Bool
glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap,
struct gbm_bo *bo,
Bool used_modifiers);
extern _X_EXPORT const char *glamor_egl_get_driver_name(ScreenPtr screen);
#endif
extern _X_EXPORT void glamor_egl_screen_init(ScreenPtr screen,
struct glamor_context *glamor_ctx);
extern _X_EXPORT int glamor_create_gc(GCPtr gc);
extern _X_EXPORT void glamor_validate_gc(GCPtr gc, unsigned long changes,
DrawablePtr drawable);
extern _X_EXPORT void glamor_destroy_gc(GCPtr gc);
#define HAS_GLAMOR_DESTROY_GC 1
extern Bool _X_EXPORT glamor_change_window_attributes(WindowPtr pWin, unsigned long mask);
extern void _X_EXPORT glamor_copy_window(WindowPtr window, DDXPointRec old_origin, RegionPtr src_region);
extern _X_EXPORT void glamor_finish(ScreenPtr screen);
#define HAS_GLAMOR_TEXT 1
#ifdef GLAMOR_FOR_XORG
extern _X_EXPORT XF86VideoAdaptorPtr glamor_xv_init(ScreenPtr pScreen,
int num_texture_ports);
#endif
#endif /* GLAMOR_H */
xorg-server-21.1.4/glamor/glamor_debug.h 0000644 0001750 0001750 00000005200 14263273335 015071 0000000 0000000 /*
* Copyright © 2009 Intel Corporation
* Copyright © 1998 Keith Packard
*
* 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:
* Zhigang Gong
*
*/
#ifndef __GLAMOR_DEBUG_H__
#define __GLAMOR_DEBUG_H__
#define GLAMOR_DEBUG_NONE 0
#define GLAMOR_DEBUG_UNIMPL 0
#define GLAMOR_DEBUG_FALLBACK 1
#define GLAMOR_DEBUG_TEXTURE_DOWNLOAD 2
#define GLAMOR_DEBUG_TEXTURE_DYNAMIC_UPLOAD 3
extern void
AbortServer(void)
_X_NORETURN;
#define GLAMOR_PANIC(_format_, ...) \
do { \
LogMessageVerb(X_NONE, 0, "Glamor Fatal Error" \
" at %32s line %d: " _format_ "\n", \
__FUNCTION__, __LINE__, \
##__VA_ARGS__ ); \
exit(1); \
} while(0)
#define __debug_output_message(_format_, _prefix_, ...) \
LogMessageVerb(X_NONE, 0, \
"%32s:\t" _format_ , \
/*_prefix_,*/ \
__FUNCTION__, \
##__VA_ARGS__)
#define glamor_debug_output(_level_, _format_,...) \
do { \
if (glamor_debug_level >= _level_) \
__debug_output_message(_format_, \
"Glamor debug", \
##__VA_ARGS__); \
} while(0)
#define glamor_fallback(_format_,...) \
do { \
if (glamor_debug_level >= GLAMOR_DEBUG_FALLBACK) \
__debug_output_message(_format_, \
"Glamor fallback", \
##__VA_ARGS__);} while(0)
#define DEBUGF(str, ...) do {} while(0)
//#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
#define DEBUGRegionPrint(x) do {} while (0)
//#define DEBUGRegionPrint RegionPrint
#endif
xorg-server-21.1.4/glamor/glamor_largepixmap.c 0000644 0001750 0001750 00000170233 14263273335 016320 0000000 0000000 #include
#include /* For INT16_MAX */
#include "glamor_priv.h"
static void
glamor_get_transform_extent_from_box(struct pixman_box32 *box,
struct pixman_transform *transform);
static inline glamor_pixmap_private *
__glamor_large(glamor_pixmap_private *pixmap_priv) {
assert(glamor_pixmap_priv_is_large(pixmap_priv));
return pixmap_priv;
}
/**
* Clip the boxes regards to each pixmap's block array.
*
* Should translate the region to relative coords to the pixmap,
* start at (0,0).
*/
#if 0
//#define DEBUGF(str, ...) do {} while(0)
#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
//#define DEBUGRegionPrint(x) do {} while (0)
#define DEBUGRegionPrint RegionPrint
#endif
static glamor_pixmap_clipped_regions *
__glamor_compute_clipped_regions(int block_w,
int block_h,
int block_stride,
int x, int y,
int w, int h,
RegionPtr region,
int *n_region, int reverse, int upsidedown)
{
glamor_pixmap_clipped_regions *clipped_regions;
BoxPtr extent;
int start_x, start_y, end_x, end_y;
int start_block_x, start_block_y;
int end_block_x, end_block_y;
int loop_start_block_x, loop_start_block_y;
int loop_end_block_x, loop_end_block_y;
int loop_block_stride;
int i, j, delta_i, delta_j;
RegionRec temp_region;
RegionPtr current_region;
int block_idx;
int k = 0;
int temp_block_idx;
extent = RegionExtents(region);
start_x = MAX(x, extent->x1);
start_y = MAX(y, extent->y1);
end_x = MIN(x + w, extent->x2);
end_y = MIN(y + h, extent->y2);
DEBUGF("start compute clipped regions:\n");
DEBUGF("block w %d h %d x %d y %d w %d h %d, block_stride %d \n",
block_w, block_h, x, y, w, h, block_stride);
DEBUGRegionPrint(region);
DEBUGF("start_x %d start_y %d end_x %d end_y %d \n", start_x, start_y,
end_x, end_y);
if (start_x >= end_x || start_y >= end_y) {
*n_region = 0;
return NULL;
}
start_block_x = (start_x - x) / block_w;
start_block_y = (start_y - y) / block_h;
end_block_x = (end_x - x) / block_w;
end_block_y = (end_y - y) / block_h;
clipped_regions = calloc((end_block_x - start_block_x + 1)
* (end_block_y - start_block_y + 1),
sizeof(*clipped_regions));
DEBUGF("startx %d starty %d endx %d endy %d \n",
start_x, start_y, end_x, end_y);
DEBUGF("start_block_x %d end_block_x %d \n", start_block_x, end_block_x);
DEBUGF("start_block_y %d end_block_y %d \n", start_block_y, end_block_y);
if (!reverse) {
loop_start_block_x = start_block_x;
loop_end_block_x = end_block_x + 1;
delta_i = 1;
}
else {
loop_start_block_x = end_block_x;
loop_end_block_x = start_block_x - 1;
delta_i = -1;
}
if (!upsidedown) {
loop_start_block_y = start_block_y;
loop_end_block_y = end_block_y + 1;
delta_j = 1;
}
else {
loop_start_block_y = end_block_y;
loop_end_block_y = start_block_y - 1;
delta_j = -1;
}
loop_block_stride = delta_j * block_stride;
block_idx = (loop_start_block_y - delta_j) * block_stride;
for (j = loop_start_block_y; j != loop_end_block_y; j += delta_j) {
block_idx += loop_block_stride;
temp_block_idx = block_idx + loop_start_block_x;
for (i = loop_start_block_x;
i != loop_end_block_x; i += delta_i, temp_block_idx += delta_i) {
BoxRec temp_box;
temp_box.x1 = x + i * block_w;
temp_box.y1 = y + j * block_h;
temp_box.x2 = MIN(temp_box.x1 + block_w, end_x);
temp_box.y2 = MIN(temp_box.y1 + block_h, end_y);
RegionInitBoxes(&temp_region, &temp_box, 1);
DEBUGF("block idx %d \n", temp_block_idx);
DEBUGRegionPrint(&temp_region);
current_region = RegionCreate(NULL, 4);
RegionIntersect(current_region, &temp_region, region);
DEBUGF("i %d j %d region: \n", i, j);
DEBUGRegionPrint(current_region);
if (RegionNumRects(current_region)) {
clipped_regions[k].region = current_region;
clipped_regions[k].block_idx = temp_block_idx;
k++;
}
else
RegionDestroy(current_region);
RegionUninit(&temp_region);
}
}
*n_region = k;
return clipped_regions;
}
/**
* Do a two round clipping,
* first is to clip the region regard to current pixmap's
* block array. Then for each clipped region, do a inner
* block clipping. This is to make sure the final result
* will be shapped by inner_block_w and inner_block_h, and
* the final region also will not cross the pixmap's block
* boundary.
*
* This is mainly used by transformation support when do
* compositing.
*/
glamor_pixmap_clipped_regions *
glamor_compute_clipped_regions_ext(PixmapPtr pixmap,
RegionPtr region,
int *n_region,
int inner_block_w, int inner_block_h,
int reverse, int upsidedown)
{
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
glamor_pixmap_clipped_regions *clipped_regions, *inner_regions,
*result_regions;
int i, j, x, y, k, inner_n_regions;
int width, height;
BoxPtr box_array;
BoxRec small_box;
int block_w, block_h;
DEBUGF("ext called \n");
if (glamor_pixmap_priv_is_small(pixmap_priv)) {
clipped_regions = calloc(1, sizeof(*clipped_regions));
if (clipped_regions == NULL) {
*n_region = 0;
return NULL;
}
clipped_regions[0].region = RegionCreate(NULL, 1);
clipped_regions[0].block_idx = 0;
RegionCopy(clipped_regions[0].region, region);
*n_region = 1;
block_w = pixmap->drawable.width;
block_h = pixmap->drawable.height;
box_array = &small_box;
small_box.x1 = small_box.y1 = 0;
small_box.x2 = block_w;
small_box.y2 = block_h;
}
else {
glamor_pixmap_private *priv = __glamor_large(pixmap_priv);
clipped_regions = __glamor_compute_clipped_regions(priv->block_w,
priv->block_h,
priv->block_wcnt,
0, 0,
pixmap->drawable.width,
pixmap->drawable.height,
region, n_region,
reverse, upsidedown);
if (clipped_regions == NULL) {
*n_region = 0;
return NULL;
}
block_w = priv->block_w;
block_h = priv->block_h;
box_array = priv->box_array;
}
if (inner_block_w >= block_w && inner_block_h >= block_h)
return clipped_regions;
result_regions = calloc(*n_region
* ((block_w + inner_block_w - 1) /
inner_block_w)
* ((block_h + inner_block_h - 1) /
inner_block_h), sizeof(*result_regions));
k = 0;
for (i = 0; i < *n_region; i++) {
x = box_array[clipped_regions[i].block_idx].x1;
y = box_array[clipped_regions[i].block_idx].y1;
width = box_array[clipped_regions[i].block_idx].x2 - x;
height = box_array[clipped_regions[i].block_idx].y2 - y;
inner_regions = __glamor_compute_clipped_regions(inner_block_w,
inner_block_h,
0, x, y,
width,
height,
clipped_regions[i].
region,
&inner_n_regions,
reverse, upsidedown);
for (j = 0; j < inner_n_regions; j++) {
result_regions[k].region = inner_regions[j].region;
result_regions[k].block_idx = clipped_regions[i].block_idx;
k++;
}
free(inner_regions);
}
*n_region = k;
free(clipped_regions);
return result_regions;
}
/*
*
* For the repeat pad mode, we can simply convert the region and
* let the out-of-box region can cover the needed edge of the source/mask
* Then apply a normal clip we can get what we want.
*/
static RegionPtr
_glamor_convert_pad_region(RegionPtr region, int w, int h)
{
RegionPtr pad_region;
int nrect;
BoxPtr box;
int overlap;
nrect = RegionNumRects(region);
box = RegionRects(region);
pad_region = RegionCreate(NULL, 4);
if (pad_region == NULL)
return NULL;
while (nrect--) {
BoxRec pad_box;
RegionRec temp_region;
pad_box = *box;
if (pad_box.x1 < 0 && pad_box.x2 <= 0)
pad_box.x2 = 1;
else if (pad_box.x1 >= w && pad_box.x2 > w)
pad_box.x1 = w - 1;
if (pad_box.y1 < 0 && pad_box.y2 <= 0)
pad_box.y2 = 1;
else if (pad_box.y1 >= h && pad_box.y2 > h)
pad_box.y1 = h - 1;
RegionInitBoxes(&temp_region, &pad_box, 1);
RegionAppend(pad_region, &temp_region);
RegionUninit(&temp_region);
box++;
}
RegionValidate(pad_region, &overlap);
return pad_region;
}
/*
* For one type of large pixmap, its one direction is not exceed the
* size limitation, and in another word, on one direction it has only
* one block.
*
* This case of reflect repeating, we can optimize it and avoid repeat
* clip on that direction. We can just enlarge the repeat box and can
* cover all the dest region on that direction. But latter, we need to
* fixup the clipped result to get a correct coords for the subsequent
* processing. This function is to do the coords correction.
*
* */
static void
_glamor_largepixmap_reflect_fixup(short *xy1, short *xy2, int wh)
{
int odd1, odd2;
int c1, c2;
if (*xy2 - *xy1 > wh) {
*xy1 = 0;
*xy2 = wh;
return;
}
modulus(*xy1, wh, c1);
odd1 = ((*xy1 - c1) / wh) & 0x1;
modulus(*xy2, wh, c2);
odd2 = ((*xy2 - c2) / wh) & 0x1;
if (odd1 && odd2) {
*xy1 = wh - c2;
*xy2 = wh - c1;
}
else if (odd1 && !odd2) {
*xy1 = 0;
*xy2 = MAX(c2, wh - c1);
}
else if (!odd1 && odd2) {
*xy2 = wh;
*xy1 = MIN(c1, wh - c2);
}
else {
*xy1 = c1;
*xy2 = c2;
}
}
/**
* Clip the boxes regards to each pixmap's block array.
*
* Should translate the region to relative coords to the pixmap,
* start at (0,0).
*
* @is_transform: if it is set, it has a transform matrix.
*
*/
static glamor_pixmap_clipped_regions *
_glamor_compute_clipped_regions(PixmapPtr pixmap,
glamor_pixmap_private *pixmap_priv,
RegionPtr region, int *n_region,
int repeat_type, int is_transform,
int reverse, int upsidedown)
{
glamor_pixmap_clipped_regions *clipped_regions;
BoxPtr extent;
int i, j;
RegionPtr current_region;
int pixmap_width, pixmap_height;
int m;
BoxRec repeat_box;
RegionRec repeat_region;
int right_shift = 0;
int down_shift = 0;
int x_center_shift = 0, y_center_shift = 0;
glamor_pixmap_private *priv;
DEBUGRegionPrint(region);
if (glamor_pixmap_priv_is_small(pixmap_priv)) {
clipped_regions = calloc(1, sizeof(*clipped_regions));
clipped_regions[0].region = RegionCreate(NULL, 1);
clipped_regions[0].block_idx = 0;
RegionCopy(clipped_regions[0].region, region);
*n_region = 1;
return clipped_regions;
}
priv = __glamor_large(pixmap_priv);
pixmap_width = pixmap->drawable.width;
pixmap_height = pixmap->drawable.height;
if (repeat_type == 0 || repeat_type == RepeatPad) {
RegionPtr saved_region = NULL;
if (repeat_type == RepeatPad) {
saved_region = region;
region =
_glamor_convert_pad_region(saved_region, pixmap_width,
pixmap_height);
if (region == NULL) {
*n_region = 0;
return NULL;
}
}
clipped_regions = __glamor_compute_clipped_regions(priv->block_w,
priv->block_h,
priv->block_wcnt,
0, 0,
pixmap->drawable.width,
pixmap->drawable.height,
region, n_region,
reverse, upsidedown);
if (saved_region)
RegionDestroy(region);
return clipped_regions;
}
extent = RegionExtents(region);
x_center_shift = extent->x1 / pixmap_width;
if (x_center_shift < 0)
x_center_shift--;
if (abs(x_center_shift) & 1)
x_center_shift++;
y_center_shift = extent->y1 / pixmap_height;
if (y_center_shift < 0)
y_center_shift--;
if (abs(y_center_shift) & 1)
y_center_shift++;
if (extent->x1 < 0)
right_shift = ((-extent->x1 + pixmap_width - 1) / pixmap_width);
if (extent->y1 < 0)
down_shift = ((-extent->y1 + pixmap_height - 1) / pixmap_height);
if (right_shift != 0 || down_shift != 0) {
if (repeat_type == RepeatReflect) {
right_shift = (right_shift + 1) & ~1;
down_shift = (down_shift + 1) & ~1;
}
RegionTranslate(region, right_shift * pixmap_width,
down_shift * pixmap_height);
}
extent = RegionExtents(region);
/* Tile a large pixmap to another large pixmap.
* We can't use the target large pixmap as the
* loop variable, instead we need to loop for all
* the blocks in the tile pixmap.
*
* simulate repeat each single block to cover the
* target's blocks. Two special case:
* a block_wcnt == 1 or block_hcnt ==1, then we
* only need to loop one direction as the other
* direction is fully included in the first block.
*
* For the other cases, just need to start
* from a proper shiftx/shifty, and then increase
* y by tile_height each time to walk trhough the
* target block and then walk trhough the target
* at x direction by increate tile_width each time.
*
* This way, we can consolidate all the sub blocks
* of the target boxes into one tile source's block.
*
* */
m = 0;
clipped_regions = calloc(priv->block_wcnt * priv->block_hcnt,
sizeof(*clipped_regions));
if (clipped_regions == NULL) {
*n_region = 0;
return NULL;
}
if (right_shift != 0 || down_shift != 0) {
DEBUGF("region to be repeated shifted \n");
DEBUGRegionPrint(region);
}
DEBUGF("repeat pixmap width %d height %d \n", pixmap_width, pixmap_height);
DEBUGF("extent x1 %d y1 %d x2 %d y2 %d \n", extent->x1, extent->y1,
extent->x2, extent->y2);
for (j = 0; j < priv->block_hcnt; j++) {
for (i = 0; i < priv->block_wcnt; i++) {
int dx = pixmap_width;
int dy = pixmap_height;
int idx;
int shift_x;
int shift_y;
int saved_y1, saved_y2;
int x_idx = 0, y_idx = 0, saved_y_idx = 0;
RegionRec temp_region;
BoxRec reflect_repeat_box;
BoxPtr valid_repeat_box;
shift_x = (extent->x1 / pixmap_width) * pixmap_width;
shift_y = (extent->y1 / pixmap_height) * pixmap_height;
idx = j * priv->block_wcnt + i;
if (repeat_type == RepeatReflect) {
x_idx = (extent->x1 / pixmap_width);
y_idx = (extent->y1 / pixmap_height);
}
/* Construct a rect to clip the target region. */
repeat_box.x1 = shift_x + priv->box_array[idx].x1;
repeat_box.y1 = shift_y + priv->box_array[idx].y1;
if (priv->block_wcnt == 1) {
repeat_box.x2 = extent->x2;
dx = extent->x2 - repeat_box.x1;
}
else
repeat_box.x2 = shift_x + priv->box_array[idx].x2;
if (priv->block_hcnt == 1) {
repeat_box.y2 = extent->y2;
dy = extent->y2 - repeat_box.y1;
}
else
repeat_box.y2 = shift_y + priv->box_array[idx].y2;
current_region = RegionCreate(NULL, 4);
RegionInit(&temp_region, NULL, 4);
DEBUGF("init repeat box %d %d %d %d \n",
repeat_box.x1, repeat_box.y1, repeat_box.x2, repeat_box.y2);
if (repeat_type == RepeatNormal) {
saved_y1 = repeat_box.y1;
saved_y2 = repeat_box.y2;
for (; repeat_box.x1 < extent->x2;
repeat_box.x1 += dx, repeat_box.x2 += dx) {
repeat_box.y1 = saved_y1;
repeat_box.y2 = saved_y2;
for (repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;
repeat_box.y1 < extent->y2;
repeat_box.y1 += dy, repeat_box.y2 += dy) {
RegionInitBoxes(&repeat_region, &repeat_box, 1);
DEBUGF("Start to clip repeat region: \n");
DEBUGRegionPrint(&repeat_region);
RegionIntersect(&temp_region, &repeat_region, region);
DEBUGF("clip result:\n");
DEBUGRegionPrint(&temp_region);
RegionAppend(current_region, &temp_region);
RegionUninit(&repeat_region);
}
}
}
else if (repeat_type == RepeatReflect) {
saved_y1 = repeat_box.y1;
saved_y2 = repeat_box.y2;
saved_y_idx = y_idx;
for (;; repeat_box.x1 += dx, repeat_box.x2 += dx) {
repeat_box.y1 = saved_y1;
repeat_box.y2 = saved_y2;
y_idx = saved_y_idx;
reflect_repeat_box.x1 = (x_idx & 1) ?
((2 * x_idx + 1) * dx - repeat_box.x2) : repeat_box.x1;
reflect_repeat_box.x2 = (x_idx & 1) ?
((2 * x_idx + 1) * dx - repeat_box.x1) : repeat_box.x2;
valid_repeat_box = &reflect_repeat_box;
if (valid_repeat_box->x1 >= extent->x2)
break;
for (repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;;
repeat_box.y1 += dy, repeat_box.y2 += dy) {
DEBUGF("x_idx %d y_idx %d dx %d dy %d\n", x_idx, y_idx,
dx, dy);
DEBUGF("repeat box %d %d %d %d \n", repeat_box.x1,
repeat_box.y1, repeat_box.x2, repeat_box.y2);
if (priv->block_hcnt > 1) {
reflect_repeat_box.y1 = (y_idx & 1) ?
((2 * y_idx + 1) * dy -
repeat_box.y2) : repeat_box.y1;
reflect_repeat_box.y2 =
(y_idx & 1) ? ((2 * y_idx + 1) * dy -
repeat_box.y1) : repeat_box.y2;
}
else {
reflect_repeat_box.y1 = repeat_box.y1;
reflect_repeat_box.y2 = repeat_box.y2;
}
DEBUGF("valid_repeat_box x1 %d y1 %d \n",
valid_repeat_box->x1, valid_repeat_box->y1);
if (valid_repeat_box->y1 >= extent->y2)
break;
RegionInitBoxes(&repeat_region, valid_repeat_box, 1);
DEBUGF("start to clip repeat[reflect] region: \n");
DEBUGRegionPrint(&repeat_region);
RegionIntersect(&temp_region, &repeat_region, region);
DEBUGF("result:\n");
DEBUGRegionPrint(&temp_region);
if (is_transform && RegionNumRects(&temp_region)) {
BoxRec temp_box;
BoxPtr temp_extent;
temp_extent = RegionExtents(&temp_region);
if (priv->block_wcnt > 1) {
if (x_idx & 1) {
temp_box.x1 =
((2 * x_idx + 1) * dx -
temp_extent->x2);
temp_box.x2 =
((2 * x_idx + 1) * dx -
temp_extent->x1);
}
else {
temp_box.x1 = temp_extent->x1;
temp_box.x2 = temp_extent->x2;
}
modulus(temp_box.x1, pixmap_width, temp_box.x1);
modulus(temp_box.x2, pixmap_width, temp_box.x2);
if (temp_box.x2 == 0)
temp_box.x2 = pixmap_width;
}
else {
temp_box.x1 = temp_extent->x1;
temp_box.x2 = temp_extent->x2;
_glamor_largepixmap_reflect_fixup(&temp_box.x1,
&temp_box.x2,
pixmap_width);
}
if (priv->block_hcnt > 1) {
if (y_idx & 1) {
temp_box.y1 =
((2 * y_idx + 1) * dy -
temp_extent->y2);
temp_box.y2 =
((2 * y_idx + 1) * dy -
temp_extent->y1);
}
else {
temp_box.y1 = temp_extent->y1;
temp_box.y2 = temp_extent->y2;
}
modulus(temp_box.y1, pixmap_height,
temp_box.y1);
modulus(temp_box.y2, pixmap_height,
temp_box.y2);
if (temp_box.y2 == 0)
temp_box.y2 = pixmap_height;
}
else {
temp_box.y1 = temp_extent->y1;
temp_box.y2 = temp_extent->y2;
_glamor_largepixmap_reflect_fixup(&temp_box.y1,
&temp_box.y2,
pixmap_height);
}
RegionInitBoxes(&temp_region, &temp_box, 1);
RegionTranslate(&temp_region,
x_center_shift * pixmap_width,
y_center_shift * pixmap_height);
DEBUGF("for transform result:\n");
DEBUGRegionPrint(&temp_region);
}
RegionAppend(current_region, &temp_region);
RegionUninit(&repeat_region);
y_idx++;
}
x_idx++;
}
}
DEBUGF("dx %d dy %d \n", dx, dy);
if (RegionNumRects(current_region)) {
if ((right_shift != 0 || down_shift != 0) &&
!(is_transform && repeat_type == RepeatReflect))
RegionTranslate(current_region, -right_shift * pixmap_width,
-down_shift * pixmap_height);
clipped_regions[m].region = current_region;
clipped_regions[m].block_idx = idx;
m++;
}
else
RegionDestroy(current_region);
RegionUninit(&temp_region);
}
}
if (right_shift != 0 || down_shift != 0)
RegionTranslate(region, -right_shift * pixmap_width,
-down_shift * pixmap_height);
*n_region = m;
return clipped_regions;
}
glamor_pixmap_clipped_regions *
glamor_compute_clipped_regions(PixmapPtr pixmap,
RegionPtr region,
int *n_region, int repeat_type,
int reverse, int upsidedown)
{
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
return _glamor_compute_clipped_regions(pixmap, priv, region, n_region, repeat_type,
0, reverse, upsidedown);
}
/* XXX overflow still exist. maybe we need to change to use region32.
* by default. Or just use region32 for repeat cases?
**/
static glamor_pixmap_clipped_regions *
glamor_compute_transform_clipped_regions(PixmapPtr pixmap,
struct pixman_transform *transform,
RegionPtr region, int *n_region,
int dx, int dy, int repeat_type,
int reverse, int upsidedown)
{
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
BoxPtr temp_extent;
struct pixman_box32 temp_box;
struct pixman_box16 short_box;
RegionPtr temp_region;
glamor_pixmap_clipped_regions *ret;
temp_region = RegionCreate(NULL, 4);
temp_extent = RegionExtents(region);
DEBUGF("dest region \n");
DEBUGRegionPrint(region);
/* dx/dy may exceed MAX SHORT. we have to use
* a box32 to represent it.*/
temp_box.x1 = temp_extent->x1 + dx;
temp_box.x2 = temp_extent->x2 + dx;
temp_box.y1 = temp_extent->y1 + dy;
temp_box.y2 = temp_extent->y2 + dy;
DEBUGF("source box %d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2,
temp_box.y2);
if (transform)
glamor_get_transform_extent_from_box(&temp_box, transform);
if (repeat_type == RepeatNone) {
if (temp_box.x1 < 0)
temp_box.x1 = 0;
if (temp_box.y1 < 0)
temp_box.y1 = 0;
temp_box.x2 = MIN(temp_box.x2, pixmap->drawable.width);
temp_box.y2 = MIN(temp_box.y2, pixmap->drawable.height);
}
/* Now copy back the box32 to a box16 box, avoiding overflow. */
short_box.x1 = MIN(temp_box.x1, INT16_MAX);
short_box.y1 = MIN(temp_box.y1, INT16_MAX);
short_box.x2 = MIN(temp_box.x2, INT16_MAX);
short_box.y2 = MIN(temp_box.y2, INT16_MAX);
RegionInitBoxes(temp_region, &short_box, 1);
DEBUGF("copy to temp source region \n");
DEBUGRegionPrint(temp_region);
ret = _glamor_compute_clipped_regions(pixmap,
priv,
temp_region,
n_region,
repeat_type, 1, reverse, upsidedown);
DEBUGF("n_regions = %d \n", *n_region);
RegionDestroy(temp_region);
return ret;
}
/*
* As transform and repeatpad mode.
* We may get a clipped result which in multiple regions.
* It's not easy to do a 2nd round clipping just as we do
* without transform/repeatPad. As it's not easy to reverse
* the 2nd round clipping result with a transform/repeatPad mode,
* or even impossible for some transformation.
*
* So we have to merge the fragmental region into one region
* if the clipped result cross the region boundary.
*/
static void
glamor_merge_clipped_regions(PixmapPtr pixmap,
glamor_pixmap_private *pixmap_priv,
int repeat_type,
glamor_pixmap_clipped_regions *clipped_regions,
int *n_regions, int *need_clean_fbo)
{
BoxRec temp_box, copy_box;
RegionPtr temp_region;
glamor_pixmap_private *temp_priv;
PixmapPtr temp_pixmap;
int overlap;
int i;
int pixmap_width, pixmap_height;
glamor_pixmap_private *priv;
priv = __glamor_large(pixmap_priv);
pixmap_width = pixmap->drawable.width;
pixmap_height =pixmap->drawable.height;
temp_region = RegionCreate(NULL, 4);
for (i = 0; i < *n_regions; i++) {
DEBUGF("Region %d:\n", i);
DEBUGRegionPrint(clipped_regions[i].region);
RegionAppend(temp_region, clipped_regions[i].region);
}
RegionValidate(temp_region, &overlap);
DEBUGF("temp region: \n");
DEBUGRegionPrint(temp_region);
temp_box = *RegionExtents(temp_region);
DEBUGF("need copy region: \n");
DEBUGF("%d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2,
temp_box.y2);
temp_pixmap =
glamor_create_pixmap(pixmap->drawable.pScreen,
temp_box.x2 - temp_box.x1,
temp_box.y2 - temp_box.y1,
pixmap->drawable.depth,
GLAMOR_CREATE_PIXMAP_FIXUP);
if (temp_pixmap == NULL) {
assert(0);
return;
}
temp_priv = glamor_get_pixmap_private(temp_pixmap);
assert(glamor_pixmap_priv_is_small(temp_priv));
priv->box = temp_box;
if (temp_box.x1 >= 0 && temp_box.x2 <= pixmap_width
&& temp_box.y1 >= 0 && temp_box.y2 <= pixmap_height) {
int dx, dy;
copy_box.x1 = 0;
copy_box.y1 = 0;
copy_box.x2 = temp_box.x2 - temp_box.x1;
copy_box.y2 = temp_box.y2 - temp_box.y1;
dx = temp_box.x1;
dy = temp_box.y1;
glamor_copy(&pixmap->drawable,
&temp_pixmap->drawable,
NULL, ©_box, 1, dx, dy, 0, 0, 0, NULL);
// glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width,
// temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff00);
}
else {
for (i = 0; i < *n_regions; i++) {
BoxPtr box;
int nbox;
box = REGION_RECTS(clipped_regions[i].region);
nbox = REGION_NUM_RECTS(clipped_regions[i].region);
while (nbox--) {
int dx, dy, c, d;
DEBUGF("box x1 %d y1 %d x2 %d y2 %d \n",
box->x1, box->y1, box->x2, box->y2);
modulus(box->x1, pixmap_width, c);
dx = c - (box->x1 - temp_box.x1);
copy_box.x1 = box->x1 - temp_box.x1;
copy_box.x2 = box->x2 - temp_box.x1;
modulus(box->y1, pixmap_height, d);
dy = d - (box->y1 - temp_box.y1);
copy_box.y1 = box->y1 - temp_box.y1;
copy_box.y2 = box->y2 - temp_box.y1;
DEBUGF("copying box %d %d %d %d, dx %d dy %d\n",
copy_box.x1, copy_box.y1, copy_box.x2,
copy_box.y2, dx, dy);
glamor_copy(&pixmap->drawable,
&temp_pixmap->drawable,
NULL, ©_box, 1, dx, dy, 0, 0, 0, NULL);
box++;
}
}
//glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width,
// temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff);
}
/* The first region will be released at caller side. */
for (i = 1; i < *n_regions; i++)
RegionDestroy(clipped_regions[i].region);
RegionDestroy(temp_region);
priv->box = temp_box;
priv->fbo = glamor_pixmap_detach_fbo(temp_priv);
DEBUGF("priv box x1 %d y1 %d x2 %d y2 %d \n",
priv->box.x1, priv->box.y1, priv->box.x2, priv->box.y2);
glamor_destroy_pixmap(temp_pixmap);
*need_clean_fbo = 1;
*n_regions = 1;
}
/**
* Given an expected transformed block width and block height,
*
* This function calculate a new block width and height which
* guarantee the transform result will not exceed the given
* block width and height.
*
* For large block width and height (> 2048), we choose a
* smaller new width and height and to reduce the cross region
* boundary and can avoid some overhead.
*
**/
static Bool
glamor_get_transform_block_size(struct pixman_transform *transform,
int block_w, int block_h,
int *transformed_block_w,
int *transformed_block_h)
{
double a, b, c, d, e, f, g, h;
double scale;
int width, height;
a = pixman_fixed_to_double(transform->matrix[0][0]);
b = pixman_fixed_to_double(transform->matrix[0][1]);
c = pixman_fixed_to_double(transform->matrix[1][0]);
d = pixman_fixed_to_double(transform->matrix[1][1]);
scale = pixman_fixed_to_double(transform->matrix[2][2]);
if (block_w > 2048) {
/* For large block size, we shrink it to smaller box,
* thus latter we may get less cross boundary regions and
* thus can avoid some extra copy.
*
**/
width = block_w / 4;
height = block_h / 4;
}
else {
width = block_w - 2;
height = block_h - 2;
}
e = a + b;
f = c + d;
g = a - b;
h = c - d;
e = MIN(block_w, floor(width * scale) / MAX(fabs(e), fabs(g)));
f = MIN(block_h, floor(height * scale) / MAX(fabs(f), fabs(h)));
*transformed_block_w = MIN(e, f) - 1;
*transformed_block_h = *transformed_block_w;
if (*transformed_block_w <= 0 || *transformed_block_h <= 0)
return FALSE;
DEBUGF("original block_w/h %d %d, fixed %d %d \n", block_w, block_h,
*transformed_block_w, *transformed_block_h);
return TRUE;
}
#define VECTOR_FROM_POINT(p, x, y) do {\
p.v[0] = x; \
p.v[1] = y; \
p.v[2] = 1.0; } while (0)
static void
glamor_get_transform_extent_from_box(struct pixman_box32 *box,
struct pixman_transform *transform)
{
struct pixman_f_vector p0, p1, p2, p3;
float min_x, min_y, max_x, max_y;
struct pixman_f_transform ftransform;
VECTOR_FROM_POINT(p0, box->x1, box->y1);
VECTOR_FROM_POINT(p1, box->x2, box->y1);
VECTOR_FROM_POINT(p2, box->x2, box->y2);
VECTOR_FROM_POINT(p3, box->x1, box->y2);
pixman_f_transform_from_pixman_transform(&ftransform, transform);
pixman_f_transform_point(&ftransform, &p0);
pixman_f_transform_point(&ftransform, &p1);
pixman_f_transform_point(&ftransform, &p2);
pixman_f_transform_point(&ftransform, &p3);
min_x = MIN(p0.v[0], p1.v[0]);
min_x = MIN(min_x, p2.v[0]);
min_x = MIN(min_x, p3.v[0]);
min_y = MIN(p0.v[1], p1.v[1]);
min_y = MIN(min_y, p2.v[1]);
min_y = MIN(min_y, p3.v[1]);
max_x = MAX(p0.v[0], p1.v[0]);
max_x = MAX(max_x, p2.v[0]);
max_x = MAX(max_x, p3.v[0]);
max_y = MAX(p0.v[1], p1.v[1]);
max_y = MAX(max_y, p2.v[1]);
max_y = MAX(max_y, p3.v[1]);
box->x1 = floor(min_x) - 1;
box->y1 = floor(min_y) - 1;
box->x2 = ceil(max_x) + 1;
box->y2 = ceil(max_y) + 1;
}
static void
_glamor_process_transformed_clipped_region(PixmapPtr pixmap,
glamor_pixmap_private *priv,
int repeat_type,
glamor_pixmap_clipped_regions *
clipped_regions, int *n_regions,
int *need_clean_fbo)
{
int shift_x, shift_y;
if (*n_regions != 1) {
/* Merge all source regions into one region. */
glamor_merge_clipped_regions(pixmap, priv, repeat_type,
clipped_regions, n_regions,
need_clean_fbo);
}
else {
glamor_set_pixmap_fbo_current(priv, clipped_regions[0].block_idx);
if (repeat_type == RepeatReflect || repeat_type == RepeatNormal) {
/* The required source areas are in one region,
* we need to shift the corresponding box's coords to proper position,
* thus we can calculate the relative coords correctly.*/
BoxPtr temp_box;
int rem;
temp_box = RegionExtents(clipped_regions[0].region);
modulus(temp_box->x1, pixmap->drawable.width, rem);
shift_x = (temp_box->x1 - rem) / pixmap->drawable.width;
modulus(temp_box->y1, pixmap->drawable.height, rem);
shift_y = (temp_box->y1 - rem) / pixmap->drawable.height;
if (shift_x != 0) {
__glamor_large(priv)->box.x1 +=
shift_x * pixmap->drawable.width;
__glamor_large(priv)->box.x2 +=
shift_x * pixmap->drawable.width;
}
if (shift_y != 0) {
__glamor_large(priv)->box.y1 +=
shift_y * pixmap->drawable.height;
__glamor_large(priv)->box.y2 +=
shift_y * pixmap->drawable.height;
}
}
}
}
Bool
glamor_composite_largepixmap_region(CARD8 op,
PicturePtr source,
PicturePtr mask,
PicturePtr dest,
PixmapPtr source_pixmap,
PixmapPtr mask_pixmap,
PixmapPtr dest_pixmap,
RegionPtr region, Bool force_clip,
INT16 x_source,
INT16 y_source,
INT16 x_mask,
INT16 y_mask,
INT16 x_dest, INT16 y_dest,
CARD16 width, CARD16 height)
{
ScreenPtr screen = dest_pixmap->drawable.pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_pixmap_private *source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
glamor_pixmap_private *mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
glamor_pixmap_private *dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
glamor_pixmap_clipped_regions *clipped_dest_regions;
glamor_pixmap_clipped_regions *clipped_source_regions;
glamor_pixmap_clipped_regions *clipped_mask_regions;
int n_dest_regions;
int n_mask_regions;
int n_source_regions;
int i, j, k;
int need_clean_source_fbo = 0;
int need_clean_mask_fbo = 0;
int is_normal_source_fbo = 0;
int is_normal_mask_fbo = 0;
int fixed_block_width, fixed_block_height;
int dest_block_width, dest_block_height;
int null_source, null_mask;
glamor_pixmap_private *need_free_source_pixmap_priv = NULL;
glamor_pixmap_private *need_free_mask_pixmap_priv = NULL;
int source_repeat_type = 0, mask_repeat_type = 0;
int ok = TRUE;
if (source_pixmap == dest_pixmap) {
glamor_fallback("source and dest pixmaps are the same\n");
return FALSE;
}
if (mask_pixmap == dest_pixmap) {
glamor_fallback("mask and dest pixmaps are the same\n");
return FALSE;
}
if (source->repeat)
source_repeat_type = source->repeatType;
else
source_repeat_type = RepeatNone;
if (mask && mask->repeat)
mask_repeat_type = mask->repeatType;
else
mask_repeat_type = RepeatNone;
if (glamor_pixmap_priv_is_large(dest_pixmap_priv)) {
dest_block_width = __glamor_large(dest_pixmap_priv)->block_w;
dest_block_height = __glamor_large(dest_pixmap_priv)->block_h;
} else {
dest_block_width = dest_pixmap->drawable.width;
dest_block_height = dest_pixmap->drawable.height;
}
fixed_block_width = dest_block_width;
fixed_block_height = dest_block_height;
/* If we got an totally out-of-box region for a source or mask
* region without repeat, we need to set it as null_source and
* give it a solid color (0,0,0,0). */
null_source = 0;
null_mask = 0;
RegionTranslate(region, -dest->pDrawable->x, -dest->pDrawable->y);
/* need to transform the dest region to the correct sourcei/mask region.
* it's a little complex, as one single edge of the
* target region may be transformed to cross a block boundary of the
* source or mask. Then it's impossible to handle it as usual way.
* We may have to split the original dest region to smaller region, and
* make sure each region's transformed region can fit into one texture,
* and then continue this loop again, and each time when a transformed region
* cross the bound, we need to copy it to a single pixmap and do the composition
* with the new pixmap. If the transformed region doesn't cross a source/mask's
* boundary then we don't need to copy.
*
*/
if (source_pixmap_priv
&& source->transform
&& glamor_pixmap_priv_is_large(source_pixmap_priv)) {
int source_transformed_block_width, source_transformed_block_height;
if (!glamor_get_transform_block_size(source->transform,
__glamor_large(source_pixmap_priv)->block_w,
__glamor_large(source_pixmap_priv)->block_h,
&source_transformed_block_width,
&source_transformed_block_height))
{
DEBUGF("source block size less than 1, fallback.\n");
RegionTranslate(region, dest->pDrawable->x, dest->pDrawable->y);
return FALSE;
}
fixed_block_width =
min(fixed_block_width, source_transformed_block_width);
fixed_block_height =
min(fixed_block_height, source_transformed_block_height);
DEBUGF("new source block size %d x %d \n", fixed_block_width,
fixed_block_height);
}
if (mask_pixmap_priv
&& mask->transform && glamor_pixmap_priv_is_large(mask_pixmap_priv)) {
int mask_transformed_block_width, mask_transformed_block_height;
if (!glamor_get_transform_block_size(mask->transform,
__glamor_large(mask_pixmap_priv)->block_w,
__glamor_large(mask_pixmap_priv)->block_h,
&mask_transformed_block_width,
&mask_transformed_block_height)) {
DEBUGF("mask block size less than 1, fallback.\n");
RegionTranslate(region, dest->pDrawable->x, dest->pDrawable->y);
return FALSE;
}
fixed_block_width =
min(fixed_block_width, mask_transformed_block_width);
fixed_block_height =
min(fixed_block_height, mask_transformed_block_height);
DEBUGF("new mask block size %d x %d \n", fixed_block_width,
fixed_block_height);
}
/*compute the correct block width and height whose transformed source/mask
*region can fit into one texture.*/
if (force_clip || fixed_block_width < dest_block_width
|| fixed_block_height < dest_block_height)
clipped_dest_regions =
glamor_compute_clipped_regions_ext(dest_pixmap, region,
&n_dest_regions,
fixed_block_width,
fixed_block_height, 0, 0);
else
clipped_dest_regions = glamor_compute_clipped_regions(dest_pixmap,
region,
&n_dest_regions,
0, 0, 0);
DEBUGF("dest clipped result %d region: \n", n_dest_regions);
if (source_pixmap_priv
&& (source_pixmap_priv == dest_pixmap_priv ||
source_pixmap_priv == mask_pixmap_priv)
&& glamor_pixmap_priv_is_large(source_pixmap_priv)) {
/* XXX self-copy... */
need_free_source_pixmap_priv = source_pixmap_priv;
source_pixmap_priv = malloc(sizeof(*source_pixmap_priv));
*source_pixmap_priv = *need_free_source_pixmap_priv;
need_free_source_pixmap_priv = source_pixmap_priv;
}
assert(mask_pixmap_priv != dest_pixmap_priv);
for (i = 0; i < n_dest_regions; i++) {
DEBUGF("dest region %d idx %d\n", i,
clipped_dest_regions[i].block_idx);
DEBUGRegionPrint(clipped_dest_regions[i].region);
glamor_set_pixmap_fbo_current(dest_pixmap_priv,
clipped_dest_regions[i].block_idx);
if (source_pixmap_priv &&
glamor_pixmap_priv_is_large(source_pixmap_priv)) {
if (!source->transform && source_repeat_type != RepeatPad) {
RegionTranslate(clipped_dest_regions[i].region,
x_source - x_dest, y_source - y_dest);
clipped_source_regions =
glamor_compute_clipped_regions(source_pixmap,
clipped_dest_regions[i].
region, &n_source_regions,
source_repeat_type, 0, 0);
is_normal_source_fbo = 1;
}
else {
clipped_source_regions =
glamor_compute_transform_clipped_regions(source_pixmap,
source->transform,
clipped_dest_regions
[i].region,
&n_source_regions,
x_source - x_dest,
y_source - y_dest,
source_repeat_type,
0, 0);
is_normal_source_fbo = 0;
if (n_source_regions == 0) {
/* Pad the out-of-box region to (0,0,0,0). */
null_source = 1;
n_source_regions = 1;
}
else
_glamor_process_transformed_clipped_region
(source_pixmap, source_pixmap_priv, source_repeat_type,
clipped_source_regions, &n_source_regions,
&need_clean_source_fbo);
}
DEBUGF("source clipped result %d region: \n", n_source_regions);
for (j = 0; j < n_source_regions; j++) {
if (is_normal_source_fbo)
glamor_set_pixmap_fbo_current(source_pixmap_priv,
clipped_source_regions[j].block_idx);
if (mask_pixmap_priv &&
glamor_pixmap_priv_is_large(mask_pixmap_priv)) {
if (is_normal_mask_fbo && is_normal_source_fbo) {
/* both mask and source are normal fbo box without transform or repeatpad.
* The region is clipped against source and then we clip it against mask here.*/
DEBUGF("source region %d idx %d\n", j,
clipped_source_regions[j].block_idx);
DEBUGRegionPrint(clipped_source_regions[j].region);
RegionTranslate(clipped_source_regions[j].region,
-x_source + x_mask, -y_source + y_mask);
clipped_mask_regions =
glamor_compute_clipped_regions(mask_pixmap,
clipped_source_regions
[j].region,
&n_mask_regions,
mask_repeat_type, 0,
0);
is_normal_mask_fbo = 1;
}
else if (is_normal_mask_fbo && !is_normal_source_fbo) {
assert(n_source_regions == 1);
/* The source fbo is not a normal fbo box, it has transform or repeatpad.
* the valid clip region should be the clip dest region rather than the
* clip source region.*/
RegionTranslate(clipped_dest_regions[i].region,
-x_dest + x_mask, -y_dest + y_mask);
clipped_mask_regions =
glamor_compute_clipped_regions(mask_pixmap,
clipped_dest_regions
[i].region,
&n_mask_regions,
mask_repeat_type, 0,
0);
is_normal_mask_fbo = 1;
}
else {
/* This mask region has transform or repeatpad, we need clip it against the previous
* valid region rather than the mask region. */
if (!is_normal_source_fbo)
clipped_mask_regions =
glamor_compute_transform_clipped_regions
(mask_pixmap, mask->transform,
clipped_dest_regions[i].region,
&n_mask_regions, x_mask - x_dest,
y_mask - y_dest, mask_repeat_type, 0, 0);
else
clipped_mask_regions =
glamor_compute_transform_clipped_regions
(mask_pixmap, mask->transform,
clipped_source_regions[j].region,
&n_mask_regions, x_mask - x_source,
y_mask - y_source, mask_repeat_type, 0, 0);
is_normal_mask_fbo = 0;
if (n_mask_regions == 0) {
/* Pad the out-of-box region to (0,0,0,0). */
null_mask = 1;
n_mask_regions = 1;
}
else
_glamor_process_transformed_clipped_region
(mask_pixmap, mask_pixmap_priv, mask_repeat_type,
clipped_mask_regions, &n_mask_regions,
&need_clean_mask_fbo);
}
DEBUGF("mask clipped result %d region: \n", n_mask_regions);
#define COMPOSITE_REGION(region) do { \
if (!glamor_composite_clipped_region(op, \
null_source ? NULL : source, \
null_mask ? NULL : mask, dest, \
null_source ? NULL : source_pixmap, \
null_mask ? NULL : mask_pixmap, \
dest_pixmap, region, \
x_source, y_source, x_mask, y_mask, \
x_dest, y_dest)) { \
assert(0); \
} \
} while(0)
for (k = 0; k < n_mask_regions; k++) {
DEBUGF("mask region %d idx %d\n", k,
clipped_mask_regions[k].block_idx);
DEBUGRegionPrint(clipped_mask_regions[k].region);
if (is_normal_mask_fbo) {
glamor_set_pixmap_fbo_current(mask_pixmap_priv,
clipped_mask_regions[k].
block_idx);
DEBUGF("mask fbo off %d %d \n",
__glamor_large(mask_pixmap_priv)->box.x1,
__glamor_large(mask_pixmap_priv)->box.y1);
DEBUGF("start composite mask hasn't transform.\n");
RegionTranslate(clipped_mask_regions[k].region,
x_dest - x_mask +
dest->pDrawable->x,
y_dest - y_mask +
dest->pDrawable->y);
COMPOSITE_REGION(clipped_mask_regions[k].region);
}
else if (!is_normal_mask_fbo && !is_normal_source_fbo) {
DEBUGF
("start composite both mask and source have transform.\n");
RegionTranslate(clipped_dest_regions[i].region,
dest->pDrawable->x,
dest->pDrawable->y);
COMPOSITE_REGION(clipped_dest_regions[i].region);
}
else {
DEBUGF
("start composite only mask has transform.\n");
RegionTranslate(clipped_source_regions[j].region,
x_dest - x_source +
dest->pDrawable->x,
y_dest - y_source +
dest->pDrawable->y);
COMPOSITE_REGION(clipped_source_regions[j].region);
}
RegionDestroy(clipped_mask_regions[k].region);
}
free(clipped_mask_regions);
if (null_mask)
null_mask = 0;
if (need_clean_mask_fbo) {
assert(is_normal_mask_fbo == 0);
glamor_destroy_fbo(glamor_priv, mask_pixmap_priv->fbo);
mask_pixmap_priv->fbo = NULL;
need_clean_mask_fbo = 0;
}
}
else {
if (is_normal_source_fbo) {
RegionTranslate(clipped_source_regions[j].region,
-x_source + x_dest + dest->pDrawable->x,
-y_source + y_dest +
dest->pDrawable->y);
COMPOSITE_REGION(clipped_source_regions[j].region);
}
else {
/* Source has transform or repeatPad. dest regions is the right
* region to do the composite. */
RegionTranslate(clipped_dest_regions[i].region,
dest->pDrawable->x, dest->pDrawable->y);
COMPOSITE_REGION(clipped_dest_regions[i].region);
}
}
if (clipped_source_regions && clipped_source_regions[j].region)
RegionDestroy(clipped_source_regions[j].region);
}
free(clipped_source_regions);
if (null_source)
null_source = 0;
if (need_clean_source_fbo) {
assert(is_normal_source_fbo == 0);
glamor_destroy_fbo(glamor_priv, source_pixmap_priv->fbo);
source_pixmap_priv->fbo = NULL;
need_clean_source_fbo = 0;
}
}
else {
if (mask_pixmap_priv &&
glamor_pixmap_priv_is_large(mask_pixmap_priv)) {
if (!mask->transform && mask_repeat_type != RepeatPad) {
RegionTranslate(clipped_dest_regions[i].region,
x_mask - x_dest, y_mask - y_dest);
clipped_mask_regions =
glamor_compute_clipped_regions(mask_pixmap,
clipped_dest_regions[i].
region, &n_mask_regions,
mask_repeat_type, 0, 0);
is_normal_mask_fbo = 1;
}
else {
clipped_mask_regions =
glamor_compute_transform_clipped_regions
(mask_pixmap, mask->transform,
clipped_dest_regions[i].region, &n_mask_regions,
x_mask - x_dest, y_mask - y_dest, mask_repeat_type, 0,
0);
is_normal_mask_fbo = 0;
if (n_mask_regions == 0) {
/* Pad the out-of-box region to (0,0,0,0). */
null_mask = 1;
n_mask_regions = 1;
}
else
_glamor_process_transformed_clipped_region
(mask_pixmap, mask_pixmap_priv, mask_repeat_type,
clipped_mask_regions, &n_mask_regions,
&need_clean_mask_fbo);
}
for (k = 0; k < n_mask_regions; k++) {
DEBUGF("mask region %d idx %d\n", k,
clipped_mask_regions[k].block_idx);
DEBUGRegionPrint(clipped_mask_regions[k].region);
if (is_normal_mask_fbo) {
glamor_set_pixmap_fbo_current(mask_pixmap_priv,
clipped_mask_regions[k].
block_idx);
RegionTranslate(clipped_mask_regions[k].region,
x_dest - x_mask + dest->pDrawable->x,
y_dest - y_mask + dest->pDrawable->y);
COMPOSITE_REGION(clipped_mask_regions[k].region);
}
else {
RegionTranslate(clipped_dest_regions[i].region,
dest->pDrawable->x, dest->pDrawable->y);
COMPOSITE_REGION(clipped_dest_regions[i].region);
}
RegionDestroy(clipped_mask_regions[k].region);
}
free(clipped_mask_regions);
if (null_mask)
null_mask = 0;
if (need_clean_mask_fbo) {
glamor_destroy_fbo(glamor_priv, mask_pixmap_priv->fbo);
mask_pixmap_priv->fbo = NULL;
need_clean_mask_fbo = 0;
}
}
else {
RegionTranslate(clipped_dest_regions[i].region,
dest->pDrawable->x, dest->pDrawable->y);
COMPOSITE_REGION(clipped_dest_regions[i].region);
}
}
RegionDestroy(clipped_dest_regions[i].region);
}
free(clipped_dest_regions);
free(need_free_source_pixmap_priv);
free(need_free_mask_pixmap_priv);
ok = TRUE;
return ok;
}
xorg-server-21.1.4/glamor/glamor_segs.c 0000644 0001750 0001750 00000012614 14263273335 014746 0000000 0000000 /*
* Copyright © 2014 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "glamor_priv.h"
#include "glamor_program.h"
#include "glamor_transform.h"
#include "glamor_prepare.h"
static const glamor_facet glamor_facet_poly_segment = {
.name = "poly_segment",
.vs_vars = "attribute vec2 primitive;\n",
.vs_exec = (" vec2 pos = vec2(0.0,0.0);\n"
GLAMOR_POS(gl_Position, primitive.xy)),
};
static Bool
glamor_poly_segment_solid_gl(DrawablePtr drawable, GCPtr gc,
int nseg, xSegment *segs)
{
ScreenPtr screen = drawable->pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *pixmap_priv;
glamor_program *prog;
int off_x, off_y;
xSegment *v;
char *vbo_offset;
int box_index;
int add_last;
Bool ret = FALSE;
pixmap_priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
goto bail;
add_last = 0;
if (gc->capStyle != CapNotLast)
add_last = 1;
glamor_make_current(glamor_priv);
prog = glamor_use_program_fill(pixmap, gc,
&glamor_priv->poly_segment_program,
&glamor_facet_poly_segment);
if (!prog)
goto bail;
/* Set up the vertex buffers for the points */
v = glamor_get_vbo_space(drawable->pScreen,
(nseg << add_last) * sizeof (xSegment),
&vbo_offset);
glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
sizeof(DDXPointRec), vbo_offset);
if (add_last) {
int i, j;
for (i = 0, j=0; i < nseg; i++) {
v[j++] = segs[i];
v[j].x1 = segs[i].x2;
v[j].y1 = segs[i].y2;
v[j].x2 = segs[i].x2+1;
v[j].y2 = segs[i].y2;
j++;
}
} else
memcpy(v, segs, nseg * sizeof (xSegment));
glamor_put_vbo_space(screen);
glEnable(GL_SCISSOR_TEST);
glamor_pixmap_loop(pixmap_priv, box_index) {
int nbox = RegionNumRects(gc->pCompositeClip);
BoxPtr box = RegionRects(gc->pCompositeClip);
if (!glamor_set_destination_drawable(drawable, box_index, TRUE, TRUE,
prog->matrix_uniform, &off_x, &off_y))
goto bail;
while (nbox--) {
glScissor(box->x1 + off_x,
box->y1 + off_y,
box->x2 - box->x1,
box->y2 - box->y1);
box++;
glDrawArrays(GL_LINES, 0, nseg << (1 + add_last));
}
}
ret = TRUE;
glDisable(GL_SCISSOR_TEST);
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
bail:
return ret;
}
static Bool
glamor_poly_segment_gl(DrawablePtr drawable, GCPtr gc,
int nseg, xSegment *segs)
{
if (gc->lineWidth != 0)
return FALSE;
switch (gc->lineStyle) {
case LineSolid:
return glamor_poly_segment_solid_gl(drawable, gc, nseg, segs);
case LineOnOffDash:
return glamor_poly_segment_dash_gl(drawable, gc, nseg, segs);
case LineDoubleDash:
if (gc->fillStyle == FillTiled)
return glamor_poly_segment_solid_gl(drawable, gc, nseg, segs);
else
return glamor_poly_segment_dash_gl(drawable, gc, nseg, segs);
default:
return FALSE;
}
}
static void
glamor_poly_segment_bail(DrawablePtr drawable, GCPtr gc,
int nseg, xSegment *segs)
{
glamor_fallback("to %p (%c)\n", drawable,
glamor_get_drawable_location(drawable));
if (gc->lineWidth == 0) {
if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW) &&
glamor_prepare_access_gc(gc)) {
fbPolySegment(drawable, gc, nseg, segs);
}
glamor_finish_access_gc(gc);
glamor_finish_access(drawable);
} else
miPolySegment(drawable, gc, nseg, segs);
}
void
glamor_poly_segment(DrawablePtr drawable, GCPtr gc,
int nseg, xSegment *segs)
{
if (glamor_poly_segment_gl(drawable, gc, nseg, segs))
return;
glamor_poly_segment_bail(drawable, gc, nseg, segs);
}
xorg-server-21.1.4/glamor/glamor_program.c 0000644 0001750 0001750 00000055563 14263273335 015466 0000000 0000000 /*
* Copyright © 2014 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "glamor_priv.h"
#include "glamor_transform.h"
#include "glamor_program.h"
static Bool
use_solid(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
{
return glamor_set_solid(pixmap, gc, TRUE, prog->fg_uniform);
}
const glamor_facet glamor_fill_solid = {
.name = "solid",
.fs_exec = " gl_FragColor = fg;\n",
.locations = glamor_program_location_fg,
.use = use_solid,
};
static Bool
use_tile(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
{
return glamor_set_tiled(pixmap, gc, prog->fill_offset_uniform, prog->fill_size_inv_uniform);
}
static const glamor_facet glamor_fill_tile = {
.name = "tile",
.vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
.fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n",
.locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
.use = use_tile,
};
static Bool
use_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
{
return glamor_set_stippled(pixmap, gc, prog->fg_uniform,
prog->fill_offset_uniform,
prog->fill_size_inv_uniform);
}
static const glamor_facet glamor_fill_stipple = {
.name = "stipple",
.vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
.fs_exec = (" float a = texture2D(sampler, fill_pos).w;\n"
" if (a == 0.0)\n"
" discard;\n"
" gl_FragColor = fg;\n"),
.locations = glamor_program_location_fg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
.use = use_stipple,
};
static Bool
use_opaque_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
{
if (!use_stipple(pixmap, gc, prog, arg))
return FALSE;
glamor_set_color(pixmap, gc->bgPixel, prog->bg_uniform);
return TRUE;
}
static const glamor_facet glamor_fill_opaque_stipple = {
.name = "opaque_stipple",
.vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
.fs_exec = (" float a = texture2D(sampler, fill_pos).w;\n"
" if (a == 0.0)\n"
" gl_FragColor = bg;\n"
" else\n"
" gl_FragColor = fg;\n"),
.locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
.use = use_opaque_stipple
};
static const glamor_facet *glamor_facet_fill[4] = {
&glamor_fill_solid,
&glamor_fill_tile,
&glamor_fill_stipple,
&glamor_fill_opaque_stipple,
};
typedef struct {
glamor_program_location location;
const char *vs_vars;
const char *fs_vars;
} glamor_location_var;
static glamor_location_var location_vars[] = {
{
.location = glamor_program_location_fg,
.fs_vars = "uniform vec4 fg;\n"
},
{
.location = glamor_program_location_bg,
.fs_vars = "uniform vec4 bg;\n"
},
{
.location = glamor_program_location_fillsamp,
.fs_vars = "uniform sampler2D sampler;\n"
},
{
.location = glamor_program_location_fillpos,
.vs_vars = ("uniform vec2 fill_offset;\n"
"uniform vec2 fill_size_inv;\n"
"varying vec2 fill_pos;\n"),
.fs_vars = ("varying vec2 fill_pos;\n")
},
{
.location = glamor_program_location_font,
.fs_vars = "uniform usampler2D font;\n",
},
{
.location = glamor_program_location_bitplane,
.fs_vars = ("uniform uvec4 bitplane;\n"
"uniform vec4 bitmul;\n"),
},
{
.location = glamor_program_location_dash,
.vs_vars = "uniform float dash_length;\n",
.fs_vars = "uniform sampler2D dash;\n",
},
{
.location = glamor_program_location_atlas,
.fs_vars = "uniform sampler2D atlas;\n",
},
};
static char *
add_var(char *cur, const char *add)
{
char *new;
if (!add)
return cur;
new = realloc(cur, strlen(cur) + strlen(add) + 1);
if (!new) {
free(cur);
return NULL;
}
strcat(new, add);
return new;
}
static char *
vs_location_vars(glamor_program_location locations)
{
int l;
char *vars = strdup("");
for (l = 0; vars && l < ARRAY_SIZE(location_vars); l++)
if (locations & location_vars[l].location)
vars = add_var(vars, location_vars[l].vs_vars);
return vars;
}
static char *
fs_location_vars(glamor_program_location locations)
{
int l;
char *vars = strdup("");
for (l = 0; vars && l < ARRAY_SIZE(location_vars); l++)
if (locations & location_vars[l].location)
vars = add_var(vars, location_vars[l].fs_vars);
return vars;
}
static const char vs_template[] =
"%s" /* version */
"%s" /* exts */
"%s" /* defines */
"%s" /* prim vs_vars */
"%s" /* fill vs_vars */
"%s" /* location vs_vars */
GLAMOR_DECLARE_MATRIX
"void main() {\n"
"%s" /* prim vs_exec, outputs 'pos' and gl_Position */
"%s" /* fill vs_exec */
"}\n";
static const char fs_template[] =
"%s" /* version */
"%s" /* exts */
GLAMOR_DEFAULT_PRECISION
"%s" /* defines */
"%s" /* prim fs_vars */
"%s" /* fill fs_vars */
"%s" /* location fs_vars */
"void main() {\n"
"%s" /* prim fs_exec */
"%s" /* fill fs_exec */
"%s" /* combine */
"}\n";
static const char *
str(const char *s)
{
if (!s)
return "";
return s;
}
static const glamor_facet facet_null_fill = {
.name = ""
};
#define DBG 0
static GLint
glamor_get_uniform(glamor_program *prog,
glamor_program_location location,
const char *name)
{
GLint uniform;
if (location && (prog->locations & location) == 0)
return -2;
uniform = glGetUniformLocation(prog->prog, name);
#if DBG
ErrorF("%s uniform %d\n", name, uniform);
#endif
return uniform;
}
Bool
glamor_build_program(ScreenPtr screen,
glamor_program *prog,
const glamor_facet *prim,
const glamor_facet *fill,
const char *combine,
const char *defines)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_program_location locations = prim->locations;
glamor_program_flag flags = prim->flags;
int version = prim->version;
char *version_string = NULL;
char *fs_vars = NULL;
char *vs_vars = NULL;
char *vs_prog_string = NULL;
char *fs_prog_string = NULL;
GLint fs_prog, vs_prog;
Bool gpu_shader4 = FALSE;
if (!fill)
fill = &facet_null_fill;
locations |= fill->locations;
flags |= fill->flags;
version = MAX(version, fill->version);
if (version > glamor_priv->glsl_version) {
if (version == 130 && !glamor_priv->use_gpu_shader4)
goto fail;
else {
version = 120;
gpu_shader4 = TRUE;
}
}
vs_vars = vs_location_vars(locations);
fs_vars = fs_location_vars(locations);
if (!vs_vars)
goto fail;
if (!fs_vars)
goto fail;
if (version) {
if (asprintf(&version_string, "#version %d\n", version) < 0)
version_string = NULL;
if (!version_string)
goto fail;
}
if (asprintf(&vs_prog_string,
vs_template,
str(version_string),
gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n" : "",
str(defines),
str(prim->vs_vars),
str(fill->vs_vars),
vs_vars,
str(prim->vs_exec),
str(fill->vs_exec)) < 0)
vs_prog_string = NULL;
if (asprintf(&fs_prog_string,
fs_template,
str(version_string),
gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n#define texelFetch texelFetch2D\n#define uint unsigned int\n" : "",
str(defines),
str(prim->fs_vars),
str(fill->fs_vars),
fs_vars,
str(prim->fs_exec),
str(fill->fs_exec),
str(combine)) < 0)
fs_prog_string = NULL;
if (!vs_prog_string || !fs_prog_string)
goto fail;
prog->prog = glCreateProgram();
#if DBG
ErrorF("\n\tProgram %d for %s %s\n\tVertex shader:\n\n\t================\n%s\n\n\tFragment Shader:\n\n%s\t================\n",
prog->prog, prim->name, fill->name, vs_prog_string, fs_prog_string);
#endif
prog->flags = flags;
prog->locations = locations;
prog->prim_use = prim->use;
prog->prim_use_render = prim->use_render;
prog->fill_use = fill->use;
prog->fill_use_render = fill->use_render;
vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
free(vs_prog_string);
free(fs_prog_string);
glAttachShader(prog->prog, vs_prog);
glDeleteShader(vs_prog);
glAttachShader(prog->prog, fs_prog);
glDeleteShader(fs_prog);
glBindAttribLocation(prog->prog, GLAMOR_VERTEX_POS, "primitive");
if (prim->source_name) {
#if DBG
ErrorF("Bind GLAMOR_VERTEX_SOURCE to %s\n", prim->source_name);
#endif
glBindAttribLocation(prog->prog, GLAMOR_VERTEX_SOURCE, prim->source_name);
}
if (prog->alpha == glamor_program_alpha_dual_blend) {
glBindFragDataLocationIndexed(prog->prog, 0, 0, "color0");
glBindFragDataLocationIndexed(prog->prog, 0, 1, "color1");
}
glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name);
prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix");
prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg");
prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg");
prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_offset");
prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_size_inv");
prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font");
prog->bitplane_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitplane");
prog->bitmul_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitmul");
prog->dash_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash");
prog->dash_length_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash_length");
prog->atlas_uniform = glamor_get_uniform(prog, glamor_program_location_atlas, "atlas");
free(version_string);
free(fs_vars);
free(vs_vars);
return TRUE;
fail:
prog->failed = 1;
if (prog->prog) {
glDeleteProgram(prog->prog);
prog->prog = 0;
}
free(vs_prog_string);
free(fs_prog_string);
free(version_string);
free(fs_vars);
free(vs_vars);
return FALSE;
}
Bool
glamor_use_program(PixmapPtr pixmap,
GCPtr gc,
glamor_program *prog,
void *arg)
{
glUseProgram(prog->prog);
if (prog->prim_use && !prog->prim_use(pixmap, gc, prog, arg))
return FALSE;
if (prog->fill_use && !prog->fill_use(pixmap, gc, prog, arg))
return FALSE;
return TRUE;
}
glamor_program *
glamor_use_program_fill(PixmapPtr pixmap,
GCPtr gc,
glamor_program_fill *program_fill,
const glamor_facet *prim)
{
ScreenPtr screen = pixmap->drawable.pScreen;
glamor_program *prog = &program_fill->progs[gc->fillStyle];
int fill_style = gc->fillStyle;
const glamor_facet *fill;
if (prog->failed)
return FALSE;
if (!prog->prog) {
fill = glamor_facet_fill[fill_style];
if (!fill)
return NULL;
if (!glamor_build_program(screen, prog, prim, fill, NULL, NULL))
return NULL;
}
if (!glamor_use_program(pixmap, gc, prog, NULL))
return NULL;
return prog;
}
static struct blendinfo composite_op_info[] = {
[PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
[PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
[PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
[PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
[PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
[PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
[PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
[PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
[PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
[PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
[PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
[PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
[PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
};
static void
glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(dst->pDrawable->pScreen);
GLenum src_blend, dst_blend;
struct blendinfo *op_info;
switch (alpha) {
case glamor_program_alpha_ca_first:
op = PictOpOutReverse;
break;
case glamor_program_alpha_ca_second:
op = PictOpAdd;
break;
default:
break;
}
if (!glamor_priv->is_gles)
glDisable(GL_COLOR_LOGIC_OP);
if (op == PictOpSrc)
return;
op_info = &composite_op_info[op];
src_blend = op_info->source_blend;
dst_blend = op_info->dest_blend;
/* If there's no dst alpha channel, adjust the blend op so that we'll treat
* it as always 1.
*/
if (PICT_FORMAT_A(dst->format) == 0 && op_info->dest_alpha) {
if (src_blend == GL_DST_ALPHA)
src_blend = GL_ONE;
else if (src_blend == GL_ONE_MINUS_DST_ALPHA)
src_blend = GL_ZERO;
}
/* Set up the source alpha value for blending in component alpha mode. */
if (alpha == glamor_program_alpha_dual_blend) {
switch (dst_blend) {
case GL_SRC_ALPHA:
dst_blend = GL_SRC1_COLOR;
break;
case GL_ONE_MINUS_SRC_ALPHA:
dst_blend = GL_ONE_MINUS_SRC1_COLOR;
break;
}
} else if (alpha != glamor_program_alpha_normal) {
switch (dst_blend) {
case GL_SRC_ALPHA:
dst_blend = GL_SRC_COLOR;
break;
case GL_ONE_MINUS_SRC_ALPHA:
dst_blend = GL_ONE_MINUS_SRC_COLOR;
break;
}
}
glEnable(GL_BLEND);
glBlendFunc(src_blend, dst_blend);
}
static Bool
use_source_solid(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
{
PictSolidFill *solid = &src->pSourcePict->solidFill;
float color[4];
glamor_get_rgba_from_color(&solid->fullcolor, color);
glamor_set_blend(op, prog->alpha, dst);
glUniform4fv(prog->fg_uniform, 1, color);
return TRUE;
}
static const glamor_facet glamor_source_solid = {
.name = "render_solid",
.fs_exec = " vec4 source = fg;\n",
.locations = glamor_program_location_fg,
.use_render = use_source_solid,
};
static Bool
use_source_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
{
glamor_set_blend(op, prog->alpha, dst);
return glamor_set_texture((PixmapPtr) src->pDrawable,
glamor_picture_red_is_alpha(dst),
0, 0,
prog->fill_offset_uniform,
prog->fill_size_inv_uniform);
}
static const glamor_facet glamor_source_picture = {
.name = "render_picture",
.vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
.fs_exec = " vec4 source = texture2D(sampler, fill_pos);\n",
.locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
.use_render = use_source_picture,
};
static Bool
use_source_1x1_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
{
glamor_set_blend(op, prog->alpha, dst);
return glamor_set_texture_pixmap((PixmapPtr) src->pDrawable,
glamor_picture_red_is_alpha(dst));
}
static const glamor_facet glamor_source_1x1_picture = {
.name = "render_picture",
.fs_exec = " vec4 source = texture2D(sampler, vec2(0.5));\n",
.locations = glamor_program_location_fillsamp,
.use_render = use_source_1x1_picture,
};
static const glamor_facet *glamor_facet_source[glamor_program_source_count] = {
[glamor_program_source_solid] = &glamor_source_solid,
[glamor_program_source_picture] = &glamor_source_picture,
[glamor_program_source_1x1_picture] = &glamor_source_1x1_picture,
};
static const char *glamor_combine[] = {
[glamor_program_alpha_normal] = " gl_FragColor = source * mask.a;\n",
[glamor_program_alpha_ca_first] = " gl_FragColor = source.a * mask;\n",
[glamor_program_alpha_ca_second] = " gl_FragColor = source * mask;\n",
[glamor_program_alpha_dual_blend] = " color0 = source * mask;\n"
" color1 = source.a * mask;\n"
};
static Bool
glamor_setup_one_program_render(ScreenPtr screen,
glamor_program *prog,
glamor_program_source source_type,
glamor_program_alpha alpha,
const glamor_facet *prim,
const char *defines)
{
if (prog->failed)
return FALSE;
if (!prog->prog) {
const glamor_facet *fill = glamor_facet_source[source_type];
if (!fill)
return FALSE;
prog->alpha = alpha;
if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines))
return FALSE;
}
return TRUE;
}
glamor_program *
glamor_setup_program_render(CARD8 op,
PicturePtr src,
PicturePtr mask,
PicturePtr dst,
glamor_program_render *program_render,
const glamor_facet *prim,
const char *defines)
{
ScreenPtr screen = dst->pDrawable->pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_program_alpha alpha;
glamor_program_source source_type;
glamor_program *prog;
if (op > ARRAY_SIZE(composite_op_info))
return NULL;
if (glamor_is_component_alpha(mask)) {
if (glamor_priv->has_dual_blend) {
alpha = glamor_program_alpha_dual_blend;
} else {
/* This only works for PictOpOver */
if (op != PictOpOver)
return NULL;
alpha = glamor_program_alpha_ca_first;
}
} else
alpha = glamor_program_alpha_normal;
if (src->pDrawable) {
/* Can't do transforms, alphamaps or sourcing from non-pixmaps yet */
if (src->transform || src->alphaMap || src->pDrawable->type != DRAWABLE_PIXMAP)
return NULL;
if (src->pDrawable->width == 1 && src->pDrawable->height == 1 && src->repeat)
source_type = glamor_program_source_1x1_picture;
else
source_type = glamor_program_source_picture;
} else {
SourcePictPtr sp = src->pSourcePict;
if (!sp)
return NULL;
switch (sp->type) {
case SourcePictTypeSolidFill:
source_type = glamor_program_source_solid;
break;
default:
return NULL;
}
}
prog = &program_render->progs[source_type][alpha];
if (!glamor_setup_one_program_render(screen, prog, source_type, alpha, prim, defines))
return NULL;
if (alpha == glamor_program_alpha_ca_first) {
/* Make sure we can also build the second program before
* deciding to use this path.
*/
if (!glamor_setup_one_program_render(screen,
&program_render->progs[source_type][glamor_program_alpha_ca_second],
source_type, glamor_program_alpha_ca_second, prim,
defines))
return NULL;
}
return prog;
}
Bool
glamor_use_program_render(glamor_program *prog,
CARD8 op,
PicturePtr src,
PicturePtr dst)
{
glUseProgram(prog->prog);
if (prog->prim_use_render && !prog->prim_use_render(op, src, dst, prog))
return FALSE;
if (prog->fill_use_render && !prog->fill_use_render(op, src, dst, prog))
return FALSE;
return TRUE;
}
xorg-server-21.1.4/glamor/glamor_transform.c 0000644 0001750 0001750 00000022712 14263273335 016020 0000000 0000000 /*
* Copyright © 2014 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "glamor_priv.h"
#include "glamor_transform.h"
/*
* Set up rendering to target the specified drawable, computing an
* appropriate transform for the vertex shader to convert
* drawable-relative coordinates into pixmap-relative coordinates. If
* requested, the offset from pixmap origin coordinates back to window
* system coordinates will be returned in *p_off_x, *p_off_y so that
* clipping computations can be adjusted as appropriate
*/
Bool
glamor_set_destination_drawable(DrawablePtr drawable,
int box_index,
Bool do_drawable_translate,
Bool center_offset,
GLint matrix_uniform_location,
int *p_off_x,
int *p_off_y)
{
ScreenPtr screen = drawable->pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
int off_x, off_y;
BoxPtr box = glamor_pixmap_box_at(pixmap_priv, box_index);
int w = box->x2 - box->x1;
int h = box->y2 - box->y1;
float scale_x = 2.0f / (float) w;
float scale_y = 2.0f / (float) h;
float center_adjust = 0.0f;
glamor_pixmap_fbo *pixmap_fbo;
pixmap_fbo = glamor_pixmap_fbo_at(pixmap_priv, box_index);
if (!pixmap_fbo)
return FALSE;
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
off_x -= box->x1;
off_y -= box->y1;
if (p_off_x) {
*p_off_x = off_x;
*p_off_y = off_y;
}
/* A tricky computation to find the right value for the two linear functions
* that transform rendering coordinates to pixmap coordinates
*
* pixmap_x = render_x + drawable->x + off_x
* pixmap_y = render_y + drawable->y + off_y
*
* gl_x = pixmap_x * 2 / width - 1
* gl_y = pixmap_y * 2 / height - 1
*
* gl_x = (render_x + drawable->x + off_x) * 2 / width - 1
*
* gl_x = (render_x) * 2 / width + (drawable->x + off_x) * 2 / width - 1
*/
if (do_drawable_translate) {
off_x += drawable->x;
off_y += drawable->y;
}
/*
* To get GL_POINTS drawn in the right spot, we need to adjust the
* coordinates by 1/2 a pixel.
*/
if (center_offset)
center_adjust = 0.5f;
glUniform4f(matrix_uniform_location,
scale_x, (off_x + center_adjust) * scale_x - 1.0f,
scale_y, (off_y + center_adjust) * scale_y - 1.0f);
glamor_set_destination_pixmap_fbo(glamor_priv, pixmap_fbo,
0, 0, w, h);
return TRUE;
}
/*
* Set up for solid rendering to the specified pixmap using alu, fg and planemask
* from the specified GC. Load the target color into the specified uniform
*/
void
glamor_set_color_depth(ScreenPtr pScreen,
int depth,
CARD32 pixel,
GLint uniform)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
float color[4];
glamor_get_rgba_from_pixel(pixel,
&color[0], &color[1], &color[2], &color[3],
glamor_priv->formats[depth].render_format);
if ((depth <= 8) && glamor_priv->formats[8].format == GL_RED)
color[0] = color[3];
glUniform4fv(uniform, 1, color);
}
Bool
glamor_set_solid(PixmapPtr pixmap,
GCPtr gc,
Bool use_alu,
GLint uniform)
{
CARD32 pixel;
int alu = use_alu ? gc->alu : GXcopy;
if (!glamor_set_planemask(gc->depth, gc->planemask))
return FALSE;
pixel = gc->fgPixel;
if (!glamor_set_alu(pixmap->drawable.pScreen, alu)) {
switch (gc->alu) {
case GXclear:
pixel = 0;
break;
case GXcopyInverted:
pixel = ~pixel;
break;
case GXset:
pixel = ~0 & gc->planemask;
break;
default:
return FALSE;
}
}
glamor_set_color(pixmap, pixel, uniform);
return TRUE;
}
Bool
glamor_set_texture_pixmap(PixmapPtr texture, Bool destination_red)
{
glamor_pixmap_private *texture_priv;
texture_priv = glamor_get_pixmap_private(texture);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(texture_priv))
return FALSE;
if (glamor_pixmap_priv_is_large(texture_priv))
return FALSE;
glamor_bind_texture(glamor_get_screen_private(texture->drawable.pScreen),
GL_TEXTURE0,
texture_priv->fbo, destination_red);
/* we're not setting the sampler uniform here as we always use
* GL_TEXTURE0, and the default value for uniforms is zero. So,
* save a bit of CPU time by taking advantage of that.
*/
return TRUE;
}
Bool
glamor_set_texture(PixmapPtr texture,
Bool destination_red,
int off_x,
int off_y,
GLint offset_uniform,
GLint size_inv_uniform)
{
if (!glamor_set_texture_pixmap(texture, destination_red))
return FALSE;
glUniform2f(offset_uniform, off_x, off_y);
glUniform2f(size_inv_uniform, 1.0f/texture->drawable.width, 1.0f/texture->drawable.height);
return TRUE;
}
Bool
glamor_set_tiled(PixmapPtr pixmap,
GCPtr gc,
GLint offset_uniform,
GLint size_inv_uniform)
{
if (!glamor_set_alu(pixmap->drawable.pScreen, gc->alu))
return FALSE;
if (!glamor_set_planemask(gc->depth, gc->planemask))
return FALSE;
return glamor_set_texture(gc->tile.pixmap,
TRUE,
-gc->patOrg.x,
-gc->patOrg.y,
offset_uniform,
size_inv_uniform);
}
static PixmapPtr
glamor_get_stipple_pixmap(GCPtr gc)
{
glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
ScreenPtr screen = gc->pScreen;
PixmapPtr bitmap;
PixmapPtr pixmap;
GCPtr scratch_gc;
ChangeGCVal changes[2];
if (gc_priv->stipple)
return gc_priv->stipple;
bitmap = gc->stipple;
if (!bitmap)
goto bail;
pixmap = glamor_create_pixmap(screen,
bitmap->drawable.width,
bitmap->drawable.height,
8, GLAMOR_CREATE_NO_LARGE);
if (!pixmap)
goto bail;
scratch_gc = GetScratchGC(8, screen);
if (!scratch_gc)
goto bail_pixmap;
changes[0].val = 0xff;
changes[1].val = 0x00;
if (ChangeGC(NullClient, scratch_gc,
GCForeground|GCBackground, changes) != Success)
goto bail_gc;
ValidateGC(&pixmap->drawable, scratch_gc);
(*scratch_gc->ops->CopyPlane)(&bitmap->drawable,
&pixmap->drawable,
scratch_gc,
0, 0,
bitmap->drawable.width,
bitmap->drawable.height,
0, 0, 0x1);
FreeScratchGC(scratch_gc);
gc_priv->stipple = pixmap;
glamor_track_stipple(gc);
return pixmap;
bail_gc:
FreeScratchGC(scratch_gc);
bail_pixmap:
glamor_destroy_pixmap(pixmap);
bail:
return NULL;
}
Bool
glamor_set_stippled(PixmapPtr pixmap,
GCPtr gc,
GLint fg_uniform,
GLint offset_uniform,
GLint size_uniform)
{
PixmapPtr stipple;
stipple = glamor_get_stipple_pixmap(gc);
if (!stipple)
return FALSE;
if (!glamor_set_solid(pixmap, gc, TRUE, fg_uniform))
return FALSE;
return glamor_set_texture(stipple,
FALSE,
-gc->patOrg.x,
-gc->patOrg.y,
offset_uniform,
size_uniform);
}
xorg-server-21.1.4/glamor/glamor_egl.h 0000644 0001750 0001750 00000006204 14263273335 014557 0000000 0000000 /*
* Copyright © 2016 Red Hat, Inc.
*
* 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:
* Adam Jackson
*/
#ifndef GLAMOR_EGL_H
#define GLAMOR_EGL_H
#define MESA_EGL_NO_X11_HEADERS
#define EGL_NO_X11
#include
#include
#include
/*
* Create an EGLDisplay from a native display type. This is a little quirky
* for a few reasons.
*
* 1: GetPlatformDisplayEXT and GetPlatformDisplay are the API you want to
* use, but have different function signatures in the third argument; this
* happens not to matter for us, at the moment, but it means epoxy won't alias
* them together.
*
* 2: epoxy 1.3 and earlier don't understand EGL client extensions, which
* means you can't call "eglGetPlatformDisplayEXT" directly, as the resolver
* will crash.
*
* 3: You can't tell whether you have EGL 1.5 at this point, because
* eglQueryString(EGL_VERSION) is a property of the display, which we don't
* have yet. So you have to query for extensions no matter what. Fortunately
* epoxy_has_egl_extension _does_ let you query for client extensions, so
* we don't have to write our own extension string parsing.
*
* 4. There is no EGL_KHR_platform_base to complement the EXT one, thus one
* needs to know EGL 1.5 is supported in order to use the eglGetPlatformDisplay
* function pointer.
* We can workaround this (circular dependency) by probing for the EGL 1.5
* platform extensions (EGL_KHR_platform_gbm and friends) yet it doesn't seem
* like mesa will be able to adverise these (even though it can do EGL 1.5).
*/
static inline EGLDisplay
glamor_egl_get_display(EGLint type, void *native)
{
/* In practise any EGL 1.5 implementation would support the EXT extension */
if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) {
PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT =
(void *) eglGetProcAddress("eglGetPlatformDisplayEXT");
if (getPlatformDisplayEXT)
return getPlatformDisplayEXT(type, native, NULL);
}
/* Welp, everything is awful. */
return eglGetDisplay(native);
}
#endif
xorg-server-21.1.4/glamor/glamor_utils.c 0000644 0001750 0001750 00000005054 14263273335 015145 0000000 0000000 /*
* Copyright © 2014 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "glamor_priv.h"
void
glamor_solid_boxes(PixmapPtr pixmap,
BoxPtr box, int nbox, unsigned long fg_pixel)
{
DrawablePtr drawable = &pixmap->drawable;
GCPtr gc;
xRectangle *rect;
int n;
rect = xallocarray(nbox, sizeof(xRectangle));
if (!rect)
return;
for (n = 0; n < nbox; n++) {
rect[n].x = box[n].x1;
rect[n].y = box[n].y1;
rect[n].width = box[n].x2 - box[n].x1;
rect[n].height = box[n].y2 - box[n].y1;
}
gc = GetScratchGC(drawable->depth, drawable->pScreen);
if (gc) {
ChangeGCVal vals[1];
vals[0].val = fg_pixel;
ChangeGC(NullClient, gc, GCForeground, vals);
ValidateGC(drawable, gc);
gc->ops->PolyFillRect(drawable, gc, nbox, rect);
FreeScratchGC(gc);
}
free(rect);
}
void
glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
unsigned long fg_pixel)
{
DrawablePtr drawable = &pixmap->drawable;
GCPtr gc;
ChangeGCVal vals[1];
xRectangle rect;
vals[0].val = fg_pixel;
gc = GetScratchGC(drawable->depth, drawable->pScreen);
if (!gc)
return;
ChangeGC(NullClient, gc, GCForeground, vals);
ValidateGC(drawable, gc);
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
gc->ops->PolyFillRect(drawable, gc, 1, &rect);
FreeScratchGC(gc);
}
xorg-server-21.1.4/glamor/glamor_egl_stubs.c 0000644 0001750 0001750 00000003606 14263273335 015775 0000000 0000000 /*
* Copyright © 2013 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.
*/
/** @file glamor_egl_stubs.c
*
* Stubbed out glamor_egl.c functions for servers other than Xorg.
*/
#include "dix-config.h"
#include "glamor.h"
void
glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
{
}
int
glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
PixmapPtr pixmap,
CARD16 *stride, CARD32 *size)
{
return -1;
}
int
glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
uint32_t *offsets, uint32_t *strides,
uint64_t *modifier)
{
return 0;
}
int
glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
CARD16 *stride, CARD32 *size)
{
return -1;
}
xorg-server-21.1.4/glamor/glamor_triangles.c 0000644 0001750 0001750 00000003373 14263273335 015777 0000000 0000000 /*
* Copyright © 2009 Intel Corporation
* Copyright © 1998 Keith Packard
*
* 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:
* Zhigang Gong
*
*/
#include "glamor_priv.h"
void
glamor_triangles(CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc, INT16 ySrc, int ntris, xTriangle * tris)
{
if (glamor_prepare_access_picture(pDst, GLAMOR_ACCESS_RW) &&
glamor_prepare_access_picture(pSrc, GLAMOR_ACCESS_RO)) {
fbTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntris, tris);
}
glamor_finish_access_picture(pSrc);
glamor_finish_access_picture(pDst);
}
xorg-server-21.1.4/glamor/glamor_sync.c 0000644 0001750 0001750 00000010033 14263273335 014752 0000000 0000000 /*
* Copyright © 2014 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "glamor_priv.h"
#include "misyncshm.h"
#include "misyncstr.h"
#if XSYNC
/*
* This whole file exists to wrap a sync fence trigger operation so
* that we can flush GL to provide serialization between the server
* and the shm fence client
*/
static DevPrivateKeyRec glamor_sync_fence_key;
struct glamor_sync_fence {
SyncFenceSetTriggeredFunc set_triggered;
};
static inline struct glamor_sync_fence *
glamor_get_sync_fence(SyncFence *fence)
{
return (struct glamor_sync_fence *) dixLookupPrivate(&fence->devPrivates, &glamor_sync_fence_key);
}
static void
glamor_sync_fence_set_triggered (SyncFence *fence)
{
ScreenPtr screen = fence->pScreen;
glamor_screen_private *glamor = glamor_get_screen_private(screen);
struct glamor_sync_fence *glamor_fence = glamor_get_sync_fence(fence);
/* Flush pending rendering operations */
glamor_make_current(glamor);
glFlush();
fence->funcs.SetTriggered = glamor_fence->set_triggered;
fence->funcs.SetTriggered(fence);
glamor_fence->set_triggered = fence->funcs.SetTriggered;
fence->funcs.SetTriggered = glamor_sync_fence_set_triggered;
}
static void
glamor_sync_create_fence(ScreenPtr screen,
SyncFence *fence,
Bool initially_triggered)
{
glamor_screen_private *glamor = glamor_get_screen_private(screen);
SyncScreenFuncsPtr screen_funcs = miSyncGetScreenFuncs(screen);
struct glamor_sync_fence *glamor_fence = glamor_get_sync_fence(fence);
screen_funcs->CreateFence = glamor->saved_procs.sync_screen_funcs.CreateFence;
screen_funcs->CreateFence(screen, fence, initially_triggered);
glamor->saved_procs.sync_screen_funcs.CreateFence = screen_funcs->CreateFence;
screen_funcs->CreateFence = glamor_sync_create_fence;
glamor_fence->set_triggered = fence->funcs.SetTriggered;
fence->funcs.SetTriggered = glamor_sync_fence_set_triggered;
}
#endif
Bool
glamor_sync_init(ScreenPtr screen)
{
#if XSYNC
glamor_screen_private *glamor = glamor_get_screen_private(screen);
SyncScreenFuncsPtr screen_funcs;
if (!dixPrivateKeyRegistered(&glamor_sync_fence_key)) {
if (!dixRegisterPrivateKey(&glamor_sync_fence_key,
PRIVATE_SYNC_FENCE,
sizeof (struct glamor_sync_fence)))
return FALSE;
}
#ifdef HAVE_XSHMFENCE
if (!miSyncShmScreenInit(screen))
return FALSE;
#else
if (!miSyncSetup(screen))
return FALSE;
#endif
screen_funcs = miSyncGetScreenFuncs(screen);
glamor->saved_procs.sync_screen_funcs.CreateFence = screen_funcs->CreateFence;
screen_funcs->CreateFence = glamor_sync_create_fence;
#endif
return TRUE;
}
void
glamor_sync_close(ScreenPtr screen)
{
#if XSYNC
glamor_screen_private *glamor = glamor_get_screen_private(screen);
SyncScreenFuncsPtr screen_funcs = miSyncGetScreenFuncs(screen);
if (screen_funcs)
screen_funcs->CreateFence = glamor->saved_procs.sync_screen_funcs.CreateFence;
#endif
}
xorg-server-21.1.4/glamor/glamor_picture.c 0000644 0001750 0001750 00000026736 14263273335 015472 0000000 0000000 /*
* Copyright © 2016 Broadcom
* Copyright © 2009 Intel Corporation
* Copyright © 1998 Keith Packard
*
* 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.
*/
/**
* @file glamor_picture.c
*
* Implements temporary uploads of GL_MEMORY Pixmaps to a texture that
* is swizzled appropriately for a given Render picture format.
* laid *
*
* This is important because GTK likes to use SHM Pixmaps for Render
* blending operations, and we don't want a blend operation to fall
* back to software (readback is more expensive than the upload we do
* here, and you'd have to re-upload the fallback output anyway).
*/
#include
#include "glamor_priv.h"
#include "mipict.h"
static void byte_swap_swizzle(GLenum *swizzle)
{
GLenum temp;
temp = swizzle[0];
swizzle[0] = swizzle[3];
swizzle[3] = temp;
temp = swizzle[1];
swizzle[1] = swizzle[2];
swizzle[2] = temp;
}
/**
* Returns the GL format and type for uploading our bits to a given PictFormat.
*
* We may need to tell the caller to translate the bits to another
* format, as in PICT_a1 (which GL doesn't support). We may also need
* to tell the GL to swizzle the texture on sampling, because GLES3
* doesn't support the GL_UNSIGNED_INT_8_8_8_8{,_REV} types, so we
* don't have enough channel reordering options at upload time without
* it.
*/
static Bool
glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
PictFormatShort format,
PictFormatShort *temp_format,
GLenum *tex_format,
GLenum *tex_type,
GLenum *swizzle)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
Bool is_little_endian = IMAGE_BYTE_ORDER == LSBFirst;
*temp_format = format;
swizzle[0] = GL_RED;
swizzle[1] = GL_GREEN;
swizzle[2] = GL_BLUE;
swizzle[3] = GL_ALPHA;
switch (format) {
case PICT_a1:
*tex_format = glamor_priv->formats[1].format;
*tex_type = GL_UNSIGNED_BYTE;
*temp_format = PICT_a8;
break;
case PICT_b8g8r8x8:
case PICT_b8g8r8a8:
if (!glamor_priv->is_gles) {
*tex_format = GL_BGRA;
*tex_type = GL_UNSIGNED_INT_8_8_8_8;
} else {
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_BYTE;
swizzle[0] = GL_GREEN;
swizzle[1] = GL_BLUE;
swizzle[2] = GL_ALPHA;
swizzle[3] = GL_RED;
if (!is_little_endian)
byte_swap_swizzle(swizzle);
}
break;
case PICT_x8r8g8b8:
case PICT_a8r8g8b8:
if (!glamor_priv->is_gles) {
*tex_format = GL_BGRA;
*tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
} else {
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_BYTE;
swizzle[0] = GL_BLUE;
swizzle[2] = GL_RED;
if (!is_little_endian)
byte_swap_swizzle(swizzle);
break;
}
break;
case PICT_x8b8g8r8:
case PICT_a8b8g8r8:
*tex_format = GL_RGBA;
if (!glamor_priv->is_gles) {
*tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
} else {
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_BYTE;
if (!is_little_endian)
byte_swap_swizzle(swizzle);
}
break;
case PICT_x2r10g10b10:
case PICT_a2r10g10b10:
if (!glamor_priv->is_gles) {
*tex_format = GL_BGRA;
*tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
} else {
return FALSE;
}
break;
case PICT_x2b10g10r10:
case PICT_a2b10g10r10:
if (!glamor_priv->is_gles) {
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
} else {
return FALSE;
}
break;
case PICT_r5g6b5:
*tex_format = GL_RGB;
*tex_type = GL_UNSIGNED_SHORT_5_6_5;
break;
case PICT_b5g6r5:
*tex_format = GL_RGB;
if (!glamor_priv->is_gles) {
*tex_type = GL_UNSIGNED_SHORT_5_6_5_REV;
} else {
*tex_type = GL_UNSIGNED_SHORT_5_6_5;
swizzle[0] = GL_BLUE;
swizzle[2] = GL_RED;
}
break;
case PICT_x1b5g5r5:
case PICT_a1b5g5r5:
*tex_format = GL_RGBA;
if (!glamor_priv->is_gles) {
*tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
} else {
return FALSE;
}
break;
case PICT_x1r5g5b5:
case PICT_a1r5g5b5:
if (!glamor_priv->is_gles) {
*tex_format = GL_BGRA;
*tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
} else {
return FALSE;
}
break;
case PICT_a8:
*tex_format = glamor_priv->formats[8].format;
*tex_type = GL_UNSIGNED_BYTE;
break;
case PICT_x4r4g4b4:
case PICT_a4r4g4b4:
if (!glamor_priv->is_gles) {
*tex_format = GL_BGRA;
*tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
} else {
/* XXX */
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
}
break;
case PICT_x4b4g4r4:
case PICT_a4b4g4r4:
if (!glamor_priv->is_gles) {
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
} else {
/* XXX */
*tex_format = GL_RGBA;
*tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
}
break;
default:
return FALSE;
}
if (!PICT_FORMAT_A(format))
swizzle[3] = GL_ONE;
return TRUE;
}
/**
* Takes a set of source bits with a given format and returns an
* in-memory pixman image of those bits in a destination format.
*/
static pixman_image_t *
glamor_get_converted_image(PictFormatShort dst_format,
PictFormatShort src_format,
void *src_bits,
int src_stride,
int w, int h)
{
pixman_image_t *dst_image;
pixman_image_t *src_image;
dst_image = pixman_image_create_bits(dst_format, w, h, NULL, 0);
if (dst_image == NULL) {
return NULL;
}
src_image = pixman_image_create_bits(src_format, w, h, src_bits, src_stride);
if (src_image == NULL) {
pixman_image_unref(dst_image);
return NULL;
}
pixman_image_composite(PictOpSrc, src_image, NULL, dst_image,
0, 0, 0, 0, 0, 0, w, h);
pixman_image_unref(src_image);
return dst_image;
}
/**
* Uploads a picture based on a GLAMOR_MEMORY pixmap to a texture in a
* temporary FBO.
*/
Bool
glamor_upload_picture_to_texture(PicturePtr picture)
{
PixmapPtr pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
ScreenPtr screen = pixmap->drawable.pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
PictFormatShort converted_format;
void *bits = pixmap->devPrivate.ptr;
int stride = pixmap->devKind;
GLenum format, type;
GLenum swizzle[4];
GLenum iformat;
Bool ret = TRUE;
Bool needs_swizzle;
pixman_image_t *converted_image = NULL;
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
assert(glamor_pixmap_is_memory(pixmap));
assert(!pixmap_priv->fbo);
glamor_make_current(glamor_priv);
/* No handling of large pixmap pictures here (would need to make
* an FBO array and split the uploads across it).
*/
if (!glamor_check_fbo_size(glamor_priv,
pixmap->drawable.width,
pixmap->drawable.height)) {
return FALSE;
}
if (!glamor_get_tex_format_type_from_pictformat(screen,
picture->format,
&converted_format,
&format,
&type,
swizzle)) {
glamor_fallback("Unknown pixmap depth %d.\n", pixmap->drawable.depth);
return FALSE;
}
needs_swizzle = (swizzle[0] != GL_RED ||
swizzle[1] != GL_GREEN ||
swizzle[2] != GL_BLUE ||
swizzle[3] != GL_ALPHA);
if (!glamor_priv->has_texture_swizzle && needs_swizzle) {
glamor_fallback("Couldn't upload temporary picture due to missing "
"GL_ARB_texture_swizzle.\n");
return FALSE;
}
if (converted_format != picture->format) {
converted_image = glamor_get_converted_image(converted_format,
picture->format,
bits, stride,
pixmap->drawable.width,
pixmap->drawable.height);
if (!converted_image)
return FALSE;
bits = pixman_image_get_data(converted_image);
stride = pixman_image_get_stride(converted_image);
}
if (!glamor_priv->is_gles)
iformat = f->internalformat;
else
iformat = format;
if (!glamor_pixmap_ensure_fbo(pixmap, GLAMOR_CREATE_FBO_NO_FBO)) {
ret = FALSE;
goto fail;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glamor_priv->suppress_gl_out_of_memory_logging = true;
/* We can't use glamor_pixmap_loop() because GLAMOR_MEMORY pixmaps
* don't have initialized boxes.
*/
glBindTexture(GL_TEXTURE_2D, pixmap_priv->fbo->tex);
glTexImage2D(GL_TEXTURE_2D, 0, iformat,
pixmap->drawable.width, pixmap->drawable.height, 0,
format, type, bits);
if (needs_swizzle) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, swizzle[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, swizzle[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, swizzle[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, swizzle[3]);
}
glamor_priv->suppress_gl_out_of_memory_logging = false;
if (glGetError() == GL_OUT_OF_MEMORY) {
ret = FALSE;
}
fail:
if (converted_image)
pixman_image_unref(converted_image);
return ret;
}
xorg-server-21.1.4/glamor/glamor_gradient.c 0000644 0001750 0001750 00000155113 14263273335 015604 0000000 0000000 /*
* 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:
* Junyan He
*
*/
/** @file glamor_gradient.c
*
* Gradient acceleration implementation
*/
#include "glamor_priv.h"
#define LINEAR_SMALL_STOPS (6 + 2)
#define LINEAR_LARGE_STOPS (16 + 2)
#define RADIAL_SMALL_STOPS (6 + 2)
#define RADIAL_LARGE_STOPS (16 + 2)
static char *
_glamor_create_getcolor_fs_source(ScreenPtr screen, int stops_count,
int use_array)
{
char *gradient_fs = NULL;
#define gradient_fs_getcolor\
GLAMOR_DEFAULT_PRECISION\
"uniform int n_stop;\n"\
"uniform float stops[%d];\n"\
"uniform vec4 stop_colors[%d];\n"\
"vec4 get_color(float stop_len)\n"\
"{\n"\
" int i = 0;\n"\
" vec4 stop_color_before;\n"\
" vec4 gradient_color;\n"\
" float stop_delta;\n"\
" float percentage; \n"\
" \n"\
" if(stop_len < stops[0])\n"\
" return vec4(0.0, 0.0, 0.0, 0.0); \n"\
" for(i = 1; i < n_stop; i++) {\n"\
" if(stop_len < stops[i])\n"\
" break; \n"\
" }\n"\
" if(i == n_stop)\n"\
" return vec4(0.0, 0.0, 0.0, 0.0); \n"\
" \n"\
" stop_color_before = stop_colors[i-1];\n"\
" stop_delta = stops[i] - stops[i-1];\n"\
" if(stop_delta > 2.0)\n"\
" percentage = 0.0;\n" /*For comply with pixman, walker->stepper overflow.*/\
" else if(stop_delta < 0.000001)\n"\
" percentage = 0.0;\n"\
" else \n"\
" percentage = (stop_len - stops[i-1])/stop_delta;\n"\
" \n"\
" gradient_color = stop_color_before;\n"\
" if(percentage != 0.0)\n"\
" gradient_color += (stop_colors[i] - gradient_color)*percentage;\n"\
" return vec4(gradient_color.rgb * gradient_color.a, gradient_color.a);\n"\
"}\n"
/* Because the array access for shader is very slow, the performance is very low
if use array. So use global uniform to replace for it if the number of n_stops is small. */
const char *gradient_fs_getcolor_no_array =
GLAMOR_DEFAULT_PRECISION
"uniform int n_stop;\n"
"uniform float stop0;\n"
"uniform float stop1;\n"
"uniform float stop2;\n"
"uniform float stop3;\n"
"uniform float stop4;\n"
"uniform float stop5;\n"
"uniform float stop6;\n"
"uniform float stop7;\n"
"uniform vec4 stop_color0;\n"
"uniform vec4 stop_color1;\n"
"uniform vec4 stop_color2;\n"
"uniform vec4 stop_color3;\n"
"uniform vec4 stop_color4;\n"
"uniform vec4 stop_color5;\n"
"uniform vec4 stop_color6;\n"
"uniform vec4 stop_color7;\n"
"\n"
"vec4 get_color(float stop_len)\n"
"{\n"
" vec4 stop_color_before;\n"
" vec4 stop_color_after;\n"
" vec4 gradient_color;\n"
" float stop_before;\n"
" float stop_delta;\n"
" float percentage; \n"
" \n"
" if((stop_len < stop0) && (n_stop >= 1)) {\n"
" stop_color_before = vec4(0.0, 0.0, 0.0, 0.0);\n"
" stop_delta = 0.0;\n"
" } else if((stop_len < stop1) && (n_stop >= 2)) {\n"
" stop_color_before = stop_color0;\n"
" stop_color_after = stop_color1;\n"
" stop_before = stop0;\n"
" stop_delta = stop1 - stop0;\n"
" } else if((stop_len < stop2) && (n_stop >= 3)) {\n"
" stop_color_before = stop_color1;\n"
" stop_color_after = stop_color2;\n"
" stop_before = stop1;\n"
" stop_delta = stop2 - stop1;\n"
" } else if((stop_len < stop3) && (n_stop >= 4)){\n"
" stop_color_before = stop_color2;\n"
" stop_color_after = stop_color3;\n"
" stop_before = stop2;\n"
" stop_delta = stop3 - stop2;\n"
" } else if((stop_len < stop4) && (n_stop >= 5)){\n"
" stop_color_before = stop_color3;\n"
" stop_color_after = stop_color4;\n"
" stop_before = stop3;\n"
" stop_delta = stop4 - stop3;\n"
" } else if((stop_len < stop5) && (n_stop >= 6)){\n"
" stop_color_before = stop_color4;\n"
" stop_color_after = stop_color5;\n"
" stop_before = stop4;\n"
" stop_delta = stop5 - stop4;\n"
" } else if((stop_len < stop6) && (n_stop >= 7)){\n"
" stop_color_before = stop_color5;\n"
" stop_color_after = stop_color6;\n"
" stop_before = stop5;\n"
" stop_delta = stop6 - stop5;\n"
" } else if((stop_len < stop7) && (n_stop >= 8)){\n"
" stop_color_before = stop_color6;\n"
" stop_color_after = stop_color7;\n"
" stop_before = stop6;\n"
" stop_delta = stop7 - stop6;\n"
" } else {\n"
" stop_color_before = vec4(0.0, 0.0, 0.0, 0.0);\n"
" stop_delta = 0.0;\n"
" }\n"
" if(stop_delta > 2.0)\n"
" percentage = 0.0;\n" //For comply with pixman, walker->stepper overflow.
" else if(stop_delta < 0.000001)\n"
" percentage = 0.0;\n"
" else\n"
" percentage = (stop_len - stop_before)/stop_delta;\n"
" \n"
" gradient_color = stop_color_before;\n"
" if(percentage != 0.0)\n"
" gradient_color += (stop_color_after - gradient_color)*percentage;\n"
" return vec4(gradient_color.rgb * gradient_color.a, gradient_color.a);\n"
"}\n";
if (use_array) {
XNFasprintf(&gradient_fs,
gradient_fs_getcolor, stops_count, stops_count);
return gradient_fs;
}
else {
return XNFstrdup(gradient_fs_getcolor_no_array);
}
}
static void
_glamor_create_radial_gradient_program(ScreenPtr screen, int stops_count,
int dyn_gen)
{
glamor_screen_private *glamor_priv;
int index;
GLint gradient_prog = 0;
char *gradient_fs = NULL;
GLint fs_prog, vs_prog;
const char *gradient_vs =
GLAMOR_DEFAULT_PRECISION
"attribute vec4 v_position;\n"
"attribute vec4 v_texcoord;\n"
"varying vec2 source_texture;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = v_position;\n"
" source_texture = v_texcoord.xy;\n"
"}\n";
/*
* Refer to pixman radial gradient.
*
* The problem is given the two circles of c1 and c2 with the radius of r1 and
* r1, we need to calculate the t, which is used to do interpolate with stops,
* using the fomula:
* length((1-t)*c1 + t*c2 - p) = (1-t)*r1 + t*r2
* expand the fomula with xy coond, get the following:
* sqrt(sqr((1-t)*c1.x + t*c2.x - p.x) + sqr((1-t)*c1.y + t*c2.y - p.y))
* = (1-t)r1 + t*r2
* <====> At*t- 2Bt + C = 0
* where A = sqr(c2.x - c1.x) + sqr(c2.y - c1.y) - sqr(r2 -r1)
* B = (p.x - c1.x)*(c2.x - c1.x) + (p.y - c1.y)*(c2.y - c1.y) + r1*(r2 -r1)
* C = sqr(p.x - c1.x) + sqr(p.y - c1.y) - r1*r1
*
* solve the fomula and we get the result of
* t = (B + sqrt(B*B - A*C)) / A or
* t = (B - sqrt(B*B - A*C)) / A (quadratic equation have two solutions)
*
* The solution we are going to prefer is the bigger one, unless the
* radius associated to it is negative (or it falls outside the valid t range)
*/
#define gradient_radial_fs_template\
GLAMOR_DEFAULT_PRECISION\
"uniform mat3 transform_mat;\n"\
"uniform int repeat_type;\n"\
"uniform float A_value;\n"\
"uniform vec2 c1;\n"\
"uniform float r1;\n"\
"uniform vec2 c2;\n"\
"uniform float r2;\n"\
"varying vec2 source_texture;\n"\
"\n"\
"vec4 get_color(float stop_len);\n"\
"\n"\
"int t_invalid;\n"\
"\n"\
"float get_stop_len()\n"\
"{\n"\
" float t = 0.0;\n"\
" float sqrt_value;\n"\
" t_invalid = 0;\n"\
" \n"\
" vec3 tmp = vec3(source_texture.x, source_texture.y, 1.0);\n"\
" vec3 source_texture_trans = transform_mat * tmp;\n"\
" source_texture_trans.xy = source_texture_trans.xy/source_texture_trans.z;\n"\
" float B_value = (source_texture_trans.x - c1.x) * (c2.x - c1.x)\n"\
" + (source_texture_trans.y - c1.y) * (c2.y - c1.y)\n"\
" + r1 * (r2 - r1);\n"\
" float C_value = (source_texture_trans.x - c1.x) * (source_texture_trans.x - c1.x)\n"\
" + (source_texture_trans.y - c1.y) * (source_texture_trans.y - c1.y)\n"\
" - r1*r1;\n"\
" if(abs(A_value) < 0.00001) {\n"\
" if(B_value == 0.0) {\n"\
" t_invalid = 1;\n"\
" return t;\n"\
" }\n"\
" t = 0.5 * C_value / B_value;"\
" } else {\n"\
" sqrt_value = B_value * B_value - A_value * C_value;\n"\
" if(sqrt_value < 0.0) {\n"\
" t_invalid = 1;\n"\
" return t;\n"\
" }\n"\
" sqrt_value = sqrt(sqrt_value);\n"\
" t = (B_value + sqrt_value) / A_value;\n"\
" }\n"\
" if(repeat_type == %d) {\n" /* RepeatNone case. */\
" if((t <= 0.0) || (t > 1.0))\n"\
/* try another if first one invalid*/\
" t = (B_value - sqrt_value) / A_value;\n"\
" \n"\
" if((t <= 0.0) || (t > 1.0)) {\n" /*still invalid, return.*/\
" t_invalid = 1;\n"\
" return t;\n"\
" }\n"\
" } else {\n"\
" if(t * (r2 - r1) <= -1.0 * r1)\n"\
/* try another if first one invalid*/\
" t = (B_value - sqrt_value) / A_value;\n"\
" \n"\
" if(t * (r2 -r1) <= -1.0 * r1) {\n" /*still invalid, return.*/\
" t_invalid = 1;\n"\
" return t;\n"\
" }\n"\
" }\n"\
" \n"\
" if(repeat_type == %d){\n" /* repeat normal*/\
" t = fract(t);\n"\
" }\n"\
" \n"\
" if(repeat_type == %d) {\n" /* repeat reflect*/\
" t = abs(fract(t * 0.5 + 0.5) * 2.0 - 1.0);\n"\
" }\n"\
" \n"\
" return t;\n"\
"}\n"\
"\n"\
"void main()\n"\
"{\n"\
" float stop_len = get_stop_len();\n"\
" if(t_invalid == 1) {\n"\
" gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"\
" } else {\n"\
" gl_FragColor = get_color(stop_len);\n"\
" }\n"\
"}\n"\
"\n"\
"%s\n" /* fs_getcolor_source */
char *fs_getcolor_source;
glamor_priv = glamor_get_screen_private(screen);
if ((glamor_priv->radial_max_nstops >= stops_count) && (dyn_gen)) {
/* Very Good, not to generate again. */
return;
}
glamor_make_current(glamor_priv);
if (dyn_gen && glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2]) {
glDeleteProgram(glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2]);
glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2] = 0;
}
gradient_prog = glCreateProgram();
vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, gradient_vs);
fs_getcolor_source =
_glamor_create_getcolor_fs_source(screen, stops_count,
(stops_count > 0));
XNFasprintf(&gradient_fs,
gradient_radial_fs_template,
PIXMAN_REPEAT_NONE, PIXMAN_REPEAT_NORMAL,
PIXMAN_REPEAT_REFLECT,
fs_getcolor_source);
fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, gradient_fs);
free(gradient_fs);
free(fs_getcolor_source);
glAttachShader(gradient_prog, vs_prog);
glAttachShader(gradient_prog, fs_prog);
glDeleteShader(vs_prog);
glDeleteShader(fs_prog);
glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_position");
glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_SOURCE, "v_texcoord");
glamor_link_glsl_prog(screen, gradient_prog, "radial gradient");
if (dyn_gen) {
index = 2;
glamor_priv->radial_max_nstops = stops_count;
}
else if (stops_count) {
index = 1;
}
else {
index = 0;
}
glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][index] = gradient_prog;
}
static void
_glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count,
int dyn_gen)
{
glamor_screen_private *glamor_priv;
int index = 0;
GLint gradient_prog = 0;
char *gradient_fs = NULL;
GLint fs_prog, vs_prog;
const char *gradient_vs =
GLAMOR_DEFAULT_PRECISION
"attribute vec4 v_position;\n"
"attribute vec4 v_texcoord;\n"
"varying vec2 source_texture;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = v_position;\n"
" source_texture = v_texcoord.xy;\n"
"}\n";
/*
* |
* |\
* | \
* | \
* | \
* |\ \
* | \ \
* cos_val = |\ p1d \ /
* sqrt(1/(slope*slope+1.0)) ------>\ \ \ /
* | \ \ \
* | \ \ / \
* | \ *Pt1\
* *p1 | \ \ *P
* \ | / \ \ /
* \ | / \ \ /
* \ | pd \
* \ | \ / \
* p2* | \ / \ /
* slope = (p2.y - p1.y) / | / p2d /
* (p2.x - p1.x) | / \ /
* | / \ /
* | / /
* | / /
* | / *Pt2
* | /
* | /
* | /
* | /
* | /
* -------+---------------------------------
* O|
* |
* |
*
* step 1: compute the distance of p, pt1 and pt2 in the slope direction.
* Calculate the distance on Y axis first and multiply cos_val to
* get the value on slope direction(pd, p1d and p2d represent the
* distance of p, pt1, and pt2 respectively).
*
* step 2: calculate the percentage of (pd - p1d)/(p2d - p1d).
* If (pd - p1d) > (p2d - p1d) or < 0, then sub or add (p2d - p1d)
* to make it in the range of [0, (p2d - p1d)].
*
* step 3: compare the percentage to every stop and find the stpos just
* before and after it. Use the interpolation fomula to compute RGBA.
*/
#define gradient_fs_template \
GLAMOR_DEFAULT_PRECISION\
"uniform mat3 transform_mat;\n"\
"uniform int repeat_type;\n"\
"uniform int hor_ver;\n"\
"uniform float pt_slope;\n"\
"uniform float cos_val;\n"\
"uniform float p1_distance;\n"\
"uniform float pt_distance;\n"\
"varying vec2 source_texture;\n"\
"\n"\
"vec4 get_color(float stop_len);\n"\
"\n"\
"float get_stop_len()\n"\
"{\n"\
" vec3 tmp = vec3(source_texture.x, source_texture.y, 1.0);\n"\
" float distance;\n"\
" float _p1_distance;\n"\
" float _pt_distance;\n"\
" float y_dist;\n"\
" vec3 source_texture_trans = transform_mat * tmp;\n"\
" \n"\
" if(hor_ver == 0) { \n" /*Normal case.*/\
" y_dist = source_texture_trans.y - source_texture_trans.x*pt_slope;\n"\
" distance = y_dist * cos_val;\n"\
" _p1_distance = p1_distance * source_texture_trans.z;\n"\
" _pt_distance = pt_distance * source_texture_trans.z;\n"\
" \n"\
" } else if (hor_ver == 1) {\n"/*horizontal case.*/\
" distance = source_texture_trans.x;\n"\
" _p1_distance = p1_distance * source_texture_trans.z;\n"\
" _pt_distance = pt_distance * source_texture_trans.z;\n"\
" } \n"\
" \n"\
" distance = (distance - _p1_distance) / _pt_distance;\n"\
" \n"\
" if(repeat_type == %d){\n" /* repeat normal*/\
" distance = fract(distance);\n"\
" }\n"\
" \n"\
" if(repeat_type == %d) {\n" /* repeat reflect*/\
" distance = abs(fract(distance * 0.5 + 0.5) * 2.0 - 1.0);\n"\
" }\n"\
" \n"\
" return distance;\n"\
"}\n"\
"\n"\
"void main()\n"\
"{\n"\
" float stop_len = get_stop_len();\n"\
" gl_FragColor = get_color(stop_len);\n"\
"}\n"\
"\n"\
"%s" /* fs_getcolor_source */
char *fs_getcolor_source;
glamor_priv = glamor_get_screen_private(screen);
if ((glamor_priv->linear_max_nstops >= stops_count) && (dyn_gen)) {
/* Very Good, not to generate again. */
return;
}
glamor_make_current(glamor_priv);
if (dyn_gen && glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2]) {
glDeleteProgram(glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2]);
glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2] = 0;
}
gradient_prog = glCreateProgram();
vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, gradient_vs);
fs_getcolor_source =
_glamor_create_getcolor_fs_source(screen, stops_count, stops_count > 0);
XNFasprintf(&gradient_fs,
gradient_fs_template,
PIXMAN_REPEAT_NORMAL, PIXMAN_REPEAT_REFLECT,
fs_getcolor_source);
fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, gradient_fs);
free(gradient_fs);
free(fs_getcolor_source);
glAttachShader(gradient_prog, vs_prog);
glAttachShader(gradient_prog, fs_prog);
glDeleteShader(vs_prog);
glDeleteShader(fs_prog);
glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_position");
glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_SOURCE, "v_texcoord");
glamor_link_glsl_prog(screen, gradient_prog, "linear gradient");
if (dyn_gen) {
index = 2;
glamor_priv->linear_max_nstops = stops_count;
}
else if (stops_count) {
index = 1;
}
else {
index = 0;
}
glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][index] = gradient_prog;
}
void
glamor_init_gradient_shader(ScreenPtr screen)
{
glamor_screen_private *glamor_priv;
int i;
glamor_priv = glamor_get_screen_private(screen);
for (i = 0; i < 3; i++) {
glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][i] = 0;
glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][i] = 0;
}
glamor_priv->linear_max_nstops = 0;
glamor_priv->radial_max_nstops = 0;
_glamor_create_linear_gradient_program(screen, 0, 0);
_glamor_create_linear_gradient_program(screen, LINEAR_LARGE_STOPS, 0);
_glamor_create_radial_gradient_program(screen, 0, 0);
_glamor_create_radial_gradient_program(screen, RADIAL_LARGE_STOPS, 0);
}
static void
_glamor_gradient_convert_trans_matrix(PictTransform *from, float to[3][3],
int width, int height, int normalize)
{
/*
* Because in the shader program, we normalize all the pixel cood to [0, 1],
* so with the transform matrix, the correct logic should be:
* v_s = A*T*v
* v_s: point vector in shader after normalized.
* A: The transition matrix from width X height --> 1.0 X 1.0
* T: The transform matrix.
* v: point vector in width X height space.
*
* result is OK if we use this fomula. But for every point in width X height space,
* we can just use their normalized point vector in shader, namely we can just
* use the result of A*v in shader. So we have no chance to insert T in A*v.
* We can just convert v_s = A*T*v to v_s = A*T*inv(A)*A*v, where inv(A) is the
* inverse matrix of A. Now, v_s = (A*T*inv(A)) * (A*v)
* So, to get the correct v_s, we need to cacula1 the matrix: (A*T*inv(A)), and
* we name this matrix T_s.
*
* Firstly, because A is for the scale conversion, we find
* -- --
* |1/w 0 0 |
* A = | 0 1/h 0 |
* | 0 0 1.0|
* -- --
* so T_s = A*T*inv(a) and result
*
* -- --
* | t11 h*t12/w t13/w|
* T_s = | w*t21/h t22 t23/h|
* | w*t31 h*t32 t33 |
* -- --
*/
to[0][0] = (float) pixman_fixed_to_double(from->matrix[0][0]);
to[0][1] = (float) pixman_fixed_to_double(from->matrix[0][1])
* (normalize ? (((float) height) / ((float) width)) : 1.0);
to[0][2] = (float) pixman_fixed_to_double(from->matrix[0][2])
/ (normalize ? ((float) width) : 1.0);
to[1][0] = (float) pixman_fixed_to_double(from->matrix[1][0])
* (normalize ? (((float) width) / ((float) height)) : 1.0);
to[1][1] = (float) pixman_fixed_to_double(from->matrix[1][1]);
to[1][2] = (float) pixman_fixed_to_double(from->matrix[1][2])
/ (normalize ? ((float) height) : 1.0);
to[2][0] = (float) pixman_fixed_to_double(from->matrix[2][0])
* (normalize ? ((float) width) : 1.0);
to[2][1] = (float) pixman_fixed_to_double(from->matrix[2][1])
* (normalize ? ((float) height) : 1.0);
to[2][2] = (float) pixman_fixed_to_double(from->matrix[2][2]);
DEBUGF("the transform matrix is:\n%f\t%f\t%f\n%f\t%f\t%f\n%f\t%f\t%f\n",
to[0][0], to[0][1], to[0][2],
to[1][0], to[1][1], to[1][2], to[2][0], to[2][1], to[2][2]);
}
static int
_glamor_gradient_set_pixmap_destination(ScreenPtr screen,
glamor_screen_private *glamor_priv,
PicturePtr dst_picture,
GLfloat *xscale, GLfloat *yscale,
int x_source, int y_source,
int tex_normalize)
{
glamor_pixmap_private *pixmap_priv;
PixmapPtr pixmap = NULL;
GLfloat *v;
char *vbo_offset;
pixmap = glamor_get_drawable_pixmap(dst_picture->pDrawable);
pixmap_priv = glamor_get_pixmap_private(pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) { /* should always have here. */
return 0;
}
glamor_set_destination_pixmap_priv_nc(glamor_priv, pixmap, pixmap_priv);
pixmap_priv_get_dest_scale(pixmap, pixmap_priv, xscale, yscale);
DEBUGF("xscale = %f, yscale = %f,"
" x_source = %d, y_source = %d, width = %d, height = %d\n",
*xscale, *yscale, x_source, y_source,
dst_picture->pDrawable->width, dst_picture->pDrawable->height);
v = glamor_get_vbo_space(screen, 16 * sizeof(GLfloat), &vbo_offset);
glamor_set_normalize_vcoords_tri_strip(*xscale, *yscale,
0, 0,
(INT16) (dst_picture->pDrawable->
width),
(INT16) (dst_picture->pDrawable->
height),
v);
if (tex_normalize) {
glamor_set_normalize_tcoords_tri_stripe(*xscale, *yscale,
x_source, y_source,
(INT16) (dst_picture->
pDrawable->width +
x_source),
(INT16) (dst_picture->
pDrawable->height +
y_source),
&v[8]);
}
else {
glamor_set_tcoords_tri_strip(x_source, y_source,
(INT16) (dst_picture->pDrawable->width) +
x_source,
(INT16) (dst_picture->pDrawable->height) +
y_source,
&v[8]);
}
DEBUGF("vertices --> leftup : %f X %f, rightup: %f X %f,"
"rightbottom: %f X %f, leftbottom : %f X %f\n",
v[0], v[1], v[2], v[3],
v[4], v[5], v[6], v[7]);
DEBUGF("tex_vertices --> leftup : %f X %f, rightup: %f X %f,"
"rightbottom: %f X %f, leftbottom : %f X %f\n",
v[8], v[9], v[10], v[11],
v[12], v[13], v[14], v[15]);
glamor_make_current(glamor_priv);
glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
GL_FALSE, 0, vbo_offset);
glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
GL_FALSE, 0, vbo_offset + 8 * sizeof(GLfloat));
glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
glamor_put_vbo_space(screen);
return 1;
}
static int
_glamor_gradient_set_stops(PicturePtr src_picture, PictGradient *pgradient,
GLfloat *stop_colors, GLfloat *n_stops)
{
int i;
int count = 1;
for (i = 0; i < pgradient->nstops; i++) {
stop_colors[count * 4] =
pixman_fixed_to_double(pgradient->stops[i].color.red);
stop_colors[count * 4 + 1] =
pixman_fixed_to_double(pgradient->stops[i].color.green);
stop_colors[count * 4 + 2] =
pixman_fixed_to_double(pgradient->stops[i].color.blue);
stop_colors[count * 4 + 3] =
pixman_fixed_to_double(pgradient->stops[i].color.alpha);
n_stops[count] =
(GLfloat) pixman_fixed_to_double(pgradient->stops[i].x);
count++;
}
/* for the end stop. */
count++;
switch (src_picture->repeatType) {
#define REPEAT_FILL_STOPS(m, n) \
stop_colors[(m)*4 + 0] = stop_colors[(n)*4 + 0]; \
stop_colors[(m)*4 + 1] = stop_colors[(n)*4 + 1]; \
stop_colors[(m)*4 + 2] = stop_colors[(n)*4 + 2]; \
stop_colors[(m)*4 + 3] = stop_colors[(n)*4 + 3];
default:
case PIXMAN_REPEAT_NONE:
stop_colors[0] = 0.0; //R
stop_colors[1] = 0.0; //G
stop_colors[2] = 0.0; //B
stop_colors[3] = 0.0; //Alpha
n_stops[0] = n_stops[1];
stop_colors[0 + (count - 1) * 4] = 0.0; //R
stop_colors[1 + (count - 1) * 4] = 0.0; //G
stop_colors[2 + (count - 1) * 4] = 0.0; //B
stop_colors[3 + (count - 1) * 4] = 0.0; //Alpha
n_stops[count - 1] = n_stops[count - 2];
break;
case PIXMAN_REPEAT_NORMAL:
REPEAT_FILL_STOPS(0, count - 2);
n_stops[0] = n_stops[count - 2] - 1.0;
REPEAT_FILL_STOPS(count - 1, 1);
n_stops[count - 1] = n_stops[1] + 1.0;
break;
case PIXMAN_REPEAT_REFLECT:
REPEAT_FILL_STOPS(0, 1);
n_stops[0] = -n_stops[1];
REPEAT_FILL_STOPS(count - 1, count - 2);
n_stops[count - 1] = 1.0 + 1.0 - n_stops[count - 2];
break;
case PIXMAN_REPEAT_PAD:
REPEAT_FILL_STOPS(0, 1);
n_stops[0] = -(float) INT_MAX;
REPEAT_FILL_STOPS(count - 1, count - 2);
n_stops[count - 1] = (float) INT_MAX;
break;
#undef REPEAT_FILL_STOPS
}
for (i = 0; i < count; i++) {
DEBUGF("n_stops[%d] = %f, color = r:%f g:%f b:%f a:%f\n",
i, n_stops[i],
stop_colors[i * 4], stop_colors[i * 4 + 1],
stop_colors[i * 4 + 2], stop_colors[i * 4 + 3]);
}
return count;
}
PicturePtr
glamor_generate_radial_gradient_picture(ScreenPtr screen,
PicturePtr src_picture,
int x_source, int y_source,
int width, int height,
PictFormatShort format)
{
glamor_screen_private *glamor_priv;
PicturePtr dst_picture = NULL;
PixmapPtr pixmap = NULL;
GLint gradient_prog = 0;
int error;
int stops_count = 0;
int count = 0;
GLfloat *stop_colors = NULL;
GLfloat *n_stops = NULL;
GLfloat xscale, yscale;
float transform_mat[3][3];
static const float identity_mat[3][3] = { {1.0, 0.0, 0.0},
{0.0, 1.0, 0.0},
{0.0, 0.0, 1.0}
};
GLfloat stop_colors_st[RADIAL_SMALL_STOPS * 4];
GLfloat n_stops_st[RADIAL_SMALL_STOPS];
GLfloat A_value;
GLfloat cxy[4];
float c1x, c1y, c2x, c2y, r1, r2;
GLint transform_mat_uniform_location = 0;
GLint repeat_type_uniform_location = 0;
GLint n_stop_uniform_location = 0;
GLint stops_uniform_location = 0;
GLint stop_colors_uniform_location = 0;
GLint stop0_uniform_location = 0;
GLint stop1_uniform_location = 0;
GLint stop2_uniform_location = 0;
GLint stop3_uniform_location = 0;
GLint stop4_uniform_location = 0;
GLint stop5_uniform_location = 0;
GLint stop6_uniform_location = 0;
GLint stop7_uniform_location = 0;
GLint stop_color0_uniform_location = 0;
GLint stop_color1_uniform_location = 0;
GLint stop_color2_uniform_location = 0;
GLint stop_color3_uniform_location = 0;
GLint stop_color4_uniform_location = 0;
GLint stop_color5_uniform_location = 0;
GLint stop_color6_uniform_location = 0;
GLint stop_color7_uniform_location = 0;
GLint A_value_uniform_location = 0;
GLint c1_uniform_location = 0;
GLint r1_uniform_location = 0;
GLint c2_uniform_location = 0;
GLint r2_uniform_location = 0;
glamor_priv = glamor_get_screen_private(screen);
glamor_make_current(glamor_priv);
/* Create a pixmap with VBO. */
pixmap = glamor_create_pixmap(screen,
width, height,
PIXMAN_FORMAT_DEPTH(format), 0);
if (!pixmap)
goto GRADIENT_FAIL;
dst_picture = CreatePicture(0, &pixmap->drawable,
PictureMatchFormat(screen,
PIXMAN_FORMAT_DEPTH(format),
format), 0, 0, serverClient,
&error);
/* Release the reference, picture will hold the last one. */
glamor_destroy_pixmap(pixmap);
if (!dst_picture)
goto GRADIENT_FAIL;
ValidatePicture(dst_picture);
stops_count = src_picture->pSourcePict->radial.nstops + 2;
/* Because the max value of nstops is unknown, so create a program
when nstops > LINEAR_LARGE_STOPS. */
if (stops_count <= RADIAL_SMALL_STOPS) {
gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][0];
}
else if (stops_count <= RADIAL_LARGE_STOPS) {
gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][1];
}
else {
_glamor_create_radial_gradient_program(screen,
src_picture->pSourcePict->linear.
nstops + 2, 1);
gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2];
}
/* Bind all the uniform vars . */
transform_mat_uniform_location = glGetUniformLocation(gradient_prog,
"transform_mat");
repeat_type_uniform_location = glGetUniformLocation(gradient_prog,
"repeat_type");
n_stop_uniform_location = glGetUniformLocation(gradient_prog, "n_stop");
A_value_uniform_location = glGetUniformLocation(gradient_prog, "A_value");
c1_uniform_location = glGetUniformLocation(gradient_prog, "c1");
r1_uniform_location = glGetUniformLocation(gradient_prog, "r1");
c2_uniform_location = glGetUniformLocation(gradient_prog, "c2");
r2_uniform_location = glGetUniformLocation(gradient_prog, "r2");
if (src_picture->pSourcePict->radial.nstops + 2 <= RADIAL_SMALL_STOPS) {
stop0_uniform_location =
glGetUniformLocation(gradient_prog, "stop0");
stop1_uniform_location =
glGetUniformLocation(gradient_prog, "stop1");
stop2_uniform_location =
glGetUniformLocation(gradient_prog, "stop2");
stop3_uniform_location =
glGetUniformLocation(gradient_prog, "stop3");
stop4_uniform_location =
glGetUniformLocation(gradient_prog, "stop4");
stop5_uniform_location =
glGetUniformLocation(gradient_prog, "stop5");
stop6_uniform_location =
glGetUniformLocation(gradient_prog, "stop6");
stop7_uniform_location =
glGetUniformLocation(gradient_prog, "stop7");
stop_color0_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color0");
stop_color1_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color1");
stop_color2_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color2");
stop_color3_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color3");
stop_color4_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color4");
stop_color5_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color5");
stop_color6_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color6");
stop_color7_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color7");
}
else {
stops_uniform_location =
glGetUniformLocation(gradient_prog, "stops");
stop_colors_uniform_location =
glGetUniformLocation(gradient_prog, "stop_colors");
}
glUseProgram(gradient_prog);
glUniform1i(repeat_type_uniform_location, src_picture->repeatType);
if (src_picture->transform) {
_glamor_gradient_convert_trans_matrix(src_picture->transform,
transform_mat, width, height, 0);
glUniformMatrix3fv(transform_mat_uniform_location,
1, 1, &transform_mat[0][0]);
}
else {
glUniformMatrix3fv(transform_mat_uniform_location,
1, 1, &identity_mat[0][0]);
}
if (!_glamor_gradient_set_pixmap_destination
(screen, glamor_priv, dst_picture, &xscale, &yscale, x_source, y_source,
0))
goto GRADIENT_FAIL;
glamor_set_alu(screen, GXcopy);
/* Set all the stops and colors to shader. */
if (stops_count > RADIAL_SMALL_STOPS) {
stop_colors = xallocarray(stops_count, 4 * sizeof(float));
if (stop_colors == NULL) {
ErrorF("Failed to allocate stop_colors memory.\n");
goto GRADIENT_FAIL;
}
n_stops = xallocarray(stops_count, sizeof(float));
if (n_stops == NULL) {
ErrorF("Failed to allocate n_stops memory.\n");
goto GRADIENT_FAIL;
}
}
else {
stop_colors = stop_colors_st;
n_stops = n_stops_st;
}
count =
_glamor_gradient_set_stops(src_picture,
&src_picture->pSourcePict->gradient,
stop_colors, n_stops);
if (src_picture->pSourcePict->linear.nstops + 2 <= RADIAL_SMALL_STOPS) {
int j = 0;
glUniform4f(stop_color0_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color1_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color2_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color3_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color4_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color5_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color6_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color7_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j = 0;
glUniform1f(stop0_uniform_location, n_stops[j++]);
glUniform1f(stop1_uniform_location, n_stops[j++]);
glUniform1f(stop2_uniform_location, n_stops[j++]);
glUniform1f(stop3_uniform_location, n_stops[j++]);
glUniform1f(stop4_uniform_location, n_stops[j++]);
glUniform1f(stop5_uniform_location, n_stops[j++]);
glUniform1f(stop6_uniform_location, n_stops[j++]);
glUniform1f(stop7_uniform_location, n_stops[j++]);
glUniform1i(n_stop_uniform_location, count);
}
else {
glUniform4fv(stop_colors_uniform_location, count, stop_colors);
glUniform1fv(stops_uniform_location, count, n_stops);
glUniform1i(n_stop_uniform_location, count);
}
c1x = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.x);
c1y = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.y);
c2x = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.x);
c2y = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.y);
r1 = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.
radius);
r2 = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.
radius);
glamor_set_circle_centre(width, height, c1x, c1y, cxy);
glUniform2fv(c1_uniform_location, 1, cxy);
glUniform1f(r1_uniform_location, r1);
glamor_set_circle_centre(width, height, c2x, c2y, cxy);
glUniform2fv(c2_uniform_location, 1, cxy);
glUniform1f(r2_uniform_location, r2);
A_value =
(c2x - c1x) * (c2x - c1x) + (c2y - c1y) * (c2y - c1y) - (r2 -
r1) * (r2 -
r1);
glUniform1f(A_value_uniform_location, A_value);
DEBUGF("C1:(%f, %f) R1:%f\nC2:(%f, %f) R2:%f\nA = %f\n",
c1x, c1y, r1, c2x, c2y, r2, A_value);
/* Now rendering. */
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* Do the clear logic. */
if (stops_count > RADIAL_SMALL_STOPS) {
free(n_stops);
free(stop_colors);
}
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
return dst_picture;
GRADIENT_FAIL:
if (dst_picture) {
FreePicture(dst_picture, 0);
}
if (stops_count > RADIAL_SMALL_STOPS) {
if (n_stops)
free(n_stops);
if (stop_colors)
free(stop_colors);
}
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
return NULL;
}
PicturePtr
glamor_generate_linear_gradient_picture(ScreenPtr screen,
PicturePtr src_picture,
int x_source, int y_source,
int width, int height,
PictFormatShort format)
{
glamor_screen_private *glamor_priv;
PicturePtr dst_picture = NULL;
PixmapPtr pixmap = NULL;
GLint gradient_prog = 0;
int error;
float pt_distance;
float p1_distance;
GLfloat cos_val;
int stops_count = 0;
GLfloat *stop_colors = NULL;
GLfloat *n_stops = NULL;
int count = 0;
float slope;
GLfloat xscale, yscale;
GLfloat pt1[2], pt2[2];
float transform_mat[3][3];
static const float identity_mat[3][3] = { {1.0, 0.0, 0.0},
{0.0, 1.0, 0.0},
{0.0, 0.0, 1.0}
};
GLfloat stop_colors_st[LINEAR_SMALL_STOPS * 4];
GLfloat n_stops_st[LINEAR_SMALL_STOPS];
GLint transform_mat_uniform_location = 0;
GLint n_stop_uniform_location = 0;
GLint stops_uniform_location = 0;
GLint stop0_uniform_location = 0;
GLint stop1_uniform_location = 0;
GLint stop2_uniform_location = 0;
GLint stop3_uniform_location = 0;
GLint stop4_uniform_location = 0;
GLint stop5_uniform_location = 0;
GLint stop6_uniform_location = 0;
GLint stop7_uniform_location = 0;
GLint stop_colors_uniform_location = 0;
GLint stop_color0_uniform_location = 0;
GLint stop_color1_uniform_location = 0;
GLint stop_color2_uniform_location = 0;
GLint stop_color3_uniform_location = 0;
GLint stop_color4_uniform_location = 0;
GLint stop_color5_uniform_location = 0;
GLint stop_color6_uniform_location = 0;
GLint stop_color7_uniform_location = 0;
GLint pt_slope_uniform_location = 0;
GLint repeat_type_uniform_location = 0;
GLint hor_ver_uniform_location = 0;
GLint cos_val_uniform_location = 0;
GLint p1_distance_uniform_location = 0;
GLint pt_distance_uniform_location = 0;
glamor_priv = glamor_get_screen_private(screen);
glamor_make_current(glamor_priv);
/* Create a pixmap with VBO. */
pixmap = glamor_create_pixmap(screen,
width, height,
PIXMAN_FORMAT_DEPTH(format), 0);
if (!pixmap)
goto GRADIENT_FAIL;
dst_picture = CreatePicture(0, &pixmap->drawable,
PictureMatchFormat(screen,
PIXMAN_FORMAT_DEPTH(format),
format), 0, 0, serverClient,
&error);
/* Release the reference, picture will hold the last one. */
glamor_destroy_pixmap(pixmap);
if (!dst_picture)
goto GRADIENT_FAIL;
ValidatePicture(dst_picture);
stops_count = src_picture->pSourcePict->linear.nstops + 2;
/* Because the max value of nstops is unknown, so create a program
when nstops > LINEAR_LARGE_STOPS. */
if (stops_count <= LINEAR_SMALL_STOPS) {
gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][0];
}
else if (stops_count <= LINEAR_LARGE_STOPS) {
gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][1];
}
else {
_glamor_create_linear_gradient_program(screen,
src_picture->pSourcePict->linear.
nstops + 2, 1);
gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2];
}
/* Bind all the uniform vars . */
n_stop_uniform_location =
glGetUniformLocation(gradient_prog, "n_stop");
pt_slope_uniform_location =
glGetUniformLocation(gradient_prog, "pt_slope");
repeat_type_uniform_location =
glGetUniformLocation(gradient_prog, "repeat_type");
hor_ver_uniform_location =
glGetUniformLocation(gradient_prog, "hor_ver");
transform_mat_uniform_location =
glGetUniformLocation(gradient_prog, "transform_mat");
cos_val_uniform_location =
glGetUniformLocation(gradient_prog, "cos_val");
p1_distance_uniform_location =
glGetUniformLocation(gradient_prog, "p1_distance");
pt_distance_uniform_location =
glGetUniformLocation(gradient_prog, "pt_distance");
if (src_picture->pSourcePict->linear.nstops + 2 <= LINEAR_SMALL_STOPS) {
stop0_uniform_location =
glGetUniformLocation(gradient_prog, "stop0");
stop1_uniform_location =
glGetUniformLocation(gradient_prog, "stop1");
stop2_uniform_location =
glGetUniformLocation(gradient_prog, "stop2");
stop3_uniform_location =
glGetUniformLocation(gradient_prog, "stop3");
stop4_uniform_location =
glGetUniformLocation(gradient_prog, "stop4");
stop5_uniform_location =
glGetUniformLocation(gradient_prog, "stop5");
stop6_uniform_location =
glGetUniformLocation(gradient_prog, "stop6");
stop7_uniform_location =
glGetUniformLocation(gradient_prog, "stop7");
stop_color0_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color0");
stop_color1_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color1");
stop_color2_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color2");
stop_color3_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color3");
stop_color4_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color4");
stop_color5_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color5");
stop_color6_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color6");
stop_color7_uniform_location =
glGetUniformLocation(gradient_prog, "stop_color7");
}
else {
stops_uniform_location =
glGetUniformLocation(gradient_prog, "stops");
stop_colors_uniform_location =
glGetUniformLocation(gradient_prog, "stop_colors");
}
glUseProgram(gradient_prog);
glUniform1i(repeat_type_uniform_location, src_picture->repeatType);
/* set the transform matrix. */
if (src_picture->transform) {
_glamor_gradient_convert_trans_matrix(src_picture->transform,
transform_mat, width, height, 1);
glUniformMatrix3fv(transform_mat_uniform_location,
1, 1, &transform_mat[0][0]);
}
else {
glUniformMatrix3fv(transform_mat_uniform_location,
1, 1, &identity_mat[0][0]);
}
if (!_glamor_gradient_set_pixmap_destination
(screen, glamor_priv, dst_picture, &xscale, &yscale, x_source, y_source,
1))
goto GRADIENT_FAIL;
glamor_set_alu(screen, GXcopy);
/* Normalize the PTs. */
glamor_set_normalize_pt(xscale, yscale,
pixman_fixed_to_double(src_picture->pSourcePict->
linear.p1.x),
pixman_fixed_to_double(src_picture->pSourcePict->
linear.p1.y),
pt1);
DEBUGF("pt1:(%f, %f) ---> (%f %f)\n",
pixman_fixed_to_double(src_picture->pSourcePict->linear.p1.x),
pixman_fixed_to_double(src_picture->pSourcePict->linear.p1.y),
pt1[0], pt1[1]);
glamor_set_normalize_pt(xscale, yscale,
pixman_fixed_to_double(src_picture->pSourcePict->
linear.p2.x),
pixman_fixed_to_double(src_picture->pSourcePict->
linear.p2.y),
pt2);
DEBUGF("pt2:(%f, %f) ---> (%f %f)\n",
pixman_fixed_to_double(src_picture->pSourcePict->linear.p2.x),
pixman_fixed_to_double(src_picture->pSourcePict->linear.p2.y),
pt2[0], pt2[1]);
/* Set all the stops and colors to shader. */
if (stops_count > LINEAR_SMALL_STOPS) {
stop_colors = xallocarray(stops_count, 4 * sizeof(float));
if (stop_colors == NULL) {
ErrorF("Failed to allocate stop_colors memory.\n");
goto GRADIENT_FAIL;
}
n_stops = xallocarray(stops_count, sizeof(float));
if (n_stops == NULL) {
ErrorF("Failed to allocate n_stops memory.\n");
goto GRADIENT_FAIL;
}
}
else {
stop_colors = stop_colors_st;
n_stops = n_stops_st;
}
count =
_glamor_gradient_set_stops(src_picture,
&src_picture->pSourcePict->gradient,
stop_colors, n_stops);
if (src_picture->pSourcePict->linear.nstops + 2 <= LINEAR_SMALL_STOPS) {
int j = 0;
glUniform4f(stop_color0_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color1_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color2_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color3_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color4_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color5_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color6_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j++;
glUniform4f(stop_color7_uniform_location,
stop_colors[4 * j + 0], stop_colors[4 * j + 1],
stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
j = 0;
glUniform1f(stop0_uniform_location, n_stops[j++]);
glUniform1f(stop1_uniform_location, n_stops[j++]);
glUniform1f(stop2_uniform_location, n_stops[j++]);
glUniform1f(stop3_uniform_location, n_stops[j++]);
glUniform1f(stop4_uniform_location, n_stops[j++]);
glUniform1f(stop5_uniform_location, n_stops[j++]);
glUniform1f(stop6_uniform_location, n_stops[j++]);
glUniform1f(stop7_uniform_location, n_stops[j++]);
glUniform1i(n_stop_uniform_location, count);
}
else {
glUniform4fv(stop_colors_uniform_location, count, stop_colors);
glUniform1fv(stops_uniform_location, count, n_stops);
glUniform1i(n_stop_uniform_location, count);
}
if (src_picture->pSourcePict->linear.p2.y == src_picture->pSourcePict->linear.p1.y) { // The horizontal case.
glUniform1i(hor_ver_uniform_location, 1);
DEBUGF("p1.y: %f, p2.y: %f, enter the horizontal case\n",
pt1[1], pt2[1]);
p1_distance = pt1[0];
pt_distance = (pt2[0] - p1_distance);
glUniform1f(p1_distance_uniform_location, p1_distance);
glUniform1f(pt_distance_uniform_location, pt_distance);
}
else {
/* The slope need to compute here. In shader, the viewport set will change
the original slope and the slope which is vertical to it will not be correct. */
slope = -(float) (src_picture->pSourcePict->linear.p2.x
- src_picture->pSourcePict->linear.p1.x) /
(float) (src_picture->pSourcePict->linear.p2.y
- src_picture->pSourcePict->linear.p1.y);
slope = slope * yscale / xscale;
glUniform1f(pt_slope_uniform_location, slope);
glUniform1i(hor_ver_uniform_location, 0);
cos_val = sqrt(1.0 / (slope * slope + 1.0));
glUniform1f(cos_val_uniform_location, cos_val);
p1_distance = (pt1[1] - pt1[0] * slope) * cos_val;
pt_distance = (pt2[1] - pt2[0] * slope) * cos_val - p1_distance;
glUniform1f(p1_distance_uniform_location, p1_distance);
glUniform1f(pt_distance_uniform_location, pt_distance);
}
/* Now rendering. */
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* Do the clear logic. */
if (stops_count > LINEAR_SMALL_STOPS) {
free(n_stops);
free(stop_colors);
}
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
return dst_picture;
GRADIENT_FAIL:
if (dst_picture) {
FreePicture(dst_picture, 0);
}
if (stops_count > LINEAR_SMALL_STOPS) {
if (n_stops)
free(n_stops);
if (stop_colors)
free(stop_colors);
}
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
return NULL;
}
xorg-server-21.1.4/glamor/glamor_font.h 0000644 0001750 0001750 00000003306 14263273335 014756 0000000 0000000 /*
* Copyright © 2014 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef _GLAMOR_FONT_H_
#define _GLAMOR_FONT_H_
typedef struct {
Bool realized;
CharInfoPtr default_char;
CARD8 default_row;
CARD8 default_col;
GLuint texture_id;
GLuint row_width;
CARD16 glyph_width_bytes;
CARD16 glyph_width_pixels;
CARD16 glyph_height;
} glamor_font_t;
glamor_font_t *
glamor_font_get(ScreenPtr screen, FontPtr font);
Bool
glamor_font_init(ScreenPtr screen);
void
glamor_fini_glyph_shader(ScreenPtr screen);
#endif /* _GLAMOR_FONT_H_ */
xorg-server-21.1.4/glamor/glamor_egl_ext.h 0000644 0001750 0001750 00000006006 14263273335 015437 0000000 0000000 /*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* 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.
*/
/* Extensions used by Glamor, copied from Mesa's eglmesaext.h, */
#ifndef GLAMOR_EGL_EXT_H
#define GLAMOR_EGL_EXT_H
/* Define needed tokens from EGL_EXT_image_dma_buf_import extension
* here to avoid having to add ifdefs everywhere.*/
#ifndef EGL_EXT_image_dma_buf_import
#define EGL_LINUX_DMA_BUF_EXT 0x3270
#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
#endif
/* Define tokens from EGL_EXT_image_dma_buf_import_modifiers */
#ifndef EGL_EXT_image_dma_buf_import_modifiers
#define EGL_EXT_image_dma_buf_import_modifiers 1
#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440
#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441
#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442
#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445
#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446
#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447
#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448
#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449
#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
#endif
#endif /* GLAMOR_EGL_EXT_H */
xorg-server-21.1.4/glamor/glamor_vbo.c 0000644 0001750 0001750 00000016003 14263273335 014567 0000000 0000000 /*
* Copyright © 2014 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.
*/
/**
* @file glamor_vbo.c
*
* Helpers for managing streamed vertex buffers used in glamor.
*/
#include "glamor_priv.h"
/** Default size of the VBO, in bytes.
*
* If a single request is larger than this size, we'll resize the VBO
* and return an appropriate mapping, but we'll resize back down after
* that to avoid hogging that memory forever. We don't anticipate
* normal usage actually requiring larger VBO sizes.
*/
#define GLAMOR_VBO_SIZE (512 * 1024)
/**
* Returns a pointer to @size bytes of VBO storage, which should be
* accessed by the GL using vbo_offset within the VBO.
*/
void *
glamor_get_vbo_space(ScreenPtr screen, unsigned size, char **vbo_offset)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
void *data;
glamor_make_current(glamor_priv);
glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
if (glamor_priv->has_buffer_storage) {
if (glamor_priv->vbo_size < glamor_priv->vbo_offset + size) {
if (glamor_priv->vbo_size)
glUnmapBuffer(GL_ARRAY_BUFFER);
if (size > glamor_priv->vbo_size) {
glamor_priv->vbo_size = MAX(GLAMOR_VBO_SIZE, size);
/* We aren't allowed to resize glBufferStorage()
* buffers, so we need to gen a new one.
*/
glDeleteBuffers(1, &glamor_priv->vbo);
glGenBuffers(1, &glamor_priv->vbo);
glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
assert(glGetError() == GL_NO_ERROR);
glBufferStorage(GL_ARRAY_BUFFER, glamor_priv->vbo_size, NULL,
GL_MAP_WRITE_BIT |
GL_MAP_PERSISTENT_BIT |
GL_MAP_COHERENT_BIT);
if (glGetError() != GL_NO_ERROR) {
/* If the driver failed our coherent mapping, fall
* back to the ARB_mbr path.
*/
glamor_priv->has_buffer_storage = false;
glamor_priv->vbo_size = 0;
return glamor_get_vbo_space(screen, size, vbo_offset);
}
}
glamor_priv->vbo_offset = 0;
glamor_priv->vb = glMapBufferRange(GL_ARRAY_BUFFER,
0, glamor_priv->vbo_size,
GL_MAP_WRITE_BIT |
GL_MAP_INVALIDATE_BUFFER_BIT |
GL_MAP_PERSISTENT_BIT |
GL_MAP_COHERENT_BIT);
}
*vbo_offset = (void *)(uintptr_t)glamor_priv->vbo_offset;
data = glamor_priv->vb + glamor_priv->vbo_offset;
glamor_priv->vbo_offset += size;
} else if (glamor_priv->has_map_buffer_range) {
/* Avoid GL errors on GL 4.5 / ES 3.0 with mapping size == 0,
* which callers may sometimes pass us (for example, if
* clipping leads to zero rectangles left). Prior to that
* version, Mesa would sometimes throw errors on unmapping a
* zero-size mapping.
*/
if (size == 0)
return NULL;
if (glamor_priv->vbo_size < glamor_priv->vbo_offset + size) {
glamor_priv->vbo_size = MAX(GLAMOR_VBO_SIZE, size);
glamor_priv->vbo_offset = 0;
glBufferData(GL_ARRAY_BUFFER,
glamor_priv->vbo_size, NULL, GL_STREAM_DRAW);
}
data = glMapBufferRange(GL_ARRAY_BUFFER,
glamor_priv->vbo_offset,
size,
GL_MAP_WRITE_BIT |
GL_MAP_UNSYNCHRONIZED_BIT |
GL_MAP_INVALIDATE_RANGE_BIT);
*vbo_offset = (char *)(uintptr_t)glamor_priv->vbo_offset;
glamor_priv->vbo_offset += size;
glamor_priv->vbo_mapped = TRUE;
} else {
/* Return a pointer to the statically allocated non-VBO
* memory. We'll upload it through glBufferData() later.
*/
if (glamor_priv->vbo_size < size) {
glamor_priv->vbo_size = MAX(GLAMOR_VBO_SIZE, size);
free(glamor_priv->vb);
glamor_priv->vb = xnfalloc(glamor_priv->vbo_size);
}
*vbo_offset = NULL;
/* We point to the start of glamor_priv->vb every time, and
* the vbo_offset determines the size of the glBufferData().
*/
glamor_priv->vbo_offset = size;
data = glamor_priv->vb;
}
return data;
}
void
glamor_put_vbo_space(ScreenPtr screen)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_make_current(glamor_priv);
if (glamor_priv->has_buffer_storage) {
/* If we're in the ARB_buffer_storage path, we have a
* persistent mapping, so we can leave it around until we
* reach the end of the buffer.
*/
} else if (glamor_priv->has_map_buffer_range) {
if (glamor_priv->vbo_mapped) {
glUnmapBuffer(GL_ARRAY_BUFFER);
glamor_priv->vbo_mapped = FALSE;
}
} else {
glBufferData(GL_ARRAY_BUFFER, glamor_priv->vbo_offset,
glamor_priv->vb, GL_DYNAMIC_DRAW);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void
glamor_init_vbo(ScreenPtr screen)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_make_current(glamor_priv);
glGenBuffers(1, &glamor_priv->vbo);
glGenVertexArrays(1, &glamor_priv->vao);
glBindVertexArray(glamor_priv->vao);
}
void
glamor_fini_vbo(ScreenPtr screen)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_make_current(glamor_priv);
glDeleteVertexArrays(1, &glamor_priv->vao);
glamor_priv->vao = 0;
if (!glamor_priv->has_map_buffer_range)
free(glamor_priv->vb);
}
xorg-server-21.1.4/glamor/glamor_core.c 0000644 0001750 0001750 00000021117 14263273335 014733 0000000 0000000 /*
* 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
*
*/
/** @file glamor_core.c
*
* This file covers core X rendering in glamor.
*/
#include
#include "glamor_priv.h"
Bool
glamor_get_drawable_location(const DrawablePtr drawable)
{
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
if (pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED)
return 'm';
else
return 'f';
}
GLint
glamor_compile_glsl_prog(GLenum type, const char *source)
{
GLint ok;
GLint prog;
prog = glCreateShader(type);
glShaderSource(prog, 1, (const GLchar **) &source, NULL);
glCompileShader(prog);
glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
if (!ok) {
GLchar *info;
GLint size;
glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
info = malloc(size);
if (info) {
glGetShaderInfoLog(prog, size, NULL, info);
ErrorF("Failed to compile %s: %s\n",
type == GL_FRAGMENT_SHADER ? "FS" : "VS", info);
ErrorF("Program source:\n%s", source);
free(info);
}
else
ErrorF("Failed to get shader compilation info.\n");
FatalError("GLSL compile failure\n");
}
return prog;
}
void
glamor_link_glsl_prog(ScreenPtr screen, GLint prog, const char *format, ...)
{
GLint ok;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
if (glamor_priv->has_khr_debug) {
char *label;
va_list va;
va_start(va, format);
XNFvasprintf(&label, format, va);
glObjectLabel(GL_PROGRAM, prog, -1, label);
free(label);
va_end(va);
}
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &ok);
if (!ok) {
GLchar *info;
GLint size;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
info = malloc(size);
glGetProgramInfoLog(prog, size, NULL, info);
ErrorF("Failed to link: %s\n", info);
FatalError("GLSL link failure\n");
}
}
static GCOps glamor_gc_ops = {
.FillSpans = glamor_fill_spans,
.SetSpans = glamor_set_spans,
.PutImage = glamor_put_image,
.CopyArea = glamor_copy_area,
.CopyPlane = glamor_copy_plane,
.PolyPoint = glamor_poly_point,
.Polylines = glamor_poly_lines,
.PolySegment = glamor_poly_segment,
.PolyRectangle = miPolyRectangle,
.PolyArc = miPolyArc,
.FillPolygon = miFillPolygon,
.PolyFillRect = glamor_poly_fill_rect,
.PolyFillArc = miPolyFillArc,
.PolyText8 = glamor_poly_text8,
.PolyText16 = glamor_poly_text16,
.ImageText8 = glamor_image_text8,
.ImageText16 = glamor_image_text16,
.ImageGlyphBlt = miImageGlyphBlt,
.PolyGlyphBlt = glamor_poly_glyph_blt,
.PushPixels = glamor_push_pixels,
};
/*
* When the stipple is changed or drawn to, invalidate any
* cached copy
*/
static void
glamor_invalidate_stipple(GCPtr gc)
{
glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
if (gc_priv->stipple) {
if (gc_priv->stipple_damage)
DamageUnregister(gc_priv->stipple_damage);
glamor_destroy_pixmap(gc_priv->stipple);
gc_priv->stipple = NULL;
}
}
static void
glamor_stipple_damage_report(DamagePtr damage, RegionPtr region,
void *closure)
{
GCPtr gc = closure;
glamor_invalidate_stipple(gc);
}
static void
glamor_stipple_damage_destroy(DamagePtr damage, void *closure)
{
GCPtr gc = closure;
glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
gc_priv->stipple_damage = NULL;
glamor_invalidate_stipple(gc);
}
void
glamor_track_stipple(GCPtr gc)
{
if (gc->stipple) {
glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
if (!gc_priv->stipple_damage)
gc_priv->stipple_damage = DamageCreate(glamor_stipple_damage_report,
glamor_stipple_damage_destroy,
DamageReportNonEmpty,
TRUE, gc->pScreen, gc);
if (gc_priv->stipple_damage)
DamageRegister(&gc->stipple->drawable, gc_priv->stipple_damage);
}
}
/**
* uxa_validate_gc() sets the ops to glamor's implementations, which may be
* accelerated or may sync the card and fall back to fb.
*/
void
glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
{
/* 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.
*/
if (changes & GCTile) {
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, GLAMOR_ACCESS_RW)) {
fbPadPixmap(gc->tile.pixmap);
glamor_finish_access(&gc->tile.pixmap->drawable);
}
}
}
/* Mask out the GCTile change notification, now that we've done FB's
* job for it.
*/
changes &= ~GCTile;
}
if (changes & GCStipple)
glamor_invalidate_stipple(gc);
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);
}
}
else {
fbValidateGC(gc, changes, drawable);
}
if (changes & GCDashList) {
glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
if (gc_priv->dash) {
glamor_destroy_pixmap(gc_priv->dash);
gc_priv->dash = NULL;
}
}
gc->ops = &glamor_gc_ops;
}
void
glamor_destroy_gc(GCPtr gc)
{
glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
if (gc_priv->dash) {
glamor_destroy_pixmap(gc_priv->dash);
gc_priv->dash = NULL;
}
glamor_invalidate_stipple(gc);
if (gc_priv->stipple_damage)
DamageDestroy(gc_priv->stipple_damage);
miDestroyGC(gc);
}
static GCFuncs glamor_gc_funcs = {
glamor_validate_gc,
miChangeGC,
miCopyGC,
glamor_destroy_gc,
miChangeClip,
miDestroyClip,
miCopyClip
};
/**
* exaCreateGC makes a new GC and hooks up its funcs handler, so that
* exaValidateGC() will get called.
*/
int
glamor_create_gc(GCPtr gc)
{
glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
gc_priv->dash = NULL;
gc_priv->stipple = NULL;
if (!fbCreateGC(gc))
return FALSE;
gc->funcs = &glamor_gc_funcs;
return TRUE;
}
RegionPtr
glamor_bitmap_to_region(PixmapPtr pixmap)
{
RegionPtr ret;
glamor_fallback("pixmap %p \n", pixmap);
if (!glamor_prepare_access(&pixmap->drawable, GLAMOR_ACCESS_RO))
return NULL;
ret = fbPixmapToRegion(pixmap);
glamor_finish_access(&pixmap->drawable);
return ret;
}
xorg-server-21.1.4/glamor/glamor_window.c 0000644 0001750 0001750 00000004635 14263273335 015320 0000000 0000000 /*
* Copyright © 2008 Intel Corporation
* Copyright © 1998 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "glamor_priv.h"
/** @file glamor_window.c
*
* Screen Change Window Attribute implementation.
*/
static void
glamor_fixup_window_pixmap(DrawablePtr pDrawable, PixmapPtr *ppPixmap)
{
PixmapPtr pPixmap = *ppPixmap;
glamor_pixmap_private *pixmap_priv;
if (pPixmap->drawable.bitsPerPixel != pDrawable->bitsPerPixel) {
pixmap_priv = glamor_get_pixmap_private(pPixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
glamor_fallback("pixmap %p has no fbo\n", pPixmap);
goto fail;
}
glamor_debug_output(GLAMOR_DEBUG_UNIMPL, "To be implemented.\n");
}
return;
fail:
GLAMOR_PANIC
(" We can't fall back to fbFixupWindowPixmap, as the fb24_32ReformatTile"
" is broken for glamor. \n");
}
Bool
glamor_change_window_attributes(WindowPtr pWin, unsigned long mask)
{
if (mask & CWBackPixmap) {
if (pWin->backgroundState == BackgroundPixmap)
glamor_fixup_window_pixmap(&pWin->drawable,
&pWin->background.pixmap);
}
if (mask & CWBorderPixmap) {
if (pWin->borderIsPixel == FALSE)
glamor_fixup_window_pixmap(&pWin->drawable, &pWin->border.pixmap);
}
return TRUE;
}
xorg-server-21.1.4/glamor/glamor_dash.c 0000644 0001750 0001750 00000025075 14263273335 014731 0000000 0000000 /*
* Copyright © 2014 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "glamor_priv.h"
#include "glamor_program.h"
#include "glamor_transform.h"
#include "glamor_transfer.h"
#include "glamor_prepare.h"
static const char dash_vs_vars[] =
"attribute vec3 primitive;\n"
"varying float dash_offset;\n";
static const char dash_vs_exec[] =
" dash_offset = primitive.z / dash_length;\n"
" vec2 pos = vec2(0,0);\n"
GLAMOR_POS(gl_Position, primitive.xy);
static const char dash_fs_vars[] =
"varying float dash_offset;\n";
static const char on_off_fs_exec[] =
" float pattern = texture2D(dash, vec2(dash_offset, 0.5)).w;\n"
" if (pattern == 0.0)\n"
" discard;\n";
/* XXX deal with stippled double dashed lines once we have stippling support */
static const char double_fs_exec[] =
" float pattern = texture2D(dash, vec2(dash_offset, 0.5)).w;\n"
" if (pattern == 0.0)\n"
" gl_FragColor = bg;\n"
" else\n"
" gl_FragColor = fg;\n";
static const glamor_facet glamor_facet_on_off_dash_lines = {
.version = 130,
.name = "poly_lines_on_off_dash",
.vs_vars = dash_vs_vars,
.vs_exec = dash_vs_exec,
.fs_vars = dash_fs_vars,
.fs_exec = on_off_fs_exec,
.locations = glamor_program_location_dash,
};
static const glamor_facet glamor_facet_double_dash_lines = {
.version = 130,
.name = "poly_lines_double_dash",
.vs_vars = dash_vs_vars,
.vs_exec = dash_vs_exec,
.fs_vars = dash_fs_vars,
.fs_exec = double_fs_exec,
.locations = (glamor_program_location_dash|
glamor_program_location_fg|
glamor_program_location_bg),
};
static PixmapPtr
glamor_get_dash_pixmap(GCPtr gc)
{
glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
ScreenPtr screen = gc->pScreen;
PixmapPtr pixmap;
int offset;
int d;
uint32_t pixel;
GCPtr scratch_gc;
if (gc_priv->dash)
return gc_priv->dash;
offset = 0;
for (d = 0; d < gc->numInDashList; d++)
offset += gc->dash[d];
pixmap = glamor_create_pixmap(screen, offset, 1, 8, 0);
if (!pixmap)
goto bail;
scratch_gc = GetScratchGC(8, screen);
if (!scratch_gc)
goto bail_pixmap;
pixel = 0xffffffff;
offset = 0;
for (d = 0; d < gc->numInDashList; d++) {
xRectangle rect;
ChangeGCVal changes;
changes.val = pixel;
(void) ChangeGC(NullClient, scratch_gc,
GCForeground, &changes);
ValidateGC(&pixmap->drawable, scratch_gc);
rect.x = offset;
rect.y = 0;
rect.width = gc->dash[d];
rect.height = 1;
scratch_gc->ops->PolyFillRect (&pixmap->drawable, scratch_gc, 1, &rect);
offset += gc->dash[d];
pixel = ~pixel;
}
FreeScratchGC(scratch_gc);
gc_priv->dash = pixmap;
return pixmap;
bail_pixmap:
glamor_destroy_pixmap(pixmap);
bail:
return NULL;
}
static glamor_program *
glamor_dash_setup(DrawablePtr drawable, GCPtr gc)
{
ScreenPtr screen = drawable->pScreen;
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
PixmapPtr dash_pixmap;
glamor_pixmap_private *dash_priv;
glamor_program *prog;
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
goto bail;
if (gc->lineWidth != 0)
goto bail;
dash_pixmap = glamor_get_dash_pixmap(gc);
dash_priv = glamor_get_pixmap_private(dash_pixmap);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dash_priv))
goto bail;
glamor_make_current(glamor_priv);
switch (gc->lineStyle) {
case LineOnOffDash:
prog = glamor_use_program_fill(pixmap, gc,
&glamor_priv->on_off_dash_line_progs,
&glamor_facet_on_off_dash_lines);
if (!prog)
goto bail;
break;
case LineDoubleDash:
if (gc->fillStyle != FillSolid)
goto bail;
prog = &glamor_priv->double_dash_line_prog;
if (!prog->prog) {
if (!glamor_build_program(screen, prog,
&glamor_facet_double_dash_lines,
NULL, NULL, NULL))
goto bail;
}
if (!glamor_use_program(pixmap, gc, prog, NULL))
goto bail;
glamor_set_color(pixmap, gc->fgPixel, prog->fg_uniform);
glamor_set_color(pixmap, gc->bgPixel, prog->bg_uniform);
break;
default:
goto bail;
}
/* Set the dash pattern as texture 1 */
glamor_bind_texture(glamor_priv, GL_TEXTURE1, dash_priv->fbo, FALSE);
glUniform1i(prog->dash_uniform, 1);
glUniform1f(prog->dash_length_uniform, dash_pixmap->drawable.width);
return prog;
bail:
return NULL;
}
static void
glamor_dash_loop(DrawablePtr drawable, GCPtr gc, glamor_program *prog,
int n, GLenum mode)
{
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
int box_index;
int off_x, off_y;
glEnable(GL_SCISSOR_TEST);
glamor_pixmap_loop(pixmap_priv, box_index) {
int nbox = RegionNumRects(gc->pCompositeClip);
BoxPtr box = RegionRects(gc->pCompositeClip);
glamor_set_destination_drawable(drawable, box_index, TRUE, TRUE,
prog->matrix_uniform, &off_x, &off_y);
while (nbox--) {
glScissor(box->x1 + off_x,
box->y1 + off_y,
box->x2 - box->x1,
box->y2 - box->y1);
box++;
glDrawArrays(mode, 0, n);
}
}
glDisable(GL_SCISSOR_TEST);
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
}
static int
glamor_line_length(short x1, short y1, short x2, short y2)
{
return max(abs(x2 - x1), abs(y2 - y1));
}
Bool
glamor_poly_lines_dash_gl(DrawablePtr drawable, GCPtr gc,
int mode, int n, DDXPointPtr points)
{
ScreenPtr screen = drawable->pScreen;
glamor_program *prog;
short *v;
char *vbo_offset;
int add_last;
int dash_pos;
int prev_x, prev_y;
int i;
if (n < 2)
return TRUE;
if (!(prog = glamor_dash_setup(drawable, gc)))
return FALSE;
add_last = 0;
if (gc->capStyle != CapNotLast)
add_last = 1;
/* Set up the vertex buffers for the points */
v = glamor_get_vbo_space(drawable->pScreen,
(n + add_last) * 3 * sizeof (short),
&vbo_offset);
glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
glVertexAttribPointer(GLAMOR_VERTEX_POS, 3, GL_SHORT, GL_FALSE,
3 * sizeof (short), vbo_offset);
dash_pos = gc->dashOffset;
prev_x = prev_y = 0;
for (i = 0; i < n; i++) {
int this_x = points[i].x;
int this_y = points[i].y;
if (i) {
if (mode == CoordModePrevious) {
this_x += prev_x;
this_y += prev_y;
}
dash_pos += glamor_line_length(prev_x, prev_y,
this_x, this_y);
}
v[0] = prev_x = this_x;
v[1] = prev_y = this_y;
v[2] = dash_pos;
v += 3;
}
if (add_last) {
v[0] = prev_x + 1;
v[1] = prev_y;
v[2] = dash_pos + 1;
}
glamor_put_vbo_space(screen);
glamor_dash_loop(drawable, gc, prog, n + add_last, GL_LINE_STRIP);
return TRUE;
}
static short *
glamor_add_segment(short *v, short x1, short y1, short x2, short y2,
int dash_start, int dash_end)
{
v[0] = x1;
v[1] = y1;
v[2] = dash_start;
v[3] = x2;
v[4] = y2;
v[5] = dash_end;
return v + 6;
}
Bool
glamor_poly_segment_dash_gl(DrawablePtr drawable, GCPtr gc,
int nseg, xSegment *segs)
{
ScreenPtr screen = drawable->pScreen;
glamor_program *prog;
short *v;
char *vbo_offset;
int dash_start = gc->dashOffset;
int add_last;
int i;
if (!(prog = glamor_dash_setup(drawable, gc)))
return FALSE;
add_last = 0;
if (gc->capStyle != CapNotLast)
add_last = 1;
/* Set up the vertex buffers for the points */
v = glamor_get_vbo_space(drawable->pScreen,
(nseg<