Compare commits

...

122 Commits

Author SHA1 Message Date
Matthias Clasen b99ed180a1 Convert GtkSpinner to indirect rendering 2016-08-18 17:25:41 -04:00
Matthias Clasen 32de0ed6e5 Convert GtkImage to indirect rendering 2016-08-18 16:06:31 -04:00
Matthias Clasen 7044e7c85b Convert GtkAccelLabel to indirect rendering 2016-08-18 10:01:15 -04:00
Matthias Clasen 92e6935485 Convert GtkLabel to indirect rendering
Warning! This breaks GtkAccelLabel. It will be fixed in the next
commit.
2016-08-18 09:59:35 -04:00
Matthias Clasen 90549054cf Convert GtkFlowBox to indirect rendering 2016-08-18 02:39:08 -04:00
Matthias Clasen 01ea2fcd23 container: Prepare to prune render nodes
Add a should_propagate function for render nodes. Eventually,
this is meant to avoid creating render nodes for child widgets
that are outside the parents clip area. Since we don't have
that information available right now, just filter out nondrawable
children for now.
2016-08-16 12:21:18 -04:00
Matthias Clasen e8b8d4f8e1 Split css background into individual render nodes
Use separate render nodes for each layer in a multi-image
background. WARNING: blend modes don't work right yet.
2016-08-16 12:16:06 -04:00
Matthias Clasen ec448efa6e Add blend mode to debug spew 2016-08-16 12:15:57 -04:00
Matthias Clasen 43bd010640 Don't create render nodes for empty backgrounds 2016-08-16 12:15:38 -04:00
Matthias Clasen 67492d32de Break out the css background render node in a function
This is in preparation for creating separate render nodes
for individual backgrounds.
2016-08-16 12:15:29 -04:00
Matthias Clasen 970013af89 Make outer shadows work again
Change get_render_node to return nodes that are sized to the clip
area and expect to be placed at the clip position; change
gtk_container_propagate_render_node to place child render nodes
accordingly, and change gtk_css_gadget_get_render_node to return
nodes that are sized accordingly as well.
2016-08-16 12:15:20 -04:00
Alexander Larsson 73cd9087d2 gsk: Fix hidpi scaling
We store the vertices in (unscaled) window coords (but the item size
is still scaled to match the texture size). Also, the
projection/model-view multiplication order is switched so that the scale
is applied at the right place.
2016-08-16 12:44:39 +02:00
Alexander Larsson dff269d197 gdk_cairo_surface_upload_to_gl: Don't apply device scale
The arguments to this function is the texture width/height, and these
are already scaled.
2016-08-16 12:05:02 +02:00
Emmanuele Bassi cdca6c326b gsk: Remove :use-alpha from GskRenderer
It's unused, and we always assume we render with an alpha channel
enabled because it's 2016.
2016-08-13 08:59:41 +01:00
Emmanuele Bassi f70c4824d3 gsk: Move scaling filters to GskRenderNode
The renderer will always use nearest-neighbor filters because it renders
at 1:1 pixel to texel ratio.

On the other hand, render nodes may be scaled, so we need to offer a way
to control the minification and magnification filters.
2016-08-13 08:34:22 +01:00
Emmanuele Bassi e6c37c8e83 gsk: Allow adding a GL texture as a node content
If we already have a GL texture we definitely don't want to use
gdk_cairo_draw_from_gl() to draw on a Cairo context if we're going
to take the Cairo surface to which we draw and put it into an OpenGL
texture.
2016-08-12 16:44:29 +01:00
Emmanuele Bassi 0dd2328361 gsk: Drop modelview/projection from GskRenderer API
The details of the modelview and projection matrices are only useful for
the GL renderer; there's really no point in having those details
available in the generic API — especially as the Cairo fallback renderer
cannot really set up a complex modelview or a projection matrix.
2016-08-10 17:59:48 +01:00
Emmanuele Bassi bd27631831 gtk: Sort children by window depth when rendering
This makes popovers pop over instead of under.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 4e2431abb5 gsk: Ensure that non-drawing nodes are supported
Non-drawing nodes should skip the texturing phase.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 6d5ada6062 gtk: Add a box render node for gadgets
Instead of using the background as the gadget's node, we add a
non-drawing node that can be used to apply offsets; all other nodes are
children of the "box" node.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi ddd7d489e3 gsk: Fix the blend mode
The default blend mode should be the equivalent of Cairo's OVER
operator.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 83e7140e7b gsk: Reuse VAOs with identical buffers
Just like we reuse texture ids with the same size we can, at the expense
of a little memory, reuse vertex buffers if they reference the same
attributes and contain the same data.

Each VAO is marked as free at the end of the frame, and if it's not
reused in the following frame, it gets dropped.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi e80800692e gsk: Remove child-transform from render nodes
The child-transform is useful only if we also provide clipping to the
parent nodes, otherwise children will just be drawn outside of the
parent's bounds.

We'll introduce child transforms either at a higher layer, or once we
add clipping support to GskRenderNode.
2016-08-09 17:31:55 +01:00
Matthias Clasen 0dcfd78be9 Covert GtkOverlay to indirect rendering
There is no gadget, so we use the gtk_widget_create_render_node
function for the first time here.
2016-08-09 17:31:55 +01:00
Matthias Clasen a86109556b Convert GtkComboBox to indirect rendering
The removal of the draw method in GtkComboBox reveals another
instance of parent-child invariant violation in GtkComboBoxText.
2016-08-09 17:31:55 +01:00
Matthias Clasen b6170be2c3 GtkButtonBox: Convert to indirect rendering 2016-08-09 17:31:55 +01:00
Matthias Clasen 891b39425c Small documentation additions 2016-08-09 17:31:55 +01:00
Matthias Clasen 3089f0afd1 Small fixes for the docs
Set titles and short descriptions for the sections.
2016-08-09 17:31:55 +01:00
Matthias Clasen c5d1764ccf gsk: Build docs 2016-08-09 17:31:55 +01:00
Matthias Clasen 21206e7206 GtkListBox: Convert to indirect rendering
Note that there is a problem with the pixel cache that causes
listboxes to come out black when in a scrolled window.
2016-08-09 17:31:55 +01:00
Matthias Clasen 7fffdb1e4a gadget: Fix handling of custom content
The transformations here were wrong, causing content to go nowhere.
This patch fixes check and radio buttons to appear as expected.
2016-08-09 17:31:55 +01:00
Matthias Clasen 4a163a2bbe GtkCheckButton: Convert to indirect rendering
This is another example of indirect rendering with a box gadget.
There is currently still some positioning problem with the
checkmark.
2016-08-09 17:31:55 +01:00
Matthias Clasen f3f444aec4 Prevent box gadget content from being drawn twice
Now that we split out box gadget children into separate
render nodes, we must not draw them onto the box gadgets
node anymore.
2016-08-09 17:31:55 +01:00
Matthias Clasen ceb4c0a959 GtkExpander: Convert to indirect rendering
This is the first example of indirect rendering involving
a box gadget. For now, we iterate the child gadgets manually,
and rely on gtk_container_propagate_render_node for the
child widgets. Eventually, we may want a better solution
here.
2016-08-09 17:31:55 +01:00
Matthias Clasen c9101298fc gadget: Add a has_content vfunc
...and implement it for GtkCssGadget and GtkCssCustomGadget.
This allows us to decide on a per-object basis if a custom
gadget needs a render node for content or not.
2016-08-09 17:31:55 +01:00
Matthias Clasen 5638e68a34 button: Restore focus
The custom gadget draw function has the side effect of informing
the gadget machinery wether to draw focus or not. Bring the
draw function back, just for its boolean return value. We may
want to find a better solution for this.
2016-08-09 17:31:55 +01:00
Matthias Clasen d9f4ac9ecc Allow selective debug spew
I don't think this should stay in the code long-term, but it
is useful for debugging. It helped me track down some suspicious
placements of render nodes.
2016-08-09 17:31:55 +01:00
Matthias Clasen 15ed294471 Add details to css render nodes
Give all nodes the same detail about the owner widget.
This reveals that every GtkCssCustomGadget gets a
DrawGadgetContents node, even if their draw_func is NULL.
We may want to come up with a better solution for that.
2016-08-09 17:31:55 +01:00
Matthias Clasen 457094bda5 Some debug help
Make the bounds of drawing surfaces created by render nodes visible.

Trigger with GSK_DEBUG=surface.
2016-08-09 17:31:55 +01:00
Matthias Clasen 8d14c67735 Drop an unused variable 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 867ca3a13f gtk: Clean up render fallback node creation in GtkWidget 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 71cedfb8f5 gtk: Port GtkHeaderBar to render nodes 2016-08-09 17:31:55 +01:00
Emmanuele Bassi d823d9bfde gtk: Port GtkActionBar to render nodes 2016-08-09 17:31:55 +01:00
Emmanuele Bassi f722c74158 gtk: Attempt at handling CSS coordinates
When creating the GskRenderNodes for the gadgets we should not translate
the coordinates inside the Cairo context, but we should tweak the
coordinates of the anchor point.

This is still not enough to get an appropriate rendering, as the result
is still slightly offset to the left.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi a571b9553f gsk: Pass the appropriate value for the n_quads argument
Instead of passing the size of the buffer, we should pass the number of
quads; we know what the size of a single quad structure is, so we can do
the multiplication internally when creating the VAO.

This allows us to print the quads for debugging purposes.
2016-08-09 17:31:55 +01:00
Matthias Clasen 887dd5666e GtkFrame: Convert to indirect rendering
Create a GskRenderNode for the contents of the frame.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 935d74ffa6 gtk: Add convenience function for creating render nodes
GtkWidget.create_render_node() sets up a GskRenderNode appropriate for
rendering the contents of a widget, including its bounds,
transformation, and anchor point.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 8b9cd74413 gsk: Rename set_offset() to set_anchor_point()
The naming is consistent with other scene graph libraries, as it
represents an additional translation transformation applied on top of
the provided transformation matrices.

We can also simplify the implementation by applying the translation when
we compute the world matrix.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 82e35ddbd5 gsk: Recycle textures across frames
We keep the textures used inside a frame around until the end of the
following frame; whenever we need a texture with the same size, and
it's not marked in use, then we just reuse the existing texture.
2016-08-09 17:31:55 +01:00
Matthias Clasen 79bace4f81 Fix fallback render nodes
We were allocating a surface thats big enough for the clip, and
we were setting the transform for that, but then GtkContainer
was overriding the transform with the one for the allocation.
Also, we were drawing at the clip position, not the allocation
position.
2016-08-09 17:31:55 +01:00
Matthias Clasen 4e2699ec9c Add an offset to render nodes
This will let us account for the difference between
clip and allocation.
2016-08-09 17:31:55 +01:00
Matthias Clasen 55d7073c69 gsk: Split of debug spew for transforms
This was overwhelming other useful debug output, so make it
opt-in. We print the render items for both opengl and transforms,
since the matrices bleed into each other, otherwise.
2016-08-09 17:31:55 +01:00
Matthias Clasen 5c1f277bf3 gsk: Add debug macros that trigger on two conditions
This will be useful in the following commits.
2016-08-09 17:31:55 +01:00
Matthias Clasen c18d866a1b gsk: Add a debug flag for transforms 2016-08-09 17:31:55 +01:00
Matthias Clasen 7d8829c1ab gsk: Improve debug output a bit
Indent render node debug spew to make the tree structure obvious.
2016-08-09 17:31:55 +01:00
Matthias Clasen 108b790cac button: Convert to indirect rendering
WARNING! This commit breaks GtkButton subclasses.
2016-08-09 17:31:55 +01:00
Matthias Clasen 08799f6d15 Convert GtkGrid to indirect rendering
Following the example of GtkBox.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 9e3458d1cc gsk: Add GskProfiler to GskRenderer
The profiler instance is per-renderer, and is accesible to
implementations.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 980e732778 gsk: Add profiler object
The GskProfiler holds counters and timers, and will be used by the
renderer implementations to acquire frame timings.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi fcd1d32e65 box: Port from immediate to deferred rendering
Drop the ::draw() vfunc implementation in favour of the
::get_render_node() vfunc.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 0d6253e300 Integrate CSS gadget with GSK render nodes
First stab at an internal API that generates render nodes when drawing a
CSS gadget.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 49a91f1f2d gtk: Update the coordinates when propagating render nodes
Just like gtk_container_propagate_draw() does for the immediate mode
rendering.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 347fd38744 Use the projection to flip around the content
Since we use an FBO to render the contents of the render node tree, the
coordinate space is going to be flipped in GL. We can undo the flip by
using an appropriate projection matrix, instead of changing the sampling
coordinates in the shaders and updating all our coordinates at render
time.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi bf997b4db3 widget: Fix compatibility fallbacks 2016-08-09 17:31:55 +01:00
Emmanuele Bassi e14100d712 gsk: Add texture size to debug message 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 82e635bad1 gsk: Take into account the scaling factor
We need to apply a scaling factor whenever we deal with user-supplied
coordinates, like:

 - when creating textures
 - when setting up the viewport
 - when submitting the scene
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 5b74850a8c gsk: Tie render nodes to renderers
Render nodes need access to rendering information like scaling factors.
If we keep render nodes separate from renderers until we submit a nodes
tree for rendering we're going to have to duplicate all that information
in a way that makes the API more complicated and fuzzier on its
semantics.

By having GskRenderer create GskRenderNode instances we can tie nodes
and renderers together; since higher layers will also have access to
the renderer instance, this does not add any burden to callers.

