Você está na página 1de 31

Introduction to COGL

GNOME tech talks 3rd.


ChangSeok Oh (shivamidow@gmail.com)

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

COGL is ...
A modern 3D graphics APIs + Some useful utility APIs.
Direct state access API design, as opposed to the state-machine style of OpenGL.
Implemented in C language, but will provide several other languages binding.
Basic information about COGL project.
- Reference manual
http://developer.gnome.org/cogl/1.9/
- Wiki
http://wiki.clutter-project.org/wiki/Cogl
- Getting the source
git clone git://git.gnome.org/cogl
git clone http://git.gnome.org/browse/cogl
- Browse:
http://git.gnome.org/browse/cogl
- Mailing list
http://lists.freedesktop.org/mailman/listinfo/cogl
- Cogl Bugzilla
https://bugzilla.gnome.org/enter_bug.cgi?product=cogl

Features

COGL is built on OpenGL


The COGL project is started to solve the problem of developing OpenGL programming, but COGL still
runs on OpenGL since the OpenGL is an open standard supported on many platforms.
Eventually the aim is to break down that OpenGL abstraction so that Cogl can drive the GPU more
directly.
Current Supportting OpenGL coverage.
- OpenGL 1.x ~ 3.x
- OpenGLES 1.x ~ 2.x

One open source implementation


Better platform integration.
One place to go when we need to fix bugs and add features.
Applied the recent trend like simplified GL API.
Built in utilities like matrix manipulation.
Easy to maintain.

Direct state access model


Cogl encapsulates state in objects so that writing orthogonal drawing routines is easy. This is in
contrast to OpenGL's fairly flat state machine model which is difficult to share.
But the object model implementation is very low-fi, we don't for instance use GObject as we want the
API to be palatable to the widest range of high level framework/toolkit/application developers.

Math utilities
Cogl provides an optimized matrix stack API that can internally classify matrices so as to optimize
operations such as invert.
Cogl also provides Eular, Quaternion and Vector APIs to simplify the development of complex 3D
applications.

Framebuffer management
Cogl is able to provide a consistent framebuffer API to manage both on and off screen framebuffers in
a way not possible with OpenGL.
Framebuffers in Cogl own the projection matrix, the viewport state, a modelview matrix stack and a
clip stack. Each framebuffer can have optional ancillary buffers attached such as color, depth and
stencil buffer.

Textures
Native textures
These are the low level textures that the hardware understands.
Meta textures
These are high level textures that allow us to define virtual textures comprised of native textures. We
use these to support slice textures, sub-textures, atlas textures and texture-from pixmap textures.
Here's an overview of the some of these meta texture types:
Sliced textures
Cogl supports textures larger than your hardware limits by "slicing" into multiple GPU
textures. Sliced textures can also be used with GPUs only supporting power-of-two
textures to avoid wasting memory.
Atlas textures
Cogl can pack multiple textures into one large GPU texture so we can avoid repeatedly
binding new textures and forcing us to split our geometry into multiple draw commands.
Sub textures
Cogl allows you to create textures derived from sub-regions of other textures, similar to
OpenVG child images.

Adaptable clipping API


Cogl can optimize clipping depending on the complexity of your clip regions.
The GPU's scissoring hardware can be used for screen aligned rectangles; clip planes can be used for
non screen aligned rectangles and the stencil buffer can be used for complex shaped clips

Pipelines
Cogl separates geometry from the GPU processing pipeline including vertex transform, rasterizing, per
fragment processing, depth testing and blending.
CoglPipelines encapsulate all the state to setup a GPU pipeline - this can be compared to a full GL
context. Internally CoglPipeline is designed as a sparse representation of state though so they have
some interesting properties including being extremely cheap to copy and compare.
Unlike OpenGL where you would avoid creating multiple GL contexts with Cogl you wouldn't think
twice about copying a pipeline from a template and tweaking it to draw something.
Shaders
Cogl provides access to GLSL shaders for advanced fragment and vertex shading effects. We are
also working on a new framework to allow you to hook into small sections of the pipeline with shader
snippets and also provide portability across multiple versions of GLSL.

Optimized vertex data for GPU


Cogl allows you to map vertices directly into your GPU and reference these vertex buffers for very
efficient redrawing of complex models. You can use this for geometry that you will re-use multiple
times for best performance.
You can use this to render models from Blender or 3Ds Max.

Primitives
Since many user interfaces are predominantly built from many simple primitives Cogl provides an
optimized path for batching tiny primitives such as rectangles and polygons that would normally have
an excessive overhead if passed directly to the hardware as lots of tiny drawing requests.
The Cogl Journal
Internally Cogl queues primitives into a "journal" which optimizes how they are submitted to the GPU
by batching the geometry together, minimizing state changes and reducing expensive draw calls.

