Compare commits

...

32 Commits

Author SHA1 Message Date
Emmanuele Bassi
1d859a45ef gsk: Add GskLayer
After GskRenderer and GskRenderNode, this commit adds the higher level
scene graph API of GSK.

GskLayer is a 2D layer in 3D space, which can be manipulated like a
widget would, but without the history; unlike GskRenderNode, a scene
graph of GskLayer instances is meant to be kept around.
2016-07-04 16:57:49 +01:00
Emmanuele Bassi
d810989cfd gsk: Add fundamental type annotations for GskRenderNode
We need to annotate the GskRenderNode so that the introspection
machinery can find the functions for managing reference counting
and GValues.
2016-07-04 14:07:24 +01:00
Emmanuele Bassi
ac9517c0aa gsk: Add 'blit' program
For the root node we do not need to use blending, as it does not have
any backdrop to blend into. We can use a simpler 'blit' program that
only takes the content of the source and fills the texture quad with
it.
2016-07-04 13:55:00 +01:00
Emmanuele Bassi
7acc254d51 gsk: Consolidate program creation and storage
We should use ShaderBuilder to create and store programs for the GL
renderer. This allows us to simplify the creation of programs (by moving
the compilation phase into the ShaderBuilder::create_program() method),
and move towards the ability to create multiple programs and just keep a
reference to the program id.
2016-07-04 13:46:22 +01:00
Emmanuele Bassi
c672682668 docs: Add more GSK documentation 2016-07-04 00:23:19 +01:00
Emmanuele Bassi
5aaf111862 gsk: Add more modes to the blend shader
Use the compositing CSS spec at:

  https://www.w3.org/TR/compositing-1/#blending

For the implementation.
2016-07-03 23:30:26 +01:00
Emmanuele Bassi
dee52aec7c gsk: Don't store the uniform and attribute location twice
We should keep the ShaderBuilder around and use it to query the various
uniform and attribute locations when needed, instead of storing those
offsets into the Renderer instance, and copying them. This allows a bit
more flexibility, once we have more than one program built into the
renderer.
2016-07-03 23:30:26 +01:00
Emmanuele Bassi
4dd866c08f gsk: Add getter for program id in ShaderBuilder
Since we store it into the ShaderBuilder instance we should also allow
getting the program id.
2016-07-03 23:30:26 +01:00
Emmanuele Bassi
8d2df67388 gsk: Add debugging notes to ShaderBuilder
Print out the generated shader and the list of available uniforms and
attributes.
2016-07-03 23:30:26 +01:00
Emmanuele Bassi
d7a5c2ccf6 gsk: Rework how GLSL shaders are built
The GL renderer should build the GLSL shaders using GskShaderBuilder.
This allows us to separate the common parts into separate files, and
assemble them as necessary, instead of shipping one big shader per type
of GL API (GL3, GL legacy, and GLES).
2016-07-03 23:30:26 +01:00
Emmanuele Bassi
b5db5fb601 gsk: Add ShaderBuilder
GskShaderBuilder is an ancillary, private type that deals with the
internals of taking GLSL shaders from resources and building them,
with the additional feature of being able to compose shaders from a
common preamble, as well as adding conditional defines (useful for
enabling debugging code in the shaders themselves).
2016-07-03 23:30:26 +01:00
Emmanuele Bassi
c9420c4b3b gsk: Add rendering debug mode for shaders
It's going to be useful to inject debugging data into the shaders used
by GSK.
2016-07-03 23:30:26 +01:00
Emmanuele Bassi
0634f221e3 gdk: Add more GDK_GL_ERROR error ids
We're going to use them in other locations.
2016-07-03 23:30:26 +01:00
Emmanuele Bassi
0de191ca62 build: Fix dependency on GDK for introspection scanner
Otherwise libtool may attempt to use the installed copy of GDK.
2016-07-03 23:30:26 +01:00
Emmanuele Bassi
6e9988cb8b gsk: Use the node's blend mode in the GL renderer 2016-07-03 23:30:26 +01:00
Emmanuele Bassi
88f575d611 gsk: Store blend mode in the render node 2016-07-03 23:30:26 +01:00
Emmanuele Bassi
20848c5eea gsk: Make GskBlendMode enumeration public 2016-07-03 23:30:26 +01:00
Emmanuele Bassi
545a8892ce gsk: Allow sampling between parent and child nodes 2016-07-03 23:30:26 +01:00
Emmanuele Bassi
1319ded55e gsk: Group render state attributes 2016-07-03 23:30:25 +01:00
Emmanuele Bassi
120e8454c3 gsk: Turn GskRenderNode into a pure GTypeInstance
Using GObject as the base type for a transient tree may prove to be too
intensive, especially when creating a lot of node instances. Since we
don't need properties or signals, and we don't need complex destruction
semantics, we can use GTypeInstance directly as the base type for
GskRenderNode.
2016-07-03 23:30:25 +01:00
Emmanuele Bassi
4e07f8234d gtk: Use GskRenderNode to render widgets
We need a virtual function to retrieve the GskRenderNode for each
widget, which is supposed to attach its own children's GskRenderNodes.
Additionally, we want to maintain the existing GtkWidget::draw mechanism
for widgets that do not implement get_render_node() — as well as widgets
that have handlers connected to the ::draw signal.
2016-07-03 23:30:25 +01:00
Emmanuele Bassi
119654155e gtk: Add a GskRenderer to GtkWindow
Each top-level should have its own GskRenderer, to be used when drawing
the render node tree.
2016-07-03 23:30:25 +01:00
Emmanuele Bassi
bb785ad689 gsk: Rework GskRenderer and GskRenderNode semantics
This commit changes the way GskRenderer and GskRenderNode interact and
are meant to be used.

GskRenderNode should represent a transient tree of rendering nodes,
which are submitted to the GskRenderer at render time; this allows the
renderer to take ownership of the render tree. Once the toolkit and
application code have finished assembling it, the render tree ownership
is transferred to the renderer.
2016-07-03 23:30:25 +01:00
Emmanuele Bassi
7c64170a13 gsk: Flush the GL render items cache
Whenever the render tree changes we want to drop the RenderItem arrays,
as each item contains a pointer to the GskRenderNode which becomes
dangling once the root node changed.
2016-07-03 23:30:25 +01:00
Emmanuele Bassi
c6a83f1ba4 gsk: Add GskRenderer::clear_tree
We need a way to clear eventual caches inside GskRenderer subclasses if
the root node has changed.
2016-07-03 23:30:25 +01:00
Emmanuele Bassi
e7309b1474 gsk: Port GskGLRenderer to GLES
Use the appropriate API and shaders if the GdkGLContext was created for
OpenGL ES instead of OpenGL.
2016-07-03 23:30:25 +01:00
Emmanuele Bassi
9e50de3a56 gsk: Use surface-to-texture utility function
Now that we have it.
2016-07-03 23:30:25 +01:00
Emmanuele Bassi
c0c7cf46d6 gsk: Rename shaders for OpenGL 2016-07-03 23:30:25 +01:00
Emmanuele Bassi
b35b32f5dd gdk: Add utility for uploading Cairo surfaces to GL
The surface-to-GL upload logic has become more complicated with the
addition of the GLES code paths; it's more logical to have a public
utility function that can be called from GDK users, instead of copy
pasting the whole thing multiple times.
2016-07-03 23:30:25 +01:00
Emmanuele Bassi
c4262644ea build: Add GSK deps to GTK 2016-07-03 23:30:24 +01:00
Emmanuele Bassi
a3c32b738a Initial implementation of GSK rendering pipeline
GSK is conceptually split into two scene graphs:

 * a simple rendering tree of operations
 * a complex set of logical layers

The latter is built on the former, and adds convenience and high level
API for application developers.

The lower layer, though, is what gets transformed into the rendering
pipeline, as it's simple and thus can be transformed into appropriate
rendering commands with minimal state changes.

The lower layer is also suitable for reuse from more complex higher
layers, like the CSS machinery in GTK, without necessarily port those
layers to the GSK high level API.

This lower layer is based on GskRenderNode instances, which represent
the tree of rendering operations; and a GskRenderer instance, which
takes the render nodes and submits them (after potentially reordering
and transforming them to a more appropriate representation) to the
underlying graphic system.
2016-07-03 23:30:24 +01:00
Emmanuele Bassi
ad8b82f8bd gsk: Initial commit / build environment 2016-07-03 23:30:24 +01:00
51 changed files with 6105 additions and 23 deletions

View File

@@ -1,7 +1,7 @@
## Makefile.am for GTK+
include $(top_srcdir)/Makefile.decl
SRC_SUBDIRS = gdk gtk libgail-util modules demos tests testsuite examples
SRC_SUBDIRS = gdk gsk gtk libgail-util modules demos tests testsuite examples
SUBDIRS = po po-properties $(SRC_SUBDIRS) docs m4macros build
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
@@ -46,7 +46,7 @@ gdk-x11-3.0.pc gdk-win32-3.0.pc gdk-quartz-3.0.pc gdk-broadway-3.0.pc gdk-waylan
cp gdk-3.0.pc $@
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = gdk-3.0.pc gtk+-3.0.pc gail-3.0.pc
pkgconfig_DATA = gdk-3.0.pc gsk-3.0.pc gtk+-3.0.pc gail-3.0.pc
pkgconfig_DATA += ${GDK_BACKENDS:%=gtk+-%-3.0.pc}
pkgconfig_DATA += ${GDK_BACKENDS:%=gdk-%-3.0.pc}
@@ -63,6 +63,7 @@ DISTCLEANFILES = \
gtk+-broadway-3.0.pc \
gtk+-wayland-3.0.pc \
gtk+-mir-3.0.pc \
gsk-3.0.pc \
gdk-3.0.pc \
gdk-x11-3.0.pc \
gdk-win32-3.0.pc \

View File

@@ -64,6 +64,7 @@ m4_define([wayland_protocols_required_version], [1.3])
m4_define([mirclient_required_version], [0.11.0])
m4_define([mircookie_required_version], [0.17.0])
m4_define([epoxy_required_version], [1.0])
m4_define([graphene_required_version], [1.2])
GLIB_REQUIRED_VERSION=glib_required_version
PANGO_REQUIRED_VERSION=pango_required_version
ATK_REQUIRED_VERSION=atk_required_version
@@ -1365,6 +1366,26 @@ AC_SUBST(GDK_EXTRA_CFLAGS)
AC_SUBST(GDK_DEP_LIBS)
AC_SUBST(GDK_DEP_CFLAGS)
########################################
# Check for GSK flags
########################################
GSK_EXTRA_LIBS=
GSK_EXTRA_CFLAGS=
GSK_PACKAGES="gdk-pixbuf-2.0 >= gdk_pixbuf_required_version cairo >= cairo_required_version cairo-gobject >= cairo_required_version graphene-1.0 >= graphene_required_version"
GSK_PRIVATE_PACKAGES="epoxy >= epoxy_required_version"
PKG_CHECK_MODULES(GSK_DEP, $PANGO_PACKAGES $GSK_PACKAGES $GSK_PRIVATE_PACKAGES)
GSK_DEP_LIBS="$GSK_EXTRA_LIBS $GSK_DEP_LIBS $MATH_LIB"
GSK_DEP_CFLAGS="$GSK_DEP_CFLAGS $GSK_EXTRA_CFLAGS"
AC_SUBST(GSK_PACKAGES)
AC_SUBST(GSK_PRIVATE_PACKAGES)
AC_SUBST(GSK_EXTRA_LIBS)
AC_SUBST(GSK_EXTRA_CFLAGS)
AC_SUBST(GSK_DEP_LIBS)
AC_SUBST(GSK_DEP_CFLAGS)
########################################
# Check for Accessibility Toolkit flags
@@ -1379,7 +1400,7 @@ fi
PKG_CHECK_MODULES(ATK, $ATK_PACKAGES)
GTK_PACKAGES="atk >= atk_required_version cairo >= cairo_required_version cairo-gobject >= cairo_required_version gdk-pixbuf-2.0 >= gdk_pixbuf_required_version gio-2.0 >= glib_required_version"
GTK_PRIVATE_PACKAGES="$ATK_PACKAGES $WAYLAND_PACKAGES $MIR_PACKAGES epoxy >= epoxy_required_version"
GTK_PRIVATE_PACKAGES="$ATK_PACKAGES $WAYLAND_PACKAGES $MIR_PACKAGES epoxy >= epoxy_required_version graphene-1.0 >= graphene_required_version"
if test "x$enable_x11_backend" = xyes -o "x$enable_wayland_backend" = xyes; then
GTK_PRIVATE_PACKAGES="$GTK_PRIVATE_PACKAGES pangoft2"
fi
@@ -1892,6 +1913,7 @@ config.h.win32
gtk-zip.sh
Makefile
gdk-3.0.pc
gsk-3.0.pc
gtk+-3.0.pc
gtk+-unix-print-3.0.pc
gail-3.0.pc
@@ -1925,6 +1947,7 @@ testsuite/css/parser/Makefile
testsuite/css/nodes/Makefile
testsuite/css/style/Makefile
testsuite/gdk/Makefile
testsuite/gsk/Makefile
testsuite/gtk/Makefile
testsuite/reftests/Makefile
testsuite/tools/Makefile
@@ -1957,6 +1980,7 @@ gdk/quartz/Makefile
gdk/wayland/Makefile
gdk/mir/Makefile
gdk/gdkversionmacros.h
gsk/Makefile
gtk/Makefile
gtk/makefile.msc
gtk/gtkversion.h

View File

