This adds a new CoglDriver for GL 3 called COGL_DRIVER_GL3. When
requested, the GLX, EGL and SDL2 winsyss will set the necessary
attributes to request a forward-compatible core profile 3.1 context.
That means it will have no deprecated features.
To simplify the explosion of checks for specific combinations of
context->driver, many of these conditionals have now been replaced
with private feature flags that are checked instead. The GL and GLES
drivers now initialise these private feature flags depending on which
driver is used.
The fixed function backends now explicitly check whether the fixed
function private feature is available which means the GL3 driver will
fall back to always using the GLSL progend. Since Rob's latest patches
the GLSL progend no longer uses any fixed function API anyway so it
should just work.
The driver is currently lower priority than COGL_DRIVER_GL so it will
not be used unless it is specificly requested. We may want to change
this priority at some point because apparently Mesa can make some
memory savings if a core profile context is used.
In GL 3, getting the combined extensions string with glGetString is
deprecated so this patch changes it to use glGetStringi to build up an
array of extensions instead. _cogl_context_get_gl_extensions now
returns this array instead of trying to return a const string. The
caller is expected to free the array.
Some issues with this patch:
• GL 3 does not support GL_ALPHA format textures. We should probably
make this a feature flag or something. Cogl uses this to render text
which currently just throws a GL error and breaks so it's pretty
important to do something about this before considering the GL3
driver to be stable.
• GL 3 doesn't support client side vertex buffers. This probably
doesn't matter because CoglBuffer won't normally use malloc'd
buffers if VBOs are available, but it might but worth making
malloc'd buffers a private feature and forcing it not to use them.
• GL 3 doesn't support the default vertex array object. This patch
just makes it create and bind a single non-default vertex array
object which gets used just like the normal default object. Ideally
it would be good to use vertex array objects properly and attach
them to a CoglPrimitive to cache the state.
Reviewed-by: Robert Bragg <robert@linux.intel.com>
(cherry picked from commit 66c9db993595b3a22e63f4c201ea468bc9b88cb6)
Previously if an application does not use the matrix stack as a stack
but instead just loads its own matrices for each frame using
cogl_framebuffer_set_modelview_matrix then it will continously push
OP_LOAD entries on the stack and the stack will grow forever. This
patch fixes that use case by resetting the top of the stack to the
last save entry whenever something is pushed that replaces the
previous matrix on the stack.
Reviewed-by: Robert Bragg <robert@linux.intel.com>
(cherry picked from commit d31ed33241a9e9e3bc25f01b2614678827a7a9aa)
This adds the following new functions to apply a rotation described by
a euler or a quaternion to either a CoglMatrix or directly to the
modelview stack of a framebuffer:
cogl_matrix_rotate_quaternion
cogl_matrix_rotate_euler
cogl_framebuffer_rotate_quaternion
cogl_framebuffer_rotate_euler
The direct framebuffer functions have corresponding functions in the
CoglMatrixStack to store an entry describing the rotation.
Reviewed-by: Robert Bragg <robert@linux.intel.com>
(cherry picked from commit 5064315678b496395e1d01f266f322d73e55e324)
The _cogl_matrix_entry_equal function has a large switch statement to
do the right kind of comparison for the entry. However most of the
entries have a return statement that is only conditionally reached.
There were no corresponding break statements to the case labels so
presumably if the comparison succeeded for the correct entry type it
would also flow through and try the comparison for the next type which
would be extremely unlikely to pass.
Reviewed-by: Robert Bragg <robert@linux.intel.com>
(cherry picked from commit 339db0f9cc3ee2bee4c56f9cb05dcb4ddd6815ed)
This re-designs the matrix stack so we now keep track of each separate
operation such as rotating, scaling, translating and multiplying as
immutable, ref-counted nodes in a graph.
Being a "graph" here means that different transformations composed of
a sequence of linked operation nodes may share nodes.
The first node in a matrix-stack is always a LOAD_IDENTITY operation.
As an example consider if an application where to draw three rectangles
A, B and C something like this:
cogl_framebuffer_scale (fb, 2, 2, 2);
cogl_framebuffer_push_matrix(fb);
cogl_framebuffer_translate (fb, 10, 0, 0);
cogl_framebuffer_push_matrix(fb);
cogl_framebuffer_rotate (fb, 45, 0, 0, 1);
cogl_framebuffer_draw_rectangle (...); /* A */
cogl_framebuffer_pop_matrix(fb);
cogl_framebuffer_draw_rectangle (...); /* B */
cogl_framebuffer_pop_matrix(fb);
cogl_framebuffer_push_matrix(fb);
cogl_framebuffer_set_modelview_matrix (fb, &mv);
cogl_framebuffer_draw_rectangle (...); /* C */
cogl_framebuffer_pop_matrix(fb);
That would result in a graph of nodes like this:
LOAD_IDENTITY
|
SCALE
/ \
SAVE LOAD
| |
TRANSLATE RECTANGLE(C)
| \
SAVE RECTANGLE(B)
|
ROTATE
|
RECTANGLE(A)
Each push adds a SAVE operation which serves as a marker to rewind too
when a corresponding pop is issued and also each SAVE node may also
store a cached matrix representing the composition of all its ancestor
nodes. This means if we repeatedly need to resolve a real CoglMatrix
for a given node then we don't need to repeat the composition.
Some advantages of this design are:
- A single pointer to any node in the graph can now represent a
complete, immutable transformation that can be logged for example
into a journal. Previously we were storing a full CoglMatrix in
each journal entry which is 16 floats for the matrix itself as well
as space for flags and another 16 floats for possibly storing a
cache of the inverse. This means that we significantly reduce
the size of the journal when drawing lots of primitives and we also
avoid copying over 128 bytes per entry.
- It becomes much cheaper to check for equality. In cases where some
(unlikely) false negatives are allowed simply comparing the pointers
of two matrix stack graph entries is enough. Previously we would use
memcmp() to compare matrices.
- It becomes easier to do comparisons of transformations. By looking
for the common ancestry between nodes we can determine the operations
that differentiate the transforms and use those to gain a high level
understanding of the differences. For example we use this in the
journal to be able to efficiently determine when two rectangle
transforms only differ by some translation so that we can perform
software clipping.
Reviewed-by: Neil Roberts <neil@linux.intel.com>
(cherry picked from commit f75aee93f6b293ca7a7babbd8fcc326ee6bf7aef)
The coding style has for a long time said to avoid using redundant glib
data types such as gint or gchar etc because we feel that they make the
code look unnecessarily foreign to developers coming from outside of the
Gnome developer community.
Note: When we tried to find the historical rationale for the types we
just found that they were apparently only added for consistent syntax
highlighting which didn't seem that compelling.
Up until now we have been continuing to use some of the platform
specific type such as gint{8,16,32,64} and gsize but this patch switches
us over to using the standard c99 equivalents instead so we can further
ensure that our code looks familiar to the widest range of C developers
who might potentially contribute to Cogl.
So instead of using the gint{8,16,32,64} and guint{8,16,32,64} types this
switches all Cogl code to instead use the int{8,16,32,64}_t and
uint{8,16,32,64}_t c99 types instead.
Instead of gsize we now use size_t
For now we are not going to use the c99 _Bool type and instead we have
introduced a new CoglBool type to use instead of gboolean.
Reviewed-by: Neil Roberts <neil@linux.intel.com>
(cherry picked from commit 5967dad2400d32ca6319cef6cb572e81bf2c15f0)
If the matrix was reallocated we would use values from the stack
for the matrix parameters. This fixes that and also uses the
function instead of out of lining the same code.
https://bugzilla.gnome.org/show_bug.cgi?id=671985
Reviewed-by: Robert Bragg <robert@linux.intel.com>
Reviewed-by: Neil Roberts <neil@linux.intel.com>
Some of the state when flushing a pipeline depends on the current
framebuffer being used. These are:
• The matrix stack, so that it can flip vertically or not depending on
whether the framebuffer is offscreen.
• The colormask. This is combined with the framebuffer's color mask.
• The cull face mode. If the framebuffer is offscreen then backface
culling is translated to frontface culling and vice-versa.
These states were not working if the new framebuffer draw_primitive
API was used because in that case the framebuffer is not pushed to the
framebuffer stack so it would use the wrong one. This patch changes it
to use ctx->current_draw_buffer which is a pointer to the framebuffer
whose state was last flushed.
https://bugzilla.gnome.org/show_bug.cgi?id=670793
Reviewed-by: Robert Bragg <robert@linux.intel.com>
The cogl.h header is meant to be the public header for including the 1.x
api used by Clutter so we should stop using that as a convenient way to
include all likely prototypes and typedefs. Actually we already do a
good job of listing the specific headers we depend on in each of the .c
files we have so mostly this patch just strip out the redundant
includes for cogl.h with a few fixups where that broke the build.
Reviewed-by: Neil Roberts <neil@linux.intel.com>
Previously flushing the matrices was performed as part of the
framebuffer state. When on GLES2 this matrix flushing is actually
diverted so that it only keeps a reference to the intended matrix
stack. This is necessary because on GLES2 there are no builtin
uniforms so it can't actually flush the matrices until the program for
the pipeline is generated. When the matrices are flushed it would
store the age of modifications on the matrix stack so that it could
detect when the matrix hasn't changed and avoid flushing it.
This patch changes it so that the pipeline is responsible for flushing
the matrices even when we are using the GL builtins. The same
mechanism for detecting unmodified matrix stacks is used in all
cases. There is a new CoglMatrixStackCache type which is used to store
a reference to the intended matrix stack along with its last flushed
age. There are now two of these attached to the CoglContext to track
the flushed state for the global matrix builtins and also two for each
glsl progend program state to track the flushed state for a
program. The framebuffer matrix flush now just updates the intended
matrix stacks without actually trying to flush.
When a vertex snippet is attached to the pipeline, the GLSL vertend
will now avoid using the projection matrix to flip the rendering. This
is necessary because any vertex snippet may cause the projection
matrix not to be used. Instead the flip is done as a forced final step
by multiplying cogl_position_out by a vec4 uniform. This uniform is
updated as part of the progend pre_paint depending on whether the
framebuffer is offscreen or not.
Reviewed-by: Robert Bragg <robert@linux.intel.com>
The aim is to make cogl-framebuffer.c responsible for avoiding redundant
flushing of its matrix stacks so this removes the checks done directly
within cogl-matrix-stack.c.
Reviewed-by: Neil Roberts <neil@linux.intel.com>
This removes the use of _COGL_GET_CONTEXT() from cogl-matrix-stack.c
as part of the ongoing effort to evolve cogl to get rid of the need for
a default context.
Reviewed-by: Neil Roberts <neil@linux.intel.com>
The GL or GLES library is now dynamically loaded by the CoglRenderer
so that it can choose between GL, GLES1 and GLES2 at runtime. The
library is loaded by the renderer because it needs to be done before
calling eglInitialize. There is a new environment variable called
COGL_DRIVER to choose between gl, gles1 or gles2.
The #ifdefs for HAVE_COGL_GL, HAVE_COGL_GLES and HAVE_COGL_GLES2 have
been changed so that they don't assume the ifdefs are mutually
exclusive. They haven't been removed entirely so that it's possible to
compile the GLES backends without the the enums from the GL headers.
When using GLX the winsys additionally dynamically loads libGL because
that also contains the GLX API. It can't be linked in directly because
that would probably conflict with the GLES API if the EGL is
selected. When compiling with EGL support the library links directly
to libEGL because it doesn't contain any GL API so it shouldn't have
any conflicts.
When building for WGL or OSX Cogl still directly links against the GL
API so there is a #define in config.h so that Cogl won't try to dlopen
the library.
Cogl-pango previously had a #ifdef to detect when the GL backend is
used so that it can sneakily pass GL_QUADS to
cogl_vertex_buffer_draw. This is now changed so that it queries the
CoglContext for the backend. However to get this to work Cogl now
needs to export the _cogl_context_get_default symbol and cogl-pango
needs some extra -I flags to so that it can include
cogl-context-private.h
cogl-ext-functions.h now contains definitions for all of the core GL
and GLES functions that we would normally link to directly. All of the
code has changed to access them through the cogl context pointer. The
GE macro now takes an extra parameter to specify the context because
the macro itself needs to make GL calls but various points in the Cogl
source use different names for the context variable.
This renames the two internal functions _cogl_get_draw/read_buffer
as cogl_get_draw_framebuffer and _cogl_get_read_framebuffer. The
former is now also exposed as experimental API.
The current framebuffer is now internally separated so that there can
be a different draw and read buffer. This is required to use the
GL_EXT_framebuffer_blit extension. The current draw and read buffers
are stored as a pair in a single stack so that pushing the draw and
read buffer is done simultaneously with the new
_cogl_push_framebuffers internal function. Calling
cogl_pop_framebuffer will restore both the draw and read buffer to the
previous state. The public cogl_push_framebuffer function is layered
on top of the new function so that it just pushes the same buffer for
both drawing and reading.
When flushing the framebuffer state, the cogl_framebuffer_flush_state
function now tackes a pointer to both the draw and the read
buffer. Anywhere that was just flushing the state for the current
framebuffer with _cogl_get_framebuffer now needs to call both
_cogl_get_draw_buffer and _cogl_get_read_buffer.
Once the GLES2 wrapper is removed we won't be able to upload the
matrices with the fixed function API any more. The fixed function API
gives a global state for setting the matrix but if a custom shader
uniform is used for the matrices then the state is per
program. _cogl_matrix_stack_flush_to_gl is called in a few places and
it is assumed the current pipeline doesn't need to be flushed before
it is called. To allow these semantics to continue to work, on GLES2
the matrix flush now just stores a reference to the matrix stack in
the CoglContext. A pre_paint virtual is added to the progend which is
called whenever a pipeline is flushed, even if the same pipeline was
flushed already. This gives the GLSL progend a chance to upload the
matrices to the uniforms. The combined modelview/projection matrix is
only calculated if it is used. The generated programs end up never
using the modelview or projection matrix so it usually only has to
upload the combined matrix. When a matrix stack is flushed a reference
is taked to it by the pipeline progend and the age is stored so that
if the same state is used with the same program again then we don't
need to reupload the uniform.
Sometimes it would be useful if we could efficiently track when a matrix
stack has been modified. For example on GLES2 we have to upload the
modelview as a uniform to our glsl programs but because the modelview
state is part of the framebuffer state it becomes a bit more tricky to
know when to re-sync the value of the uniform with the framebuffer
state. This adds an "age" counter to CoglMatrixStack which is
incremented for any operation that effectively modifies the top of the
stack so now we can save the age of the stack inside the pipeline
whenever we update modelview uniform and later compare that with the
stack to determine if it has changed.
In some micro-benchmarks testing journal throughput the list
manipulation jumps pretty high in the profile. This replaces the GSList
usage with a GArray instead which is effectively a grow only allocation
that means we avoid ongoing allocations while manipulating the stack
mid-scene.
Since using addresses that might change is something that finally
the FSF acknowledge as a plausible scenario (after changing address
twice), the license blurb in the source files should use the URI
for getting the license in case the library did not come with it.
Not that URIs cannot possibly change, but at least it's easier to
set up a redirection at the same place.
As a side note: this commit closes the oldes bug in Clutter's bug
report tool.
http://bugzilla.openedhand.com/show_bug.cgi?id=521
cogl_push_draw_buffer, cogl_set_draw_buffer and cogl_pop_draw_buffer are now
deprecated and new code should use the new cogl_framebuffer_* API instead.
Code that previously did:
cogl_push_draw_buffer ();
cogl_set_draw_buffer (COGL_OFFSCREEN_BUFFER, buffer);
/* draw */
cogl_pop_draw_buffer ();
should now be re-written as:
cogl_push_framebuffer (buffer);
/* draw */
cogl_pop_framebuffer ();
As can be seen from the example above the rename has been used as an
opportunity to remove the redundant target argument from
cogl_set_draw_buffer; it now only takes one call to redirect to an offscreen
buffer, and finally the term framebuffer may be a bit more familiar to
anyone coming from an OpenGL background.
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.
First a few notes about Cogl coordinate systems:
- Cogl defines the window origin, viewport origin and texture coordinates
origin to be top left unlike OpenGL which defines them as bottom left.
- Cogl defines the modelview and projection identity matrices in exactly the
same way as OpenGL.
- I.e. we believe that for 2D centric constructs: windows/framebuffers,
viewports and textures developers are more used to dealing with a top left
origin, but when modeling objects in 3D; an origin at the center with y
going up is quite natural.
The way Cogl handles textures is by uploading data upside down in OpenGL
terms so that bottom left becomes top left. (Note: This also has the
benefit that we don't need to flip the data we get from image decoding
libraries since they typically also consider top left to be the image
origin.)
The viewport and window coords are mostly handled with various y =
height - y tweaks before we pass y coordinates to OpenGL.
Generally speaking though the handling of coordinate spaces in Cogl is a bit
fragile. I guess partly because none of it was design to be, it just
evolved from how Clutter defines its coordinates without much consideration
or testing. I hope to improve this over a number of commits; starting here.
This commit deals with the fact that offscreen draw buffers may be bound to
textures but we don't "upload" the texture data upside down, and so if you
texture from an offscreen draw buffer you need to manually flip the texture
coordinates to get it the right way around. We now force offscreen
rendering to be flipped upside down by tweaking the projection matrix right
before we submit it to OpenGL to scale y by -1. The tweak is entirely
hidden from the user such that if you call cogl_get_projection you will not
see this scale.
This cache of the gl matrix mode lets us avoid repeat calls to glMatrixMode
in _cogl_matrix_stack_flush_to_gl when we have lots of sequential modelview
matrix modifications.
This goes a bit further than the previous patch, and as a special case
we now simply represent identity matrices using a boolean, and only
lazily initialize them when they need to be modified.
The journal always uses an identity matrix since it uses software
transformation. Currently it manually uses glLoadMatrix since previous
experimentation showed that the cogl-matrix-stack gave bad performance, but
it would be nice to fix performance so we only have to care about one path
for loading matrices.
For the common case where we do:
cogl_matrix_stack_push()
cogl_matrix_stack_load_identity()
we were effectively initializing the matrix 3 times. Once due to use of
g_slice_new0, then we had a cogl_matrix_init_identity in
_cogl_matrix_state_new for good measure, and then finally in
cogl_matrix_stack_load_identity we did another cogl_matrix_init_identity.
We don't use g_slice_new0 anymore, _cogl_matrix_state_new is documented as
not initializing the matrix (instead _cogl_matrix_stack_top_mutable now
takes a boolean to choose if new stack entries should be initialised) and so
we now only initialize once in cogl_matrix_stack_load_identity.
This relates back to an earlier commitment to stop using the OpenGL matrix
API which is considered deprecated. (ref 54159f5a1d)
The new texture matrix stacks are hung from a list of (internal only)
CoglTextureUnit structures which the CoglMaterial code internally references
via _cogl_get_texure_unit ().
So we would be left with only the cogl-matrix-stack code being responsible
for glMatrixMode, glLoadMatrix and glLoadIdentity this commit updates the
journal code so it now uses the matrix-stack API instead of GL directly.
As part of an incremental process to have Cogl be a standalone project we
want to re-consider how we organise the Cogl source code.
Currently this is the structure I'm aiming for:
cogl/
cogl/
<put common source here>
winsys/
cogl-glx.c
cogl-wgl.c
driver/
gl/
gles/
os/ ?
utils/
cogl-fixed
cogl-matrix-stack?
cogl-journal?
cogl-primitives?
pango/
The new winsys component is a starting point for migrating window system
code (i.e. x11,glx,wgl,osx,egl etc) from Clutter to Cogl.
The utils/ and pango/ directories aren't added by this commit, but they are
noted because I plan to add them soon.
Overview of the planned structure:
* The winsys/ API is the API that binds OpenGL to a specific window system,
be that X11 or win32 etc. Example are glx, wgl and egl. Much of the logic
under clutter/{glx,osx,win32 etc} should migrate here.
* Note there is also the idea of a winsys-base that may represent a window
system for which there are multiple winsys APIs. An example of this is
x11, since glx and egl may both be used with x11. (currently only Clutter
has the idea of a winsys-base)
* The driver/ represents a specific varient of OpenGL. Currently we have "gl"
representing OpenGL 1.4-2.1 (mostly fixed function) and "gles" representing
GLES 1.1 (fixed funciton) and 2.0 (fully shader based)
* Everything under cogl/ should fundamentally be supporting access to the
GPU. Essentially Cogl's most basic requirement is to provide a nice GPU
Graphics API and drawing a line between this and the utility functionality
we add to support Clutter should help keep this lean and maintainable.
* Code under utils/ as suggested builds on cogl/ adding more convenient
APIs or mechanism to optimize special cases. Broadly speaking you can
compare cogl/ to OpenGL and utils/ to GLU.
* clutter/pango will be moved to clutter/cogl/pango
How some of the internal configure.ac/pkg-config terminology has changed:
backendextra -> CLUTTER_WINSYS_BASE # e.g. "x11"
backendextralib -> CLUTTER_WINSYS_BASE_LIB # e.g. "x11/libclutter-x11.la"
clutterbackend -> {CLUTTER,COGL}_WINSYS # e.g. "glx"
CLUTTER_FLAVOUR -> {CLUTTER,COGL}_WINSYS
clutterbackendlib -> CLUTTER_WINSYS_LIB
CLUTTER_COGL -> COGL_DRIVER # e.g. "gl"
Note: The CLUTTER_FLAVOUR and CLUTTER_COGL defines are kept for apps
As the first thing to take advantage of the new winsys component in Cogl;
cogl_get_proc_address() has been moved from cogl/{gl,gles}/cogl.c into
cogl/common/cogl.c and this common implementation first trys
_cogl_winsys_get_proc_address() but if that fails then it falls back to
gmodule.