Pixel buffers
Cogl provides a means to allocate GPU memory to hold pixel data and to map that memory into the
CPU. This can be used to achieve zero copy uploads of texture or video data.

Traceable for performance analysis


Applications built on top of Cogl can be traced such that we log all Cogl commands to disk allowing us
to replay the traces removing all application logic from the equation so that we - and upstream driver
developers - can directly analyze the rendering bottlenecks of Cogl applications.

COGL Crate sample

The goal is ...

Define user data structure


typedef struct _Data {
CoglFramebuffer* fb;
int framebufferWidth;
int framebufferHeight;

CoglMatrix view;

CoglIndices* indices;
CoglPrimitive* prim;
CoglTexture* texture;
CoglPipeline* cratePipeline;

CoglPangoFontMap* pangoFontMap;
PangoContext* pangoContext;
PangoFontDescription* pangoFontDesc;

int hellLabelWidth;
int helloLabelHeight;

GTimer* timer;
gboolean swapReady;
} Data;

Create Window
/* Cogl provides a easier way to create host window
* than the way using native OpenGL & GLX */
// Create a new CoglContext.
CoglContext* ctx = cogl_context_new(NULL, &error);

// Instantiates an "unallocated" CoglOnscreen, Its width and height are 640, 480.
int width = 640, height = 480;
CoglOnscreen* onscreen = cogl_onscreen_new(ctx, width, height);

// Type casting.
CoglFramebuffer* fb = COGL_FRAMEBUFFER(onscreen);

// Explicitly allocate a configured CoglFramebuffer.


// But we don't need to do, because just calling cogl_onscreen_show is enough.
cogl_framebuffer_allocate(fb, &error);

data.fb = fb;
data.framebufferWidth = cogl_framebuffer_get_width(fb);
data.framebufferHeight = cogl_framebuffer_get_height(fb);

// This requests to make @onscreen visible to the user.


cogl_onscreen_show(onscreen);

Initialize viewport & projection matrix


// Redirects all subsequent drawing to the specified framebuffer.
cogl_push_framebuffer(fb);

// Replaces the current viewport with the given values.


cogl_set_viewport (0, 0, width, height);

// Replaces the current projection matrix with a perspective matrix based on the provied
values.
float fovy = 60, aspect = (float)width / (float)height, z_near = 0.1, z_far = 2000;
cogl_perspective (fovy, aspect, z_near, z_far);

Initialize viewport & projection matrix


for text rendering
CoglMatrix view;
cogl_matrix_init_identity(&view);

// Multiplies matrix by a view transform that maps the 2D coordinates(0, 0) top-left and
(width, height) bottom-right the full viewport size.
cogl_matrix_view_2d_in_perspective(&view, fovy, aspect, z_near, z_2d, width, height);
cogl_set_modelview_matrix(&view);

//Restores the framebuffer that was previously at the top of the stack.
// All subsequent drawing will be redirected to this framebuffer.
cogl_pop_framebuffer();

Set up a cube
/* Define an index buffer & primitive vertex buffer */

// Rectangle indices allow the GPU to interpret a list of quads as a list of triangles.
// This is a convenience function for accessing internal index buffers that can be
shared.
CoglIndices* indices = cogl_get_rectangle_indices(6);

// Create a primitive, such as a single triangle strip or a triangle fan.


// p3t2 means 3 positions and 2 texture coordinates.
coglPrimitive* prim = cogl_primitive_new_p3t2(COGL_VERTICES_MODE_TRIANGLES,
G_N_ELEMENTS(vertices), vertices);

// Associates a sequence of #CoglIndices with the given primitive.


// Each face will have 6 indices so we have 6 * 6 indices in total.
cogl_primitive_set_indices(prim, indices, 6 * 6);

Prepare a texture
/* Cogl provides a convenient method to create a texture from jpg, png etc.
* If you use the native OpenGL then you need to handle your own-self to do it
* or find an another library to load specific image formats. */

// Load a jpeg crate texture form a file.


CoglTexture* texture = cogl_texture_new_from_file("crate.jpg",
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY,
NULL);

Set up a cogl pipeline


/* A pipleline on Cogl means a single procedure that processes all given resource
* like vertex buffer, index buffer, texture, lights & transformation information
* to draw a scene */

CoglPipeline* cratePipeline = cogl_pipeline_new();


cogl_pipeline_set_layer_texture(cratePipeline, 0, texture);

// Since the box is made of multiple triangles that will overlap when drawn
// and we don't control the order they are drawn in, we enable depth testing
// to make sure that triangles that shouldn't be visible get culled by the GPU.
CoglDepthState depthState;
cogl_depth_state_init(&depthState);
cogl_depth_state_set(test)enabled(&depthState, TRUE);