@@ -86,6 +86,13 @@ void gdk_cairo_draw_from_gl (cairo_t *cr,
GDK_AVAILABLE_IN_3_22
GdkDrawingContext * gdk_cairo_get_drawing_context (cairo_t *cr);
GDK_AVAILABLE_IN_3_22
void gdk_cairo_surface_upload_to_gl (cairo_surface_t *surface,
int target,
int width,
int height,
GdkGLContext *context);
G_END_DECLS
#endif /* __GDK_CAIRO_H__ */

View File

@@ -814,3 +814,51 @@ gdk_gl_texture_from_surface (cairo_surface_t *surface,
glDisable (GL_SCISSOR_TEST);
glDeleteTextures (1, &texture_id);
}
/**
* gdk_cairo_surface_upload_to_gl:
* @surface: a Cairo surface
* @target: a GL texture target
* @width: the width of the texture @target
* @height: the height of the texture @target
* @context: (nullable): a #GdkGLContext, or %NULL to use the currently
* bound context
*
* Uploads the contents of a Cairo @surface to a GL texture @target.
*
* Since: 3.22
*/
void
gdk_cairo_surface_upload_to_gl (cairo_surface_t *surface,
int target,
int width,
int height,
GdkGLContext *context)
{
cairo_rectangle_int_t rect;
cairo_surface_t *tmp;
double sx, sy;
double device_x_offset, device_y_offset;
g_return_if_fail (surface != NULL);
g_return_if_fail (context == NULL || GDK_IS_GL_CONTEXT (context));
if (context == NULL)
context = gdk_gl_context_get_current ();
cairo_surface_flush (surface);
sx = sy = 1;
cairo_surface_get_device_scale (surface, &sx, &sy);
cairo_surface_get_device_offset (surface, &device_x_offset, &device_y_offset);
rect.x = (int) device_x_offset;
rect.y = (int) device_y_offset;
rect.width = width * sx;
rect.height = height * sx;
tmp = cairo_surface_map_to_image (surface, &rect);
gdk_gl_context_upload_texture (context, tmp, rect.width, rect.height, target);
cairo_surface_unmap_image (surface, tmp);
}

View File

@@ -470,6 +470,8 @@ struct _GdkPoint
* @GDK_GL_ERROR_NOT_AVAILABLE: OpenGL support is not available
* @GDK_GL_ERROR_UNSUPPORTED_FORMAT: The requested visual format is not supported
* @GDK_GL_ERROR_UNSUPPORTED_PROFILE: The requested profile is not supported
* @GDK_GL_ERROR_COMPILATION_FAILED: The shader compilation failed (available since 3.22)
* @GDK_GL_ERROR_LINK_FAILED: The shader linking failed (available since 3.22)
*
* Error enumeration for #GdkGLContext.
*
@@ -478,7 +480,9 @@ struct _GdkPoint
typedef enum {
GDK_GL_ERROR_NOT_AVAILABLE,
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
GDK_GL_ERROR_UNSUPPORTED_PROFILE
GDK_GL_ERROR_UNSUPPORTED_PROFILE,
GDK_GL_ERROR_COMPILATION_FAILED,
GDK_GL_ERROR_LINK_FAILED
} GdkGLError;
/**

13
gsk-3.0.pc.in Normal file
View File

@@ -0,0 +1,13 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
targets=@GDK_BACKENDS@
Name: GSK
Description: GTK+ Scene Graph Kit
Version: @VERSION@
Requires: gdk-@GTK_API_VERSION@ @GSK_PACKAGES@
Requires.private: @GSK_PRIVATE_PACKAGES@
Libs: -L${libdir} -lgsk-3 @GSK_EXTRA_LIBS@
Cflags: -I${includedir}/gsk-@GTK_API_VERSION@ @GSK_EXTRA_CFLAGS@

159
gsk/Makefile.am Normal file
View File

@@ -0,0 +1,159 @@
include $(top_srcdir)/Makefile.decl
AM_CPPFLAGS = \
-DG_LOG_DOMAIN=\"Gsk\" \
-DGSK_COMPILATION \
-I$(top_srcdir) \
-I$(top_srcdir)/gdk \
-I$(top_builddir) \
-I$(top_builddir)/gsk \
$(GTK_DEBUG_FLAGS) \
$(GSK_DEP_CFLAGS)
# libtool stuff: set version and export symbols for resolving
# since automake doesn't support conditionalized libsomething_la_LDFLAGS
# we use the general approach here
LDADD = \
$(GTK_LINK_FLAGS) \
-version-info $(LT_VERSION_INFO) \
-export-dynamic \
-rpath $(libdir) \
$(no_undefined)
BUILT_SOURCES =
CLEANFILES =
DISTCLEANFILES =
lib_LTLIBRARIES =
gsk_public_source_h = \
gskenums.h \
gsklayer.h \
gskrenderer.h \
gskrendernode.h \
gskrendernodeiter.h \
gsktypes.h
gsk_private_source_h = \
gskcairorendererprivate.h \
gskdebugprivate.h \
gskglrendererprivate.h \
gskprivate.h \
gskrendererprivate.h \
gskrendernodeprivate.h \
gskshaderbuilderprivate.h
gsk_private_source_c = \
gskprivate.c
gsk_built_source_h = \
gskenumtypes.h \
gskresources.h
gsk_built_source_c = \
gskenumtypes.c \
gskresources.c
gsk_source_c = \
gskcairorenderer.c \
gskdebug.c \
gskglrenderer.c \
gsklayer.c \
gskrenderer.c \
gskrendernode.c \
gskrendernodeiter.c \
gskshaderbuilder.c
all_sources = \
$(gsk_public_source_h) \
$(gsk_private_source_h) \
$(gsk_built_source_h) \
$(gsk_private_source_c) \
$(gsk_source_c)
BUILT_SOURCES += $(gsk_built_source_h) $(gsk_built_source_c) gsk.resources.xml
gskenumtypes.h: $(gsk_public_source_h) gskenumtypes.h.template
$(AM_V_GEN) $(GLIB_MKENUMS) --template $(filter %.template,$^) $(filter-out %.template,$^) > \
gskenumtypes.h.tmp && \
mv gskenumtypes.h.tmp gskenumtypes.h
gskenumtypes.c: $(gsk_public_source_h) gskenumtypes.c.template
$(AM_V_GEN) $(GLIB_MKENUMS) --template $(filter %.template,$^) $(filter-out %.template,$^) > \
gskenumtypes.c.tmp && \
mv gskenumtypes.c.tmp gskenumtypes.c
EXTRA_DIST += gskenumtypes.h.template gskenumtypes.c.template
DISTCLEANFILES += gskenumtypes.h gskenumtypes.c
resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(builddir)/gsk.resources.xml)
gsk.resources.xml: Makefile.am
$(AM_V_GEN) echo "<?xml version='1.0' encoding='UTF-8'?>" > $@; \
echo "<gresources>" >> $@; \
echo " <gresource prefix='/org/gtk/libgsk'>" >> $@; \
for f in $(top_srcdir)/gsk/resources/glsl/*; do \
n=`basename $$f`; \
echo " <file alias='glsl/$$n'>resources/glsl/$$n</file>" >> $@; \
done; \
echo " </gresource>" >> $@; \
echo "</gresources>" >> $@
gskresources.h: gsk.resources.xml
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $< \
--target=$@ --sourcedir=$(srcdir) --c-name _gsk --generate-header --manual-register
gskresources.c: gsk.resources.xml $(resource_files)
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $< \
--target=$@ --sourcedir=$(srcdir) --c-name _gsk --generate-source --manual-register
EXTRA_DIST += $(resource_files)
CLEANFILES += gsk.resources.xml
DISTCLEANFILES += gskresources.h gskresources.c
libgsk_3_la_SOURCES = $(all_sources)
nodist_libgsk_3_la_SOURCES = $(gsk_built_source_h) $(gsk_built_source_c)
libgsk_3_la_CFLAGS = $(AM_CFLAGS) $(GDK_HIDDEN_VISIBILITY_CFLAGS)
libgsk_3_la_LIBADD = $(GSK_DEP_LIBS) $(top_builddir)/gdk/libgdk-3.la
libgsk_3_la_LDFLAGS = $(LDADD)
lib_LTLIBRARIES += libgsk-3.la
gskincludedir = $(includedir)/gtk-3.0/gsk
gskinclude_HEADERS = $(gsk_public_source_h) gskenumtypes.h gsk.h
-include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS =
INTROSPECTION_SCANNER_ENV = \
CC="$(CC)"
INTROSPECTION_SCANNER_ARGS = \
--add-include-path=../gdk \
--warn-all
INTROSPECTION_COMPILER_ARGS = \
--includedir=$(srcdir) \
--includedir=. \
--includedir=../gdk
if HAVE_INTROSPECTION
introspection_files = $(filter-out $(wildcard *private.h),$(all_sources))
Gsk-3.0.gir: libgsk-3.la Makefile
Gsk_3_0_gir_SCANNERFLAGS = \
--add-include-path=$(top_builddir)/gdk \
--include-uninstalled=$(top_builddir)/gdk/Gdk-3.0.gir \
--c-include="gsk/gsk.h"
Gsk_3_0_gir_LIBS = libgsk-3.la $(top_builddir)/gdk/libgdk-3.la
Gsk_3_0_gir_FILES = $(introspection_files)
Gsk_3_0_gir_CFLAGS = $(AM_CPPFLAGS)
Gsk_3_0_gir_EXPORT_PACKAGES = gsk-3.0
Gsk_3_0_gir_INCLUDES = GObject-2.0 cairo-1.0 Graphene-1.0
INTROSPECTION_GIRS += Gsk-3.0.gir
girdir = $(datadir)/gir-1.0
gir_DATA = $(INTROSPECTION_GIRS)
typelibsdir = $(libdir)/girepository-1.0
typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
CLEANFILES += $(gir_DATA) $(typelibs_DATA)
endif
-include $(top_srcdir)/git.mk

35
gsk/gsk.h Normal file
View File

@@ -0,0 +1,35 @@
/* GSK - The GTK Scene Kit
* Copyright 2016 Endless
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GSK_H__
#define __GSK_H__
#define __GSK_H_INSIDE__
#include <gsk/gsktypes.h>
#include <gsk/gskenums.h>
#include <gsk/gskenumtypes.h>
#include <gsk/gskrenderer.h>
#include <gsk/gskrendernode.h>
#include <gsk/gskrendernodeiter.h>
#include <gsk/gsklayer.h>
#undef __GSK_H_INSIDE__
#endif /* __GSK_H__ */

180
gsk/gskcairorenderer.c Normal file
View File

@@ -0,0 +1,180 @@
#include "config.h"
#include "gskcairorendererprivate.h"
#include "gskdebugprivate.h"
#include "gskrendererprivate.h"
#include "gskrendernodeiter.h"
#include "gskrendernodeprivate.h"
struct _GskCairoRenderer
{
GskRenderer parent_instance;
graphene_rect_t viewport;
};
struct _GskCairoRendererClass
{
GskRendererClass parent_class;
};
G_DEFINE_TYPE (GskCairoRenderer, gsk_cairo_renderer, GSK_TYPE_RENDERER)
static gboolean
gsk_cairo_renderer_realize (GskRenderer *renderer)
{
return TRUE;
}
static void
gsk_cairo_renderer_unrealize (GskRenderer *renderer)
{
}
static void
gsk_cairo_renderer_render_node (GskCairoRenderer *self,
GskRenderNode *node,
cairo_t *cr)
{
GskRenderNodeIter iter;
GskRenderNode *child;
gboolean pop_group = FALSE;
graphene_matrix_t mvp;
cairo_matrix_t ctm;
graphene_rect_t frame;
if (gsk_render_node_is_hidden (node))
return;
cairo_save (cr);
gsk_render_node_get_world_matrix (node, &mvp);
if (graphene_matrix_to_2d (&mvp, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0))
{
GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n",
ctm.xx, ctm.yx,
ctm.xy, ctm.yy,
ctm.x0, ctm.y0));
cairo_transform (cr, &ctm);
}
else
g_critical ("Invalid non-affine transformation for node %p", node);
gsk_render_node_get_bounds (node, &frame);
GSK_NOTE (CAIRO, g_print ("CLIP = { .x = %g, .y = %g, .width = %g, .height = %g }\n",
frame.origin.x, frame.origin.y,
frame.size.width, frame.size.height));
if (!GSK_RENDER_MODE_CHECK (GEOMETRY))
{
cairo_rectangle (cr, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
cairo_clip (cr);
}
if (!gsk_render_node_is_opaque (node) && gsk_render_node_get_opacity (node) != 1.0)
{
GSK_NOTE (CAIRO, g_print ("Pushing opacity group (opacity:%g)\n",
gsk_render_node_get_opacity (node)));
cairo_push_group (cr);
pop_group = TRUE;
}
GSK_NOTE (CAIRO, g_print ("Rendering surface %p for node %p at %g, %g\n",
gsk_render_node_get_surface (node),
node,
frame.origin.x, frame.origin.y));
cairo_set_source_surface (cr, gsk_render_node_get_surface (node), frame.origin.x, frame.origin.y);
cairo_paint (cr);
if (GSK_RENDER_MODE_CHECK (GEOMETRY))
{
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_rectangle (cr, frame.origin.x - 1, frame.origin.y - 1, frame.size.width + 2, frame.size.height + 2);
cairo_set_line_width (cr, 2);
cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
cairo_stroke (cr);
cairo_restore (cr);
}
cairo_matrix_invert (&ctm);
cairo_transform (cr, &ctm);
if (gsk_render_node_get_n_children (node) != 0)
{
GSK_NOTE (CAIRO, g_print ("Drawing %d children of node [%p]\n",
gsk_render_node_get_n_children (node),
node));
gsk_render_node_iter_init (&iter, node);
while (gsk_render_node_iter_next (&iter, &child))
gsk_cairo_renderer_render_node (self, child, cr);
}
if (pop_group)
{
cairo_pop_group_to_source (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_paint_with_alpha (cr, gsk_render_node_get_opacity (node));
}
cairo_restore (cr);
}
static void
gsk_cairo_renderer_render (GskRenderer *renderer,
GskRenderNode *root,
GdkDrawingContext *context)
{
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
gsk_renderer_get_viewport (renderer, &self->viewport);
if (gsk_renderer_get_auto_clear (renderer))
{
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
if (gsk_renderer_get_use_alpha (renderer))
cairo_set_source_rgba (cr, 0, 0, 0, 0);
else
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_paint (cr);
cairo_restore (cr);
}
if (GSK_RENDER_MODE_CHECK (GEOMETRY))
{
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_rectangle (cr,
self->viewport.origin.x,
self->viewport.origin.y,
self->viewport.size.width,
self->viewport.size.height);
cairo_set_source_rgba (cr, 0, 0, 0.85, 0.5);
cairo_stroke (cr);
cairo_restore (cr);
}
gsk_cairo_renderer_render_node (self, root, cr);
}
static void
gsk_cairo_renderer_class_init (GskCairoRendererClass *klass)
{
GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
renderer_class->realize = gsk_cairo_renderer_realize;
renderer_class->unrealize = gsk_cairo_renderer_unrealize;
renderer_class->render = gsk_cairo_renderer_render;
}
static void
gsk_cairo_renderer_init (GskCairoRenderer *self)
{
}

View File

@@ -0,0 +1,26 @@
#ifndef __GSK_CAIRO_RENDERER_PRIVATE_H__
#define __GSK_CAIRO_RENDERER_PRIVATE_H__
#include <cairo.h>
#include <gsk/gskrenderer.h>
G_BEGIN_DECLS
#define GSK_TYPE_CAIRO_RENDERER (gsk_cairo_renderer_get_type ())
#define GSK_CAIRO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_CAIRO_RENDERER, GskCairoRenderer))
#define GSK_IS_CAIRO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_CAIRO_RENDERER))
#define GSK_CAIRO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_CAIRO_RENDERER, GskCairoRendererClass))
#define GSK_IS_CAIRO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_CAIRO_RENDERER))
#define GSK_CAIRO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_CAIRO_RENDERER, GskCairoRendererClass))
typedef struct _GskCairoRenderer GskCairoRenderer;
typedef struct _GskCairoRendererClass GskCairoRendererClass;
GType gsk_cairo_renderer_get_type (void) G_GNUC_CONST;
GskRenderer *gsk_cairo_renderer_new (void);
G_END_DECLS
#endif /* __GSK_CAIRO_RENDERER_PRIVATE_H__ */

59
gsk/gskdebug.c Normal file
View File

@@ -0,0 +1,59 @@
#include "gskdebugprivate.h"
#ifdef G_ENABLE_DEBUG
static const GDebugKey gsk_debug_keys[] = {
{ "rendernode", GSK_DEBUG_RENDER_NODE },
{ "renderer", GSK_DEBUG_RENDERER },
{ "cairo", GSK_DEBUG_CAIRO },
{ "opengl", GSK_DEBUG_OPENGL },
};
#endif
static const GDebugKey gsk_rendering_keys[] = {
{ "geometry", GSK_RENDERING_MODE_GEOMETRY },
{ "shaders", GSK_RENDERING_MODE_SHADERS },
};
gboolean
gsk_check_debug_flags (GskDebugFlags flags)
{
#ifdef G_ENABLE_DEBUG
static volatile gsize gsk_debug_flags__set;
static guint gsk_debug_flags;
if (g_once_init_enter (&gsk_debug_flags__set))
{
const char *env = g_getenv ("GSK_DEBUG");
gsk_debug_flags = g_parse_debug_string (env,
(GDebugKey *) gsk_debug_keys,
G_N_ELEMENTS (gsk_debug_keys));
g_once_init_leave (&gsk_debug_flags__set, TRUE);
}
return (gsk_debug_flags & flags) != 0;
#else
return FALSE;
#endif
}
gboolean
gsk_check_rendering_flags (GskRenderingMode flags)
{
static volatile gsize gsk_rendering_flags__set;
static guint gsk_rendering_flags;
if (g_once_init_enter (&gsk_rendering_flags__set))
{
const char *env = g_getenv ("GSK_RENDERING_MODE");
gsk_rendering_flags = g_parse_debug_string (env,
(GDebugKey *) gsk_rendering_keys,
G_N_ELEMENTS (gsk_rendering_keys));
g_once_init_leave (&gsk_rendering_flags__set, TRUE);
}
return (gsk_rendering_flags & flags) != 0;
}

44
gsk/gskdebugprivate.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef __GSK_DEBUG_PRIVATE_H__
#define __GSK_DEBUG_PRIVATE_H__
#include <glib.h>
G_BEGIN_DECLS
typedef enum {
GSK_DEBUG_RENDER_NODE = 1 << 0,
GSK_DEBUG_RENDERER = 1 << 1,
GSK_DEBUG_CAIRO = 1 << 2,
GSK_DEBUG_OPENGL = 1 << 3
} GskDebugFlags;
typedef enum {
GSK_RENDERING_MODE_GEOMETRY = 1 << 0,
GSK_RENDERING_MODE_SHADERS = 1 << 1
} GskRenderingMode;
gboolean gsk_check_debug_flags (GskDebugFlags flags);
gboolean gsk_check_rendering_flags (GskRenderingMode flags);
#ifdef G_ENABLE_DEBUG
#define GSK_DEBUG_CHECK(type) G_UNLIKELY (gsk_check_debug_flags (GSK_DEBUG_ ## type))
#define GSK_RENDER_MODE_CHECK(type) G_UNLIKELY (gsk_check_rendering_flags (GSK_RENDERING_MODE_ ## type))
#define GSK_NOTE(type,action) G_STMT_START { \
if (GSK_DEBUG_CHECK (type)) { \
action; \
} } G_STMT_END
#else
#define GSK_RENDER_MODE_CHECK(type) 0
#define GSK_DEBUG_CHECK(type) 0
#define GSK_NOTE(type,action)
#endif
G_END_DECLS
#endif /* __GSK_DEBUG_PRIVATE_H__ */

