static gboolean should_use_rectangle (void) { _COGL_GET_CONTEXT (ctxt, FALSE); if (ctxt->winsys.rectangle_state == COGL_WINSYS_RECTANGLE_STATE_UNKNOWN) { if (cogl_features_available (COGL_FEATURE_TEXTURE_RECTANGLE)) { const char *rect_env; /* Use the rectangle only if it is available and either: the COGL_PIXMAP_TEXTURE_RECTANGLE environment variable is set to 'force' *or* the env var is set to 'allow' or not set and NPOTs textures are not available */ ctxt->winsys.rectangle_state = cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) ? COGL_WINSYS_RECTANGLE_STATE_DISABLE : COGL_WINSYS_RECTANGLE_STATE_ENABLE; if ((rect_env = g_getenv ("COGL_PIXMAP_TEXTURE_RECTANGLE")) || /* For compatibility, we'll also look at the old Clutter environment variable */ (rect_env = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE"))) { if (g_ascii_strcasecmp (rect_env, "force") == 0) ctxt->winsys.rectangle_state = COGL_WINSYS_RECTANGLE_STATE_ENABLE; else if (g_ascii_strcasecmp (rect_env, "disable") == 0) ctxt->winsys.rectangle_state = COGL_WINSYS_RECTANGLE_STATE_DISABLE; else if (g_ascii_strcasecmp (rect_env, "allow")) g_warning ("Unknown value for COGL_PIXMAP_TEXTURE_RECTANGLE, " "should be 'force' or 'disable'"); } } else ctxt->winsys.rectangle_state = COGL_WINSYS_RECTANGLE_STATE_DISABLE; } return ctxt->winsys.rectangle_state == COGL_WINSYS_RECTANGLE_STATE_ENABLE; }
CoglVertexArray * cogl_vertex_array_new (gsize bytes, const void *data) { CoglVertexArray *array = g_slice_new (CoglVertexArray); gboolean use_malloc; if (!cogl_features_available (COGL_FEATURE_VBOS)) use_malloc = TRUE; else use_malloc = FALSE; /* parent's constructor */ _cogl_buffer_initialize (COGL_BUFFER (array), bytes, use_malloc, COGL_BUFFER_BIND_TARGET_VERTEX_ARRAY, COGL_BUFFER_USAGE_HINT_VERTEX_ARRAY, COGL_BUFFER_UPDATE_HINT_STATIC); _cogl_vertex_array_object_new (array); if (data) cogl_buffer_set_data (COGL_BUFFER (array), 0, data, bytes); return array; }
static gboolean _cogl_texture_2d_can_create (unsigned int width, unsigned int height, CoglPixelFormat internal_format) { GLenum gl_intformat; GLenum gl_type; /* If the driver doesn't support glGenerateMipmap then we need to store a copy of the first pixels to cause an update. Instead of duplicating the code here we'll just make it fallback to CoglTexture2DSliced */ if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) return FALSE; /* If NPOT textures aren't supported then the size must be a power of two */ if (!cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) && (!_cogl_texture_2d_is_pot (width) || !_cogl_texture_2d_is_pot (height))) return FALSE; _cogl_pixel_format_to_gl (internal_format, &gl_intformat, NULL, &gl_type); /* Check that the driver can create a texture with that size */ if (!_cogl_texture_driver_size_supported (GL_TEXTURE_2D, gl_intformat, gl_type, width, height)) return FALSE; return TRUE; }
void test_cogl_pipeline_uniforms (TestUtilsGTestFixture *fixture, void *user_data) { TestUtilsSharedState *shared_state = user_data; /* If shaders aren't supported then we can't run the test */ if (cogl_features_available (COGL_FEATURE_SHADERS_GLSL)) { TestState state; init_state (&state); cogl_ortho (/* left, right */ 0, cogl_framebuffer_get_width (shared_state->fb), /* bottom, top */ cogl_framebuffer_get_height (shared_state->fb), 0, /* z near, far */ -1, 100); paint (&state); validate_result (); /* Try the test again after querying the location of a large number of uniforms. This should verify that the bitmasks still work even if they have to allocate a separate array to store the bits */ init_long_pipeline_state (&state); paint (&state); paint_long_pipeline (&state); validate_result (); validate_long_pipeline_result (); destroy_state (&state); if (g_test_verbose ()) g_print ("OK\n"); } else if (g_test_verbose ()) g_print ("Skipping\n"); }
CoglHandle cogl_pixel_buffer_new_EXP (unsigned int size) { CoglPixelBuffer *pixel_buffer = g_slice_new0 (CoglPixelBuffer); CoglBuffer *buffer = COGL_BUFFER (pixel_buffer); _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); /* parent's constructor */ _cogl_buffer_initialize (buffer, size, COGL_BUFFER_USAGE_HINT_TEXTURE, COGL_BUFFER_UPDATE_HINT_STATIC); /* malloc version only for GLES */ #if !defined (COGL_HAS_GLES) if (cogl_features_available (COGL_FEATURE_PBOS)) { /* PBOS */ buffer->vtable = &cogl_pixel_buffer_vtable; GE( glGenBuffers (1, &buffer->gl_handle) ); COGL_BUFFER_SET_FLAG (buffer, BUFFER_OBJECT); } else #endif { /* malloc fallback subclass */ buffer->vtable = &cogl_malloc_pixel_buffer_vtable; /* create the buffer here as there's no point for a lazy allocation in * the malloc case */ buffer->data = g_malloc (size); } pixel_buffer->flags = COGL_PIXEL_BUFFER_FLAG_NONE; /* return COGL_INVALID_HANDLE; */ return _cogl_pixel_buffer_handle_new (pixel_buffer); }
static gboolean get_texture_bits_via_offscreen (CoglHandle texture_handle, int x, int y, int width, int height, guint8 *dst_bits, unsigned int dst_rowstride, CoglPixelFormat dst_format) { CoglFramebuffer *framebuffer; _COGL_GET_CONTEXT (ctx, FALSE); if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) return FALSE; framebuffer = _cogl_offscreen_new_to_texture_full (texture_handle, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0); if (framebuffer == NULL) return FALSE; cogl_push_framebuffer (framebuffer); _cogl_read_pixels_with_rowstride (x, y, width, height, COGL_READ_PIXELS_COLOR_BUFFER, dst_format, dst_bits, dst_rowstride); cogl_pop_framebuffer (); cogl_object_unref (framebuffer); return TRUE; }
void _cogl_flush_clip_state (CoglClipStackState *clip_state) { CoglClipStack *stack; int has_clip_planes; gboolean using_clip_planes = FALSE; gboolean using_stencil_buffer = FALSE; GList *node; int scissor_x0 = 0; int scissor_y0 = 0; int scissor_x1 = G_MAXINT; int scissor_y1 = G_MAXINT; CoglMatrixStack *modelview_stack = _cogl_framebuffer_get_modelview_stack (_cogl_get_framebuffer ()); if (!clip_state->stack_dirty) return; /* The current primitive journal does not support tracking changes to the * clip stack... */ _cogl_journal_flush (); /* XXX: the handling of clipping is quite complex. It may involve use of * the Cogl Journal or other Cogl APIs which may end up recursively * wanting to ensure the clip state is flushed. We need to ensure we * don't recurse infinitely... */ clip_state->stack_dirty = FALSE; has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES); stack = clip_state->stacks->data; clip_state->stencil_used = FALSE; disable_clip_planes (); disable_stencil_buffer (); GE (glDisable (GL_SCISSOR_TEST)); /* If the stack is empty then there's nothing else to do */ if (stack->stack_top == NULL) return; /* Find the bottom of the stack */ for (node = stack->stack_top; node->next; node = node->next); /* Re-add every entry from the bottom of the stack up */ for (; node; node = node->prev) { gpointer entry = node->data; CoglClipStackEntryType type = *(CoglClipStackEntryType *) entry; if (type == COGL_CLIP_STACK_PATH) { CoglClipStackEntryPath *path = (CoglClipStackEntryPath *) entry; _cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_set (modelview_stack, &path->matrix); _cogl_add_path_to_stencil_buffer (path->path_nodes_min, path->path_nodes_max, path->path_size, path->path, using_stencil_buffer, TRUE); _cogl_matrix_stack_pop (modelview_stack); using_stencil_buffer = TRUE; /* We can't use clip planes any more */ has_clip_planes = FALSE; } else if (type == COGL_CLIP_STACK_RECT) { CoglClipStackEntryRect *rect = (CoglClipStackEntryRect *) entry; _cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_set (modelview_stack, &rect->matrix); /* If this is the first entry and we support clip planes then use that instead */ if (has_clip_planes) { set_clip_planes (rect->x0, rect->y0, rect->x1, rect->y1); using_clip_planes = TRUE; /* We can't use clip planes a second time */ has_clip_planes = FALSE; } else { add_stencil_clip_rectangle (rect->x0, rect->y0, rect->x1, rect->y1, !using_stencil_buffer); using_stencil_buffer = TRUE; } _cogl_matrix_stack_pop (modelview_stack); } else { /* Get the intersection of all window space rectangles in the clip * stack */ CoglClipStackEntryWindowRect *window_rect = entry; scissor_x0 = MAX (scissor_x0, window_rect->x0); scissor_y0 = MAX (scissor_y0, window_rect->y0); scissor_x1 = MIN (scissor_x1, window_rect->x1); scissor_y1 = MIN (scissor_y1, window_rect->y1); } } /* Enabling clip planes is delayed to now so that they won't affect setting up the stencil buffer */ if (using_clip_planes) enable_clip_planes (); if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1) scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = 0; if (!(scissor_x0 == 0 && scissor_y0 == 0 && scissor_x1 == G_MAXINT && scissor_y1 == G_MAXINT)) { GE (glEnable (GL_SCISSOR_TEST)); GE (glScissor (scissor_x0, scissor_y0, scissor_x1 - scissor_x0, scissor_y1 - scissor_y0)); } clip_state->stencil_used = using_stencil_buffer; }
static gboolean _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference) { CoglPipelineShaderState *shader_state; CoglPipeline *template_pipeline = NULL; CoglProgram *user_program; _COGL_GET_CONTEXT (ctx, FALSE); if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL)) return FALSE; user_program = cogl_pipeline_get_user_program (pipeline); /* If the user program has a vertex shader that isn't GLSL then the appropriate vertend for that language should handle it */ if (user_program && _cogl_program_has_vertex_shader (user_program) && _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL) return FALSE; /* Now lookup our glsl backend private state (allocating if * necessary) */ shader_state = get_shader_state (pipeline); if (shader_state == NULL) { CoglPipeline *authority; /* Get the authority for anything affecting vertex shader state */ authority = _cogl_pipeline_find_equivalent_parent (pipeline, COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN & ~COGL_PIPELINE_STATE_LAYERS, COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN); shader_state = get_shader_state (authority); if (shader_state == NULL) { /* Check if there is already a similar cached pipeline whose shader state we can share */ if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) { template_pipeline = _cogl_pipeline_cache_get_vertex_template (ctx->pipeline_cache, authority); shader_state = get_shader_state (template_pipeline); } if (shader_state) shader_state->ref_count++; else shader_state = shader_state_new (); set_shader_state (authority, shader_state); if (template_pipeline) { shader_state->ref_count++; set_shader_state (template_pipeline, shader_state); } } if (authority != pipeline) { shader_state->ref_count++; set_shader_state (pipeline, shader_state); } } if (shader_state->gl_shader) { /* If we already have a valid GLSL shader then we don't need to generate a new one. However if there's a user program and it has changed since the last link then we do need a new shader */ if (user_program == NULL || shader_state->user_program_age == user_program->age) return TRUE; /* We need to recreate the shader so destroy the existing one */ GE( ctx, glDeleteShader (shader_state->gl_shader) ); shader_state->gl_shader = 0; } /* If we make it here then we have a shader_state struct without a gl_shader either because this is the first time we've encountered it or because the user program has changed */ if (user_program) shader_state->user_program_age = user_program->age; /* If the user program contains a vertex shader then we don't need to generate one */ if (user_program && _cogl_program_has_vertex_shader (user_program)) return TRUE; /* We reuse two grow-only GStrings for code-gen. One string contains the uniform and attribute declarations while the other contains the main function. We need two strings because we need to dynamically declare attributes as the add_layer callback is invoked */ g_string_set_size (ctx->codegen_header_buffer, 0); g_string_set_size (ctx->codegen_source_buffer, 0); shader_state->header = ctx->codegen_header_buffer; shader_state->source = ctx->codegen_source_buffer; g_string_append (shader_state->source, "void\n" "main ()\n" "{\n"); if (ctx->driver == COGL_DRIVER_GLES2) /* There is no builtin uniform for the pointsize on GLES2 so we need to copy it from the custom uniform in the vertex shader */ g_string_append (shader_state->source, " cogl_point_size_out = cogl_point_size_in;\n"); /* On regular OpenGL we'll just flush the point size builtin */ else if (pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_POINT_SIZE); if (ctx->point_size_cache != authority->big_state->point_size) { GE( ctx, glPointSize (authority->big_state->point_size) ); ctx->point_size_cache = authority->big_state->point_size; } } return TRUE; }
static GSList * clutter_gst_build_renderers_list (ClutterGstSymbols *syms) { GSList *list = NULL; const gchar *gl_extensions; GLint nb_texture_units = 0; gint features = 0, i; /* The order of the list of renderers is important. They will be prepended * to a GSList and we'll iterate over that list to choose the first matching * renderer. Thus if you want to use the fp renderer over the glsl one, the * fp renderer has to be put after the glsl one in this array */ ClutterGstRenderer *renderers[] = { &rgb24_renderer, &rgb32_renderer, &yv12_glsl_renderer, &i420_glsl_renderer, #ifdef CLUTTER_COGL_HAS_GL &yv12_fp_renderer, &i420_fp_renderer, #endif &ayuv_glsl_renderer, NULL }; /* get the features */ gl_extensions = (const gchar*) glGetString (GL_EXTENSIONS); glGetIntegerv (CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &nb_texture_units); if (nb_texture_units >= 3) features |= CLUTTER_GST_MULTI_TEXTURE; #ifdef CLUTTER_COGL_HAS_GL if (cogl_check_extension ("GL_ARB_fragment_program", gl_extensions)) { /* the shaders we'll feed to the GPU are simple enough, we don't need * to check GL limits for GL_FRAGMENT_PROGRAM_ARB */ syms->glGenProgramsARB = (GLGENPROGRAMSPROC) cogl_get_proc_address ("glGenProgramsARB"); syms->glBindProgramARB = (GLBINDPROGRAMPROC) cogl_get_proc_address ("glBindProgramARB"); syms->glProgramStringARB = (GLPROGRAMSTRINGPROC) cogl_get_proc_address ("glProgramStringARB"); if (syms->glGenProgramsARB && syms->glBindProgramARB && syms->glProgramStringARB) { features |= CLUTTER_GST_FP; } } #endif if (cogl_features_available (COGL_FEATURE_SHADERS_GLSL)) features |= CLUTTER_GST_GLSL; GST_INFO ("GL features: 0x%08x", features); for (i = 0; renderers[i]; i++) { gint needed = renderers[i]->flags; if ((needed & features) == needed) list = g_slist_prepend (list, renderers[i]); } return list; }
static gboolean get_fbconfig_for_depth (unsigned int depth, GLXFBConfig *fbconfig_ret, gboolean *can_mipmap_ret) { GLXFBConfig *fbconfigs; int n_elements, i; Display *dpy; int db, stencil, alpha, mipmap, rgba, value; int spare_cache_slot = 0; gboolean found = FALSE; _COGL_GET_CONTEXT (ctxt, FALSE); /* Check if we've already got a cached config for this depth */ for (i = 0; i < COGL_WINSYS_N_CACHED_CONFIGS; i++) if (ctxt->winsys.glx_cached_configs[i].depth == -1) spare_cache_slot = i; else if (ctxt->winsys.glx_cached_configs[i].depth == depth) { *fbconfig_ret = ctxt->winsys.glx_cached_configs[i].fb_config; *can_mipmap_ret = ctxt->winsys.glx_cached_configs[i].can_mipmap; return ctxt->winsys.glx_cached_configs[i].found; } dpy = _cogl_xlib_get_display (); fbconfigs = glXGetFBConfigs (dpy, DefaultScreen (dpy), &n_elements); db = G_MAXSHORT; stencil = G_MAXSHORT; mipmap = 0; rgba = 0; for (i = 0; i < n_elements; i++) { XVisualInfo *vi; int visual_depth; vi = glXGetVisualFromFBConfig (dpy, fbconfigs[i]); if (vi == NULL) continue; visual_depth = vi->depth; XFree (vi); if (visual_depth != depth) continue; glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_ALPHA_SIZE, &alpha); glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_BUFFER_SIZE, &value); if (value != depth && (value - alpha) != depth) continue; value = 0; if (depth == 32) { glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &value); if (value) rgba = 1; } if (!value) { if (rgba) continue; glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &value); if (!value) continue; } glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_DOUBLEBUFFER, &value); if (value > db) continue; db = value; glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_STENCIL_SIZE, &value); if (value > stencil) continue; stencil = value; /* glGenerateMipmap is defined in the offscreen extension */ if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) { glXGetFBConfigAttrib (dpy, fbconfigs[i], GLX_BIND_TO_MIPMAP_TEXTURE_EXT, &value); if (value < mipmap) continue; mipmap = value; } *fbconfig_ret = fbconfigs[i]; *can_mipmap_ret = mipmap; found = TRUE; } if (n_elements) XFree (fbconfigs); ctxt->winsys.glx_cached_configs[spare_cache_slot].depth = depth; ctxt->winsys.glx_cached_configs[spare_cache_slot].found = found; ctxt->winsys.glx_cached_configs[spare_cache_slot].fb_config = *fbconfig_ret; ctxt->winsys.glx_cached_configs[spare_cache_slot].can_mipmap = mipmap; return found; }