mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-24 20:51:10 +00:00
gpu: Copy the clear trick from the Vulkan shader
When drawing opaque color regions that are large enough, use vkCmdClearAttachments()/glClear() instead of a shader. This speeds up background rendering on particular on older GPUs. See the commit messages ofbb2cd7225e
ce042f7ba1
0edd7547c1
for a further discussion of performance impacts.
This commit is contained in:
parent
48012a1ce4
commit
e3bac4063c
127
gsk/gpu/gskgpuclearop.c
Normal file
127
gsk/gpu/gskgpuclearop.c
Normal file
@ -0,0 +1,127 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskgpuclearopprivate.h"
|
||||
|
||||
#include "gskgpuopprivate.h"
|
||||
#include "gskgpuprintprivate.h"
|
||||
/* for gsk_gpu_rgba_to_float() */
|
||||
#include "gskgpushaderopprivate.h"
|
||||
|
||||
typedef struct _GskGpuClearOp GskGpuClearOp;
|
||||
|
||||
struct _GskGpuClearOp
|
||||
{
|
||||
GskGpuOp op;
|
||||
|
||||
cairo_rectangle_int_t rect;
|
||||
GdkRGBA color;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_gpu_clear_op_finish (GskGpuOp *op)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gpu_clear_op_print (GskGpuOp *op,
|
||||
GskGpuFrame *frame,
|
||||
GString *string,
|
||||
guint indent)
|
||||
{
|
||||
GskGpuClearOp *self = (GskGpuClearOp *) op;
|
||||
float rgba[4];
|
||||
|
||||
gsk_gpu_print_op (string, indent, "clear");
|
||||
gsk_gpu_print_int_rect (string, &self->rect);
|
||||
gsk_gpu_rgba_to_float (&self->color, rgba);
|
||||
gsk_gpu_print_rgba (string, rgba);
|
||||
gsk_gpu_print_newline (string);
|
||||
}
|
||||
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
static void
|
||||
gsk_gpu_init_clear_value (VkClearValue *value,
|
||||
const GdkRGBA *rgba)
|
||||
{
|
||||
gsk_gpu_rgba_to_float (rgba, value->color.float32);
|
||||
}
|
||||
|
||||
static GskGpuOp *
|
||||
gsk_gpu_clear_op_vk_command (GskGpuOp *op,
|
||||
GskGpuFrame *frame,
|
||||
VkRenderPass render_pass,
|
||||
VkFormat format,
|
||||
VkCommandBuffer command_buffer)
|
||||
{
|
||||
GskGpuClearOp *self = (GskGpuClearOp *) op;
|
||||
VkClearValue clear_value;
|
||||
|
||||
gsk_gpu_init_clear_value (&clear_value, &self->color);
|
||||
|
||||
vkCmdClearAttachments (command_buffer,
|
||||
1,
|
||||
&(VkClearAttachment) {
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
0,
|
||||
clear_value,
|
||||
},
|
||||
1,
|
||||
&(VkClearRect) {
|
||||
{
|
||||
{ self->rect.x, self->rect.y },
|
||||
{ self->rect.width, self->rect.height },
|
||||
},
|
||||
0,
|
||||
1
|
||||
});
|
||||
|
||||
return op->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
static GskGpuOp *
|
||||
gsk_gpu_clear_op_gl_command (GskGpuOp *op,
|
||||
GskGpuFrame *frame,
|
||||
gsize flip_y)
|
||||
{
|
||||
GskGpuClearOp *self = (GskGpuClearOp *) op;
|
||||
int scissor[4];
|
||||
|
||||
glGetIntegerv (GL_SCISSOR_BOX, scissor);
|
||||
|
||||
if (flip_y)
|
||||
glScissor (self->rect.x, flip_y - self->rect.y - self->rect.height, self->rect.width, self->rect.height);
|
||||
else
|
||||
glScissor (self->rect.x, self->rect.y, self->rect.width, self->rect.height);
|
||||
|
||||
glClearColor (self->color.red, self->color.green, self->color.blue, self->color.alpha);
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glScissor (scissor[0], scissor[1], scissor[2], scissor[3]);
|
||||
|
||||
return op->next;
|
||||
}
|
||||
|
||||
static const GskGpuOpClass GSK_GPU_CLEAR_OP_CLASS = {
|
||||
GSK_GPU_OP_SIZE (GskGpuClearOp),
|
||||
GSK_GPU_STAGE_COMMAND,
|
||||
gsk_gpu_clear_op_finish,
|
||||
gsk_gpu_clear_op_print,
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
gsk_gpu_clear_op_vk_command,
|
||||
#endif
|
||||
gsk_gpu_clear_op_gl_command
|
||||
};
|
||||
|
||||
void
|
||||
gsk_gpu_clear_op (GskGpuFrame *frame,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
GskGpuClearOp *self;
|
||||
|
||||
self = (GskGpuClearOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_CLEAR_OP_CLASS);
|
||||
|
||||
self->rect = *rect;
|
||||
self->color = *color;
|
||||
}
|
13
gsk/gpu/gskgpuclearopprivate.h
Normal file
13
gsk/gpu/gskgpuclearopprivate.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "gskgputypesprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gsk_gpu_clear_op (GskGpuFrame *frame,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
const GdkRGBA *color);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "gskgpuborderopprivate.h"
|
||||
#include "gskgpubluropprivate.h"
|
||||
#include "gskgpuclearopprivate.h"
|
||||
#include "gskgpuclipprivate.h"
|
||||
#include "gskgpucolorizeopprivate.h"
|
||||
#include "gskgpucoloropprivate.h"
|
||||
@ -945,6 +946,104 @@ static void
|
||||
gsk_gpu_node_processor_add_color_node (GskGpuNodeProcessor *self,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
cairo_rectangle_int_t int_clipped;
|
||||
graphene_rect_t rect, clipped;
|
||||
const GdkRGBA *color;
|
||||
|
||||
color = gsk_color_node_get_color (node);
|
||||
graphene_rect_offset_r (&node->bounds,
|
||||
self->offset.x, self->offset.y,
|
||||
&rect);
|
||||
gsk_rect_intersection (&self->clip.rect.bounds, &rect, &clipped);
|
||||
|
||||
if (gdk_rgba_is_opaque (color) &&
|
||||
node->bounds.size.width * node->bounds.size.height > 100 * 100 && /* not worth the effort for small images */
|
||||
gsk_gpu_node_processor_rect_is_integer (self, &clipped, &int_clipped))
|
||||
{
|
||||
/* now handle all the clip */
|
||||
if (!gdk_rectangle_intersect (&int_clipped, &self->scissor, &int_clipped))
|
||||
return;
|
||||
|
||||
/* we have handled the bounds, now do the corners */
|
||||
if (self->clip.type == GSK_GPU_CLIP_ROUNDED)
|
||||
{
|
||||
graphene_rect_t cover;
|
||||
GskGpuShaderClip shader_clip;
|
||||
float scale_x, scale_y;
|
||||
|
||||
if (self->modelview)
|
||||
{
|
||||
/* Yuck, rounded clip and modelview. I give up. */
|
||||
gsk_gpu_color_op (self->frame,
|
||||
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
|
||||
&node->bounds,
|
||||
&self->offset,
|
||||
gsk_color_node_get_color (node));
|
||||
return;
|
||||
}
|
||||
|
||||
scale_x = graphene_vec2_get_x (&self->scale);
|
||||
scale_y = graphene_vec2_get_y (&self->scale);
|
||||
clipped = GRAPHENE_RECT_INIT (int_clipped.x / scale_x, int_clipped.y / scale_y,
|
||||
int_clipped.width / scale_x, int_clipped.height / scale_y);
|
||||
shader_clip = gsk_gpu_clip_get_shader_clip (&self->clip, graphene_point_zero(), &clipped);
|
||||
if (shader_clip != GSK_GPU_SHADER_CLIP_NONE)
|
||||
{
|
||||
gsk_rounded_rect_get_largest_cover (&self->clip.rect, &clipped, &cover);
|
||||
int_clipped.x = ceil (cover.origin.x * scale_x);
|
||||
int_clipped.y = ceil (cover.origin.y * scale_y);
|
||||
int_clipped.width = floor ((cover.origin.x + cover.size.width) * scale_x) - int_clipped.x;
|
||||
int_clipped.height = floor ((cover.origin.y + cover.size.height) * scale_y) - int_clipped.y;
|
||||
if (int_clipped.width == 0 || int_clipped.height == 0)
|
||||
{
|
||||
gsk_gpu_color_op (self->frame,
|
||||
shader_clip,
|
||||
&clipped,
|
||||
graphene_point_zero (),
|
||||
color);
|
||||
return;
|
||||
}
|
||||
cover = GRAPHENE_RECT_INIT (int_clipped.x / scale_x, int_clipped.y / scale_y,
|
||||
int_clipped.width / scale_x, int_clipped.height / scale_y);
|
||||
if (clipped.origin.x != cover.origin.x)
|
||||
gsk_gpu_color_op (self->frame,
|
||||
shader_clip,
|
||||
&GRAPHENE_RECT_INIT (clipped.origin.x, clipped.origin.y, cover.origin.x - clipped.origin.x, clipped.size.height),
|
||||
graphene_point_zero (),
|
||||
color);
|
||||
if (clipped.origin.y != cover.origin.y)
|
||||
gsk_gpu_color_op (self->frame,
|
||||
shader_clip,
|
||||
&GRAPHENE_RECT_INIT (clipped.origin.x, clipped.origin.y, clipped.size.width, cover.origin.y - clipped.origin.y),
|
||||
graphene_point_zero (),
|
||||
color);
|
||||
if (clipped.origin.x + clipped.size.width != cover.origin.x + cover.size.width)
|
||||
gsk_gpu_color_op (self->frame,
|
||||
shader_clip,
|
||||
&GRAPHENE_RECT_INIT (cover.origin.x + cover.size.width,
|
||||
clipped.origin.y,
|
||||
clipped.origin.x + clipped.size.width - cover.origin.x - cover.size.width,
|
||||
clipped.size.height),
|
||||
graphene_point_zero (),
|
||||
color);
|
||||
if (clipped.origin.y + clipped.size.height != cover.origin.y + cover.size.height)
|
||||
gsk_gpu_color_op (self->frame,
|
||||
shader_clip,
|
||||
&GRAPHENE_RECT_INIT (clipped.origin.x,
|
||||
cover.origin.y + cover.size.height,
|
||||
clipped.size.width,
|
||||
clipped.origin.y + clipped.size.height - cover.origin.y - cover.size.height),
|
||||
graphene_point_zero (),
|
||||
color);
|
||||
}
|
||||
}
|
||||
|
||||
gsk_gpu_clear_op (self->frame,
|
||||
&int_clipped,
|
||||
color);
|
||||
return;
|
||||
}
|
||||
|
||||
gsk_gpu_color_op (self->frame,
|
||||
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
|
||||
&node->bounds,
|
||||
|
@ -76,6 +76,7 @@ gsk_private_sources = files([
|
||||
'gpu/gskgpuborderop.c',
|
||||
'gpu/gskgpubuffer.c',
|
||||
'gpu/gskgpubufferwriter.c',
|
||||
'gpu/gskgpuclearop.c',
|
||||
'gpu/gskgpuclip.c',
|
||||
'gpu/gskgpucolorizeop.c',
|
||||
'gpu/gskgpucolorop.c',
|
||||
|
Loading…
Reference in New Issue
Block a user