85
gsk/gskenums.h Normal file
View File

@@ -0,0 +1,85 @@
/* GSK - The GTK Scene Kit
* Copyright 2016 Endless
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GSK_ENUMS_H__
#define __GSK_ENUMS_H__
#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
/**
* GskScalingFilter:
* @GSK_SCALING_FILTER_LINEAR: linear interpolation filter
* @GSK_SCALING_FILTER_NEAREST: nearest neighbor interpolation filter
* @GSK_SCALING_FILTER_TRILINEAR: linear interpolation along each axis,
* plus mipmap generation, with linear interpolation along the mipmap
* levels
*
* The filters used when scaling texture data.
*
* The actual implementation of each filter is deferred to the
* rendering pipeline.
*
* Since: 3.22
*/
typedef enum {
GSK_SCALING_FILTER_LINEAR,
GSK_SCALING_FILTER_NEAREST,
GSK_SCALING_FILTER_TRILINEAR
} GskScalingFilter;
/**
* GskBlendMode:
* @GSK_BLEND_MODE_DEFAULT: The default blend mode, which specifies no blending
* @GSK_BLEND_MODE_MULTIPLY: The source color is multiplied by the destination
* and replaces the destination
* @GSK_BLEND_MODE_SCREEN:
* @GSK_BLEND_MODE_OVERLAY: ...
* @GSK_BLEND_MODE_DARKEN: ...
* @GSK_BLEND_MODE_LIGHTEN: ...
* @GSK_BLEND_MODE_COLOR_DODGE: ...
* @GSK_BLEND_MODE_COLOR_BURN: ...
* @GSK_BLEND_MODE_HARD_LIGHT: ...
* @GSK_BLEND_MODE_SOFT_LIGHT: ...
* @GSK_BLEND_MODE_DIFFERENCE: ...
* @GSK_BLEND_MODE_EXCLUSION: ...
*
* The blend modes available for render nodes.
*
* The implementation of each blend mode is deferred to the
* rendering pipeline.
*
* Since: 3.22
*/
typedef enum {
GSK_BLEND_MODE_DEFAULT = 0,
GSK_BLEND_MODE_MULTIPLY,
GSK_BLEND_MODE_SCREEN,
GSK_BLEND_MODE_OVERLAY,
GSK_BLEND_MODE_DARKEN,
GSK_BLEND_MODE_LIGHTEN,
GSK_BLEND_MODE_COLOR_DODGE,
GSK_BLEND_MODE_COLOR_BURN,
GSK_BLEND_MODE_HARD_LIGHT,
GSK_BLEND_MODE_SOFT_LIGHT,
GSK_BLEND_MODE_DIFFERENCE,
GSK_BLEND_MODE_EXCLUSION
} GskBlendMode;
#endif /* __GSK_TYPES_H__ */

View File

@@ -0,0 +1,38 @@
/*** BEGIN file-header ***/
#include "config.h"
#include "gskenumtypes.h"
#include <gsk.h>
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
GType g_define_type_id =
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
/*** END value-tail ***/

View File

@@ -0,0 +1,24 @@
/*** BEGIN file-header ***/
#ifndef __GSK_ENUM_TYPES_H__
#define __GSK_ENUM_TYPES_H__
#include <gdk/gdk.h>
G_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GDK_AVAILABLE_IN_ALL GType @enum_name@_get_type (void) G_GNUC_CONST;
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
/*** END value-header ***/
/*** BEGIN file-tail ***/
G_END_DECLS
#endif /* __GSK_ENUM_TYPES_H__ */
/*** END file-tail ***/

978
gsk/gskglrenderer.c Normal file
View File

