Beispiel #1
0
static void
test_global_vertex_hook(TestState *state)
{
    cg_pipeline_t *pipeline;
    cg_snippet_t *snippet;

    pipeline = cg_pipeline_new(test_dev);

    /* Creates a function in the global declarations hook which is used
     * by a subsequent snippet. The subsequent snippets replace any
     * previous snippets but this shouldn't prevent the global
     * declarations from being generated */

    snippet = cg_snippet_new(CG_SNIPPET_HOOK_VERTEX_GLOBALS,
                             /* declarations */
                             "float\n"
                             "multiply_by_two(float number)\n"
                             "{\n"
                             "  return number * 2.0;\n"
                             "}\n",
                             /* post */
                             "This string shouldn't be used so "
                             "we can safely put garbage in here.");
    cg_snippet_set_pre(snippet,
                       "This string shouldn't be used so "
                       "we can safely put garbage in here.");
    cg_snippet_set_replace(snippet,
                           "This string shouldn't be used so "
                           "we can safely put garbage in here.");
    cg_pipeline_add_snippet(pipeline, snippet);
    cg_object_unref(snippet);

    snippet = cg_snippet_new(CG_SNIPPET_HOOK_VERTEX,
                             NULL, /* declarations */
                             NULL /* replace */);
    cg_snippet_set_replace(snippet,
                           "cg_color_out.r = multiply_by_two(0.5);\n"
                           "cg_color_out.gba = vec3(0.0, 0.0, 1.0);\n"
                           "cg_position_out = cg_position_in;\n");
    cg_pipeline_add_snippet(pipeline, snippet);
    cg_object_unref(snippet);

    cg_framebuffer_draw_rectangle(test_fb,
                                  pipeline,
                                  -1, 1,
                                  10.0f * 2.0f / state->fb_width - 1.0f,
                                  10.0f * 2.0f / state->fb_height - 1.0f);

    cg_object_unref(pipeline);

    test_cg_check_pixel(test_fb, 5, 5, 0xff0000ff);
}
Beispiel #2
0
rig_downsampler_t *
rig_downsampler_new(rig_engine_t *engine)
{
    rig_downsampler_t *downsampler = c_slice_new0(rig_downsampler_t);
    cg_pipeline_t *pipeline;

    downsampler->engine = engine;

    pipeline = cg_pipeline_new(engine->shell->cg_device);
    cg_pipeline_set_layer_texture(pipeline, 0, NULL);
    cg_pipeline_set_blend(pipeline, "RGBA=ADD(SRC_COLOR, 0)", NULL);

    downsampler->pipeline = pipeline;

    return downsampler;
}
Beispiel #3
0
static void
test_vertex_transform_hook(TestState *state)
{
    cg_pipeline_t *pipeline;
    cg_snippet_t *snippet;
    c_matrix_t identity_matrix;
    c_matrix_t matrix;
    int location;

    /* Test the vertex transform hook */

    c_matrix_init_identity(&identity_matrix);

    pipeline = cg_pipeline_new(test_dev);

    cg_pipeline_set_color4ub(pipeline, 255, 0, 255, 255);

    snippet = cg_snippet_new(CG_SNIPPET_HOOK_VERTEX_TRANSFORM,
                             "uniform mat4 pmat;",
                             NULL);
    cg_snippet_set_replace(snippet, "cg_position_out = "
                           "pmat * cg_position_in;");
    cg_pipeline_add_snippet(pipeline, snippet);
    cg_object_unref(snippet);

    /* Copy the current projection matrix to a uniform */
    cg_framebuffer_get_projection_matrix(test_fb, &matrix);
    location = cg_pipeline_get_uniform_location(pipeline, "pmat");
    cg_pipeline_set_uniform_matrix(pipeline,
                                   location,
                                   4, /* dimensions */
                                   1, /* count */
                                   false, /* don't transpose */
                                   c_matrix_get_array(&matrix));

    /* Replace the real projection matrix with the identity. This should
       mess up the drawing unless the snippet replacement is working */
    cg_framebuffer_set_projection_matrix(test_fb, &identity_matrix);

    cg_framebuffer_draw_rectangle(test_fb, pipeline, 150, 0, 160, 10);
    cg_object_unref(pipeline);

    /* Restore the projection matrix */
    cg_framebuffer_set_projection_matrix(test_fb, &matrix);

    test_cg_check_pixel(test_fb, 155, 5, 0xff00ffff);
}
Beispiel #4
0
static bool
draw_rectangle (TestState *state,
                int x,
                int y,
                TestDepthState *rect_state)
{
  uint8_t Cr = MASK_RED (rect_state->color);
  uint8_t Cg = MASK_GREEN (rect_state->color);
  uint8_t Cb = MASK_BLUE (rect_state->color);
  uint8_t Ca = MASK_ALPHA (rect_state->color);
  cg_pipeline_t *pipeline;
  cg_depth_state_t depth_state;

  cg_depth_state_init (&depth_state);
  cg_depth_state_set_test_enabled (&depth_state, rect_state->test_enable);
  cg_depth_state_set_test_function (&depth_state, rect_state->test_function);
  cg_depth_state_set_write_enabled (&depth_state, rect_state->write_enable);
  cg_depth_state_set_range (&depth_state,
                              rect_state->range_near,
                              rect_state->range_far);

  pipeline = cg_pipeline_new (test_dev);
  if (!cg_pipeline_set_depth_state (pipeline, &depth_state, NULL))
    {
      cg_object_unref (pipeline);
      return false;
    }

  cg_pipeline_set_color4ub (pipeline, Cr, Cg, Cb, Ca);

  cg_framebuffer_set_depth_write_enabled (test_fb, rect_state->fb_write_enable);
  cg_framebuffer_push_matrix (test_fb);
  cg_framebuffer_translate (test_fb, 0, 0, rect_state->depth);
  cg_framebuffer_draw_rectangle (test_fb,
                                   pipeline,
                                   x * QUAD_WIDTH,
                                   y * QUAD_WIDTH,
                                   x * QUAD_WIDTH + QUAD_WIDTH,
                                   y * QUAD_WIDTH + QUAD_WIDTH);
  cg_framebuffer_pop_matrix (test_fb);

  cg_object_unref (pipeline);

  return true;
}
Beispiel #5
0
static void
paint (void)
{
  cg_pipeline_t *pipeline = cg_pipeline_new (test_dev);
  int width = cg_framebuffer_get_width (test_fb);
  int half_width = width / 2;
  int height = cg_framebuffer_get_height (test_fb);
  cg_vertex_p2_t tri0_vertices[] = {
        { 0, 0 },
        { 0, height },
        { half_width, height },
  };
  cg_vertex_p2c4_t tri1_vertices[] = {
        { half_width, 0, 0x80, 0x80, 0x80, 0x80 },
        { half_width, height, 0x80, 0x80, 0x80, 0x80 },
        { width, height, 0x80, 0x80, 0x80, 0x80 },
  };
  cg_primitive_t *tri0;
  cg_primitive_t *tri1;

  cg_framebuffer_clear4f (test_fb, CG_BUFFER_BIT_COLOR, 0, 0, 0, 0);

  tri0 = cg_primitive_new_p2 (test_dev, CG_VERTICES_MODE_TRIANGLES,
                                3, tri0_vertices);
  tri1 = cg_primitive_new_p2c4 (test_dev, CG_VERTICES_MODE_TRIANGLES,
                                  3, tri1_vertices);

  /* Check that cogl correctly handles the case where we draw
   * different primitives same pipeline and switch from using the
   * opaque color associated with the pipeline and using a colour
   * attribute with an alpha component which implies blending is
   * required.
   *
   * If Cogl gets this wrong then then in all likelyhood the second
   * primitive will be drawn with blending still disabled.
   */

  cg_primitive_draw (tri0, test_fb, pipeline);
  cg_primitive_draw (tri1, test_fb, pipeline);

  test_cg_check_pixel_and_alpha (test_fb,
                                    half_width + 5,
                                    height - 5,
                                    0x80808080);
}
Beispiel #6
0
static void
lots_snippets(TestState *state)
{
    cg_pipeline_t *pipeline;
    cg_snippet_t *snippet;
    int location;
    int i;

    /* Lots of snippets on one pipeline */
    pipeline = cg_pipeline_new(test_dev);

    cg_pipeline_set_color4ub(pipeline, 0, 0, 0, 255);

    for(i = 0; i < 3; i++) {
        char letter = 'x' + i;
        char *uniform_name = c_strdup_printf("%c_value", letter);
        char *declarations = c_strdup_printf("uniform float %s;\n",
                                             uniform_name);
        char *code = c_strdup_printf("cg_color_out.%c = %s;\n",
                                     letter,
                                     uniform_name);

        location = cg_pipeline_get_uniform_location(pipeline, uniform_name);
        cg_pipeline_set_uniform_1f(pipeline, location,(i + 1) * 0.1f);

        snippet = cg_snippet_new(CG_SNIPPET_HOOK_FRAGMENT,
                                 declarations,
                                 code);
        cg_pipeline_add_snippet(pipeline, snippet);
        cg_object_unref(snippet);

        c_free(code);
        c_free(uniform_name);
        c_free(declarations);
    }

    cg_framebuffer_draw_rectangle(test_fb, pipeline, 30, 0, 40, 10);

    cg_object_unref(pipeline);

    test_cg_check_pixel(test_fb, 35, 5, 0x19334cff);
}
Beispiel #7
0
static void
simple_vertex_snippet(TestState *state)
{
    cg_pipeline_t *pipeline;
    cg_snippet_t *snippet;

    /* Simple vertex snippet */
    pipeline = cg_pipeline_new(test_dev);

    cg_pipeline_set_color4ub(pipeline, 255, 0, 0, 255);

    snippet = cg_snippet_new(CG_SNIPPET_HOOK_VERTEX,
                             NULL,
                             "cg_color_out.b += 1.0;");
    cg_pipeline_add_snippet(pipeline, snippet);
    cg_object_unref(snippet);

    cg_framebuffer_draw_rectangle(test_fb, pipeline, 10, 0, 20, 10);

    cg_object_unref(pipeline);

    test_cg_check_pixel(test_fb, 15, 5, 0xff00ffff);
}
Beispiel #8
0
static void
simple_fragment_snippet(TestState *state)
{
    cg_pipeline_t *pipeline;
    cg_snippet_t *snippet;

    /* Simple fragment snippet */
    pipeline = cg_pipeline_new(test_dev);

    cg_pipeline_set_color4ub(pipeline, 255, 0, 0, 255);

    snippet = cg_snippet_new(CG_SNIPPET_HOOK_FRAGMENT,
                             NULL, /* declarations */
                             "cg_color_out.g += 1.0;");
    cg_pipeline_add_snippet(pipeline, snippet);
    cg_object_unref(snippet);

    cg_framebuffer_draw_rectangle(test_fb, pipeline, 0, 0, 10, 10);

    cg_object_unref(pipeline);

    test_cg_check_pixel(test_fb, 5, 5, 0xffff00ff);
}
Beispiel #9
0
rut_rectangle_t *
rut_rectangle_new4f(rut_shell_t *shell,
                    float width,
                    float height,
                    float red,
                    float green,
                    float blue,
                    float alpha)
{
    rut_rectangle_t *rectangle = rut_object_alloc0(
        rut_rectangle_t, &rut_rectangle_type, _rut_rectangle_init_type);

    rut_graphable_init(rectangle);
    rut_paintable_init(rectangle);

    rectangle->width = width;
    rectangle->height = height;

    rectangle->pipeline = cg_pipeline_new(shell->cg_device);
    cg_pipeline_set_color4f(rectangle->pipeline, red, green, blue, alpha);

    return rectangle;
}
Beispiel #10
0
static void
test_naming_texture_units(TestState *state)
{
    cg_pipeline_t *pipeline;
    cg_snippet_t *snippet;
    cg_texture_t *tex1, *tex2;

    /* Test that we can sample from an arbitrary texture unit by naming
       its layer number */

    snippet = cg_snippet_new(CG_SNIPPET_HOOK_FRAGMENT,
                             NULL,
                             NULL);
    cg_snippet_set_replace(snippet,
                           "cg_color_out = "
                           "texture2D(cg_sampler100, vec2(0.0, 0.0)) + "
                           "texture2D(cg_sampler200, vec2(0.0, 0.0));");

    tex1 = test_cg_create_color_texture(test_dev, 0xff0000ff);
    tex2 = test_cg_create_color_texture(test_dev, 0x00ff00ff);

    pipeline = cg_pipeline_new(test_dev);

    cg_pipeline_set_layer_texture(pipeline, 100, tex1);
    cg_pipeline_set_layer_texture(pipeline, 200, tex2);

    cg_pipeline_add_snippet(pipeline, snippet);

    cg_framebuffer_draw_rectangle(test_fb, pipeline, 0, 0, 10, 10);

    cg_object_unref(pipeline);
    cg_object_unref(snippet);
    cg_object_unref(tex1);
    cg_object_unref(tex2);

    test_cg_check_pixel(test_fb, 5, 5, 0xffff00ff);
}
Beispiel #11
0
static void
test_snippet_order(TestState *state)
{
    cg_pipeline_t *pipeline;
    cg_snippet_t *snippet;

    /* Verify that the snippets are executed in the right order. We'll
       replace the r component of the color in the pre sections of the
       snippets and the g component in the post. The pre sections should
       be executed in the reverse order they were added and the post
       sections in the same order as they were added. Therefore the r
       component should be taken from the the second snippet and the g
       component from the first */
    pipeline = cg_pipeline_new(test_dev);

    cg_pipeline_set_color4ub(pipeline, 0, 0, 0, 255);

    snippet = cg_snippet_new(CG_SNIPPET_HOOK_FRAGMENT,
                             NULL,
                             "cg_color_out.g = 0.5;\n");
    cg_snippet_set_pre(snippet, "cg_color_out.r = 0.5;\n");
    cg_snippet_set_replace(snippet, "cg_color_out.ba = vec2(0.0, 1.0);");
    cg_pipeline_add_snippet(pipeline, snippet);
    cg_object_unref(snippet);

    snippet = cg_snippet_new(CG_SNIPPET_HOOK_FRAGMENT,
                             NULL,
                             "cg_color_out.g = 1.0;\n");
    cg_snippet_set_pre(snippet, "cg_color_out.r = 1.0;\n");
    cg_pipeline_add_snippet(pipeline, snippet);
    cg_object_unref(snippet);

    cg_framebuffer_draw_rectangle(test_fb, pipeline, 160, 0, 170, 10);
    cg_object_unref(pipeline);

    test_cg_check_pixel(test_fb, 165, 5, 0x80ff00ff);
}
Beispiel #12
0
static void
paint (cg_texture_t *texture)
{
  cg_pipeline_t *pipeline = cg_pipeline_new (test_dev);
  int x = 0, y = 0, size = TEXTURE_SIZE;

  cg_pipeline_set_layer_texture (pipeline, 0, texture);
  cg_pipeline_set_layer_filters (pipeline, 0,
                                   CG_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST,
                                   CG_PIPELINE_FILTER_NEAREST);

  cg_framebuffer_draw_rectangle (test_fb,
                                   pipeline,
                                   x, y,
                                   x + size,
                                   y + size);

  x += size;
  size /= 2;
  cg_framebuffer_draw_rectangle (test_fb,
                                   pipeline,
                                   x, y,
                                   x + size,
                                   y + size);

  x += size;
  size /= 2;
  cg_framebuffer_draw_rectangle (test_fb,
                                   pipeline,
                                   x, y,
                                   x + size,
                                   y + size);

  cg_object_unref (pipeline);
  cg_object_unref (texture);
}
Beispiel #13
0
int
main(int argc, char **argv)
{
    Data data;
    cg_onscreen_t *onscreen;
    cg_error_t *error = NULL;
    cg_vertex_p2c4_t triangle_vertices[] = {
        { 0, 0.7, 0xff, 0x00, 0x00, 0xff },
        { -0.7, -0.7, 0x00, 0xff, 0x00, 0xff },
        { 0.7, -0.7, 0x00, 0x00, 0xff, 0xff }
    };
    cg_renderer_t *renderer;
    cg_display_t *display;
    uv_loop_t *loop = uv_default_loop();

    renderer = cg_renderer_new();
    cg_renderer_add_constraint(renderer,
                               CG_RENDERER_CONSTRAINT_SUPPORTS_CG_GLES2);

    if (!cg_renderer_connect(renderer, &error)) {
        c_error("%s", error->message);
        exit(1);
    }

    display = cg_display_new(renderer, NULL);
    data.dev = cg_device_new();
    cg_device_set_display(data.dev, display);

    if (!cg_device_connect(data.dev, &error)) {
        c_error("%s", error->message);
        exit(1);
    }

    onscreen = cg_onscreen_new(data.dev, 640, 480);
    cg_onscreen_show(onscreen);
    data.fb = onscreen;

    /* Prepare onscreen primitive */
    data.triangle = cg_primitive_new_p2c4(
        data.dev, CG_VERTICES_MODE_TRIANGLES, 3, triangle_vertices);
    data.pipeline = cg_pipeline_new(data.dev);

    data.offscreen_texture = cg_texture_2d_new_with_size(
        data.dev, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT);
    data.offscreen = cg_offscreen_new_with_texture(data.offscreen_texture);

    data.gles2_ctx = cg_gles2_context_new(data.dev, &error);
    if (!data.gles2_ctx) {
        c_error("Failed to create GLES2 context: %s\n", error->message);
    }

    data.gles2_vtable = cg_gles2_context_get_vtable(data.gles2_ctx);

    /* Draw scene with GLES2 */
    if (!cg_push_gles2_context(
            data.dev, data.gles2_ctx, data.fb, data.fb, &error)) {
        c_error("Failed to push gles2 context: %s\n", error->message);
    }

    cg_pop_gles2_context(data.dev);

    cg_onscreen_add_frame_callback(
        CG_ONSCREEN(data.fb), frame_event_cb, &data, NULL); /* destroy notify */

    uv_idle_init(loop, &data.idle);
    data.idle.data = &data;
    uv_idle_start(&data.idle, paint_cb);

    cg_uv_set_mainloop(data.dev, loop);
    uv_run(loop, UV_RUN_DEFAULT);

    return 0;
}
Beispiel #14
0
int
main(int argc, char **argv)
{
    cg_renderer_t *renderer;
    cg_device_t *dev;
    cg_onscreen_t *onscreen;
    cg_error_t *error = NULL;
    cg_vertex_p2c4_t triangle_vertices[] = {
        { 0, 0.7, 0xff, 0x00, 0x00, 0xff },
        { -0.7, -0.7, 0x00, 0xff, 0x00, 0xff },
        { 0.7, -0.7, 0x00, 0x00, 0xff, 0xff }
    };
    Data data;
    SDL_Event event;

    renderer = cg_renderer_new();
    dev = cg_device_new();

    cg_renderer_set_winsys_id(renderer, CG_WINSYS_ID_SDL);
    if (cg_renderer_connect(renderer, &error))
        cg_device_set_renderer(dev, renderer);
    else {
        cg_error_free(error);
        fprintf(stderr, "Failed to create device: %s\n", error->message);
        return 1;
    }

    onscreen = cg_onscreen_new(dev, 800, 600);
    data.fb = onscreen;

    cg_onscreen_add_frame_callback(
        onscreen, frame_cb, &data, NULL /* destroy callback */);
    cg_onscreen_add_dirty_callback(
        onscreen, dirty_cb, &data, NULL /* destroy callback */);

    data.center_x = 0.0f;
    data.center_y = 0.0f;
    data.quit = false;

    /* In SDL2, setting resizable only works before allocating the
     * onscreen */
    cg_onscreen_set_resizable(onscreen, true);

    cg_onscreen_show(onscreen);

    data.triangle = cg_primitive_new_p2c4(dev, CG_VERTICES_MODE_TRIANGLES, 3,
                                          triangle_vertices);
    data.pipeline = cg_pipeline_new(dev);

    data.redraw_queued = false;
    data.ready_to_draw = true;

    while (!data.quit) {
        if (!SDL_PollEvent(&event)) {
            if (data.redraw_queued && data.ready_to_draw) {
                redraw(&data);
                data.redraw_queued = false;
                data.ready_to_draw = false;
                continue;
            }

            cg_sdl_idle(dev);
            if (!SDL_WaitEvent(&event)) {
                fprintf(stderr, "Error waiting for SDL events");
                return 1;
            }
        }

        handle_event(&data, &event);
        cg_sdl_handle_event(dev, &event);
    }

    cg_object_unref(dev);

    return 0;
}
Beispiel #15
0
bool
cg_device_connect(cg_device_t *dev, cg_error_t **error)
{
    uint8_t white_pixel[] = { 0xff, 0xff, 0xff, 0xff };
    const cg_winsys_vtable_t *winsys;
    int i;
    cg_error_t *internal_error = NULL;

    if (dev->connected)
        return true;

    /* Mark as connected now to avoid recursion issues,
     * but revert in error paths */
    dev->connected = true;

    if (!dev->renderer) {
        cg_renderer_t *renderer = cg_renderer_new();
        if (!cg_renderer_connect(renderer, error)) {
            cg_object_unref(renderer);
            dev->connected = false;
            return false;
        }
        cg_device_set_renderer(dev, renderer);
    }

    if (!dev->display) {
        cg_display_t *display = cg_display_new(dev->renderer, NULL);
        if (!cg_display_setup(display, error)) {
            cg_object_unref(display);
            dev->connected = false;
            return false;
        }
        cg_device_set_display(dev, display);
    }

    /* This is duplicated data, but it's much more convenient to have
       the driver attached to the context and the value is accessed a
       lot throughout CGlib */
    dev->driver = dev->renderer->driver;

    /* Again this is duplicated data, but it convenient to be able
     * access these from the context. */
    dev->driver_vtable = dev->renderer->driver_vtable;
    dev->texture_driver = dev->renderer->texture_driver;

    for (i = 0; i < C_N_ELEMENTS(dev->private_features); i++)
        dev->private_features[i] |= dev->renderer->private_features[i];

    winsys = _cg_device_get_winsys(dev);
    if (!winsys->device_init(dev, error)) {
        dev->connected = false;
        return false;
    }

    dev->attribute_name_states_hash =
        c_hash_table_new_full(c_str_hash, c_str_equal, c_free, c_free);
    dev->attribute_name_index_map = NULL;
    dev->n_attribute_names = 0;

    /* The "cg_color_in" attribute needs a deterministic name_index
     * so we make sure it's the first attribute name we register */
    _cg_attribute_register_attribute_name(dev, "cg_color_in");

    dev->uniform_names =
        c_ptr_array_new_with_free_func((c_destroy_func_t)c_free);
    dev->uniform_name_hash = c_hash_table_new(c_str_hash, c_str_equal);
    dev->n_uniform_names = 0;

    /* Initialise the driver specific state */
    _cg_init_feature_overrides(dev);

    /* XXX: ONGOING BUG: Intel viewport scissor
     *
     * Intel gen6 drivers don't currently correctly handle offset
     * viewports, since primitives aren't clipped within the bounds of
     * the viewport.  To workaround this we push our own clip for the
     * viewport that will use scissoring to ensure we clip as expected.
     *
     * TODO: file a bug upstream!
     */
    if (dev->gpu.driver_package == CG_GPU_INFO_DRIVER_PACKAGE_MESA &&
        dev->gpu.architecture == CG_GPU_INFO_ARCHITECTURE_SANDYBRIDGE &&
        !getenv("CG_DISABLE_INTEL_VIEWPORT_SCISSORT_WORKAROUND"))
        dev->needs_viewport_scissor_workaround = true;
    else
        dev->needs_viewport_scissor_workaround = false;

    dev->sampler_cache = _cg_sampler_cache_new(dev);

    _cg_pipeline_init_default_pipeline();
    _cg_pipeline_init_default_layers();
    _cg_pipeline_init_state_hash_functions();
    _cg_pipeline_init_layer_state_hash_functions();

    dev->current_clip_stack_valid = false;
    dev->current_clip_stack = NULL;

    c_matrix_init_identity(&dev->identity_matrix);
    c_matrix_init_identity(&dev->y_flip_matrix);
    c_matrix_scale(&dev->y_flip_matrix, 1, -1, 1);

    dev->texture_units =
        c_array_new(false, false, sizeof(cg_texture_unit_t));

    if (_cg_has_private_feature(dev, CG_PRIVATE_FEATURE_ANY_GL)) {
        /* See cg-pipeline.c for more details about why we leave texture unit
         * 1
         * active by default... */
        dev->active_texture_unit = 1;
        GE(dev, glActiveTexture(GL_TEXTURE1));
    }

    dev->opaque_color_pipeline = cg_pipeline_new(dev);
    dev->codegen_header_buffer = c_string_new("");
    dev->codegen_source_buffer = c_string_new("");

    dev->default_gl_texture_2d_tex = NULL;
    dev->default_gl_texture_3d_tex = NULL;

    dev->framebuffers = NULL;
    dev->current_draw_buffer = NULL;
    dev->current_read_buffer = NULL;
    dev->current_draw_buffer_state_flushed = 0;
    dev->current_draw_buffer_changes = CG_FRAMEBUFFER_STATE_ALL;

    c_list_init(&dev->onscreen_events_queue);
    c_list_init(&dev->onscreen_dirty_queue);

    c_queue_init(&dev->gles2_context_stack);

    dev->current_pipeline = NULL;
    dev->current_pipeline_changes_since_flush = 0;
    dev->current_pipeline_with_color_attrib = false;

    _cg_bitmask_init(&dev->enabled_custom_attributes);
    _cg_bitmask_init(&dev->enable_custom_attributes_tmp);
    _cg_bitmask_init(&dev->changed_bits_tmp);

    dev->max_texture_units = -1;
    dev->max_activateable_texture_units = -1;

    dev->current_gl_program = 0;

    dev->current_gl_dither_enabled = true;
    dev->current_gl_color_mask = CG_COLOR_MASK_ALL;

    dev->gl_blend_enable_cache = false;

    dev->depth_test_enabled_cache = false;
    dev->depth_test_function_cache = CG_DEPTH_TEST_FUNCTION_LESS;
    dev->depth_writing_enabled_cache = true;
    dev->depth_range_near_cache = 0;
    dev->depth_range_far_cache = 1;

    dev->pipeline_cache = _cg_pipeline_cache_new();

    for (i = 0; i < CG_BUFFER_BIND_TARGET_COUNT; i++)
        dev->current_buffer[i] = NULL;

    dev->stencil_pipeline = cg_pipeline_new(dev);

    dev->rectangle_byte_indices = NULL;
    dev->rectangle_short_indices = NULL;
    dev->rectangle_short_indices_len = 0;

    dev->texture_download_pipeline = NULL;
    dev->blit_texture_pipeline = NULL;

#if defined(CG_HAS_GL_SUPPORT)
    if ((dev->driver == CG_DRIVER_GL3)) {
        GLuint vertex_array;

        /* In a forward compatible context, GL 3 doesn't support rendering
         * using the default vertex array object. CGlib doesn't use vertex
         * array objects yet so for now we just create a dummy array
         * object that we will use as our own default object. Eventually
         * it could be good to attach the vertex array objects to
         * cg_primitive_ts */
        dev->glGenVertexArrays(1, &vertex_array);
        dev->glBindVertexArray(vertex_array);
    }
#endif

    dev->current_modelview_entry = NULL;
    dev->current_projection_entry = NULL;
    _cg_matrix_entry_identity_init(&dev->identity_entry);
    _cg_matrix_entry_cache_init(&dev->builtin_flushed_projection);
    _cg_matrix_entry_cache_init(&dev->builtin_flushed_modelview);

    /* Create default textures used for fall backs */
    dev->default_gl_texture_2d_tex =
        cg_texture_2d_new_from_data(dev,
                                    1,
                                    1,
                                    CG_PIXEL_FORMAT_RGBA_8888_PRE,
                                    0, /* rowstride */
                                    white_pixel,
                                    NULL); /* abort on error */

    /* If 3D or rectangle textures aren't supported then these will
     * return errors that we can simply ignore. */
    internal_error = NULL;
    dev->default_gl_texture_3d_tex =
        cg_texture_3d_new_from_data(dev,
                                    1,
                                    1,
                                    1, /* width, height, depth */
                                    CG_PIXEL_FORMAT_RGBA_8888_PRE,
                                    0, /* rowstride */
                                    0, /* image stride */
                                    white_pixel,
                                    &internal_error);
    if (internal_error)
        cg_error_free(internal_error);

    dev->buffer_map_fallback_array = c_byte_array_new();
    dev->buffer_map_fallback_in_use = false;

    c_list_init(&dev->fences);

    dev->atlas_set = cg_atlas_set_new(dev);
    cg_atlas_set_set_components(dev->atlas_set, CG_TEXTURE_COMPONENTS_RGBA);
    cg_atlas_set_set_premultiplied(dev->atlas_set, false);
    cg_atlas_set_add_atlas_callback(dev->atlas_set,
                                    _cg_atlas_texture_atlas_event_handler,
                                    NULL, /* user data */
                                    NULL); /* destroy */

    return true;
}