For a long time now the GLES driver for Cogl has supported a fallback
scanline rasterizer for filling paths when no stencil buffer is available,
but now that we build the same cogl-primitives code for GL and GLES I
thought it may sometimes be useful for debugging to force Cogl to use the
scanline rasterizer instead of the current stencil buffer approach.
The build for interactive tests creates symbolic links for the data
under tests/data; it also uses symbolic links for creating "binaries"
for each interactive test. This is less than ideal, though.
Instead, the tests should build a path to the data files by using
a pre-processor define like TESTS_DATADIR; both g_build_filename() and
pre-processor string concatenation can be used to generate a valid
file name with the full path to the files.
The build system should also create wrapper scripts, just like we
do inside the conformance test suite, to be able to launch single
tests.
In order to know if a layout property exists and retrieve its
description in form of a GParamSpec, we need a wrapper API inside
ClutterLayoutManager. This allows introspecting a LayoutManager
sub-class and eventually serialize and deserialize it.
The ClutterScript parser needs to be extended to parse child properties
and apply them after an actor has been added to a container. In order to
distinguish child properties from regular GObject properties we can use
the "child::" prefix, e.g.:
{
"type" : "ClutterRectangle",
"id" : "child-01",
"child::has-focus" : true,
...
}
Parsing child properties can be deferred to the ClutterScriptable
interface, just like regular properties.
These files were practically identical, except the gles code had additional
support for filling paths without a stencil buffer. All the driver code has
now been moved into cogl/cogl-primitives.c
All the ClutterColor parsing rules should be coalesced inside
clutter_script_parse_color(): object, array and string notations
are the canonical ways of defining a ClutterColor inside a
ClutterScript definition. Having a single function in charge of
the parsing cleans up the code.
Currently, ClutterScriptParser will construct the object (using the
construct-only and construct parameters), apply the properties from
the ClutterScript definition, and eventuall will add children and
behaviours.
The construction phase should be more compartimentalized: the objects
should be constructed first and eventual children and behaviours
added. Then, once an object is requested or when the parsing process
has terminated, all the properties should be applied.
This change allows us to set up the actors before setting their
non-construct properties.
ClutterScript is currently a mix of parser-related code and
the ClutterScript object. All the parser-related code should
be moved inside a private class, ClutterScriptParser, inheriting
from JsonParser.
ClutterScript is a very complicated piece of machinery, with a
parser that has custom variations on top of the basic JSON
format; it could also be extended in the future, so if we don't
want to introduce regressions or break existing ClutterScript
definitions, we'd better have a conformance test suite.
The units under the conformance test suite should be able to use
external files. Linking the files in tests/conform like the
interactive tests do seems like a hack piled on top of a hack, so
instead we should provide a programmatic way for a conformance
test unit to get the full path of a file, regardless of where the
tests/data directory is.
We can use a define to get the full path of tests/data and then
a function using g_build_filename() to construct the path to the
file we want.
Instead of counting on a JsonNode pointer to survive we should take
a copy. This allows keeping unresolved properties across different
ClutterScript passes.
* cogl-reorg-draw-buffers: (38 commits)
[test-fbo] greatly simplify the test
[tests] test-backface-culling: test culling with offscreen rendering
[tests] Adds test-cogl-readpixels.c for very basic cogl_read_pixels testing
[tests] Adds test-cogl-offscreen to validate offscreen draw buffer
[tests] test-cogl-viewport tests semantics of over/under size viewports
[test-texture-fbo] comment the colors defined in corner_colors
Add a conformance test for clutter_texture_new_from_actor
[cogl-texture-2d-sliced] allow COGL_FORMAT_ANY with _new_with_size()
[texture] fix rounding when calculating update_fbo viewport offset
[texture] switch to a new design for handling offscreen rendering
[texture] split out fbo update code from cluter_texture_paint
[texture] push/pop draw buffer when painting actors to a texture
[texture] Avoid redundant use of cogl_clip_stack_save when drawing offscreen
[cogl-draw-buffer] fix Cogl -> GL viewport coord conversion
[cogl_clip_push_window_rect] fix Cogl -> GL coordinate conversion
[matrix] Adds cogl_matrix_get_inverse API
[debug] Adds a COGL_DEBUG=matrices debug option
[cogl-matrix] Import Mesa's matrix manipulation code
[cogl] avoid any state changes when cogl_set_backface_culling_enable is a nop
[cogl] Use clockwise face winding for offscreen buffers with culling enabled
...
This test tried to do too much, and I can't remember the last time I saw this
test work.
It no longer tries to create a texture from an offscreen actor and it no
longer tries to use shaders.
It does though show that chaining of clutter_texture_new_from_actor now
works, and that animating the source actor is reflected in textures created
from it.
When run you should see three actors:
- on the left is the pristine source actor rotating around the y-axis
- in the middle is the first texture created from the source actor
- and on the right a texture created from the middle actor
Note: the somewhat strange bobbing of the middle and right textures is
actually correct given how it was decided long ago to map the transformed
(to screen space) allocation of the source actor to the texture. When the
hand spins around the perspective projection of the top of the hand results
in the origin of the texture bobbing up to a higher stage position, but the
position of the textures is fixed. This design also means we end up
reallocating our offscreen draw buffer every frame that the actors
transformed size changes, which isn't ideal.
Since offscreen rendering is internally forced to be upside down Cogl
needs to reverse the glFrontFace winding order so as not to interfere
with the use of cogl_set_backface_culling_enabled()
This ensures we test that mechanism.
Mostly this was written to verify that we don't flip the data read back from
an offscreen draw buffer. (since all offscreen rendering is done upside
down)
This adds a basic test to check that rendering a few colored rectangles
offscreen works and that the modelview gets restored when switching back to
the previous buffer.
Unlike OpenGL Cogl puts the origin of windows/viewports at the top left
instead of bottom left. This test verifies that we correctly translate Cogl
viewports to OpenGL viewports for the awkward cases where the given viewport
has an offset and/or the viewport has a different size to the current draw
buffer.
It helps to be able to quickly glance at the definition to see which
quadrant of the test actor should be which color, so when debugging a
problem and looking at the visual output you can easily verify if it's being
flipped upside down/left to right.
This contains four tests :-
- A regular onscreen source with a clone next to it
- An offscreen source with a clone. This is currently commented out
because it no longer works.
- An onscreen source with a rectangular clip and a clone.
- An onscreen source with a clip from a path and a clone.
The sources are all a 2x2 grid of colors. Each clone is tested that it
either contains the color that should be at that grid position or that
the stage color is showing through if the source is clipped.
It's useful when initialzing offscreen draw buffers to be able to ask
Cogl to create a texture of a given size and with the default internal
pixel format.
When rendering to an fbo for supporting clutter_texture_new_from_actor we
render to an fbo with the same size as the source actor, but with a viewport
the same size as the stage. We offset the viewport so when we render the
source actor in its normal transformed stage position it lands on the fbo.
Previously we were rounding the transformed position given as a float by
truncating the fraction (just using a C cast) but that resulted in an
incorrect pixel offset when rendering offscreen depending on the source
position.
We now simply + 0.5 before casting (or -0.5 for negative numbers)
For supporting clutter_texture_new_from_actor(): when updating a
ClutterTexture's fbo we previously set up an offset frustum in the
perspective matrix before rendering source actors to an offscreen draw
buffer so as to give a perspective as if it were being drawn at its
original stage location.
Now that Cogl supports offset viewports there is a simpler way...
When we come to render the source actor to our offscreen draw buffer we
now copy the projection matrix from the stage; we create a viewport
that's also the same size as the stage (though larger than the offscreen
draw buffer) and as before we apply the modelview transformations of
the source actors ancestry before painting it.
The only trick we need now is to offset the viewport according to the
transformed (to screen space) allocation of the source actor (something we
required previously too). We negatively offset the stage sized viewport
such that the smaller offscreen draw buffer is positioned to sit underneath
the source actor in stage coordinates.
To help keep clutter_texture_paint maintainable this splits out a big
chunk of standalone code that's responsible for updating the fbo when
clutter_texture_new_from_actor has been used.
When updating the FBO for a source actor (to support
clutter_texture_new_from_actor()) we used to simply set an offscreen draw
buffer to be current, paint the source actor and then explicitly set the
window to be current again. This precluded chaining texture_new_from_actor
though because updating another FBO associated with a source actor would end
up restoring the window as the current buffer instead of the previous
offscreen buffer. Now that we use Cogl's draw buffer stack; chaining
clutter_texture_new_from_actor() should be possible.
Before we call glViewport we need to convert Cogl viewport coordinates
(where the origin is defined to be top left) to OpenGL coordinates
(where the origin is defined to be bottom left)
We weren't considering that offscreen rendering is always upside down
and in this case Cogl coordinates == OpenGL coordinates.
Firstly this now uses the draw buffer height not the viewport height
when we need to perform a y = height - y conversion, since (as the
name suggests) we are dealing with window coordinates not viewport
coordinates.
Secondly this skips any conversion when the current draw buffer is an
offscreen draw buffer since offscreen rendering is always forced to be
upside down and in this case Cogl window coordinates == GL window
coordinates.
This new API takes advantage of the recently imported Mesa code to support
inverse matrix calculation. The matrix code keeps track (via internal
flags) of the transformations a matrix represents so that it can select an
optimized inversion function.
Note: although other aspects of the Cogl matrix API have followed a similar
style to Cairo's matrix API we haven't added a cogl_matrix_invert API
because the inverse of a CoglMatrix is actually cached as part of the
CoglMatrix structure meaning a destructive API like cogl_matrix_invert
doesn't let users take advantage of this caching design.
This adds a COGL_DEBUG=matrices debug option that can be used to trace all
matrix manipulation done using the Cogl API. This can be handy when you
break something in such a way that a trace is still comparable with a
previous working version since you can simply diff a log of the broken
version vs the working version to home in on the bug.
This pulls in code from Mesa to improve our matrix manipulation support. It
includes support for calculating the inverse of matrices based on top of a
matrix categorizing system that allows optimizing certain matrix types.
(the main thing we were after) but also adds some optimisations for
rotations.
Changes compared to the original code from Mesa:
- Coding style is consistent with the rest of Cogl
- Instead of allocating matrix->m and matrix->inv using malloc, our public
CoglMatrix typedef is large enough to directly contain the matrix, its
inverse, a type and a set of flags.
- Instead of having a _math_matrix_analyse which updates the type, flags and
inverse, we have _math_matrix_update_inverse which essentially does the
same thing (internally making use of _math_matrix_update_type_and_flags())
but with additional guards in place to bail out when the inverse matrix is
still valid.
- When initializing a matrix with the identity matrix we don't immediately
initialize the inverse matrix; rather we just set the dirty flag for the
inverse (since it's likely the user won't request the inverse of the
identity matrix)
Because Cogl defines the origin for texture as top left and offscreen draw
buffers can be used to render to textures, we (internally) force all
offscreen rendering to be upside down. (because OpenGL defines the origin
to be bottom left)
By forcing the users scene to be rendered upside down though we also reverse
the winding order of all the drawn triangles which may interfere with the
users use of backface culling. This patch ensures that we reverse the
winding order for a front face (if culling is in use) while rendering
offscreen so we don't conflict with the users back face culling.
The debugging function read_pixels_to_file() and _clutter_do_pick were both
directly calling glReadPixels, but we don't wan't Clutter making direct
OpenGL calls and Cogl provides a suitable alternative. It also means
read_pixels_to_file() doesn't need to manually flip the data read due to
differences in Clutter/Cogl coordinate systems.
Technically this change shouldn't make a difference since we are
calling glReadPixels with GL_RGBA GL_UNSIGNED_BYTE which is a 4
byte format and it should always result in the same value according
to how OpenGL calculates the location of sequential rows.
i.e. k = a/s * ceil(snl/a) where:
a = alignment
s = component size (1)
n = number of components per pixel (4)
l = number of pixels in a row
gives:
k = 4/1 * ceil(4l/4) and k = 1/1 * ceil(4l/1) which are equivalent
I'm changing it because I've seen i915 driver code that bails out of
hardware accelerated paths if the alignment isn't 1, and because
conceptually we have no alignment constraints here so even if the current
value has no effect, when we start reading back other formats it may upset
things.
We were previously calling cogl_flush() after setting up the glPixelStore
state for calling glReadPixels, but flushing the journal could itself
change the glPixelStore state.
Since offscreen rendering is forced to be upside down we don't need to do
any conversion of the users coordinates to go from Cogl window coordinates
to OpenGL window coordinates.
Since we do all offscreen rendering upside down (so that we can have the
origin for texture coordinates be the top left of textures for the cases
where offscreen draw buffers are bound to textures) we don't need to flip
data read back from an offscreen framebuffer before we we return it to the
user.
I was originally expecting the code not to handle offset viewports or
viewports with a different size to the framebuffer, but it turns out the
code worked fine. In the process though I think I made the code slightly
more readable.
cogl_viewport only accepted a viewport width and height, but there are times
when it's also desireable to have a viewport offset so that a scene can be
translated after projection but before hitting the framebuffer.
Because Cogl defines the origin of viewport and window coordinates to be
top-left it always needs to know the size of the current window so that Cogl
window/viewport coordinates can be transformed into OpenGL coordinates.
This also fixes cogl_read_pixels to use the current draw buffer height
instead of the viewport height to determine the OpenGL y coordinate to use
for glReadPixels.