@@ -0,0 +1,978 @@
#include "config.h"
#include "gskglrendererprivate.h"
#include "gskdebugprivate.h"
#include "gskenums.h"
#include "gskrendererprivate.h"
#include "gskrendernodeprivate.h"
#include "gskrendernodeiter.h"
#include "gskshaderbuilderprivate.h"
#include "gskprivate.h"
#include <epoxy/gl.h>
#define SHADER_VERSION_GLES 110
#define SHADER_VERSION_GL_LEGACY 120
#define SHADER_VERSION_GL3 150
typedef struct {
guint vao_id;
guint buffer_id;
guint texture_id;
guint program_id;
guint mvp_location;
guint map_location;
guint parentMap_location;
guint uv_location;
guint position_location;
guint alpha_location;
guint blendMode_location;
} RenderData;
typedef struct {
/* Back pointer to the node, only meant for comparison */
GskRenderNode *node;
graphene_point3d_t min;
graphene_point3d_t max;
graphene_size_t size;
graphene_matrix_t mvp;
gboolean opaque : 1;
float opacity;
float z;
const char *name;
GskBlendMode blend_mode;
RenderData render_data;
RenderData *parent_data;
} RenderItem;
enum {
MVP,
MAP,
PARENT_MAP,
ALPHA,
BLEND_MODE,
N_UNIFORMS
};
enum {
POSITION,
UV,
N_ATTRIBUTES
};
struct _GskGLRenderer
{
GskRenderer parent_instance;
GdkGLContext *context;
graphene_matrix_t mvp;
graphene_frustum_t frustum;
guint frame_buffer;
guint render_buffer;
guint depth_stencil_buffer;
guint texture_id;
GQuark uniforms[N_UNIFORMS];
GQuark attributes[N_ATTRIBUTES];
GskShaderBuilder *shader_builder;
int blend_program_id;
int blit_program_id;
guint vao_id;
GArray *opaque_render_items;
GArray *transparent_render_items;
gboolean has_buffers : 1;
gboolean has_alpha : 1;
gboolean has_stencil_buffer : 1;
gboolean has_depth_buffer : 1;
};
struct _GskGLRendererClass
{
GskRendererClass parent_class;
};
static void render_item_clear (gpointer data_);
G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER)
static void
gsk_gl_renderer_dispose (GObject *gobject)
{
GskGLRenderer *self = GSK_GL_RENDERER (gobject);
g_clear_object (&self->context);
G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (gobject);
}
static void
gsk_gl_renderer_create_buffers (GskGLRenderer *self)
{
if (self->has_buffers)
return;
GSK_NOTE (OPENGL, g_print ("Creating buffers\n"));
glGenFramebuffersEXT (1, &self->frame_buffer);
if (gsk_renderer_get_use_alpha (GSK_RENDERER (self)))
{
if (self->texture_id == 0)
glGenTextures (1, &self->texture_id);
if (self->render_buffer != 0)
{
glDeleteRenderbuffersEXT (1, &self->render_buffer);
self->render_buffer = 0;
}
}
else
{
if (self->render_buffer == 0)
glGenRenderbuffersEXT (1, &self->render_buffer);
if (self->texture_id != 0)
{
glDeleteTextures (1, &self->texture_id);
self->texture_id = 0;
}
}
if (self->has_depth_buffer || self->has_stencil_buffer)
{
if (self->depth_stencil_buffer == 0)
glGenRenderbuffersEXT (1, &self->depth_stencil_buffer);
}
else
{
if (self->depth_stencil_buffer != 0)
{
glDeleteRenderbuffersEXT (1, &self->depth_stencil_buffer);
self->depth_stencil_buffer = 0;
}
}
/* We only have one VAO at the moment */
glGenVertexArrays (1, &self->vao_id);
glBindVertexArray (self->vao_id);
self->has_buffers = TRUE;
}
static void
gsk_gl_renderer_allocate_buffers (GskGLRenderer *self,
int width,
int height)
{
if (self->context == NULL)
return;
if (self->texture_id != 0)
{
glBindTexture (GL_TEXTURE_2D, self->texture_id);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (gdk_gl_context_get_use_es (self->context))
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
}
if (self->render_buffer != 0)
{
glBindRenderbuffer (GL_RENDERBUFFER, self->render_buffer);
glRenderbufferStorage (GL_RENDERBUFFER, GL_RGB8, width, height);
}
if (self->has_depth_buffer || self->has_stencil_buffer)
{
glBindRenderbuffer (GL_RENDERBUFFER, self->depth_stencil_buffer);
if (self->has_stencil_buffer)
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
else
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
}
}
static void
gsk_gl_renderer_attach_buffers (GskGLRenderer *self)
{
gsk_gl_renderer_create_buffers (self);
GSK_NOTE (OPENGL, g_print ("Attaching buffers\n"));
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, self->frame_buffer);
if (self->texture_id != 0)
{
glFramebufferTexture2D (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, self->texture_id, 0);
}
else if (self->render_buffer != 0)
{
glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_RENDERBUFFER_EXT, self->render_buffer);
}
if (self->depth_stencil_buffer != 0)
{
if (self->has_depth_buffer)
glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, self->depth_stencil_buffer);
if (self->has_stencil_buffer)
glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, self->depth_stencil_buffer);
}
}
static void
gsk_gl_renderer_destroy_buffers (GskGLRenderer *self)
{
if (self->context == NULL)
return;
if (!self->has_buffers)
return;
GSK_NOTE (OPENGL, g_print ("Destroying buffers\n"));
gdk_gl_context_make_current (self->context);
if (self->vao_id != 0)
{
glDeleteVertexArrays (1, &self->vao_id);
self->vao_id = 0;
}
if (self->depth_stencil_buffer != 0)
{
glDeleteRenderbuffersEXT (1, &self->depth_stencil_buffer);
self->depth_stencil_buffer = 0;
}
if (self->render_buffer != 0)
{
glDeleteRenderbuffersEXT (1, &self->render_buffer);
self->render_buffer = 0;
}
if (self->texture_id != 0)
{
glDeleteTextures (1, &self->texture_id);
self->texture_id = 0;
}
if (self->frame_buffer != 0)
{
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT (1, &self->frame_buffer);
self->frame_buffer = 0;
}
self->has_buffers = FALSE;
}
static gboolean
gsk_gl_renderer_create_programs (GskGLRenderer *self)
{
GskShaderBuilder *builder;
GError *error = NULL;
gboolean res = FALSE;
builder = gsk_shader_builder_new ();
gsk_shader_builder_set_resource_base_path (builder, "/org/gtk/libgsk/glsl");
self->uniforms[MVP] = gsk_shader_builder_add_uniform (builder, "mvp");
self->uniforms[MAP] = gsk_shader_builder_add_uniform (builder, "map");
self->uniforms[PARENT_MAP] = gsk_shader_builder_add_uniform (builder, "parentMap");
self->uniforms[ALPHA] = gsk_shader_builder_add_uniform (builder, "alpha");
self->uniforms[BLEND_MODE] = gsk_shader_builder_add_uniform (builder, "blendMode");
self->attributes[POSITION] = gsk_shader_builder_add_attribute (builder, "position");
self->attributes[UV] = gsk_shader_builder_add_attribute (builder, "uv");
if (gdk_gl_context_get_use_es (self->context))
{
gsk_shader_builder_set_version (builder, SHADER_VERSION_GLES);
gsk_shader_builder_set_vertex_preamble (builder, "es2_common.vs.glsl");
gsk_shader_builder_set_fragment_preamble (builder, "es2_common.fs.glsl");
gsk_shader_builder_add_define (builder, "GSK_GLES", "1");
}
else if (gdk_gl_context_is_legacy (self->context))
{
gsk_shader_builder_set_version (builder, SHADER_VERSION_GL_LEGACY);
gsk_shader_builder_set_vertex_preamble (builder, "gl_common.vs.glsl");
gsk_shader_builder_set_fragment_preamble (builder, "gl_common.fs.glsl");
gsk_shader_builder_add_define (builder, "GSK_LEGACY", "1");
}
else
{
gsk_shader_builder_set_version (builder, SHADER_VERSION_GL3);
gsk_shader_builder_set_vertex_preamble (builder, "gl3_common.vs.glsl");
gsk_shader_builder_set_fragment_preamble (builder, "gl3_common.fs.glsl");
gsk_shader_builder_add_define (builder, "GSK_GL3", "1");
}
#ifdef G_ENABLE_DEBUG
if (GSK_RENDER_MODE_CHECK (SHADERS))
gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1");
#endif
self->blend_program_id =
gsk_shader_builder_create_program (builder, "blend.vs.glsl", "blend.fs.glsl", &error);
if (error != NULL)
{
g_critical ("Unable to create 'blend' program: %s", error->message);
g_error_free (error);
g_object_unref (builder);
goto out;
}
self->blit_program_id =
gsk_shader_builder_create_program (builder, "blit.vs.glsl", "blit.fs.glsl", &error);
if (error != NULL)
{
g_critical ("Unable to create 'blit' program: %s", error->message);
g_error_free (error);
g_object_unref (builder);
goto out;
}
/* Keep a pointer to query for the uniform and attribute locations
* when rendering the scene
*/
self->shader_builder = builder;
res = TRUE;
out:
return res;
}
static void
gsk_gl_renderer_destroy_programs (GskGLRenderer *self)
{
g_clear_object (&self->shader_builder);
}
static gboolean
gsk_gl_renderer_realize (GskRenderer *renderer)
{
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
GError *error = NULL;
/* If we didn't get a GdkGLContext before realization, try creating
* one now, for our exclusive use.
*/
if (self->context == NULL)
{
GdkWindow *window = gsk_renderer_get_window (renderer);
if (window == NULL)
return FALSE;
self->context = gdk_window_create_gl_context (window, &error);
if (error != NULL)
{
g_critical ("Unable to create GL context for renderer: %s",
error->message);
g_error_free (error);
return FALSE;
}
}
gdk_gl_context_realize (self->context, &error);
if (error != NULL)
{
g_critical ("Unable to realize GL renderer: %s", error->message);
g_error_free (error);
return FALSE;
}
gdk_gl_context_make_current (self->context);
GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
if (!gsk_gl_renderer_create_programs (self))
return FALSE;
gsk_gl_renderer_create_buffers (self);
return TRUE;
}
static void
gsk_gl_renderer_unrealize (GskRenderer *renderer)
{
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
if (self->context == NULL)
return;
gdk_gl_context_make_current (self->context);
g_clear_pointer (&self->opaque_render_items, g_array_unref);
g_clear_pointer (&self->transparent_render_items, g_array_unref);
gsk_gl_renderer_destroy_buffers (self);
gsk_gl_renderer_destroy_programs (self);
if (self->context == gdk_gl_context_get_current ())
gdk_gl_context_clear_current ();
}
static void
gsk_gl_renderer_resize_viewport (GskGLRenderer *self,
const graphene_rect_t *viewport)
{
GSK_NOTE (OPENGL, g_print ("glViewport(0, 0, %g, %g)\n",
viewport->size.width,
viewport->size.height));
glViewport (viewport->origin.x, viewport->origin.y,
viewport->size.width, viewport->size.height);
}
static void
gsk_gl_renderer_update_frustum (GskGLRenderer *self,
const graphene_matrix_t *modelview,
const graphene_matrix_t *projection)
{
GSK_NOTE (OPENGL, g_print ("Updating the modelview/projection\n"));
graphene_matrix_multiply (projection, modelview, &self->mvp);
graphene_frustum_init_from_matrix (&self->frustum, &self->mvp);
GSK_NOTE (OPENGL, g_print ("Renderer MVP:\n"));
GSK_NOTE (OPENGL, graphene_matrix_print (&self->mvp));
}
static void
render_item_clear (gpointer data_)
{
RenderItem *item = data_;
GSK_NOTE (OPENGL, g_print ("Destroying render item [%p] buffer %u\n",
item,
item->render_data.buffer_id));
glDeleteBuffers (1, &item->render_data.buffer_id);
item->render_data.buffer_id = 0;
GSK_NOTE (OPENGL, g_print ("Destroying render item [%p] texture %u\n",
item,
item->render_data.texture_id));
glDeleteTextures (1, &item->render_data.texture_id);
item->render_data.texture_id = 0;
graphene_matrix_init_identity (&item->mvp);
item->opacity = 1;
}
#define N_VERTICES 6
static void
render_item (RenderItem *item)
{
struct vertex_info {
float position[2];
float uv[2];
};
float mvp[16];
glBindVertexArray (item->render_data.vao_id);
/* Generate the vertex buffer for the texture quad */
if (item->render_data.buffer_id == 0)
{
struct vertex_info vertex_data[] = {
{ { item->min.x, item->min.y }, { 0, 0 }, },
{ { item->min.x, item->max.y }, { 0, 1 }, },
{ { item->max.x, item->min.y }, { 1, 0 }, },
{ { item->max.x, item->max.y }, { 1, 1 }, },
{ { item->min.x, item->max.y }, { 0, 1 }, },
{ { item->max.x, item->min.y }, { 1, 0 }, },
};
GSK_NOTE (OPENGL, g_print ("Creating quad for render item [%p]\n", item));
glGenBuffers (1, &(item->render_data.buffer_id));
glBindBuffer (GL_ARRAY_BUFFER, item->render_data.buffer_id);
/* The data won't change */
glBufferData (GL_ARRAY_BUFFER, sizeof (vertex_data), vertex_data, GL_STATIC_DRAW);
/* Set up the buffers with the computed position and texels */
glEnableVertexAttribArray (item->render_data.position_location);
glVertexAttribPointer (item->render_data.position_location, 2, GL_FLOAT, GL_FALSE,
sizeof (struct vertex_info),
(void *) G_STRUCT_OFFSET (struct vertex_info, position));
glEnableVertexAttribArray (item->render_data.uv_location);
glVertexAttribPointer (item->render_data.uv_location, 2, GL_FLOAT, GL_FALSE,
sizeof (struct vertex_info),
(void *) G_STRUCT_OFFSET (struct vertex_info, uv));
}
else
{
/* We already set up the vertex buffer, so we just need to reuse it */
glBindBuffer (GL_ARRAY_BUFFER, item->render_data.buffer_id);
glEnableVertexAttribArray (item->render_data.position_location);
glEnableVertexAttribArray (item->render_data.uv_location);
}
glUseProgram (item->render_data.program_id);
/* Use texture unit 0 for the sampler */
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, item->render_data.texture_id);
glUniform1i (item->render_data.map_location, 0);
if (item->parent_data != NULL)
{
if (item->parent_data->texture_id != 0)
{
glActiveTexture (GL_TEXTURE1);
glBindTexture (GL_TEXTURE_2D, item->parent_data->texture_id);
glUniform1i (item->render_data.parentMap_location, 1);
}
glUniform1i (item->render_data.blendMode_location, item->blend_mode);
}
/* Pass the opacity component */
glUniform1f (item->render_data.alpha_location, item->opaque ? 1 : item->opacity);
/* Pass the mvp to the vertex shader */
GSK_NOTE (OPENGL, graphene_matrix_print (&item->mvp));
graphene_matrix_to_float (&item->mvp, mvp);
glUniformMatrix4fv (item->render_data.mvp_location, 1, GL_FALSE, mvp);
/* Draw the quad */
GSK_NOTE (OPENGL, g_print ("Drawing item <%s>[%p] with opacity: %g\n",
item->name,
item,
item->opaque ? 1 : item->opacity));
glDrawArrays (GL_TRIANGLES, 0, N_VERTICES);
/* Reset the state */
glBindTexture (GL_TEXTURE_2D, 0);
glDisableVertexAttribArray (item->render_data.position_location);
glDisableVertexAttribArray (item->render_data.uv_location);
glUseProgram (0);
}
static void
surface_to_texture (cairo_surface_t *surface,
graphene_rect_t *clip,
int min_filter,
int mag_filter,
guint *texture_out)
{
guint texture_id;
glGenTextures (1, &texture_id);
glBindTexture (GL_TEXTURE_2D, texture_id);
GSK_NOTE (OPENGL, g_print ("Uploading surface[%p] { w:%g, h:%g } to texid:%d\n",
surface,
clip->size.width,
clip->size.height,
texture_id));
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
gdk_cairo_surface_upload_to_gl (surface, GL_TEXTURE_2D, clip->size.width, clip->size.height, NULL);
if (min_filter != GL_NEAREST)
glGenerateMipmap (GL_TEXTURE_2D);
GSK_NOTE (OPENGL, g_print ("New texture id %d from surface %p\n", texture_id, surface));
*texture_out = texture_id;
}
static void
get_gl_scaling_filters (GskRenderer *renderer,
int *min_filter_r,
int *mag_filter_r)
{
GskScalingFilter min_filter, mag_filter;
gsk_renderer_get_scaling_filters (renderer, &min_filter, &mag_filter);
switch (min_filter)
{
case GSK_SCALING_FILTER_NEAREST:
*min_filter_r = GL_NEAREST;
break;
case GSK_SCALING_FILTER_LINEAR:
*min_filter_r = GL_LINEAR;
break;
case GSK_SCALING_FILTER_TRILINEAR:
*min_filter_r = GL_LINEAR_MIPMAP_LINEAR;
break;
}
switch (mag_filter)
{
case GSK_SCALING_FILTER_NEAREST:
*mag_filter_r = GL_NEAREST;
break;
/* There's no point in using anything above GL_LINEAR for
* magnification filters
*/
case GSK_SCALING_FILTER_LINEAR:
case GSK_SCALING_FILTER_TRILINEAR:
*mag_filter_r = GL_LINEAR;
break;
}
}
#if 0
static gboolean
check_in_frustum (const graphene_frustum_t *frustum,
RenderItem *item)
{
graphene_box_t aabb;
graphene_box_init (&aabb, &item->min, &item->max);
graphene_matrix_transform_box (&item->mvp, &aabb, &aabb);
return graphene_frustum_intersects_box (frustum, &aabb);
}
#endif
static float
project_item (const graphene_matrix_t *projection,
const graphene_matrix_t *modelview)
{
graphene_vec4_t vec;
graphene_matrix_get_row (modelview, 3, &vec);
graphene_matrix_transform_vec4 (projection, &vec, &vec);
return graphene_vec4_get_z (&vec) / graphene_vec4_get_w (&vec);
}
static void
gsk_gl_renderer_add_render_item (GskGLRenderer *self,
GskRenderNode *node,
RenderItem *parent)
{
graphene_rect_t viewport;
int gl_min_filter, gl_mag_filter;
cairo_surface_t *surface;
GskRenderNodeIter iter;
graphene_matrix_t mv, projection;
graphene_rect_t bounds;
GskRenderNode *child;
RenderItem item;
int program_id;
if (gsk_render_node_is_hidden (node))
{
GSK_NOTE (OPENGL, g_print ("Skipping hidden node <%s>[%p]\n",
node->name != NULL ? node->name : "unnamed",
node));
return;
}
memset (&item, 0, sizeof (RenderItem));
gsk_renderer_get_viewport (GSK_RENDERER (self), &viewport);
gsk_render_node_get_bounds (node, &bounds);
item.node = node;
item.name = node->name != NULL ? node->name : "unnamed";
/* The texture size */
item.size = bounds.size;
/* Each render item is an axis-aligned bounding box that we
* transform using the given transformation matrix
*/
item.min.x = bounds.origin.x;
item.min.y = bounds.origin.y;
item.min.z = 0.f;
item.max.x = bounds.origin.x + bounds.size.width;
item.max.y = bounds.origin.y + bounds.size.height;
item.max.z = 0.f;
/* The location of the item, in normalized world coordinates */
gsk_render_node_get_world_matrix (node, &mv);
graphene_matrix_multiply (&mv, &self->mvp, &item.mvp);
item.opaque = gsk_render_node_is_opaque (node);
item.opacity = gsk_render_node_get_opacity (node);
item.blend_mode = gsk_render_node_get_blend_mode (node);
/* GL objects */
item.render_data.vao_id = self->vao_id;
item.render_data.buffer_id = 0;
/* Select the program to use */
if (parent != NULL)
program_id = self->blend_program_id;
else
program_id = self->blit_program_id;
item.render_data.map_location =
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MAP]);
item.render_data.parentMap_location =
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[PARENT_MAP]);
item.render_data.mvp_location =
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MVP]);
item.render_data.alpha_location =
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[ALPHA]);
item.render_data.blendMode_location =
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[BLEND_MODE]);
item.render_data.position_location =
gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[POSITION]);
item.render_data.uv_location =
gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[UV]);
item.render_data.program_id = program_id;
if (parent != NULL)
item.parent_data = &(parent->render_data);
else
item.parent_data = NULL;
gsk_renderer_get_projection (GSK_RENDERER (self), &projection);
item.z = project_item (&projection, &mv);
/* TODO: This should really be an asset atlas, to avoid uploading a ton
* of textures. Ideally we could use a single Cairo surface to get around
* the GL texture limits and reorder the texture data on the CPU side and
* do a single upload; alternatively, we could use a separate FBO and
* render each texture into it
*/
get_gl_scaling_filters (GSK_RENDERER (self), &gl_min_filter, &gl_mag_filter);
surface = gsk_render_node_get_surface (node);
/* If the node does not have any surface we skip drawing it, but we still
* recurse.
*
* XXX: This needs to be re-done if the opacity is != 0, in which case we
* need to composite the opacity level of the children
*/
if (surface == NULL)
goto recurse_children;
surface_to_texture (surface, &bounds, gl_min_filter, gl_mag_filter, &(item.render_data.texture_id));
GSK_NOTE (OPENGL, g_print ("Adding node <%s>[%p] to render items\n",
node->name != NULL ? node->name : "unnamed",
node));
if (gsk_render_node_is_opaque (node) && gsk_render_node_get_opacity (node) == 1.f)
g_array_append_val (self->opaque_render_items, item);
else
g_array_prepend_val (self->transparent_render_items, item);
recurse_children:
gsk_render_node_iter_init (&iter, node);
while (gsk_render_node_iter_next (&iter, &child))
gsk_gl_renderer_add_render_item (self, child, &item);
}
static gboolean
gsk_gl_renderer_validate_tree (GskGLRenderer *self,
GskRenderNode *root)
{
int n_nodes;
if (self->context == NULL)
{
GSK_NOTE (OPENGL, g_print ("No valid GL context associated to the renderer"));
return FALSE;
}
n_nodes = gsk_render_node_get_size (root);
gdk_gl_context_make_current (self->context);
self->opaque_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_nodes);
self->transparent_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_nodes);
g_array_set_clear_func (self->opaque_render_items, render_item_clear);
g_array_set_clear_func (self->transparent_render_items, render_item_clear);
GSK_NOTE (OPENGL, g_print ("RenderNode -> RenderItem\n"));
gsk_gl_renderer_add_render_item (self, root, NULL);
GSK_NOTE (OPENGL, g_print ("Total render items: %d of %d (opaque:%d, transparent:%d)\n",
self->opaque_render_items->len + self->transparent_render_items->len,
n_nodes,
self->opaque_render_items->len,
self->transparent_render_items->len));
return TRUE;
}
static void
gsk_gl_renderer_clear_tree (GskGLRenderer *self)
{
if (self->context == NULL)
return;
g_clear_pointer (&self->opaque_render_items, g_array_unref);
g_clear_pointer (&self->transparent_render_items, g_array_unref);
}
static void
gsk_gl_renderer_clear (GskGLRenderer *self)
{
int clear_bits = GL_COLOR_BUFFER_BIT;
if (self->has_depth_buffer)
clear_bits |= GL_DEPTH_BUFFER_BIT;
if (self->has_stencil_buffer)
clear_bits |= GL_STENCIL_BUFFER_BIT;
GSK_NOTE (OPENGL, g_print ("Clearing viewport\n"));
glClearColor (0, 0, 0, 0);
glClear (clear_bits);
}
static void
gsk_gl_renderer_render (GskRenderer *renderer,
GskRenderNode *root,
GdkDrawingContext *context)
{
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
graphene_matrix_t modelview, projection;
graphene_rect_t viewport;
gboolean use_alpha;
int status;
guint i;
if (self->context == NULL)
return;
gdk_gl_context_make_current (self->context);
gsk_renderer_get_viewport (renderer, &viewport);
gsk_gl_renderer_create_buffers (self);
gsk_gl_renderer_allocate_buffers (self, viewport.size.width, viewport.size.height);
gsk_gl_renderer_attach_buffers (self);
if (self->has_depth_buffer)
glEnable (GL_DEPTH_TEST);
else
glDisable (GL_DEPTH_TEST);
/* Ensure that the viewport is up to date */
status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
if (status == GL_FRAMEBUFFER_COMPLETE_EXT)
gsk_gl_renderer_resize_viewport (self, &viewport);
gsk_gl_renderer_clear (self);
gsk_renderer_get_modelview (renderer, &modelview);
gsk_renderer_get_projection (renderer, &projection);
gsk_gl_renderer_update_frustum (self, &modelview, &projection);
if (!gsk_gl_renderer_validate_tree (self, root))
goto out;
/* Opaque pass: front-to-back */
GSK_NOTE (OPENGL, g_print ("Rendering %u opaque items\n", self->opaque_render_items->len));
for (i = 0; i < self->opaque_render_items->len; i++)
{
RenderItem *item = &g_array_index (self->opaque_render_items, RenderItem, i);
render_item (item);
}
glEnable (GL_BLEND);
/* Transparent pass: back-to-front */
GSK_NOTE (OPENGL, g_print ("Rendering %u transparent items\n", self->transparent_render_items->len));
for (i = 0; i < self->transparent_render_items->len; i++)
{
RenderItem *item = &g_array_index (self->transparent_render_items, RenderItem, i);
render_item (item);
}
glDisable (GL_BLEND);
/* Draw the output of the GL rendering to the window */
GSK_NOTE (OPENGL, g_print ("Drawing GL content on Cairo surface using a %s\n",
self->texture_id != 0 ? "texture" : "renderbuffer"));
out:
use_alpha = gsk_renderer_get_use_alpha (renderer);
gdk_cairo_draw_from_gl (gdk_drawing_context_get_cairo_context (context),
gdk_drawing_context_get_window (context),
use_alpha ? self->texture_id : self->render_buffer,
use_alpha ? GL_TEXTURE : GL_RENDERBUFFER,
gsk_renderer_get_scale_factor (renderer),
0, 0, viewport.size.width, viewport.size.height);
gdk_gl_context_make_current (self->context);
gsk_gl_renderer_clear_tree (self);
}
static void
gsk_gl_renderer_class_init (GskGLRendererClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
gobject_class->dispose = gsk_gl_renderer_dispose;
renderer_class->realize = gsk_gl_renderer_realize;
renderer_class->unrealize = gsk_gl_renderer_unrealize;
renderer_class->render = gsk_gl_renderer_render;
}
static void
gsk_gl_renderer_init (GskGLRenderer *self)
{
gsk_ensure_resources ();
graphene_matrix_init_identity (&self->mvp);
self->has_depth_buffer = TRUE;
self->has_stencil_buffer = TRUE;
}

