CoglTexture2D * cogl_texture_2d_new_from_data (CoglContext *ctx, int width, int height, CoglPixelFormat format, CoglPixelFormat internal_format, int rowstride, const uint8_t *data, CoglError **error) { CoglBitmap *bmp; CoglTexture2D *tex_2d; _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL); _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL); /* Rowstride from width if not given */ if (rowstride == 0) rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format); /* Wrap the data into a bitmap */ bmp = cogl_bitmap_new_for_data (ctx, width, height, format, rowstride, (uint8_t *) data); tex_2d = cogl_texture_2d_new_from_bitmap (bmp, internal_format, error); cogl_object_unref (bmp); return tex_2d; }
static CoglTexture2D * _cogl_atlas_create_texture (CoglAtlas *atlas, int width, int height) { CoglTexture2D *tex; CoglError *ignore_error = NULL; _COGL_GET_CONTEXT (ctx, NULL); if ((atlas->flags & COGL_ATLAS_CLEAR_TEXTURE)) { uint8_t *clear_data; CoglBitmap *clear_bmp; int bpp = _cogl_pixel_format_get_bytes_per_pixel (atlas->texture_format); /* Create a buffer of zeroes to initially clear the texture */ clear_data = g_malloc0 (width * height * bpp); clear_bmp = cogl_bitmap_new_for_data (ctx, width, height, atlas->texture_format, width * bpp, clear_data); tex = cogl_texture_2d_new_from_bitmap (clear_bmp); _cogl_texture_set_internal_format (COGL_TEXTURE (tex), atlas->texture_format); if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error)) { cogl_error_free (ignore_error); cogl_object_unref (tex); tex = NULL; } cogl_object_unref (clear_bmp); g_free (clear_data); } else { tex = cogl_texture_2d_new_with_size (ctx, width, height); _cogl_texture_set_internal_format (COGL_TEXTURE (tex), atlas->texture_format); if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error)) { cogl_error_free (ignore_error); cogl_object_unref (tex); tex = NULL; } } return tex; }
/* This first tries to upload the texture to a CoglTexture2D, but * if that's not possible it falls back to a CoglTexture2DSliced. * * Auto-mipmapping of any uploaded texture is disabled */ static CoglTexture * video_texture_new_from_data (CoglContext *ctx, int width, int height, CoglPixelFormat format, CoglPixelFormat internal_format, int rowstride, const uint8_t *data, CoglError **error) { CoglBitmap *bitmap; CoglTexture *tex; CoglError *internal_error = NULL; bitmap = cogl_bitmap_new_for_data (ctx, width, height, format, rowstride, (uint8_t *) data); if ((is_pot (cogl_bitmap_get_width (bitmap)) && is_pot (cogl_bitmap_get_height (bitmap))) || cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC)) { tex = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap, internal_format, &internal_error)); if (!tex) { cogl_error_free (internal_error); internal_error = NULL; } } else tex = NULL; if (!tex) { /* Otherwise create a sliced texture */ CoglTexture2DSliced *tex_2ds = cogl_texture_2d_sliced_new_from_bitmap (bitmap, -1, /* no maximum waste */ internal_format, error); tex = COGL_TEXTURE (tex_2ds); } cogl_object_unref (bitmap); return tex; }
/* For reference: There was some deliberation over whether to have a * constructor that could throw an exception but looking at standard * practices with several high level OO languages including python, C++, * C# Java and Ruby they all support exceptions in constructors and the * general consensus appears to be that throwing an exception is neater * than successfully constructing with an internal error status that * would then have to be explicitly checked via some form of ::is_ok() * method. */ CoglContext * cogl_context_new (CoglDisplay *display, GError **error) { CoglContext *context; GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; CoglBitmap *default_texture_bitmap; const CoglWinsysVtable *winsys; int i; _cogl_init (); #ifdef COGL_ENABLE_PROFILE /* We need to be absolutely sure that uprof has been initialized * before calling _cogl_uprof_init. uprof_init (NULL, NULL) * will be a NOP if it has been initialized but it will also * mean subsequent parsing of the UProf GOptionGroup will have no * affect. * * Sadly GOptionGroup based library initialization is extremely * fragile by design because GOptionGroups have no notion of * dependencies and so the order things are initialized isn't * currently under tight control. */ uprof_init (NULL, NULL); _cogl_uprof_init (); #endif /* Allocate context memory */ context = g_malloc0 (sizeof (CoglContext)); /* Convert the context into an object immediately in case any of the code below wants to verify that the context pointer is a valid object */ _cogl_context_object_new (context); /* XXX: Gross hack! * Currently everything in Cogl just assumes there is a default * context which it can access via _COGL_GET_CONTEXT() including * code used to construct a CoglContext. Until all of that code * has been updated to take an explicit context argument we have * to immediately make our pointer the default context. */ _context = context; /* Init default values */ memset (context->features, 0, sizeof (context->features)); context->feature_flags = 0; context->private_feature_flags = 0; context->texture_types = NULL; context->buffer_types = NULL; context->rectangle_state = COGL_WINSYS_RECTANGLE_STATE_UNKNOWN; memset (context->winsys_features, 0, sizeof (context->winsys_features)); if (!display) { CoglRenderer *renderer = cogl_renderer_new (); if (!cogl_renderer_connect (renderer, error)) { g_free (context); return NULL; } display = cogl_display_new (renderer, NULL); } else cogl_object_ref (display); if (!cogl_display_setup (display, error)) { cogl_object_unref (display); g_free (context); return NULL; } context->display = 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 Cogl */ context->driver = display->renderer->driver; switch (context->driver) { #ifdef HAVE_COGL_GL case COGL_DRIVER_GL: context->driver_vtable = &_cogl_driver_gl; context->texture_driver = &_cogl_texture_driver_gl; break; #endif #if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) case COGL_DRIVER_GLES1: case COGL_DRIVER_GLES2: context->driver_vtable = &_cogl_driver_gles; context->texture_driver = &_cogl_texture_driver_gles; break; #endif default: g_assert_not_reached (); } winsys = _cogl_context_get_winsys (context); if (!winsys->context_init (context, error)) { cogl_object_unref (display); g_free (context); return NULL; } context->attribute_name_states_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); context->attribute_name_index_map = NULL; context->n_attribute_names = 0; /* The "cogl_color_in" attribute needs a deterministic name_index * so we make sure it's the first attribute name we register */ _cogl_attribute_register_attribute_name (context, "cogl_color_in"); context->uniform_names = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); context->uniform_name_hash = g_hash_table_new (g_str_hash, g_str_equal); context->n_uniform_names = 0; /* Initialise the driver specific state */ _cogl_init_feature_overrides (context); _context->sampler_cache = _cogl_sampler_cache_new (_context); _cogl_pipeline_init_default_pipeline (); _cogl_pipeline_init_default_layers (); _cogl_pipeline_init_state_hash_functions (); _cogl_pipeline_init_layer_state_hash_functions (); context->current_clip_stack_valid = FALSE; context->current_clip_stack = NULL; cogl_matrix_init_identity (&context->identity_matrix); cogl_matrix_init_identity (&context->y_flip_matrix); cogl_matrix_scale (&context->y_flip_matrix, 1, -1, 1); context->flushed_matrix_mode = COGL_MATRIX_MODELVIEW; context->texture_units = g_array_new (FALSE, FALSE, sizeof (CoglTextureUnit)); /* See cogl-pipeline.c for more details about why we leave texture unit 1 * active by default... */ context->active_texture_unit = 1; GE (context, glActiveTexture (GL_TEXTURE1)); context->opaque_color_pipeline = cogl_pipeline_new (context); context->blended_color_pipeline = cogl_pipeline_new (context); context->texture_pipeline = cogl_pipeline_new (context); context->codegen_header_buffer = g_string_new (""); context->codegen_source_buffer = g_string_new (""); context->default_gl_texture_2d_tex = NULL; context->default_gl_texture_3d_tex = NULL; context->default_gl_texture_rect_tex = NULL; context->framebuffers = NULL; context->current_draw_buffer = NULL; context->current_read_buffer = NULL; context->current_draw_buffer_state_flushed = 0; context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL; g_queue_init (&context->gles2_context_stack); context->journal_flush_attributes_array = g_array_new (TRUE, FALSE, sizeof (CoglAttribute *)); context->journal_clip_bounds = NULL; context->polygon_vertices = g_array_new (FALSE, FALSE, sizeof (float)); context->current_pipeline = NULL; context->current_pipeline_changes_since_flush = 0; context->current_pipeline_skip_gl_color = FALSE; _cogl_bitmask_init (&context->enabled_builtin_attributes); _cogl_bitmask_init (&context->enable_builtin_attributes_tmp); _cogl_bitmask_init (&context->enabled_texcoord_attributes); _cogl_bitmask_init (&context->enable_texcoord_attributes_tmp); _cogl_bitmask_init (&context->enabled_custom_attributes); _cogl_bitmask_init (&context->enable_custom_attributes_tmp); _cogl_bitmask_init (&context->changed_bits_tmp); context->max_texture_units = -1; context->max_activateable_texture_units = -1; context->current_fragment_program_type = COGL_PIPELINE_PROGRAM_TYPE_FIXED; context->current_vertex_program_type = COGL_PIPELINE_PROGRAM_TYPE_FIXED; context->current_gl_program = 0; context->current_gl_dither_enabled = TRUE; context->current_gl_color_mask = COGL_COLOR_MASK_ALL; context->gl_blend_enable_cache = FALSE; context->depth_test_enabled_cache = FALSE; context->depth_test_function_cache = COGL_DEPTH_TEST_FUNCTION_LESS; context->depth_writing_enabled_cache = TRUE; context->depth_range_near_cache = 0; context->depth_range_far_cache = 1; context->pipeline_cache = cogl_pipeline_cache_new (); for (i = 0; i < COGL_BUFFER_BIND_TARGET_COUNT; i++) context->current_buffer[i] = NULL; context->window_buffer = NULL; context->framebuffer_stack = _cogl_create_framebuffer_stack (); /* XXX: In this case the Clutter backend is still responsible for * the OpenGL binding API and for creating onscreen framebuffers and * so we have to add a dummy framebuffer to represent the backend * owned window... */ if (_cogl_context_get_winsys (context) == _cogl_winsys_stub_get_vtable ()) { CoglOnscreen *window = _cogl_onscreen_new (); cogl_set_framebuffer (COGL_FRAMEBUFFER (window)); cogl_object_unref (COGL_FRAMEBUFFER (window)); } context->stencil_pipeline = cogl_pipeline_new (context); context->in_begin_gl_block = FALSE; context->quad_buffer_indices_byte = NULL; context->quad_buffer_indices = NULL; context->quad_buffer_indices_len = 0; context->rectangle_byte_indices = NULL; context->rectangle_short_indices = NULL; context->rectangle_short_indices_len = 0; context->texture_download_pipeline = NULL; context->blit_texture_pipeline = NULL; #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) if (context->driver != COGL_DRIVER_GLES2) /* The default for GL_ALPHA_TEST is to always pass which is equivalent to * the test being disabled therefore we assume that for all drivers there * will be no performance impact if we always leave the test enabled which * makes things a bit simpler for us. Under GLES2 the alpha test is * implemented in the fragment shader so there is no enable for it */ GE (context, glEnable (GL_ALPHA_TEST)); #endif _context->current_modelview_entry = NULL; _context->current_projection_entry = NULL; _cogl_matrix_entry_identity_init (&_context->identity_entry); _cogl_matrix_entry_cache_init (&_context->builtin_flushed_projection); _cogl_matrix_entry_cache_init (&_context->builtin_flushed_modelview); default_texture_bitmap = cogl_bitmap_new_for_data (_context, 1, 1, /* width/height */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 4, /* rowstride */ default_texture_data); /* Create default textures used for fall backs */ context->default_gl_texture_2d_tex = cogl_texture_2d_new_from_bitmap (default_texture_bitmap, /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, NULL); /* If 3D or rectangle textures aren't supported then these should just silently return NULL */ context->default_gl_texture_3d_tex = cogl_texture_3d_new_from_bitmap (default_texture_bitmap, 1, /* height */ 1, /* depth */ COGL_PIXEL_FORMAT_RGBA_8888_PRE, NULL); context->default_gl_texture_rect_tex = cogl_texture_rectangle_new_from_bitmap (default_texture_bitmap, COGL_PIXEL_FORMAT_RGBA_8888_PRE, NULL); cogl_object_unref (default_texture_bitmap); context->atlases = NULL; g_hook_list_init (&context->atlas_reorganize_callbacks, sizeof (GHook)); _context->buffer_map_fallback_array = g_byte_array_new (); _context->buffer_map_fallback_in_use = FALSE; /* As far as I can tell, GL_POINT_SPRITE doesn't have any effect unless GL_COORD_REPLACE is enabled for an individual layer. Therefore it seems like it should be ok to just leave it enabled all the time instead of having to have a set property on each pipeline to track whether any layers have point sprite coords enabled. We don't need to do this for GLES2 because point sprites are handled using a builtin varying in the shader. */ if (_context->driver != COGL_DRIVER_GLES2 && cogl_has_feature (context, COGL_FEATURE_ID_POINT_SPRITE)) GE (context, glEnable (GL_POINT_SPRITE)); return context; }
CoglTexture2D * cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, struct wl_resource *buffer, CoglError **error) { struct wl_shm_buffer *shm_buffer; CoglTexture2D *tex = NULL; shm_buffer = wl_shm_buffer_get (buffer); if (shm_buffer) { int stride = wl_shm_buffer_get_stride (shm_buffer); int width = wl_shm_buffer_get_width (shm_buffer); int height = wl_shm_buffer_get_height (shm_buffer); CoglPixelFormat format; CoglTextureComponents components; CoglBitmap *bmp; shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components); bmp = cogl_bitmap_new_for_data (ctx, width, height, format, stride, wl_shm_buffer_get_data (shm_buffer)); tex = cogl_texture_2d_new_from_bitmap (bmp); cogl_texture_set_components (COGL_TEXTURE (tex), components); cogl_object_unref (bmp); if (!cogl_texture_allocate (COGL_TEXTURE (tex), error)) { cogl_object_unref (tex); return NULL; } else return tex; } else { int format, width, height; if (_cogl_egl_query_wayland_buffer (ctx, buffer, EGL_TEXTURE_FORMAT, &format) && _cogl_egl_query_wayland_buffer (ctx, buffer, EGL_WIDTH, &width) && _cogl_egl_query_wayland_buffer (ctx, buffer, EGL_HEIGHT, &height)) { EGLImageKHR image; CoglPixelFormat internal_format; _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints & COGL_RENDERER_CONSTRAINT_USES_EGL, NULL); switch (format) { case EGL_TEXTURE_RGB: internal_format = COGL_PIXEL_FORMAT_RGB_888; break; case EGL_TEXTURE_RGBA: internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; break; default: _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Can't create texture from unknown " "wayland buffer format %d\n", format); return NULL; } image = _cogl_egl_create_image (ctx, EGL_WAYLAND_BUFFER_WL, buffer, NULL); tex = _cogl_egl_texture_2d_new_from_image (ctx, width, height, internal_format, image, error); _cogl_egl_destroy_image (ctx, image); return tex; } } _cogl_set_error (error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_UNSUPPORTED, "Can't create texture from unknown " "wayland buffer type\n"); return NULL; }
CoglTexture * cogl_texture_new_from_bitmap (CoglBitmap *bitmap, CoglTextureFlags flags, CoglPixelFormat internal_format, CoglError **error) { CoglContext *ctx = _cogl_bitmap_get_context (bitmap); CoglAtlasTexture *atlas_tex; CoglTexture *tex; CoglError *internal_error = NULL; /* First try putting the texture in the atlas */ if ((atlas_tex = _cogl_atlas_texture_new_from_bitmap (bitmap, flags, internal_format, &internal_error))) return COGL_TEXTURE (atlas_tex); if (cogl_error_matches (internal_error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_NO_MEMORY)) { _cogl_propagate_error (error, internal_error); return NULL; } cogl_error_free (internal_error); internal_error = NULL; /* If that doesn't work try a fast path 2D texture */ if ((_cogl_util_is_pot (bitmap->width) && _cogl_util_is_pot (bitmap->height)) || (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) && cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP))) { tex = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap, internal_format, &internal_error)); if (cogl_error_matches (internal_error, COGL_SYSTEM_ERROR, COGL_SYSTEM_ERROR_NO_MEMORY)) { _cogl_propagate_error (error, internal_error); return NULL; } if (!tex) { cogl_error_free (internal_error); internal_error = NULL; } } else tex = NULL; if (tex) { CoglBool auto_mipmap = !(flags & COGL_TEXTURE_NO_AUTO_MIPMAP); cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (tex), auto_mipmap); } else { /* Otherwise create a sliced texture */ tex = COGL_TEXTURE (_cogl_texture_2d_sliced_new_from_bitmap (bitmap, flags, internal_format, error)); } return tex; }
RutAsset * rut_asset_new_from_data (RutContext *ctx, const char *path, RutAssetType type, uint8_t *data, size_t len) { RutAsset *asset = g_slice_new0 (RutAsset); rut_object_init (&asset->_parent, &rut_asset_type); asset->ref_count = 1; asset->ctx = ctx; asset->type = type; switch (type) { case RUT_ASSET_TYPE_BUILTIN: case RUT_ASSET_TYPE_TEXTURE: case RUT_ASSET_TYPE_NORMAL_MAP: case RUT_ASSET_TYPE_ALPHA_MASK: { GInputStream *istream = g_memory_input_stream_new_from_data (data, len, NULL); GError *error = NULL; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream (istream, NULL, &error); CoglBitmap *bitmap; CoglError *cogl_error = NULL; if (!pixbuf) { g_slice_free (RutAsset, asset); g_warning ("Failed to load asset texture: %s", error->message); g_error_free (error); return NULL; } g_object_unref (istream); bitmap = bitmap_new_from_pixbuf (ctx->cogl_context, pixbuf); asset->texture = COGL_TEXTURE ( cogl_texture_2d_new_from_bitmap (bitmap, COGL_PIXEL_FORMAT_ANY, &cogl_error)); cogl_object_unref (bitmap); g_object_unref (pixbuf); if (!asset->texture) { g_slice_free (RutAsset, asset); g_warning ("Failed to load asset texture: %s", cogl_error->message); cogl_error_free (cogl_error); return NULL; } break; } case RUT_ASSET_TYPE_PLY_MODEL: { RutPLYAttributeStatus padding_status[G_N_ELEMENTS (ply_attributes)]; GError *error = NULL; asset->mesh = rut_mesh_new_from_ply_data (ctx, data, len, ply_attributes, G_N_ELEMENTS (ply_attributes), padding_status, &error); if (!asset->mesh) { g_slice_free (RutAsset, asset); g_warning ("could not load model %s: %s", path, error->message); g_error_free (error); return NULL; } break; } } asset->path = g_strdup (path); return asset; }
static gboolean shm_buffer_attach (MetaWaylandBuffer *buffer, CoglTexture **texture, gboolean *changed_texture, GError **error) { MetaBackend *backend = meta_get_backend (); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); struct wl_shm_buffer *shm_buffer; int stride, width, height; CoglPixelFormat format; CoglTextureComponents components; CoglBitmap *bitmap; CoglTexture *new_texture; shm_buffer = wl_shm_buffer_get (buffer->resource); stride = wl_shm_buffer_get_stride (shm_buffer); width = wl_shm_buffer_get_width (shm_buffer); height = wl_shm_buffer_get_height (shm_buffer); shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components); if (*texture && cogl_texture_get_width (*texture) == width && cogl_texture_get_height (*texture) == height && cogl_texture_get_components (*texture) == components && _cogl_texture_get_format (*texture) == format) { buffer->is_y_inverted = TRUE; *changed_texture = FALSE; return TRUE; } cogl_clear_object (texture); wl_shm_buffer_begin_access (shm_buffer); bitmap = cogl_bitmap_new_for_data (cogl_context, width, height, format, stride, wl_shm_buffer_get_data (shm_buffer)); new_texture = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap)); cogl_texture_set_components (new_texture, components); if (!cogl_texture_allocate (new_texture, error)) { g_clear_pointer (&new_texture, cogl_object_unref); if (g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE)) { CoglTexture2DSliced *texture_sliced; g_clear_error (error); texture_sliced = cogl_texture_2d_sliced_new_from_bitmap (bitmap, COGL_TEXTURE_MAX_WASTE); new_texture = COGL_TEXTURE (texture_sliced); cogl_texture_set_components (new_texture, components); if (!cogl_texture_allocate (new_texture, error)) g_clear_pointer (&new_texture, cogl_object_unref); } } cogl_object_unref (bitmap); wl_shm_buffer_end_access (shm_buffer); if (!new_texture) return FALSE; *texture = new_texture; *changed_texture = TRUE; buffer->is_y_inverted = TRUE; return TRUE; }