Compare commits
5 Commits
arnaudb/cs
...
wip/matthi
Author | SHA1 | Date | |
---|---|---|---|
|
984d257d1a | ||
|
d850ca03f8 | ||
|
0b8d58ca3d | ||
|
6d8eb2441a | ||
|
2905e9dbcc |
@@ -187,6 +187,7 @@
|
||||
<file>scale.c</file>
|
||||
<file>search_entry.c</file>
|
||||
<file>search_entry2.c</file>
|
||||
<file>shadertoy.c</file>
|
||||
<file>shortcuts.c</file>
|
||||
<file>sizegroup.c</file>
|
||||
<file>sidebar.c</file>
|
||||
@@ -241,4 +242,7 @@
|
||||
<gresource prefix="/modelbutton">
|
||||
<file>modelbutton.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/shadertoy">
|
||||
<file>shadertoy.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
87
demos/gtk-demo/fire.frag
Normal file
87
demos/gtk-demo/fire.frag
Normal file
@@ -0,0 +1,87 @@
|
||||
#version 420 core
|
||||
|
||||
layout(location = 0) in vec2 iPos;
|
||||
layout(location = 1) in vec2 iTexCoord1;
|
||||
layout(location = 2) in vec2 iTexCoord2;
|
||||
layout(location = 3) in float iTime;
|
||||
layout(location = 4) in vec2 iResolution;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D iTexture1;
|
||||
layout(set = 1, binding = 0) uniform sampler2D iTexture2;
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
|
||||
// based on http://glslsandbox.com/e#35642.0
|
||||
|
||||
vec3 TextureSource(vec2 uv)
|
||||
{
|
||||
return texture(iTexture1, uv).rgb;;
|
||||
}
|
||||
|
||||
vec3 TextureTarget(vec2 uv)
|
||||
{
|
||||
return texture(iTexture2, uv).rgb;;
|
||||
}
|
||||
|
||||
|
||||
float Hash( vec2 p)
|
||||
{
|
||||
vec3 p2 = vec3(p.xy,1.0);
|
||||
return fract(sin(dot(p2,vec3(37.1,61.7, 12.4)))*3758.5453123);
|
||||
}
|
||||
|
||||
float noise(in vec2 p)
|
||||
{
|
||||
vec2 i = floor(p);
|
||||
vec2 f = fract(p);
|
||||
f *= f * (3.0-2.0*f);
|
||||
|
||||
return mix(mix(Hash(i + vec2(0.,0.)), Hash(i + vec2(1.,0.)),f.x),
|
||||
mix(Hash(i + vec2(0.,1.)), Hash(i + vec2(1.,1.)),f.x),
|
||||
f.y);
|
||||
}
|
||||
|
||||
float fbm(vec2 p)
|
||||
{
|
||||
float v = 0.0;
|
||||
v += noise(p*1.)*.5;
|
||||
v += noise(p*2.)*.25;
|
||||
v += noise(p*4.)*.125;
|
||||
return v;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 uv = iTexCoord1;
|
||||
vec3 src = TextureSource(uv);
|
||||
vec3 tgt = TextureTarget(uv);
|
||||
vec3 col = src;
|
||||
|
||||
uv.x -= 1.5;
|
||||
|
||||
if (iTime <= 0) {
|
||||
fragColor.rgb = src.rgb;
|
||||
return;
|
||||
}
|
||||
else if (iTime > 5) {
|
||||
fragColor.rgb = tgt.rgb;
|
||||
return;
|
||||
}
|
||||
|
||||
float ctime = iTime*.5;
|
||||
// burn
|
||||
float d = uv.x+uv.y*0.5 + 0.5*fbm(uv*15.1) + ctime*1.3;
|
||||
if (d >0.35) col = clamp(col-(d-0.35)*10.,0.0,1.0);
|
||||
if (d >0.47) {
|
||||
if (d < 0.5 ) col += (d-0.4)*33.0*0.5*(0.0+noise(100.*uv+vec2(-ctime*2.,0.)))*vec3(1.5,0.5,0.0);
|
||||
else col += tgt; }
|
||||
|
||||
fragColor.rgb = col;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
mainImage (color, iPos);
|
||||
}
|
@@ -54,6 +54,7 @@ demos = files([
|
||||
'scale.c',
|
||||
'search_entry.c',
|
||||
'search_entry2.c',
|
||||
'shadertoy.c',
|
||||
'shortcuts.c',
|
||||
'sidebar.c',
|
||||
'sizegroup.c',
|
||||
|
567
demos/gtk-demo/shadertoy.c
Normal file
567
demos/gtk-demo/shadertoy.c
Normal file
@@ -0,0 +1,567 @@
|
||||
/* Shadertoy
|
||||
*
|
||||
* Play with shaders. Everybody does it.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_TIME,
|
||||
PROP_RUNNING,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GtkShadertoy, gtk_shadertoy, GTK, SHADERTOY, GtkWidget)
|
||||
|
||||
struct _GtkShadertoy {
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GBytes *fragment_shader;
|
||||
|
||||
GtkWidget *child1;
|
||||
GtkWidget *child2;
|
||||
|
||||
guint tick;
|
||||
guint64 starttime;
|
||||
|
||||
float time;
|
||||
float base;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkShadertoy, gtk_shadertoy, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
gtk_shadertoy_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkShadertoy *self = GTK_SHADERTOY (widget);
|
||||
GtkAllocation alloc;
|
||||
graphene_rect_t bounds;
|
||||
int offset_x, offset_y;
|
||||
float time = (float)(g_get_monotonic_time () - self->starttime)/1000000.0;
|
||||
GskRenderNode *node, *child1, *child2;
|
||||
GtkAllocation child_alloc;
|
||||
GtkSnapshot *child_snapshot;
|
||||
|
||||
|
||||
if (!self->fragment_shader)
|
||||
{
|
||||
GTK_WIDGET_CLASS (gtk_shadertoy_parent_class)->snapshot (widget, snapshot);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y);
|
||||
gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
bounds.origin.x = offset_x;
|
||||
bounds.origin.y = offset_y;
|
||||
bounds.size.width = alloc.width;
|
||||
bounds.size.height = alloc.height;
|
||||
|
||||
gtk_widget_get_allocation (self->child1, &child_alloc);
|
||||
child_snapshot = gtk_snapshot_new (snapshot, "shadertoy child1");
|
||||
gtk_snapshot_offset (child_snapshot, offset_x + child_alloc.x, offset_y + child_alloc.y);
|
||||
gtk_widget_snapshot (self->child1, child_snapshot);
|
||||
gtk_snapshot_offset (child_snapshot, - offset_x - child_alloc.x, - offset_y - child_alloc.y);
|
||||
child1 = gtk_snapshot_free (child_snapshot);
|
||||
|
||||
gtk_widget_get_allocation (self->child2, &child_alloc);
|
||||
child_snapshot = gtk_snapshot_new (snapshot, "shadertoy child2");
|
||||
gtk_snapshot_offset (child_snapshot, offset_x + child_alloc.x, offset_y + child_alloc.y);
|
||||
gtk_widget_snapshot (self->child2, child_snapshot);
|
||||
gtk_snapshot_offset (child_snapshot, - offset_x - child_alloc.x, - offset_y - child_alloc.y);
|
||||
child2 = gtk_snapshot_free (child_snapshot);
|
||||
|
||||
node = gsk_pixel_shader_node_new (&bounds,
|
||||
child1, child2,
|
||||
self->fragment_shader,
|
||||
time);
|
||||
gsk_render_node_set_name (node, "shader");
|
||||
gtk_snapshot_append_node (snapshot, node);
|
||||
gsk_render_node_unref (child1);
|
||||
gsk_render_node_unref (child2);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_shadertoy_finalize (GObject *object)
|
||||
{
|
||||
GtkShadertoy *self = GTK_SHADERTOY (object);
|
||||
|
||||
if (self->fragment_shader)
|
||||
g_bytes_unref (self->fragment_shader);
|
||||
|
||||
G_OBJECT_CLASS (gtk_shadertoy_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_shadertoy_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkShadertoy *self = GTK_SHADERTOY (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_TIME:
|
||||
g_value_set_float (value, self->time);
|
||||
break;
|
||||
|
||||
case PROP_RUNNING:
|
||||
g_value_set_boolean (value, self->tick != 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void gtk_shadertoy_set_running (GtkShadertoy *self,
|
||||
gboolean running);
|
||||
static void gtk_shadertoy_reset_time (GtkShadertoy *self);
|
||||
|
||||
static void
|
||||
gtk_shadertoy_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkShadertoy *self = GTK_SHADERTOY (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_RUNNING:
|
||||
gtk_shadertoy_set_running (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shadertoy_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkShadertoy *self = GTK_SHADERTOY (widget);
|
||||
gint child1_min, child1_nat;
|
||||
gint child2_min, child2_nat;
|
||||
|
||||
*minimum = 0;
|
||||
*natural = 0;
|
||||
|
||||
gtk_widget_measure (self->child1, orientation, -1, &child1_min, &child1_nat, NULL, NULL);
|
||||
gtk_widget_measure (self->child2, orientation, -1, &child2_min, &child2_nat, NULL, NULL);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
*minimum = MAX (*minimum, MAX (child1_min, child2_min));
|
||||
*natural = MAX (*natural, MAX (child1_nat, child2_nat));
|
||||
}
|
||||
else /* VERTICAL */
|
||||
{
|
||||
*minimum = MAX (*minimum, MAX (child1_min, child2_min));
|
||||
*natural = MAX (*natural, MAX (child1_nat, child2_nat));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shadertoy_size_allocate (GtkWidget *widget,
|
||||
const GtkAllocation *allocation,
|
||||
int baseline,
|
||||
GtkAllocation *out_clip)
|
||||
{
|
||||
GtkShadertoy *self = GTK_SHADERTOY (widget);
|
||||
GtkAllocation child_allocation;
|
||||
GtkRequisition child_requisition;
|
||||
|
||||
gtk_widget_get_preferred_size (self->child1, &child_requisition, NULL);
|
||||
gtk_widget_get_preferred_size (self->child2, &child_requisition, NULL);
|
||||
child_allocation.x = 0;
|
||||
child_allocation.y = 0;
|
||||
child_allocation.width = allocation->width;
|
||||
child_allocation.height = allocation->height;
|
||||
|
||||
gtk_widget_size_allocate (self->child1, &child_allocation, -1, out_clip);
|
||||
gtk_widget_size_allocate (self->child2, &child_allocation, -1, out_clip);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shadertoy_class_init (GtkShadertoyClass *klass)
|
||||
{
|
||||
GParamSpec *pspec;
|
||||
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->finalize = gtk_shadertoy_finalize;
|
||||
object_class->get_property = gtk_shadertoy_get_property;
|
||||
object_class->set_property = gtk_shadertoy_set_property;
|
||||
widget_class->snapshot = gtk_shadertoy_snapshot;
|
||||
widget_class->measure = gtk_shadertoy_measure;
|
||||
widget_class->size_allocate = gtk_shadertoy_size_allocate;
|
||||
|
||||
pspec = g_param_spec_float ("time", NULL, NULL,
|
||||
0.0, G_MAXFLOAT, 0.0,
|
||||
G_PARAM_READABLE);
|
||||
g_object_class_install_property (object_class, PROP_TIME, pspec);
|
||||
|
||||
pspec = g_param_spec_boolean ("running", NULL, NULL,
|
||||
FALSE,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property (object_class, PROP_RUNNING, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shadertoy_init (GtkShadertoy *self)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
|
||||
|
||||
self->child2 = gtk_entry_new ();
|
||||
gtk_entry_set_text (GTK_ENTRY (self->child2), "Stat rosa prisina nomine, nomina nuda tenemus");
|
||||
gtk_widget_set_parent (self->child2, GTK_WIDGET (self));
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_file_at_scale ("tests/portland-rose.jpg", 400, 400, TRUE, NULL);
|
||||
self->child1 = gtk_image_new_from_pixbuf (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
gtk_widget_set_parent (self->child1, GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gtk_shadertoy_new (void)
|
||||
{
|
||||
return g_object_new (gtk_shadertoy_get_type (), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shadertoy_set_fragment_shader (GtkShadertoy *self,
|
||||
GBytes *shader)
|
||||
{
|
||||
if (self->fragment_shader)
|
||||
g_bytes_unref (self->fragment_shader);
|
||||
self->fragment_shader = shader;
|
||||
if (self->fragment_shader)
|
||||
g_bytes_ref (self->fragment_shader);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tick_cb (GtkWidget *widget, GdkFrameClock *clock, gpointer data)
|
||||
{
|
||||
GtkShadertoy *self = GTK_SHADERTOY (widget);
|
||||
|
||||
self->time = self->base + (g_get_monotonic_time () - self->starttime) / 1000000.0;
|
||||
g_object_notify (G_OBJECT (widget), "time");
|
||||
|
||||
gtk_widget_queue_draw (widget);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shadertoy_set_running (GtkShadertoy *self,
|
||||
gboolean running)
|
||||
{
|
||||
if (running && self->tick == 0)
|
||||
{
|
||||
self->tick = gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_cb, NULL, NULL);
|
||||
self->starttime = g_get_monotonic_time ();
|
||||
self->time = 0;
|
||||
}
|
||||
else if (!running && self->tick != 0)
|
||||
{
|
||||
gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->tick);
|
||||
self->base += (g_get_monotonic_time () - self->starttime) / 1000000.0;
|
||||
self->tick = 0;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
g_object_notify (G_OBJECT (self), "running");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_shadertoy_is_running (GtkShadertoy *self)
|
||||
{
|
||||
return self->tick != 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_shadertoy_reset_time (GtkShadertoy *self)
|
||||
{
|
||||
self->base = 0;
|
||||
self->time = 0;
|
||||
self->starttime = g_get_monotonic_time ();
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
g_object_notify (G_OBJECT (self), "time");
|
||||
}
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
static GtkWidget *textview;
|
||||
static GtkWidget *toy;
|
||||
|
||||
static const char *frag_text =
|
||||
"#version 420 core\n"
|
||||
"\n"
|
||||
"layout(location = 0) in vec2 iPos;\n"
|
||||
"layout(location = 1) in vec2 iTexCoord1;\n"
|
||||
"layout(location = 2) in vec2 iTexCoord2;\n"
|
||||
"layout(location = 3) in float iTime;\n"
|
||||
"layout(location = 4) in vec2 iResolution;\n"
|
||||
"\n"
|
||||
"layout(set = 0, binding = 0) uniform sampler2D iTexture1;\n"
|
||||
"layout(set = 1, binding = 0) uniform sampler2D iTexture2;\n"
|
||||
"\n"
|
||||
"layout(location = 0) out vec4 color;\n"
|
||||
"\n"
|
||||
"void\n"
|
||||
"mainImage (out vec4 fragColor, in vec2 fragCoord)\n"
|
||||
"{\n"
|
||||
" vec2 uv = fragCoord.xy / iResolution.xy;\n"
|
||||
" fragColor = texture(iTexture1,iTexCoord1*(0.3*sin(iTime) + 0.5));\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" mainImage (color, iPos);\n"
|
||||
"}";
|
||||
|
||||
static gboolean
|
||||
update_shader (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
int status;
|
||||
char *spv;
|
||||
gsize length;
|
||||
GBytes *shader;
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextIter start, end;
|
||||
char *text;
|
||||
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
|
||||
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
||||
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
|
||||
|
||||
if (!g_file_set_contents ("gtk4-demo-shader.frag", text, -1, &error))
|
||||
{
|
||||
g_print ("Failed to write shader file: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
g_free (text);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (text);
|
||||
|
||||
if (!g_spawn_command_line_sync ("glslc -fshader-stage=fragment -DCLIP_NONE gtk4-demo-shader.frag -o gtk4-demo-shader.frag.spv", NULL, NULL, &status, &error))
|
||||
{
|
||||
g_print ("Running glslc failed (%d): %s\n", status, error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!g_file_get_contents ("gtk4-demo-shader.frag.spv", &spv, &length, &error))
|
||||
{
|
||||
g_print ("Reading compiled shader failed: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
shader = g_bytes_new_take (spv, length);
|
||||
gtk_shadertoy_set_fragment_shader (GTK_SHADERTOY (toy), shader);
|
||||
g_bytes_unref (shader);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
play_cb (GtkButton *button)
|
||||
{
|
||||
if (gtk_shadertoy_is_running (GTK_SHADERTOY (toy)))
|
||||
{
|
||||
gtk_shadertoy_set_running (GTK_SHADERTOY (toy), FALSE);
|
||||
gtk_button_set_icon_name (button, "media-playback-start-symbolic");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (update_shader ())
|
||||
{
|
||||
gtk_shadertoy_set_running (GTK_SHADERTOY (toy), TRUE);
|
||||
gtk_button_set_icon_name (button, "media-playback-stop-symbolic");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rewind_cb (GtkButton *button)
|
||||
{
|
||||
gtk_shadertoy_reset_time (GTK_SHADERTOY (toy));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
format_time (GBinding *binding,
|
||||
const GValue *from_value,
|
||||
GValue *to_value,
|
||||
gpointer data)
|
||||
{
|
||||
char buffer[256];
|
||||
|
||||
g_snprintf (buffer, sizeof (buffer), "%.2f", g_value_get_float (from_value));
|
||||
g_value_set_string (to_value, buffer);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
save_cb (GtkButton *button)
|
||||
{
|
||||
GtkFileChooserNative *fs;
|
||||
int response;
|
||||
|
||||
fs = gtk_file_chooser_native_new ("Save Shader",
|
||||
GTK_WINDOW (window),
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
"Save", "Cancel");
|
||||
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (fs), TRUE);
|
||||
|
||||
response = gtk_native_dialog_run (GTK_NATIVE_DIALOG (fs));
|
||||
|
||||
if (response == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextIter start, end;
|
||||
char *text;
|
||||
char *filename;
|
||||
GError *error = NULL;
|
||||
|
||||
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (fs));
|
||||
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
|
||||
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
||||
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
|
||||
|
||||
if (!g_file_set_contents (filename, text, -1, &error))
|
||||
{
|
||||
g_print ("Failed to save :-( %s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
g_object_unref (fs);
|
||||
}
|
||||
|
||||
static void
|
||||
load_cb (GtkButton *button)
|
||||
{
|
||||
GtkFileChooserNative *fs;
|
||||
int response;
|
||||
|
||||
fs = gtk_file_chooser_native_new ("Load Shader",
|
||||
GTK_WINDOW (window),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"Open", "Cancel");
|
||||
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (fs), TRUE);
|
||||
|
||||
response = gtk_native_dialog_run (GTK_NATIVE_DIALOG (fs));
|
||||
|
||||
if (response == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
GtkTextBuffer *buffer;
|
||||
char *text;
|
||||
gsize len;
|
||||
char *filename;
|
||||
GError *error = NULL;
|
||||
|
||||
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (fs));
|
||||
|
||||
if (!g_file_get_contents (filename, &text, &len, &error))
|
||||
{
|
||||
g_print ("Failed to load :-( %s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
|
||||
gtk_text_buffer_set_text (buffer, text, len);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
g_object_unref (fs);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_shadertoy (GtkWidget *do_widget)
|
||||
{
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *content;
|
||||
GtkWidget *rewind;
|
||||
GtkWidget *play;
|
||||
GtkWidget *time;
|
||||
GtkWidget *load;
|
||||
GtkWidget *save;
|
||||
GtkTextBuffer *buffer;
|
||||
|
||||
builder = gtk_builder_new_from_resource ("/shadertoy/shadertoy.ui");
|
||||
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
||||
content = GTK_WIDGET (gtk_builder_get_object (builder, "content"));
|
||||
textview = GTK_WIDGET (gtk_builder_get_object (builder, "text"));
|
||||
rewind = GTK_WIDGET (gtk_builder_get_object (builder, "rewind"));
|
||||
play = GTK_WIDGET (gtk_builder_get_object (builder, "play"));
|
||||
time = GTK_WIDGET (gtk_builder_get_object (builder, "time"));
|
||||
load = GTK_WIDGET (gtk_builder_get_object (builder, "load"));
|
||||
save = GTK_WIDGET (gtk_builder_get_object (builder, "save"));
|
||||
|
||||
gtk_window_set_screen (GTK_WINDOW (window),
|
||||
gtk_widget_get_screen (do_widget));
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
toy = gtk_shadertoy_new ();
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
|
||||
gtk_text_buffer_set_text (buffer, frag_text, -1);
|
||||
|
||||
gtk_widget_set_hexpand (toy, TRUE);
|
||||
gtk_widget_set_vexpand (toy, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (content), toy);
|
||||
|
||||
g_signal_connect (play, "clicked", G_CALLBACK (play_cb), NULL);
|
||||
g_signal_connect (rewind, "clicked", G_CALLBACK (rewind_cb), NULL);
|
||||
g_signal_connect (load, "clicked", G_CALLBACK (load_cb), NULL);
|
||||
g_signal_connect (save, "clicked", G_CALLBACK (save_cb), NULL);
|
||||
g_object_bind_property_full (toy, "time",
|
||||
time, "label",
|
||||
G_BINDING_SYNC_CREATE,
|
||||
format_time,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
64
demos/gtk-demo/shadertoy.ui
Normal file
64
demos/gtk-demo/shadertoy.ui
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<!-- interface-requires gtk+ 3.6 -->
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="default-width">640</property>
|
||||
<property name="default-height">480</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<property name="title" translatable="yes">Shadertoy</property>
|
||||
<property name="show-close-button">1</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="rewind">
|
||||
<property name="icon-name">media-skip-backward-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="play">
|
||||
<property name="icon-name">media-playback-start-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="time">
|
||||
<property name="margin-start">20</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="save">
|
||||
<property name="icon-name">document-save-as-symbolic</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="load">
|
||||
<property name="icon-name">document-open-symbolic</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPaned" id="content">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="position">240</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="expand">1</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="text">
|
||||
<property name="top-margin">10</property>
|
||||
<property name="bottom-margin">10</property>
|
||||
<property name="left-margin">10</property>
|
||||
<property name="right-margin">10</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
@@ -45,6 +45,7 @@
|
||||
* @GSK_CROSS_FADE_NODE: A node that cross-fades between two children
|
||||
* @GSK_TEXT_NODE: A node containing a glyph string
|
||||
* @GSK_BLUR_NODE: A node that applies a blur
|
||||
* @GSK_PIXEL_SHADER_NODE: A node that applies a custom shader
|
||||
*
|
||||
* The type of a node determines what the node is rendering.
|
||||
*
|
||||
@@ -71,7 +72,8 @@ typedef enum {
|
||||
GSK_BLEND_NODE,
|
||||
GSK_CROSS_FADE_NODE,
|
||||
GSK_TEXT_NODE,
|
||||
GSK_BLUR_NODE
|
||||
GSK_BLUR_NODE,
|
||||
GSK_PIXEL_SHADER_NODE
|
||||
} GskRenderNodeType;
|
||||
|
||||
/**
|
||||
|
@@ -182,6 +182,18 @@ GDK_AVAILABLE_IN_3_92
|
||||
GskRenderNode * gsk_blur_node_new (GskRenderNode *child,
|
||||
double radius);
|
||||
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
GskRenderNode * gsk_pixel_shader_node_new (const graphene_rect_t *bounds,
|
||||
GskRenderNode *child1,
|
||||
GskRenderNode *child2,
|
||||
GBytes *fragement_bytes,
|
||||
float time);
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
GskRenderNode *gsk_pixel_shader_node_get_child1 (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
GskRenderNode *gsk_pixel_shader_node_get_child2 (GskRenderNode *node);
|
||||
|
||||
|
||||
GDK_AVAILABLE_IN_3_90
|
||||
void gsk_render_node_set_scaling_filters (GskRenderNode *node,
|
||||
GskScalingFilter min_filter,
|
||||
|
@@ -4414,6 +4414,223 @@ gsk_blur_node_get_radius (GskRenderNode *node)
|
||||
return self->radius;
|
||||
}
|
||||
|
||||
/*** GSK_PIXEL_SHADER_NODE ***/
|
||||
|
||||
typedef struct _GskPixelShaderNode GskPixelShaderNode;
|
||||
|
||||
struct _GskPixelShaderNode
|
||||
{
|
||||
GskRenderNode render_node;
|
||||
|
||||
GBytes *fragment_bytes;
|
||||
|
||||
float time;
|
||||
|
||||
GskRenderNode *child1;
|
||||
GskRenderNode *child2;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_pixel_shader_node_finalize (GskRenderNode *node)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
|
||||
g_bytes_unref (self->fragment_bytes);
|
||||
|
||||
if (self->child1)
|
||||
gsk_render_node_unref (self->child1);
|
||||
if (self->child2)
|
||||
gsk_render_node_unref (self->child2);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pixel_shader_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
|
||||
if (self->child1)
|
||||
gsk_render_node_draw (self->child1, cr);
|
||||
if (self->child2)
|
||||
gsk_render_node_draw (self->child2, cr);
|
||||
}
|
||||
|
||||
#define GSK_PIXEL_SHADER_NODE_VARIANT_TYPE "(dddda(uv)ayd)"
|
||||
|
||||
static GVariant *
|
||||
gsk_pixel_shader_node_serialize (GskRenderNode *node)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE (GSK_CONTAINER_NODE_VARIANT_TYPE));
|
||||
|
||||
if (self->child1)
|
||||
g_variant_builder_add (&builder, "(uv)",
|
||||
(guint32) gsk_render_node_get_node_type (self->child1),
|
||||
gsk_render_node_serialize_node (self->child1));
|
||||
if (self->child2)
|
||||
g_variant_builder_add (&builder, "(uv)",
|
||||
(guint32) gsk_render_node_get_node_type (self->child2),
|
||||
gsk_render_node_serialize_node (self->child2));
|
||||
|
||||
return g_variant_new ("(dddd@ayda(uv))",
|
||||
(double) node->bounds.origin.x, (double) node->bounds.origin.y,
|
||||
(double) node->bounds.size.width, (double) node->bounds.size.height,
|
||||
&builder,
|
||||
g_variant_new_fixed_array (G_VARIANT_TYPE ("y"),
|
||||
g_bytes_get_data (self->fragment_bytes, NULL),
|
||||
g_bytes_get_size (self->fragment_bytes), 1),
|
||||
self->time);
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
gsk_pixel_shader_node_deserialize (GVariant *variant,
|
||||
GError **error)
|
||||
{
|
||||
GVariant *fragment_variant;
|
||||
char *data;
|
||||
double bounds[4];
|
||||
double time;
|
||||
gsize length;
|
||||
GBytes *fragment_bytes;
|
||||
GskRenderNode *node;
|
||||
GVariantIter *iter;
|
||||
gsize i, n_children;
|
||||
guint32 child_type;
|
||||
GVariant *child_variant;
|
||||
GskRenderNode *children[2] = { NULL, NULL };
|
||||
|
||||
if (!check_variant_type (variant, GSK_PIXEL_SHADER_NODE_VARIANT_TYPE, error))
|
||||
return NULL;
|
||||
|
||||
g_variant_get (variant, "(dddda(uv)@ayd)",
|
||||
&bounds[0], &bounds[1], &bounds[2], &bounds[3],
|
||||
&iter, &fragment_variant, &time);
|
||||
|
||||
n_children = g_variant_iter_init (iter, variant);
|
||||
if (n_children > 2)
|
||||
return NULL;
|
||||
|
||||
i = 0;
|
||||
while (g_variant_iter_loop (iter, "(uv)", &child_type, &child_variant))
|
||||
{
|
||||
children[i] = gsk_render_node_deserialize_node (child_type, child_variant, error);
|
||||
if (children[i] == NULL)
|
||||
{
|
||||
guint j;
|
||||
for (j = 0; j < i; j++)
|
||||
gsk_render_node_unref (children[j]);
|
||||
g_variant_unref (child_variant);
|
||||
return NULL;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
data = g_variant_get_fixed_array (fragment_variant, &length, 1);
|
||||
fragment_bytes = g_bytes_new (data, length);
|
||||
|
||||
node = gsk_pixel_shader_node_new (&GRAPHENE_RECT_INIT(bounds[0], bounds[1], bounds[2], bounds[3]),
|
||||
children[0], children[1],
|
||||
fragment_bytes, time);
|
||||
|
||||
if (children[0])
|
||||
gsk_render_node_unref (children[0]);
|
||||
if (children[1])
|
||||
gsk_render_node_unref (children[1]);
|
||||
|
||||
g_bytes_unref (fragment_bytes);
|
||||
g_variant_unref (fragment_variant);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static const GskRenderNodeClass GSK_PIXEL_SHADER_NODE_CLASS = {
|
||||
GSK_PIXEL_SHADER_NODE,
|
||||
sizeof (GskPixelShaderNode),
|
||||
"GskPixelShaderNode",
|
||||
gsk_pixel_shader_node_finalize,
|
||||
gsk_pixel_shader_node_draw,
|
||||
gsk_pixel_shader_node_serialize,
|
||||
gsk_pixel_shader_node_deserialize
|
||||
};
|
||||
|
||||
GskRenderNode *
|
||||
gsk_pixel_shader_node_new (const graphene_rect_t *bounds,
|
||||
GskRenderNode *child1,
|
||||
GskRenderNode *child2,
|
||||
GBytes *fragment_bytes,
|
||||
float time)
|
||||
{
|
||||
GskPixelShaderNode *self;
|
||||
|
||||
self = (GskPixelShaderNode *) gsk_render_node_new (&GSK_PIXEL_SHADER_NODE_CLASS, 0);
|
||||
|
||||
if (child1)
|
||||
self->child1 = gsk_render_node_ref (child1);
|
||||
else
|
||||
self->child1 = NULL;
|
||||
|
||||
if (child2)
|
||||
self->child2 = gsk_render_node_ref (child2);
|
||||
else
|
||||
self->child2 = NULL;
|
||||
|
||||
graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
|
||||
|
||||
self->fragment_bytes = g_bytes_ref (fragment_bytes);
|
||||
self->time = time;
|
||||
|
||||
return &self->render_node;
|
||||
}
|
||||
|
||||
GBytes *
|
||||
gsk_pixel_shader_node_get_fragment_bytes (GskRenderNode *node)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_PIXEL_SHADER_NODE), NULL);
|
||||
|
||||
return self->fragment_bytes;
|
||||
}
|
||||
|
||||
float
|
||||
gsk_pixel_shader_node_get_time (GskRenderNode *node)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_PIXEL_SHADER_NODE), 0);
|
||||
|
||||
return self->time;
|
||||
}
|
||||
|
||||
GskRenderNode *
|
||||
gsk_pixel_shader_node_get_child1 (GskRenderNode *node)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_PIXEL_SHADER_NODE), 0);
|
||||
|
||||
return self->child1;
|
||||
}
|
||||
|
||||
GskRenderNode *
|
||||
gsk_pixel_shader_node_get_child2 (GskRenderNode *node)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_PIXEL_SHADER_NODE), 0);
|
||||
|
||||
return self->child2;
|
||||
}
|
||||
|
||||
/*** ***/
|
||||
|
||||
static const GskRenderNodeClass *klasses[] = {
|
||||
[GSK_CONTAINER_NODE] = &GSK_CONTAINER_NODE_CLASS,
|
||||
[GSK_CAIRO_NODE] = &GSK_CAIRO_NODE_CLASS,
|
||||
@@ -4434,7 +4651,8 @@ static const GskRenderNodeClass *klasses[] = {
|
||||
[GSK_BLEND_NODE] = &GSK_BLEND_NODE_CLASS,
|
||||
[GSK_CROSS_FADE_NODE] = &GSK_CROSS_FADE_NODE_CLASS,
|
||||
[GSK_TEXT_NODE] = &GSK_TEXT_NODE_CLASS,
|
||||
[GSK_BLUR_NODE] = &GSK_BLUR_NODE_CLASS
|
||||
[GSK_BLUR_NODE] = &GSK_BLUR_NODE_CLASS,
|
||||
[GSK_PIXEL_SHADER_NODE] = &GSK_PIXEL_SHADER_NODE_CLASS,
|
||||
};
|
||||
|
||||
GskRenderNode *
|
||||
|
@@ -110,6 +110,9 @@ double gsk_cross_fade_node_get_progress (GskRenderNode *node);
|
||||
GskRenderNode * gsk_blur_node_get_child (GskRenderNode *node);
|
||||
double gsk_blur_node_get_radius (GskRenderNode *node);
|
||||
|
||||
GBytes * gsk_pixel_shader_node_get_fragment_bytes (GskRenderNode *node);
|
||||
float gsk_pixel_shader_node_get_time (GskRenderNode *node);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_RENDER_NODE_PRIVATE_H__ */
|
||||
|
171
gsk/gskvulkancustompipeline.c
Normal file
171
gsk/gskvulkancustompipeline.c
Normal file
@@ -0,0 +1,171 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskvulkancustompipelineprivate.h"
|
||||
|
||||
struct _GskVulkanCustomPipeline
|
||||
{
|
||||
GObject parent_instance;
|
||||
};
|
||||
|
||||
typedef struct _GskVulkanCustomInstance GskVulkanCustomInstance;
|
||||
|
||||
struct _GskVulkanCustomInstance
|
||||
{
|
||||
float rect[4];
|
||||
float tex_rect1[4];
|
||||
float tex_rect2[4];
|
||||
float time;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GskVulkanCustomPipeline, gsk_vulkan_custom_pipeline, GSK_TYPE_VULKAN_PIPELINE)
|
||||
|
||||
static const VkPipelineVertexInputStateCreateInfo *
|
||||
gsk_vulkan_custom_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
|
||||
{
|
||||
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.stride = sizeof (GskVulkanCustomInstance),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
|
||||
}
|
||||
};
|
||||
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
|
||||
{
|
||||
.location = 0,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.offset = 0,
|
||||
},
|
||||
{
|
||||
.location = 1,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.offset = G_STRUCT_OFFSET (GskVulkanCustomInstance, tex_rect1),
|
||||
},
|
||||
{
|
||||
.location = 2,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.offset = G_STRUCT_OFFSET (GskVulkanCustomInstance, tex_rect2),
|
||||
},
|
||||
{
|
||||
.location = 3,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32_SFLOAT,
|
||||
.offset = G_STRUCT_OFFSET (GskVulkanCustomInstance, time),
|
||||
},
|
||||
};
|
||||
static const VkPipelineVertexInputStateCreateInfo info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
|
||||
.pVertexBindingDescriptions = vertexBindingDescriptions,
|
||||
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
|
||||
.pVertexAttributeDescriptions = vertexInputAttributeDescription
|
||||
};
|
||||
|
||||
return &info;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_vulkan_custom_pipeline_finalize (GObject *gobject)
|
||||
{
|
||||
//GskVulkanCustomPipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
|
||||
|
||||
G_OBJECT_CLASS (gsk_vulkan_custom_pipeline_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_vulkan_custom_pipeline_class_init (GskVulkanCustomPipelineClass *klass)
|
||||
{
|
||||
GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
|
||||
|
||||
G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_custom_pipeline_finalize;
|
||||
|
||||
pipeline_class->get_input_state_create_info = gsk_vulkan_custom_pipeline_get_input_state_create_info;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_vulkan_custom_pipeline_init (GskVulkanCustomPipeline *self)
|
||||
{
|
||||
}
|
||||
|
||||
GskVulkanPipeline *
|
||||
gsk_vulkan_custom_pipeline_new (GdkVulkanContext *context,
|
||||
VkPipelineLayout layout,
|
||||
GBytes *fragment_bytes,
|
||||
VkRenderPass render_pass)
|
||||
{
|
||||
GskVulkanShader *vertex_shader;
|
||||
GskVulkanShader *fragment_shader;
|
||||
GError *error = NULL;
|
||||
|
||||
vertex_shader = gsk_vulkan_shader_new_from_resource (context,
|
||||
GSK_VULKAN_SHADER_VERTEX,
|
||||
"custom",
|
||||
&error);
|
||||
fragment_shader = gsk_vulkan_shader_new_from_bytes (context,
|
||||
GSK_VULKAN_SHADER_FRAGMENT,
|
||||
fragment_bytes,
|
||||
&error);
|
||||
if (fragment_shader == NULL)
|
||||
{
|
||||
g_error ("%s", error->message);
|
||||
g_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gsk_vulkan_pipeline_new_with_shaders (GSK_TYPE_VULKAN_CUSTOM_PIPELINE,
|
||||
context, layout,
|
||||
vertex_shader,
|
||||
fragment_shader,
|
||||
render_pass,
|
||||
VK_BLEND_FACTOR_ONE,
|
||||
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
gsize
|
||||
gsk_vulkan_custom_pipeline_count_vertex_data (GskVulkanCustomPipeline *pipeline)
|
||||
{
|
||||
return sizeof (GskVulkanCustomInstance);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_vulkan_custom_pipeline_collect_vertex_data (GskVulkanCustomPipeline *pipeline,
|
||||
guchar *data,
|
||||
const graphene_rect_t *bounds,
|
||||
const graphene_rect_t *tex_rect1,
|
||||
const graphene_rect_t *tex_rect2,
|
||||
float time)
|
||||
{
|
||||
GskVulkanCustomInstance *instance = (GskVulkanCustomInstance *) data;
|
||||
|
||||
instance->rect[0] = bounds->origin.x;
|
||||
instance->rect[1] = bounds->origin.y;
|
||||
instance->rect[2] = bounds->size.width;
|
||||
instance->rect[3] = bounds->size.height;
|
||||
|
||||
instance->tex_rect1[0] = tex_rect1->origin.x;
|
||||
instance->tex_rect1[1] = tex_rect1->origin.y;
|
||||
instance->tex_rect1[2] = tex_rect1->size.width;
|
||||
instance->tex_rect1[3] = tex_rect1->size.height;
|
||||
|
||||
instance->tex_rect2[0] = tex_rect2->origin.x;
|
||||
instance->tex_rect2[1] = tex_rect2->origin.y;
|
||||
instance->tex_rect2[2] = tex_rect2->size.width;
|
||||
instance->tex_rect2[3] = tex_rect2->size.height;
|
||||
|
||||
instance->time = time;
|
||||
}
|
||||
|
||||
gsize
|
||||
gsk_vulkan_custom_pipeline_draw (GskVulkanCustomPipeline *pipeline,
|
||||
VkCommandBuffer command_buffer,
|
||||
gsize offset,
|
||||
gsize n_commands)
|
||||
{
|
||||
vkCmdDraw (command_buffer,
|
||||
6, n_commands,
|
||||
0, offset);
|
||||
|
||||
return n_commands;
|
||||
}
|
35
gsk/gskvulkancustompipelineprivate.h
Normal file
35
gsk/gskvulkancustompipelineprivate.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef __GSK_VULKAN_CUSTOM_PIPELINE_PRIVATE_H__
|
||||
#define __GSK_VULKAN_CUSTOM_PIPELINE_PRIVATE_H__
|
||||
|
||||
#include <graphene.h>
|
||||
|
||||
#include "gskvulkanpipelineprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GskVulkanCustomPipelineLayout GskVulkanCustomPipelineLayout;
|
||||
|
||||
#define GSK_TYPE_VULKAN_CUSTOM_PIPELINE (gsk_vulkan_custom_pipeline_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GskVulkanCustomPipeline, gsk_vulkan_custom_pipeline, GSK, VULKAN_CUSTOM_PIPELINE, GskVulkanPipeline)
|
||||
|
||||
GskVulkanPipeline * gsk_vulkan_custom_pipeline_new (GdkVulkanContext *context,
|
||||
VkPipelineLayout layout,
|
||||
GBytes *fragment_shader,
|
||||
VkRenderPass render_pass);
|
||||
|
||||
gsize gsk_vulkan_custom_pipeline_count_vertex_data (GskVulkanCustomPipeline *pipeline);
|
||||
void gsk_vulkan_custom_pipeline_collect_vertex_data (GskVulkanCustomPipeline *pipeline,
|
||||
guchar *data,
|
||||
const graphene_rect_t *rect,
|
||||
const graphene_rect_t *child1_bounds,
|
||||
const graphene_rect_t *child2_bounds,
|
||||
float time);
|
||||
gsize gsk_vulkan_custom_pipeline_draw (GskVulkanCustomPipeline *pipeline,
|
||||
VkCommandBuffer command_buffer,
|
||||
gsize offset,
|
||||
gsize n_commands);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_VULKAN_CUSTOM_PIPELINE_PRIVATE_H__ */
|
@@ -60,7 +60,9 @@ gsk_vulkan_pipeline_new (GType pipeline_type,
|
||||
const char *shader_name,
|
||||
VkRenderPass render_pass)
|
||||
{
|
||||
return gsk_vulkan_pipeline_new_full (pipeline_type, context, layout, shader_name, render_pass,
|
||||
return gsk_vulkan_pipeline_new_full (pipeline_type, context, layout,
|
||||
shader_name,
|
||||
render_pass,
|
||||
VK_BLEND_FACTOR_ONE,
|
||||
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
@@ -73,6 +75,34 @@ gsk_vulkan_pipeline_new_full (GType pipeline_type,
|
||||
VkRenderPass render_pass,
|
||||
VkBlendFactor srcBlendFactor,
|
||||
VkBlendFactor dstBlendFactor)
|
||||
{
|
||||
GskVulkanShader *vertex_shader;
|
||||
GskVulkanShader *fragment_shader;
|
||||
|
||||
vertex_shader = gsk_vulkan_shader_new_from_resource (context,
|
||||
GSK_VULKAN_SHADER_VERTEX,
|
||||
shader_name,
|
||||
NULL);
|
||||
fragment_shader = gsk_vulkan_shader_new_from_resource (context,
|
||||
GSK_VULKAN_SHADER_FRAGMENT,
|
||||
shader_name,
|
||||
NULL);
|
||||
|
||||
return gsk_vulkan_pipeline_new_with_shaders (pipeline_type, context, layout,
|
||||
vertex_shader, fragment_shader,
|
||||
render_pass,
|
||||
srcBlendFactor, dstBlendFactor);
|
||||
}
|
||||
|
||||
GskVulkanPipeline *
|
||||
gsk_vulkan_pipeline_new_with_shaders (GType pipeline_type,
|
||||
GdkVulkanContext *context,
|
||||
VkPipelineLayout layout,
|
||||
GskVulkanShader *vertex_shader,
|
||||
GskVulkanShader *fragment_shader,
|
||||
VkRenderPass render_pass,
|
||||
VkBlendFactor srcBlendFactor,
|
||||
VkBlendFactor dstBlendFactor)
|
||||
{
|
||||
GskVulkanPipelinePrivate *priv;
|
||||
GskVulkanPipeline *self;
|
||||
@@ -80,7 +110,8 @@ gsk_vulkan_pipeline_new_full (GType pipeline_type,
|
||||
|
||||
g_return_val_if_fail (g_type_is_a (pipeline_type, GSK_TYPE_VULKAN_PIPELINE), NULL);
|
||||
g_return_val_if_fail (layout != VK_NULL_HANDLE, NULL);
|
||||
g_return_val_if_fail (shader_name != NULL, NULL);
|
||||
g_return_val_if_fail (vertex_shader != NULL, NULL);
|
||||
g_return_val_if_fail (fragment_shader != NULL, NULL);
|
||||
g_return_val_if_fail (render_pass != VK_NULL_HANDLE, NULL);
|
||||
|
||||
self = g_object_new (pipeline_type, NULL);
|
||||
@@ -92,8 +123,8 @@ gsk_vulkan_pipeline_new_full (GType pipeline_type,
|
||||
priv->context = context;
|
||||
priv->layout = layout;
|
||||
|
||||
priv->vertex_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_VERTEX, shader_name, NULL);
|
||||
priv->fragment_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_FRAGMENT, shader_name, NULL);
|
||||
priv->vertex_shader = vertex_shader;
|
||||
priv->fragment_shader = fragment_shader;
|
||||
|
||||
GSK_VK_CHECK (vkCreateGraphicsPipelines, device,
|
||||
VK_NULL_HANDLE,
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskvulkanshaderprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -44,6 +45,14 @@ GskVulkanPipeline * gsk_vulkan_pipeline_new_full (GType
|
||||
VkRenderPass render_pass,
|
||||
VkBlendFactor srcBlendFactor,
|
||||
VkBlendFactor dstBlendFactor);
|
||||
GskVulkanPipeline * gsk_vulkan_pipeline_new_with_shaders (GType pipeline_type,
|
||||
GdkVulkanContext *context,
|
||||
VkPipelineLayout layout,
|
||||
GskVulkanShader *vertex_shader,
|
||||
GskVulkanShader *fragment_shader,
|
||||
VkRenderPass render_pass,
|
||||
VkBlendFactor srcBlendFactor,
|
||||
VkBlendFactor dstBlendFactor);
|
||||
|
||||
VkPipeline gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self);
|
||||
VkPipelineLayout gsk_vulkan_pipeline_get_pipeline_layout (GskVulkanPipeline *self);
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include "gskvulkancolorpipelineprivate.h"
|
||||
#include "gskvulkancolortextpipelineprivate.h"
|
||||
#include "gskvulkancrossfadepipelineprivate.h"
|
||||
#include "gskvulkancustompipelineprivate.h"
|
||||
#include "gskvulkaneffectpipelineprivate.h"
|
||||
#include "gskvulkanlineargradientpipelineprivate.h"
|
||||
#include "gskvulkantextpipelineprivate.h"
|
||||
@@ -57,6 +58,7 @@ struct _GskVulkanRender
|
||||
|
||||
GList *render_passes;
|
||||
GSList *cleanup_images;
|
||||
GSList *cleanup_pipelines;
|
||||
|
||||
GQuark render_pass_counter;
|
||||
GQuark gpu_time_timer;
|
||||
@@ -419,6 +421,22 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
|
||||
return self->pipelines[type];
|
||||
}
|
||||
|
||||
GskVulkanPipeline *
|
||||
gsk_vulkan_render_get_custom_pipeline (GskVulkanRender *self,
|
||||
GBytes *fragment_bytes)
|
||||
{
|
||||
GskVulkanPipeline *pipeline;
|
||||
|
||||
pipeline = gsk_vulkan_custom_pipeline_new (self->vulkan,
|
||||
self->pipeline_layout[2],
|
||||
fragment_bytes,
|
||||
self->render_pass);
|
||||
|
||||
self->cleanup_pipelines = g_slist_prepend (self->cleanup_pipelines, pipeline);
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
VkDescriptorSet
|
||||
gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
|
||||
gsize id)
|
||||
@@ -666,6 +684,8 @@ gsk_vulkan_render_cleanup (GskVulkanRender *self)
|
||||
self->render_passes = NULL;
|
||||
g_slist_free_full (self->cleanup_images, g_object_unref);
|
||||
self->cleanup_images = NULL;
|
||||
g_slist_free_full (self->cleanup_pipelines, g_object_unref);
|
||||
self->cleanup_pipelines = NULL;
|
||||
|
||||
g_clear_pointer (&self->clip, cairo_region_destroy);
|
||||
g_clear_object (&self->target);
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include "gskvulkancolorpipelineprivate.h"
|
||||
#include "gskvulkancolortextpipelineprivate.h"
|
||||
#include "gskvulkancrossfadepipelineprivate.h"
|
||||
#include "gskvulkancustompipelineprivate.h"
|
||||
#include "gskvulkaneffectpipelineprivate.h"
|
||||
#include "gskvulkanlineargradientpipelineprivate.h"
|
||||
#include "gskvulkantextpipelineprivate.h"
|
||||
@@ -53,6 +54,7 @@ typedef enum {
|
||||
GSK_VULKAN_OP_REPEAT,
|
||||
GSK_VULKAN_OP_CROSS_FADE,
|
||||
GSK_VULKAN_OP_BLEND_MODE,
|
||||
GSK_VULKAN_OP_PIXEL_SHADER,
|
||||
/* GskVulkanOpText */
|
||||
GSK_VULKAN_OP_TEXT,
|
||||
GSK_VULKAN_OP_COLOR_TEXT,
|
||||
@@ -278,6 +280,13 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
|
||||
default:
|
||||
FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name);
|
||||
|
||||
case GSK_PIXEL_SHADER_NODE:
|
||||
op.type = GSK_VULKAN_OP_PIXEL_SHADER;
|
||||
op.render.pipeline = gsk_vulkan_render_get_custom_pipeline (render,
|
||||
gsk_pixel_shader_node_get_fragment_bytes (node));
|
||||
g_array_append_val (self->render_ops, op);
|
||||
return;
|
||||
|
||||
case GSK_REPEAT_NODE:
|
||||
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
||||
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
|
||||
@@ -304,7 +313,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
|
||||
op.type = GSK_VULKAN_OP_BLEND_MODE;
|
||||
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
|
||||
g_array_append_val (self->render_ops, op);
|
||||
return;
|
||||
return;
|
||||
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
||||
@@ -1040,6 +1049,34 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_PIXEL_SHADER:
|
||||
{
|
||||
GskRenderNode *child1 = gsk_pixel_shader_node_get_child1 (op->render.node);
|
||||
GskRenderNode *child2 = gsk_pixel_shader_node_get_child2 (op->render.node);
|
||||
|
||||
if (child1)
|
||||
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
child1,
|
||||
&child1->bounds,
|
||||
clip,
|
||||
&op->render.source_rect);
|
||||
else
|
||||
op->render.source = NULL;
|
||||
if (child2)
|
||||
op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
child2,
|
||||
&child2->bounds,
|
||||
clip,
|
||||
&op->render.source_rect);
|
||||
else
|
||||
op->render.source2 = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
|
||||
clip = &op->constants.constants.clip;
|
||||
break;
|
||||
@@ -1134,6 +1171,11 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
|
||||
n_bytes += op->render.vertex_count;
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_PIXEL_SHADER:
|
||||
op->render.vertex_count = gsk_vulkan_custom_pipeline_count_vertex_data (GSK_VULKAN_CUSTOM_PIPELINE (op->render.pipeline));
|
||||
n_bytes += op->render.vertex_count;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
|
||||
@@ -1368,6 +1410,19 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_PIXEL_SHADER:
|
||||
{
|
||||
op->render.vertex_offset = offset + n_bytes;
|
||||
gsk_vulkan_custom_pipeline_collect_vertex_data (GSK_VULKAN_CUSTOM_PIPELINE (op->render.pipeline),
|
||||
data + n_bytes + offset,
|
||||
&op->render.node->bounds,
|
||||
&op->render.source ? &op->render.source_rect : &GRAPHENE_RECT_INIT(0,0,1,1),
|
||||
&op->render.source2 ? &op->render.source2_rect : &GRAPHENE_RECT_INIT(0,0,1,1),
|
||||
gsk_pixel_shader_node_get_time (op->render.node));
|
||||
n_bytes += op->render.vertex_count;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
|
||||
@@ -1445,6 +1500,13 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
|
||||
op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, TRUE);
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_PIXEL_SHADER:
|
||||
if (op->render.source)
|
||||
op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
|
||||
if (op->render.source2)
|
||||
op->render.descriptor_set_index2 = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source2, FALSE);
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_TEXT:
|
||||
case GSK_VULKAN_OP_COLOR_TEXT:
|
||||
op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source, FALSE);
|
||||
@@ -1844,6 +1906,45 @@ gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass *self,
|
||||
current_draw_index, 1);
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_PIXEL_SHADER:
|
||||
if (current_pipeline != op->render.pipeline)
|
||||
{
|
||||
current_pipeline = op->render.pipeline;
|
||||
vkCmdBindPipeline (command_buffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
|
||||
vkCmdBindVertexBuffers (command_buffer,
|
||||
0,
|
||||
1,
|
||||
(VkBuffer[1]) {
|
||||
gsk_vulkan_buffer_get_buffer (vertex_buffer)
|
||||
},
|
||||
(VkDeviceSize[1]) { op->render.vertex_offset });
|
||||
current_draw_index = 0;
|
||||
}
|
||||
|
||||
{
|
||||
VkDescriptorSet ds[2];
|
||||
gsize size = 0;
|
||||
if (op->render.source != NULL)
|
||||
ds[size++] = gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index);
|
||||
if (op->render.source2 != NULL)
|
||||
ds[size++] = gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2);
|
||||
vkCmdBindDescriptorSets (command_buffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
|
||||
0,
|
||||
size,
|
||||
ds,
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
current_draw_index += gsk_vulkan_custom_pipeline_draw (GSK_VULKAN_CUSTOM_PIPELINE (current_pipeline),
|
||||
command_buffer,
|
||||
current_draw_index, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
|
@@ -76,6 +76,8 @@ void gsk_vulkan_render_upload (GskVulk
|
||||
|
||||
GskVulkanPipeline * gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
|
||||
GskVulkanPipelineType pipeline_type);
|
||||
GskVulkanPipeline * gsk_vulkan_render_get_custom_pipeline (GskVulkanRender *self,
|
||||
GBytes *fragment_bytes);
|
||||
VkDescriptorSet gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
|
||||
gsize id);
|
||||
gsize gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
|
||||
|
@@ -11,7 +11,7 @@ struct _GskVulkanShader
|
||||
VkShaderModule vk_shader;
|
||||
};
|
||||
|
||||
static GskVulkanShader *
|
||||
GskVulkanShader *
|
||||
gsk_vulkan_shader_new_from_bytes (GdkVulkanContext *context,
|
||||
GskVulkanShaderType type,
|
||||
GBytes *bytes,
|
||||
|
@@ -20,6 +20,10 @@ typedef struct _GskVulkanShader GskVulkanShader;
|
||||
.pName = "main", \
|
||||
}
|
||||
|
||||
GskVulkanShader * gsk_vulkan_shader_new_from_bytes (GdkVulkanContext *context,
|
||||
GskVulkanShaderType type,
|
||||
GBytes *bytes,
|
||||
GError **error);
|
||||
GskVulkanShader * gsk_vulkan_shader_new_from_resource (GdkVulkanContext *context,
|
||||
GskVulkanShaderType type,
|
||||
const char *resource_name,
|
||||
|
@@ -63,6 +63,7 @@ if have_vulkan
|
||||
'gskvulkancolorpipeline.c',
|
||||
'gskvulkancolortextpipeline.c',
|
||||
'gskvulkancrossfadepipeline.c',
|
||||
'gskvulkancustompipeline.c',
|
||||
'gskvulkancommandpool.c',
|
||||
'gskvulkaneffectpipeline.c',
|
||||
'gskvulkanglyphcache.c',
|
||||
|
BIN
gsk/resources/vulkan/custom-clip-rounded.vert.spv
Normal file
BIN
gsk/resources/vulkan/custom-clip-rounded.vert.spv
Normal file
Binary file not shown.
BIN
gsk/resources/vulkan/custom-clip.vert.spv
Normal file
BIN
gsk/resources/vulkan/custom-clip.vert.spv
Normal file
Binary file not shown.
53
gsk/resources/vulkan/custom.vert
Normal file
53
gsk/resources/vulkan/custom.vert
Normal file
@@ -0,0 +1,53 @@
|
||||
#version 420 core
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
mat4 mvp;
|
||||
vec4 clip_bounds;
|
||||
vec4 clip_widths;
|
||||
vec4 clip_heights;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in vec4 inRect;
|
||||
layout(location = 1) in vec4 inTexRect1;
|
||||
layout(location = 2) in vec4 inTexRect2;
|
||||
layout(location = 3) in float inTime;
|
||||
|
||||
layout(location = 0) out vec2 outPos;
|
||||
layout(location = 1) out vec2 outTexCoord1;
|
||||
layout(location = 2) out vec2 outTexCoord2;
|
||||
layout(location = 3) out float outTime;
|
||||
layout(location = 4) out vec2 outResolution;
|
||||
|
||||
out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
vec4 clip(vec4 rect) { return rect; }
|
||||
|
||||
vec2 offsets[6] = { vec2(0.0, 0.0),
|
||||
vec2(1.0, 0.0),
|
||||
vec2(0.0, 1.0),
|
||||
vec2(0.0, 1.0),
|
||||
vec2(1.0, 0.0),
|
||||
vec2(1.0, 1.0) };
|
||||
|
||||
void main() {
|
||||
vec4 rect = clip (inRect);
|
||||
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
|
||||
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
|
||||
|
||||
outPos = pos;
|
||||
|
||||
vec4 texrect = vec4((rect.xy - inRect.xy) / inRect.zw,
|
||||
rect.zw / inRect.zw);
|
||||
vec4 texrect1 = vec4(inTexRect1.xy + inTexRect1.zw * texrect.xy,
|
||||
inTexRect1.zw * texrect.zw);
|
||||
outTexCoord1 = texrect1.xy + texrect1.zw * offsets[gl_VertexIndex];
|
||||
|
||||
vec4 texrect2 = vec4(inTexRect2.xy + inTexRect2.zw * texrect.xy,
|
||||
inTexRect2.zw * texrect.zw);
|
||||
outTexCoord2 = texrect2.xy + texrect2.zw * offsets[gl_VertexIndex];
|
||||
|
||||
outTime = inTime;
|
||||
outResolution = inRect.zw;
|
||||
}
|
BIN
gsk/resources/vulkan/custom.vert.spv
Normal file
BIN
gsk/resources/vulkan/custom.vert.spv
Normal file
Binary file not shown.
@@ -32,6 +32,7 @@ gsk_private_vulkan_vertex_shaders = [
|
||||
'mask.vert',
|
||||
'outset-shadow.vert',
|
||||
'texture.vert',
|
||||
'custom.vert'
|
||||
]
|
||||
|
||||
gsk_private_vulkan_shaders += gsk_private_vulkan_fragment_shaders
|
||||
|
@@ -125,13 +125,13 @@ gtk_snapshot_state_clear (GtkSnapshotState *state)
|
||||
g_clear_pointer (&state->name, g_free);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_snapshot_init (GtkSnapshot *snapshot,
|
||||
GskRenderer *renderer,
|
||||
gboolean record_names,
|
||||
const cairo_region_t *clip,
|
||||
const char *name,
|
||||
...)
|
||||
static void
|
||||
gtk_snapshot_init_va (GtkSnapshot *snapshot,
|
||||
GskRenderer *renderer,
|
||||
gboolean record_names,
|
||||
const cairo_region_t *clip,
|
||||
const char *name,
|
||||
va_list args)
|
||||
{
|
||||
char *str;
|
||||
|
||||
@@ -142,13 +142,7 @@ gtk_snapshot_init (GtkSnapshot *snapshot,
|
||||
snapshot->nodes = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_render_node_unref);
|
||||
|
||||
if (name && record_names)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, name);
|
||||
str = g_strdup_vprintf (name, args);
|
||||
va_end (args);
|
||||
}
|
||||
str = g_strdup_vprintf (name, args);
|
||||
else
|
||||
str = NULL;
|
||||
|
||||
@@ -159,6 +153,38 @@ gtk_snapshot_init (GtkSnapshot *snapshot,
|
||||
gtk_snapshot_collect_default);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_snapshot_init (GtkSnapshot *snapshot,
|
||||
GskRenderer *renderer,
|
||||
gboolean record_names,
|
||||
const cairo_region_t *clip,
|
||||
const char *name,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, name);
|
||||
gtk_snapshot_init_va (snapshot, renderer, record_names, clip, name, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
GtkSnapshot *
|
||||
gtk_snapshot_new (GtkSnapshot *parent,
|
||||
const char *name,
|
||||
...)
|
||||
{
|
||||
GtkSnapshot *snapshot;
|
||||
va_list args;
|
||||
|
||||
snapshot = g_new (GtkSnapshot, 1);
|
||||
|
||||
va_start (args, name);
|
||||
gtk_snapshot_init_va (snapshot, parent->renderer, parent->record_names, NULL, name, args);
|
||||
va_end (args);
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_snapshot_push:
|
||||
* @snapshot: a #GtkSnapshot
|
||||
@@ -1021,6 +1047,17 @@ gtk_snapshot_finish (GtkSnapshot *snapshot)
|
||||
return result;
|
||||
}
|
||||
|
||||
GskRenderNode *
|
||||
gtk_snapshot_free (GtkSnapshot *snapshot)
|
||||
{
|
||||
GskRenderNode *node;
|
||||
|
||||
node = gtk_snapshot_finish (snapshot);
|
||||
g_free (snapshot);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_snapshot_pop:
|
||||
* @snapshot: a #GtkSnapshot
|
||||
|
@@ -36,6 +36,13 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
GtkSnapshot * gtk_snapshot_new (GtkSnapshot *parent,
|
||||
const char *name,
|
||||
...) G_GNUC_PRINTF (2, 3);
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
GskRenderNode * gtk_snapshot_free (GtkSnapshot *snapshot);
|
||||
|
||||
GDK_AVAILABLE_IN_3_90
|
||||
void gtk_snapshot_push (GtkSnapshot *snapshot,
|
||||
gboolean keep_coordinates,
|
||||
|
@@ -87,14 +87,17 @@ struct _GtkSnapshot {
|
||||
GPtrArray *nodes;
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_snapshot_init (GtkSnapshot *state,
|
||||
GskRenderer *renderer,
|
||||
gboolean record_names,
|
||||
const cairo_region_t *clip,
|
||||
const char *name,
|
||||
...) G_GNUC_PRINTF (5, 6);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderNode * gtk_snapshot_finish (GtkSnapshot *state);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderer * gtk_snapshot_get_renderer (const GtkSnapshot *snapshot);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -518,6 +518,10 @@ void gtk_widget_unrealize (GtkWidget *widget);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
void gtk_widget_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot);
|
||||
|
||||
/* Queuing draws */
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_queue_draw (GtkWidget *widget);
|
||||
|
@@ -282,9 +282,6 @@ void gtk_widget_render (GtkWidget
|
||||
GdkWindow *window,
|
||||
const cairo_region_t *region);
|
||||
|
||||
|
||||
void gtk_widget_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot);
|
||||
void gtk_widget_adjust_size_request (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
gint *minimum_size,
|
||||
|
@@ -534,6 +534,13 @@ append_node (GtkTreeModelRenderNode *nodemodel,
|
||||
/* no children */
|
||||
break;
|
||||
|
||||
case GSK_PIXEL_SHADER_NODE:
|
||||
if (gsk_pixel_shader_node_get_child1 (node))
|
||||
append_node (nodemodel, gsk_pixel_shader_node_get_child1 (node), priv->nodes->len - 1);
|
||||
if (gsk_pixel_shader_node_get_child2 (node))
|
||||
append_node (nodemodel, gsk_pixel_shader_node_get_child2 (node), priv->nodes->len - 1);
|
||||
break;
|
||||
|
||||
case GSK_TRANSFORM_NODE:
|
||||
append_node (nodemodel, gsk_transform_node_get_child (node), priv->nodes->len - 1);
|
||||
break;
|
||||
|
@@ -189,6 +189,8 @@ node_type_name (GskRenderNodeType type)
|
||||
return "Text";
|
||||
case GSK_BLUR_NODE:
|
||||
return "Blur";
|
||||
case GSK_PIXEL_SHADER_NODE:
|
||||
return "Pixel Shader";
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user