View File

@@ -0,0 +1,23 @@
#ifndef __GSK_GL_RENDERER_PRIVATE_H__
#define __GSK_GL_RENDERER_PRIVATE_H__
#include <gsk/gskrenderer.h>
G_BEGIN_DECLS
#define GSK_TYPE_GL_RENDERER (gsk_gl_renderer_get_type ())
#define GSK_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_RENDERER, GskGLRenderer))
#define GSK_IS_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_RENDERER))
#define GSK_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
#define GSK_IS_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_RENDERER))
#define GSK_GL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
typedef struct _GskGLRenderer GskGLRenderer;
typedef struct _GskGLRendererClass GskGLRendererClass;
GType gsk_gl_renderer_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GSK_GL_RENDERER_PRIVATE_H__ */

59
gsk/gsklayer.c Normal file
View File

@@ -0,0 +1,59 @@
#include "config.h"
#include "gsklayer.h"
#include <gdk/gdk.h>
#include "gskenumtypes.h"
#include "gskdebugprivate.h"
typedef struct {
GskLayer *parent;
GskLayer *first_child;
GskLayer *last_child;
GskLayer *prev_sibling;
GskLayer *next_sibling;
int n_children;
gint64 age;
graphene_rect_t bounds;
graphene_point_t anchor;
graphene_matrix_t transform;
graphene_matrix_t child_transform;
gboolean transform_set : 1;
gboolean child_transform_set : 1;
gboolean is_hidden : 1;
gboolean is_opaque : 1;
} GskLayerPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (GskLayer, gsk_layer, G_TYPE_INITIALLY_UNOWNED)
static void
gsk_layer_class_init (GskLayerClass *klass)
{
}
static void
gsk_layer_init (GskLayer *self)
{
}
/**
* gsk_layer_new:
*
* Creates a new #GskLayer.
*
* Returns: (transfer full): the newly created #GskLayer
*
* Since: 3.22
*/
GskLayer *
gsk_layer_new (void)
{
return g_object_new (GSK_TYPE_LAYER, NULL);
}

68
gsk/gsklayer.h Normal file
View File

@@ -0,0 +1,68 @@
/* GSK - The GTK Scene Kit
*
* Copyright 2016 Endless
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GSK_LAYER_H__
#define __GSK_LAYER_H__
#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gsktypes.h>
#include <gsk/gskrenderer.h>
G_BEGIN_DECLS
#define GSK_TYPE_LAYER gsk_layer_get_type()
GDK_AVAILABLE_IN_3_22
G_DECLARE_DERIVABLE_TYPE (GskLayer, gsk_layer, GSK, LAYER, GInitiallyUnowned)
struct _GskLayerClass
{
/*< private >*/
GInitiallyUnowned parent_instance;
/*< public >*/
/* vfuncs */
GskRenderNode *(* get_render_node) (GskLayer *layer,
GskRenderer *renderer);
void (* queue_resize) (GskLayer *layer,
GskLayer *origin);
void (* queue_redraw) (GskLayer *layer,
GskLayer *origin);
/* signals */
void (* child_added) (GskLayer *layer,
GskLayer *child);
void (* child_removed) (GskLayer *layer,
GskLayer *child);
void (* destroy) (GskLayer *layer);
/*< private >*/
gpointer _padding[16];
};
GskLayer * gsk_layer_new (void);
G_END_DECLS
#endif /* __GSK_LAYER_H__ */

16
gsk/gskprivate.c Normal file
View File

@@ -0,0 +1,16 @@
#include "gskresources.h"
static gpointer
register_resources (gpointer data)
{
_gsk_register_resource ();
return NULL;
}
void
gsk_ensure_resources (void)
{
static GOnce register_resources_once = G_ONCE_INIT;
g_once (&register_resources_once, register_resources, NULL);
}

12
gsk/gskprivate.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef __GSK_PRIVATE_H__
#define __GSK_PRIVATE_H__
#include <glib.h>
G_BEGIN_DECLS
void gsk_ensure_resources (void);
G_END_DECLS
#endif /* __GSK_PRIVATE_H__ */

1083
gsk/gskrenderer.c Normal file

File diff suppressed because it is too large Load Diff

106
gsk/gskrenderer.h Normal file
View File

@@ -0,0 +1,106 @@
/* GSK - The GTK Scene Kit
*
* Copyright 2016 Endless
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GSK_RENDERER_H__
#define __GSK_RENDERER_H__
#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gsktypes.h>
#include <gsk/gskrendernode.h>
G_BEGIN_DECLS
#define GSK_TYPE_RENDERER (gsk_renderer_get_type ())
#define GSK_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_RENDERER, GskRenderer))
#define GSK_IS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_RENDERER))
typedef struct _GskRenderer GskRenderer;
typedef struct _GskRendererClass GskRendererClass;
GDK_AVAILABLE_IN_3_22
GType gsk_renderer_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_22
GskRenderer * gsk_renderer_get_for_display (GdkDisplay *display);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_set_viewport (GskRenderer *renderer,
const graphene_rect_t *viewport);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_get_viewport (GskRenderer *renderer,
graphene_rect_t *viewport);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_set_projection (GskRenderer *renderer,
const graphene_matrix_t *projection);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_get_projection (GskRenderer *renderer,
graphene_matrix_t *projection);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_set_modelview (GskRenderer *renderer,
const graphene_matrix_t *modelview);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_get_modelview (GskRenderer *renderer,
graphene_matrix_t *modelview);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_set_scaling_filters (GskRenderer *renderer,
GskScalingFilter min_filter,
GskScalingFilter mag_filter);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_get_scaling_filters (GskRenderer *renderer,
GskScalingFilter *min_filter,
GskScalingFilter *mag_filter);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_set_scale_factor (GskRenderer *renderer,
int scale_factor);
GDK_AVAILABLE_IN_3_22
int gsk_renderer_get_scale_factor (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_set_auto_clear (GskRenderer *renderer,
gboolean clear);
GDK_AVAILABLE_IN_3_22
gboolean gsk_renderer_get_auto_clear (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_set_use_alpha (GskRenderer *renderer,
gboolean use_alpha);
GDK_AVAILABLE_IN_3_22
gboolean gsk_renderer_get_use_alpha (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_set_window (GskRenderer *renderer,
GdkWindow *window);
GDK_AVAILABLE_IN_3_22
GdkWindow * gsk_renderer_get_window (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_22
GdkDisplay * gsk_renderer_get_display (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_22
gboolean gsk_renderer_realize (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_unrealize (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_render (GskRenderer *renderer,
GskRenderNode *root,
GdkDrawingContext *context);
G_END_DECLS
#endif /* __GSK_RENDERER_H__ */

54
gsk/gskrendererprivate.h Normal file
View File

@@ -0,0 +1,54 @@
/* GSK - The GTK Scene Kit
*
* Copyright 2016 Endless
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GSK_RENDERER_PRIVATE_H__
#define __GSK_RENDERER_PRIVATE_H__
#include "gskrenderer.h"
G_BEGIN_DECLS
#define GSK_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_RENDERER, GskRendererClass))
#define GSK_IS_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_RENDERER))
#define GSK_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_RENDERER, GskRendererClass))
struct _GskRenderer
{
GObject parent_instance;
};
struct _GskRendererClass
{
GObjectClass parent_class;
gboolean (* realize) (GskRenderer *renderer);
void (* unrealize) (GskRenderer *renderer);
void (* render) (GskRenderer *renderer,
GskRenderNode *root,
GdkDrawingContext *context);
};
gboolean gsk_renderer_is_realized (GskRenderer *renderer);
GskRenderNode * gsk_renderer_get_root_node (GskRenderer *renderer);
GdkDrawingContext * gsk_renderer_get_drawing_context (GskRenderer *renderer);
G_END_DECLS
#endif /* __GSK_RENDERER_PRIVATE_H__ */

1483
gsk/gskrendernode.c Normal file

File diff suppressed because it is too large Load Diff

143
gsk/gskrendernode.h Normal file
View File

