This is a complete overhaul of the data structures used to manage
CoglMaterial state.
We have these requirements that were aiming to meet:
(Note: the references to "renderlists" correspond to the effort to
support scenegraph level shuffling of Clutter actor primitives so we can
minimize GPU state changes)
Sparse State:
We wanted a design that allows sparse descriptions of state so it scales
well as we make CoglMaterial responsible for more and more state. It
needs to scale well in terms of memory usage and the cost of operations
we need to apply to materials such as comparing, copying and flushing
their state. I.e. we would rather have these things scale by the number
of real changes a material represents not by how much overall state
CoglMaterial becomes responsible for.
Cheap Copies:
As we add support for renderlists in Clutter we will need to be able to
get an immutable handle for a given material's current state so that we
can retain a record of a primitive with its associated material without
worrying that changes to the original material will invalidate that
record.
No more flush override options:
We want to get rid of the flush overrides mechanism we currently use to
deal with texture fallbacks, wrap mode changes and to handle the use of
highlevel CoglTextures that need to be resolved into lowlevel textures
before flushing the material state.
The flush options structure has been expanding in size and the structure
is logged with every journal entry so it is not an approach that scales
well at all. It also makes flushing material state that much more
complex.
Weak Materials:
Again for renderlists we need a way to create materials derived from
other materials but without the strict requirement that modifications to
the original material wont affect the derived ("weak") material. The
only requirement is that its possible to later check if the original
material has been changed.
A summary of the new design:
A CoglMaterial now basically represents a diff against its parent.
Each material has a single parent and a mask of state that it changes.
Each group of state (such as the blending state) has an "authority"
which is found by walking up from a given material through its ancestors
checking the difference mask until a match for that group is found.
There is only one root node to the graph of all materials, which is the
default material first created when Cogl is being initialized.
All the groups of state are divided into two types, such that
infrequently changed state belongs in a separate "BigState" structure
that is only allocated and attached to a material when necessary.
CoglMaterialLayers are another sparse structure. Like CoglMaterials they
represent a diff against their parent and all the layers are part of
another graph with the "default_layer_0" layer being the root node that
Cogl creates during initialization.
Copying a material is now basically just a case of slice allocating a
CoglMaterial, setting the parent to be the source being copied and
zeroing the mask of changes.
Flush overrides should now be handled by simply relying on the cheapness
of copying a material and making changes to it. (This will be done in a
follow on commit)
Weak material support will be added in a follow on commit.
As part of an effort to improve the architecture of CoglMaterial
internally this overhauls how we flush layer state to OpenGL by adding a
formal backend abstraction for fragment processing and further
formalizing the CoglTextureUnit abstraction.
There are three backends: "glsl", "arbfp" and "fixed". The fixed backend
uses the OpenGL fixed function APIs to setup the fragment processing,
the arbfp backend uses code generation to handle fragment processing
using an ARBfp program, and the GLSL backend is currently only there as
a formality to handle user programs associated with a material. (i.e.
the glsl backend doesn't yet support code generation)
The GLSL backend has highest precedence, then arbfp and finally the
fixed. If a backend can't support some particular CoglMaterial feature
then it will fallback to the next backend.
This adds three new COGL_DEBUG options:
* "disable-texturing" as expected should disable all texturing
* "disable-arbfp" always make the arbfp backend fallback
* "disable-glsl" always make the glsl backend fallback
* "show-source" show code generated by the arbfp/glsl backends
The Cogl context has now a feature_flags_private enum that will allow us
to query and use OpenGL features without exposing them in the public
API.
The ARB_fragment_program extension is the first user of those flags.
Looking for this extension only happens in the gl driver as the gles
drivers will not expose them.
One can use _cogl_features_available_private() to check for the
availability of such private features.
While at it, reindent cogl-internal.h as described in CODING_STYLE.
It's valid C to declare a function omitting it prototype, but it seems
to be a good practise to always declare a function with its
corresponding prototype.
Since the default alpha test function of GL_ALWAYS is equivalent to
GL_ALPHA_TEST being disabled we don't need to worry about Enabling/Disabling
it when flushing material state, instead it's enough to leave it always
enabled. We will assume that any driver worth its salt wont incur any
additional cost for glEnable (GL_ALPHA_TEST) + GL_ALWAYS vs
glDisable (GL_ALPHA_TEST).
This patch simply calls glEnable (GL_ALPHA_TEST) in cogl_create_context
Instead of directly using a guint32 to store a bitmask for each used
texcoord array, it now stores them in a CoglBitmask. This removes the
limitation of 32 layers (although there are still other places in Cogl
that imply this restriction). To disable texcoord arrays code should
call _cogl_disable_other_texcoord_arrays which takes a bitmask of
texcoord arrays that should not be disabled. There are two extra
bitmasks stored in the CoglContext which are used temporarily for this
function to avoid allocating a new bitmask each time.
http://bugzilla.openedhand.com/show_bug.cgi?id=2132
It should be quite acceptable to use a texture without defining any
texture coords. For example a shader may be in use that is doing
texture lookups without referencing the texture coordinates. Also it
should be possible to replace the vertex colors using a texture layer
without a texture but with a constant layer color.
enable_state_for_drawing_buffer no longer sets any disabled layers in
the overrides. Instead of counting the number of units with texture
coordinates it now keeps them in a mask. This means there can now be
gaps in the list of enabled texture coordinate arrays. To cope with
this, the Cogl context now also stores a mask to track the enabled
arrays. Instead of code manually iterating each enabled array to
disable them, there is now an internal function called
_cogl_disable_texcoord_arrays which disables a given mask.
I think this could also fix potential bugs when a vertex buffer has
gaps in the texture coordinate attributes that it provides. For
example if the vertex buffer only had texture coordinates for layer 2
then the disabling code would not disable the coordinates for layers 0
and 1 even though they are not used. This could cause a crash if the
previous data for those arrays is no longer valid.
http://bugzilla.openedhand.com/show_bug.cgi?id=2132
Instead of using cogl_get_bitmasks() to query the GL machinery for the
size of the color bits, we should store the values inside the
CoglFramebuffer object and query them the first time we set the framebuffer
as the current one.
Currently, cogl_get_bitmasks() is re-implemented in terms of
cogl_framebuffer_get_*_bits(). As soon as we are able to expose the
CoglOnscreen framebuffer object in the public API we'll be able to
deprecate cogl_get_bitmasks() altogether.
http://bugzilla.openedhand.com/show_bug.cgi?id=2094
This adds three new API calls:
CoglHandle cogl_path_get()
void cogl_path_set(CoglHandle path)
CoglHandle cogl_path_copy(CoglHandle path)
All of the fields relating to the path have been moved from the Cogl
context to a new CoglPath handle type. The cogl context now just
contains a CoglPath handle. All of the existing path commands
manipulate the data in the current path handle. cogl_path_new now just
creates a new path handle and unrefs the old one.
The path handle can be stored for later with cogl_path_get. The path
can then be copied with cogl_path_copy. Internally it implements
copy-on-write semantics with an extra optimisation that it will only
copy the data if the new path is modified, but not if the original
path is modified. It can do this because the only way to modify a path
is by appending to it so the copied path is able to store its own path
length and only render the nodes up to that length. For this to work
the copied path also needs to keep its own copies of the path extents
because the parent path may change these by adding nodes.
The clip stack now uses the cogl_path_copy mechanism to store paths in
the stack instead of directly copying the data. This should save some
memory and processing time.
Every now and then someone sees the cogl_enable API and gets confused,
thinking its public API so this renames the symbol to be clear that it's
is an internal only API.
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
The function _cogl_get_max_texture_units is called quite often while
rendering and it returns a constant value so we might as well cache
the result. Calling glGetInteger on Mesa can be expensive because it
flushes a lot of state.
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
Buffer objects are cool! This abstracts the buffer API first introduced
by GL_ARB_vertex_buffer_object and then extended to other objects.
The coglBuffer abstract class is intended to be the base class of all
the buffer objects, letting the user map() buffers. If the underlying
implementation does not support buffer objects (or only support VBO but
not FBO for instance), fallback paths should be provided.
The internal format of the atlas texture is still set to the
appropriate format so Cogl will disable blending for textures that are
intended to be RGB. This should end up ignoring the alpha channel from
the texture in the atlas. This makes the code slightly easier to
maintain and should also improve the chances of batching.
This adds a CoglAtlas type which is a data structure that keeps track
of unused sub rectangles of a larger rectangle. There is a new atlased
texture backend which uses this to put multiple textures into a single
larger texture.
Currently the atlas is always sized 256x256 and the textures are never
moved once they are put in. Eventually it needs to be able to
reorganise the atlas and grow it if necessary. It also needs to
migrate the textures out of the atlas if mipmaps are required.
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.
cogl_material_copy can be used to create a new CoglHandle referencing a copy
of some given material.
From now on we will advise that developers always aim to use this function
instead of cogl_material_new() when creating a material that is in any way
derived from another.
By using cogl_material_copy, Cogl can maintain an ancestry for each material
and keep track of "similar" materials. The plan is that Cogl will use this
information to minimize the cost of GPU state transitions.
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.
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.
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.
Cogl's support for offscreen rendering was originally written just to support
the clutter_texture_new_from_actor API and due to lack of documentation and
several confusing - non orthogonal - side effects of using the API it wasn't
really possible to use directly.
This commit does a number of things:
- It removes {gl,gles}/cogl-fbo.{c,h} and adds shared cogl-draw-buffer.{c,h}
files instead which should be easier to maintain.
- internally CoglFbo objects are now called CoglDrawBuffers. A
CoglDrawBuffer is an abstract base class that is inherited from to
implement CoglOnscreen and CoglOffscreen draw buffers. CoglOffscreen draw
buffers will initially be used to support the
cogl_offscreen_new_to_texture API, and CoglOnscreen draw buffers will
start to be used internally to represent windows as we aim to migrate some
of Clutter's backend code to Cogl.
- It makes draw buffer objects the owners of the following state:
- viewport
- projection matrix stack
- modelview matrix stack
- clip state
(This means when you switch between draw buffers you will automatically be
switching to their associated viewport, matrix and clip state)
Aside from hopefully making cogl_offscreen_new_to_texture be more useful
short term by having simpler and well defined semantics for
cogl_set_draw_buffer, as mentioned above this is the first step for a couple
of other things:
- Its a step toward moving ownership for windows down from Clutter backends
into Cogl, by (internally at least) introducing the CoglOnscreen draw
buffer. Note: the plan is that cogl_set_draw_buffer will accept on or
offscreen draw buffer handles, and the "target" argument will become
redundant since we will instead query the type of the given draw buffer
handle.
- Because we have a common type for on and offscreen framebuffers we can
provide a unified API for framebuffer management. Things like:
- blitting between buffers
- managing ancillary buffers (e.g. attaching depth and stencil buffers)
- size requisition
- clearing
The indirection through this API isn't necessary since we no longer
arbitrate between the OpenGL matrix API and Cogl's client side API. Also it
doesn't help to maintain an OpenGL style matrix mode API for internal use
since it's awkward to keep restoring the MODELVIEW mode and easy enough to
directly work with the matrix stacks of interest.
This replaces use of the _cogl_current_matrix API with direct use of the
_cogl_matrix_stack API. All the unused cogl_current_matrix API is removed
and the matrix utility code left in cogl-current-matrix.c was moved to
cogl.c.
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 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.
The Journal can be considered a standalone component, so even though
it's currently only used to log quads, it seems better to split it
out into its own file.
cogl-texture-2d-sliced provides an implementation of CoglTexture and this
seperation lays the foundation for potentially supporting atlas textures,
pixmap textures (as in GLX_EXT_texture_from_pixmap) and fast-path
GL_TEXTURE_{1D,2D,3D,RECTANGLE} textures in a maintainable fashion.
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.