Additionally, if memory measurements indicate that we are spending too
much time in the allocation of new render nodes, we can now easily
implement a free-list or a renderer-specific allocator without breaking
the API.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi a64168cba2 gsk: Bind GL context to the GL profiler
Similarly to how we bind it to the GL driver object used by the GSK GL
renderer.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 87fb23fadd gtk: Port GtkWindow to render nodes
WARNING: BROKEN COMMIT
2016-08-09 17:31:55 +01:00
Emmanuele Bassi d6d1568f4d gtk: Add GtkContainer API to gather render nodes
We cannot implement GtkWidgetClass.get_render_node() in GtkContainer
without breaking the fallback path that renders a widget to a single
render node rasterization. For GtkContainer subclasses we should provide
a simple API, similar to gtk_container_propagate_draw(), that gathers
all the render nodes for each child.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi e160b80853 gtk: Name GSK render nodes
For debugging purposes it's helpful to name the nodes.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 06ede28b11 gsk: Fix build without Wayland 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 420825ca33 gsk: Add redirection to FBOs for opacity groups
If a node is non-opaque and has a non-zero opacity we need to paint its
contents and children first to an off screen buffer, and then render the
resulting texture at the desired opacity — otherwise the opacities will
combine and result in the wrong rendering.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 4d7e6e2cad gsk: Drop opaque/transparent item split
We're not going to use separate rendering lists soon, and the way we
render items is less similar to a gaming engine and more similar to a
simpler compositor. This means we don't need to perform a two pass
rendering — opaque items first, transparent items later.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 3c7ea1ebd9 gsk: Rename uniforms and attributes in shaders
Use appropriate names, and annotate the names with the types — 'u' for
uniforms, 'a' for attributes. The common preambles for shaders are split
from the bodies, so we need some way to distinguish the uniforms and the
attributes just from their name.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 7aa99f5af7 gsk: Move resource handling inside GskGLDriver
We want the GL driver to cache as many resources as possible, so we can
always ensure that we're in a consistent state, and we can handle state
transitions more appropriately.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 5821b1de09 gsk: Simplify buffer handling in GskGLRenderer
We don't have optional stencil and depth buffers, like GtkGLArea: we
always create both of them internally.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 3aed149e43 gsk: Drop render buffer code path from GskGLRenderer
We always use texturing, to preserve the alpha channel when blitting the
frame buffer object on the window surface.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 5e978a94b4 gsk: Rework surface -> texture API
Drop the texture parameters handling from the texture creation, and
associate them with the contents upload. Also, rename the function to
something more in line with what it does.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 7b576bb94b gsk: Add GL driver API to create render targets
It's going to be used by the GL renderer to safely create and bind
FBOs when needed.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 60fb2af97d gsk: Turn texture cache into a hash table
We want to add the list of FBOs tied to a texture; this means we cannot
trivally copy the Texture structure when adding it to a GArray. We're
also going to have more textures than VAOs, so it makes more sense to
use a O(1) access data structure for them.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 7493fa4277 gsk: Add GL profiler
We can use the GL_ARB_timer_query extension (available since OpenGL
3.2, and part of the OpenGL specification since version 3.3) to query
the time elapsed when drawing each frame. This allows us to gather
timing information on our use of the GPU.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi c940cc8002 gsk: Split surface upload from texture creation
We're going to need a method to create textures without a surface.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 7eba4b5af5 gsk: Enable depth testing
Use the appropriate depth testing function for transparent items.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 1e4393ba7a gsk: Use consistent naming for blend fragment shader
This should make it immediately clear if we're doing something wrong.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 8b3e93b64f gsk: Fix pre-condition check
We warn if the node is marked as not mutable.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 962cb77026 gsk: Flip mutability on GskRenderNode.finalize
We use the public API when removing children nodes, so we need to mark
the node as mutable while we destroy it.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi abc543c792 gsk: Add specific debug type for shaders
So that we don't lose GskShaderBuilder debugging messages in the stream
of GskGLRenderer ones.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 8ea83eb998 gsk: Add GskGLDriver
We can move the caching and management of textures, VAOs, and state of
the GL machinery into a single object, GskGLDriver.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 32a3b4a43c gsk: Use the right pointer to the parent RenderItem
We copy the local RenderItem into the render items array, so we need to
use the copy in the array in order to get the correct reference.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi c071a2a818 Ensure that render nodes are translated
The clip rectangle may have non-zero offsets, so we need to ensure that
the GskRenderNode associated to the rendered area is translated by those
same offsets.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi c0f9ecbf4b 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-08-09 17:31:55 +01:00
Emmanuele Bassi 4484be9c7b 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-08-09 17:31:55 +01:00
Emmanuele Bassi 49661a7cf8 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-08-09 17:31:55 +01:00
Emmanuele Bassi 63d218e29c docs: Add more GSK documentation 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 5ffcdc0dde 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-08-09 17:31:55 +01:00
Emmanuele Bassi 713a1c5d1d 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-08-09 17:31:55 +01:00
Emmanuele Bassi 10e197c9c2 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-08-09 17:31:55 +01:00
Emmanuele Bassi fee200187a gsk: Add debugging notes to ShaderBuilder
Print out the generated shader and the list of available uniforms and
attributes.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi d417b1c73e 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-08-09 17:31:55 +01:00
Emmanuele Bassi b3d50a47a9 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-08-09 17:31:55 +01:00
Emmanuele Bassi 4611ced84d gsk: Add rendering debug mode for shaders
It's going to be useful to inject debugging data into the shaders used
by GSK.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi fbe43c4e5d gdk: Add more GDK_GL_ERROR error ids
We're going to use them in other locations.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 1b85794ac3 build: Fix dependency on GDK for introspection scanner
Otherwise libtool may attempt to use the installed copy of GDK.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 1f2b98ccf2 gsk: Use the node's blend mode in the GL renderer 2016-08-09 17:31:55 +01:00
Emmanuele Bassi f6fd57ea46 gsk: Store blend mode in the render node 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 3c07c2543d gsk: Make GskBlendMode enumeration public 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 71de0df96d gsk: Allow sampling between parent and child nodes 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 2148720651 gsk: Group render state attributes 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 9cce83cfc2 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-08-09 17:31:55 +01:00
Emmanuele Bassi 657bb588b7 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-08-09 17:31:55 +01:00
Emmanuele Bassi 6686b664cd gtk: Add a GskRenderer to GtkWindow
Each top-level should have its own GskRenderer, to be used when drawing
the render node tree.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 1ebafff76b 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-08-09 17:31:55 +01:00
Emmanuele Bassi b09441cf91 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-08-09 17:31:55 +01:00
Emmanuele Bassi ca97923bbd gsk: Add GskRenderer::clear_tree
We need a way to clear eventual caches inside GskRenderer subclasses if
the root node has changed.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi bc05963b9c gsk: Port GskGLRenderer to GLES
Use the appropriate API and shaders if the GdkGLContext was created for
OpenGL ES instead of OpenGL.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi 498f8852a1 gsk: Use surface-to-texture utility function
Now that we have it.
2016-08-09 17:31:55 +01:00
Emmanuele Bassi f15cb77d1c gsk: Rename shaders for OpenGL 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 979f059d62 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-08-09 17:31:55 +01:00
Emmanuele Bassi c462f3ef2e build: Add GSK deps to GTK 2016-08-09 17:31:55 +01:00
Emmanuele Bassi 49a061ce20 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-08-09 17:31:55 +01:00
Emmanuele Bassi ebc6509421 gsk: Initial commit / build environment 2016-08-09 17:31:55 +01:00
86 changed files with 8492 additions and 542 deletions
+3 -2
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}
@@ -45,7 +45,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}
@@ -62,6 +62,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 \
+27 -1
View File
@@ -64,6 +64,7 @@ m4_define([wayland_protocols_required_version], [1.5])
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
@@ -1932,6 +1955,8 @@ docs/Makefile
docs/reference/Makefile
docs/reference/gdk/Makefile
docs/reference/gdk/version.xml
docs/reference/gsk/Makefile
docs/reference/gsk/version.xml
docs/reference/gtk/Makefile
docs/reference/gtk/gtk3.types
docs/reference/gtk/version.xml
@@ -1957,6 +1982,7 @@ gdk/quartz/Makefile
gdk/wayland/Makefile
gdk/mir/Makefile
gdk/gdkversionmacros.h
gsk/Makefile
gtk/Makefile
gtk/makefile.msc
gtk/gtkversion.h
+1 -1
View File
@@ -1,7 +1,7 @@
## Process this file with automake to produce Makefile.in
include $(top_srcdir)/Makefile.decl
SUBDIRS = gdk gtk libgail-util
SUBDIRS = gdk gsk gtk libgail-util
GITIGNOREFILES = */*.1
+79
View File
@@ -0,0 +1,79 @@
## Process this file with automake to produce Makefile.in
AUTOMAKE_OPTIONS = 1.6
# The name of the module.
DOC_MODULE = gsk3
# The top-level SGML file.
DOC_MAIN_SGML_FILE = gsk-docs.xml
# Extra options to supply to gtkdoc-scan
SCAN_OPTIONS = --deprecated-guards=GDK_DISABLE_DEPRECATED \
--ignore-decorators=G_GNUC_WARN_UNUSED_RESULT
# The directory containing the source code. Relative to $(srcdir)
DOC_SOURCE_DIR = $(top_srcdir)/gsk
# Used for dependencies
HFILE_GLOB = $(top_srcdir)/gsk/*.h
CFILE_GLOB = $(top_srcdir)/gsk/*.c
# Header files to ignore when scanning
IGNORE_HFILES = \
gskcairorendererprivate.h \
gskdebugprivate.h \
gskdriverprivate.h \
gskprofilerprivate.h \
gskglrendererprivate.h \
gskprivate.h \
gskprofilerprivate.h \
gskrendererprivate.h \
gskrendernodeprivate.h \
gskshaderbiulderprivate.h
# Extra files to add when scanning
EXTRA_HFILES =
# CFLAGS and LDFLAGS for compiling scan program. Only needed
# if $(DOC_MODULE).types is non-empty.
AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_builddir) \
-I$(top_builddir)/gsk \
$(GTK_DEBUG_FLAGS) \
$(GDK_DEP_CFLAGS)
GTKDOC_LIBS = $(top_builddir)/gsk/libgsk-3.la $(GDK_DEP_LIBS)
# Extra options to supply to gtkdoc-mkdb
MKDB_OPTIONS=--output-format=xml --name-space=gsk
# Extra SGML files that are included by DOC_MAIN_SGML_FILE
content_files = \
version.xml
# Images to copy into HTML directory
HTML_IMAGES =
if ENABLE_DOC_CROSS_REFERENCES
# Extra options to supply to gtkdoc-fixref
FIXXREF_OPTIONS= \
--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gobject \
--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \
--extra-dir=$(CAIRO_PREFIX)/share/gtk-doc/html/cairo
endif
include $(top_srcdir)/gtk-doc.make
# Other files to distribute
EXTRA_DIST += version.xml.in
if ENABLE_GTK_DOC
TESTS_ENVIRONMENT = cd $(srcdir) && \
DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
#TESTS = $(GTKDOC_CHECK)
endif
-include $(top_srcdir)/git.mk
+29
View File
@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
<!ENTITY version SYSTEM "version.xml">
]>
<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
<bookinfo>
<title>GSK 3 Reference Manual</title>
<releaseinfo>
This document is for the GSK 3 library, version &version;
The latest versions can be found online at
<ulink role="online-location" url="http://developer.gnome.org/gdk3/">http://developer.gnome.org/gsk3/</ulink>.
</releaseinfo>
</bookinfo>
<reference id="reference">
<title>API Reference</title>
<xi:include href="xml/GskRenderer.xml" />
<xi:include href="xml/GskRenderNode.xml" />
<xi:include href="xml/GskRenderNodeIter.xml" />
</reference>
<index id="api-index-full">
<title>Index of all symbols</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
</book>
+97
View File
@@ -0,0 +1,97 @@
<SECTION>
<FILE>GskRenderer</FILE>
gsk_renderer_get_for_display
gsk_renderer_set_viewport
gsk_renderer_get_viewport
gsk_renderer_set_projection
gsk_renderer_get_projection
gsk_renderer_set_modelview
gsk_renderer_get_modelview
GskScalingFilter
gsk_renderer_set_scaling_filters
gsk_renderer_get_scaling_filters
gsk_renderer_set_scale_factor
gsk_renderer_get_scale_factor
gsk_renderer_set_auto_clear
gsk_renderer_get_auto_clear
gsk_renderer_set_use_alpha
gsk_renderer_get_use_alpha
gsk_renderer_set_window
gsk_renderer_get_window
gsk_renderer_get_display
gsk_renderer_realize
gsk_renderer_unrealize
gsk_renderer_create_render_node
gsk_renderer_render
<SUBSECTION Standard>
GSK_IS_RENDERER
GSK_RENDERER
GSK_TYPE_RENDERER
GskRenderer
GskRendererClass
gsk_renderer_get_type
GSK_TYPE_SCALING_FILTER
</SECTION>
<SECTION>
<FILE>GskRenderNode</FILE>
gsk_render_node_ref
gsk_render_node_unref
gsk_render_node_get_parent
gsk_render_node_get_first_child
gsk_render_node_get_last_child
gsk_render_node_get_next_sibling
gsk_render_node_get_previous_sibling
gsk_render_node_append_child
gsk_render_node_prepend_child
gsk_render_node_insert_child_at_pos
gsk_render_node_insert_child_before
gsk_render_node_insert_child_after
gsk_render_node_remove_child
gsk_render_node_replace_child
gsk_render_node_remove_all_children
gsk_render_node_get_n_children
gsk_render_node_contains
gsk_render_node_set_bounds
gsk_render_node_set_transform
gsk_render_node_set_anchor_point
gsk_render_node_set_opacity
gsk_render_node_set_hidden
gsk_render_node_is_hidden
gsk_render_node_set_opaque
gsk_render_node_is_opaque
gsk_render_node_get_draw_context
GskBlendMode
gsk_render_node_set_blend_mode
gsk_render_node_get_blend_mode
gsk_render_node_get_scale_factor
gsk_render_node_set_name
gsk_value_set_render_node
gsk_value_take_render_node
gsk_value_get_render_node
gsk_value_dup_render_node
<SUBSECTION Standard>
GSK_IS_RENDER_NODE
GSK_RENDER_NODE
GSK_TYPE_RENDER_NODE
GSK_VALUE_HOLDS_RENDER_NODE
GskRenderNode
GskRenderNodeClass
gsk_render_node_get_type
GSK_TYPE_BLEND_MODE
</SECTION>
<SECTION>
<FILE>GskRenderNodeIter</FILE>
gsk_render_node_iter_new
gsk_render_node_iter_free
gsk_render_node_iter_init
gsk_render_node_iter_is_valid
gsk_render_node_iter_prev
gsk_render_node_iter_next
gsk_render_node_iter_remove
<SUBSECTION Standard>
GSK_TYPE_RENDER_NODE_ITER
GskRenderNodeIter
gsk_render_node_iter_get_type
</SECTION>
+3
View File
@@ -0,0 +1,3 @@
gsk_render_node_get_type
gsk_render_node_iter_get_type
gsk_renderer_get_type
+1
View File
@@ -0,0 +1 @@
@GTK_VERSION@
+7
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__ */
+45
View File
@@ -814,3 +814,48 @@ 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 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);
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;
rect.height = height;
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);
}
+5 -1
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
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@
+163
View File
@@ -0,0 +1,163 @@
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 \
gskrenderer.h \
gskrendernode.h \
gskrendernodeiter.h \
gsktypes.h
gsk_private_source_h = \
gskcairorendererprivate.h \
gskdebugprivate.h \
gskgldriverprivate.h \
gskglprofilerprivate.h \
gskglrendererprivate.h \
gskprivate.h \
gskprofilerprivate.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 \
gskgldriver.c \
gskglprofiler.c \
gskglrenderer.c \
gskprofiler.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
+33
View File
@@ -0,0 +1,33 @@
/* 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/gskenums.h>
#include <gsk/gskrenderer.h>
#include <gsk/gskrendernode.h>
#include <gsk/gskrendernodeiter.h>
#include <gsk/gsktypes.h>
#include <gsk/gskenumtypes.h>
#undef __GSK_H_INSIDE__
#endif /* __GSK_H__ */
+177
View File
@@ -0,0 +1,177 @@
#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);
cairo_set_source_rgba (cr, 0, 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)
{
}
+26
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__ */
+62
View File
@@ -0,0 +1,62 @@
#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 },
{ "shaders", GSK_DEBUG_SHADERS },
{ "transforms", GSK_DEBUG_TRANSFORMS },
{ "surface", GSK_DEBUG_SURFACE }
};
#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;
}
+54
View File
@@ -0,0 +1,54 @@
#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,
GSK_DEBUG_SHADERS = 1 << 4,
GSK_DEBUG_TRANSFORMS = 1 << 5,
GSK_DEBUG_SURFACE = 1 << 6
} 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_DEBUG_CHECK2(type1,type2) G_UNLIKELY (gsk_check_debug_flags (GSK_DEBUG_ ## type1 | GSK_DEBUG_ ## type2))
#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
#define GSK_NOTE2(type1,type2,action) G_STMT_START { \
if (GSK_DEBUG_CHECK2 (type1, type2)) { \
action; \
} } G_STMT_END
#else
#define GSK_RENDER_MODE_CHECK(type) 0
#define GSK_DEBUG_CHECK(type) 0
#define GSK_DEBUG_CHECK2(type1,type2) 0
#define GSK_NOTE(type,action)
#define GSK_NOTE2(type1,type2,action)
#endif
G_END_DECLS
#endif /* __GSK_DEBUG_PRIVATE_H__ */
+85
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__ */
+38
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 ***/
+24
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 ***/
+751
View File
@@ -0,0 +1,751 @@
#include "config.h"
#include "gskgldriverprivate.h"
#include "gskdebugprivate.h"
#include <gdk/gdk.h>
#include <epoxy/gl.h>
typedef struct {
GLuint texture_id;
int width;
int height;
GLuint min_filter;
GLuint mag_filter;
GArray *fbos;
gboolean in_use : 1;
} Texture;
typedef struct {
GLuint vao_id;
GLuint buffer_id;
GLuint position_id;
GLuint uv_id;
GskQuadVertex *quads;
int n_quads;
gboolean in_use : 1;
} Vao;
typedef struct {
GLuint fbo_id;
GLuint depth_stencil_id;
} Fbo;
struct _GskGLDriver
{
GObject parent_instance;
GdkGLContext *gl_context;
Fbo default_fbo;
GHashTable *textures;
GHashTable *vaos;
Texture *bound_source_texture;
Texture *bound_mask_texture;
Vao *bound_vao;
Fbo *bound_fbo;
gboolean in_frame : 1;
};
enum
{
PROP_GL_CONTEXT = 1,
N_PROPS
};
static GParamSpec *gsk_gl_driver_properties[N_PROPS];
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
static Texture *
texture_new (void)
{
return g_slice_new0 (Texture);
}
static void
texture_free (gpointer data)
{
Texture *t = data;
g_clear_pointer (&t->fbos, g_array_unref);
glDeleteTextures (1, &t->texture_id);
g_slice_free (Texture, t);
}
static void
fbo_clear (gpointer data)
{
Fbo *f = data;
if (f->depth_stencil_id != 0)
glDeleteRenderbuffers (1, &f->depth_stencil_id);
glDeleteFramebuffers (1, &f->fbo_id);
}
static Vao *
vao_new (void)
{
return g_slice_new0 (Vao);
}
static void
vao_free (gpointer data)
{
Vao *v = data;
g_free (v->quads);
glDeleteBuffers (1, &v->buffer_id);
glDeleteVertexArrays (1, &v->vao_id);
g_slice_free (Vao, v);
}
static void
gsk_gl_driver_finalize (GObject *gobject)
{
GskGLDriver *self = GSK_GL_DRIVER (gobject);
gdk_gl_context_make_current (self->gl_context);
g_clear_pointer (&self->textures, g_hash_table_unref);
g_clear_pointer (&self->vaos, g_hash_table_unref);
if (self->gl_context == gdk_gl_context_get_current ())
gdk_gl_context_clear_current ();
g_clear_object (&self->gl_context);
G_OBJECT_CLASS (gsk_gl_driver_parent_class)->finalize (gobject);
}
static void
gsk_gl_driver_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GskGLDriver *self = GSK_GL_DRIVER (gobject);
switch (prop_id)
{
case PROP_GL_CONTEXT:
self->gl_context = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
gsk_gl_driver_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GskGLDriver *self = GSK_GL_DRIVER (gobject);
switch (prop_id)
{
case PROP_GL_CONTEXT:
g_value_set_object (value, self->gl_context);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
gsk_gl_driver_class_init (GskGLDriverClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = gsk_gl_driver_set_property;
gobject_class->get_property = gsk_gl_driver_get_property;
gobject_class->finalize = gsk_gl_driver_finalize;
gsk_gl_driver_properties[PROP_GL_CONTEXT] =
g_param_spec_object ("gl-context", "GL Context", "The GL context used by the driver",
GDK_TYPE_GL_CONTEXT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, gsk_gl_driver_properties);
}
static void
gsk_gl_driver_init (GskGLDriver *self)
{
self->textures = g_hash_table_new_full (NULL, NULL, NULL, texture_free);
self->vaos = g_hash_table_new_full (NULL, NULL, NULL, vao_free);
}
GskGLDriver *
gsk_gl_driver_new (GdkGLContext *context)
{
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
return g_object_new (GSK_TYPE_GL_DRIVER,
"gl-context", context,
NULL);
}
void
gsk_gl_driver_begin_frame (GskGLDriver *driver)
{
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
g_return_if_fail (!driver->in_frame);
driver->in_frame = TRUE;
glGetIntegerv (GL_FRAMEBUFFER_BINDING, (GLint *) &(driver->default_fbo.fbo_id));
driver->bound_fbo = &driver->default_fbo;
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, 0);
glActiveTexture (GL_TEXTURE0 + 1);
glBindTexture (GL_TEXTURE_2D, 0);
glBindVertexArray (0);
glUseProgram (0);
glActiveTexture (GL_TEXTURE0);
}
void
gsk_gl_driver_end_frame (GskGLDriver *driver)
{
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
g_return_if_fail (driver->in_frame);
glBindTexture (GL_TEXTURE_2D, 0);
glUseProgram (0);
glBindVertexArray (0);
driver->bound_source_texture = NULL;
driver->bound_mask_texture = NULL;
driver->bound_vao = NULL;
driver->bound_fbo = NULL;
GSK_NOTE (OPENGL,
g_print ("*** Frame end: textures=%d, vaos=%d\n",
g_hash_table_size (driver->textures),
g_hash_table_size (driver->vaos)));
driver->in_frame = FALSE;
}
int
gsk_gl_driver_collect_textures (GskGLDriver *driver)
{
GHashTableIter iter;
gpointer value_p = NULL;
int old_size;
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), 0);
g_return_val_if_fail (!driver->in_frame, 0);
old_size = g_hash_table_size (driver->textures);
g_hash_table_iter_init (&iter, driver->textures);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
Texture *t = value_p;
if (t->in_use)
{
t->in_use = FALSE;
g_clear_pointer (&t->fbos, g_array_unref);
}
else
g_hash_table_iter_remove (&iter);
}
return old_size - g_hash_table_size (driver->textures);
}
int
gsk_gl_driver_collect_vaos (GskGLDriver *driver)
{
GHashTableIter iter;
gpointer value_p = NULL;
int old_size;
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), 0);
g_return_val_if_fail (!driver->in_frame, 0);
old_size = g_hash_table_size (driver->vaos);
g_hash_table_iter_init (&iter, driver->vaos);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
Vao *v = value_p;
if (v->in_use)
v->in_use = FALSE;
else
g_hash_table_iter_remove (&iter);
}
return old_size - g_hash_table_size (driver->vaos);
}
static Texture *
gsk_gl_driver_get_texture (GskGLDriver *driver,
int texture_id)
{
Texture *t;
if (g_hash_table_lookup_extended (driver->textures, GINT_TO_POINTER (texture_id), NULL, (gpointer *) &t))
return t;
return NULL;
}
static Vao *
gsk_gl_driver_get_vao (GskGLDriver *driver,
int vao_id)
{
Vao *v;
if (g_hash_table_lookup_extended (driver->vaos, GINT_TO_POINTER (vao_id), NULL, (gpointer *) &v))
return v;
return NULL;
}
static Fbo *
gsk_gl_driver_get_fbo (GskGLDriver *driver,
int texture_id)
{
Texture *t = gsk_gl_driver_get_texture (driver, texture_id);
if (t->fbos == NULL)
return &driver->default_fbo;
return &g_array_index (t->fbos, Fbo, 0);
}
static Texture *
find_texture_by_size (GHashTable *textures,
int width,
int height)
{
GHashTableIter iter;
gpointer value_p = NULL;
g_hash_table_iter_init (&iter, textures);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
Texture *t = value_p;
if (t->width == width && t->height == height)
return t;
}
return NULL;
}
int
gsk_gl_driver_create_texture (GskGLDriver *driver,
int width,
int height)
{
guint texture_id;
Texture *t;
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
t = find_texture_by_size (driver->textures, width, height);
if (t != NULL && !t->in_use)
{
GSK_NOTE (OPENGL, g_print ("Reusing Texture(%d) for size %dx%d\n",
t->texture_id, t->width, t->height));
t->in_use = TRUE;
return t->texture_id;
}
glGenTextures (1, &texture_id);
t = texture_new ();
t->texture_id = texture_id;
t->width = width;
t->height = height;
t->min_filter = GL_NEAREST;
t->mag_filter = GL_NEAREST;
t->in_use = TRUE;
g_hash_table_insert (driver->textures, GINT_TO_POINTER (texture_id), t);
return t->texture_id;
}
static Vao *
find_vao (GHashTable *vaos,
int position_id,
int uv_id,
int n_quads,
GskQuadVertex *quads)
{
GHashTableIter iter;
gpointer value_p = NULL;
g_hash_table_iter_init (&iter, vaos);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
Vao *v = value_p;
if (v->position_id != position_id || v->uv_id != uv_id)
continue;
if (v->n_quads != n_quads)
continue;
if (memcmp (v->quads, quads, sizeof (GskQuadVertex) * n_quads) == 0)
return v;
}
return NULL;
}
int
gsk_gl_driver_create_vao_for_quad (GskGLDriver *driver,
int position_id,
int uv_id,
int n_quads,
GskQuadVertex *quads)
{
GLuint vao_id, buffer_id;
Vao *v;
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
g_return_val_if_fail (driver->in_frame, -1);
v = find_vao (driver->vaos, position_id, uv_id, n_quads, quads);
if (v != NULL && !v->in_use)
{
GSK_NOTE (OPENGL, g_print ("Reusing VAO(%d)\n", v->vao_id));
v->in_use = TRUE;
return v->vao_id;
}
glGenVertexArrays (1, &vao_id);
glBindVertexArray (vao_id);
glGenBuffers (1, &buffer_id);
glBindBuffer (GL_ARRAY_BUFFER, buffer_id);
glBufferData (GL_ARRAY_BUFFER, sizeof (GskQuadVertex) * n_quads, quads, GL_STATIC_DRAW);
glEnableVertexAttribArray (position_id);
glVertexAttribPointer (position_id, 2, GL_FLOAT, GL_FALSE,
sizeof (GskQuadVertex),
(void *) G_STRUCT_OFFSET (GskQuadVertex, position));
glEnableVertexAttribArray (uv_id);
glVertexAttribPointer (uv_id, 2, GL_FLOAT, GL_FALSE,
sizeof (GskQuadVertex),
(void *) G_STRUCT_OFFSET (GskQuadVertex, uv));
glBindBuffer (GL_ARRAY_BUFFER, 0);
glBindVertexArray (0);
v = vao_new ();
v->vao_id = vao_id;
v->buffer_id = buffer_id;
v->position_id = position_id;
v->uv_id = uv_id;
v->n_quads = n_quads;
v->quads = g_memdup (quads, sizeof (GskQuadVertex) * n_quads);
v->in_use = TRUE;
g_hash_table_insert (driver->vaos, GINT_TO_POINTER (vao_id), v);
#ifdef G_ENABLE_DEBUG
if (GSK_DEBUG_CHECK (OPENGL))
{
int i;
g_print ("New VAO(%d) for quad[%d] : {\n", v->vao_id, n_quads);
for (i = 0; i < n_quads; i++)
{
g_print (" { x:%.2f, y:%.2f } { u:%.2f, v:%.2f }\n",
quads[i].position[0], quads[i].position[1],
quads[i].uv[0], quads[i].uv[1]);
}
g_print ("}\n");
}
#endif
return vao_id;
}
int
gsk_gl_driver_create_render_target (GskGLDriver *driver,
int texture_id,
gboolean add_depth_buffer,
gboolean add_stencil_buffer)
{
GLuint fbo_id, depth_stencil_buffer_id;
Texture *t;
Fbo f;
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), -1);
g_return_val_if_fail (driver->in_frame, -1);
t = gsk_gl_driver_get_texture (driver, texture_id);
if (t == NULL)
return -1;
if (t->fbos == NULL)
{
t->fbos = g_array_new (FALSE, FALSE, sizeof (Fbo));
g_array_set_clear_func (t->fbos, fbo_clear);
}
glGenFramebuffers (1, &fbo_id);
glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, t->texture_id, 0);
if (add_depth_buffer || add_stencil_buffer)
glGenRenderbuffersEXT (1, &depth_stencil_buffer_id);
else
depth_stencil_buffer_id = 0;
glBindRenderbuffer (GL_RENDERBUFFER, depth_stencil_buffer_id);
if (add_depth_buffer || add_stencil_buffer)
{
if (add_stencil_buffer)
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, t->width, t->height);
else
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, t->width, t->height);
if (add_depth_buffer)
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_buffer_id);
if (add_stencil_buffer)
glFramebufferRenderbufferEXT (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_buffer_id);
}
f.fbo_id = fbo_id;
f.depth_stencil_id = depth_stencil_buffer_id;
g_array_append_val (t->fbos, f);
glBindFramebuffer (GL_FRAMEBUFFER, driver->default_fbo.fbo_id);
return fbo_id;
}
void
gsk_gl_driver_bind_source_texture (GskGLDriver *driver,
int texture_id)
{
Texture *t;
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
g_return_if_fail (driver->in_frame);
t = gsk_gl_driver_get_texture (driver, texture_id);
if (t == NULL)
{
g_critical ("No texture %d found.", texture_id);
return;
}
if (driver->bound_source_texture != t)
{
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, t->texture_id);
driver->bound_source_texture = t;
}
}
void
gsk_gl_driver_bind_mask_texture (GskGLDriver *driver,
int texture_id)
{
Texture *t;
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
g_return_if_fail (driver->in_frame);
t = gsk_gl_driver_get_texture (driver, texture_id);
if (t == NULL)
{
g_critical ("No texture %d found.", texture_id);
return;
}
if (driver->bound_mask_texture != t)
{
glActiveTexture (GL_TEXTURE0 + 1);
glBindTexture (GL_TEXTURE_2D, t->texture_id);
glActiveTexture (GL_TEXTURE0);
driver->bound_mask_texture = t;
}
}
void
gsk_gl_driver_bind_vao (GskGLDriver *driver,
int vao_id)
{
Vao *v;
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
g_return_if_fail (driver->in_frame);
v = gsk_gl_driver_get_vao (driver, vao_id);
if (v == NULL)
{
g_critical ("No VAO %d found.", vao_id);
return;
}
if (driver->bound_vao != v)
{
glBindVertexArray (v->vao_id);
glBindBuffer (GL_ARRAY_BUFFER, v->buffer_id);
glEnableVertexAttribArray (v->position_id);
glEnableVertexAttribArray (v->uv_id);
driver->bound_vao = v;
}
}
gboolean
gsk_gl_driver_bind_render_target (GskGLDriver *driver,
int texture_id)
{
int status;
Fbo *f;
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), FALSE);
g_return_val_if_fail (driver->in_frame, FALSE);
f = gsk_gl_driver_get_fbo (driver, texture_id);
if (f == NULL)
{
g_critical ("No render target associated to texture %d found.", texture_id);
return FALSE;
}
if (f != driver->bound_fbo)
{
glBindFramebuffer (GL_FRAMEBUFFER, f->fbo_id);
driver->bound_fbo = f;
}
status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
return status == GL_FRAMEBUFFER_COMPLETE;
}
void
gsk_gl_driver_destroy_texture (GskGLDriver *driver,
int texture_id)
{
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
g_hash_table_remove (driver->textures, GINT_TO_POINTER (texture_id));
}
void
gsk_gl_driver_destroy_vao (GskGLDriver *driver,
int vao_id)
{
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
g_hash_table_remove (driver->vaos, GINT_TO_POINTER (vao_id));
}
static void
gsk_gl_driver_set_texture_parameters (GskGLDriver *driver,
int min_filter,
int mag_filter)
{
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
void
gsk_gl_driver_init_texture_empty (GskGLDriver *driver,
int texture_id)
{
Texture *t;
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
t = gsk_gl_driver_get_texture (driver, texture_id);
if (t == NULL)
{
g_critical ("No texture %d found.", texture_id);
return;
}
if (!(driver->bound_source_texture == t || driver->bound_mask_texture == t))
{
g_critical ("You must bind the texture before initializing it.");
return;
}
gsk_gl_driver_set_texture_parameters (driver, t->min_filter, t->mag_filter);
if (gdk_gl_context_get_use_es (driver->gl_context))
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture (GL_TEXTURE_2D, 0);
}
void
gsk_gl_driver_init_texture_with_surface (GskGLDriver *driver,
int texture_id,
cairo_surface_t *surface,
int min_filter,
int mag_filter)
{
Texture *t;
g_return_if_fail (GSK_IS_GL_DRIVER (driver));
t = gsk_gl_driver_get_texture (driver, texture_id);
if (t == NULL)
{
g_critical ("No texture %d found.", texture_id);
return;
}
if (!(driver->bound_source_texture == t || driver->bound_mask_texture == t))
{
g_critical ("You must bind the texture before initializing it.");
return;
}
gsk_gl_driver_set_texture_parameters (driver, min_filter, mag_filter);
gdk_cairo_surface_upload_to_gl (surface, GL_TEXTURE_2D, t->width, t->height, NULL);
t->min_filter = min_filter;
t->mag_filter = mag_filter;
if (t->min_filter != GL_NEAREST)
glGenerateMipmap (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, 0);
}
+64
View File
@@ -0,0 +1,64 @@
#ifndef __GSK_GL_DRIVER_PRIVATE_H__
#define __GSK_GL_DRIVER_PRIVATE_H__
#include <cairo.h>
#include <gdk/gdk.h>
#include <graphene.h>
G_BEGIN_DECLS
#define GSK_TYPE_GL_DRIVER (gsk_gl_driver_get_type ())
G_DECLARE_FINAL_TYPE (GskGLDriver, gsk_gl_driver, GSK, GL_DRIVER, GObject)
typedef struct {
float position[2];
float uv[2];
} GskQuadVertex;
GskGLDriver * gsk_gl_driver_new (GdkGLContext *context);
void gsk_gl_driver_begin_frame (GskGLDriver *driver);
void gsk_gl_driver_end_frame (GskGLDriver *driver);
int gsk_gl_driver_create_texture (GskGLDriver *driver,
int width,
int height);
int gsk_gl_driver_create_vao_for_quad (GskGLDriver *driver,
int position_id,
int uv_id,
int n_vertices,
GskQuadVertex *vertices);
int gsk_gl_driver_create_render_target (GskGLDriver *driver,
int texture_id,
gboolean add_depth_buffer,
gboolean add_stencil_buffer);
void gsk_gl_driver_bind_source_texture (GskGLDriver *driver,
int texture_id);
void gsk_gl_driver_bind_mask_texture (GskGLDriver *driver,
int texture_id);
void gsk_gl_driver_bind_vao (GskGLDriver *driver,
int vao_id);
gboolean gsk_gl_driver_bind_render_target (GskGLDriver *driver,
int texture_id);
void gsk_gl_driver_init_texture_empty (GskGLDriver *driver,
int texture_id);
void gsk_gl_driver_init_texture_with_surface (GskGLDriver *driver,
int texture_id,
cairo_surface_t *surface,
int min_filter,
int mag_filter);
void gsk_gl_driver_destroy_texture (GskGLDriver *driver,
int texture_id);
void gsk_gl_driver_destroy_vao (GskGLDriver *driver,
int vao_id);
int gsk_gl_driver_collect_textures (GskGLDriver *driver);
int gsk_gl_driver_collect_vaos (GskGLDriver *driver);
G_END_DECLS
#endif /* __GSK_GL_DRIVER_PRIVATE_H__ */
+175
View File
@@ -0,0 +1,175 @@
#include "config.h"
#include "gskglprofilerprivate.h"
#include <epoxy/gl.h>
#define N_QUERIES 4
struct _GskGLProfiler
{
GObject parent_instance;
GdkGLContext *gl_context;
/* Creating GL queries is kind of expensive, so we pay the
* price upfront and create a circular buffer of queries
*/
GLuint gl_queries[N_QUERIES];
GLuint active_query;
gboolean has_timer : 1;
gboolean first_frame : 1;
};
enum {
PROP_GL_CONTEXT = 1,
N_PROPERTIES
};
static GParamSpec *gsk_gl_profiler_properties[N_PROPERTIES];
G_DEFINE_TYPE (GskGLProfiler, gsk_gl_profiler, G_TYPE_OBJECT)
static void
gsk_gl_profiler_finalize (GObject *gobject)
{
GskGLProfiler *self = GSK_GL_PROFILER (gobject);
glDeleteQueries (N_QUERIES, self->gl_queries);
g_clear_object (&self->gl_context);
G_OBJECT_CLASS (gsk_gl_profiler_parent_class)->finalize (gobject);
}
static void
gsk_gl_profiler_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GskGLProfiler *self = GSK_GL_PROFILER (gobject);
switch (prop_id)
{
case PROP_GL_CONTEXT:
self->gl_context = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
gsk_gl_profiler_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GskGLProfiler *self = GSK_GL_PROFILER (gobject);
switch (prop_id)
{
case PROP_GL_CONTEXT:
g_value_set_object (value, self->gl_context);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
}
static void
gsk_gl_profiler_class_init (GskGLProfilerClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = gsk_gl_profiler_set_property;
gobject_class->get_property = gsk_gl_profiler_get_property;
gobject_class->finalize = gsk_gl_profiler_finalize;
gsk_gl_profiler_properties[PROP_GL_CONTEXT] =
g_param_spec_object ("gl-context",
"GL Context",
"The GdkGLContext used by the GL profiler",
GDK_TYPE_GL_CONTEXT,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPERTIES, gsk_gl_profiler_properties);
}
static void
gsk_gl_profiler_init (GskGLProfiler *self)
{
glGenQueries (N_QUERIES, self->gl_queries);
self->first_frame = TRUE;
self->has_timer = epoxy_has_gl_extension ("GL_ARB_timer_query");
}
GskGLProfiler *
gsk_gl_profiler_new (GdkGLContext *context)
{
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
return g_object_new (GSK_TYPE_GL_PROFILER, "gl-context", context, NULL);
}
void
gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler)
{
GLuint query_id;
g_return_if_fail (GSK_IS_GL_PROFILER (profiler));
if (!profiler->has_timer)
return;
query_id = profiler->gl_queries[profiler->active_query];
glBeginQuery (GL_TIME_ELAPSED, query_id);
}
guint64
gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler)
{
GLuint last_query_id;
GLint res;
GLuint64 elapsed;
g_return_val_if_fail (GSK_IS_GL_PROFILER (profiler), 0);
if (!profiler->has_timer)
return 0;
glEndQuery (GL_TIME_ELAPSED);
if (profiler->active_query == 0)
last_query_id = N_QUERIES - 1;
else
last_query_id = profiler->active_query - 1;
/* Advance iterator */
profiler->active_query += 1;
if (profiler->active_query == N_QUERIES)
profiler->active_query = 0;
/* If this is the first frame we already have a result */
if (profiler->first_frame)
{
profiler->first_frame = FALSE;
return 0;
}
glGetQueryObjectiv (profiler->gl_queries[last_query_id], GL_QUERY_RESULT_AVAILABLE, &res);
if (res == 1)
glGetQueryObjectui64v (profiler->gl_queries[last_query_id], GL_QUERY_RESULT, &elapsed);
else
elapsed = 0;
return elapsed;
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef __GSK_GL_PROFILER_PRIVATE_H__
#define __GSK_GL_PROFILER_PRIVATE_H__
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
#define GSK_TYPE_GL_PROFILER (gsk_gl_profiler_get_type ())
G_DECLARE_FINAL_TYPE (GskGLProfiler, gsk_gl_profiler, GSK, GL_PROFILER, GObject)
GskGLProfiler * gsk_gl_profiler_new (GdkGLContext *context);
void gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler);
guint64 gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler);
G_END_DECLS
#endif /* __GSK_GL_PROFILER_PRIVATE_H__ */
+961
View File
@@ -0,0 +1,961 @@
#include "config.h"
#include "gskglrendererprivate.h"
#include "gskdebugprivate.h"
#include "gskenums.h"
#include "gskgldriverprivate.h"
#include "gskglprofilerprivate.h"
#include "gskprofilerprivate.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 {
int render_target_id;
int vao_id;
int buffer_id;
int texture_id;
int program_id;
int mvp_location;
int source_location;
int mask_location;
int uv_location;
int position_location;
int alpha_location;
int 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;
GArray *children;
} RenderItem;
enum {
MVP,
SOURCE,
MASK,
ALPHA,
BLEND_MODE,
N_UNIFORMS
};
enum {
POSITION,
UV,
N_ATTRIBUTES
};
#ifdef G_ENABLE_DEBUG
typedef struct {
GQuark frames;
GQuark draw_calls;
} ProfileCounters;
typedef struct {
GQuark cpu_time;
GQuark gpu_time;
} ProfileTimers;
#endif
struct _GskGLRenderer
{
GskRenderer parent_instance;
graphene_matrix_t mvp;
graphene_frustum_t frustum;
guint frame_buffer;
guint depth_stencil_buffer;
guint texture_id;
GQuark uniforms[N_UNIFORMS];
GQuark attributes[N_ATTRIBUTES];
GdkGLContext *gl_context;
GskGLDriver *gl_driver;
GskGLProfiler *gl_profiler;
GskShaderBuilder *shader_builder;
int blend_program_id;
int blit_program_id;
GArray *render_items;
#ifdef G_ENABLE_DEBUG
ProfileCounters profile_counters;
ProfileTimers profile_timers;
#endif
gboolean has_buffers : 1;
};
struct _GskGLRendererClass
{
GskRendererClass parent_class;
};
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->gl_context);
G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (gobject);
}
static void
gsk_gl_renderer_create_buffers (GskGLRenderer *self,
int width,
int height,
int scale_factor)
{
if (self->has_buffers)
return;
GSK_NOTE (OPENGL, g_print ("Creating buffers (w:%d, h:%d, scale:%d)\n", width, height, scale_factor));
if (self->texture_id == 0)
{
self->texture_id = gsk_gl_driver_create_texture (self->gl_driver,
width * scale_factor,
height * scale_factor);
gsk_gl_driver_bind_source_texture (self->gl_driver, self->texture_id);
gsk_gl_driver_init_texture_empty (self->gl_driver, self->texture_id);
}
gsk_gl_driver_create_render_target (self->gl_driver, self->texture_id, TRUE, TRUE);
self->has_buffers = TRUE;
}
static void
gsk_gl_renderer_destroy_buffers (GskGLRenderer *self)
{
if (self->gl_context == NULL)
return;
if (!self->has_buffers)
return;
GSK_NOTE (OPENGL, g_print ("Destroying buffers\n"));
gdk_gl_context_make_current (self->gl_context);
if (self->texture_id != 0)
{
gsk_gl_driver_destroy_texture (self->gl_driver, self->texture_id);
self->texture_id = 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, "uMVP");
self->uniforms[SOURCE] = gsk_shader_builder_add_uniform (builder, "uSource");
self->uniforms[MASK] = gsk_shader_builder_add_uniform (builder, "uMask");
self->uniforms[ALPHA] = gsk_shader_builder_add_uniform (builder, "uAlpha");
self->uniforms[BLEND_MODE] = gsk_shader_builder_add_uniform (builder, "uBlendMode");
self->attributes[POSITION] = gsk_shader_builder_add_attribute (builder, "aPosition");
self->attributes[UV] = gsk_shader_builder_add_attribute (builder, "aUv");
if (gdk_gl_context_get_use_es (self->gl_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->gl_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->gl_context == NULL)
{
GdkWindow *window = gsk_renderer_get_window (renderer);
if (window == NULL)
return FALSE;
self->gl_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->gl_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->gl_context);
g_assert (self->gl_driver == NULL);
self->gl_driver = gsk_gl_driver_new (self->gl_context);
self->gl_profiler = gsk_gl_profiler_new (self->gl_context);
GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
if (!gsk_gl_renderer_create_programs (self))
return FALSE;
return TRUE;
}
static void
gsk_gl_renderer_unrealize (GskRenderer *renderer)
{
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
if (self->gl_context == NULL)
return;
gdk_gl_context_make_current (self->gl_context);
/* We don't need to iterate to destroy the associated GL resources,
* as they will be dropped when we finalize the GskGLDriver
*/
g_clear_pointer (&self->render_items, g_array_unref);
gsk_gl_renderer_destroy_buffers (self);
gsk_gl_renderer_destroy_programs (self);
g_clear_object (&self->gl_profiler);
g_clear_object (&self->gl_driver);
if (self->gl_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,
int scale_factor)
{
int width = viewport->size.width * scale_factor;
int height = viewport->size.height * scale_factor;
GSK_NOTE (OPENGL, g_print ("glViewport(0, 0, %d, %d) [scale:%d]\n",
width,
height,
scale_factor));
glViewport (0, 0, width, height);
}
static void
gsk_gl_renderer_update_frustum (GskGLRenderer *self,
const graphene_matrix_t *modelview,
const graphene_matrix_t *projection)
{
GSK_NOTE (TRANSFORMS, g_print ("Updating the modelview/projection\n"));
graphene_matrix_multiply (modelview, projection, &self->mvp);
graphene_frustum_init_from_matrix (&self->frustum, &self->mvp);
GSK_NOTE (TRANSFORMS,
g_print ("Renderer MVP:\n");
graphene_matrix_print (&self->mvp);
g_print ("\n"));
}
#define N_VERTICES 6
static inline int
node_depth (GskRenderNode *node)
{
int ret = 0;
while (node->parent)
{
ret++;
node = node->parent;
}
return ret;
}
static void
render_item (GskGLRenderer *self,
RenderItem *item)
{
float mvp[16];
float opacity;
if (item->children != NULL)
{
if (gsk_gl_driver_bind_render_target (self->gl_driver, item->render_data.render_target_id))
{
glViewport (0, 0, item->size.width, item->size.height);
glClearColor (0.0, 0.0, 0.0, 0.0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
}
gsk_gl_driver_bind_vao (self->gl_driver, item->render_data.vao_id);
glUseProgram (item->render_data.program_id);
if (item->render_data.texture_id != 0)
{
/* Use texture unit 0 for the source */
glUniform1i (item->render_data.source_location, 0);
gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_data.texture_id);
if (item->parent_data != NULL)
{
glUniform1i (item->render_data.blendMode_location, item->blend_mode);
/* Use texture unit 1 for the mask */
if (item->parent_data->texture_id != 0)
{
glUniform1i (item->render_data.mask_location, 1);
gsk_gl_driver_bind_mask_texture (self->gl_driver, item->parent_data->texture_id);
}
}
}
/* Pass the opacity component */
if (item->children != NULL || item->opaque)
opacity = 1.0;
else
opacity = item->opacity;
glUniform1f (item->render_data.alpha_location, opacity);
/* Pass the mvp to the vertex shader */
GSK_NOTE (TRANSFORMS, 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_NOTE2 (OPENGL, TRANSFORMS,
g_print ("%*sDrawing item <%s>[%p] (w:%g, h:%g) with opacity: %g blend mode: %d\n",
2 * node_depth (item->node), "",
item->name,
item,
item->size.width, item->size.height,
item->opaque ? 1 : item->opacity,
item->blend_mode));
glDrawArrays (GL_TRIANGLES, 0, N_VERTICES);
#ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (gsk_renderer_get_profiler (GSK_RENDERER (self)),
self->profile_counters.draw_calls);
#endif
/* Render all children items, so we can take the result
* render target texture during the compositing
*/
if (item->children != NULL)
{
int i;
for (i = 0; i < item->children->len; i++)
{
RenderItem *child = &g_array_index (item->children, RenderItem, i);
render_item (self, child);
}
/* Bind the parent render target */
if (item->parent_data != NULL)
gsk_gl_driver_bind_render_target (self->gl_driver, item->parent_data->render_target_id);
/* Bind the same VAO, as the render target is created with the same size
* and vertices as the texture target
*/
gsk_gl_driver_bind_vao (self->gl_driver, item->render_data.vao_id);
/* Since we're rendering the target texture, we only need the blit program */
glUseProgram (self->blit_program_id);
/* Use texture unit 0 for the render target */
glUniform1i (item->render_data.source_location, 0);
gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_data.render_target_id);
/* Pass the opacity component; if we got here, we know that the original render
* target is neither fully opaque nor at full opacity
*/
glUniform1f (item->render_data.alpha_location, item->opacity);
/* Pass the mvp to the vertex shader */
GSK_NOTE (TRANSFORMS, 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_NOTE2 (OPENGL, TRANSFORMS,
g_print ("%*sDrawing offscreen item <%s>[%p] (w:%g, h:%g) with opacity: %g\n",
2 * node_depth (item->node), "",
item->name,
item,
item->size.width, item->size.height,
item->opacity));
glDrawArrays (GL_TRIANGLES, 0, N_VERTICES);
}
}
static void
get_gl_scaling_filters (GskRenderNode *node,
int *min_filter_r,
int *mag_filter_r)
{
switch (node->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 (node->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 gboolean
render_node_needs_render_target (GskRenderNode *node)
{
if (!gsk_render_node_is_opaque (node))
{
double opacity = gsk_render_node_get_opacity (node);
if (opacity < 1.0)
return TRUE;
}
return FALSE;
}
static void
gsk_gl_renderer_add_render_item (GskGLRenderer *self,
const graphene_matrix_t *projection,
GArray *render_items,
GskRenderNode *node,
RenderItem *parent)
{
graphene_rect_t viewport;
GskRenderNodeIter iter;
graphene_matrix_t mv;
graphene_rect_t bounds;
GskRenderNode *child;
RenderItem item;
RenderItem *ritem = NULL;
int program_id;
int scale_factor;
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);
scale_factor = gsk_render_node_get_scale_factor (node);
if (scale_factor < 1)
scale_factor = 1;
gsk_render_node_get_bounds (node, &bounds);
item.node = node;
item.name = node->name != NULL ? node->name : "unnamed";
/* The texture size */
item.size.width = bounds.size.width * scale_factor;
item.size.height = bounds.size.height * scale_factor;
/* 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 = item.min.x + bounds.size.width;
item.max.y = item.min.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.z = project_item (projection, &mv);
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);
/* Back-pointer to the parent node */
if (parent != NULL)
item.parent_data = &(parent->render_data);
else
item.parent_data = NULL;
/* Select the program to use */
if (parent != NULL)
program_id = self->blend_program_id;
else
program_id = self->blit_program_id;
item.render_data.program_id = program_id;
/* Retrieve all the uniforms and attributes */
item.render_data.source_location =
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[SOURCE]);
item.render_data.mask_location =
gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MASK]);
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]);
if (render_node_needs_render_target (node))
{
item.render_data.render_target_id =
gsk_gl_driver_create_texture (self->gl_driver, item.size.width, item.size.height);
gsk_gl_driver_init_texture_empty (self->gl_driver, item.render_data.render_target_id);
gsk_gl_driver_create_render_target (self->gl_driver, item.render_data.render_target_id, TRUE, TRUE);
item.children = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem),
gsk_render_node_get_n_children (node));
}
else
{
item.render_data.render_target_id = self->texture_id;
item.children = NULL;
}
if (gsk_render_node_has_texture (node))
{
item.render_data.texture_id = gsk_render_node_get_texture (node);
}
else if (gsk_render_node_has_surface (node))
{
cairo_surface_t *surface = gsk_render_node_get_surface (node);
int gl_min_filter = GL_NEAREST, gl_mag_filter = GL_NEAREST;
get_gl_scaling_filters (node, &gl_min_filter, &gl_mag_filter);
/* Upload the Cairo surface to a GL texture */
item.render_data.texture_id = gsk_gl_driver_create_texture (self->gl_driver,
item.size.width,
item.size.height);
gsk_gl_driver_bind_source_texture (self->gl_driver, item.render_data.texture_id);
gsk_gl_driver_init_texture_with_surface (self->gl_driver,
item.render_data.texture_id,
surface,
gl_min_filter,
gl_mag_filter);
}
else
{
/* If the node does not draw anything, we skip it */
if (item.render_data.render_target_id == self->texture_id)
goto out;
}
/* Create the vertex buffers holding the geometry of the quad */
{
GskQuadVertex vertex_data[N_VERTICES] = {
{ { 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 }, },
};
item.render_data.vao_id =
gsk_gl_driver_create_vao_for_quad (self->gl_driver,
item.render_data.position_location,
item.render_data.uv_location,
N_VERTICES,
vertex_data);
}
GSK_NOTE (OPENGL, g_print ("%*sAdding node <%s>[%p] to render items\n",
2 * node_depth (node), "",
node->name != NULL ? node->name : "unnamed",
node));
g_array_append_val (render_items, item);
ritem = &g_array_index (render_items, RenderItem, render_items->len - 1);
if (item.children != NULL)
render_items = item.children;
out:
gsk_render_node_iter_init (&iter, node);
while (gsk_render_node_iter_next (&iter, &child))
gsk_gl_renderer_add_render_item (self, projection, render_items, child, ritem);
}
static gboolean
gsk_gl_renderer_validate_tree (GskGLRenderer *self,
GskRenderNode *root,
const graphene_matrix_t *projection)
{
int n_nodes;
if (self->gl_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->gl_context);
self->render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_nodes);
gsk_gl_driver_begin_frame (self->gl_driver);
GSK_NOTE (OPENGL, g_print ("RenderNode -> RenderItem\n"));
gsk_gl_renderer_add_render_item (self, projection, self->render_items, root, NULL);
GSK_NOTE (OPENGL, g_print ("Total render items: %d of max:%d\n",
self->render_items->len,
n_nodes));
gsk_gl_driver_end_frame (self->gl_driver);
return TRUE;
}
static void
gsk_gl_renderer_clear_tree (GskGLRenderer *self)
{
int removed_textures, removed_vaos;
if (self->gl_context == NULL)
return;
gdk_gl_context_make_current (self->gl_context);
g_clear_pointer (&self->render_items, g_array_unref);
removed_textures = gsk_gl_driver_collect_textures (self->gl_driver);
removed_vaos = gsk_gl_driver_collect_vaos (self->gl_driver);
GSK_NOTE (OPENGL, g_print ("Collected: %d textures, %d vaos\n",
removed_textures,
removed_vaos));
}
static void
gsk_gl_renderer_clear (GskGLRenderer *self)
{
GSK_NOTE (OPENGL, g_print ("Clearing viewport\n"));
glClearColor (0, 0, 0, 0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
#define ORTHO_NEAR_PLANE -10000
#define ORTHO_FAR_PLANE 10000
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;
guint i;
int scale_factor;
#ifdef G_ENABLE_DEBUG
GskProfiler *profiler;
gint64 gpu_time, cpu_time;
#endif
if (self->gl_context == NULL)
return;
profiler = gsk_renderer_get_profiler (renderer);
gdk_gl_context_make_current (self->gl_context);
gsk_renderer_get_viewport (renderer, &viewport);
scale_factor = gsk_renderer_get_scale_factor (renderer);
gsk_gl_driver_begin_frame (self->gl_driver);
gsk_gl_renderer_create_buffers (self, viewport.size.width, viewport.size.height, scale_factor);
gsk_gl_driver_end_frame (self->gl_driver);
/* Set up the modelview and projection matrices to fit our viewport */
graphene_matrix_init_scale (&modelview, scale_factor, scale_factor, 1.0);
graphene_matrix_init_ortho (&projection,
0, viewport.size.width * scale_factor,
viewport.size.height * scale_factor, 0,
ORTHO_NEAR_PLANE,
ORTHO_FAR_PLANE);
gsk_gl_renderer_update_frustum (self, &modelview, &projection);
if (!gsk_gl_renderer_validate_tree (self, root, &projection))
goto out;
gsk_gl_driver_begin_frame (self->gl_driver);
#ifdef G_ENABLE_DEBUG
gsk_gl_profiler_begin_gpu_region (self->gl_profiler);
gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
#endif
/* Ensure that the viewport is up to date */
if (gsk_gl_driver_bind_render_target (self->gl_driver, self->texture_id))
gsk_gl_renderer_resize_viewport (self, &viewport, scale_factor);
gsk_gl_renderer_clear (self);
glEnable (GL_DEPTH_TEST);
glDepthFunc (GL_LEQUAL);
glEnable (GL_BLEND);
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
GSK_NOTE (OPENGL, g_print ("Rendering %u items\n", self->render_items->len));
for (i = 0; i < self->render_items->len; i++)
{
RenderItem *item = &g_array_index (self->render_items, RenderItem, i);
render_item (self, item);
}
/* Draw the output of the GL rendering to the window */
gsk_gl_driver_end_frame (self->gl_driver);
#ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
gpu_time = gsk_gl_profiler_end_gpu_region (self->gl_profiler);
gsk_profiler_timer_set (profiler, self->profile_timers.gpu_time, gpu_time);
gsk_profiler_push_samples (profiler);
#endif
out:
/* XXX: Add GdkDrawingContext API */
gdk_cairo_draw_from_gl (gdk_drawing_context_get_cairo_context (context),
gdk_drawing_context_get_window (context),
self->texture_id,
GL_TEXTURE,
scale_factor,
0, 0,
viewport.size.width * scale_factor,
viewport.size.height * scale_factor);
gdk_gl_context_make_current (self->gl_context);
gsk_gl_renderer_clear_tree (self);
gsk_gl_renderer_destroy_buffers (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);
#ifdef G_ENABLE_DEBUG
{
GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
self->profile_counters.frames = gsk_profiler_add_counter (profiler, "frames", "Frames", FALSE);
self->profile_counters.draw_calls = gsk_profiler_add_counter (profiler, "draws", "glDrawArrays", TRUE);
self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
}
#endif
}
+23
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__ */
+16
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
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__ */
+470
View File
@@ -0,0 +1,470 @@
#include "config.h"
#include "gskprofilerprivate.h"
#define MAX_SAMPLES 32
typedef struct {
GQuark id;
char *description;
gint64 value;
gint64 n_samples;
gboolean can_reset : 1;
} NamedCounter;
typedef struct {
GQuark id;
char *description;
gint64 value;
gint64 start_time;
gint64 min_value;
gint64 max_value;
gint64 avg_value;
gint64 n_samples;
gboolean in_flight : 1;
gboolean can_reset : 1;
gboolean invert : 1;
} NamedTimer;
typedef struct {
GQuark id;
gint64 value;
} Sample;
struct _GskProfiler
{
GObject parent_instance;
GHashTable *counters;
GHashTable *timers;
Sample timer_samples[MAX_SAMPLES];
guint last_sample;
};
G_DEFINE_TYPE (GskProfiler, gsk_profiler, G_TYPE_OBJECT)
static void
named_counter_free (gpointer data)
{
NamedCounter *counter = data;
if (data == NULL)
return;
g_free (counter->description);
g_slice_free (NamedCounter, counter);
}
static void
named_timer_free (gpointer data)
{
NamedTimer *timer = data;
if (data == NULL)
return;
g_free (timer->description);
g_slice_free (NamedTimer, timer);
}
static void
gsk_profiler_finalize (GObject *gobject)
{
GskProfiler *self = GSK_PROFILER (gobject);
g_clear_pointer (&self->counters, g_hash_table_unref);
g_clear_pointer (&self->timers, g_hash_table_unref);
G_OBJECT_CLASS (gsk_profiler_parent_class)->finalize (gobject);
}
static void
gsk_profiler_class_init (GskProfilerClass *klass)
{
G_OBJECT_CLASS (klass)->finalize = gsk_profiler_finalize;
}
static void
gsk_profiler_init (GskProfiler *self)
{
self->counters = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL,
named_counter_free);
self->timers = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL,
named_timer_free);
}
GskProfiler *
gsk_profiler_new (void)
{
return g_object_new (GSK_TYPE_PROFILER, NULL);
}
static NamedCounter *
named_counter_new (GQuark id,
const char *description,
gboolean can_reset)
{
NamedCounter *res = g_slice_new0 (NamedCounter);
res->id = id;
res->description = g_strdup (description);
res->can_reset = can_reset;
return res;
}
static NamedCounter *
gsk_profiler_get_counter (GskProfiler *profiler,
GQuark id)
{
return g_hash_table_lookup (profiler->counters, GINT_TO_POINTER (id));
}
GQuark
gsk_profiler_add_counter (GskProfiler *profiler,
const char *counter_name,
const char *description,
gboolean can_reset)
{
NamedCounter *counter;
GQuark id;
g_return_val_if_fail (GSK_IS_PROFILER (profiler), 0);
id = g_quark_from_string (counter_name);
counter = gsk_profiler_get_counter (profiler, id);
if (counter != NULL)
{
g_critical ("Cannot add a counter '%s' as one already exists.", counter_name);
return counter->id;
}
counter = named_counter_new (id, description, can_reset);
g_hash_table_insert (profiler->counters, GINT_TO_POINTER (id), counter);
return counter->id;
}
static NamedTimer *
named_timer_new (GQuark id,
const char *description,
gboolean invert,
gboolean can_reset)
{
NamedTimer *res = g_slice_new0 (NamedTimer);
res->id = id;
res->description = g_strdup (description);
res->invert = invert;
res->can_reset = can_reset;
return res;
}
static NamedTimer *
gsk_profiler_get_timer (GskProfiler *profiler,
GQuark id)
{
return g_hash_table_lookup (profiler->timers, GINT_TO_POINTER (id));
}
GQuark
gsk_profiler_add_timer (GskProfiler *profiler,
const char *timer_name,
const char *description,
gboolean invert,
gboolean can_reset)
{
NamedTimer *timer;
GQuark id;
g_return_val_if_fail (GSK_IS_PROFILER (profiler), 0);
id = g_quark_from_string (timer_name);
timer = gsk_profiler_get_timer (profiler, id);
if (timer != NULL)
{
g_critical ("Cannot add a timer '%s' as one already exists.", timer_name);
return timer->id;
}
timer = named_timer_new (id, description, invert, can_reset);
g_hash_table_insert (profiler->timers, GINT_TO_POINTER (id), timer);
return timer->id;
}
void
gsk_profiler_counter_inc (GskProfiler *profiler,
GQuark counter_id)
{
NamedCounter *counter;
g_return_if_fail (GSK_IS_PROFILER (profiler));
counter = gsk_profiler_get_counter (profiler, counter_id);
if (counter == NULL)
return;
counter->value += 1;
}
void
gsk_profiler_timer_begin (GskProfiler *profiler,
GQuark timer_id)
{
NamedTimer *timer;
g_return_if_fail (GSK_IS_PROFILER (profiler));
timer = gsk_profiler_get_timer (profiler, timer_id);
if (timer == NULL)
return;
if (timer->in_flight)
return;
timer->in_flight = TRUE;
timer->start_time = g_get_monotonic_time () * 1000;
}
gint64
gsk_profiler_timer_end (GskProfiler *profiler,
GQuark timer_id)
{
NamedTimer *timer;
gint64 diff;
g_return_val_if_fail (GSK_IS_PROFILER (profiler), 0);
timer = gsk_profiler_get_timer (profiler, timer_id);
if (timer == NULL)
{
g_critical ("No timer '%s' (id:%d) found; did you forget to call gsk_profiler_add_timer()?",
g_quark_to_string (timer_id), timer_id);
return 0;
}
if (!timer->in_flight)
{
g_critical ("Timer '%s' (id:%d) is not running; did you forget to call gsk_profiler_timer_begin()?",
g_quark_to_string (timer->id), timer->id);
return 0;
}
diff = (g_get_monotonic_time () * 1000) - timer->start_time;
timer->in_flight = FALSE;
timer->value += diff;
return diff;
}
void
gsk_profiler_timer_set (GskProfiler *profiler,
GQuark timer_id,
gint64 value)
{
NamedTimer *timer;
g_return_if_fail (GSK_IS_PROFILER (profiler));
timer = gsk_profiler_get_timer (profiler, timer_id);
if (timer == NULL)
{
g_critical ("No timer '%s' (id:%d) found; did you forget to call gsk_profiler_add_timer()?",
g_quark_to_string (timer_id), timer_id);
return;
}
if (timer->in_flight)
{
g_critical ("Timer '%s' (id:%d) is running; are you sure you don't want to call "
"gsk_profiler_timer_end() instead of gsk_profiler_timer_set()?",
g_quark_to_string (timer_id), timer_id);
}
timer->value = value;
}
gint64
gsk_profiler_counter_get (GskProfiler *profiler,
GQuark counter_id)
{
NamedCounter *counter;
g_return_val_if_fail (GSK_IS_PROFILER (profiler), 0);
counter = gsk_profiler_get_counter (profiler, counter_id);
if (counter == NULL)
{
g_critical ("No counter '%s' (id:%d) found; did you forget to call gsk_profiler_add_counter()?",
g_quark_to_string (counter_id), counter_id);
return 0;
}
return counter->value;
}
gint64
gsk_profiler_timer_get (GskProfiler *profiler,
GQuark timer_id)
{
NamedTimer *timer;
g_return_val_if_fail (GSK_IS_PROFILER (profiler), 0);
timer = gsk_profiler_get_timer (profiler, timer_id);
if (timer == NULL)
{
g_critical ("No timer '%s' (id:%d) found; did you forget to call gsk_profiler_add_timer()?",
g_quark_to_string (timer_id), timer_id);
return 0;
}
if (timer->invert)
return (gint64) (1000000000.0 / (double) timer->value);
return timer->value;
}
void
gsk_profiler_reset (GskProfiler *profiler)
{
GHashTableIter iter;
gpointer value_p = NULL;
g_return_if_fail (GSK_IS_PROFILER (profiler));
g_hash_table_iter_init (&iter, profiler->counters);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
NamedCounter *counter = value_p;
if (counter->can_reset)
counter->value = 0;
}
g_hash_table_iter_init (&iter, profiler->timers);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
NamedTimer *timer = value_p;
if (timer->can_reset)
{
timer->value = 0;
timer->min_value = 0;
timer->max_value = 0;
timer->avg_value = 0;
timer->n_samples = 0;
}
}
profiler->last_sample = 0;
}
void
gsk_profiler_push_samples (GskProfiler *profiler)
{
GHashTableIter iter;
gpointer value_p = NULL;
guint last_sample;
g_return_if_fail (GSK_IS_PROFILER (profiler));
g_hash_table_iter_init (&iter, profiler->timers);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
NamedTimer *timer = value_p;
Sample *s;
last_sample = profiler->last_sample;
profiler->last_sample += 1;
if (profiler->last_sample == MAX_SAMPLES)
profiler->last_sample = 0;
s = &(profiler->timer_samples[last_sample]);
s->id = timer->id;
if (timer->invert)
s->value = (gint64) (1000000000.0 / (double) timer->value);
else
s->value = timer->value;
}
}
void
gsk_profiler_append_counters (GskProfiler *profiler,
GString *buffer)
{
GHashTableIter iter;
gpointer value_p = NULL;
g_return_if_fail (GSK_IS_PROFILER (profiler));
g_return_if_fail (buffer != NULL);
g_hash_table_iter_init (&iter, profiler->counters);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
NamedCounter *counter = value_p;
g_string_append_printf (buffer, "%s: %" G_GINT64_FORMAT "\n",
counter->description,
counter->value);
}
}
void
gsk_profiler_append_timers (GskProfiler *profiler,
GString *buffer)
{
GHashTableIter iter;
gpointer value_p = NULL;
int i;
g_return_if_fail (GSK_IS_PROFILER (profiler));
g_return_if_fail (buffer != NULL);
for (i = 0; i < profiler->last_sample; i++)
{
Sample *s = &(profiler->timer_samples[i]);
NamedTimer *timer;
if (s->id == 0)
continue;
timer = gsk_profiler_get_timer (profiler, s->id);
timer->min_value = MIN (timer->min_value, s->value);
timer->max_value = MAX (timer->max_value, s->value);
timer->avg_value += s->value;
timer->n_samples += 1;
}
g_hash_table_iter_init (&iter, profiler->timers);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
NamedTimer *timer = value_p;
const char *unit = timer->invert ? "" : "usec";
double scale = timer->invert ? 1.0 : 1000.0;
if (timer->n_samples != 0)
timer->avg_value = timer->avg_value / timer->n_samples;
g_string_append_printf (buffer,
"%s %s: "
"Min:%.2f, "
"Avg:%.2f, "
"Max:%.2f\n",
timer->description,
unit,
(double) timer->min_value / scale,
(double) timer->avg_value / scale,
(double) timer->max_value / scale);
}
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef __GSK_PROFILER_PRIVATE_H__
#define __GSK_PROFILER_PRIVATE_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define GSK_TYPE_PROFILER (gsk_profiler_get_type ())
G_DECLARE_FINAL_TYPE (GskProfiler, gsk_profiler, GSK, PROFILER, GObject)
GskProfiler * gsk_profiler_new (void);
GQuark gsk_profiler_add_counter (GskProfiler *profiler,
const char *counter_name,
const char *description,
gboolean can_reset);
GQuark gsk_profiler_add_timer (GskProfiler *profiler,
const char *timer_name,
const char *description,
gboolean invert,
gboolean can_reset);
void gsk_profiler_counter_inc (GskProfiler *profiler,
GQuark counter_id);
void gsk_profiler_timer_begin (GskProfiler *profiler,
GQuark timer_id);
gint64 gsk_profiler_timer_end (GskProfiler *profiler,
GQuark timer_id);
void gsk_profiler_timer_set (GskProfiler *profiler,
GQuark timer_id,
gint64 value);
gint64 gsk_profiler_counter_get (GskProfiler *profiler,
GQuark counter_id);
gint64 gsk_profiler_timer_get (GskProfiler *profiler,
GQuark timer_id);
void gsk_profiler_reset (GskProfiler *profiler);
void gsk_profiler_push_samples (GskProfiler *profiler);
void gsk_profiler_append_counters (GskProfiler *profiler,
GString *buffer);
void gsk_profiler_append_timers (GskProfiler *profiler,
GString *buffer);
G_END_DECLS
#endif /* __GSK_PROFILER_PRIVATE_H__ */
+802
View File
@@ -0,0 +1,802 @@
/* 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:GskRenderer
* @Title: GskRenderer
* @Short_description: Renders a scene
*
* #GskRenderer is a class that renders a scene graph defined via a
* tree of #GskRenderNode instances.
*
* Typically you will use a #GskRenderer instance with a #GdkDrawingContext
* associated to a #GdkWindow, and call gsk_renderer_render() with the
* drawing context and the scene to be rendered.
*
* It is necessary to realize a #GskRenderer instance using gsk_renderer_realize()
* before calling gsk_renderer_render(), in order to create the appropriate
* windowing system resources needed to render the scene.
*/
#include "config.h"
#include "gskrendererprivate.h"
#include "gskdebugprivate.h"
#include "gskglrendererprivate.h"
#include "gskprofilerprivate.h"
#include "gskrendernodeprivate.h"
#include "gskenumtypes.h"
#include <graphene-gobject.h>
#include <cairo-gobject.h>
#include <gdk/gdk.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/x11/gdkx.h>
#endif
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/wayland/gdkwayland.h>
#endif
typedef struct
{
GObject parent_instance;
graphene_rect_t viewport;
GskScalingFilter min_filter;
GskScalingFilter mag_filter;
GdkWindow *window;
GdkDrawingContext *drawing_context;
GskRenderNode *root_node;
GdkDisplay *display;
GskProfiler *profiler;
int scale_factor;
gboolean is_realized : 1;
gboolean auto_clear : 1;
} GskRendererPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GskRenderer, gsk_renderer, G_TYPE_OBJECT)
enum {
PROP_VIEWPORT = 1,
PROP_AUTO_CLEAR,
PROP_SCALE_FACTOR,
PROP_WINDOW,
PROP_DISPLAY,
PROP_DRAWING_CONTEXT,
N_PROPS
};
static GParamSpec *gsk_renderer_properties[N_PROPS];
#define GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD(obj,method) \
g_critical ("Renderer of type '%s' does not implement GskRenderer::" # method, G_OBJECT_TYPE_NAME (obj))
static gboolean
gsk_renderer_real_realize (GskRenderer *self)
{
GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, realize);
return FALSE;
}
static void
gsk_renderer_real_unrealize (GskRenderer *self)
{
GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, unrealize);
}
static void
gsk_renderer_real_render (GskRenderer *self,
GskRenderNode *root,
GdkDrawingContext *context)
{
GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, render);
}
static void
gsk_renderer_dispose (GObject *gobject)
{
GskRenderer *self = GSK_RENDERER (gobject);
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
gsk_renderer_unrealize (self);
g_clear_object (&priv->window);
g_clear_object (&priv->display);
G_OBJECT_CLASS (gsk_renderer_parent_class)->dispose (gobject);
}
static void
gsk_renderer_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GskRenderer *self = GSK_RENDERER (gobject);
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
switch (prop_id)
{
case PROP_VIEWPORT:
gsk_renderer_set_viewport (self, g_value_get_boxed (value));
break;
case PROP_AUTO_CLEAR:
gsk_renderer_set_auto_clear (self, g_value_get_boolean (value));
break;
case PROP_SCALE_FACTOR:
gsk_renderer_set_scale_factor (self, g_value_get_int (value));
break;
case PROP_WINDOW:
gsk_renderer_set_window (self, g_value_get_object (value));
break;
case PROP_DISPLAY:
/* Construct-only */
priv->display = g_value_dup_object (value);
break;
}
}
static void
gsk_renderer_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GskRenderer *self = GSK_RENDERER (gobject);
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
switch (prop_id)
{
case PROP_VIEWPORT:
g_value_set_boxed (value, &priv->viewport);
break;
case PROP_AUTO_CLEAR:
g_value_set_boolean (value, priv->auto_clear);
break;
case PROP_SCALE_FACTOR:
g_value_set_int (value, priv->scale_factor);
break;
case PROP_WINDOW:
g_value_set_object (value, priv->window);
break;
case PROP_DRAWING_CONTEXT:
g_value_set_object (value, priv->drawing_context);
break;
case PROP_DISPLAY:
g_value_set_object (value, priv->display);
break;
}
}
static void
gsk_renderer_constructed (GObject *gobject)
{
GskRenderer *self = GSK_RENDERER (gobject);
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
if (priv->display == NULL)
{
GdkDisplayManager *manager = gdk_display_manager_get ();
priv->display = gdk_display_manager_get_default_display (manager);
g_assert (priv->display != NULL);
}
G_OBJECT_CLASS (gsk_renderer_parent_class)->constructed (gobject);
}
static void
gsk_renderer_class_init (GskRendererClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
klass->realize = gsk_renderer_real_realize;
klass->unrealize = gsk_renderer_real_unrealize;
klass->render = gsk_renderer_real_render;
gobject_class->constructed = gsk_renderer_constructed;
gobject_class->set_property = gsk_renderer_set_property;
gobject_class->get_property = gsk_renderer_get_property;
gobject_class->dispose = gsk_renderer_dispose;
/**
* GskRenderer:viewport:
*
* The visible area used by the #GskRenderer to render its contents.
*
* Since: 3.22
*/
gsk_renderer_properties[PROP_VIEWPORT] =
g_param_spec_boxed ("viewport",
"Viewport",
"The visible area used by the renderer",
GRAPHENE_TYPE_RECT,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GskRenderer:auto-clear:
*
* Automatically clear the rendering surface when rendering.
*
* Setting this property to %FALSE assumes that the owner of the
* rendering surface will have cleared it prior to calling
* gsk_renderer_render().
*
* Since: 3.22
*/
gsk_renderer_properties[PROP_AUTO_CLEAR] =
g_param_spec_boolean ("auto-clear",
"Auto Clear",
"Automatically clears the rendering target on render",
TRUE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GskRenderer:display:
*
* The #GdkDisplay used by the #GskRenderer.
*
* Since: 3.22
*/
gsk_renderer_properties[PROP_DISPLAY] =
g_param_spec_object ("display",
"Display",
"The GdkDisplay object used by the renderer",
GDK_TYPE_DISPLAY,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
gsk_renderer_properties[PROP_WINDOW] =
g_param_spec_object ("window",
"Window",
"The window associated to the renderer",
GDK_TYPE_WINDOW,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
/**
* GskRenderer:scale-factor:
*
* The scale factor used when rendering.
*
* Since: 3.22
*/
gsk_renderer_properties[PROP_SCALE_FACTOR] =
g_param_spec_int ("scale-factor",
"Scale Factor",
"The scaling factor of the renderer",
1, G_MAXINT,
1,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GskRenderer:drawing-context:
*
* The drawing context used when rendering.
*
* Since: 3.22
*/
gsk_renderer_properties[PROP_DRAWING_CONTEXT] =
g_param_spec_object ("drawing-context",
"Drawing Context",
"The drawing context used by the renderer",
GDK_TYPE_DRAWING_CONTEXT,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, gsk_renderer_properties);
}
static void
gsk_renderer_init (GskRenderer *self)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (self);
priv->profiler = gsk_profiler_new ();
priv->auto_clear = TRUE;
priv->scale_factor = 1;
}
/**
* gsk_renderer_set_viewport:
* @renderer: a #GskRenderer
* @viewport: (nullable): the viewport rectangle used by the @renderer
*
* Sets the visible rectangle to be used as the viewport for
* the rendering.
*
* Since: 3.22
*/
void
gsk_renderer_set_viewport (GskRenderer *renderer,
const graphene_rect_t *viewport)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_if_fail (GSK_IS_RENDERER (renderer));
if (viewport == NULL)
{
graphene_rect_init (&priv->viewport, 0.f, 0.f, 0.f, 0.f);
g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_VIEWPORT]);
return;
}
if (graphene_rect_equal (viewport, &priv->viewport))
return;
graphene_rect_init_from_rect (&priv->viewport, viewport);
g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_VIEWPORT]);
}
/**
* gsk_renderer_get_viewport:
* @renderer: a #GskRenderer
* @viewport: (out caller-allocates): return location for the viewport rectangle
*
* Retrieves the viewport of the #GskRenderer.
*
* Since: 3.22
*/
void
gsk_renderer_get_viewport (GskRenderer *renderer,
graphene_rect_t *viewport)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_if_fail (GSK_IS_RENDERER (renderer));
g_return_if_fail (viewport != NULL);
graphene_rect_init_from_rect (viewport, &priv->viewport);
}
/**
* gsk_renderer_set_scale_factor:
* @renderer: a #GskRenderer
* @scale_factor: the new scale factor
*
* Sets the scale factor for the renderer.
*
* Since: 3.22
*/
void
gsk_renderer_set_scale_factor (GskRenderer *renderer,
int scale_factor)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_if_fail (GSK_IS_RENDERER (renderer));
if (priv->scale_factor != scale_factor)
{
priv->scale_factor = scale_factor;
g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_SCALE_FACTOR]);
}
}
/**
* gsk_renderer_get_scale_factor:
* @renderer: a #GskRenderer
*
* Gets the scale factor for the @renderer.
*
* Returns: the scale factor
*
* Since: 3.22
*/
int
gsk_renderer_get_scale_factor (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_val_if_fail (GSK_IS_RENDERER (renderer), 1);
return priv->scale_factor;
}
/**
* gsk_renderer_set_window:
* @renderer: a #GskRenderer
* @window: the window to set
*
* Sets the window on which the @renderer is rendering.
*
* Since: 3.22
*/
void
gsk_renderer_set_window (GskRenderer *renderer,
GdkWindow *window)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_if_fail (GSK_IS_RENDERER (renderer));
g_return_if_fail (!priv->is_realized);
g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
if (g_set_object (&priv->window, window))
g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_WINDOW]);
}
/**
* gsk_renderer_get_window:
* @renderer: a #GskRenderer
*
* Retrieves the #GdkWindow set using gsk_renderer_set_window().
*
* Returns: (transfer none) (nullable): a #GdkWindow
*
* Since: 3.22
*/
GdkWindow *
gsk_renderer_get_window (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
return priv->window;
}
/*< private >
* gsk_renderer_get_root_node:
* @renderer: a #GskRenderer
*
* Retrieves the #GskRenderNode used by @renderer.
*
* Returns: (transfer none) (nullable): a #GskRenderNode
*/
GskRenderNode *
gsk_renderer_get_root_node (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
return priv->root_node;
}
/*< private >
* gsk_renderer_get_drawing_context:
* @renderer: a #GskRenderer
*
* Retrieves the #GdkDrawingContext used by @renderer.
*
* Returns: (transfer none) (nullable): a #GdkDrawingContext
*/
GdkDrawingContext *
gsk_renderer_get_drawing_context (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
return priv->drawing_context;
}
/**
* gsk_renderer_get_display:
* @renderer: a #GskRenderer
*
* Retrieves the #GdkDisplay used when creating the #GskRenderer.
*
* Returns: (transfer none): a #GdkDisplay
*
* Since: 3.22
*/
GdkDisplay *
gsk_renderer_get_display (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
return priv->display;
}
/*< private >
* gsk_renderer_is_realized:
* @renderer: a #GskRenderer
*
* Checks whether the @renderer is realized or not.
*
* Returns: %TRUE if the #GskRenderer was realized, and %FALSE otherwise
*
* Since: 3.22
*/
gboolean
gsk_renderer_is_realized (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_val_if_fail (GSK_IS_RENDERER (renderer), FALSE);
return priv->is_realized;
}
/**
* gsk_renderer_realize:
* @renderer: a #GskRenderer
*
* Creates the resources needed by the @renderer to render the scene
* graph.
*
* Since: 3.22
*/
gboolean
gsk_renderer_realize (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_val_if_fail (GSK_IS_RENDERER (renderer), FALSE);
if (priv->is_realized)
return TRUE;
priv->is_realized = GSK_RENDERER_GET_CLASS (renderer)->realize (renderer);
return priv->is_realized;
}
/**
* gsk_renderer_unrealize:
* @renderer: a #GskRenderer
*
* Releases all the resources created by gsk_renderer_realize().
*
* Since: 3.22
*/
void
gsk_renderer_unrealize (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_if_fail (GSK_IS_RENDERER (renderer));
if (!priv->is_realized)
return;
GSK_RENDERER_GET_CLASS (renderer)->unrealize (renderer);
priv->is_realized = FALSE;
}
/**
* gsk_renderer_render:
* @renderer: a #GskRenderer
* @root: a #GskRenderNode
* @context: a #GdkDrawingContext
*
* Renders the scene graph, described by a tree of #GskRenderNode instances,
* using the given #GdkDrawingContext.
*
* The @renderer will acquire a reference on the #GskRenderNode tree while
* the rendering is in progress, and will make the tree immutable.
*
* Since: 3.22
*/
void
gsk_renderer_render (GskRenderer *renderer,
GskRenderNode *root,
GdkDrawingContext *context)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_if_fail (GSK_IS_RENDERER (renderer));
g_return_if_fail (priv->is_realized);
g_return_if_fail (GSK_IS_RENDER_NODE (root));
g_return_if_fail (GDK_IS_DRAWING_CONTEXT (context));
g_return_if_fail (priv->drawing_context == NULL);
g_return_if_fail (priv->root_node == NULL);
g_return_if_fail (root->renderer == renderer);
priv->drawing_context = g_object_ref (context);
priv->root_node = gsk_render_node_ref (root);
gsk_render_node_make_immutable (priv->root_node);
#ifdef G_ENABLE_DEBUG
gsk_profiler_reset (priv->profiler);
#endif
GSK_RENDERER_GET_CLASS (renderer)->render (renderer, root, context);
#ifdef G_ENABLE_DEBUG
if (GSK_DEBUG_CHECK (RENDERER))
{
GString *buf = g_string_new ("*** Frame stats ***\n\n");
gsk_profiler_append_counters (priv->profiler, buf);
g_string_append_c (buf, '\n');
gsk_profiler_append_timers (priv->profiler, buf);
g_string_append_c (buf, '\n');
g_print ("%s\n***\n\n", buf->str);
g_string_free (buf, TRUE);
}
#endif
g_clear_object (&priv->drawing_context);
g_clear_pointer (&priv->root_node, gsk_render_node_unref);
}
/**
* gsk_renderer_set_auto_clear:
* @renderer: a #GskRenderer
* @clear: whether the target surface should be cleared prior
* to rendering to it
*
* Sets whether the target surface used by @renderer should be cleared
* before rendering.
*
* If you pass a custom surface to gsk_renderer_set_surface(), you may
* want to manage the clearing manually; this is possible by passing
* %FALSE to this function.
*
* Since: 3.22
*/
void
gsk_renderer_set_auto_clear (GskRenderer *renderer,
gboolean clear)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_if_fail (GSK_IS_RENDERER (renderer));
clear = !!clear;
if (clear == priv->auto_clear)
return;
priv->auto_clear = clear;
g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_AUTO_CLEAR]);
}
/**
* gsk_renderer_get_auto_clear:
* @renderer: a #GskRenderer
*
* Retrieves the value set using gsk_renderer_set_auto_clear().
*
* Returns: %TRUE if the target surface should be cleared prior to rendering
*
* Since: 3.22
*/
gboolean
gsk_renderer_get_auto_clear (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_val_if_fail (GSK_IS_RENDERER (renderer), FALSE);
return priv->auto_clear;
}
/**
* gsk_renderer_create_render_node:
* @renderer: a #GskRenderer
*
* Creates a new #GskRenderNode instance tied to the given @renderer.
*
* Returns: (transfer full): the new #GskRenderNode
*
* Since: 3.22
*/
GskRenderNode *
gsk_renderer_create_render_node (GskRenderer *renderer)
{
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
return gsk_render_node_new (renderer);
}
/*< private >
* gsk_renderer_get_profiler:
* @renderer: a #GskRenderer
*
* Retrieves a pointer to the GskProfiler instance of the renderer.
*
* Returns: (transfer none): the profiler
*/
GskProfiler *
gsk_renderer_get_profiler (GskRenderer *renderer)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
return priv->profiler;
}
/**
* gsk_renderer_get_for_display:
* @display: a #GdkDisplay
*
* Creates an appropriate #GskRenderer instance for the given @display.
*
* Returns: (transfer full) (nullable): a #GskRenderer
*
* Since: 3.22
*/
GskRenderer *
gsk_renderer_get_for_display (GdkDisplay *display)
{
static const char *use_software;
GType renderer_type = G_TYPE_INVALID;
if (use_software == NULL)
{
use_software = g_getenv ("GSK_USE_SOFTWARE");
if (use_software == NULL)
use_software = "0";
}
if (use_software[0] != '0')
return NULL;
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY (display))
renderer_type = GSK_TYPE_GL_RENDERER;
else
#endif
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY (display))
renderer_type = GSK_TYPE_GL_RENDERER;
else
#endif
return NULL;
GSK_NOTE (RENDERER, g_print ("Creating renderer of type '%s' for display '%s'\n",
g_type_name (renderer_type),
G_OBJECT_TYPE_NAME (display)));
g_assert (renderer_type != G_TYPE_INVALID);
return g_object_new (renderer_type, "display", display, NULL);
}
+85
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_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_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_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
GskRenderNode * gsk_renderer_create_render_node (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_22
void gsk_renderer_render (GskRenderer *renderer,
GskRenderNode *root,
GdkDrawingContext *context);
G_END_DECLS
#endif /* __GSK_RENDERER_H__ */
+57
View File
@@ -0,0 +1,57 @@
/* 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"
#include "gskprofilerprivate.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);
GskProfiler * gsk_renderer_get_profiler (GskRenderer *renderer);
G_END_DECLS
#endif /* __GSK_RENDERER_PRIVATE_H__ */
+1585
View File
File diff suppressed because it is too large Load Diff
+153
View File
@@ -0,0 +1,153 @@
/* 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_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_anchor_point (GskRenderNode *node,
const graphene_point3d_t *offset);
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_texture (GskRenderNode *node,
int texture_id);
GDK_AVAILABLE_IN_3_22
void gsk_render_node_set_scaling_filter (GskRenderNode *node,
GskScalingFilter min_filter,
GskScalingFilter mag_filter);
GDK_AVAILABLE_IN_3_22
int gsk_render_node_get_scale_factor (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
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_description: 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
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 */
+109
View File
@@ -0,0 +1,109 @@
#ifndef __GSK_RENDER_NODE_PRIVATE_H__
#define __GSK_RENDER_NODE_PRIVATE_H__
#include "gskrendernode.h"
#include "gskrenderer.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;
/* Back pointer to the renderer that created the node */
GskRenderer *renderer;
/* 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 as a Cairo surface */
cairo_surface_t *surface;
/* The contents of the node as a GL surface */
int texture_id;
/* Paint opacity */
double opacity;
/* Blend mode */
GskBlendMode blend_mode;
/* Scaling filters */
GskScalingFilter min_filter;
GskScalingFilter mag_filter;
/* 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;
graphene_point3d_t anchor_point;
/* Bit fields; leave at the end */
gboolean is_mutable : 1;
gboolean hidden : 1;
gboolean opaque : 1;
gboolean transform_set : 1;
gboolean needs_world_matrix_update : 1;
};
struct _GskRenderNodeClass
{
GTypeClass parent_class;
void (* finalize) (GskRenderNode *node);
};
GskRenderNode *gsk_render_node_new (GskRenderer *renderer);
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);
int gsk_render_node_get_texture (GskRenderNode *node);
gboolean gsk_render_node_has_surface (GskRenderNode *node);
gboolean gsk_render_node_has_texture (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__ */
+482
View File
@@ -0,0 +1,482 @@
#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 (SHADERS))
{
g_print ("*** Compiling %s shader from '%s' + '%s' ***\n"
"%s\n",
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
shader_preamble, shader_source,
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 (SHADERS))
{
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;
if (!g_hash_table_lookup_extended (builder->programs, GINT_TO_POINTER (program_id), NULL, (gpointer *) &p))
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;
if (!g_hash_table_lookup_extended (builder->programs, GINT_TO_POINTER (program_id), NULL, (gpointer *) &p))
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;
}
+46
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
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__ */
+62
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 Cs = Texture(uSource, vUv);
vec4 Cb = Texture(uMask, vUv);
vec3 res;
if (uBlendMode == 0) {
res = Cs.xyz;
}
else if (uBlendMode == 1) {
res = BlendMultiply(Cb.xyz, Cs.xyz);
}
else if (uBlendMode == 2) {
res = BlendScreen(Cb.xyz, Cs.xyz);
}
else if (uBlendMode == 3) {
res = BlendOverlay(Cb.xyz, Cs.xyz);
}
else if (uBlendMode == 4) {
res = BlendDarken(Cb.xyz, Cs.xyz);
}
else if (uBlendMode == 5) {
res = BlendLighten(Cb.xyz, Cs.xyz);
}
else if (uBlendMode == 8) {
res = BlendHardLight(Cb.xyz, Cs.xyz);
}
else {
// Use red for debugging missing blend modes
res = vec3(1.0, 0.0, 0.0);
}
setOutputColor(vec4(res, Cs.a * uAlpha));
}
+6
View File
@@ -0,0 +1,6 @@
void main() {
gl_Position = uMVP * vec4(aPosition, 0.0, 1.0);
// Flip the sampling
vUv = vec2(aUv.x, aUv.y);
}
+5
View File
@@ -0,0 +1,5 @@
void main() {
vec4 diffuse = Texture(uSource, vUv);
setOutputColor(vec4(diffuse.xyz, diffuse.a * uAlpha));
}
+6
View File
@@ -0,0 +1,6 @@
void main() {
gl_Position = uMVP * vec4(aPosition, 0.0, 1.0);
// Flip the sampling
vUv = vec2(aUv.x, aUv.y);
}
+17
View File
@@ -0,0 +1,17 @@
precision mediump float;
uniform mat4 uMVP;
uniform sampler2D uSource;
uniform sampler2D uMask;
uniform float uAlpha;
uniform int uBlendMode;
varying vec2 vUv;
vec4 Texture(sampler2D sampler, vec2 texCoords) {
return texture2D(sampler, texCoords);
}
void setOutputColor(vec4 color) {
gl_FragColor = color;
}
+6
View File
@@ -0,0 +1,6 @@
uniform mat4 uMVP;
attribute vec2 aPosition;
attribute vec2 aUv;
varying vec2 vUv;
+19
View File
@@ -0,0 +1,19 @@
precision highp float;
uniform sampler2D uSource;
uniform sampler2D uMask;
uniform mat4 uMVP;
uniform float uAlpha;
uniform int uBlendMode;
in vec2 vUv;
out vec4 outputColor;
vec4 Texture(sampler2D sampler, vec2 texCoords) {
return texture(sampler, texCoords);
}
void setOutputColor(vec4 color) {
outputColor = color;
}
+6
View File
@@ -0,0 +1,6 @@
uniform mat4 uMVP;
in vec2 aPosition;
in vec2 aUv;
out vec2 vUv;
+15
View File
@@ -0,0 +1,15 @@
uniform mat4 uMVP;
uniform sampler2D uSource;
uniform sampler2D uMask;
uniform float uAlpha;
uniform int uBlendMode;
varying vec2 vUv;
vec4 Texture(sampler2D sampler, vec2 texCoords) {
return texture2D(sampler, texCoords);
}
void setOutputColor(vec4 color) {
gl_FragColor = color;
}
+6
View File
@@ -0,0 +1,6 @@
uniform mat4 uMVP;
attribute vec2 aPosition;
attribute vec2 aUv;
varying vec2 vUv;
+11 -2
View File
@@ -27,6 +27,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) \
@@ -80,10 +82,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
@@ -1561,7 +1565,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
@@ -1589,6 +1593,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)
@@ -1599,24 +1604,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
+25 -8
View File
@@ -139,8 +139,8 @@ static void gtk_accel_label_get_property (GObject *object,
GParamSpec *pspec);
static void gtk_accel_label_destroy (GtkWidget *widget);
static void gtk_accel_label_finalize (GObject *object);
static gboolean gtk_accel_label_draw (GtkWidget *widget,
cairo_t *cr);
static GskRenderNode *gtk_accel_label_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
static const gchar *gtk_accel_label_get_string (GtkAccelLabel *accel_label);
@@ -161,7 +161,7 @@ gtk_accel_label_class_init (GtkAccelLabelClass *class)
gobject_class->set_property = gtk_accel_label_set_property;
gobject_class->get_property = gtk_accel_label_get_property;
widget_class->draw = gtk_accel_label_draw;
widget_class->get_render_node = gtk_accel_label_get_render_node;
widget_class->get_preferred_width = gtk_accel_label_get_preferred_width;
widget_class->destroy = gtk_accel_label_destroy;
@@ -444,16 +444,17 @@ get_first_baseline (PangoLayout *layout)
return PANGO_PIXELS (result);
}
static gboolean
gtk_accel_label_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_accel_label_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GtkAccelLabel *accel_label = GTK_ACCEL_LABEL (widget);
guint ac_width;
GtkAllocation allocation;
GtkRequisition requisition;
GskRenderNode *res;
GTK_WIDGET_CLASS (gtk_accel_label_parent_class)->draw (widget, cr);
res = GTK_WIDGET_CLASS (gtk_accel_label_parent_class)->get_render_node (widget, renderer);
ac_width = gtk_accel_label_get_accel_width (accel_label);
gtk_widget_get_allocation (widget, &allocation);
@@ -466,6 +467,17 @@ gtk_accel_label_draw (GtkWidget *widget,
PangoLayout *accel_layout;
gint x;
gint y;
GtkAllocation alloc, clip;
GskRenderNode *node;
cairo_t *cr;
node = gtk_widget_create_render_node (widget, renderer, "AccelLabel Content");
gtk_widget_get_clip (widget, &clip);
_gtk_widget_get_allocation (widget, &alloc);
cr = gsk_render_node_get_draw_context (node);
cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y);
context = gtk_widget_get_style_context (widget);
@@ -486,9 +498,14 @@ gtk_accel_label_draw (GtkWidget *widget,
gtk_style_context_restore (context);
g_object_unref (accel_layout);
cairo_destroy (cr);
gsk_render_node_append_child (res, node);
gsk_render_node_unref (node);
}
return FALSE;
return res;
}
static void
+11 -21
View File
@@ -199,29 +199,19 @@ gtk_action_bar_set_child_property (GtkContainer *container,
value);
}
static gboolean
gtk_action_bar_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GTK_WIDGET_CLASS (gtk_action_bar_parent_class)->draw (gtk_css_gadget_get_owner (gadget), cr);
return FALSE;
}
static gboolean
gtk_action_bar_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_action_bar_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (GTK_ACTION_BAR (widget));
GskRenderNode *node = gtk_css_gadget_get_render_node (priv->gadget, renderer, FALSE);
gtk_css_gadget_draw (priv->gadget, cr);
if (node == NULL)
return NULL;
return FALSE;
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, node);
return node;
}
static void
@@ -320,7 +310,7 @@ gtk_action_bar_class_init (GtkActionBarClass *klass)
widget_class->show = gtk_action_bar_show;
widget_class->hide = gtk_action_bar_hide;
widget_class->destroy = gtk_action_bar_destroy;
widget_class->draw = gtk_action_bar_draw;
widget_class->get_render_node = gtk_action_bar_get_render_node;
widget_class->size_allocate = gtk_action_bar_size_allocate;
widget_class->get_preferred_width_for_height = gtk_action_bar_get_preferred_width_for_height;
widget_class->get_preferred_height_and_baseline_for_width = gtk_action_bar_get_preferred_height_and_baseline_for_width;
@@ -373,7 +363,7 @@ gtk_action_bar_init (GtkActionBar *action_bar)
GTK_WIDGET (action_bar),
gtk_action_bar_measure,
gtk_action_bar_allocate,
gtk_action_bar_render,
NULL,
NULL,
NULL);
}
+17 -48
View File
@@ -92,8 +92,9 @@ static void gtk_button_box_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static gboolean gtk_button_box_draw (GtkWidget *widget,
cairo_t *cr);
static GskRenderNode *gtk_button_box_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
static void gtk_button_box_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural);
@@ -143,13 +144,6 @@ static void gtk_button_box_allocate (GtkCssGadget *gadget,
int baseline,
GtkAllocation *out_clip,
gpointer unused);
static gboolean gtk_button_box_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data);
#define DEFAULT_CHILD_MIN_WIDTH 85
#define DEFAULT_CHILD_MIN_HEIGHT 27
@@ -197,7 +191,7 @@ gtk_button_box_class_init (GtkButtonBoxClass *class)
widget_class->get_preferred_height_for_width = gtk_button_box_get_preferred_height_for_width;
widget_class->get_preferred_height_and_baseline_for_width = gtk_button_box_get_preferred_height_and_baseline_for_width;
widget_class->size_allocate = gtk_button_box_size_allocate;
widget_class->draw = gtk_button_box_draw;
widget_class->get_render_node = gtk_button_box_get_render_node;
container_class->remove = gtk_button_box_remove;
container_class->add = gtk_button_box_add;
@@ -297,49 +291,24 @@ gtk_button_box_class_init (GtkButtonBoxClass *class)
gtk_widget_class_set_css_name (widget_class, "buttonbox");
}
static gboolean
gtk_button_box_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer unused)
{
GtkWidget *widget;
GList *children, *l;
widget = gtk_css_gadget_get_owner (gadget);
children = gtk_container_get_children (GTK_CONTAINER (widget));
for (l = children; l; l = l->next)
{
GtkWidget *child = l->data;
gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
}
g_list_free (children);
return FALSE;
}
static gboolean
gtk_button_box_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_button_box_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GtkButtonBoxPrivate *priv = GTK_BUTTON_BOX (widget)->priv;
GtkCssGadget *gadget;
GskRenderNode *res;
if (priv->layout_style == GTK_BUTTONBOX_EXPAND)
gadget = gtk_box_get_gadget (GTK_BOX (widget));
else
gadget = priv->gadget;
return GTK_WIDGET_CLASS (gtk_button_box_parent_class)->get_render_node (widget, renderer);
gtk_css_gadget_draw (gadget, cr);
res = gtk_css_gadget_get_render_node (priv->gadget, renderer, FALSE);
return FALSE;
if (res == NULL)
return NULL;
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
return res;
}
static void
@@ -354,7 +323,7 @@ gtk_button_box_init (GtkButtonBox *button_box)
GTK_WIDGET (button_box),
gtk_button_box_measure,
gtk_button_box_allocate,
gtk_button_box_render,
NULL,
NULL,
NULL);
}
+17 -24
View File
@@ -167,8 +167,6 @@ struct _GtkBoxChild
static void gtk_box_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean gtk_box_draw (GtkWidget *widget,
cairo_t *cr);
static void gtk_box_direction_changed (GtkWidget *widget,
GtkTextDirection previous_direction);
@@ -226,6 +224,9 @@ static void gtk_box_get_preferred_height_and_baseline_for_width (GtkWidget
gint *minimum_baseline,
gint *natural_baseline);
static GskRenderNode * gtk_box_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
static void gtk_box_buildable_init (GtkBuildableIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER,
@@ -255,7 +256,7 @@ gtk_box_class_init (GtkBoxClass *class)
object_class->get_property = gtk_box_get_property;
object_class->dispose = gtk_box_dispose;
widget_class->draw = gtk_box_draw;
widget_class->get_render_node = gtk_box_get_render_node;
widget_class->size_allocate = gtk_box_size_allocate;
widget_class->get_preferred_width = gtk_box_get_preferred_width;
widget_class->get_preferred_height = gtk_box_get_preferred_height;
@@ -436,30 +437,22 @@ gtk_box_get_property (GObject *object,
}
}
static gboolean
gtk_box_draw_contents (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer unused)
static GskRenderNode *
gtk_box_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GTK_WIDGET_CLASS (gtk_box_parent_class)->draw (gtk_css_gadget_get_owner (gadget), cr);
GskRenderNode *res = gtk_css_gadget_get_render_node (GTK_BOX (widget)->priv->gadget,
renderer,
FALSE);
return FALSE;
if (res == NULL)
return NULL;
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
return res;
}
static gboolean
gtk_box_draw (GtkWidget *widget,
cairo_t *cr)
{
gtk_css_gadget_draw (GTK_BOX (widget)->priv->gadget, cr);
return FALSE;
}
static void
count_expand_children (GtkBox *box,
gint *visible_children,
@@ -2107,7 +2100,7 @@ gtk_box_init (GtkBox *box)
GTK_WIDGET (box),
gtk_box_get_content_size,
gtk_box_allocate_contents,
gtk_box_draw_contents,
NULL,
NULL,
NULL);
+7
View File
@@ -518,6 +518,12 @@ gtk_box_gadget_draw (GtkCssGadget *gadget,
return FALSE;
}
static gboolean
gtk_box_gadget_has_content (GtkCssGadget *gadget)
{
return FALSE;
}
static void
gtk_box_gadget_finalize (GObject *object)
{
@@ -539,6 +545,7 @@ gtk_box_gadget_class_init (GtkBoxGadgetClass *klass)
gadget_class->get_preferred_size = gtk_box_gadget_get_preferred_size;
gadget_class->allocate = gtk_box_gadget_allocate;
gadget_class->draw = gtk_box_gadget_draw;
gadget_class->has_content = gtk_box_gadget_has_content;
}
static void
+14 -31
View File
@@ -134,7 +134,8 @@ static void gtk_button_unmap (GtkWidget * widget);
static void gtk_button_style_updated (GtkWidget * widget);
static void gtk_button_size_allocate (GtkWidget * widget,
GtkAllocation * allocation);
static gint gtk_button_draw (GtkWidget * widget, cairo_t *cr);
static GskRenderNode *gtk_button_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
static gint gtk_button_grab_broken (GtkWidget * widget,
GdkEventGrabBroken * event);
static gint gtk_button_key_release (GtkWidget * widget, GdkEventKey * event);
@@ -209,13 +210,6 @@ static void gtk_button_allocate (GtkCssGadget *gadget,
int baseline,
GtkAllocation *out_clip,
gpointer data);
static gboolean gtk_button_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data);
static GParamSpec *props[LAST_PROP] = { NULL, };
static guint button_signals[LAST_SIGNAL] = { 0 };
@@ -257,7 +251,7 @@ gtk_button_class_init (GtkButtonClass *klass)
widget_class->unmap = gtk_button_unmap;
widget_class->style_updated = gtk_button_style_updated;
widget_class->size_allocate = gtk_button_size_allocate;
widget_class->draw = gtk_button_draw;
widget_class->get_render_node = gtk_button_get_render_node;
widget_class->grab_broken_event = gtk_button_grab_broken;
widget_class->key_release_event = gtk_button_key_release;
widget_class->enter_notify_event = gtk_button_enter_notify;
@@ -748,7 +742,7 @@ gtk_button_init (GtkButton *button)
GTK_WIDGET (button),
gtk_button_measure,
gtk_button_allocate,
gtk_button_render,
NULL,
NULL,
NULL);
@@ -1799,31 +1793,20 @@ gtk_button_allocate (GtkCssGadget *gadget,
gtk_container_get_children_clip (GTK_CONTAINER (widget), out_clip);
}
static gboolean
gtk_button_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_button_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
gtk_css_gadget_draw (GTK_BUTTON (widget)->priv->gadget, cr);
GskRenderNode *res = gtk_css_gadget_get_render_node (GTK_BUTTON (widget)->priv->gadget,
renderer,
gtk_widget_has_visible_focus (widget));
return FALSE;
}
if (res == NULL)
return NULL;
static gboolean
gtk_button_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkWidget *widget;
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
widget = gtk_css_gadget_get_owner (gadget);
GTK_WIDGET_CLASS (gtk_button_parent_class)->draw (widget, cr);
return gtk_widget_has_visible_focus (widget);
return res;
}
static void
+26 -13
View File
@@ -104,8 +104,9 @@ static void gtk_check_button_get_preferred_height_and_baseline_for_width (GtkWid
gint *natural_baseline);
static void gtk_check_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean gtk_check_button_draw (GtkWidget *widget,
cairo_t *cr);
static GskRenderNode *gtk_check_button_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
typedef struct {
GtkCssGadget *gadget;
@@ -213,7 +214,7 @@ gtk_check_button_class_init (GtkCheckButtonClass *class)
widget_class->get_preferred_height_for_width = gtk_check_button_get_preferred_height_for_width;
widget_class->get_preferred_height_and_baseline_for_width = gtk_check_button_get_preferred_height_and_baseline_for_width;
widget_class->size_allocate = gtk_check_button_size_allocate;
widget_class->draw = gtk_check_button_draw;
widget_class->get_render_node = gtk_check_button_get_render_node;
widget_class->state_flags_changed = gtk_check_button_state_flags_changed;
widget_class->direction_changed = gtk_check_button_direction_changed;
@@ -528,21 +529,33 @@ gtk_check_button_size_allocate (GtkWidget *widget,
}
}
static gint
gtk_check_button_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_check_button_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (GTK_CHECK_BUTTON (widget));
GtkCssGadget *gadget;
GskRenderNode *res;
GskRenderNode *node;
if (gtk_toggle_button_get_mode (GTK_TOGGLE_BUTTON (widget)))
gadget = priv->gadget;
else
gadget = GTK_BUTTON (widget)->priv->gadget;
if (!gtk_toggle_button_get_mode (GTK_TOGGLE_BUTTON (widget)))
return GTK_WIDGET_CLASS (gtk_check_button_parent_class)->get_render_node (widget, renderer);
gtk_css_gadget_draw (gadget, cr);
res = gtk_css_gadget_get_render_node (priv->gadget,
renderer,
gtk_widget_has_visible_focus (widget));
return FALSE;
if (res == NULL)
return NULL;
node = gtk_css_gadget_get_render_node (priv->indicator_gadget,
renderer,
FALSE);
gsk_render_node_append_child (res, node);
gsk_render_node_unref (node);
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
return res;
}
GtkCssNode *
+20 -28
View File
@@ -31,6 +31,7 @@
#include "gtkframe.h"
#include "gtkiconprivate.h"
#include "gtkbox.h"
#include "gtkcontainerprivate.h"
#include "gtkliststore.h"
#include "gtkmain.h"
#include "gtkmenuprivate.h"
@@ -532,25 +533,6 @@ gtk_combo_box_allocate (GtkCssGadget *gadget,
}
}
static gboolean
gtk_combo_box_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
GtkComboBoxPrivate *priv = combo_box->priv;
gtk_container_propagate_draw (GTK_CONTAINER (widget),
priv->box, cr);
return FALSE;
}
static void
gtk_combo_box_get_preferred_width (GtkWidget *widget,
gint *minimum_size,
@@ -577,7 +559,8 @@ gtk_combo_box_get_preferred_height (GtkWidget *widget,
gint min_width;
/* Combo box is height-for-width only
* (so we always just reserve enough height for the minimum width) */
* (so we always just reserve enough height for the minimum width)
*/
gtk_css_gadget_get_preferred_size (GTK_COMBO_BOX (widget)->priv->gadget,
GTK_ORIENTATION_HORIZONTAL,
-1,
@@ -597,7 +580,8 @@ gtk_combo_box_get_preferred_width_for_height (GtkWidget *widget,
gint *natural_size)
{
/* Combo box is height-for-width only
* (so we assume we always reserved enough height for the minimum width) */
* (so we assume we always reserved enough height for the minimum width)
*/
gtk_css_gadget_get_preferred_size (GTK_COMBO_BOX (widget)->priv->gadget,
GTK_ORIENTATION_HORIZONTAL,
avail_size,
@@ -634,12 +618,20 @@ gtk_combo_box_size_allocate (GtkWidget *widget,
gtk_widget_set_clip (widget, &clip);
}
static gboolean
gtk_combo_box_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_combo_box_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
gtk_css_gadget_draw (GTK_COMBO_BOX (widget)->priv->gadget, cr);
return FALSE;
GskRenderNode *res = gtk_css_gadget_get_render_node (GTK_COMBO_BOX (widget)->priv->gadget,
renderer,
FALSE);
if (res == NULL)
return NULL;
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
return res;
}
static void
@@ -681,7 +673,7 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
widget_class = (GtkWidgetClass *)klass;
widget_class->size_allocate = gtk_combo_box_size_allocate;
widget_class->draw = gtk_combo_box_draw;
widget_class->get_render_node = gtk_combo_box_get_render_node;
widget_class->scroll_event = gtk_combo_box_scroll_event;
widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
widget_class->grab_focus = gtk_combo_box_grab_focus;
@@ -1332,7 +1324,7 @@ gtk_combo_box_init (GtkComboBox *combo_box)
GTK_WIDGET (combo_box),
gtk_combo_box_measure,
gtk_combo_box_allocate,
gtk_combo_box_render,
NULL,
NULL, NULL);
}
+133 -1
View File
@@ -24,7 +24,6 @@
#include "config.h"
#include "gtkcontainer.h"
#include "gtkcontainerprivate.h"
#include <stdarg.h>
@@ -54,6 +53,7 @@
#include "gtkpopovermenu.h"
#include "gtkshortcutswindow.h"
/* A handful of containers inside GTK+ are cheating and widgets
* inside internal structure as direct children for the purpose
* of forall().
@@ -3878,3 +3878,135 @@ gtk_container_get_path_for_child (GtkContainer *container,
return path;
}
typedef struct {
GtkContainer *container;
GskRenderer *renderer;
GskRenderNode *parent;
GArray *child_infos;
} RenderData;
static gboolean
should_propagate_node (GtkWidget *child,
RenderData *data)
{
if (!_gtk_widget_is_drawable (child))
return FALSE;
return TRUE;
}
static void
propagate_render_node (GtkWidget *child,
gpointer data_)
{
RenderData *data = data_;
GskRenderNode *node;
GdkWindow *window, *w;
GtkAllocation allocation;
int x, y;
graphene_matrix_t m;
graphene_point3d_t tmp;
node = gtk_widget_get_render_node (child, data->renderer);
if (node == NULL)
return;
/* translate coordinates. Ugly business, that. */
if (!_gtk_widget_get_has_window (GTK_WIDGET (data->container)))
{
gtk_widget_get_clip (GTK_WIDGET (data->container), &allocation);
x = -allocation.x;
y = -allocation.y;
}
else
{
x = 0;
y = 0;
}
window = _gtk_widget_get_window (GTK_WIDGET (data->container));
for (w = _gtk_widget_get_window (child); w && w != window; w = gdk_window_get_parent (w))
{
int wx, wy;
gdk_window_get_position (w, &wx, &wy);
x += wx;
y += wy;
}
if (w == NULL)
{
x = 0;
y = 0;
}
if (!_gtk_widget_get_has_window (child))
{
gtk_widget_get_clip (child, &allocation);
x += allocation.x;
y += allocation.y;
}
graphene_matrix_init_translate (&m, graphene_point3d_init (&tmp, x, y, 0));
gsk_render_node_set_transform (node, &m);
gsk_render_node_append_child (data->parent, node);
gsk_render_node_unref (node);
}
static void
collect_child_infos (GtkWidget *widget,
gpointer data_)
{
RenderData *data = data_;
ChildOrderInfo info;
GList *siblings;
GdkWindow *window;
if (!should_propagate_node (widget, data))
return;
info.child = widget;
info.window_depth = G_MAXINT;
window = _gtk_widget_get_window (widget);
if (window == NULL)
return;
if (window != gtk_widget_get_window (GTK_WIDGET (data->container)))
{
siblings = gdk_window_peek_children (gdk_window_get_parent (window));
info.window_depth = g_list_index (siblings, window);
}
g_array_append_val (data->child_infos, info);
}
void
gtk_container_propagate_render_node (GtkContainer *container,
GskRenderer *renderer,
GskRenderNode *parent_node)
{
RenderData data;
int i;
data.container = container;
data.renderer = renderer;
data.parent = parent_node;
data.child_infos = g_array_new (FALSE, TRUE, sizeof (ChildOrderInfo));
gtk_container_forall (container, collect_child_infos, &data);
g_array_sort (data.child_infos, compare_children_for_draw);
for (i = 0; i < data.child_infos->len; i++)
{
ChildOrderInfo *info = &g_array_index (data.child_infos, ChildOrderInfo, i);
propagate_render_node (info->child, &data);
}
g_array_free (data.child_infos, TRUE);
}
+5
View File
@@ -21,6 +21,7 @@
#define __GTK_CONTAINER_PRIVATE_H__
#include "gtkcontainer.h"
#include <gsk/gsk.h>
G_BEGIN_DECLS
@@ -47,6 +48,10 @@ void gtk_container_get_children_clip (GtkContainer *container,
void gtk_container_set_default_resize_mode (GtkContainer *container,
GtkResizeMode resize_mode);
void gtk_container_propagate_render_node (GtkContainer *container,
GskRenderer *renderer,
GskRenderNode *parent_node);
G_END_DECLS
#endif /* __GTK_CONTAINER_PRIVATE_H__ */
+9
View File
@@ -161,6 +161,14 @@ gtk_css_custom_gadget_draw (GtkCssGadget *gadget,
return GTK_CSS_GADGET_CLASS (gtk_css_custom_gadget_parent_class)->draw (gadget, cr, x, y, width, height);
}
static gboolean
gtk_css_custom_gadget_has_content (GtkCssGadget *gadget)
{
GtkCssCustomGadgetPrivate *priv = gtk_css_custom_gadget_get_instance_private (GTK_CSS_CUSTOM_GADGET (gadget));
return priv->draw_func != NULL;
}
static void
gtk_css_custom_gadget_finalize (GObject *object)
{
@@ -183,6 +191,7 @@ gtk_css_custom_gadget_class_init (GtkCssCustomGadgetClass *klass)
gadget_class->get_preferred_size = gtk_css_custom_gadget_get_preferred_size;
gadget_class->allocate = gtk_css_custom_gadget_allocate;
gadget_class->draw = gtk_css_custom_gadget_draw;
gadget_class->has_content = gtk_css_custom_gadget_has_content;
}
static void
+166 -1
View File
@@ -67,6 +67,7 @@ struct _GtkCssGadgetPrivate {
GtkWidget *owner;
GtkAllocation allocated_size;
gint allocated_baseline;
GtkAllocation clip;
};
enum {
@@ -242,7 +243,6 @@ gtk_css_gadget_set_property (GObject *object,
}
}
static void
gtk_css_gadget_finalize (GObject *object)
{
@@ -253,6 +253,14 @@ gtk_css_gadget_finalize (GObject *object)
G_OBJECT_CLASS (gtk_css_gadget_parent_class)->finalize (object);
}
static gboolean
gtk_css_gadget_has_content (GtkCssGadget *gadget)
{
GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_GET_CLASS (gadget);
return gadget_class->draw != gtk_css_gadget_real_draw;
}
static void
gtk_css_gadget_class_init (GtkCssGadgetClass *klass)
{
@@ -266,6 +274,7 @@ gtk_css_gadget_class_init (GtkCssGadgetClass *klass)
klass->allocate = gtk_css_gadget_real_allocate;
klass->draw = gtk_css_gadget_real_draw;
klass->style_changed = gtk_css_gadget_real_style_changed;
klass->has_content = gtk_css_gadget_has_content;
properties[PROP_NODE] = g_param_spec_object ("node", "Node",
"CSS node",
@@ -734,6 +743,7 @@ gtk_css_gadget_allocate (GtkCssGadget *gadget,
out_clip->y = 0;
out_clip->width = 0;
out_clip->height = 0;
priv->clip = *out_clip;
return;
}
@@ -798,6 +808,161 @@ gtk_css_gadget_allocate (GtkCssGadget *gadget,
allocation->height - margin.top - margin.bottom,
&tmp_clip))
gdk_rectangle_union (&tmp_clip, out_clip, out_clip);
priv->clip = *out_clip;
}
GskRenderNode *
gtk_css_gadget_get_render_node (GtkCssGadget *gadget,
GskRenderer *renderer,
gboolean draw_focus)
{
GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget);
GtkBorder clip, margin, border, padding;
GtkCssStyle *style;
cairo_t *cr;
GskRenderNode *box_node, *border_node;
graphene_rect_t bounds;
int width, height;
int contents_x, contents_y, contents_width, contents_height;
GtkAllocation margin_box;
GtkAllocation clip_box;
char *str;
if (!gtk_css_gadget_get_visible (gadget))
return NULL;
margin_box = priv->allocated_size;
clip_box = priv->clip;
width = clip_box.width;
height = clip_box.height;
clip.left = margin_box.x - clip_box.x;
clip.top = margin_box.y - clip_box.y;
clip.right = clip_box.width - margin_box.width - clip.left;
clip.bottom = clip_box.height - margin_box.height - clip.top;
if (width < 0 || height < 0)
{
g_warning ("Drawing a gadget with negative dimensions. "
"Did you forget to allocate a size? (node %s owner %s)",
gtk_css_node_get_name (gtk_css_gadget_get_node (gadget)),
G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)));
width = gtk_widget_get_allocated_width (priv->owner);
height = gtk_widget_get_allocated_height (priv->owner);
}
graphene_rect_init (&bounds, 0, 0, width, height);
str = g_strconcat ("Box<", G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)), ">", NULL);
box_node = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_name (box_node, str);
gsk_render_node_set_bounds (box_node, &bounds);
g_free (str);
style = gtk_css_gadget_get_style (gadget);
get_box_margin (style, &margin);
get_box_border (style, &border);
get_box_padding (style, &padding);
gtk_css_style_add_background_render_nodes (style,
renderer,
box_node,
&bounds,
G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)),
clip.left + margin.left,
clip.top + margin.top,
width - clip.left - clip.right - margin.left - margin.right,
height - clip.top - clip.bottom - margin.top - margin.bottom,
gtk_css_node_get_junction_sides (priv->node));
str = g_strconcat ("Border<", G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)), ">", NULL);
border_node = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_name (border_node, str);
gsk_render_node_set_bounds (border_node, &bounds);
cr = gsk_render_node_get_draw_context (border_node);
gtk_css_style_render_border (style,
cr,
clip.left + margin.left,
clip.top + margin.top,
width - clip.left - clip.right - margin.left - margin.right,
height - clip.top - clip.bottom - margin.top - margin.bottom,
0,
gtk_css_node_get_junction_sides (priv->node));
cairo_destroy (cr);
g_free (str);
gsk_render_node_append_child (box_node, border_node);
gsk_render_node_unref (border_node);
contents_x = clip.left + margin.left + border.left + padding.left;
contents_y = clip.top + margin.top + border.top + padding.top;
contents_width = width - clip.left - clip.right - margin.left - margin.right - border.left - border.right - padding.left - padding.right;
contents_height = height - clip.top - clip.bottom - margin.top - margin.bottom - border.top - border.bottom - padding.top - padding.bottom;
if (contents_width > 0 && contents_height > 0)
{
GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_GET_CLASS (gadget);
graphene_rect_t content_bounds =
GRAPHENE_RECT_INIT (0, 0, contents_width, contents_height);
GskRenderNode *content_node = NULL;
graphene_matrix_t content_transform;
graphene_point3d_t tmp;
graphene_matrix_init_translate (&content_transform,
graphene_point3d_init (&tmp, contents_x, contents_y, 0));
/* If there's an override in place, create a temporary node */
if (gadget_class->has_content (gadget))
{
content_node = gsk_renderer_create_render_node (renderer);
str = g_strconcat ("DrawGadgetContent<", G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)), ">", NULL);
gsk_render_node_set_name (content_node, str);
gsk_render_node_set_bounds (content_node, &content_bounds);
gsk_render_node_set_transform (content_node, &content_transform);
cr = gsk_render_node_get_draw_context (content_node);
/* Compatibility mode: draw_focus is left to the draw() implementation */
draw_focus = gadget_class->draw (gadget, cr,
0, 0,
contents_width, contents_height);
g_free (str);
cairo_destroy (cr);
gsk_render_node_append_child (box_node, content_node);
gsk_render_node_unref (content_node);
}
}
if (draw_focus)
{
GskRenderNode *focus_node = gsk_renderer_create_render_node (renderer);
str = g_strconcat ("Focus<", G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget)), ">", NULL);
gsk_render_node_set_name (focus_node, str);
gsk_render_node_set_bounds (focus_node, &bounds);
cr = gsk_render_node_get_draw_context (focus_node);
gtk_css_style_render_outline (style,
cr,
clip.left + margin.left,
clip.top + margin.top,
width - clip.left - clip.right - margin.left - margin.right,
height - clip.top - clip.bottom - margin.top - margin.bottom);
g_free (str);
cairo_destroy (cr);
gsk_render_node_append_child (box_node, focus_node);
gsk_render_node_unref (focus_node);
}
return box_node;
}
/**
+7
View File
@@ -70,6 +70,8 @@ struct _GtkCssGadgetClass
void (* style_changed) (GtkCssGadget *gadget,
GtkCssStyleChange *change);
gboolean (* has_content) (GtkCssGadget *gadget);
};
GType gtk_css_gadget_get_type (void) G_GNUC_CONST;
@@ -125,6 +127,10 @@ void gtk_css_gadget_allocate (GtkCssGadget
void gtk_css_gadget_draw (GtkCssGadget *gadget,
cairo_t *cr);
GskRenderNode * gtk_css_gadget_get_render_node (GtkCssGadget *gadget,
GskRenderer *renderer,
gboolean draw_focus);
void gtk_css_gadget_queue_resize (GtkCssGadget *gadget);
void gtk_css_gadget_queue_allocate (GtkCssGadget *gadget);
void gtk_css_gadget_queue_draw (GtkCssGadget *gadget);
@@ -139,6 +145,7 @@ void gtk_css_gadget_get_content_allocation (GtkCssGadget
GtkAllocation *allocation,
int *baseline);
G_END_DECLS
#endif /* __GTK_CSS_GADGET_PRIVATE_H__ */
+30 -8
View File
@@ -181,8 +181,8 @@ static void gtk_expander_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_expander_map (GtkWidget *widget);
static void gtk_expander_unmap (GtkWidget *widget);
static gboolean gtk_expander_draw (GtkWidget *widget,
cairo_t *cr);
static GskRenderNode *gtk_expander_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
static gboolean gtk_expander_enter_notify (GtkWidget *widget,
GdkEventCrossing *event);
@@ -271,7 +271,7 @@ gtk_expander_class_init (GtkExpanderClass *klass)
widget_class->size_allocate = gtk_expander_size_allocate;
widget_class->map = gtk_expander_map;
widget_class->unmap = gtk_expander_unmap;
widget_class->draw = gtk_expander_draw;
widget_class->get_render_node = gtk_expander_get_render_node;
widget_class->enter_notify_event = gtk_expander_enter_notify;
widget_class->leave_notify_event = gtk_expander_leave_notify;
widget_class->focus = gtk_expander_focus;
@@ -709,13 +709,35 @@ gtk_expander_unmap (GtkWidget *widget)
gtk_widget_unmap (priv->label_widget);
}
static gboolean
gtk_expander_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_expander_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
gtk_css_gadget_draw (GTK_EXPANDER (widget)->priv->gadget, cr);
GskRenderNode *res;
GskRenderNode *node;
return FALSE;
res = gtk_css_gadget_get_render_node (GTK_EXPANDER (widget)->priv->gadget,
renderer,
FALSE);
if (res == NULL)
return NULL;
node = gtk_css_gadget_get_render_node (GTK_EXPANDER (widget)->priv->title_gadget,
renderer,
FALSE);
gsk_render_node_append_child (res, node);
gsk_render_node_unref (node);
node = gtk_css_gadget_get_render_node (GTK_EXPANDER (widget)->priv->arrow_gadget,
renderer,
FALSE);
gsk_render_node_append_child (res, node);
gsk_render_node_unref (node);
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
return res;
}
static void
+40 -50
View File
@@ -382,31 +382,21 @@ gtk_flow_box_child_activate (GtkFlowBoxChild *child)
gtk_flow_box_select_and_activate (box, child);
}
static gboolean
gtk_flow_box_child_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_flow_box_child_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
gtk_css_gadget_draw (CHILD_PRIV (GTK_FLOW_BOX_CHILD (widget))->gadget, cr);
GtkFlowBoxChildPrivate *priv = CHILD_PRIV (widget);
GskRenderNode *res = gtk_css_gadget_get_render_node (priv->gadget,
renderer,
gtk_widget_has_visible_focus (widget));
return FALSE;
}
if (res == NULL)
return NULL;
static gboolean
gtk_flow_box_child_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkWidget *widget;
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
widget = gtk_css_gadget_get_owner (gadget);
GTK_WIDGET_CLASS (gtk_flow_box_child_parent_class)->draw (widget, cr);
return gtk_widget_has_visible_focus (widget);
return res;
}
/* Size allocation {{{3 */
@@ -595,7 +585,7 @@ gtk_flow_box_child_class_init (GtkFlowBoxChildClass *class)
object_class->finalize = gtk_flow_box_child_finalize;
widget_class->draw = gtk_flow_box_child_draw;
widget_class->get_render_node = gtk_flow_box_child_get_render_node;
widget_class->get_request_mode = gtk_flow_box_child_get_request_mode;
widget_class->get_preferred_height = gtk_flow_box_child_get_preferred_height;
widget_class->get_preferred_height_for_width = gtk_flow_box_child_get_preferred_height_for_width;
@@ -642,7 +632,7 @@ gtk_flow_box_child_init (GtkFlowBoxChild *child)
GTK_WIDGET (child),
gtk_flow_box_child_measure,
gtk_flow_box_child_allocate,
gtk_flow_box_child_render,
NULL,
NULL,
NULL);
}
@@ -2627,44 +2617,37 @@ gtk_flow_box_measure (GtkCssGadget *gadget,
/* Drawing {{{3 */
static gboolean
gtk_flow_box_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_flow_box_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
gtk_css_gadget_draw (BOX_PRIV (widget)->gadget, cr);
return FALSE;
}
static gboolean
gtk_flow_box_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
GtkFlowBox *box = GTK_FLOW_BOX (widget);
GtkFlowBoxPrivate *priv = BOX_PRIV (box);
GskRenderNode *res = gtk_css_gadget_get_render_node (priv->gadget,
renderer,
gtk_widget_has_visible_focus (widget));
GTK_WIDGET_CLASS (gtk_flow_box_parent_class)->draw (widget, cr);
if (res == NULL)
return NULL;
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
if (priv->rubberband_first && priv->rubberband_last)
{
GskRenderNode *node;
cairo_t *cr;
GtkStyleContext *context;
GSequenceIter *iter, *iter1, *iter2;
GdkRectangle line_rect, rect;
GArray *lines;
gboolean vertical;
context = gtk_widget_get_style_context (GTK_WIDGET (box));
node = gtk_widget_create_render_node (widget, renderer, "FlowBox RubberBand");
cr = gsk_render_node_get_draw_context (node);
vertical = priv->orientation == GTK_ORIENTATION_VERTICAL;
cairo_save (cr);
context = gtk_widget_get_style_context (widget);
gtk_style_context_save_to_node (context, priv->rubberband_node);
@@ -2729,7 +2712,10 @@ gtk_flow_box_render (GtkCssGadget *gadget,
cairo_save (cr);
cairo_clip (cr);
gtk_render_background (context, cr, x, y, width, height);
gtk_render_background (context, cr,
0, 0,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
cairo_restore (cr);
cairo_append_path (cr, path);
@@ -2748,10 +2734,14 @@ G_GNUC_END_IGNORE_DEPRECATIONS
g_array_free (lines, TRUE);
gtk_style_context_restore (context);
cairo_restore (cr);
cairo_destroy (cr);
gsk_render_node_append_child (res, node);
gsk_render_node_unref (node);
}
return gtk_widget_has_visible_focus (widget);
return res;
}
/* Autoscrolling {{{3 */
@@ -3788,7 +3778,7 @@ gtk_flow_box_class_init (GtkFlowBoxClass *class)
widget_class->realize = gtk_flow_box_realize;
widget_class->unmap = gtk_flow_box_unmap;
widget_class->focus = gtk_flow_box_focus;
widget_class->draw = gtk_flow_box_draw;
widget_class->get_render_node = gtk_flow_box_get_render_node;
widget_class->key_press_event = gtk_flow_box_key_press_event;
widget_class->get_request_mode = gtk_flow_box_get_request_mode;
widget_class->get_preferred_width = gtk_flow_box_get_preferred_width;
@@ -4151,7 +4141,7 @@ gtk_flow_box_init (GtkFlowBox *box)
GTK_WIDGET (box),
gtk_flow_box_measure,
gtk_flow_box_allocate,
gtk_flow_box_render,
NULL,
NULL,
NULL);
}
+19 -40
View File
@@ -126,8 +126,8 @@ static void gtk_frame_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec);
static gboolean gtk_frame_draw (GtkWidget *widget,
cairo_t *cr);
static GskRenderNode * gtk_frame_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
static void gtk_frame_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_frame_remove (GtkContainer *container,
@@ -192,13 +192,6 @@ static void gtk_frame_allocate_border (GtkCssGadget *gadget,
int baseline,
GtkAllocation *out_clip,
gpointer data);
static gboolean gtk_frame_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data);
G_DEFINE_TYPE_WITH_CODE (GtkFrame, gtk_frame, GTK_TYPE_BIN,
@@ -261,7 +254,7 @@ gtk_frame_class_init (GtkFrameClass *class)
g_object_class_install_properties (gobject_class, LAST_PROP, frame_props);
widget_class->draw = gtk_frame_draw;
widget_class->get_render_node = gtk_frame_get_render_node;
widget_class->size_allocate = gtk_frame_size_allocate;
widget_class->get_preferred_width = gtk_frame_get_preferred_width;
widget_class->get_preferred_height = gtk_frame_get_preferred_height;
@@ -319,7 +312,7 @@ gtk_frame_init (GtkFrame *frame)
GTK_WIDGET (frame),
gtk_frame_measure,
gtk_frame_allocate,
gtk_frame_render,
NULL,
NULL,
NULL);
priv->border_gadget = gtk_css_custom_gadget_new ("border",
@@ -705,42 +698,28 @@ gtk_frame_get_shadow_type (GtkFrame *frame)
return frame->priv->shadow_type;
}
static gboolean
gtk_frame_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_frame_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
gtk_css_gadget_draw (GTK_FRAME (widget)->priv->gadget, cr);
return FALSE;
}
static gboolean
gtk_frame_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkWidget *widget;
GtkFramePrivate *priv;
gint xc, yc, w, h;
GtkFramePrivate *priv = GTK_FRAME (widget)->priv;
GtkAllocation allocation;
widget = gtk_css_gadget_get_owner (gadget);
priv = GTK_FRAME (widget)->priv;
cairo_save (cr);
GskRenderNode *node;
cairo_t *cr;
int xc, yc, w, h;
gtk_widget_get_allocation (widget, &allocation);
node = gtk_widget_create_render_node (widget, renderer, "Frame");
cr = gsk_render_node_get_draw_context (node);
/* We want to use the standard gadget drawing for the border,
* so we clip out the label allocation in order to get the
* frame gap.
*/
xc = priv->label_allocation.x - allocation.x;
yc = y;
yc = allocation.y;
w = priv->label_allocation.width;
h = priv->label_allocation.height;
@@ -763,11 +742,11 @@ gtk_frame_render (GtkCssGadget *gadget,
gtk_css_gadget_draw (priv->border_gadget, cr);
cairo_restore (cr);
cairo_destroy (cr);
GTK_WIDGET_CLASS (gtk_frame_parent_class)->draw (widget, cr);
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, node);
return FALSE;
return node;
}
static void
+12 -19
View File
@@ -1704,27 +1704,20 @@ gtk_grid_allocate (GtkCssGadget *gadget,
gtk_container_get_children_clip (GTK_CONTAINER (grid), out_clip);
}
static gboolean
gtk_grid_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
static GskRenderNode *
gtk_grid_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GTK_WIDGET_CLASS (gtk_grid_parent_class)->draw (gtk_css_gadget_get_owner (gadget), cr);
GskRenderNode *res = gtk_css_gadget_get_render_node (GTK_GRID (widget)->priv->gadget,
renderer,
FALSE);
return FALSE;
}
if (res == NULL)
return NULL;
static gboolean
gtk_grid_draw (GtkWidget *widget,
cairo_t *cr)
{
gtk_css_gadget_draw (GTK_GRID (widget)->priv->gadget, cr);
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
return FALSE;
return res;
}
static void
@@ -1744,7 +1737,7 @@ gtk_grid_class_init (GtkGridClass *class)
widget_class->get_preferred_width_for_height = gtk_grid_get_preferred_width_for_height;
widget_class->get_preferred_height_for_width = gtk_grid_get_preferred_height_for_width;
widget_class->get_preferred_height_and_baseline_for_width = gtk_grid_get_preferred_height_and_baseline_for_width;
widget_class->draw = gtk_grid_draw;
widget_class->get_render_node = gtk_grid_get_render_node;
container_class->add = gtk_grid_add;
container_class->remove = gtk_grid_remove;
@@ -1852,7 +1845,7 @@ gtk_grid_init (GtkGrid *grid)
GTK_WIDGET (grid),
gtk_grid_measure,
gtk_grid_allocate,
gtk_grid_render,
NULL,
NULL,
NULL);
+12 -22
View File
@@ -1850,31 +1850,21 @@ gtk_header_bar_set_child_property (GtkContainer *container,
}
}
static gint
gtk_header_bar_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_header_bar_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (GTK_HEADER_BAR (widget));
GskRenderNode *res = gtk_css_gadget_get_render_node (priv->gadget,
renderer,
FALSE);
gtk_css_gadget_draw (priv->gadget, cr);
if (res == NULL)
return NULL;
return FALSE;
}
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
static gboolean
gtk_header_bar_render_contents (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer unused)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
GTK_WIDGET_CLASS (gtk_header_bar_parent_class)->draw (widget, cr);
return FALSE;
return res;
}
static void
@@ -1963,11 +1953,11 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class)
widget_class->get_preferred_height = gtk_header_bar_get_preferred_height;
widget_class->get_preferred_height_for_width = gtk_header_bar_get_preferred_height_for_width;
widget_class->get_preferred_width_for_height = gtk_header_bar_get_preferred_width_for_height;
widget_class->draw = gtk_header_bar_draw;
widget_class->realize = gtk_header_bar_realize;
widget_class->unrealize = gtk_header_bar_unrealize;
widget_class->hierarchy_changed = gtk_header_bar_hierarchy_changed;
widget_class->direction_changed = gtk_header_bar_direction_changed;
widget_class->get_render_node = gtk_header_bar_get_render_node;
container_class->add = gtk_header_bar_add;
container_class->remove = gtk_header_bar_remove;
@@ -2120,7 +2110,7 @@ gtk_header_bar_init (GtkHeaderBar *bar)
GTK_WIDGET (bar),
gtk_header_bar_get_content_size,
gtk_header_bar_allocate_contents,
gtk_header_bar_render_contents,
NULL,
NULL,
NULL);
+36 -37
View File
@@ -155,8 +155,8 @@ struct _GtkImagePrivate
#define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON
static gint gtk_image_draw (GtkWidget *widget,
cairo_t *cr);
static GskRenderNode *gtk_image_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
static void gtk_image_size_allocate (GtkWidget *widget,
GtkAllocation*allocation);
static void gtk_image_unmap (GtkWidget *widget);
@@ -182,13 +182,6 @@ static void gtk_image_get_content_size (GtkCssGadget *gadget,
gint *minimum_baseline,
gint *natural_baseline,
gpointer unused);
static gboolean gtk_image_render_contents (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data);
static void gtk_image_style_updated (GtkWidget *widget);
static void gtk_image_finalize (GObject *object);
@@ -241,7 +234,7 @@ gtk_image_class_init (GtkImageClass *class)
gobject_class->finalize = gtk_image_finalize;
widget_class = GTK_WIDGET_CLASS (class);
widget_class->draw = gtk_image_draw;
widget_class->get_render_node = gtk_image_get_render_node;
widget_class->get_preferred_width = gtk_image_get_preferred_width;
widget_class->get_preferred_height = gtk_image_get_preferred_height;
widget_class->get_preferred_height_and_baseline_for_width = gtk_image_get_preferred_height_and_baseline_for_width;
@@ -424,9 +417,8 @@ gtk_image_init (GtkImage *image)
GTK_WIDGET (image),
gtk_image_get_content_size,
NULL,
gtk_image_render_contents,
NULL,
NULL, NULL);
}
static void
@@ -1704,35 +1696,37 @@ G_GNUC_END_IGNORE_DEPRECATIONS
}
static gboolean
gtk_image_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_image_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
gtk_css_gadget_draw (GTK_IMAGE (widget)->priv->gadget,
cr);
return FALSE;
}
static gboolean
gtk_image_render_contents (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkWidget *widget;
GtkImage *image;
GtkImagePrivate *priv;
GtkImage *image = GTK_IMAGE (widget);
GtkImagePrivate *priv = image->priv;
gint w, h, baseline;
gfloat xalign, yalign;
gint xpad, ypad;
GskRenderNode *res;
GskRenderNode *node;
GtkAllocation alloc, clip;
gint x, y, width, height;
cairo_t *cr;
widget = gtk_css_gadget_get_owner (gadget);
image = GTK_IMAGE (widget);
priv = image->priv;
res = gtk_css_gadget_get_render_node (priv->gadget, renderer, FALSE);
if (res == NULL)
return NULL;
node = gtk_widget_create_render_node (widget, renderer, "Image Content");
gtk_widget_get_clip (widget, &clip);
_gtk_widget_get_allocation (widget, &alloc);
cr = gsk_render_node_get_draw_context (node);
cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y);
x = 0;
y = 0;
width = alloc.width;
height = alloc.height;
_gtk_icon_helper_get_size (priv->icon_helper, &w, &h);
@@ -1765,7 +1759,12 @@ G_GNUC_END_IGNORE_DEPRECATIONS
_gtk_icon_helper_draw (priv->icon_helper, cr, x, y);
}
return FALSE;
cairo_destroy (cr);
gsk_render_node_append_child (res, node);
gsk_render_node_unref (node);
return res;
}
static void
+38 -37
View File
@@ -414,11 +414,12 @@ static void gtk_label_size_allocate (GtkWidget *widget,
static void gtk_label_state_flags_changed (GtkWidget *widget,
GtkStateFlags prev_state);
static void gtk_label_style_updated (GtkWidget *widget);
static gboolean gtk_label_draw (GtkWidget *widget,
cairo_t *cr);
static gboolean gtk_label_focus (GtkWidget *widget,
GtkDirectionType direction);
static GskRenderNode *gtk_label_get_render_node (GtkWidget *label,
GskRenderer *renderer);
static void gtk_label_realize (GtkWidget *widget);
static void gtk_label_unrealize (GtkWidget *widget);
static void gtk_label_map (GtkWidget *widget);
@@ -577,13 +578,6 @@ static void gtk_label_measure (GtkCssGadget *gadget,
int *minimum_baseline,
int *natural_baseline,
gpointer unused);
static gboolean gtk_label_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data);
static GtkBuildableIface *buildable_parent_iface = NULL;
@@ -633,7 +627,7 @@ gtk_label_class_init (GtkLabelClass *class)
widget_class->state_flags_changed = gtk_label_state_flags_changed;
widget_class->style_updated = gtk_label_style_updated;
widget_class->query_tooltip = gtk_label_query_tooltip;
widget_class->draw = gtk_label_draw;
widget_class->get_render_node = gtk_label_get_render_node;
widget_class->realize = gtk_label_realize;
widget_class->unrealize = gtk_label_unrealize;
widget_class->map = gtk_label_map;
@@ -1395,7 +1389,7 @@ gtk_label_init (GtkLabel *label)
GTK_WIDGET (label),
gtk_label_measure,
NULL,
gtk_label_render,
NULL,
NULL,
NULL);
}
@@ -4259,39 +4253,41 @@ gtk_label_get_focus_link (GtkLabel *label)
return NULL;
}
static gboolean
gtk_label_draw (GtkWidget *widget,
cairo_t *cr)
{
gtk_css_gadget_draw (GTK_LABEL (widget)->priv->gadget, cr);
return FALSE;
}
static void layout_to_window_coords (GtkLabel *label,
gint *x,
gint *y);
static gboolean
gtk_label_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
static GskRenderNode *
gtk_label_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GtkWidget *widget;
GtkLabel *label;
GtkLabelPrivate *priv;
GtkLabelSelectionInfo *info;
GtkLabel *label = GTK_LABEL (widget);
GtkLabelPrivate *priv = label->priv;
GtkLabelSelectionInfo *info = priv->select_info;
GtkStyleContext *context;
gint x, y, width, height;
gint lx, ly;
cairo_t *cr;
GtkAllocation alloc, clip;
GskRenderNode *node;
GskRenderNode *res;
widget = gtk_css_gadget_get_owner (gadget);
label = GTK_LABEL (widget);
priv = label->priv;
info = priv->select_info;
res = gtk_css_gadget_get_render_node (priv->gadget, renderer, FALSE);
if (res == NULL)
return NULL;
node = gtk_widget_create_render_node (widget, renderer, "Label Content");
gtk_widget_get_clip (widget, &clip);
_gtk_widget_get_allocation (widget, &alloc);
cr = gsk_render_node_get_draw_context (node);
cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y);
x = 0;
y = 0;
width = alloc.width;
height = alloc.height;
gtk_label_ensure_layout (label);
@@ -4402,7 +4398,12 @@ gtk_label_render (GtkCssGadget *gadget,
}
}
return FALSE;
cairo_destroy (cr);
gsk_render_node_append_child (res, node);
gsk_render_node_unref (node);
return res;
}
static gboolean
+30 -53
View File
@@ -204,8 +204,9 @@ static GSequenceIter* gtk_list_box_get_previous_visible (GtkListBo
GSequenceIter *iter);
static GtkListBoxRow *gtk_list_box_get_first_focusable (GtkListBox *box);
static GtkListBoxRow *gtk_list_box_get_last_focusable (GtkListBox *box);
static gboolean gtk_list_box_draw (GtkWidget *widget,
cairo_t *cr);
static GskRenderNode * gtk_list_box_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
static void gtk_list_box_realize (GtkWidget *widget);
static void gtk_list_box_add (GtkContainer *container,
GtkWidget *widget);
@@ -296,13 +297,6 @@ static void gtk_list_box_allocate (GtkCssGadget *gadget,
int baseline,
GtkAllocation *out_clip,
gpointer data);
static gboolean gtk_list_box_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data);
@@ -421,7 +415,7 @@ gtk_list_box_class_init (GtkListBoxClass *klass)
widget_class->motion_notify_event = gtk_list_box_motion_notify_event;
widget_class->show = gtk_list_box_show;
widget_class->focus = gtk_list_box_focus;
widget_class->draw = gtk_list_box_draw;
widget_class->get_render_node = gtk_list_box_get_render_node;
widget_class->realize = gtk_list_box_realize;
widget_class->compute_expand = gtk_list_box_compute_expand;
widget_class->get_request_mode = gtk_list_box_get_request_mode;
@@ -658,7 +652,7 @@ gtk_list_box_init (GtkListBox *box)
GTK_WIDGET (box),
gtk_list_box_measure,
gtk_list_box_allocate,
gtk_list_box_render,
NULL,
NULL,
NULL);
@@ -2122,29 +2116,22 @@ gtk_list_box_focus (GtkWidget *widget,
return FALSE;
}
static gboolean
gtk_list_box_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_list_box_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
gtk_css_gadget_draw (BOX_PRIV (widget)->gadget, cr);
GtkListBox *box = GTK_LIST_BOX (widget);
GtkListBoxPrivate *priv = BOX_PRIV (box);
GskRenderNode *res = gtk_css_gadget_get_render_node (priv->gadget,
renderer,
FALSE);
return FALSE;
}
if (res == NULL)
return NULL;
static gboolean
gtk_list_box_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
GTK_WIDGET_CLASS (gtk_list_box_parent_class)->draw (widget, cr);
return FALSE;
return res;
}
static void
@@ -3216,31 +3203,21 @@ gtk_list_box_row_hide (GtkWidget *widget)
gtk_list_box_row_visibility_changed (box, row);
}
static gboolean
gtk_list_box_row_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_list_box_row_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
gtk_css_gadget_draw (ROW_PRIV (GTK_LIST_BOX_ROW (widget))->gadget, cr);
GtkListBoxRowPrivate *priv = ROW_PRIV (widget);
GskRenderNode *res = gtk_css_gadget_get_render_node (priv->gadget,
renderer,
gtk_widget_has_visible_focus (widget));
return GDK_EVENT_PROPAGATE;
}
if (res == NULL)
return NULL;
static gboolean
gtk_list_box_row_render (GtkCssGadget *gadget,
cairo_t *cr,
int x,
int y,
int width,
int height,
gpointer data)
{
GtkWidget *widget;
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
widget = gtk_css_gadget_get_owner (gadget);
GTK_WIDGET_CLASS (gtk_list_box_row_parent_class)->draw (widget, cr);
return gtk_widget_has_visible_focus (widget);
return res;
}
static void
@@ -3704,7 +3681,7 @@ gtk_list_box_row_class_init (GtkListBoxRowClass *klass)
widget_class->show = gtk_list_box_row_show;
widget_class->hide = gtk_list_box_row_hide;
widget_class->draw = gtk_list_box_row_draw;
widget_class->get_render_node = gtk_list_box_row_get_render_node;
widget_class->get_preferred_height = gtk_list_box_row_get_preferred_height;
widget_class->get_preferred_height_for_width = gtk_list_box_row_get_preferred_height_for_width;
widget_class->get_preferred_width = gtk_list_box_row_get_preferred_width;
@@ -3773,7 +3750,7 @@ gtk_list_box_row_init (GtkListBoxRow *row)
GTK_WIDGET (row),
gtk_list_box_row_measure,
gtk_list_box_row_allocate,
gtk_list_box_row_render,
NULL,
NULL,
NULL);
gtk_css_gadget_add_class (ROW_PRIV (row)->gadget, "activatable");
+17 -1
View File
@@ -24,6 +24,8 @@
#include "gtkbuildable.h"
#include "gtkscrolledwindow.h"
#include "gtkmarshalers.h"
#include "gtkwidgetprivate.h"
#include "gtkcontainerprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
@@ -483,6 +485,20 @@ gtk_overlay_unmap (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_overlay_parent_class)->unmap (widget);
}
static GskRenderNode *
gtk_overlay_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GskRenderNode *res = gtk_widget_create_render_node (widget, renderer, G_OBJECT_TYPE_NAME (widget));
if (res == NULL)
return NULL;
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, res);
return res;
}
static void
gtk_overlay_remove (GtkContainer *container,
GtkWidget *widget)
@@ -739,7 +755,6 @@ gtk_overlay_get_child_property (GtkContainer *container,
}
}
static void
gtk_overlay_class_init (GtkOverlayClass *klass)
{
@@ -752,6 +767,7 @@ gtk_overlay_class_init (GtkOverlayClass *klass)
widget_class->unrealize = gtk_overlay_unrealize;
widget_class->map = gtk_overlay_map;
widget_class->unmap = gtk_overlay_unmap;
widget_class->get_render_node = gtk_overlay_get_render_node;
container_class->remove = gtk_overlay_remove;
container_class->forall = gtk_overlay_forall;
+145
View File
@@ -428,6 +428,151 @@ gtk_css_style_render_background (GtkCssStyle *style,
cairo_restore (cr);
}
static GskBlendMode
translate_blend_mode (GtkCssBlendMode blend_mode)
{
switch (blend_mode)
{
case GTK_CSS_BLEND_MODE_COLOR_BURN: return GSK_BLEND_MODE_COLOR_BURN;
case GTK_CSS_BLEND_MODE_COLOR_DODGE: return GSK_BLEND_MODE_COLOR_BURN;
case GTK_CSS_BLEND_MODE_DARKEN: return GSK_BLEND_MODE_DARKEN;
case GTK_CSS_BLEND_MODE_LIGHTEN: return GSK_BLEND_MODE_LIGHTEN;
case GTK_CSS_BLEND_MODE_DIFFERENCE: return GSK_BLEND_MODE_DIFFERENCE;
case GTK_CSS_BLEND_MODE_EXCLUSION: return GSK_BLEND_MODE_EXCLUSION;
case GTK_CSS_BLEND_MODE_HARD_LIGHT: return GSK_BLEND_MODE_HARD_LIGHT;
case GTK_CSS_BLEND_MODE_SOFT_LIGHT: return GSK_BLEND_MODE_SOFT_LIGHT;
case GTK_CSS_BLEND_MODE_MULTIPLY: return GSK_BLEND_MODE_MULTIPLY;
case GTK_CSS_BLEND_MODE_NORMAL: return GSK_BLEND_MODE_DEFAULT;
case GTK_CSS_BLEND_MODE_OVERLAY: return GSK_BLEND_MODE_OVERLAY;
case GTK_CSS_BLEND_MODE_SCREEN: return GSK_BLEND_MODE_SCREEN;
case GTK_CSS_BLEND_MODE_SATURATE:
case GTK_CSS_BLEND_MODE_LUMINOSITY:
case GTK_CSS_BLEND_MODE_COLOR:
case GTK_CSS_BLEND_MODE_HUE:
default:
g_warning ("CSS blend mode %d not supported by GSK yet", blend_mode);
return GSK_BLEND_MODE_DEFAULT;
}
}
void
gtk_css_style_add_background_render_nodes (GtkCssStyle *style,
GskRenderer *renderer,
GskRenderNode *parent_node,
graphene_rect_t *bounds,
const char *name,
gdouble x,
gdouble y,
gdouble width,
gdouble height,
GtkJunctionSides junction)
{
GskRenderNode *bg_node;
cairo_t *cr;
GtkCssValue *background_image;
GtkCssValue *blend_modes;
GtkCssValue *box_shadow;
const GdkRGBA *bg_color;
GtkThemingBackground bg;
gchar *str;
gint number_of_layers;
gint idx;
background_image = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_IMAGE);
blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE);
bg_color = _gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_COLOR));
box_shadow = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BOX_SHADOW);
/* This is the common default case of no background */
if (gtk_rgba_is_clear (bg_color) &&
_gtk_css_array_value_get_n_values (background_image) == 1 &&
_gtk_css_image_value_get_image (_gtk_css_array_value_get_nth (background_image, 0)) == NULL &&
_gtk_css_shadows_value_is_none (box_shadow))
return;
bg.style = style;
_gtk_theming_background_init_style (&bg, width, height, junction);
if (!_gtk_css_shadows_value_is_none (box_shadow))
{
str = g_strconcat ("Outer Shadow<", name, ">", NULL);
bg_node = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_name (bg_node, str);
gsk_render_node_set_bounds (bg_node, bounds);
cr = gsk_render_node_get_draw_context (bg_node);
cairo_translate (cr, x, y);
_gtk_css_shadows_value_paint_box (box_shadow,
cr,
&bg.boxes[GTK_CSS_AREA_BORDER_BOX],
FALSE);
cairo_destroy (cr);
g_free (str);
gsk_render_node_append_child (parent_node, bg_node);
gsk_render_node_unref (bg_node);
}
if (!gtk_rgba_is_clear (bg_color))
{
str = g_strconcat ("Background Color<", name, ">", NULL);
bg_node = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_name (bg_node, str);
gsk_render_node_set_bounds (bg_node, bounds);
cr = gsk_render_node_get_draw_context (bg_node);
cairo_translate (cr, x, y);
_gtk_theming_background_paint_color (&bg, cr, bg_color, background_image);
cairo_destroy (cr);
g_free (str);
gsk_render_node_append_child (parent_node, bg_node);
gsk_render_node_unref (bg_node);
}
number_of_layers = _gtk_css_array_value_get_n_values (background_image);
for (idx = number_of_layers - 1; idx >= 0; idx--)
{
GtkCssBlendMode blend_mode;
blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx));
str = g_strdup_printf ("Background%d<%s>", idx, name);
bg_node = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_blend_mode (bg_node,
translate_blend_mode (blend_mode));
gsk_render_node_set_name (bg_node, str);
gsk_render_node_set_bounds (bg_node, bounds);
cr = gsk_render_node_get_draw_context (bg_node);
cairo_translate (cr, x, y);
_gtk_theming_background_paint_layer (&bg, idx, cr, GTK_CSS_BLEND_MODE_NORMAL);
cairo_destroy (cr);
g_free (str);
gsk_render_node_append_child (parent_node, bg_node);
gsk_render_node_unref (bg_node);
}
if (!_gtk_css_shadows_value_is_none (box_shadow))
{
str = g_strconcat ("Inner Shadow<", name, ">", NULL);
bg_node = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_name (bg_node, str);
gsk_render_node_set_bounds (bg_node, bounds);
cr = gsk_render_node_get_draw_context (bg_node);
cairo_translate (cr, x, y);
_gtk_css_shadows_value_paint_box (box_shadow,
cr,
&bg.boxes[GTK_CSS_AREA_PADDING_BOX],
TRUE);
cairo_destroy (cr);
g_free (str);
gsk_render_node_append_child (parent_node, bg_node);
gsk_render_node_unref (bg_node);
}
}
static gboolean
corner_value_is_right_angle (GtkCssValue *value)
{
+12
View File
@@ -25,6 +25,7 @@
#include "gtkcsstypesprivate.h"
#include "gtktypes.h"
#include "gsk/gsk.h"
G_BEGIN_DECLS
@@ -36,6 +37,17 @@ void gtk_css_style_render_background (GtkCssStyle
gdouble height,
GtkJunctionSides junction);
gboolean gtk_css_style_render_background_is_opaque (GtkCssStyle *style);
void gtk_css_style_add_background_render_nodes (GtkCssStyle *style,
GskRenderer *renderer,
GskRenderNode *parent_node,
graphene_rect_t *bounds,
const char *name,
gdouble x,
gdouble y,
gdouble width,
gdouble height,
GtkJunctionSides junction);
G_END_DECLS
+7 -7
View File
@@ -123,13 +123,13 @@ gtk_spinner_size_allocate (GtkWidget *widget,
gtk_widget_set_clip (widget, &clip);
}
static gboolean
gtk_spinner_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_spinner_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
gtk_css_gadget_draw (GTK_SPINNER (widget)->priv->gadget, cr);
return FALSE;
return gtk_css_gadget_get_render_node (GTK_SPINNER (widget)->priv->gadget,
renderer,
FALSE);
}
static void
@@ -204,7 +204,7 @@ gtk_spinner_class_init (GtkSpinnerClass *klass)
widget_class = GTK_WIDGET_CLASS(klass);
widget_class->size_allocate = gtk_spinner_size_allocate;
widget_class->draw = gtk_spinner_draw;
widget_class->get_render_node = gtk_spinner_get_render_node;
widget_class->get_preferred_width = gtk_spinner_get_preferred_width;
widget_class->get_preferred_height = gtk_spinner_get_preferred_height;
+145 -15
View File
@@ -17449,28 +17449,161 @@ 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_create_render_node (GtkWidget *widget,
GskRenderer *renderer,
const char *name)
{
GskRenderNode *res = gsk_renderer_create_render_node (renderer);
GtkAllocation clip;
graphene_rect_t bounds;
gtk_widget_get_clip (widget, &clip);
graphene_rect_init (&bounds, 0, 0, clip.width, clip.height);
gsk_render_node_set_name (res, name);
gsk_render_node_set_bounds (res, &bounds);
return res;
}
GskRenderNode *
gtk_widget_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS (widget);
GskRenderNode *node;
graphene_matrix_t m;
graphene_point3d_t p;
graphene_rect_t bounds;
GtkAllocation clip;
GtkAllocation alloc;
if (_gtk_widget_get_alloc_needed (widget))
return NULL;
gtk_widget_get_clip (widget, &clip);
_gtk_widget_get_allocation (widget, &alloc);
graphene_rect_init (&bounds, 0, 0, clip.width, clip.height);
graphene_matrix_init_translate (&m, graphene_point3d_init (&p, clip.x, clip.y, 0.f));
/* Compatibility mode: if the widget does not have a render node, we draw
* using gtk_widget_draw() on a temporary node
*/
if (klass->get_render_node == NULL)
{
GskRenderNode *tmp;
cairo_t *cr;
char *str;
str = g_strconcat ("Fallback<", G_OBJECT_TYPE_NAME (widget), ">", NULL);
tmp = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_name (tmp, str);
gsk_render_node_set_bounds (tmp, &bounds);
gsk_render_node_set_transform (tmp, &m);
cr = gsk_render_node_get_draw_context (tmp);
cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y);
gtk_widget_draw_internal (widget, cr, TRUE);
cairo_destroy (cr);
g_free (str);
node = tmp;
}
else
{
node = klass->get_render_node (widget, renderer);
/* Compatibility mode: if there's a ::draw signal handler, we add a
* child node with the contents of the handler
*/
if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
{
GskRenderNode *tmp;
gboolean result;
cairo_t *cr;
char *str;
str = g_strconcat ("DrawSignal<", G_OBJECT_TYPE_NAME (widget), ">", NULL);
tmp = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_name (tmp, str);
gsk_render_node_set_bounds (tmp, &bounds);
cr = gsk_render_node_get_draw_context (tmp);
cairo_translate (cr, alloc.x - clip.x, alloc.y - clip.y);
g_signal_emit (widget, widget_signals[DRAW], 0, cr, &result);
cairo_destroy (cr);
g_free (str);
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.
@@ -17480,15 +17613,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);
}
+4 -1
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);
};
+7
View File
@@ -302,6 +302,13 @@ void gtk_widget_render (GtkWidget
const cairo_region_t *region);
GskRenderNode * gtk_widget_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
GskRenderNode * gtk_widget_create_render_node (GtkWidget *widget,
GskRenderer *renderer,
const char *name);
/* inline getters */
static inline gboolean
+120 -69
View File
@@ -30,11 +30,13 @@
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <graphene.h>
#include "gtkprivate.h"
#include "gtkwindowprivate.h"
#include "gtkaccelgroupprivate.h"
#include "gtkbindings.h"
#include "gtkcontainerprivate.h"
#include "gtkcsscornervalueprivate.h"
#include "gtkcssiconthemevalueprivate.h"
#include "gtkcssrgbavalueprivate.h"
@@ -271,6 +273,8 @@ struct _GtkWindowPrivate
GdkWindow *hardcoded_window;
GtkCssNode *decoration_node;
GskRenderer *renderer;
};
static const GtkTargetEntry dnd_dest_targets [] = {
@@ -454,8 +458,8 @@ static void gtk_window_real_activate_focus (GtkWindow *window);
static void gtk_window_keys_changed (GtkWindow *window);
static gboolean gtk_window_enable_debugging (GtkWindow *window,
gboolean toggle);
static gint gtk_window_draw (GtkWidget *widget,
cairo_t *cr);
static GskRenderNode *gtk_window_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
static void gtk_window_unset_transient_for (GtkWindow *window);
static void gtk_window_transient_parent_realized (GtkWidget *parent,
GtkWidget *window);
@@ -713,7 +717,6 @@ gtk_window_class_init (GtkWindowClass *klass)
widget_class->focus_out_event = gtk_window_focus_out_event;
widget_class->focus = gtk_window_focus;
widget_class->move_focus = gtk_window_move_focus;
widget_class->draw = gtk_window_draw;
widget_class->window_state_event = gtk_window_state_event;
widget_class->get_preferred_width = gtk_window_get_preferred_width;
widget_class->get_preferred_width_for_height = gtk_window_get_preferred_width_for_height;
@@ -721,6 +724,7 @@ gtk_window_class_init (GtkWindowClass *klass)
widget_class->get_preferred_height_for_width = gtk_window_get_preferred_height_for_width;
widget_class->state_flags_changed = gtk_window_state_flags_changed;
widget_class->style_updated = gtk_window_style_updated;
widget_class->get_render_node = gtk_window_get_render_node;
container_class->remove = gtk_window_remove;
container_class->check_resize = gtk_window_check_resize;
@@ -7157,6 +7161,12 @@ gtk_window_realize (GtkWidget *widget)
_gtk_widget_get_allocation (widget, &allocation);
if (priv->renderer == NULL)
{
priv->renderer = gsk_renderer_get_for_display (gtk_widget_get_display (widget));
gsk_renderer_set_scale_factor (priv->renderer, gtk_widget_get_scale_factor (widget));
}
if (gtk_widget_get_parent_window (widget))
{
gtk_container_set_default_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT);
@@ -7180,6 +7190,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;
}
@@ -7273,6 +7286,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);
attributes.x = allocation.x;
attributes.y = allocation.y;
attributes.width = allocation.width;
@@ -7393,6 +7409,9 @@ gtk_window_realize (GtkWidget *widget)
}
check_scale_changed (window);
/* Renderer */
gsk_renderer_realize (priv->renderer);
}
static void
@@ -7420,6 +7439,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.
@@ -7567,6 +7589,18 @@ _gtk_window_set_allocation (GtkWindow *window,
child_allocation.width = allocation->width;
child_allocation.height = allocation->height;
if (priv->renderer != NULL)
{
graphene_rect_t viewport;
int scale;
scale = gtk_widget_get_scale_factor (widget);
gsk_renderer_set_scale_factor (priv->renderer, scale);
graphene_rect_init (&viewport, 0, 0, allocation->width, allocation->height);
gsk_renderer_set_viewport (priv->renderer, &viewport);
}
get_shadow_width (window, &window_border);
if (_gtk_widget_get_realized (widget))
@@ -10088,98 +10122,107 @@ gtk_window_compute_hints (GtkWindow *window,
* Redrawing functions *
***********************/
static gboolean
gtk_window_draw (GtkWidget *widget,
cairo_t *cr)
static GskRenderNode *
gtk_window_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
{
GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
GtkStyleContext *context;
gboolean ret = FALSE;
GskRenderNode *node;
GtkAllocation allocation;
GtkBorder window_border;
gint title_height;
graphene_rect_t bounds;
graphene_matrix_t m;
graphene_point3d_t p;
cairo_t *cr;
context = gtk_widget_get_style_context (widget);
get_shadow_width (GTK_WINDOW (widget), &window_border);
_gtk_widget_get_allocation (widget, &allocation);
if (gtk_cairo_should_draw_window (cr, _gtk_widget_get_window (widget)))
graphene_rect_init (&bounds, allocation.x, allocation.y, allocation.width, allocation.height);
graphene_matrix_init_translate (&m, graphene_point3d_init (&p, allocation.x, allocation.y, 0.));
node = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_name (node, "Window Decoration");
gsk_render_node_set_bounds (node, &bounds);
gsk_render_node_set_transform (node, &m);
cr = gsk_render_node_get_draw_context (node);
if (priv->client_decorated &&
priv->decorated &&
!priv->fullscreen &&
!priv->maximized)
{
if (priv->client_decorated &&
priv->decorated &&
!priv->fullscreen &&
!priv->maximized)
gtk_style_context_save_to_node (context, priv->decoration_node);
if (priv->use_client_shadow)
{
gtk_style_context_save_to_node (context, priv->decoration_node);
GtkBorder padding, border;
if (priv->use_client_shadow)
{
GtkBorder padding, border;
gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
gtk_style_context_get_border (context, gtk_style_context_get_state (context), &border);
sum_borders (&border, &padding);
gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
gtk_style_context_get_border (context, gtk_style_context_get_state (context), &border);
sum_borders (&border, &padding);
gtk_render_background (context, cr,
window_border.left - border.left, window_border.top - border.top,
allocation.width -
(window_border.left + window_border.right - border.left - border.right),
allocation.height -
(window_border.top + window_border.bottom - border.top - border.bottom));
gtk_render_frame (context, cr,
window_border.left - border.left, window_border.top - border.top,
allocation.width -
(window_border.left + window_border.right - border.left - border.right),
allocation.height -
(window_border.top + window_border.bottom - border.top - border.bottom));
}
else
{
gtk_render_background (context, cr, 0, 0,
allocation.width,
allocation.height);
gtk_render_frame (context, cr, 0, 0,
allocation.width,
allocation.height);
}
gtk_style_context_restore (context);
gtk_render_background (context, cr,
window_border.left - border.left, window_border.top - border.top,
allocation.width -
(window_border.left + window_border.right - border.left - border.right),
allocation.height -
(window_border.top + window_border.bottom - border.top - border.bottom));
gtk_render_frame (context, cr,
window_border.left - border.left, window_border.top - border.top,
allocation.width -
(window_border.left + window_border.right - border.left - border.right),
allocation.height -
(window_border.top + window_border.bottom - border.top - border.bottom));
}
if (!gtk_widget_get_app_paintable (widget))
else
{
if (priv->title_box &&
gtk_widget_get_visible (priv->title_box) &&
gtk_widget_get_child_visible (priv->title_box))
title_height = priv->title_height;
else
title_height = 0;
gtk_render_background (context, cr, 0, 0,
allocation.width,
allocation.height);
gtk_render_background (context, cr,
window_border.left,
window_border.top + title_height,
allocation.width -
(window_border.left + window_border.right),
allocation.height -
(window_border.top + window_border.bottom +
title_height));
gtk_render_frame (context, cr,
gtk_render_frame (context, cr, 0, 0,
allocation.width,
allocation.height);
}
gtk_style_context_restore (context);
}
if (!gtk_widget_get_app_paintable (widget))
{
if (priv->title_box &&
gtk_widget_get_visible (priv->title_box) &&
gtk_widget_get_child_visible (priv->title_box))
title_height = priv->title_height;
else
title_height = 0;
gtk_render_background (context, cr,
window_border.left,
window_border.top + title_height,
allocation.width -
(window_border.left + window_border.right),
(window_border.left + window_border.right),
allocation.height -
(window_border.top + window_border.bottom +
title_height));
}
(window_border.top + window_border.bottom + title_height));
gtk_render_frame (context, cr,
window_border.left,
window_border.top + title_height,
allocation.width -
(window_border.left + window_border.right),
allocation.height -
(window_border.top + window_border.bottom + title_height));
}
if (GTK_WIDGET_CLASS (gtk_window_parent_class)->draw)
ret = GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr);
cairo_destroy (cr);
return ret;
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, node);
return node;
}
/**
@@ -12640,3 +12683,11 @@ void
gtk_window_unexport_handle (GtkWindow *window)
{
}
GskRenderer *
gtk_window_get_renderer (GtkWindow *window)
{
GtkWindowPrivate *priv = window->priv;
return priv->renderer;
}
+2
View File
@@ -146,6 +146,8 @@ gboolean gtk_window_export_handle (GtkWindow *window,
gpointer user_data);
void gtk_window_unexport_handle (GtkWindow *window);
GskRenderer *gtk_window_get_renderer (GtkWindow *window);
G_END_DECLS
#endif /* __GTK_WINDOW_PRIVATE_H__ */
+3
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) \
+1 -1
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
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