@@ -0,0 +1,143 @@
/* GSK - The GTK Scene Kit
*
* Copyright 2016 Endless
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GSK_RENDER_NODE_H__
#define __GSK_RENDER_NODE_H__
#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
#define GSK_TYPE_RENDER_NODE (gsk_render_node_get_type ())
#define GSK_RENDER_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_RENDER_NODE, GskRenderNode))
#define GSK_IS_RENDER_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_RENDER_NODE))
typedef struct _GskRenderNode GskRenderNode;
typedef struct _GskRenderNodeClass GskRenderNodeClass;
GDK_AVAILABLE_IN_3_22
GType gsk_render_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_new (void);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_ref (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_unref (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_get_parent (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_get_first_child (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_get_last_child (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_get_next_sibling (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_get_previous_sibling (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_append_child (GskRenderNode *node,
GskRenderNode *child);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_prepend_child (GskRenderNode *node,
GskRenderNode *child);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_insert_child_at_pos (GskRenderNode *node,
GskRenderNode *child,
int index_);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_insert_child_before (GskRenderNode *node,
GskRenderNode *child,
GskRenderNode *sibling);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_insert_child_after (GskRenderNode *node,
GskRenderNode *child,
GskRenderNode *sibling);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_remove_child (GskRenderNode *node,
GskRenderNode *child);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_replace_child (GskRenderNode *node,
GskRenderNode *new_child,
GskRenderNode *old_child);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_render_node_remove_all_children (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
guint gsk_render_node_get_n_children (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
gboolean gsk_render_node_contains (GskRenderNode *node,
GskRenderNode *descendant);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_set_bounds (GskRenderNode *node,
const graphene_rect_t *bounds);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_set_transform (GskRenderNode *node,
const graphene_matrix_t *transform);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_set_child_transform (GskRenderNode *node,
const graphene_matrix_t *transform);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_set_opacity (GskRenderNode *node,
double opacity);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_set_hidden (GskRenderNode *node,
gboolean hidden);
GDK_AVAILABLE_IN_3_22
gboolean gsk_render_node_is_hidden (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_set_opaque (GskRenderNode *node,
gboolean opaque);
GDK_AVAILABLE_IN_3_22
gboolean gsk_render_node_is_opaque (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
cairo_t * gsk_render_node_get_draw_context (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_set_blend_mode (GskRenderNode *node,
GskBlendMode blend_mode);
GDK_AVAILABLE_IN_3_22
GskBlendMode gsk_render_node_get_blend_mode (GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_set_name (GskRenderNode *node,
const char *name);
#define GSK_VALUE_HOLDS_RENDER_NODE(value) (G_VALUE_HOLDS (value, GSK_TYPE_RENDER_NODE))
GDK_AVAILABLE_IN_3_22
void gsk_value_set_render_node (GValue *value,
GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
void gsk_value_take_render_node (GValue *value,
GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_value_get_render_node (const GValue *value);
GDK_AVAILABLE_IN_3_22
GskRenderNode * gsk_value_dup_render_node (const GValue *value);
G_END_DECLS
#endif /* __GSK_RENDER_NODE_H__ */

254
gsk/gskrendernodeiter.c Normal file
View File

@@ -0,0 +1,254 @@
/* GSK - The GTK Scene Kit
*
* Copyright 2016 Endless
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:GskRenderNodeIter
* @title: GskRenderNodeIter
* @Short_desc: Iterator helper for render nodes
*
* TODO
*/
#include "config.h"
#include "gskrendernodeiter.h"
#include "gskrendernodeprivate.h"
typedef struct {
GskRenderNode *root;
GskRenderNode *current;
gint64 age;
gpointer reserved1;
gpointer reserved2;
} RealIter;
#define REAL_ITER(iter) ((RealIter *) (iter))
/**
* gsk_render_node_iter_new: (constructor)
*
* Allocates a new #GskRenderNodeIter.
*
* Returns: (transfer full): the newly allocated #GskRenderNodeIter
*
* Since: 3.22
*/
GskRenderNodeIter *
gsk_render_node_iter_new (void)
{
return g_slice_new (GskRenderNodeIter);
}
/*< private >
* gsk_render_node_iter_copy:
* @src: a #GskRenderNodeIter
*
* Copies a #GskRenderNodeIter.
*
* Returns: (transfer full): a #GskRenderNodeIter
*/
static GskRenderNodeIter *
gsk_render_node_iter_copy (GskRenderNodeIter *src)
{
return g_slice_dup (GskRenderNodeIter, src);
}
/**
* gsk_render_node_iter_free:
* @iter: a #GskRenderNodeIter
*
* Frees the resources allocated by gsk_render_node_iter_new().
*
* Since: 3.22
*/
void
gsk_render_node_iter_free (GskRenderNodeIter *iter)
{
g_slice_free (GskRenderNodeIter, iter);
}
G_DEFINE_BOXED_TYPE (GskRenderNodeIter, gsk_render_node_iter,
gsk_render_node_iter_copy,
gsk_render_node_iter_free)
/**
* gsk_render_node_iter_init:
* @iter: a #GskRenderNodeIter
* @node: a #GskRenderNode
*
* Initializes a #GskRenderNodeIter for iterating over the
* children of @node.
*
* It's safe to call this function multiple times on the same
* #GskRenderNodeIter instance.
*
* Since: 3.22
*/
void
gsk_render_node_iter_init (GskRenderNodeIter *iter,
GskRenderNode *node)
{
RealIter *riter = REAL_ITER (iter);
g_return_if_fail (iter != NULL);
g_return_if_fail (GSK_IS_RENDER_NODE (node));
riter->root = node;
riter->age = node->age;
riter->current = NULL;
}
/**
* gsk_render_node_iter_is_valid:
* @iter: a #GskRenderNodeIter
*
* Checks whether a #GskRenderNodeIter is associated to a #GskRenderNode,
* or whether the associated node was modified while iterating.
*
* Returns: %TRUE if the iterator is still valid.
*
* Since: 3.22
*/
gboolean
gsk_render_node_iter_is_valid (GskRenderNodeIter *iter)
{
RealIter *riter = REAL_ITER (iter);
g_return_val_if_fail (iter != NULL, FALSE);
if (riter->root == NULL)
return FALSE;
return riter->root->age == riter->age;
}
/**
* gsk_render_node_iter_next:
* @iter: a #GskRenderNodeIter
* @child: (out) (transfer none): return location for a #GskRenderNode
*
* Advances the @iter and retrieves the next child of the root #GskRenderNode
* used to initialize the #GskRenderNodeIter.
*
* If the iterator could advance, this function returns %TRUE and sets the
* @child argument with the child #GskRenderNode.
*
* If the iterator could not advance, this function returns %FALSE and the
* contents of the @child argument are undefined.
*
* Returns: %TRUE if the iterator could advance, and %FALSE otherwise
*
* Since: 3.22
*/
gboolean
gsk_render_node_iter_next (GskRenderNodeIter *iter,
GskRenderNode **child)
{
RealIter *riter = REAL_ITER (iter);
g_return_val_if_fail (riter != NULL, FALSE);
g_return_val_if_fail (riter->root != NULL, FALSE);
g_return_val_if_fail (riter->root->age == riter->age, FALSE);
if (riter->current == NULL)
riter->current = riter->root->first_child;
else
riter->current = riter->current->next_sibling;
if (child != NULL)
*child = riter->current;
return riter->current != NULL;
}
/**
* gsk_render_node_iter_prev:
* @iter: a #GskRenderNodeIter
* @child: (out) (transfer none): return location for a #GskRenderNode
*
* Advances the @iter and retrieves the previous child of the root
* #GskRenderNode used to initialize the #GskRenderNodeIter.
*
* If the iterator could advance, this function returns %TRUE and sets the
* @child argument with the child #GskRenderNode.
*
* If the iterator could not advance, this function returns %FALSE and the
* contents of the @child argument are undefined.
*
* Returns: %TRUE if the iterator could advance, and %FALSE otherwise
*
* Since: 3.22
*/
gboolean
gsk_render_node_iter_prev (GskRenderNodeIter *iter,
GskRenderNode **child)
{
RealIter *riter = REAL_ITER (iter);
g_return_val_if_fail (riter != NULL, FALSE);
g_return_val_if_fail (riter->root != NULL, FALSE);
g_return_val_if_fail (riter->root->age == riter->age, FALSE);
if (riter->current == NULL)
riter->current = riter->root->last_child;
else
riter->current = riter->current->prev_sibling;
if (child != NULL)
*child = riter->current;
return riter->current != NULL;
}
/**
* gsk_render_node_iter_remove:
* @iter: a #GskRenderNodeIter
*
* Removes the child #GskRenderNode currently being visited by
* the iterator.
*
* Calling this function on an invalid #GskRenderNodeIter results
* in undefined behavior.
*
* Since: 3.22
*/
void
gsk_render_node_iter_remove (GskRenderNodeIter *iter)
{
RealIter *riter = REAL_ITER (iter);
GskRenderNode *tmp;
g_return_if_fail (riter != NULL);
g_return_if_fail (riter->root != NULL);
g_return_if_fail (riter->root->age == riter->age);
g_return_if_fail (riter->current != NULL);
tmp = riter->current;
if (tmp != NULL)
{
riter->current = tmp->prev_sibling;
gsk_render_node_remove_child (riter->root, tmp);
riter->age += 1;
/* Safety net */
g_assert (riter->age == riter->root->age);
}
}

45
gsk/gskrendernodeiter.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef __GSK_RENDER_NODE_ITER_H__
#define __GSK_RENDER_NODE_ITER_H__
#include <gsk/gskrendernode.h>
G_BEGIN_DECLS
#define GSK_TYPE_RENDER_NODE_ITER (gsk_render_node_iter_get_type())
typedef struct _GskRenderNodeIter GskRenderNodeIter;
struct _GskRenderNodeIter
{
/*< private >*/
gpointer dummy1;
gpointer dummy2;
gint64 dummy3;
gpointer dummy4;
gpointer dummy5;
};
GDK_AVAILABLE_IN_3_22
GType gsk_render_node_iter_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_22
GskRenderNodeIter * gsk_render_node_iter_new (void);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_iter_free (GskRenderNodeIter *iter);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_iter_init (GskRenderNodeIter *iter,
GskRenderNode *node);
GDK_AVAILABLE_IN_3_22
gboolean gsk_render_node_iter_is_valid (GskRenderNodeIter *iter);
GDK_AVAILABLE_IN_3_22
gboolean gsk_render_node_iter_prev (GskRenderNodeIter *iter,
GskRenderNode **child);
GDK_AVAILABLE_IN_3_22
gboolean gsk_render_node_iter_next (GskRenderNodeIter *iter,
GskRenderNode **child);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_iter_remove (GskRenderNodeIter *iter);
G_END_DECLS
#endif /* GSK_RENDER_NODE_ITER_H */

View File

@@ -0,0 +1,93 @@
#ifndef __GSK_RENDER_NODE_PRIVATE_H__
#define __GSK_RENDER_NODE_PRIVATE_H__
#include "gskrendernode.h"
#include <cairo.h>
G_BEGIN_DECLS
#define GSK_RENDER_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_RENDER_NODE, GskRenderNodeClass))
#define GSK_IS_RENDER_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_RENDER_NODE))
#define GSK_RENDER_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_RENDER_NODE, GskRenderNodeClass))
struct _GskRenderNode
{
GTypeInstance parent_instance;
volatile int ref_count;
/* The graph */
GskRenderNode *parent;
GskRenderNode *first_child;
GskRenderNode *last_child;
GskRenderNode *prev_sibling;
GskRenderNode *next_sibling;
int n_children;
/* Use for debugging */
char *name;
/* Tag updated when adding/removing children */
gint64 age;
/* The contents of the node */
cairo_surface_t *surface;
/* Paint opacity */
double opacity;
/* Blend mode */
GskBlendMode blend_mode;
/* Clip rectangle */
graphene_rect_t bounds;
/* Transformations relative to the root of the scene */
graphene_matrix_t world_matrix;
/* Transformations applied to the node */
graphene_matrix_t transform;
/* Transformations applied to the children of the node */
graphene_matrix_t child_transform;
/* Bit fields; leave at the end */
gboolean is_mutable : 1;
gboolean hidden : 1;
gboolean opaque : 1;
gboolean transform_set : 1;
gboolean child_transform_set : 1;
gboolean needs_world_matrix_update : 1;
};
struct _GskRenderNodeClass
{
GTypeClass parent_class;
void (* finalize) (GskRenderNode *node);
};
void gsk_render_node_make_immutable (GskRenderNode *node);
void gsk_render_node_get_bounds (GskRenderNode *node,
graphene_rect_t *frame);
void gsk_render_node_get_transform (GskRenderNode *node,
graphene_matrix_t *mv);
double gsk_render_node_get_opacity (GskRenderNode *node);
cairo_surface_t *gsk_render_node_get_surface (GskRenderNode *node);
GskRenderNode *gsk_render_node_get_toplevel (GskRenderNode *node);
void gsk_render_node_update_world_matrix (GskRenderNode *node,
gboolean force);
void gsk_render_node_get_world_matrix (GskRenderNode *node,
graphene_matrix_t *mv);
int gsk_render_node_get_size (GskRenderNode *root);
G_END_DECLS
#endif /* __GSK_RENDER_NODE_PRIVATE_H__ */

483
gsk/gskshaderbuilder.c Normal file
View File