// This commits all the depth state configured in @state struct to the given pipeline.
cogl_pipeline_set_depth_state(cratePipeline, &depthState, NULL);

Set up Pango font map and context


// Create pango font map
CoglPangoFontMap* pangoFontMap = COGL_PANGO_FONT_MAP(cogl_pango_font_map_new());
cogl_pango_font_map_set_use_mipmapping(pangoFontMap, TRUE);

// Create pango context with pango font map.


PangoContext* pangoContext = cogl_pango_font_map_create_context(pangoFontMap);

// Set up a pango font description.


PangoFontDescription* pangoFontDesc = pango_font_description_new();
pango_font_description_set_family(pangoFontDesc, "Sans");
pango_font_description_set_size(pangoFontDesc, 30 * PANGO_SCALE);

PangoLayout* helloLabel = pango_layout_new(pangoContext);


pango_layout_set_text(helloLabel, "Hello Cogl", -1);

PangoRectangle helloLabelSize;
pango_layout_get_extents (helloLabel, NULL, &helloLabelSize);

data.helloLabelWidth = PANGO_PIXELS (helloLabelSize.width);


data.helloLabelHeight = PANGO_PIXELS (helloLabelSize.height);

Ready to paint
// Change a target to fb
cogl_push_framebuffer(fb);

// Checks if a given feature is currently available.


bool hasSwapNotify = cogl_has_feature(ctx, COGL_FEATURE_ID_SWAP_BUFFERS_EVENT);
if (hasSwapNotify) {
// Installs a @callback function that should be called whenever a swap buffers
request
// for the given framebuffer completes.
// Nothing to do in swapNotifyCallback now.
cogl_framebuffer_add_swap_buffers_callback(fb, swapNotifyCallback, &data);
}

// Prepare a timer to check elapsed time.


data.timer = g_timer_new();

// We're ready to swap buffers.


data.swapReady = TRUE;

Loop
while (1) {
CoglPollFD* pollFds; int numPollFds; gint64 timeout;
if (data.swapReady) {
paint(&data);
// Swaps the current back buffer being rendered too, to the front for display.
cogl_framebuffer_swap_buffers(fb);
}
// This should be called whenever an application is about to go idle
// so that Cogl has a chance to describe what state it needs to be woken up on.
// timeout will contain a maximum amount of time to wait in microseconds before the
// application should wake up or -1 if the application should wait indefinitely.
cogl_poll_get_info(ctx, &pollFds, &numPollFds, &timeout);
if (!hasSwapNotify) {
data.swapReady = TRUE;
timeout = 0;
}
g_poll((GpollFD*)pllFds, numPollFds, timeout == -1 ? -1 : timeout / 1000);
// This should be called whenever an application is woken up from going idle
// in its main loop.
cogl_poll_dispatch(ctx, pollFds, numPollFds);
}

Paint (1/3)
static void paint(Data* data)
{
int framebufferWidth = data->framebufferWidth;
int framebufferHeight = data->framebufferHeight;
int helloLabelWidth = data->helloLabelWidth;
int helloLabelHeight = data->helloLabelHeight;

CoglColor black, white;


cogl_color_set_from_4ub(&black, 0x00, 0x00, 0x00, 0xff);
cogl_color_set_from_4ub(&black, 0xff, 0xff, 0xff, 0xff);

// Clear depth buffer, color buffer.


cogl_clear(&black, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH);

...
}

Paint (2/3)
/* Translate, scale and rotate the view.
* And then apply the given texture and depth test.
* Finally draw the primitive with the given all states */
static void paint(Data* data)
{
...
cogl_push_matrix();
cogl_translate(framebufferWidth / 2, framebufferHeight / 2, 0);
cogl_scale(75, 75, 75);

float rotation = g_timer_elapsed(data->timer, NULL) * 60.0f;


cogl_ratate(rotation, 0, 0, 1);
cogl_ratate(rotation, 0, 1, 0);
cogl_ratate(rotation, 1, 0, 0);

// Apply the given texture and depth test.


cogl_set_source(data->cratePipeline);

cogl_primitive_draw(data->prim);
...
}

Paint (3/3)
static void paint(Data* data)
{
...
// Pop a matrix for the state to draw a previous primitive.
cogl_pop_matrix();

// We don't need a depth test since we're going to draw 2D text here.
cogl_set_depth_test_enabled(FALSE);

// Render text image label.


cogl_pango_render_layout(data->helloLabel
, (framebufferWidth - helloLabelWidth) / 2
, (framebufferHeight - helloLabelHeight) / 2
, &white, 0);
}

Thank you
any Question?

Você também pode gostar