mirror of https://github.com/yshui/picom.git
backend: gl: change how coordinates are modeled
So they closely match what the new backend interface wants. The GL backends' coordinate system is so complicated, I don't think I ever fully understood it. Hopefully it is clearer now. I made it so all intermediate images used in the backend all have the same coordinate system as the X server (i.e. (0, 0) at top-left, Y down, X to the right), only at the final present step are the coordinates flipped. Thus reduce the number of places where Y-flipping is done. X pixmaps are usually Y-down as well, even if they are not, the backend should handle them fine as well (though there's no way for me to test that). (Cloned X pixmaps will have the same coordinates as X pixmaps, so if X pixmaps aren't Y-down, there will also be some complications there. But we will get rid of image cloning in the new interface, so it's OK). Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
134856c55e
commit
318bfffaa5
|
@ -31,15 +31,6 @@ typedef struct backend_base {
|
|||
// ...
|
||||
} backend_t;
|
||||
|
||||
typedef struct geometry {
|
||||
int width;
|
||||
int height;
|
||||
} geometry_t;
|
||||
|
||||
typedef struct coord {
|
||||
int x, y;
|
||||
} coord_t;
|
||||
|
||||
typedef void (*backend_ready_callback_t)(void *);
|
||||
|
||||
// This mimics OpenGL's ARB_robustness extension, which enables detection of GPU context
|
||||
|
|
|
@ -40,12 +40,10 @@ struct gl_blur_context {
|
|||
/**
|
||||
* Blur contents in a particular region.
|
||||
*/
|
||||
bool gl_kernel_blur(double opacity, struct gl_blur_context *bctx, const rect_t *extent,
|
||||
struct backend_image *mask, coord_t mask_dst, const GLuint vao[2],
|
||||
const int vao_nelems[2], GLuint source_texture,
|
||||
geometry_t source_size, GLuint target_fbo, GLuint default_mask) {
|
||||
int dst_y_fb_coord = bctx->fb_height - extent->y2;
|
||||
|
||||
static bool gl_kernel_blur(double opacity, struct gl_blur_context *bctx,
|
||||
struct backend_image *mask, coord_t mask_dst, const GLuint vao[2],
|
||||
const int vao_nelems[2], GLuint source_texture,
|
||||
geometry_t source_size, GLuint target_fbo, GLuint default_mask) {
|
||||
int curr = 0;
|
||||
for (int i = 0; i < bctx->npasses; ++i) {
|
||||
auto p = &bctx->blur_shader[i];
|
||||
|
@ -54,7 +52,6 @@ bool gl_kernel_blur(double opacity, struct gl_blur_context *bctx, const rect_t *
|
|||
assert(bctx->blur_textures[curr]);
|
||||
|
||||
// The origin to use when sampling from the source texture
|
||||
GLint texorig_x = extent->x1, texorig_y = dst_y_fb_coord;
|
||||
GLint tex_width, tex_height;
|
||||
GLuint src_texture;
|
||||
|
||||
|
@ -117,9 +114,8 @@ bool gl_kernel_blur(double opacity, struct gl_blur_context *bctx, const rect_t *
|
|||
glUniform1i(UNIFORM_MASK_INVERTED_LOC, mask->color_inverted);
|
||||
glUniform1f(UNIFORM_MASK_CORNER_RADIUS_LOC,
|
||||
(float)mask->corner_radius);
|
||||
glUniform2f(
|
||||
UNIFORM_MASK_OFFSET_LOC, (float)(mask_dst.x),
|
||||
(float)(bctx->fb_height - mask_dst.y - inner->height));
|
||||
glUniform2f(UNIFORM_MASK_OFFSET_LOC, (float)(mask_dst.x),
|
||||
(float)(mask_dst.y));
|
||||
}
|
||||
glBindVertexArray(vao[0]);
|
||||
nelems = vao_nelems[0];
|
||||
|
@ -128,7 +124,6 @@ bool gl_kernel_blur(double opacity, struct gl_blur_context *bctx, const rect_t *
|
|||
glUniform1f(UNIFORM_OPACITY_LOC, (float)opacity);
|
||||
}
|
||||
|
||||
glUniform2f(UNIFORM_TEXORIG_LOC, (GLfloat)texorig_x, (GLfloat)texorig_y);
|
||||
glDrawElements(GL_TRIANGLES, nelems, GL_UNSIGNED_INT, NULL);
|
||||
|
||||
// XXX use multiple draw calls is probably going to be slow than
|
||||
|
@ -140,12 +135,10 @@ bool gl_kernel_blur(double opacity, struct gl_blur_context *bctx, const rect_t *
|
|||
return true;
|
||||
}
|
||||
|
||||
bool gl_dual_kawase_blur(double opacity, struct gl_blur_context *bctx, const rect_t *extent,
|
||||
bool gl_dual_kawase_blur(double opacity, struct gl_blur_context *bctx,
|
||||
struct backend_image *mask, coord_t mask_dst, const GLuint vao[2],
|
||||
const int vao_nelems[2], GLuint source_texture,
|
||||
geometry_t source_size, GLuint target_fbo, GLuint default_mask) {
|
||||
int dst_y_fb_coord = bctx->fb_height - extent->y2;
|
||||
|
||||
int iterations = bctx->blur_texture_count;
|
||||
int scale_factor = 1;
|
||||
|
||||
|
@ -154,8 +147,6 @@ bool gl_dual_kawase_blur(double opacity, struct gl_blur_context *bctx, const rec
|
|||
assert(down_pass->prog);
|
||||
glUseProgram(down_pass->prog);
|
||||
|
||||
glUniform2f(UNIFORM_TEXORIG_LOC, (GLfloat)extent->x1, (GLfloat)dst_y_fb_coord);
|
||||
|
||||
glBindVertexArray(vao[1]);
|
||||
int nelems = vao_nelems[1];
|
||||
|
||||
|
@ -200,8 +191,6 @@ bool gl_dual_kawase_blur(double opacity, struct gl_blur_context *bctx, const rec
|
|||
assert(up_pass->prog);
|
||||
glUseProgram(up_pass->prog);
|
||||
|
||||
glUniform2f(UNIFORM_TEXORIG_LOC, (GLfloat)extent->x1, (GLfloat)dst_y_fb_coord);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, default_mask);
|
||||
|
||||
|
@ -241,9 +230,8 @@ bool gl_dual_kawase_blur(double opacity, struct gl_blur_context *bctx, const rec
|
|||
glUniform1i(UNIFORM_MASK_INVERTED_LOC, mask->color_inverted);
|
||||
glUniform1f(UNIFORM_MASK_CORNER_RADIUS_LOC,
|
||||
(float)mask->corner_radius);
|
||||
glUniform2f(
|
||||
UNIFORM_MASK_OFFSET_LOC, (float)(mask_dst.x),
|
||||
(float)(bctx->fb_height - mask_dst.y - inner->height));
|
||||
glUniform2f(UNIFORM_MASK_OFFSET_LOC, (float)(mask_dst.x),
|
||||
(float)(mask_dst.y));
|
||||
}
|
||||
glBindVertexArray(vao[0]);
|
||||
nelems = vao_nelems[0];
|
||||
|
@ -309,17 +297,19 @@ static bool gl_blur_context_preallocate_textures(struct gl_blur_context *bctx,
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Internal function that does the blur.
|
||||
///
|
||||
/// @param source_y_inverted whether `source_texture` is y inverted.
|
||||
bool gl_blur_impl(double opacity, struct gl_blur_context *bctx,
|
||||
struct backend_image *mask, coord_t mask_dst, const region_t *reg_blur,
|
||||
const region_t *reg_visible attr_unused, GLuint source_texture,
|
||||
geometry_t source_size, GLuint target_fbo, GLuint default_mask) {
|
||||
GLuint source_texture, geometry_t source_size, bool source_y_inverted,
|
||||
GLuint target_fbo, GLuint default_mask) {
|
||||
bool ret = false;
|
||||
|
||||
// Remainder: regions are in Xorg coordinates
|
||||
auto reg_blur_resized =
|
||||
resize_region(reg_blur, bctx->resize_width, bctx->resize_height);
|
||||
const rect_t *extent = pixman_region32_extents((region_t *)reg_blur),
|
||||
*extent_resized = pixman_region32_extents(®_blur_resized);
|
||||
const rect_t *extent = pixman_region32_extents((region_t *)reg_blur);
|
||||
int width = extent->x2 - extent->x1, height = extent->y2 - extent->y1;
|
||||
if (width == 0 || height == 0) {
|
||||
return true;
|
||||
|
@ -339,18 +329,16 @@ bool gl_blur_impl(double opacity, struct gl_blur_context *bctx,
|
|||
|
||||
auto coord = ccalloc(nrects * 16, GLint);
|
||||
auto indices = ccalloc(nrects * 6, GLuint);
|
||||
auto extent_height = extent_resized->y2 - extent_resized->y1;
|
||||
x_rect_to_coords(
|
||||
nrects, rects, (coord_t){.x = extent_resized->x1, .y = extent_resized->y1},
|
||||
extent_height, bctx->fb_height, source_size.height, false, coord, indices);
|
||||
gl_mask_rects_to_coords_simple(nrects, rects, coord, indices);
|
||||
|
||||
auto coord_resized = ccalloc(nrects_resized * 16, GLint);
|
||||
auto indices_resized = ccalloc(nrects_resized * 6, GLuint);
|
||||
x_rect_to_coords(nrects_resized, rects_resized,
|
||||
(coord_t){.x = extent_resized->x1, .y = extent_resized->y1},
|
||||
extent_height, bctx->fb_height, bctx->fb_height, false,
|
||||
coord_resized, indices_resized);
|
||||
gl_mask_rects_to_coords_simple(nrects_resized, rects_resized, coord_resized,
|
||||
indices_resized);
|
||||
pixman_region32_fini(®_blur_resized);
|
||||
// FIXME(yshui) In theory we should handle blurring a non-y-inverted source, but
|
||||
// we never actually use that capability anywhere.
|
||||
assert(source_y_inverted);
|
||||
|
||||
GLuint vao[2];
|
||||
glGenVertexArrays(2, vao);
|
||||
|
@ -386,13 +374,12 @@ bool gl_blur_impl(double opacity, struct gl_blur_context *bctx,
|
|||
int vao_nelems[2] = {nrects * 6, nrects_resized * 6};
|
||||
|
||||
if (bctx->method == BLUR_METHOD_DUAL_KAWASE) {
|
||||
ret = gl_dual_kawase_blur(opacity, bctx, extent_resized, mask, mask_dst,
|
||||
vao, vao_nelems, source_texture, source_size,
|
||||
target_fbo, default_mask);
|
||||
ret = gl_dual_kawase_blur(opacity, bctx, mask, mask_dst, vao, vao_nelems,
|
||||
source_texture, source_size, target_fbo,
|
||||
default_mask);
|
||||
} else {
|
||||
ret = gl_kernel_blur(opacity, bctx, extent_resized, mask, mask_dst, vao,
|
||||
vao_nelems, source_texture, source_size, target_fbo,
|
||||
default_mask);
|
||||
ret = gl_kernel_blur(opacity, bctx, mask, mask_dst, vao, vao_nelems,
|
||||
source_texture, source_size, target_fbo, default_mask);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
@ -421,8 +408,8 @@ bool gl_blur(backend_t *base, double opacity, void *ctx, image_handle mask, coor
|
|||
auto gd = (struct gl_data *)base;
|
||||
auto bctx = (struct gl_blur_context *)ctx;
|
||||
return gl_blur_impl(opacity, bctx, (struct backend_image *)mask, mask_dst,
|
||||
reg_blur, reg_visible, gd->back_texture,
|
||||
(geometry_t){.width = gd->width, .height = gd->height},
|
||||
reg_blur, gd->back_texture,
|
||||
(geometry_t){.width = gd->width, .height = gd->height}, true,
|
||||
gd->back_fbo, gd->default_mask_texture);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
#include <epoxy/gl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
@ -354,12 +355,13 @@ struct gl_uniform_value {
|
|||
* @param indices GL indices
|
||||
* @param nrects number of rectangles to render
|
||||
*/
|
||||
static void
|
||||
gl_blit_inner(GLuint target_fbo, GLint *coord, GLuint *indices, int nrects,
|
||||
struct gl_shader *shader, int nuniforms, struct gl_uniform_value *uniforms) {
|
||||
static void gl_blit_inner(GLuint target_fbo, GLint *coord, GLuint *indices, int nrects,
|
||||
const struct gl_shader *shader, int nuniforms,
|
||||
struct gl_uniform_value *uniforms) {
|
||||
// FIXME(yshui) breaks when `mask` and `img` doesn't have the same y_inverted
|
||||
// value. but we don't ever hit this problem because all of our
|
||||
// images and masks are y_inverted.
|
||||
log_trace("Blitting %d rectangles", nrects);
|
||||
assert(shader);
|
||||
assert(shader->prog);
|
||||
glUseProgram(shader->prog);
|
||||
|
@ -440,13 +442,104 @@ gl_blit_inner(GLuint target_fbo, GLint *coord, GLuint *indices, int nrects,
|
|||
gl_check_err();
|
||||
}
|
||||
|
||||
static void
|
||||
gl_blit_args_to_uniforms(struct gl_data *gd, struct backend_blit_args *args,
|
||||
struct gl_shader **shader, struct gl_uniform_value *uniforms) {
|
||||
void gl_mask_rects_to_coords(struct coord origin, struct coord mask_origin, int nrects,
|
||||
const rect_t *rects, GLint *coord, GLuint *indices) {
|
||||
for (ptrdiff_t i = 0; i < nrects; i++) {
|
||||
// Rectangle in source image coordinates
|
||||
rect_t rect_src = region_translate_rect(rects[i], mask_origin);
|
||||
// Rectangle in target image coordinates
|
||||
rect_t rect_dst = region_translate_rect(rect_src, origin);
|
||||
|
||||
memcpy(&coord[i * 16],
|
||||
((GLint[][2]){
|
||||
{rect_dst.x1, rect_dst.y1}, // Vertex, bottom-left
|
||||
{rect_src.x1, rect_src.y1}, // Texture
|
||||
{rect_dst.x2, rect_dst.y1}, // Vertex, bottom-right
|
||||
{rect_src.x2, rect_src.y1}, // Texture
|
||||
{rect_dst.x2, rect_dst.y2}, // Vertex, top-right
|
||||
{rect_src.x2, rect_src.y2}, // Texture
|
||||
{rect_dst.x1, rect_dst.y2}, // Vertex, top-left
|
||||
{rect_src.x1, rect_src.y2}, // Texture
|
||||
}),
|
||||
sizeof(GLint[2]) * 8);
|
||||
|
||||
GLuint u = (GLuint)(i * 4);
|
||||
memcpy(&indices[i * 6],
|
||||
((GLuint[]){u + 0, u + 1, u + 2, u + 2, u + 3, u + 0}),
|
||||
sizeof(GLuint) * 6);
|
||||
}
|
||||
}
|
||||
|
||||
/// Flip the target coordinates returned by `gl_mask_rects_to_coords` vertically relative
|
||||
/// to the target. Texture coordinates are unchanged.
|
||||
///
|
||||
/// @param[in] nrects number of rectangles
|
||||
/// @param[in] coord OpenGL vertex coordinates
|
||||
/// @param[in] target_height height of the target image
|
||||
static void gl_y_flip_target(int nrects, GLint *coord, GLint target_height) {
|
||||
for (ptrdiff_t i = 0; i < nrects; i++) {
|
||||
auto current_rect = &coord[i * 16]; // 16 numbers per rectangle
|
||||
for (ptrdiff_t j = 0; j < 4; j++) {
|
||||
// 4 numbers per vertex, target coordinates are the first two
|
||||
auto current_vertex = ¤t_rect[j * 4];
|
||||
current_vertex[1] = target_height - current_vertex[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Flip the texture coordinates returned by `gl_mask_rects_to_coords` vertically relative
|
||||
/// to the texture. Target coordinates are unchanged.
|
||||
///
|
||||
/// @param[in] nrects number of rectangles
|
||||
/// @param[in] coord OpenGL vertex coordinates
|
||||
/// @param[in] texture_height height of the source image
|
||||
static inline void gl_y_flip_texture(int nrects, GLint *coord, GLint texture_height) {
|
||||
for (ptrdiff_t i = 0; i < nrects; i++) {
|
||||
auto current_rect = &coord[i * 16]; // 16 numbers per rectangle
|
||||
for (ptrdiff_t j = 0; j < 4; j++) {
|
||||
// 4 numbers per vertex, texture coordinates are the last two
|
||||
auto current_vertex = ¤t_rect[j * 4 + 2];
|
||||
current_vertex[1] = texture_height - current_vertex[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower `struct backend_blit_args` into a list of GL coordinates, vertex indices, a
|
||||
/// shader, and uniforms.
|
||||
static int gl_lower_blit_args(struct gl_data *gd, struct coord origin,
|
||||
struct backend_blit_args *args, GLint **coord, GLuint **indices,
|
||||
struct gl_shader **shader, struct gl_uniform_value *uniforms) {
|
||||
auto img = (struct gl_texture *)args->source_image;
|
||||
int nrects;
|
||||
const rect_t *rects;
|
||||
rect_t source_extent;
|
||||
if (args->mask != NULL) {
|
||||
rects = pixman_region32_rectangles(&args->mask->region, &nrects);
|
||||
} else {
|
||||
nrects = 1;
|
||||
source_extent = (rect_t){0, 0, args->ewidth, args->eheight};
|
||||
rects = &source_extent;
|
||||
}
|
||||
if (!nrects) {
|
||||
// Nothing to paint
|
||||
return 0;
|
||||
}
|
||||
struct coord mask_origin = {};
|
||||
if (args->mask != NULL) {
|
||||
mask_origin = args->mask->origin;
|
||||
}
|
||||
*coord = ccalloc(nrects * 16, GLint);
|
||||
*indices = ccalloc(nrects * 6, GLuint);
|
||||
gl_mask_rects_to_coords(origin, mask_origin, nrects, rects, *coord, *indices);
|
||||
if (!img->y_inverted) {
|
||||
gl_y_flip_texture(nrects, *coord, img->height);
|
||||
}
|
||||
|
||||
auto mask_image = args->mask ? (struct gl_texture *)args->mask->image : NULL;
|
||||
auto mask_texture = mask_image ? mask_image->texture : gd->default_mask_texture;
|
||||
GLuint brightness = 0;
|
||||
GLuint brightness = 0; // 0 means the default texture, which will be
|
||||
// incomplete, and sampling from it will return (0,
|
||||
// 0, 0, 1), which should be fine.
|
||||
if (args->max_brightness < 1.0) {
|
||||
brightness = gl_average_texture_color(gd, img);
|
||||
}
|
||||
|
@ -486,70 +579,25 @@ gl_blit_args_to_uniforms(struct gl_data *gd, struct backend_blit_args *args,
|
|||
}
|
||||
memcpy(uniforms, from_uniforms, sizeof(from_uniforms));
|
||||
*shader = args->shader ?: &gd->default_shader;
|
||||
return nrects;
|
||||
}
|
||||
|
||||
/// Convert rectangles in X coordinates to OpenGL vertex and texture coordinates
|
||||
/// @param[in] nrects, rects rectangles
|
||||
/// @param[in] image_dst origin of the OpenGL texture, affect the calculated texture
|
||||
/// coordinates
|
||||
/// @param[in] extend_height height of the drawing extent
|
||||
/// @param[in] texture_height height of the OpenGL texture
|
||||
/// @param[in] root_height height of the back buffer
|
||||
/// @param[in] y_inverted whether the texture is y inverted
|
||||
/// @param[out] coord, indices output
|
||||
void x_rect_to_coords(int nrects, const rect_t *rects, coord_t image_dst,
|
||||
int extent_height, int texture_height, int root_height,
|
||||
bool y_inverted, GLint *coord, GLuint *indices) {
|
||||
image_dst.y = root_height - image_dst.y;
|
||||
image_dst.y -= extent_height;
|
||||
|
||||
for (int i = 0; i < nrects; i++) {
|
||||
// Y-flip. Note after this, crect.y1 > crect.y2
|
||||
rect_t crect = rects[i];
|
||||
crect.y1 = root_height - crect.y1;
|
||||
crect.y2 = root_height - crect.y2;
|
||||
|
||||
// Calculate texture coordinates
|
||||
// (texture_x1, texture_y1), texture coord for the _bottom left_ corner
|
||||
GLint texture_x1 = crect.x1 - image_dst.x,
|
||||
texture_y1 = crect.y2 - image_dst.y,
|
||||
texture_x2 = texture_x1 + (crect.x2 - crect.x1),
|
||||
texture_y2 = texture_y1 + (crect.y1 - crect.y2);
|
||||
|
||||
// X pixmaps might be Y inverted, invert the texture coordinates
|
||||
if (y_inverted) {
|
||||
texture_y1 = texture_height - texture_y1;
|
||||
texture_y2 = texture_height - texture_y2;
|
||||
}
|
||||
|
||||
// Vertex coordinates
|
||||
auto vx1 = crect.x1;
|
||||
auto vy1 = crect.y2;
|
||||
auto vx2 = crect.x2;
|
||||
auto vy2 = crect.y1;
|
||||
|
||||
// log_trace("Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d",
|
||||
// ri, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
|
||||
|
||||
memcpy(&coord[i * 16],
|
||||
((GLint[][2]){
|
||||
{vx1, vy1},
|
||||
{texture_x1, texture_y1},
|
||||
{vx2, vy1},
|
||||
{texture_x2, texture_y1},
|
||||
{vx2, vy2},
|
||||
{texture_x2, texture_y2},
|
||||
{vx1, vy2},
|
||||
{texture_x1, texture_y2},
|
||||
}),
|
||||
sizeof(GLint[2]) * 8);
|
||||
|
||||
GLuint u = (GLuint)(i * 4);
|
||||
memcpy(&indices[i * 6],
|
||||
((GLuint[]){u + 0, u + 1, u + 2, u + 2, u + 3, u + 0}),
|
||||
sizeof(GLuint) * 6);
|
||||
}
|
||||
}
|
||||
static const struct gl_uniform_value default_blit_uniforms[] = {
|
||||
[UNIFORM_OPACITY_LOC] = {.type = GL_FLOAT, .f = 1.0F},
|
||||
[UNIFORM_INVERT_COLOR_LOC] = {.type = GL_INT, .i = 0},
|
||||
[UNIFORM_TEX_LOC] = {.type = GL_TEXTURE_2D, .texture = 0},
|
||||
[UNIFORM_EFFECTIVE_SIZE_LOC] = {.type = GL_FLOAT_VEC2, .f2 = {0.0F, 0.0F}}, // Must be set
|
||||
[UNIFORM_DIM_LOC] = {.type = GL_FLOAT, .f = 0.0F},
|
||||
[UNIFORM_BRIGHTNESS_LOC] = {.type = GL_TEXTURE_2D, .texture = 0},
|
||||
[UNIFORM_MAX_BRIGHTNESS_LOC] = {.type = GL_FLOAT, .f = 1.0F},
|
||||
[UNIFORM_CORNER_RADIUS_LOC] = {.type = GL_FLOAT, .f = 0.0F},
|
||||
[UNIFORM_BORDER_WIDTH_LOC] = {.type = GL_FLOAT, .f = 0.0F},
|
||||
[UNIFORM_TIME_LOC] = {.type = GL_FLOAT, .f = 0.0F},
|
||||
[UNIFORM_MASK_TEX_LOC] = {.type = GL_TEXTURE_2D, .texture = 0}, // Must be set
|
||||
[UNIFORM_MASK_OFFSET_LOC] = {.type = GL_FLOAT_VEC2, .f2 = {0.0F, 0.0F}},
|
||||
[UNIFORM_MASK_CORNER_RADIUS_LOC] = {.type = GL_FLOAT, .f = 0.0F},
|
||||
[UNIFORM_MASK_INVERTED_LOC] = {.type = GL_INT, .i = 0},
|
||||
};
|
||||
|
||||
// TODO(yshui) make use of reg_visible
|
||||
void gl_compose(backend_t *base, image_handle image, coord_t image_dst,
|
||||
|
@ -558,31 +606,12 @@ void gl_compose(backend_t *base, image_handle image, coord_t image_dst,
|
|||
auto gd = (struct gl_data *)base;
|
||||
auto img = (struct backend_image *)image;
|
||||
auto mask = (struct backend_image *)mask_;
|
||||
auto inner = (struct gl_texture *)img->inner;
|
||||
|
||||
// Painting
|
||||
int nrects;
|
||||
const rect_t *rects;
|
||||
rects = pixman_region32_rectangles((region_t *)reg_tgt, &nrects);
|
||||
if (!nrects) {
|
||||
// Nothing to paint
|
||||
return;
|
||||
}
|
||||
|
||||
// Until we start to use glClipControl, reg_tgt, dst_x and dst_y and
|
||||
// in a different coordinate system than the one OpenGL uses.
|
||||
// OpenGL window coordinate (or NDC) has the origin at the lower left of the
|
||||
// screen, with y axis pointing up; Xorg has the origin at the upper left of the
|
||||
// screen, with y axis pointing down. We have to do some coordinate conversion in
|
||||
// this function
|
||||
|
||||
auto coord = ccalloc(nrects * 16, GLint);
|
||||
auto indices = ccalloc(nrects * 6, GLuint);
|
||||
struct coord mask_offset = {.x = mask_dst.x - image_dst.x,
|
||||
.y = mask_dst.y - image_dst.y};
|
||||
x_rect_to_coords(nrects, rects, image_dst, inner->height, inner->height,
|
||||
gd->height, inner->y_inverted, coord, indices);
|
||||
|
||||
log_trace("Mask is %p, texture %d", mask ? mask->inner : NULL,
|
||||
mask ? ((struct gl_texture *)mask->inner)->texture : 0);
|
||||
struct backend_mask mask_args = {
|
||||
.image = mask ? (image_handle)mask->inner : NULL,
|
||||
.origin = mask_offset,
|
||||
|
@ -590,10 +619,11 @@ void gl_compose(backend_t *base, image_handle image, coord_t image_dst,
|
|||
.inverted = mask ? mask->color_inverted : false,
|
||||
};
|
||||
pixman_region32_init(&mask_args.region);
|
||||
|
||||
pixman_region32_copy(&mask_args.region, (region_t *)reg_tgt);
|
||||
pixman_region32_translate(&mask_args.region, -mask_dst.x, -mask_dst.y);
|
||||
struct backend_blit_args blit_args = {
|
||||
.source_image = (image_handle)img->inner,
|
||||
.mask = mask ? &mask_args : NULL,
|
||||
.mask = &mask_args,
|
||||
.shader = (void *)img->shader ?: &gd->default_shader,
|
||||
.opacity = img->opacity,
|
||||
.color_inverted = img->color_inverted,
|
||||
|
@ -606,10 +636,16 @@ void gl_compose(backend_t *base, image_handle image, coord_t image_dst,
|
|||
};
|
||||
struct gl_shader *shader;
|
||||
struct gl_uniform_value uniforms[NUMBER_OF_UNIFORMS] = {};
|
||||
gl_blit_args_to_uniforms(gd, &blit_args, &shader, uniforms);
|
||||
gl_blit_inner(gd->back_fbo, coord, indices, nrects, shader, NUMBER_OF_UNIFORMS,
|
||||
uniforms);
|
||||
GLint *coord = NULL;
|
||||
GLuint *indices = NULL;
|
||||
int nrects = gl_lower_blit_args(gd, image_dst, &blit_args, &coord, &indices,
|
||||
&shader, uniforms);
|
||||
if (nrects > 0) {
|
||||
gl_blit_inner(gd->back_fbo, coord, indices, nrects, shader,
|
||||
NUMBER_OF_UNIFORMS, uniforms);
|
||||
}
|
||||
|
||||
pixman_region32_fini(&mask_args.region);
|
||||
free(indices);
|
||||
free(coord);
|
||||
}
|
||||
|
@ -659,8 +695,7 @@ void gl_resize(struct gl_data *gd, int width, int height) {
|
|||
|
||||
/// Fill a given region in bound framebuffer.
|
||||
/// @param[in] y_inverted whether the y coordinates in `clip` should be inverted
|
||||
static void _gl_fill(backend_t *base, struct color c, const region_t *clip, GLuint target,
|
||||
int height, bool y_inverted) {
|
||||
static void _gl_fill(backend_t *base, struct color c, const region_t *clip, GLuint target) {
|
||||
static const GLuint fill_vert_in_coord_loc = 0;
|
||||
int nrects;
|
||||
const rect_t *rect = pixman_region32_rectangles((region_t *)clip, &nrects);
|
||||
|
@ -681,9 +716,8 @@ static void _gl_fill(backend_t *base, struct color c, const region_t *clip, GLui
|
|||
|
||||
auto coord = ccalloc(nrects * 8, GLint);
|
||||
auto indices = ccalloc(nrects * 6, GLuint);
|
||||
for (int i = 0; i < nrects; i++) {
|
||||
GLint y1 = y_inverted ? height - rect[i].y2 : rect[i].y1,
|
||||
y2 = y_inverted ? height - rect[i].y1 : rect[i].y2;
|
||||
for (ptrdiff_t i = 0; i < nrects; i++) {
|
||||
GLint y1 = rect[i].y1, y2 = rect[i].y2;
|
||||
// clang-format off
|
||||
memcpy(&coord[i * 8],
|
||||
((GLint[][2]){
|
||||
|
@ -723,7 +757,7 @@ static void _gl_fill(backend_t *base, struct color c, const region_t *clip, GLui
|
|||
|
||||
void gl_fill(backend_t *base, struct color c, const region_t *clip) {
|
||||
auto gd = (struct gl_data *)base;
|
||||
return _gl_fill(base, c, clip, gd->back_fbo, gd->height, true);
|
||||
return _gl_fill(base, c, clip, gd->back_fbo);
|
||||
}
|
||||
|
||||
image_handle gl_make_mask(backend_t *base, geometry_t size, const region_t *reg) {
|
||||
|
@ -731,6 +765,7 @@ image_handle gl_make_mask(backend_t *base, geometry_t size, const region_t *reg)
|
|||
auto gd = (struct gl_data *)base;
|
||||
auto img = ccalloc(1, struct backend_image);
|
||||
default_init_backend_image(img, size.width, size.height);
|
||||
log_trace("Creating mask texture %dx%d", size.width, size.height);
|
||||
tex->width = size.width;
|
||||
tex->height = size.height;
|
||||
tex->texture = gl_new_texture(GL_TEXTURE_2D);
|
||||
|
@ -753,7 +788,7 @@ image_handle gl_make_mask(backend_t *base, geometry_t size, const region_t *reg)
|
|||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
_gl_fill(base, (struct color){1, 1, 1, 1}, reg, gd->temp_fbo, size.height, false);
|
||||
_gl_fill(base, (struct color){1, 1, 1, 1}, reg, gd->temp_fbo);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
return (image_handle)img;
|
||||
|
@ -927,16 +962,15 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
|
|||
glUseProgram(0);
|
||||
|
||||
gd->dithered_present = ps->o.dithered_present;
|
||||
gd->dummy_prog =
|
||||
gl_create_program_from_strv((const char *[]){present_vertex_shader, NULL},
|
||||
(const char *[]){dummy_frag, NULL});
|
||||
gd->dummy_prog = gl_create_program_from_strv(
|
||||
(const char *[]){vertex_shader, NULL}, (const char *[]){dummy_frag, NULL});
|
||||
if (!gd->dummy_prog) {
|
||||
log_error("Failed to create the dummy shader");
|
||||
return false;
|
||||
}
|
||||
if (gd->dithered_present) {
|
||||
gd->present_prog = gl_create_program_from_strv(
|
||||
(const char *[]){present_vertex_shader, NULL},
|
||||
(const char *[]){vertex_shader, NULL},
|
||||
(const char *[]){present_frag, dither_glsl, NULL});
|
||||
} else {
|
||||
gd->present_prog = gd->dummy_prog;
|
||||
|
@ -956,7 +990,7 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
|
|||
}
|
||||
|
||||
gd->shadow_shader.prog =
|
||||
gl_create_program_from_str(present_vertex_shader, shadow_colorization_frag);
|
||||
gl_create_program_from_str(vertex_shader, shadow_colorization_frag);
|
||||
glUseProgram(gd->shadow_shader.prog);
|
||||
glUniform1i(UNIFORM_TEX_LOC, 0);
|
||||
glUniformMatrix4fv(UNIFORM_PROJECTION_LOC, 1, false, projection_matrix[0]);
|
||||
|
@ -1174,8 +1208,7 @@ static void gl_image_apply_alpha(backend_t *base, struct backend_image *img,
|
|||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
inner->texture, 0);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
_gl_fill(base, (struct color){0, 0, 0, 0}, reg_op, gd->temp_fbo, inner->height,
|
||||
!inner->y_inverted);
|
||||
_gl_fill(base, (struct color){0, 0, 0, 0}, reg_op, gd->temp_fbo);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
@ -1185,23 +1218,12 @@ void gl_present(backend_t *base, const region_t *region) {
|
|||
|
||||
int nrects;
|
||||
const rect_t *rect = pixman_region32_rectangles((region_t *)region, &nrects);
|
||||
auto coord = ccalloc(nrects * 8, GLint);
|
||||
auto coord = ccalloc(nrects * 16, GLint);
|
||||
auto indices = ccalloc(nrects * 6, GLuint);
|
||||
for (int i = 0; i < nrects; i++) {
|
||||
// clang-format off
|
||||
memcpy(&coord[i * 8],
|
||||
((GLint[]){rect[i].x1, gd->height - rect[i].y2,
|
||||
rect[i].x2, gd->height - rect[i].y2,
|
||||
rect[i].x2, gd->height - rect[i].y1,
|
||||
rect[i].x1, gd->height - rect[i].y1}),
|
||||
sizeof(GLint) * 8);
|
||||
// clang-format on
|
||||
|
||||
GLuint u = (GLuint)(i * 4);
|
||||
memcpy(&indices[i * 6],
|
||||
((GLuint[]){u + 0, u + 1, u + 2, u + 2, u + 3, u + 0}),
|
||||
sizeof(GLuint) * 6);
|
||||
}
|
||||
gl_mask_rects_to_coords_simple(nrects, rect, coord, indices);
|
||||
// Our back_texture is in Xorg coordinate system, but the GL back buffer is in
|
||||
// GL clip space, which has the Y axis flipped.
|
||||
gl_y_flip_target(nrects, coord, gd->height);
|
||||
|
||||
glUseProgram(gd->present_prog);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
@ -1213,14 +1235,17 @@ void gl_present(backend_t *base, const region_t *region) {
|
|||
|
||||
GLuint bo[2];
|
||||
glGenBuffers(2, bo);
|
||||
glEnableVertexAttribArray(vert_coord_loc);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, bo[0]);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo[1]);
|
||||
glBufferData(GL_ARRAY_BUFFER, (long)sizeof(GLint) * nrects * 8, coord, GL_STREAM_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, (long)sizeof(GLint) * nrects * 16, coord, GL_STREAM_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(GLuint) * nrects * 6, indices,
|
||||
GL_STREAM_DRAW);
|
||||
|
||||
glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE, sizeof(GLint) * 2, NULL);
|
||||
glEnableVertexAttribArray(vert_coord_loc);
|
||||
glEnableVertexAttribArray(vert_in_texcoord_loc);
|
||||
glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE, sizeof(GLint) * 4, NULL);
|
||||
glVertexAttribPointer(vert_in_texcoord_loc, 2, GL_INT, GL_FALSE,
|
||||
sizeof(GLint) * 4, &((GLint *)NULL)[2]);
|
||||
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
@ -1312,6 +1337,12 @@ image_handle gl_shadow_from_mask(backend_t *base, image_handle mask_,
|
|||
auto inner = (struct gl_texture *)mask->inner;
|
||||
auto gsctx = (struct gl_shadow_context *)sctx;
|
||||
int radius = (int)gsctx->radius;
|
||||
if (mask->eheight != inner->height || mask->ewidth != inner->width ||
|
||||
mask->dim != 0 || mask->max_brightness != 1 || mask->border_width != 0 ||
|
||||
mask->opacity != 1 || mask->shader != NULL) {
|
||||
log_error("Unsupported mask properties for shadow generation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
auto new_inner = ccalloc(1, struct gl_texture);
|
||||
new_inner->width = inner->width + radius * 2;
|
||||
|
@ -1324,8 +1355,17 @@ image_handle gl_shadow_from_mask(backend_t *base, image_handle mask_,
|
|||
new_img->inner = (struct backend_image_inner_base *)new_inner;
|
||||
new_img->inner->refcount = 1;
|
||||
|
||||
// Render the mask to a texture, so inversion and corner radius can be
|
||||
// applied.
|
||||
// We apply the mask properties by blitting a pure white texture with the mask
|
||||
// image as mask.
|
||||
auto white_texture = gl_new_texture(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, white_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE,
|
||||
(GLbyte[]){'\xff'});
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
auto source_texture = gl_new_texture(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, source_texture);
|
||||
|
@ -1340,7 +1380,9 @@ image_handle gl_shadow_from_mask(backend_t *base, image_handle mask_,
|
|||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
if (mask->color_inverted) {
|
||||
// If the mask is inverted, clear the source_texture to white, so the
|
||||
// "outside" of the mask would be correct
|
||||
// "outside" of the mask would be correct.
|
||||
// FIXME(yshui): we should make masks clamp to border, and set border
|
||||
// color to 0.
|
||||
glClearColor(1, 1, 1, 1);
|
||||
} else {
|
||||
glClearColor(0, 0, 0, 1);
|
||||
|
@ -1348,31 +1390,25 @@ image_handle gl_shadow_from_mask(backend_t *base, image_handle mask_,
|
|||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
{
|
||||
// clang-format off
|
||||
// interleaved vertex coordinates and texture coordinates
|
||||
// | vertex coordinates | texture coordinates
|
||||
GLint coords[] = {radius , radius , 0 , 0,
|
||||
radius + inner->width, radius , inner->width, 0,
|
||||
radius + inner->width, radius + inner->height, inner->width, inner->height,
|
||||
radius , radius + inner->height, 0 , inner->height,};
|
||||
// clang-format on
|
||||
GLuint indices[] = {0, 1, 2, 2, 3, 0};
|
||||
struct backend_blit_args blit_args = {
|
||||
.source_image = (image_handle)mask->inner,
|
||||
.mask = NULL,
|
||||
.shader = (void *)mask->shader ?: &gd->default_shader,
|
||||
.opacity = mask->opacity,
|
||||
.color_inverted = mask->color_inverted,
|
||||
.ewidth = mask->ewidth,
|
||||
.eheight = mask->eheight,
|
||||
.dim = mask->dim,
|
||||
.corner_radius = mask->corner_radius,
|
||||
.border_width = mask->border_width,
|
||||
.max_brightness = mask->max_brightness,
|
||||
};
|
||||
struct gl_shader *shader;
|
||||
struct gl_uniform_value uniforms[NUMBER_OF_UNIFORMS];
|
||||
gl_blit_args_to_uniforms(gd, &blit_args, &shader, uniforms);
|
||||
auto shader = &gd->default_shader;
|
||||
struct gl_uniform_value uniforms[ARR_SIZE(default_blit_uniforms)];
|
||||
memcpy(uniforms, default_blit_uniforms, sizeof(default_blit_uniforms));
|
||||
uniforms[UNIFORM_EFFECTIVE_SIZE_LOC].f2[0] = (float)inner->width;
|
||||
uniforms[UNIFORM_EFFECTIVE_SIZE_LOC].f2[1] = (float)inner->height;
|
||||
uniforms[UNIFORM_TEX_LOC].i = (GLint)white_texture;
|
||||
uniforms[UNIFORM_MASK_TEX_LOC].i = (GLint)inner->texture;
|
||||
uniforms[UNIFORM_MASK_INVERTED_LOC].i = mask->color_inverted;
|
||||
uniforms[UNIFORM_MASK_CORNER_RADIUS_LOC].f = (float)mask->corner_radius;
|
||||
gl_blit_inner(gd->temp_fbo, coords, indices, 1, shader,
|
||||
NUMBER_OF_UNIFORMS, uniforms);
|
||||
ARR_SIZE(default_blit_uniforms), uniforms);
|
||||
glDeleteTextures(1, &white_texture);
|
||||
}
|
||||
|
||||
gl_check_err();
|
||||
|
@ -1397,10 +1433,9 @@ image_handle gl_shadow_from_mask(backend_t *base, image_handle mask_,
|
|||
// but we are covering the whole texture so we don't need to worry about
|
||||
// that.
|
||||
gl_blur_impl(
|
||||
1.0, gsctx->blur_context, NULL, (coord_t){0}, ®_blur, NULL,
|
||||
source_texture,
|
||||
1.0, gsctx->blur_context, NULL, (coord_t){0}, ®_blur, source_texture,
|
||||
(geometry_t){.width = new_inner->width, .height = new_inner->height},
|
||||
gd->temp_fbo, gd->default_mask_texture);
|
||||
true, gd->temp_fbo, gd->default_mask_texture);
|
||||
pixman_region32_fini(®_blur);
|
||||
}
|
||||
|
||||
|
@ -1445,7 +1480,10 @@ image_handle gl_shadow_from_mask(backend_t *base, image_handle mask_,
|
|||
GL_STREAM_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(vert_coord_loc);
|
||||
glEnableVertexAttribArray(vert_in_texcoord_loc);
|
||||
glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE, sizeof(GLint) * 2, NULL);
|
||||
glVertexAttribPointer(vert_in_texcoord_loc, 2, GL_INT, GL_FALSE,
|
||||
sizeof(GLint) * 2, NULL);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ struct gl_blur_context;
|
|||
// Vertex shader uniforms
|
||||
#define UNIFORM_SCALE_LOC 18
|
||||
#define UNIFORM_PROJECTION_LOC 19
|
||||
#define UNIFORM_TEXORIG_LOC 20
|
||||
#define UNIFORM_TEXSIZE_LOC 21
|
||||
#define NUMBER_OF_UNIFORMS (UNIFORM_TEXSIZE_LOC + 1)
|
||||
|
||||
|
@ -55,6 +54,10 @@ struct gl_texture {
|
|||
bool has_alpha;
|
||||
GLuint texture;
|
||||
int width, height;
|
||||
/// Whether the texture is Y-inverted
|
||||
/// This is always true for all our internal textures. Textures created from
|
||||
/// binding a X pixmap might not be. And our OpenGL back buffer is never
|
||||
/// Y-inverted (until we can start using glClipControl).
|
||||
bool y_inverted;
|
||||
xcb_pixmap_t pixmap;
|
||||
|
||||
|
@ -105,9 +108,24 @@ typedef struct session session_t;
|
|||
{ .prog = 0, .unifm_opacity = -1, .unifm_invert_color = -1, .unifm_tex = -1, }
|
||||
|
||||
void gl_prepare(backend_t *base, const region_t *reg);
|
||||
void x_rect_to_coords(int nrects, const rect_t *rects, coord_t image_dst,
|
||||
int extent_height, int texture_height, int root_height,
|
||||
bool y_inverted, GLint *coord, GLuint *indices);
|
||||
/// Convert a mask formed by a collection of rectangles to OpenGL vertex and texture
|
||||
/// coordinates.
|
||||
///
|
||||
/// @param[in] origin origin of the source image in target coordinates
|
||||
/// @param[in] mask_origin origin of the mask in source coordinates
|
||||
/// @param[in] nrects number of rectangles
|
||||
/// @param[in] rects mask rectangles, in mask coordinates
|
||||
/// @param[out] coord OpenGL vertex coordinates, suitable for creating VAO/VBO
|
||||
/// @param[out] indices OpenGL vertex indices, suitable for creating VAO/VBO
|
||||
void gl_mask_rects_to_coords(struct coord origin, struct coord mask_origin, int nrects,
|
||||
const rect_t *rects, GLint *coord, GLuint *indices);
|
||||
/// Like `gl_mask_rects_to_coords`, but with `origin` and `mask_origin` set to 0. i.e. all
|
||||
/// coordinates are in the same space.
|
||||
static inline void gl_mask_rects_to_coords_simple(int nrects, const rect_t *rects,
|
||||
GLint *coord, GLuint *indices) {
|
||||
return gl_mask_rects_to_coords((struct coord){0, 0}, (struct coord){0, 0}, nrects,
|
||||
rects, coord, indices);
|
||||
}
|
||||
|
||||
GLuint gl_create_shader(GLenum shader_type, const char *shader_str);
|
||||
GLuint gl_create_program(const GLuint *const shaders, int nshaders);
|
||||
|
@ -145,8 +163,8 @@ bool gl_blur(backend_t *base, double opacity, void *ctx, image_handle mask,
|
|||
coord_t mask_dst, const region_t *reg_blur, const region_t *reg_visible);
|
||||
bool gl_blur_impl(double opacity, struct gl_blur_context *bctx,
|
||||
struct backend_image *mask, coord_t mask_dst, const region_t *reg_blur,
|
||||
const region_t *reg_visible attr_unused, GLuint source_texture,
|
||||
geometry_t source_size, GLuint target_fbo, GLuint default_mask);
|
||||
GLuint source_texture, geometry_t source_size, bool source_y_inverted,
|
||||
GLuint target_fbo, GLuint default_mask);
|
||||
void *gl_create_blur_context(backend_t *base, enum blur_method,
|
||||
enum backend_image_format format, void *args);
|
||||
void gl_destroy_blur_context(backend_t *base, void *ctx);
|
||||
|
|
|
@ -188,29 +188,17 @@ const char win_shader_default[] = GLSL(330,
|
|||
}
|
||||
);
|
||||
|
||||
const char present_vertex_shader[] = GLSL(330,
|
||||
layout(location = UNIFORM_PROJECTION_LOC)
|
||||
uniform mat4 projection;
|
||||
layout(location = 0) in vec2 coord;
|
||||
out vec2 texcoord;
|
||||
void main() {
|
||||
gl_Position = projection * vec4(coord, 0, 1);
|
||||
texcoord = coord;
|
||||
}
|
||||
);
|
||||
const char vertex_shader[] = GLSL(330,
|
||||
layout(location = UNIFORM_PROJECTION_LOC)
|
||||
uniform mat4 projection;
|
||||
layout(location = UNIFORM_SCALE_LOC)
|
||||
uniform float scale = 1.0f;
|
||||
layout(location = UNIFORM_TEXORIG_LOC)
|
||||
uniform vec2 texorig;
|
||||
layout(location = 0) in vec2 coord;
|
||||
layout(location = 1) in vec2 in_texcoord;
|
||||
out vec2 texcoord;
|
||||
void main() {
|
||||
gl_Position = projection * vec4(coord, 0, scale);
|
||||
texcoord = in_texcoord + texorig;
|
||||
texcoord = in_texcoord;
|
||||
}
|
||||
);
|
||||
const char dither_glsl[] = GLSL(330,
|
||||
|
|
10
src/region.h
10
src/region.h
|
@ -7,6 +7,7 @@
|
|||
#include <xcb/xcb.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
|
||||
typedef struct pixman_region32 pixman_region32_t;
|
||||
|
@ -97,3 +98,12 @@ static inline region_t resize_region(const region_t *region, int dx, int dy) {
|
|||
static inline void resize_region_in_place(region_t *region, int dx, int dy) {
|
||||
return _resize_region(region, region, dx, dy);
|
||||
}
|
||||
|
||||
static inline rect_t region_translate_rect(rect_t rect, struct coord origin) {
|
||||
return (rect_t){
|
||||
.x1 = rect.x1 + origin.x,
|
||||
.y1 = rect.y1 + origin.y,
|
||||
.x2 = rect.x2 + origin.x,
|
||||
.y2 = rect.y2 + origin.y,
|
||||
};
|
||||
}
|
|
@ -30,5 +30,14 @@ struct color {
|
|||
|
||||
typedef uint32_t opacity_t;
|
||||
|
||||
typedef struct geometry {
|
||||
int width;
|
||||
int height;
|
||||
} geometry_t;
|
||||
|
||||
typedef struct coord {
|
||||
int x, y;
|
||||
} coord_t;
|
||||
|
||||
#define MARGIN_INIT \
|
||||
{ 0, 0, 0, 0 }
|
||||
|
|
Loading…
Reference in New Issue