@@ -0,0 +1,483 @@
#include "config.h"
#include "gskshaderbuilderprivate.h"
#include "gskdebugprivate.h"
#include <gdk/gdk.h>
#include <epoxy/gl.h>
typedef struct {
int program_id;
GHashTable *uniform_locations;
GHashTable *attribute_locations;
} ShaderProgram;
struct _GskShaderBuilder
{
GObject parent_instance;
char *resource_base_path;
char *vertex_preamble;
char *fragment_preamble;
int version;
GPtrArray *defines;
GPtrArray *uniforms;
GPtrArray *attributes;
GHashTable *programs;
};
G_DEFINE_TYPE (GskShaderBuilder, gsk_shader_builder, G_TYPE_OBJECT)
static void
shader_program_free (gpointer data)
{
ShaderProgram *p = data;
g_clear_pointer (&p->uniform_locations, g_hash_table_unref);
g_clear_pointer (&p->attribute_locations, g_hash_table_unref);
glDeleteProgram (p->program_id);
g_slice_free (ShaderProgram, data);
}
static ShaderProgram *
shader_program_new (int program_id)
{
ShaderProgram *p = g_slice_new (ShaderProgram);
p->program_id = program_id;
p->uniform_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
p->attribute_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
return p;
}
static void
gsk_shader_builder_finalize (GObject *gobject)
{
GskShaderBuilder *self = GSK_SHADER_BUILDER (gobject);
g_free (self->resource_base_path);
g_clear_pointer (&self->defines, g_ptr_array_unref);
g_clear_pointer (&self->uniforms, g_ptr_array_unref);
g_clear_pointer (&self->attributes, g_ptr_array_unref);
g_clear_pointer (&self->programs, g_hash_table_unref);
G_OBJECT_CLASS (gsk_shader_builder_parent_class)->finalize (gobject);
}
static void
gsk_shader_builder_class_init (GskShaderBuilderClass *klass)
{
G_OBJECT_CLASS (klass)->finalize = gsk_shader_builder_finalize;
}
static void
gsk_shader_builder_init (GskShaderBuilder *self)
{
self->defines = g_ptr_array_new_with_free_func (g_free);
self->uniforms = g_ptr_array_new_with_free_func (g_free);
self->attributes = g_ptr_array_new_with_free_func (g_free);
self->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL,
shader_program_free);
}
GskShaderBuilder *
gsk_shader_builder_new (void)
{
return g_object_new (GSK_TYPE_SHADER_BUILDER, NULL);
}
void
gsk_shader_builder_set_resource_base_path (GskShaderBuilder *builder,
const char *base_path)
{
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
g_free (builder->resource_base_path);
builder->resource_base_path = g_strdup (base_path);
}
void
gsk_shader_builder_set_vertex_preamble (GskShaderBuilder *builder,
const char *vertex_preamble)
{
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
g_free (builder->vertex_preamble);
builder->vertex_preamble = g_strdup (vertex_preamble);
}
void
gsk_shader_builder_set_fragment_preamble (GskShaderBuilder *builder,
const char *fragment_preamble)
{
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
g_free (builder->fragment_preamble);
builder->fragment_preamble = g_strdup (fragment_preamble);
}
void
gsk_shader_builder_set_version (GskShaderBuilder *builder,
int version)
{
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
builder->version = version;
}
void
gsk_shader_builder_add_define (GskShaderBuilder *builder,
const char *define_name,
const char *define_value)
{
g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
g_return_if_fail (define_name != NULL && *define_name != '\0');
g_return_if_fail (define_value != NULL && *define_name != '\0');
g_ptr_array_add (builder->defines, g_strdup (define_name));
g_ptr_array_add (builder->defines, g_strdup (define_value));
}
GQuark
gsk_shader_builder_add_uniform (GskShaderBuilder *builder,
const char *uniform_name)
{
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), 0);
g_return_val_if_fail (uniform_name != NULL, 0);
g_ptr_array_add (builder->uniforms, g_strdup (uniform_name));
return g_quark_from_string (uniform_name);
}
GQuark
gsk_shader_builder_add_attribute (GskShaderBuilder *builder,
const char *attribute_name)
{
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), 0);
g_return_val_if_fail (attribute_name != NULL, 0);
g_ptr_array_add (builder->attributes, g_strdup (attribute_name));
return g_quark_from_string (attribute_name);
}
static gboolean
lookup_shader_code (GString *code,
const char *base_path,
const char *shader_file,
GError **error)
{
GBytes *source;
char *path;
if (base_path != NULL)
path = g_build_filename (base_path, shader_file, NULL);
else
path = g_strdup (shader_file);
source = g_resources_lookup_data (path, 0, error);
g_free (path);
if (source == NULL)
return FALSE;
g_string_append (code, g_bytes_get_data (source, NULL));
g_bytes_unref (source);
return TRUE;
}
static int
gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
int shader_type,
const char *shader_preamble,
const char *shader_source,
GError **error)
{
GString *code;
char *source;
int shader_id;
int status;
int i;
code = g_string_new (NULL);
if (builder->version > 0)
{
g_string_append_printf (code, "#version %d\n", builder->version);
g_string_append_c (code, '\n');
}
for (i = 0; i < builder->defines->len; i += 2)
{
const char *name = g_ptr_array_index (builder->defines, i);
const char *value = g_ptr_array_index (builder->defines, i + 1);
g_string_append (code, "#define");
g_string_append_c (code, ' ');
g_string_append (code, name);
g_string_append_c (code, ' ');
g_string_append (code, value);
g_string_append_c (code, '\n');
if (i == builder->defines->len - 2)
g_string_append_c (code, '\n');
}
if (!lookup_shader_code (code, builder->resource_base_path, shader_preamble, error))
{
g_string_free (code, TRUE);
return -1;
}
g_string_append_c (code, '\n');
if (!lookup_shader_code (code, builder->resource_base_path, shader_source, error))
{
g_string_free (code, TRUE);
return -1;
}
source = g_string_free (code, FALSE);
shader_id = glCreateShader (shader_type);
glShaderSource (shader_id, 1, (const GLchar **) &source, NULL);
glCompileShader (shader_id);
#ifdef G_ENABLE_DEBUG
if (GSK_DEBUG_CHECK (OPENGL))
{
g_print ("*** Compiling %s shader ***\n"
"%s\n",
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
source);
}
#endif
g_free (source);
glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
int log_len;
char *buffer;
glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len);
buffer = g_malloc0 (log_len + 1);
glGetShaderInfoLog (shader_id, log_len, NULL, buffer);
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_COMPILATION_FAILED,
"Compilation failure in %s shader:\n%s",
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
buffer);
g_free (buffer);
glDeleteShader (shader_id);
return -1;
}
return shader_id;
}
static void
gsk_shader_builder_cache_uniforms (GskShaderBuilder *builder,
ShaderProgram *program)
{
int i;
for (i = 0; i < builder->uniforms->len; i++)
{
const char *uniform = g_ptr_array_index (builder->uniforms, i);
int loc = glGetUniformLocation (program->program_id, uniform);
g_hash_table_insert (program->uniform_locations,
GINT_TO_POINTER (g_quark_from_string (uniform)),
GINT_TO_POINTER (loc));
}
}
static void
gsk_shader_builder_cache_attributes (GskShaderBuilder *builder,
ShaderProgram *program)
{
int i;
for (i = 0; i < builder->attributes->len; i++)
{
const char *attribute = g_ptr_array_index (builder->attributes, i);
int loc = glGetAttribLocation (program->program_id, attribute);
g_hash_table_insert (program->attribute_locations,
GINT_TO_POINTER (g_quark_from_string (attribute)),
GINT_TO_POINTER (loc));
}
}
int
gsk_shader_builder_create_program (GskShaderBuilder *builder,
const char *vertex_shader,
const char *fragment_shader,
GError **error)
{
ShaderProgram *program;
int vertex_id, fragment_id;
int program_id;
int status;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
g_return_val_if_fail (vertex_shader != NULL, -1);
g_return_val_if_fail (fragment_shader != NULL, -1);
vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
builder->vertex_preamble,
vertex_shader,
error);
if (vertex_id < 0)
return -1;
fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
builder->fragment_preamble,
fragment_shader,
error);
if (fragment_id < 0)
{
glDeleteShader (vertex_id);
return -1;
}
program_id = glCreateProgram ();
glAttachShader (program_id, vertex_id);
glAttachShader (program_id, fragment_id);
glLinkProgram (program_id);
glGetProgramiv (program_id, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
char *buffer = NULL;
int log_len = 0;
glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len);
buffer = g_malloc0 (log_len + 1);
glGetProgramInfoLog (program_id, log_len, NULL, buffer);
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED,
"Linking failure in shader:\n%s", buffer);
g_free (buffer);
glDeleteProgram (program_id);
program_id = -1;
goto out;
}
program = shader_program_new (program_id);
gsk_shader_builder_cache_uniforms (builder, program);
gsk_shader_builder_cache_attributes (builder, program);
g_hash_table_insert (builder->programs, GINT_TO_POINTER (program_id), program);
#ifdef G_ENABLE_DEBUG
if (GSK_DEBUG_CHECK (OPENGL))
{
GHashTableIter iter;
gpointer name_p, location_p;
g_hash_table_iter_init (&iter, program->uniform_locations);
while (g_hash_table_iter_next (&iter, &name_p, &location_p))
{
g_print ("Uniform '%s' - location: %d\n",
g_quark_to_string (GPOINTER_TO_INT (name_p)),
GPOINTER_TO_INT (location_p));
}
g_hash_table_iter_init (&iter, program->attribute_locations);
while (g_hash_table_iter_next (&iter, &name_p, &location_p))
{
g_print ("Attribute '%s' - location: %d\n",
g_quark_to_string (GPOINTER_TO_INT (name_p)),
GPOINTER_TO_INT (location_p));
}
}
#endif
out:
if (vertex_id > 0)
{
glDetachShader (program_id, vertex_id);
glDeleteShader (vertex_id);
}
if (fragment_id > 0)
{
glDetachShader (program_id, fragment_id);
glDeleteShader (fragment_id);
}
return program_id;
}
int
gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
int program_id,
GQuark uniform_quark)
{
ShaderProgram *p = NULL;
gpointer loc_p = NULL;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
g_return_val_if_fail (program_id >= 0, -1);
if (builder->uniforms->len == 0)
return -1;
p = g_hash_table_lookup (builder->programs, GINT_TO_POINTER (program_id));
if (p == NULL)
return -1;
if (g_hash_table_lookup_extended (p->uniform_locations, GINT_TO_POINTER (uniform_quark), NULL, &loc_p))
return GPOINTER_TO_INT (loc_p);
return -1;
}
int
gsk_shader_builder_get_attribute_location (GskShaderBuilder *builder,
int program_id,
GQuark attribute_quark)
{
ShaderProgram *p = NULL;
gpointer loc_p = NULL;
g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
g_return_val_if_fail (program_id >= 0, -1);
if (builder->attributes->len == 0)
return -1;
p = g_hash_table_lookup (builder->programs, GINT_TO_POINTER (program_id));
if (p == NULL)
return -1;
if (g_hash_table_lookup_extended (p->attribute_locations, GINT_TO_POINTER (attribute_quark), NULL, &loc_p))
return GPOINTER_TO_INT (loc_p);
return -1;
}

View File

@@ -0,0 +1,46 @@
#ifndef __GSK_SHADER_BUILDER_PRIVATE_H__
#define __GSK_SHADER_BUILDER_PRIVATE_H__
#include <gdk/gdk.h>
#include <graphene.h>
G_BEGIN_DECLS
#define GSK_TYPE_SHADER_BUILDER (gsk_shader_builder_get_type ())
G_DECLARE_FINAL_TYPE (GskShaderBuilder, gsk_shader_builder, GSK, SHADER_BUILDER, GObject)
GskShaderBuilder * gsk_shader_builder_new (void);
void gsk_shader_builder_set_version (GskShaderBuilder *builder,
int version);
void gsk_shader_builder_set_resource_base_path (GskShaderBuilder *builder,
const char *base_path);
void gsk_shader_builder_set_vertex_preamble (GskShaderBuilder *builder,
const char *shader_preamble);
void gsk_shader_builder_set_fragment_preamble (GskShaderBuilder *builder,
const char *shader_preamble);
GQuark gsk_shader_builder_add_uniform (GskShaderBuilder *builder,
const char *uniform_name);
GQuark gsk_shader_builder_add_attribute (GskShaderBuilder *builder,
const char *attribute_name);
void gsk_shader_builder_add_define (GskShaderBuilder *builder,
const char *define_name,
const char *define_value);
int gsk_shader_builder_create_program (GskShaderBuilder *builder,
const char *vertex_shader,
const char *fragment_shader,
GError **error);
int gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
int program_id,
GQuark uniform_quark);
int gsk_shader_builder_get_attribute_location (GskShaderBuilder *builder,
int program_id,
GQuark attribute_quark);
G_END_DECLS
#endif /* __GSK_SHADER_BUILDER_PRIVATE_H__ */

29
gsk/gsktypes.h Normal file
View File

@@ -0,0 +1,29 @@
/* GSK - The GTK Scene Kit
* Copyright 2016 Endless
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GSK_TYPES_H__
#define __GSK_TYPES_H__
#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <graphene.h>
#include <gdk/gdk.h>
#include <gsk/gskenums.h>
#endif /* __GSK_TYPES_H__ */

View File

@@ -0,0 +1,62 @@
vec3 BlendMultiply(vec3 Cb, vec3 Cs) {
return Cb * Cs;
}
vec3 BlendScreen(vec3 Cb, vec3 Cs) {
return Cb + Cs - (Cb * Cs);
}
vec3 BlendHardLight(vec3 Cb, vec3 Cs) {
vec3 m = BlendMultiply(Cb, 2.0 * Cs);
vec3 s = BlendScreen(Cb, 2.0 * Cs - 1.0);
vec3 edge = vec3(0.5, 0.5, 0.5);
/* Use mix() and step() to avoid a branch */
return mix(m, s, step(edge, Cs));
}
vec3 BlendOverlay(vec3 Cb, vec3 Cs) {
return BlendHardLight(Cs, Cb);
}
vec3 BlendDarken(vec3 Cb, vec3 Cs) {
return min(Cb, Cs);
}
vec3 BlendLighten(vec3 Cb, vec3 Cs) {
return max(Cb, Cs);
}
void main() {
vec4 mask = Texture(parentMap, vUv);
vec4 diffuse = Texture(map, vUv);
vec3 res;
if (blendMode == 0) {
res = diffuse.xyz;
}
else if (blendMode == 1) {
res = BlendMultiply(mask.xyz, diffuse.xyz);
}
else if (blendMode == 2) {
res = BlendScreen(mask.xyz, diffuse.xyz);
}
else if (blendMode == 3) {
res = BlendOverlay(mask.xyz, diffuse.xyz);
}
else if (blendMode == 4) {
res = BlendDarken(mask.xyz, diffuse.xyz);
}
else if (blendMode == 5) {
res = BlendLighten(mask.xyz, diffuse.xyz);
}
else if (blendMode == 8) {
res = BlendHardLight(mask.xyz, diffuse.xyz);
}
else {
// Use red for debugging missing blend modes
res = vec3(1.0, 0.0, 0.0);
}
setOutputColor(vec4(res, diffuse.a * alpha));
}

View File

@@ -0,0 +1,6 @@
void main() {
gl_Position = mvp * vec4(position, 0.0, 1.0);
// Flip the sampling
vUv = vec2(uv.x, 1.0 - uv.y);
}

View File

@@ -0,0 +1,5 @@
void main() {
vec4 diffuse = Texture(map, vUv);
setOutputColor(vec4(diffuse.xyz, diffuse.a * alpha));
}

View File

@@ -0,0 +1,6 @@
void main() {
gl_Position = mvp * vec4(position, 0.0, 1.0);
// Flip the sampling
vUv = vec2(uv.x, 1.0 - uv.y);
}

View File

@@ -0,0 +1,16 @@
precision mediump float;
uniform mat4 mvp;
uniform sampler2D map;
uniform sampler2D parentMap;
uniform float alpha;
varying vec2 vUv;
vec4 Texture(sampler2D sampler, vec2 texCoords) {
return texture2D(sampler, texCoords);
}
void setOutputColor(vec4 color) {
gl_FragColor = color;
}

View File

@@ -0,0 +1,7 @@
uniform mat4 mvp;
uniform float alpha;
attribute vec2 position;
attribute vec2 uv;
varying vec2 vUv;

View File

@@ -0,0 +1,19 @@
precision highp float;
uniform sampler2D map;
uniform sampler2D parentMap;
uniform mat4 mvp;
uniform float alpha;
uniform int blendMode;
in vec2 vUv;
out vec4 outputColor;
vec4 Texture(sampler2D sampler, vec2 texCoords) {
return texture(sampler, texCoords);
}
void setOutputColor(vec4 color) {
outputColor = color;
}

View File

@@ -0,0 +1,7 @@
uniform mat4 mvp;
uniform float alpha;
in vec2 position;
in vec2 uv;
out vec2 vUv;

View File

@@ -0,0 +1,14 @@
uniform mat4 mvp;
uniform sampler2D map;
uniform sampler2D parentMap;
uniform float alpha;
varying vec2 vUv;
vec4 Texture(sampler2D sampler, vec2 texCoords) {
return texture2D(sampler, texCoords);
}
void setOutputColor(vec4 color) {
gl_FragColor = color;
}

View File

@@ -0,0 +1,7 @@
uniform mat4 mvp;
uniform float alpha;
attribute vec2 position;
attribute vec2 uv;
varying vec2 vUv;

View File

@@ -26,6 +26,8 @@ AM_CPPFLAGS = \
-I$(top_builddir)/gtk \
-I$(top_srcdir) \
-I$(top_srcdir)/gdk \
-I$(top_srcdir) \
-I$(top_srcdir)/gsk \
$(GMODULE_CFLAGS) \
$(GTK_DEBUG_FLAGS) \
$(GDK_HIDDEN_VISIBILITY_CFLAGS) \
@@ -79,10 +81,12 @@ endif
libadd = \
$(top_builddir)/gdk/libgdk-3.la \
$(top_builddir)/gsk/libgsk-3.la \
$(GMODULE_LIBS) \
$(GTK_DEP_LIBS)
deps = \
$(top_builddir)/gdk/libgdk-3.la
$(top_builddir)/gdk/libgdk-3.la \
$(top_builddir)/gsk/libgsk-3.la
# libtool stuff: set version and export symbols for resolving
# since automake doesn't support conditionalized libsomething_la_LDFLAGS
@@ -1553,7 +1557,7 @@ Gtk_3_0_gir_CFLAGS = \
$(AM_CPPFLAGS) \
-DGTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
Gtk_3_0_gir_FILES = $(introspection_files)
Gtk_3_0_gir_LIBS = libgtk-3.la $(top_builddir)/gdk/libgdk-3.la
Gtk_3_0_gir_LIBS = libgtk-3.la $(top_builddir)/gdk/libgdk-3.la $(top_builddir)/gsk/libgsk-3.la
Gtk_3_0_gir_EXPORT_PACKAGES = gtk+-3.0
INTROSPECTION_GIRS = Gtk-3.0.gir
@@ -1581,6 +1585,7 @@ gtk_query_immodules_3_0_SOURCES = queryimmodules.c gtkutils.c
gtk_query_immodules_3_0_LDADD = \
libgtk-3.la \
$(top_builddir)/gdk/libgdk-3.la \
$(top_builddir)/gsk/libgsk-3.la \
$(GMODULE_LIBS) \
$(GTK_DEP_LIBS)
@@ -1591,24 +1596,28 @@ gtk_encode_symbolic_svg_SOURCES = encodesymbolic.c
gtk_encode_symbolic_svg_LDADD = \
$(GDK_PIXBUF_LIBS) \
$(top_builddir)/gdk/libgdk-3.la \
$(top_builddir)/gsk/libgsk-3.la \
$(GTK_DEP_LIBS)
gtk_builder_tool_SOURCES = gtk-builder-tool.c
gtk_builder_tool_LDADD = \
libgtk-3.la \
$(top_builddir)/gdk/libgdk-3.la \
$(top_builddir)/gsk/libgsk-3.la \
$(GTK_DEP_LIBS)
gtk_query_settings_SOURCES = gtk-query-settings.c
gtk_query_settings_LDADD= \
libgtk-3.la \
$(top_builddir)/gdk/libgdk-3.la \
$(top_builddir)/gsk/libgsk-3.la \
$(GTK_DEP_LIBS)
gtk_launch_SOURCES = gtk-launch.c
gtk_launch_LDADD = \
libgtk-3.la \
$(top_builddir)/gdk/libgdk-3.la \
$(top_builddir)/gsk/libgsk-3.la \
$(GTK_DEP_LIBS)
if OS_WIN32

View File

@@ -17447,28 +17447,128 @@ gtk_widget_reset_controllers (GtkWidget *widget)
}
}
GskRenderer *
gtk_widget_get_renderer (GtkWidget *widget)
{
GtkWidget *toplevel;
toplevel = _gtk_widget_get_toplevel (widget);
if (_gtk_widget_is_toplevel (toplevel))
return gtk_window_get_renderer (GTK_WINDOW (toplevel));
return NULL;
}
GskRenderNode *
gtk_widget_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS (widget);
GskRenderNode *node;
if (klass->get_render_node == NULL)
{
GskRenderNode *tmp;
graphene_rect_t bounds;
GtkAllocation clip;
cairo_t *cr;
gtk_widget_get_clip (widget, &clip);
graphene_rect_init (&bounds, clip.x, clip.y, clip.width, clip.height);
tmp = gsk_render_node_new ();
gsk_render_node_set_bounds (tmp, &bounds);
cr = gsk_render_node_get_draw_context (tmp);
gtk_widget_draw (widget, cr);
cairo_destroy (cr);
node = tmp;
}
else
{
node = klass->get_render_node (widget, renderer);
if (klass->draw != NULL ||
g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
{
GskRenderNode *tmp;
graphene_rect_t bounds;
GtkAllocation clip;
gboolean result;
cairo_t *cr;
gtk_widget_get_clip (widget, &clip);
graphene_rect_init (&bounds, clip.x, clip.y, clip.width, clip.height);
tmp = gsk_render_node_new ();
gsk_render_node_set_bounds (tmp, &bounds);
cr = gsk_render_node_get_draw_context (tmp);
if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
{
g_signal_emit (widget, widget_signals[DRAW], 0, cr, &result);
}
else if (klass->draw != NULL)
{
klass->draw (widget, cr);
}
cairo_destroy (cr);
if (node != NULL)
{
gsk_render_node_append_child (node, tmp);
gsk_render_node_unref (tmp);
}
else
{
node = tmp;
}
}
}
return node;
}
void
gtk_widget_render (GtkWidget *widget,
GdkWindow *window,
const cairo_region_t *region)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
GdkDrawingContext *context;
gboolean do_clip;
cairo_t *cr;
int x, y;
if (priv->double_buffered)
{
GdkDrawingContext *context;
GskRenderer *renderer;
GskRenderNode *root;
/* We only render double buffered on native windows */
if (!gdk_window_has_native (window))
return;
renderer = gtk_widget_get_renderer (widget);
if (renderer == NULL)
return;
root = gtk_widget_get_render_node (widget, renderer);
if (root == NULL)
return;
context = gdk_window_begin_draw_frame (window, region);
cr = gdk_drawing_context_get_cairo_context (context);
gsk_renderer_render (renderer, root, context);
gdk_window_end_draw_frame (window, context);
gsk_render_node_unref (root);
}
else
{
gboolean do_clip;
cairo_t *cr;
int x, y;
/* This is annoying, but it has to stay because Firefox
* disables double buffering on a top-level GdkWindow,
* which breaks the drawing context.
@@ -17478,15 +17578,12 @@ gtk_widget_render (GtkWidget *widget,
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
cr = gdk_cairo_create (window);
G_GNUC_END_IGNORE_DEPRECATIONS
do_clip = _gtk_widget_get_translation_to_window (widget, window, &x, &y);
cairo_translate (cr, -x, -y);
gtk_widget_draw_internal (widget, cr, do_clip);
cairo_destroy (cr);
}
do_clip = _gtk_widget_get_translation_to_window (widget, window, &x, &y);
cairo_translate (cr, -x, -y);
gtk_widget_draw_internal (widget, cr, do_clip);
if (priv->double_buffered)
gdk_window_end_draw_frame (window, context);
else
cairo_destroy (cr);
}

View File

@@ -30,6 +30,7 @@
#endif
#include <gdk/gdk.h>
#include <gsk/gsk.h>
#include <gtk/gtkaccelgroup.h>
#include <gtk/gtkborder.h>
#include <gtk/gtktypes.h>
@@ -599,12 +600,14 @@ struct _GtkWidgetClass
void (*queue_draw_region) (GtkWidget *widget,
const cairo_region_t *region);
GskRenderNode *(* get_render_node) (GtkWidget *widget,
GskRenderer *renderer);
/*< private >*/
GtkWidgetClassPrivate *priv;
/* Padding for future expansion */
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
};

View File

@@ -302,6 +302,9 @@ void gtk_widget_render (GtkWidget
const cairo_region_t *region);
GskRenderNode * gtk_widget_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
/* inline getters */
static inline gboolean

View File

@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <graphene.h>
#include "gtkprivate.h"
#include "gtkwindowprivate.h"
@@ -271,6 +272,8 @@ struct _GtkWindowPrivate
GdkWindow *hardcoded_window;
GtkCssNode *decoration_node;
GskRenderer *renderer;
};
static const GtkTargetEntry dnd_dest_targets [] = {
@@ -7159,6 +7162,16 @@ gtk_window_realize (GtkWidget *widget)
_gtk_widget_get_allocation (widget, &allocation);
if (priv->renderer == NULL)
{
graphene_rect_t viewport;
priv->renderer = gsk_renderer_get_for_display (gtk_widget_get_display (widget));
graphene_rect_init (&viewport, 0, 0, allocation.width, allocation.height);
gsk_renderer_set_viewport (priv->renderer, &viewport);
}
if (gtk_widget_get_parent_window (widget))
{
gtk_container_set_default_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT);
@@ -7182,6 +7195,9 @@ gtk_window_realize (GtkWidget *widget)
gtk_widget_register_window (widget, gdk_window);
gtk_widget_set_realized (widget, TRUE);
gsk_renderer_set_window (priv->renderer, gdk_window);
gsk_renderer_realize (priv->renderer);
return;
}
@@ -7275,6 +7291,10 @@ gtk_window_realize (GtkWidget *widget)
gtk_widget_register_window (widget, gdk_window);
gtk_widget_set_realized (widget, TRUE);
gsk_renderer_set_window (priv->renderer, gdk_window);
gsk_renderer_set_use_alpha (priv->renderer, TRUE);
gsk_renderer_realize (priv->renderer);
attributes.x = allocation.x;
attributes.y = allocation.y;
attributes.width = allocation.width;
@@ -7395,6 +7415,9 @@ gtk_window_realize (GtkWidget *widget)
}
check_scale_changed (window);
/* Renderer */
gsk_renderer_realize (priv->renderer);
}
static void
@@ -7422,6 +7445,9 @@ gtk_window_unrealize (GtkWidget *widget)
GList *link;
gint i;
if (priv->renderer != NULL)
gsk_renderer_unrealize (priv->renderer);
/* On unrealize, we reset the size of the window such
* that we will re-apply the default sizing stuff
* next time we show the window.
@@ -7569,6 +7595,27 @@ _gtk_window_set_allocation (GtkWindow *window,
child_allocation.width = allocation->width;
child_allocation.height = allocation->height;
if (priv->renderer != NULL)
{
graphene_rect_t viewport;
graphene_matrix_t projection;
graphene_matrix_t modelview;
graphene_point3d_t tmp;
graphene_rect_init (&viewport, 0, 0, allocation->width, allocation->height);
gsk_renderer_set_viewport (priv->renderer, &viewport);
graphene_matrix_init_ortho (&projection,
0, allocation->width,
0, allocation->height,
-1, 1);
gsk_renderer_set_projection (priv->renderer, &projection);
graphene_matrix_init_translate (&modelview,
graphene_point3d_init (&tmp, 0.f, 0.f, 0.f));
gsk_renderer_set_modelview (priv->renderer, &modelview);
}
get_shadow_width (window, &window_border);
if (_gtk_widget_get_realized (widget))
@@ -12631,3 +12678,11 @@ gtk_window_set_hardcoded_window (GtkWindow *window,
g_set_object (&priv->hardcoded_window, gdk_window);
}
GskRenderer *
gtk_window_get_renderer (GtkWindow *window)
{
GtkWindowPrivate *priv = window->priv;
return priv->renderer;
}

View File

@@ -135,6 +135,8 @@ void gtk_window_set_hardcoded_window (GtkWindow *window,
GdkScreen *_gtk_window_get_screen (GtkWindow *window);
GskRenderer *gtk_window_get_renderer (GtkWindow *window);
G_END_DECLS
#endif /* __GTK_WINDOW_PRIVATE_H__ */

View File

@@ -7,6 +7,8 @@ AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_builddir)/gdk \
-I$(top_srcdir)/gdk \
-I$(top_builddir)/gsk \
-I$(top_srcdir)/gsk \
$(GTK_DEBUG_FLAGS) \
$(GTK_DEP_CFLAGS) \
$(GDK_DEP_CFLAGS)
@@ -16,6 +18,7 @@ DEPS = \
LDADD = \
$(top_builddir)/gtk/libgtk-3.la \
$(top_builddir)/gsk/libgsk-3.la \
$(top_builddir)/gdk/libgdk-3.la \
$(GTK_DEP_LIBS) \
$(GDK_DEP_LIBS) \

View File

@@ -1,6 +1,6 @@
include $(top_srcdir)/Makefile.decl
SUBDIRS = gdk gtk a11y css reftests tools
SUBDIRS = gdk gsk gtk a11y css reftests tools
-include $(top_srcdir)/git.mk

39
testsuite/gsk/Makefile.am Normal file
View File

@@ -0,0 +1,39 @@
include $(top_srcdir)/Makefile.decl
NULL=
noinst_PROGRAMS = $(TEST_PROGS)
AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_builddir)/gdk \
-I$(top_srcdir)/gdk \
-I$(top_builddir)/gsk \
-I$(top_srcdir)/gsk \
$(GTK_DEBUG_FLAGS) \
$(GTK_DEP_CFLAGS)
LDADD = $(GTK_DEP_LIBS) $(top_builddir)/gsk/libgsk-3.la
TEST_PROGS += \
$(NULL)
if BUILDOPT_INSTALL_TESTS
insttestdir=$(pkglibexecdir)/installed-tests
insttest_PROGRAMS = $(TEST_PROGS)
%.test: %$(EXEEXT) Makefile
$(AM_V_GEN) (echo '[Test]' > $@.tmp; \
echo 'Type=session' >> $@.tmp; \
echo 'Exec=$(insttestdir)/$<' >> $@.tmp; \
mv $@.tmp $@)
test_files = $(TEST_PROGRS:=.test)
DISTCLEANFILES = $(test_files)
testmetadir = $(datadir)/installed-tests/$(PACKAGE)
testmeta_DATA = $(test_files)
endif
-include $(top_srcdir)/git.mk