Esempio n. 1
0
/* Updates all the function pointers */
static void
check_egl_extensions (CoglRenderer *renderer)
{
  CoglRendererEGL *egl_renderer = renderer->winsys;
  const char *egl_extensions;
  char **split_extensions;
  int i;

  egl_extensions = eglQueryString (egl_renderer->edpy, EGL_EXTENSIONS);
  split_extensions = g_strsplit (egl_extensions, " ", 0 /* max_tokens */);

  COGL_NOTE (WINSYS, "  EGL Extensions: %s", egl_extensions);

  egl_renderer->private_features = 0;
  for (i = 0; i < G_N_ELEMENTS (winsys_feature_data); i++)
    if (_cogl_feature_check (renderer,
                             "EGL", winsys_feature_data + i, 0, 0,
                             COGL_DRIVER_GL, /* the driver isn't used */
                             split_extensions,
                             egl_renderer))
      {
        egl_renderer->private_features |=
          winsys_feature_data[i].feature_flags_private;
      }

  g_strfreev (split_extensions);
}
Esempio n. 2
0
static void
log_quad_sub_textures_cb (CoglTexture *texture,
                          const float *subtexture_coords,
                          const float *virtual_coords,
                          void *user_data)
{
  TextureSlicedQuadState *state = user_data;
  CoglFramebuffer *framebuffer = state->framebuffer;
  CoglTexture *texture_override;
  float quad_coords[4];

#define TEX_VIRTUAL_TO_QUAD(V, Q, AXIS) \
    do { \
	Q = V - state->tex_virtual_origin_##AXIS; \
	Q *= state->v_to_q_scale_##AXIS; \
	if (state->flipped_##AXIS) \
	    Q = state->quad_len_##AXIS - Q; \
	Q += state->quad_origin_##AXIS; \
    } while (0);

  TEX_VIRTUAL_TO_QUAD (virtual_coords[0], quad_coords[0], x);
  TEX_VIRTUAL_TO_QUAD (virtual_coords[1], quad_coords[1], y);

  TEX_VIRTUAL_TO_QUAD (virtual_coords[2], quad_coords[2], x);
  TEX_VIRTUAL_TO_QUAD (virtual_coords[3], quad_coords[3], y);

#undef TEX_VIRTUAL_TO_QUAD

  COGL_NOTE (DRAW,
             "~~~~~ slice\n"
             "qx1: %f\t"
             "qy1: %f\n"
             "qx2: %f\t"
             "qy2: %f\n"
             "tx1: %f\t"
             "ty1: %f\n"
             "tx2: %f\t"
             "ty2: %f\n",
             quad_coords[0], quad_coords[1],
             quad_coords[2], quad_coords[3],
             subtexture_coords[0], subtexture_coords[1],
             subtexture_coords[2], subtexture_coords[3]);

  /* We only need to override the texture if it's different from the
     main texture */
  if (texture == state->main_texture)
    texture_override = NULL;
  else
    texture_override = texture;

  _cogl_journal_log_quad (framebuffer->journal,
                          quad_coords,
                          state->pipeline,
                          1, /* one layer */
                          texture_override, /* replace the layer0 texture */
                          subtexture_coords,
                          4);
}
Esempio n. 3
0
void
_cogl_atlas_remove (CoglAtlas *atlas,
                    const CoglRectangleMapEntry *rectangle)
{
  _cogl_rectangle_map_remove (atlas->map, rectangle);

  COGL_NOTE (ATLAS, "%p: Removed rectangle sized %ix%i",
             atlas,
             rectangle->width,
             rectangle->height);
  COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste",
             atlas,
             _cogl_rectangle_map_get_width (atlas->map),
             _cogl_rectangle_map_get_height (atlas->map),
             _cogl_rectangle_map_get_n_rectangles (atlas->map),
             _cogl_rectangle_map_get_remaining_space (atlas->map) *
             100 / (_cogl_rectangle_map_get_width (atlas->map) *
                    _cogl_rectangle_map_get_height (atlas->map)));
};
Esempio n. 4
0
static void
_cogl_atlas_free (CoglAtlas *atlas)
{
  COGL_NOTE (ATLAS, "%p: Atlas destroyed", atlas);

  if (atlas->texture)
    cogl_object_unref (atlas->texture);
  if (atlas->map)
    _cogl_rectangle_map_free (atlas->map);

  g_hook_list_clear (&atlas->pre_reorganize_callbacks);
  g_hook_list_clear (&atlas->post_reorganize_callbacks);

  g_free (atlas);
}
Esempio n. 5
0
static CoglBool
cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache,
                                           PangoFont *font,
                                           PangoGlyph glyph,
                                           CoglPangoGlyphCacheValue *value)
{
  CoglAtlas *atlas = NULL;
  GSList *l;

  /* Look for an atlas that can reserve the space */
  for (l = cache->atlases; l; l = l->next)
    if (_cogl_atlas_reserve_space (l->data,
                                   value->draw_width + 1,
                                   value->draw_height + 1,
                                   value))
      {
        atlas = l->data;
        break;
      }

  /* If we couldn't find one then start a new atlas */
  if (atlas == NULL)
    {
      atlas = _cogl_atlas_new (COGL_PIXEL_FORMAT_A_8,
                               COGL_ATLAS_CLEAR_TEXTURE |
                               COGL_ATLAS_DISABLE_MIGRATION,
                               cogl_pango_glyph_cache_update_position_cb);
      COGL_NOTE (ATLAS, "Created new atlas for glyphs: %p", atlas);
      /* If we still can't reserve space then something has gone
         seriously wrong so we'll just give up */
      if (!_cogl_atlas_reserve_space (atlas,
                                      value->draw_width + 1,
                                      value->draw_height + 1,
                                      value))
        {
          cogl_object_unref (atlas);
          return FALSE;
        }

      _cogl_atlas_add_reorganize_callback
        (atlas, cogl_pango_glyph_cache_reorganize_cb, NULL, cache);

      cache->atlases = g_slist_prepend (cache->atlases, atlas);
    }

  return TRUE;
}
Esempio n. 6
0
uint8_t *
_cogl_bitmap_map (CoglBitmap *bitmap,
                  CoglBufferAccess access,
                  CoglBufferMapHint hints,
                  CoglError **error)
{
  /* Divert to another bitmap if this data is shared */
  if (bitmap->shared_bmp)
    return _cogl_bitmap_map (bitmap->shared_bmp, access, hints, error);

  g_assert (!bitmap->mapped);

  if (bitmap->buffer)
    {
      uint8_t *data = cogl_buffer_map (bitmap->buffer,
                                       access,
                                       hints,
                                       error);

      COGL_NOTE (BITMAP, "A pixel array is being mapped from a bitmap. This "
                 "usually means that some conversion on the pixel array is "
                 "needed so a sub-optimal format is being used.");

      if (data)
        {
          bitmap->mapped = TRUE;

          return data + GPOINTER_TO_INT (bitmap->data);
        }
      else
        return NULL;
    }
  else
    {
      bitmap->mapped = TRUE;

      return bitmap->data;
    }
}
Esempio n. 7
0
int
_cogl_blend_string_compile (const char *string,
                            CoglBlendStringContext context,
                            CoglBlendStringStatement *statements,
                            CoglError **error)
{
  const char *p = string;
  const char *mark = NULL;
  const char *error_string;
  ParserState state = PARSER_STATE_EXPECT_DEST_CHANNELS;
  CoglBlendStringStatement *statement = statements;
  int current_statement = 0;
  int current_arg = 0;
  int remaining_argc = 0;

#if 0
  COGL_DEBUG_SET_FLAG (COGL_DEBUG_BLEND_STRINGS);
#endif

  if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
    {
      COGL_NOTE (BLEND_STRINGS, "Compiling %s string:\n%s\n",
                 context == COGL_BLEND_STRING_CONTEXT_BLENDING ?
                 "blend" : "texture combine",
                 string);
    }

  do
    {
      if (g_ascii_isspace (*p))
        continue;

      if (*p == '\0')
        {
          switch (state)
            {
            case PARSER_STATE_EXPECT_DEST_CHANNELS:
              if (current_statement != 0)
                goto finished;
              error_string = "Empty statement";
              goto error;
            case PARSER_STATE_SCRAPING_DEST_CHANNELS:
              error_string = "Expected an '=' following the destination "
                "channel mask";
              goto error;
            case PARSER_STATE_EXPECT_FUNCTION_NAME:
              error_string = "Expected a function name";
              goto error;
            case PARSER_STATE_SCRAPING_FUNCTION_NAME:
              error_string = "Expected parenthesis after the function name";
              goto error;
            case PARSER_STATE_EXPECT_ARG_START:
              error_string = "Expected to find the start of an argument";
              goto error;
            case PARSER_STATE_EXPECT_STATEMENT_END:
              error_string = "Expected closing parenthesis for statement";
              goto error;
            }
        }

      switch (state)
        {
        case PARSER_STATE_EXPECT_DEST_CHANNELS:
          mark = p;
          state = PARSER_STATE_SCRAPING_DEST_CHANNELS;

          /* fall through */
        case PARSER_STATE_SCRAPING_DEST_CHANNELS:
          if (*p != '=')
            continue;
          if (strncmp (mark, "RGBA", 4) == 0)
            statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA;
          else if (strncmp (mark, "RGB", 3) == 0)
            statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB;
          else if (strncmp (mark, "A", 1) == 0)
            statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA;
          else
            {
              error_string = "Unknown destination channel mask; "
                "expected RGBA=, RGB= or A=";
              goto error;
            }
          state = PARSER_STATE_EXPECT_FUNCTION_NAME;
          continue;

        case PARSER_STATE_EXPECT_FUNCTION_NAME:
          mark = p;
          state = PARSER_STATE_SCRAPING_FUNCTION_NAME;

          /* fall through */
        case PARSER_STATE_SCRAPING_FUNCTION_NAME:
          if (*p != '(')
            {
              if (!is_alphanum_char (*p))
                {
                  error_string = "non alpha numeric character in function"
                    "name";
                  goto error;
                }
              continue;
            }
          statement->function = get_function_info (mark, p, context);
          if (!statement->function)
            {
              error_string = "Unknown function name";
              goto error;
            }
          remaining_argc = statement->function->argc;
          current_arg = 0;
          state = PARSER_STATE_EXPECT_ARG_START;

          /* fall through */
        case PARSER_STATE_EXPECT_ARG_START:
          if (*p != '(' && *p != ',')
            continue;
          if (remaining_argc)
            {
              p++; /* parse_argument expects to see the first char of the arg */
              if (!parse_argument (string, &p, statement,
                                   current_arg, &statement->args[current_arg],
                                   context, error))
                return 0;
              current_arg++;
              remaining_argc--;
            }
          if (!remaining_argc)
            state = PARSER_STATE_EXPECT_STATEMENT_END;
          continue;

        case PARSER_STATE_EXPECT_STATEMENT_END:
          if (*p != ')')
            {
              error_string = "Expected end of statement";
              goto error;
            }
          state = PARSER_STATE_EXPECT_DEST_CHANNELS;
          if (current_statement++ == 1)
            goto finished;
          statement = &statements[current_statement];
        }
    }
  while (p++);

finished:

  if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
    {
      if (current_statement > 0)
        print_statement (0, &statements[0]);
      if (current_statement > 1)
        print_statement (1, &statements[1]);
    }

  if (!validate_statements_for_context (statements,
                                        current_statement,
                                        context,
                                        error))
    return 0;

  return current_statement;

error:
    {
      int offset = p - string;
      _cogl_set_error (error,
                       COGL_BLEND_STRING_ERROR,
                       COGL_BLEND_STRING_ERROR_PARSE_ERROR,
                       "Syntax error at offset %d: %s",
                       offset,
                       error_string);

      if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
        {
          g_debug ("Syntax error at offset %d: %s",
                   offset, error_string);
        }
      return 0;
    }
}
Esempio n. 8
0
static CoglBool
_cogl_driver_update_features (CoglContext *context,
                              CoglError **error)
{
  CoglPrivateFeatureFlags private_flags = 0;
  CoglFeatureFlags flags = 0;
  const char *gl_extensions;
  int num_stencil_bits = 0;

  /* We have to special case getting the pointer to the glGetString
     function because we need to use it to determine what functions we
     can expect */
  context->glGetString =
    (void *) _cogl_renderer_get_proc_address (context->display->renderer,
                                              "glGetString",
                                              TRUE);

  COGL_NOTE (WINSYS,
             "Checking features\n"
             "  GL_VENDOR: %s\n"
             "  GL_RENDERER: %s\n"
             "  GL_VERSION: %s\n"
             "  GL_EXTENSIONS: %s",
             context->glGetString (GL_VENDOR),
             context->glGetString (GL_RENDERER),
             _cogl_context_get_gl_version (context),
             _cogl_context_get_gl_extensions (context));

  _cogl_gpu_info_init (context, &context->gpu);

  gl_extensions = _cogl_context_get_gl_extensions (context);

  _cogl_feature_check_ext_functions (context,
                                     -1 /* GL major version */,
                                     -1 /* GL minor version */,
                                     gl_extensions);

  GE( context, glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) );
  /* We need at least three stencil bits to combine clips */
  if (num_stencil_bits > 2)
    private_flags |= COGL_PRIVATE_FEATURE_STENCIL_BUFFER;

#ifdef HAVE_COGL_GLES
  if (context->driver == COGL_DRIVER_GLES1)
    {
      int max_clip_planes;
      GE( context, glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) );
      if (max_clip_planes >= 4)
        private_flags |= COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
    }
#endif

  if (context->driver == COGL_DRIVER_GLES2)
    {
      flags |= COGL_FEATURE_SHADERS_GLSL | COGL_FEATURE_OFFSCREEN;
      /* Note GLES 2 core doesn't support mipmaps for npot textures or
       * repeat modes other than CLAMP_TO_EDGE. */
      flags |= COGL_FEATURE_TEXTURE_NPOT_BASIC;
      flags |= COGL_FEATURE_DEPTH_RANGE;
      COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_GLSL, TRUE);
      COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);
      COGL_FLAGS_SET (context->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
      COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE);
      COGL_FLAGS_SET (context->features,
                      COGL_FEATURE_ID_MIRRORED_REPEAT, TRUE);
    }

  private_flags |= COGL_PRIVATE_FEATURE_VBOS;

  /* Both GLES 1.1 and GLES 2.0 support point sprites in core */
  flags |= COGL_FEATURE_POINT_SPRITE;
  COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_POINT_SPRITE, TRUE);

  if (context->glGenRenderbuffers)
    {
      flags |= COGL_FEATURE_OFFSCREEN;
      COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);
    }

  if (context->glBlitFramebuffer)
    private_flags |= COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT;

  if (_cogl_check_extension ("GL_OES_element_index_uint", gl_extensions))
    {
      flags |= COGL_FEATURE_UNSIGNED_INT_INDICES;
      COGL_FLAGS_SET (context->features,
                      COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE);
    }

  if (_cogl_check_extension ("GL_OES_depth_texture", gl_extensions))
    {
      flags |= COGL_FEATURE_DEPTH_TEXTURE;
      COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_TEXTURE, TRUE);
    }

  if (_cogl_check_extension ("GL_OES_texture_npot", gl_extensions))
    {
      flags |= (COGL_FEATURE_TEXTURE_NPOT |
                COGL_FEATURE_TEXTURE_NPOT_BASIC |
                COGL_FEATURE_TEXTURE_NPOT_MIPMAP |
                COGL_FEATURE_TEXTURE_NPOT_REPEAT);
      COGL_FLAGS_SET (context->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT, TRUE);
      COGL_FLAGS_SET (context->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
      COGL_FLAGS_SET (context->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE);
      COGL_FLAGS_SET (context->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, TRUE);
    }
  else if (_cogl_check_extension ("GL_IMG_texture_npot", gl_extensions))
    {
      flags |= (COGL_FEATURE_TEXTURE_NPOT_BASIC |
                COGL_FEATURE_TEXTURE_NPOT_MIPMAP);
      COGL_FLAGS_SET (context->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
      COGL_FLAGS_SET (context->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE);
    }

  if (context->glTexImage3D)
    {
      flags |= COGL_FEATURE_TEXTURE_3D;
      COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_3D, TRUE);
    }

  if (context->glMapBuffer)
    {
      /* The GL_OES_mapbuffer extension doesn't support mapping for
         read */
      flags |= COGL_FEATURE_MAP_BUFFER_FOR_WRITE;
      COGL_FLAGS_SET (context->features,
                      COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE);
    }

  if (context->glEGLImageTargetTexture2D)
    private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE;

  if (_cogl_check_extension ("GL_OES_packed_depth_stencil", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL;

  if (_cogl_check_extension ("GL_EXT_texture_format_BGRA8888", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_BGRA8888;

  if (_cogl_check_extension ("GL_EXT_unpack_subimage", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE;

  /* Cache features */
  context->private_feature_flags |= private_flags;
  context->feature_flags |= flags;

  return TRUE;
}
Esempio n. 9
0
static void
update_outputs (CoglRenderer *renderer,
                gboolean notify)
{
  CoglXlibRenderer *xlib_renderer =
    _cogl_xlib_renderer_get_data (renderer);
  XRRScreenResources *resources;
  CoglXlibTrapState state;
  gboolean error = FALSE;
  GList *new_outputs = NULL;
  GList *l, *m;
  gboolean changed = FALSE;
  int i;

  xlib_renderer->outputs_update_serial = XNextRequest (xlib_renderer->xdpy);

  resources = XRRGetScreenResources (xlib_renderer->xdpy,
                                     DefaultRootWindow (xlib_renderer->xdpy));

  _cogl_xlib_renderer_trap_errors (renderer, &state);

  for (i = 0; resources && i < resources->ncrtc && !error; i++)
    {
      XRRCrtcInfo *crtc_info = NULL;
      XRROutputInfo *output_info = NULL;
      CoglOutput *output;
      float refresh_rate = 0;
      int j;

      crtc_info = XRRGetCrtcInfo (xlib_renderer->xdpy,
                                  resources, resources->crtcs[i]);
      if (crtc_info == NULL)
        {
          error = TRUE;
          goto next;
        }

      if (crtc_info->mode == None)
        goto next;

      for (j = 0; j < resources->nmode; j++)
        {
          if (resources->modes[j].id == crtc_info->mode)
            refresh_rate = (resources->modes[j].dotClock /
                            ((float)resources->modes[j].hTotal *
                             resources->modes[j].vTotal));
        }

      output_info = XRRGetOutputInfo (xlib_renderer->xdpy,
                                      resources,
                                      crtc_info->outputs[0]);
      if (output_info == NULL)
        {
          error = TRUE;
          goto next;
        }

      output = _cogl_output_new (output_info->name);
      output->x = crtc_info->x;
      output->y = crtc_info->y;
      output->width = crtc_info->width;
      output->height = crtc_info->height;
      if ((crtc_info->rotation & (RR_Rotate_90 | RR_Rotate_270)) != 0)
        {
          output->mm_width = output_info->mm_height;
          output->mm_height = output_info->mm_width;
        }
      else
        {
          output->mm_width = output_info->mm_width;
          output->mm_height = output_info->mm_height;
        }

      output->refresh_rate = refresh_rate;

      switch (output_info->subpixel_order)
        {
        case SubPixelUnknown:
        default:
          output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
          break;
        case SubPixelNone:
          output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
          break;
        case SubPixelHorizontalRGB:
          output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
          break;
        case SubPixelHorizontalBGR:
          output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
          break;
        case SubPixelVerticalRGB:
          output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
          break;
        case SubPixelVerticalBGR:
          output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
          break;
        }

      output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;

      /* Handle the effect of rotation and reflection on subpixel order (ugh) */
      for (j = 0; j < 6; j++)
        {
          if ((crtc_info->rotation & (1 << j)) != 0)
            output->subpixel_order = subpixel_map[j][output->subpixel_order];
        }

      new_outputs = g_list_prepend (new_outputs, output);

    next:
      if (crtc_info != NULL)
        XFree (crtc_info);

      if (output_info != NULL)
        XFree (output_info);
    }

  XFree (resources);

  if (!error)
    {
      new_outputs = g_list_sort (new_outputs, (GCompareFunc)compare_outputs);

      l = new_outputs;
      m = renderer->outputs;

      while (l || m)
        {
          int cmp;
          CoglOutput *output_l = l ? (CoglOutput *)l->data : NULL;
          CoglOutput *output_m = m ? (CoglOutput *)m->data : NULL;

          if (l && m)
            cmp = compare_outputs (output_l, output_m);
          else if (l)
            cmp = -1;
          else
            cmp = 1;

          if (cmp == 0)
            {
              GList *m_next = m->next;

              if (!_cogl_output_values_equal (output_l, output_m))
                {
                  renderer->outputs = g_list_remove_link (renderer->outputs, m);
                  renderer->outputs = g_list_insert_before (renderer->outputs,
                                                            m_next, output_l);
                  cogl_object_ref (output_l);

                  changed = TRUE;
                }

              l = l->next;
              m = m_next;
            }
          else if (cmp < 0)
            {
              renderer->outputs =
                g_list_insert_before (renderer->outputs, m, output_l);
              cogl_object_ref (output_l);
              changed = TRUE;
              l = l->next;
            }
          else
            {
              GList *m_next = m->next;
              renderer->outputs = g_list_remove_link (renderer->outputs, m);
              changed = TRUE;
              m = m_next;
            }
        }
    }

  g_list_free_full (new_outputs, (GDestroyNotify)cogl_object_unref);
  _cogl_xlib_renderer_untrap_errors (renderer, &state);

  if (changed)
    {
      const CoglWinsysVtable *winsys = renderer->winsys_vtable;

      if (notify)
        COGL_NOTE (WINSYS, "Outputs changed:");
      else
        COGL_NOTE (WINSYS, "Outputs:");

      for (l = renderer->outputs; l; l = l->next)
        {
          CoglOutput *output = l->data;
          const char *subpixel_string;

          switch (output->subpixel_order)
            {
            case COGL_SUBPIXEL_ORDER_UNKNOWN:
            default:
              subpixel_string = "unknown";
              break;
            case COGL_SUBPIXEL_ORDER_NONE:
              subpixel_string = "none";
              break;
            case COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB:
              subpixel_string = "horizontal_rgb";
              break;
            case COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR:
              subpixel_string = "horizontal_bgr";
              break;
            case COGL_SUBPIXEL_ORDER_VERTICAL_RGB:
              subpixel_string = "vertical_rgb";
              break;
            case COGL_SUBPIXEL_ORDER_VERTICAL_BGR:
              subpixel_string = "vertical_bgr";
              break;
            }

          COGL_NOTE (WINSYS,
                     " %10s: +%d+%dx%dx%d mm=%dx%d dpi=%.1fx%.1f "
                     "subpixel_order=%s refresh_rate=%.3f",
                     output->name,
                     output->x, output->y, output->width, output->height,
                     output->mm_width, output->mm_height,
                     output->width / (output->mm_width / 25.4),
                     output->height / (output->mm_height / 25.4),
                     subpixel_string,
                     output->refresh_rate);
        }

      if (notify && winsys->renderer_outputs_changed != NULL)
        winsys->renderer_outputs_changed (renderer);
    }
}
Esempio n. 10
0
void
_cogl_gpu_info_init (CoglContext *ctx,
                     CoglGpuInfo *gpu)
{
  CoglGpuInfoStrings strings;
  int i;

  strings.renderer_string = (const char *) ctx->glGetString (GL_RENDERER);
  strings.version_string = _cogl_context_get_gl_version (ctx);
  strings.vendor_string = (const char *) ctx->glGetString (GL_VENDOR);

  /* Determine the driver package */
  for (i = 0; ; i++)
    {
      const CoglGpuInfoDriverPackageDescription *description =
        _cogl_gpu_info_driver_packages + i;

      if (description->check_function (&strings, &gpu->driver_package_version))
        {
          gpu->driver_package = description->driver_package;
          gpu->driver_package_name = description->name;
          break;
        }
    }

  /* Determine the GPU vendor */
  for (i = 0; ; i++)
    {
      const CoglGpuInfoVendorDescription *description =
        _cogl_gpu_info_vendors + i;

      if (description->check_function (&strings))
        {
          int j;

          gpu->vendor = description->vendor;
          gpu->vendor_name = description->name;

          for (j = 0; ; j++)
            {
              const CoglGpuInfoArchitectureDescription *architecture =
                description->architectures + j;

              if (architecture->check_function (&strings))
                {
                  gpu->architecture = architecture->architecture;
                  gpu->architecture_name = architecture->name;
                  gpu->architecture_flags = architecture->flags;
                  goto probed;
                }
            }
        }
    }

probed:

  COGL_NOTE (WINSYS, "Driver package = %s, vendor = %s, architecture = %s\n",
             gpu->driver_package_name,
             gpu->vendor_name,
             gpu->architecture_name);

  /* Determine the driver bugs */

  /* In Mesa the glReadPixels implementation is really slow
     when using the Intel driver. The Intel
     driver has a fast blit path when reading into a PBO. Reading into
     a temporary PBO and then memcpying back out to the application's
     memory is faster than a regular glReadPixels in this case */
  if (gpu->vendor == COGL_GPU_INFO_VENDOR_INTEL &&
      gpu->driver_package == COGL_GPU_INFO_DRIVER_PACKAGE_MESA)
    gpu->driver_bugs |= COGL_GPU_INFO_DRIVER_BUG_MESA_46631_SLOW_READ_PIXELS;
}
Esempio n. 11
0
static CoglRectangleMap *
_cogl_atlas_create_map (CoglPixelFormat          format,
                        unsigned int             map_width,
                        unsigned int             map_height,
                        unsigned int             n_textures,
                        CoglAtlasRepositionData *textures)
{
  GLenum gl_intformat;
  GLenum gl_format;
  GLenum gl_type;

  _COGL_GET_CONTEXT (ctx, NULL);

  ctx->driver_vtable->pixel_format_to_gl (ctx,
                                          format,
                                          &gl_intformat,
                                          &gl_format,
                                          &gl_type);

  /* Keep trying increasingly larger atlases until we can fit all of
     the textures */
  while (ctx->texture_driver->size_supported (ctx,
                                              GL_TEXTURE_2D,
                                              gl_intformat,
                                              gl_format,
                                              gl_type,
                                              map_width, map_height))
    {
      CoglRectangleMap *new_atlas = _cogl_rectangle_map_new (map_width,
                                                             map_height,
                                                             NULL);
      unsigned int i;

      COGL_NOTE (ATLAS, "Trying to resize the atlas to %ux%u",
                 map_width, map_height);

      /* Add all of the textures and keep track of the new position */
      for (i = 0; i < n_textures; i++)
        if (!_cogl_rectangle_map_add (new_atlas,
                                      textures[i].old_position.width,
                                      textures[i].old_position.height,
                                      textures[i].user_data,
                                      &textures[i].new_position))
          break;

      /* If the atlas can contain all of the textures then we have a
         winner */
      if (i >= n_textures)
        return new_atlas;
      else
        COGL_NOTE (ATLAS, "Atlas size abandoned after trying "
                   "%u out of %u textures",
                   i, n_textures);

      _cogl_rectangle_map_free (new_atlas);
      _cogl_atlas_get_next_size (&map_width, &map_height);
    }

  /* If we get here then there's no atlas that can accommodate all of
     the rectangles */

  return NULL;
}
Esempio n. 12
0
CoglBool
_cogl_atlas_reserve_space (CoglAtlas             *atlas,
                           unsigned int           width,
                           unsigned int           height,
                           void                  *user_data)
{
  CoglAtlasGetRectanglesData data;
  CoglRectangleMap *new_map;
  CoglTexture2D *new_tex;
  unsigned int map_width = 0, map_height = 0;
  CoglBool ret;
  CoglRectangleMapEntry new_position;

  /* Check if we can fit the rectangle into the existing map */
  if (atlas->map &&
      _cogl_rectangle_map_add (atlas->map, width, height,
                               user_data,
                               &new_position))
    {
      COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste",
                 atlas,
                 _cogl_rectangle_map_get_width (atlas->map),
                 _cogl_rectangle_map_get_height (atlas->map),
                 _cogl_rectangle_map_get_n_rectangles (atlas->map),
                 /* waste as a percentage */
                 _cogl_rectangle_map_get_remaining_space (atlas->map) *
                 100 / (_cogl_rectangle_map_get_width (atlas->map) *
                        _cogl_rectangle_map_get_height (atlas->map)));

      atlas->update_position_cb (user_data,
                                 atlas->texture,
                                 &new_position);

      return TRUE;
    }

  /* If we make it here then we need to reorganize the atlas. First
     we'll notify any users of the atlas that this is going to happen
     so that for example in CoglAtlasTexture it can notify that the
     storage has changed and cause a flush */
  _cogl_atlas_notify_pre_reorganize (atlas);

  /* Get an array of all the textures currently in the atlas. */
  data.n_textures = 0;
  if (atlas->map == NULL)
    data.textures = g_malloc (sizeof (CoglAtlasRepositionData));
  else
    {
      unsigned int n_rectangles =
        _cogl_rectangle_map_get_n_rectangles (atlas->map);
      data.textures = g_malloc (sizeof (CoglAtlasRepositionData) *
                                (n_rectangles + 1));
      _cogl_rectangle_map_foreach (atlas->map,
                                   _cogl_atlas_get_rectangles_cb,
                                   &data);
    }

  /* Add the new rectangle as a dummy texture so that it can be
     positioned with the rest */
  data.textures[data.n_textures].old_position.x = 0;
  data.textures[data.n_textures].old_position.y = 0;
  data.textures[data.n_textures].old_position.width = width;
  data.textures[data.n_textures].old_position.height = height;
  data.textures[data.n_textures++].user_data = user_data;

  /* The atlasing algorithm works a lot better if the rectangles are
     added in decreasing order of size so we'll first sort the
     array */
  qsort (data.textures, data.n_textures,
         sizeof (CoglAtlasRepositionData),
         _cogl_atlas_compare_size_cb);

  /* Try to create a new atlas that can contain all of the textures */
  if (atlas->map)
    {
      map_width = _cogl_rectangle_map_get_width (atlas->map);
      map_height = _cogl_rectangle_map_get_height (atlas->map);

      /* If there is enough space in for the new rectangle in the
         existing atlas with at least 6% waste we'll start with the
         same size, otherwise we'll immediately double it */
      if ((map_width * map_height -
           _cogl_rectangle_map_get_remaining_space (atlas->map) +
           width * height) * 53 / 50 >
          map_width * map_height)
        _cogl_atlas_get_next_size (&map_width, &map_height);
    }
  else
    _cogl_atlas_get_initial_size (atlas->texture_format,
                                  &map_width, &map_height);

  new_map = _cogl_atlas_create_map (atlas->texture_format,
                                    map_width, map_height,
                                    data.n_textures, data.textures);

  /* If we can't create a map with the texture then give up */
  if (new_map == NULL)
    {
      COGL_NOTE (ATLAS, "%p: Could not fit texture in the atlas", atlas);
      ret = FALSE;
    }
  /* We need to migrate the existing textures into a new texture */
  else if ((new_tex = _cogl_atlas_create_texture
            (atlas,
             _cogl_rectangle_map_get_width (new_map),
             _cogl_rectangle_map_get_height (new_map))) == NULL)
    {
      COGL_NOTE (ATLAS, "%p: Could not create a CoglTexture2D", atlas);
      _cogl_rectangle_map_free (new_map);
      ret = FALSE;
    }
  else
    {
      int waste;

      COGL_NOTE (ATLAS,
                 "%p: Atlas %s with size %ix%i",
                 atlas,
                 atlas->map == NULL ||
                 _cogl_rectangle_map_get_width (atlas->map) !=
                 _cogl_rectangle_map_get_width (new_map) ||
                 _cogl_rectangle_map_get_height (atlas->map) !=
                 _cogl_rectangle_map_get_height (new_map) ?
                 "resized" : "reorganized",
                 _cogl_rectangle_map_get_width (new_map),
                 _cogl_rectangle_map_get_height (new_map));

      if (atlas->map)
        {
          /* Move all the textures to the right position in the new
             texture. This will also update the texture's rectangle */
          _cogl_atlas_migrate (atlas,
                               data.n_textures,
                               data.textures,
                               atlas->texture,
                               COGL_TEXTURE (new_tex),
                               user_data);
          _cogl_rectangle_map_free (atlas->map);
          cogl_object_unref (atlas->texture);
        }
      else
        /* We know there's only one texture so we can just directly
           update the rectangle from its new position */
        atlas->update_position_cb (data.textures[0].user_data,
                                   COGL_TEXTURE (new_tex),
                                   &data.textures[0].new_position);

      atlas->map = new_map;
      atlas->texture = COGL_TEXTURE (new_tex);

      waste = (_cogl_rectangle_map_get_remaining_space (atlas->map) *
               100 / (_cogl_rectangle_map_get_width (atlas->map) *
                      _cogl_rectangle_map_get_height (atlas->map)));

      COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste",
                 atlas,
                 _cogl_rectangle_map_get_width (atlas->map),
                 _cogl_rectangle_map_get_height (atlas->map),
                 _cogl_rectangle_map_get_n_rectangles (atlas->map),
                 waste);

      ret = TRUE;
    }

  g_free (data.textures);

  _cogl_atlas_notify_post_reorganize (atlas);

  return ret;
}
Esempio n. 13
0
void
_cogl_clip_stack_gl_flush (CoglClipStack *stack,
                           CoglFramebuffer *framebuffer)
{
  CoglContext *ctx = framebuffer->context;
  int has_clip_planes;
  CoglBool using_clip_planes = FALSE;
  CoglBool using_stencil_buffer = FALSE;
  int scissor_x0;
  int scissor_y0;
  int scissor_x1;
  int scissor_y1;
  CoglClipStack *entry;
  int scissor_y_start;

  /* If we have already flushed this state then we don't need to do
     anything */
  if (ctx->current_clip_stack_valid)
    {
      if (ctx->current_clip_stack == stack &&
          (ctx->needs_viewport_scissor_workaround == FALSE ||
           (framebuffer->viewport_age ==
            framebuffer->viewport_age_for_scissor_workaround &&
            ctx->viewport_scissor_workaround_framebuffer ==
            framebuffer)))
        return;

      _cogl_clip_stack_unref (ctx->current_clip_stack);
    }

  ctx->current_clip_stack_valid = TRUE;
  ctx->current_clip_stack = _cogl_clip_stack_ref (stack);

  has_clip_planes =
    _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES);

  if (has_clip_planes)
    disable_clip_planes (ctx);
  GE( ctx, glDisable (GL_STENCIL_TEST) );

  /* If the stack is empty then there's nothing else to do
   *
   * See comment below about ctx->needs_viewport_scissor_workaround
   */
  if (stack == NULL && !ctx->needs_viewport_scissor_workaround)
    {
      COGL_NOTE (CLIPPING, "Flushed empty clip stack");

      GE (ctx, glDisable (GL_SCISSOR_TEST));
      return;
    }

  /* Calculate the scissor rect first so that if we eventually have to
     clear the stencil buffer then the clear will be clipped to the
     intersection of all of the bounding boxes. This saves having to
     clear the whole stencil buffer */
  _cogl_clip_stack_get_bounds (stack,
                               &scissor_x0, &scissor_y0,
                               &scissor_x1, &scissor_y1);

  /* XXX: ONGOING BUG: Intel viewport scissor
   *
   * Intel gen6 drivers don't 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 (ctx->needs_viewport_scissor_workaround)
    {
      _cogl_util_scissor_intersect (framebuffer->viewport_x,
                                    framebuffer->viewport_y,
                                    framebuffer->viewport_x +
                                      framebuffer->viewport_width,
                                    framebuffer->viewport_y +
                                      framebuffer->viewport_height,
                                    &scissor_x0, &scissor_y0,
                                    &scissor_x1, &scissor_y1);
      framebuffer->viewport_age_for_scissor_workaround =
        framebuffer->viewport_age;
      ctx->viewport_scissor_workaround_framebuffer =
        framebuffer;
    }

  /* Enable scissoring as soon as possible */
  if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1)
    scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = scissor_y_start = 0;
  else
    {
      /* We store the entry coordinates in Cogl coordinate space
       * but OpenGL requires the window origin to be the bottom
       * left so we may need to convert the incoming coordinates.
       *
       * NB: Cogl forces all offscreen rendering to be done upside
       * down so in this case no conversion is needed.
       */

      if (cogl_is_offscreen (framebuffer))
        scissor_y_start = scissor_y0;
      else
        {
          int framebuffer_height =
            cogl_framebuffer_get_height (framebuffer);

          scissor_y_start = framebuffer_height - scissor_y1;
        }
    }

  COGL_NOTE (CLIPPING, "Flushing scissor to (%i, %i, %i, %i)",
             scissor_x0, scissor_y0,
             scissor_x1, scissor_y1);

  GE (ctx, glEnable (GL_SCISSOR_TEST));
  GE (ctx, glScissor (scissor_x0, scissor_y_start,
                      scissor_x1 - scissor_x0,
                      scissor_y1 - scissor_y0));

  /* Add all of the entries. This will end up adding them in the
     reverse order that they were specified but as all of the clips
     are intersecting it should work out the same regardless of the
     order */
  for (entry = stack; entry; entry = entry->parent)
    {
      switch (entry->type)
        {
        case COGL_CLIP_STACK_PRIMITIVE:
            {
              CoglClipStackPrimitive *primitive_entry =
                (CoglClipStackPrimitive *) entry;

              COGL_NOTE (CLIPPING, "Adding stencil clip for primitive");

              add_stencil_clip_primitive (framebuffer,
                                          primitive_entry->matrix_entry,
                                          primitive_entry->primitive,
                                          primitive_entry->bounds_x1,
                                          primitive_entry->bounds_y1,
                                          primitive_entry->bounds_x2,
                                          primitive_entry->bounds_y2,
                                          using_stencil_buffer,
                                          TRUE);

              using_stencil_buffer = TRUE;
              break;
            }
        case COGL_CLIP_STACK_RECT:
            {
              CoglClipStackRect *rect = (CoglClipStackRect *) entry;

              /* We don't need to do anything extra if the clip for this
                 rectangle was entirely described by its scissor bounds */
              if (!rect->can_be_scissor)
                {
                  /* If we support clip planes and we haven't already used
                     them then use that instead */
                  if (has_clip_planes)
                    {
                      COGL_NOTE (CLIPPING,
                                 "Adding clip planes clip for rectangle");

                      set_clip_planes (framebuffer,
                                       rect->matrix_entry,
                                       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
                    {
                      COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle");

                      add_stencil_clip_rectangle (framebuffer,
                                                  rect->matrix_entry,
                                                  rect->x0,
                                                  rect->y0,
                                                  rect->x1,
                                                  rect->y1,
                                                  !using_stencil_buffer);
                      using_stencil_buffer = TRUE;
                    }
                }
              break;
            }
        case COGL_CLIP_STACK_WINDOW_RECT:
          break;
          /* We don't need to do anything for window space rectangles because
           * their functionality is entirely implemented by the entry bounding
           * box */
        }
    }

  /* 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 (ctx);
}
Esempio n. 14
0
/* In addition to writing the stack matrix into the give @matrix
 * argument this function *may* sometimes also return a pointer
 * to a matrix too so if we are querying the inverse matrix we
 * should query from the return matrix so that the result can
 * be cached within the stack. */
CoglMatrix *
cogl_matrix_entry_get (CoglMatrixEntry *entry,
                        CoglMatrix *matrix)
{
  int depth;
  CoglMatrixEntry *current;
  CoglMatrixEntry **children;
  int i;

  for (depth = 0, current = entry;
       current;
       current = current->parent, depth++)
    {
      switch (current->op)
        {
        case COGL_MATRIX_OP_LOAD_IDENTITY:
          cogl_matrix_init_identity (matrix);
          goto initialized;
        case COGL_MATRIX_OP_LOAD:
          {
            CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)current;
            *matrix = *load->matrix;
            goto initialized;
          }
        case COGL_MATRIX_OP_SAVE:
          {
            CoglMatrixEntrySave *save = (CoglMatrixEntrySave *)current;
            if (!save->cache_valid)
              {
                CoglMagazine *matrices_magazine =
                  cogl_matrix_stack_matrices_magazine;
                save->cache = _cogl_magazine_chunk_alloc (matrices_magazine);
                cogl_matrix_entry_get (current->parent, save->cache);
                save->cache_valid = TRUE;
              }
            *matrix = *save->cache;
            goto initialized;
          }
        default:
          continue;
        }
    }

initialized:

  if (depth == 0)
    {
      switch (entry->op)
        {
        case COGL_MATRIX_OP_LOAD_IDENTITY:
        case COGL_MATRIX_OP_TRANSLATE:
        case COGL_MATRIX_OP_ROTATE:
        case COGL_MATRIX_OP_ROTATE_QUATERNION:
        case COGL_MATRIX_OP_ROTATE_EULER:
        case COGL_MATRIX_OP_SCALE:
        case COGL_MATRIX_OP_MULTIPLY:
          return NULL;

        case COGL_MATRIX_OP_LOAD:
          {
            CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)entry;
            return load->matrix;
          }
        case COGL_MATRIX_OP_SAVE:
          {
            CoglMatrixEntrySave *save = (CoglMatrixEntrySave *)entry;
            return save->cache;
          }
        }
      g_warn_if_reached ();
      return NULL;
    }

#ifdef COGL_ENABLE_DEBUG
  if (!current)
    {
      g_warning ("Inconsistent matrix stack");
      return NULL;
    }

  entry->composite_gets++;
#endif

  children = g_alloca (sizeof (CoglMatrixEntry) * depth);

  /* We need walk the list of entries from the init/load/save entry
   * back towards the leaf node but the nodes don't link to their
   * children so we need to re-walk them here to add to a separate
   * array. */
  for (i = depth - 1, current = entry;
       i >= 0 && current;
       i--, current = current->parent)
    {
      children[i] = current;
    }

#ifdef COGL_ENABLE_DEBUG
  if (COGL_DEBUG_ENABLED (COGL_DEBUG_PERFORMANCE) &&
      entry->composite_gets >= 2)
    {
      COGL_NOTE (PERFORMANCE,
                 "Re-composing a matrix stack entry multiple times");
    }
#endif

  for (i = 0; i < depth; i++)
    {
      switch (children[i]->op)
        {
        case COGL_MATRIX_OP_TRANSLATE:
          {
            CoglMatrixEntryTranslate *translate =
              (CoglMatrixEntryTranslate *)children[i];
            cogl_matrix_translate (matrix,
                                   translate->x,
                                   translate->y,
                                   translate->z);
            continue;
          }
        case COGL_MATRIX_OP_ROTATE:
          {
            CoglMatrixEntryRotate *rotate=
              (CoglMatrixEntryRotate *)children[i];
            cogl_matrix_rotate (matrix,
                                rotate->angle,
                                rotate->x,
                                rotate->y,
                                rotate->z);
            continue;
          }
        case COGL_MATRIX_OP_ROTATE_EULER:
          {
            CoglMatrixEntryRotateEuler *rotate =
              (CoglMatrixEntryRotateEuler *)children[i];
            CoglEuler euler;
            cogl_euler_init (&euler,
                             rotate->heading,
                             rotate->pitch,
                             rotate->roll);
            cogl_matrix_rotate_euler (matrix,
                                      &euler);
            continue;
          }
        case COGL_MATRIX_OP_ROTATE_QUATERNION:
          {
            CoglMatrixEntryRotateQuaternion *rotate =
              (CoglMatrixEntryRotateQuaternion *)children[i];
            CoglQuaternion quaternion;
            cogl_quaternion_init_from_array (&quaternion, rotate->values);
            cogl_matrix_rotate_quaternion (matrix, &quaternion);
            continue;
          }
        case COGL_MATRIX_OP_SCALE:
          {
            CoglMatrixEntryScale *scale =
              (CoglMatrixEntryScale *)children[i];
            cogl_matrix_scale (matrix,
                               scale->x,
                               scale->y,
                               scale->z);
            continue;
          }
        case COGL_MATRIX_OP_MULTIPLY:
          {
            CoglMatrixEntryMultiply *multiply =
              (CoglMatrixEntryMultiply *)children[i];
            cogl_matrix_multiply (matrix, matrix, multiply->matrix);
            continue;
          }

        case COGL_MATRIX_OP_LOAD_IDENTITY:
        case COGL_MATRIX_OP_LOAD:
        case COGL_MATRIX_OP_SAVE:
          g_warn_if_reached ();
          continue;
        }
    }

  return NULL;
}
Esempio n. 15
0
static gboolean
_cogl_texture_pixmap_x11_update_glx_texture (CoglTexturePixmapX11 *tex_pixmap,
                                             gboolean needs_mipmap)
{
  gboolean ret = TRUE;

  _COGL_GET_CONTEXT (ctx, FALSE);

  /* If we don't have a GLX pixmap then fallback */
  if (tex_pixmap->glx_pixmap == None)
    ret = FALSE;
  else
    {
      /* Lazily create a texture to hold the pixmap */
      if (tex_pixmap->glx_tex == COGL_INVALID_HANDLE)
        {
          CoglPixelFormat texture_format;

          texture_format = (tex_pixmap->depth >= 32 ?
                            COGL_PIXEL_FORMAT_RGBA_8888_PRE :
                            COGL_PIXEL_FORMAT_RGB_888);

          if (should_use_rectangle ())
            {
              tex_pixmap->glx_tex =
                _cogl_texture_rectangle_new_with_size (tex_pixmap->width,
                                                       tex_pixmap->height,
                                                       COGL_TEXTURE_NO_ATLAS,
                                                       texture_format);

              if (tex_pixmap->glx_tex)
                COGL_NOTE (TEXTURE_PIXMAP, "Created a texture rectangle for %p",
                           tex_pixmap);
              else
                {
                  COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a "
                             "texture rectangle could not be created",
                             tex_pixmap);
                  _cogl_texture_pixmap_x11_free_glx_pixmap (tex_pixmap);
                  ret = FALSE;
                }
            }
          else
            {
              tex_pixmap->glx_tex =
                _cogl_texture_2d_new_with_size (tex_pixmap->width,
                                                tex_pixmap->height,
                                                COGL_TEXTURE_NO_ATLAS,
                                                texture_format);

              if (tex_pixmap->glx_tex)
                COGL_NOTE (TEXTURE_PIXMAP, "Created a texture 2d for %p",
                           tex_pixmap);
              else
                {
                  COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a "
                             "texture 2d could not be created",
                             tex_pixmap);
                  _cogl_texture_pixmap_x11_free_glx_pixmap (tex_pixmap);
                  ret = FALSE;
                }
            }
        }

      if (ret && needs_mipmap)
        {
          /* If we can't support mipmapping then temporarily fallback */
          if (!tex_pixmap->glx_can_mipmap)
            ret = FALSE;
          /* Recreate the GLXPixmap if it wasn't previously created with a
             mipmap tree */
          else if (!tex_pixmap->glx_pixmap_has_mipmap)
            {
              _cogl_texture_pixmap_x11_free_glx_pixmap (tex_pixmap);

              COGL_NOTE (TEXTURE_PIXMAP, "Recreating GLXPixmap with mipmap "
                         "support for %p", tex_pixmap);
              try_create_glx_pixmap (tex_pixmap, TRUE);

              /* If the pixmap failed then we'll permanently fallback to using
                 XImage. This shouldn't happen */
              if (tex_pixmap->glx_pixmap == None)
                {
                  COGL_NOTE (TEXTURE_PIXMAP, "Falling back to XGetImage "
                             "updates for %p because creating the GLXPixmap "
                             "with mipmap support failed", tex_pixmap);

                  if (tex_pixmap->glx_tex)
                    cogl_handle_unref (tex_pixmap->glx_tex);

                  ret = FALSE;
                }
              else
                tex_pixmap->bind_tex_image_queued = TRUE;
            }
        }

      if (ret && tex_pixmap->bind_tex_image_queued)
        {
          GLuint gl_handle, gl_target;

          cogl_texture_get_gl_texture (tex_pixmap->glx_tex,
                                       &gl_handle, &gl_target);

          COGL_NOTE (TEXTURE_PIXMAP, "Rebinding GLXPixmap for %p", tex_pixmap);

          GE( _cogl_bind_gl_texture_transient (gl_target, gl_handle, FALSE) );

          if (tex_pixmap->pixmap_bound)
            glXReleaseTexImage (_cogl_xlib_get_display (),
                                tex_pixmap->glx_pixmap,
                                GLX_FRONT_LEFT_EXT);

          glXBindTexImage (_cogl_xlib_get_display (),
                           tex_pixmap->glx_pixmap,
                           GLX_FRONT_LEFT_EXT,
                           NULL);

          /* According to the recommended usage in the spec for
             GLX_EXT_texture_pixmap we should release the texture after
             we've finished drawing with it and it is undefined what
             happens if you render to a pixmap that is bound to a
             texture. However that would require the texture backend to
             know when Cogl has finished painting and it may be more
             expensive to keep unbinding the texture. Leaving it bound
             appears to work on Mesa and NVidia drivers and it is also
             what Compiz does so it is probably ok */

          tex_pixmap->bind_tex_image_queued = FALSE;
          tex_pixmap->pixmap_bound = TRUE;

          _cogl_texture_2d_externally_modified (tex_pixmap->glx_tex);
        }
    }

  return ret;
}
Esempio n. 16
0
static void
_cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap)
{
  CoglTexture *tex = COGL_TEXTURE (tex_pixmap);
  Display *display;
  Visual *visual;
  CoglPixelFormat image_format;
  XImage *image;
  int src_x, src_y;
  int x, y, width, height;
  int bpp;
  int offset;
  CoglError *ignore = NULL;

  _COGL_GET_CONTEXT (ctx, NO_RETVAL);

  display = cogl_xlib_renderer_get_display (ctx->display->renderer);
  visual = tex_pixmap->visual;

  /* If the damage region is empty then there's nothing to do */
  if (tex_pixmap->damage_rect.x2 == tex_pixmap->damage_rect.x1)
    return;

  x = tex_pixmap->damage_rect.x1;
  y = tex_pixmap->damage_rect.y1;
  width = tex_pixmap->damage_rect.x2 - x;
  height = tex_pixmap->damage_rect.y2 - y;

  /* We lazily create the texture the first time it is needed in case
     this texture can be entirely handled using the GLX texture
     instead */
  if (tex_pixmap->tex == NULL)
    {
      CoglPixelFormat texture_format;

      texture_format = (tex_pixmap->depth >= 32
                        ? COGL_PIXEL_FORMAT_RGBA_8888_PRE
                        : COGL_PIXEL_FORMAT_RGB_888);

      tex_pixmap->tex = create_fallback_texture (ctx,
                                                 tex->width,
                                                 tex->height,
                                                 texture_format);
    }

  if (tex_pixmap->image == NULL)
    {
      /* If we also haven't got a shm segment then this must be the
         first time we've tried to update, so lets try allocating shm
         first */
      if (tex_pixmap->shm_info.shmid == -1)
        try_alloc_shm (tex_pixmap);

      if (tex_pixmap->shm_info.shmid == -1)
        {
          COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XGetImage", tex_pixmap);

          /* We'll fallback to using a regular XImage. We'll download
             the entire area instead of a sub region because presumably
             if this is the first update then the entire pixmap is
             needed anyway and it saves trying to manually allocate an
             XImage at the right size */
          tex_pixmap->image = XGetImage (display,
                                         tex_pixmap->pixmap,
                                         0, 0,
                                         tex->width, tex->height,
                                         AllPlanes, ZPixmap);
          image = tex_pixmap->image;
          src_x = x;
          src_y = y;
        }
      else
        {
          COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XShmGetImage",
                     tex_pixmap);

          /* Create a temporary image using the beginning of the
             shared memory segment and the right size for the region
             we want to update. We need to reallocate the XImage every
             time because there is no XShmGetSubImage. */
          image = XShmCreateImage (display,
                                   tex_pixmap->visual,
                                   tex_pixmap->depth,
                                   ZPixmap,
                                   NULL,
                                   &tex_pixmap->shm_info,
                                   width,
                                   height);
          image->data = tex_pixmap->shm_info.shmaddr;
          src_x = 0;
          src_y = 0;

          XShmGetImage (display, tex_pixmap->pixmap, image, x, y, AllPlanes);
        }
    }
  else
    {
      COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XGetSubImage", tex_pixmap);

      image = tex_pixmap->image;
      src_x = x;
      src_y = y;

      XGetSubImage (display,
                    tex_pixmap->pixmap,
                    x, y, width, height,
                    AllPlanes, ZPixmap,
                    image,
                    x, y);
    }

  image_format =
    _cogl_util_pixel_format_from_masks (visual->red_mask,
                                        visual->green_mask,
                                        visual->blue_mask,
                                        image->depth,
                                        image->bits_per_pixel,
                                        image->byte_order == LSBFirst);

  bpp = _cogl_pixel_format_get_bytes_per_pixel (image_format);
  offset = image->bytes_per_line * src_y + bpp * src_x;

  _cogl_texture_set_region (tex_pixmap->tex,
                            width,
                            height,
                            image_format,
                            image->bytes_per_line,
                            ((const uint8_t *) image->data) + offset,
                            x, y,
                            0, /* level */
                            &ignore);

  /* If we have a shared memory segment then the XImage would be a
     temporary one with no data allocated so we can just XFree it */
  if (tex_pixmap->shm_info.shmid != -1)
    XFree (image);

  memset (&tex_pixmap->damage_rect, 0, sizeof (CoglDamageRectangle));
}
Esempio n. 17
0
static CoglBool
_cogl_driver_update_features (CoglContext *ctx,
                              CoglError **error)
{
  CoglPrivateFeatureFlags private_flags = 0;
  char **gl_extensions;
  int gl_major = 0, gl_minor = 0;

  /* We have to special case getting the pointer to the glGetString*
     functions because we need to use them to determine what functions
     we can expect */
  ctx->glGetString =
    (void *) _cogl_renderer_get_proc_address (ctx->display->renderer,
                                              "glGetString",
                                              TRUE);
  ctx->glGetStringi =
    (void *) _cogl_renderer_get_proc_address (ctx->display->renderer,
                                              "glGetStringi",
                                              TRUE);
  ctx->glGetIntegerv =
    (void *) _cogl_renderer_get_proc_address (ctx->display->renderer,
                                              "glGetIntegerv",
                                              TRUE);

  gl_extensions = _cogl_context_get_gl_extensions (ctx);

  if (!check_gl_version (ctx, gl_extensions, error))
    return FALSE;

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WINSYS)))
    {
      char *all_extensions = g_strjoinv (" ", gl_extensions);

      COGL_NOTE (WINSYS,
                 "Checking features\n"
                 "  GL_VENDOR: %s\n"
                 "  GL_RENDERER: %s\n"
                 "  GL_VERSION: %s\n"
                 "  GL_EXTENSIONS: %s",
                 ctx->glGetString (GL_VENDOR),
                 ctx->glGetString (GL_RENDERER),
                 _cogl_context_get_gl_version (ctx),
                 all_extensions);

      g_free (all_extensions);
    }

  _cogl_get_gl_version (ctx, &gl_major, &gl_minor);

  _cogl_gpu_info_init (ctx, &ctx->gpu);

  ctx->glsl_major = 1;
  ctx->glsl_minor = 1;

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0))
    {
      const char *glsl_version =
        (char *)ctx->glGetString (GL_SHADING_LANGUAGE_VERSION);
      parse_gl_version (glsl_version, &ctx->glsl_major, &ctx->glsl_minor);
    }

  COGL_FLAGS_SET (ctx->features,
                  COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE);
  COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE);

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 1, 4))
    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_MIRRORED_REPEAT, TRUE);

  _cogl_feature_check_ext_functions (ctx,
                                     gl_major,
                                     gl_minor,
                                     gl_extensions);

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0) ||
      _cogl_check_extension ("GL_ARB_texture_non_power_of_two", gl_extensions))
    {
      COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT, TRUE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, TRUE);
    }

  if (_cogl_check_extension ("GL_MESA_pack_invert", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_MESA_PACK_INVERT;

  if (ctx->glGenRenderbuffers)
    {
      COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);
      private_flags |= COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS;
    }

  if (ctx->glBlitFramebuffer)
    private_flags |= COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT;

  if (ctx->glRenderbufferStorageMultisampleIMG)
    COGL_FLAGS_SET (ctx->features,
                    COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE, TRUE);

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 0) ||
      _cogl_check_extension ("GL_ARB_depth_texture", gl_extensions))
    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_DEPTH_TEXTURE, TRUE);

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 1) ||
      _cogl_check_extension ("GL_EXT_pixel_buffer_object", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_PBOS;

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 1, 4) ||
      _cogl_check_extension ("GL_EXT_blend_color", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_BLEND_CONSTANT;

  if (ctx->glGenPrograms)
    private_flags |= COGL_PRIVATE_FEATURE_ARBFP;

  if (ctx->glCreateProgram)
    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, TRUE);
  else
    {
      /* If all of the old GLSL extensions are available then we can fake
       * the GL 2.0 GLSL support by diverting to the old function names */
      if (ctx->glCreateProgramObject && /* GL_ARB_shader_objects */
          ctx->glVertexAttribPointer && /* GL_ARB_vertex_shader */
          _cogl_check_extension ("GL_ARB_fragment_shader", gl_extensions))
        {
          ctx->glCreateShader = ctx->glCreateShaderObject;
          ctx->glCreateProgram = ctx->glCreateProgramObject;
          ctx->glDeleteShader = ctx->glDeleteObject;
          ctx->glDeleteProgram = ctx->glDeleteObject;
          ctx->glAttachShader = ctx->glAttachObject;
          ctx->glUseProgram = ctx->glUseProgramObject;
          ctx->glGetProgramInfoLog = ctx->glGetInfoLog;
          ctx->glGetShaderInfoLog = ctx->glGetInfoLog;
          ctx->glGetShaderiv = ctx->glGetObjectParameteriv;
          ctx->glGetProgramiv = ctx->glGetObjectParameteriv;
          ctx->glDetachShader = ctx->glDetachObject;
          ctx->glGetAttachedShaders = ctx->glGetAttachedObjects;
          /* FIXME: there doesn't seem to be an equivalent for glIsShader
           * and glIsProgram. This doesn't matter for now because Cogl
           * doesn't use these but if we add support for simulating a
           * GLES2 context on top of regular GL then we'll need to do
           * something here */

          COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, TRUE);
        }
    }

  if ((COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0) ||
       _cogl_check_extension ("GL_ARB_point_sprite", gl_extensions)) &&

      /* If GLSL is supported then we only enable point sprite support
       * too if we have glsl >= 1.2 otherwise we don't have the
       * gl_PointCoord builtin which we depend on in the glsl backend.
       */
      (!COGL_FLAGS_GET (ctx->features, COGL_FEATURE_ID_GLSL) ||
       COGL_CHECK_GL_VERSION (ctx->glsl_major, ctx->glsl_minor, 1, 2)))
    {
      COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_POINT_SPRITE, TRUE);
    }

  if (ctx->glGenBuffers)
    {
      private_flags |= COGL_PRIVATE_FEATURE_VBOS;
      COGL_FLAGS_SET (ctx->features,
                         COGL_FEATURE_ID_MAP_BUFFER_FOR_READ, TRUE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE);
    }

  if (_cogl_check_extension ("GL_ARB_texture_rectangle", gl_extensions))
    COGL_FLAGS_SET (ctx->features,
                    COGL_FEATURE_ID_TEXTURE_RECTANGLE, TRUE);

  if (ctx->glTexImage3D)
    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_3D, TRUE);

  if (ctx->glEGLImageTargetTexture2D)
    private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE;

  if (_cogl_check_extension ("GL_EXT_packed_depth_stencil", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL;

  if (ctx->glGenSamplers)
    private_flags |= COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS;


  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 3) ||
      _cogl_check_extension ("GL_ARB_texture_swizzle", gl_extensions) ||
      _cogl_check_extension ("GL_EXT_texture_swizzle", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE;

  /* The per-vertex point size is only available via GLSL with the
   * gl_PointSize builtin. This is only available in GL 2.0 (not the
   * GLSL extensions) */
  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0))
    {
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE,
                      TRUE);
      private_flags |= COGL_PRIVATE_FEATURE_ENABLE_PROGRAM_POINT_SIZE;
    }

  if (ctx->driver == COGL_DRIVER_GL)
    {
      int max_clip_planes = 0;

      /* Features which are not available in GL 3 */
      private_flags |= (COGL_PRIVATE_FEATURE_GL_FIXED |
                        COGL_PRIVATE_FEATURE_ALPHA_TEST |
                        COGL_PRIVATE_FEATURE_QUADS |
                        COGL_PRIVATE_FEATURE_ALPHA_TEXTURES);

      GE( ctx, glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) );
      if (max_clip_planes >= 4)
        private_flags |= COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
    }

  private_flags |= (COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT |
                    COGL_PRIVATE_FEATURE_ANY_GL |
                    COGL_PRIVATE_FEATURE_FORMAT_CONVERSION |
                    COGL_PRIVATE_FEATURE_BLEND_CONSTANT |
                    COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM |
                    COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS |
                    COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL);

  if (ctx->glFenceSync)
    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_FENCE, TRUE);

  /* Cache features */
  ctx->private_feature_flags |= private_flags;

  g_strfreev (gl_extensions);

  if ((private_flags & (COGL_PRIVATE_FEATURE_ALPHA_TEXTURES |
                        COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) == 0)
    {
      _cogl_set_error (error,
                       COGL_DRIVER_ERROR,
                       COGL_DRIVER_ERROR_NO_SUITABLE_DRIVER_FOUND,
                       "The GL_ARB_texture_swizzle extension is required "
                       "to use the GL3 driver");
      return FALSE;
    }

  return TRUE;
}
Esempio n. 18
0
void
_cogl_blit_begin (CoglBlitData *data,
                  CoglHandle dst_tex,
                  CoglHandle src_tex)
{
  int i;

  if (_cogl_blit_default_mode == NULL)
    {
      const char *default_mode_string;

      /* Allow the default to be specified with an environment
         variable. For the time being these functions are only used
         when blitting between atlas textures so the environment
         variable is named to be specific to the atlas code. If we
         want to use the code in other places we should create another
         environment variable for each specific use case */
      if ((default_mode_string = g_getenv ("COGL_ATLAS_DEFAULT_BLIT_MODE")))
        {
          for (i = 0; i < G_N_ELEMENTS (_cogl_blit_modes); i++)
            if (!strcmp (_cogl_blit_modes[i].name, default_mode_string))
              {
                _cogl_blit_default_mode = _cogl_blit_modes + i;
                break;
              }

          if (i >= G_N_ELEMENTS (_cogl_blit_modes))
            {
              g_warning ("Unknown blit mode %s", default_mode_string);
              _cogl_blit_default_mode = _cogl_blit_modes;
            }
        }
      else
        /* Default to the first blit mode */
        _cogl_blit_default_mode = _cogl_blit_modes;
    }

  data->dst_tex = dst_tex;
  data->src_tex = src_tex;

  data->src_width = cogl_texture_get_width (src_tex);
  data->src_height = cogl_texture_get_height (src_tex);

  /* Try the default blit mode first */
  if (!_cogl_blit_default_mode->begin_func (data))
    {
      COGL_NOTE (ATLAS, "Failed to set up blit mode %s",
                 _cogl_blit_default_mode->name);

      /* Try all of the other modes in order */
      for (i = 0; i < G_N_ELEMENTS (_cogl_blit_modes); i++)
        if (_cogl_blit_modes + i != _cogl_blit_default_mode &&
            _cogl_blit_modes[i].begin_func (data))
          {
            /* Use this mode as the default from now on */
            _cogl_blit_default_mode = _cogl_blit_modes + i;
            break;
          }
        else
          COGL_NOTE (ATLAS,
                     "Failed to set up blit mode %s",
                     _cogl_blit_modes[i].name);

      /* The last blit mode can't fail so this should never happen */
      _COGL_RETURN_IF_FAIL (i < G_N_ELEMENTS (_cogl_blit_modes));
    }

  data->blit_mode = _cogl_blit_default_mode;

  COGL_NOTE (ATLAS, "Setup blit using %s", _cogl_blit_default_mode->name);
}
Esempio n. 19
0
static void
_cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap)
{
  Display *display;
  CoglPixelFormat image_format;
  XImage *image;
  int src_x, src_y;
  int x, y, width, height;

  display = cogl_xlib_get_display ();

  /* If the damage region is empty then there's nothing to do */
  if (tex_pixmap->damage_rect.x2 == tex_pixmap->damage_rect.x1)
    return;

  x = tex_pixmap->damage_rect.x1;
  y = tex_pixmap->damage_rect.y1;
  width = tex_pixmap->damage_rect.x2 - x;
  height = tex_pixmap->damage_rect.y2 - y;

  /* We lazily create the texture the first time it is needed in case
     this texture can be entirely handled using the GLX texture
     instead */
  if (tex_pixmap->tex == COGL_INVALID_HANDLE)
    {
      CoglPixelFormat texture_format;

      texture_format = (tex_pixmap->depth >= 32
                        ? COGL_PIXEL_FORMAT_RGBA_8888_PRE
                        : COGL_PIXEL_FORMAT_RGB_888);

      tex_pixmap->tex = cogl_texture_new_with_size (tex_pixmap->width,
                                                    tex_pixmap->height,
                                                    COGL_TEXTURE_NONE,
                                                    texture_format);
    }

  if (tex_pixmap->image == NULL)
    {
      /* If we also haven't got a shm segment then this must be the
         first time we've tried to update, so lets try allocating shm
         first */
      if (tex_pixmap->shm_info.shmid == -1)
        try_alloc_shm (tex_pixmap);

      if (tex_pixmap->shm_info.shmid == -1)
        {
          COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XGetImage", tex_pixmap);

          /* We'll fallback to using a regular XImage. We'll download
             the entire area instead of a sub region because presumably
             if this is the first update then the entire pixmap is
             needed anyway and it saves trying to manually allocate an
             XImage at the right size */
          tex_pixmap->image = XGetImage (display,
                                         tex_pixmap->pixmap,
                                         0, 0,
                                         tex_pixmap->width, tex_pixmap->height,
                                         AllPlanes, ZPixmap);
          image = tex_pixmap->image;
          src_x = x;
          src_y = y;
        }
      else
        {
          COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XShmGetImage",
                     tex_pixmap);

          /* Create a temporary image using the beginning of the
             shared memory segment and the right size for the region
             we want to update. We need to reallocate the XImage every
             time because there is no XShmGetSubImage. */
          image = XShmCreateImage (display,
                                   tex_pixmap->visual,
                                   tex_pixmap->depth,
                                   ZPixmap,
                                   NULL,
                                   &tex_pixmap->shm_info,
                                   width,
                                   height);
          image->data = tex_pixmap->shm_info.shmaddr;
          src_x = 0;
          src_y = 0;

          XShmGetImage (display, tex_pixmap->pixmap, image, x, y, AllPlanes);
        }
    }
  else
    {
      COGL_NOTE (TEXTURE_PIXMAP, "Updating %p using XGetSubImage", tex_pixmap);

      image = tex_pixmap->image;
      src_x = x;
      src_y = y;

      XGetSubImage (display,
                    tex_pixmap->pixmap,
                    x, y, width, height,
                    AllPlanes, ZPixmap,
                    image,
                    x, y);
    }

  /* xlib doesn't appear to fill in image->{red,green,blue}_mask so
     this just assumes that the image is stored as ARGB from most
     significant byte to to least significant. If the format is little
     endian that means the order will be BGRA in memory */

  switch (image->bits_per_pixel)
    {
    default:
    case 32:
      {
        /* If the pixmap is actually non-packed-pixel RGB format then
           the texture would have been created in RGB_888 format so Cogl
           will ignore the alpha channel and effectively pack it for
           us */
        image_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;

        /* If the format is actually big endian then the alpha
           component will come first */
        if (image->byte_order == MSBFirst)
          image_format |= COGL_AFIRST_BIT;
      }
      break;

    case 24:
      image_format = COGL_PIXEL_FORMAT_RGB_888;
      break;

    case 16:
      /* FIXME: this should probably swap the orders around if the
         endianness does not match */
      image_format = COGL_PIXEL_FORMAT_RGB_565;
      break;
    }

  if (image->bits_per_pixel != 16)
    {
      /* If the image is in little-endian then the order in memory is
         reversed */
      if (image->byte_order == LSBFirst)
        image_format |= COGL_BGR_BIT;
    }

  cogl_texture_set_region (tex_pixmap->tex,
                           src_x, src_y,
                           x, y, width, height,
                           image->width,
                           image->height,
                           image_format,
                           image->bytes_per_line,
                           (const guint8 *) image->data);

  /* If we have a shared memory segment then the XImage would be a
     temporary one with no data allocated so we can just XFree it */
  if (tex_pixmap->shm_info.shmid != -1)
    XFree (image);

  memset (&tex_pixmap->damage_rect, 0, sizeof (CoglDamageRectangle));
}
Esempio n. 20
0
static CoglBool
_cogl_driver_update_features (CoglContext *context,
                              CoglError **error)
{
    CoglPrivateFeatureFlags private_flags = 0;
    char **gl_extensions;

    /* We have to special case getting the pointer to the glGetString
       function because we need to use it to determine what functions we
       can expect */
    context->glGetString =
        (void *) _cogl_renderer_get_proc_address (context->display->renderer,
                "glGetString",
                TRUE);

    gl_extensions = _cogl_context_get_gl_extensions (context);

    if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WINSYS)))
    {
        char *all_extensions = g_strjoinv (" ", gl_extensions);

        COGL_NOTE (WINSYS,
                   "Checking features\n"
                   "  GL_VENDOR: %s\n"
                   "  GL_RENDERER: %s\n"
                   "  GL_VERSION: %s\n"
                   "  GL_EXTENSIONS: %s",
                   context->glGetString (GL_VENDOR),
                   context->glGetString (GL_RENDERER),
                   _cogl_context_get_gl_version (context),
                   all_extensions);

        g_free (all_extensions);
    }

    context->glsl_major = 1;
    context->glsl_minor = 0;

    _cogl_gpu_info_init (context, &context->gpu);

    _cogl_feature_check_ext_functions (context,
                                       -1 /* GL major version */,
                                       -1 /* GL minor version */,
                                       gl_extensions);

#ifdef HAVE_COGL_GLES
    if (context->driver == COGL_DRIVER_GLES1)
    {
        int max_clip_planes;
        GE( context, glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) );
        if (max_clip_planes >= 4)
            private_flags |= COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
    }
#endif

    if (context->driver == COGL_DRIVER_GLES2)
    {
        /* Note GLES 2 core doesn't support mipmaps for npot textures or
         * repeat modes other than CLAMP_TO_EDGE. */
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_GLSL, TRUE);
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_MIRRORED_REPEAT, TRUE);

        private_flags |= COGL_PRIVATE_FEATURE_BLEND_CONSTANT;
    }
    else if (context->driver == COGL_DRIVER_GLES1)
        private_flags |= (COGL_PRIVATE_FEATURE_FIXED_FUNCTION |
                          COGL_PRIVATE_FEATURE_ALPHA_TEST |
                          COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM);

    private_flags |= (COGL_PRIVATE_FEATURE_VBOS |
                      COGL_PRIVATE_FEATURE_ANY_GL |
                      COGL_PRIVATE_FEATURE_ALPHA_TEXTURES);

    /* Both GLES 1.1 and GLES 2.0 support point sprites in core */
    COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_POINT_SPRITE, TRUE);

    if (context->glGenRenderbuffers)
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);

    if (context->glBlitFramebuffer)
        private_flags |= COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT;

    if (_cogl_check_extension ("GL_OES_element_index_uint", gl_extensions))
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE);

    if (_cogl_check_extension ("GL_OES_depth_texture", gl_extensions))
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_TEXTURE, TRUE);

    if (_cogl_check_extension ("GL_OES_texture_npot", gl_extensions))
    {
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, TRUE);
    }
    else if (_cogl_check_extension ("GL_IMG_texture_npot", gl_extensions))
    {
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE);
    }

    if (context->glTexImage3D)
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_3D, TRUE);

    if (context->glMapBuffer)
        /* The GL_OES_mapbuffer extension doesn't support mapping for
           read */
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE);

    if (context->glEGLImageTargetTexture2D)
        private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE;

    if (_cogl_check_extension ("GL_OES_packed_depth_stencil", gl_extensions))
        private_flags |= COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL;

    if (_cogl_check_extension ("GL_EXT_texture_format_BGRA8888", gl_extensions))
        private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_BGRA8888;

    if (_cogl_check_extension ("GL_EXT_unpack_subimage", gl_extensions))
        private_flags |= COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE;

    /* Cache features */
    context->private_feature_flags |= private_flags;

    g_strfreev (gl_extensions);

    return TRUE;
}
Esempio n. 21
0
void
_cogl_framebuffer_draw_multitextured_rectangles (
                                        CoglFramebuffer *framebuffer,
                                        CoglPipeline *pipeline,
                                        CoglMultiTexturedRect *rects,
                                        int n_rects,
                                        CoglBool disable_legacy_state)
{
  CoglContext *ctx = framebuffer->context;
  CoglPipeline *original_pipeline;
  ValidateLayerState state;
  int i;

  original_pipeline = pipeline;

  /*
   * Validate all the layers of the current source pipeline...
   */
  state.ctx = ctx;
  state.i = -1;
  state.first_layer = 0;
  state.override_source = NULL;
  state.all_use_sliced_quad_fallback = FALSE;
  cogl_pipeline_foreach_layer (pipeline,
                               _cogl_rectangles_validate_layer_cb,
                               &state);

  if (state.override_source)
    pipeline = state.override_source;

  if (!disable_legacy_state)
    {
      if (G_UNLIKELY (ctx->legacy_state_set) &&
          _cogl_get_enable_legacy_state ())
        {
          /* If we haven't already made a pipeline copy */
          if (pipeline == original_pipeline)
            pipeline = cogl_pipeline_copy (pipeline);
          _cogl_pipeline_apply_legacy_state (pipeline);
        }
    }

  /*
   * Emit geometry for each of the rectangles...
   */

  for (i = 0; i < n_rects; i++)
    {
      CoglTexture *texture;
      const float default_tex_coords[4] = {0.0, 0.0, 1.0, 1.0};
      const float *tex_coords;

      if (!state.all_use_sliced_quad_fallback)
        {
          CoglBool success =
            _cogl_multitexture_quad_single_primitive (framebuffer,
                                                      pipeline,
                                                      rects[i].position,
                                                      rects[i].tex_coords,
                                                      rects[i].tex_coords_len);

          /* NB: If _cogl_multitexture_quad_single_primitive fails then it
           * means the user tried to use texture repeat with a texture that
           * can't be repeated by the GPU (e.g. due to waste or use of
           * GL_TEXTURE_RECTANGLE_ARB) */
          if (success)
            continue;
        }

      /* If multitexturing failed or we are drawing with a sliced texture
       * then we only support a single layer so we pluck out the texture
       * from the first pipeline layer... */
      texture = cogl_pipeline_get_layer_texture (pipeline, state.first_layer);

      if (rects[i].tex_coords)
        tex_coords = rects[i].tex_coords;
      else
        tex_coords = default_tex_coords;

      COGL_NOTE (DRAW, "Drawing Tex Quad (Multi-Prim Mode)");

      _cogl_texture_quad_multiple_primitives (framebuffer,
                                              pipeline,
                                              texture,
                                              state.first_layer,
                                              rects[i].position,
                                              tex_coords[0],
                                              tex_coords[1],
                                              tex_coords[2],
                                              tex_coords[3]);
    }

  if (pipeline != original_pipeline)
    cogl_object_unref (pipeline);
}
Esempio n. 22
0
static void
process_damage_event (CoglTexturePixmapX11 *tex_pixmap,
                      XDamageNotifyEvent *damage_event)
{
  CoglTexture *tex = COGL_TEXTURE (tex_pixmap);
  Display *display;
  enum
{ DO_NOTHING, NEEDS_SUBTRACT, NEED_BOUNDING_BOX } handle_mode;
  const CoglWinsysVtable *winsys;

  _COGL_GET_CONTEXT (ctxt, NO_RETVAL);

  display = cogl_xlib_renderer_get_display (ctxt->display->renderer);

  COGL_NOTE (TEXTURE_PIXMAP, "Damage event received for %p", tex_pixmap);

  switch (tex_pixmap->damage_report_level)
    {
    case COGL_TEXTURE_PIXMAP_X11_DAMAGE_RAW_RECTANGLES:
      /* For raw rectangles we don't need do look at the damage region
         at all because the damage area is directly given in the event
         struct and the reporting of events is not affected by
         clearing the damage region */
      handle_mode = DO_NOTHING;
      break;

    case COGL_TEXTURE_PIXMAP_X11_DAMAGE_DELTA_RECTANGLES:
    case COGL_TEXTURE_PIXMAP_X11_DAMAGE_NON_EMPTY:
      /* For delta rectangles and non empty we'll query the damage
         region for the bounding box */
      handle_mode = NEED_BOUNDING_BOX;
      break;

    case COGL_TEXTURE_PIXMAP_X11_DAMAGE_BOUNDING_BOX:
      /* For bounding box we need to clear the damage region but we
         don't actually care what it was because the damage event
         itself contains the bounding box of the region */
      handle_mode = NEEDS_SUBTRACT;
      break;

    default:
      g_assert_not_reached ();
    }

  /* If the damage already covers the whole rectangle then we don't
     need to request the bounding box of the region because we're
     going to update the whole texture anyway. */
  if (cogl_damage_rectangle_is_whole (&tex_pixmap->damage_rect,
                                      tex->width,
                                      tex->height))
    {
      if (handle_mode != DO_NOTHING)
        XDamageSubtract (display, tex_pixmap->damage, None, None);
    }
  else if (handle_mode == NEED_BOUNDING_BOX)
    {
      XserverRegion parts;
      int r_count;
      XRectangle r_bounds;
      XRectangle *r_damage;

      /* We need to extract the damage region so we can get the
         bounding box */

      parts = XFixesCreateRegion (display, 0, 0);
      XDamageSubtract (display, tex_pixmap->damage, None, parts);
      r_damage = XFixesFetchRegionAndBounds (display,
                                             parts,
                                             &r_count,
                                             &r_bounds);
      cogl_damage_rectangle_union (&tex_pixmap->damage_rect,
                                   r_bounds.x,
                                   r_bounds.y,
                                   r_bounds.width,
                                   r_bounds.height);
      if (r_damage)
        XFree (r_damage);

      XFixesDestroyRegion (display, parts);
    }
  else
    {
      if (handle_mode == NEEDS_SUBTRACT)
        /* We still need to subtract from the damage region but we
           don't care what the region actually was */
        XDamageSubtract (display, tex_pixmap->damage, None, None);

      cogl_damage_rectangle_union (&tex_pixmap->damage_rect,
                                   damage_event->area.x,
                                   damage_event->area.y,
                                   damage_event->area.width,
                                   damage_event->area.height);
    }

  if (tex_pixmap->winsys)
    {
      /* If we're using the texture from pixmap extension then there's no
         point in getting the region and we can just mark that the texture
         needs updating */
      winsys = _cogl_texture_pixmap_x11_get_winsys (tex_pixmap);
      winsys->texture_pixmap_x11_damage_notify (tex_pixmap);
    }
}
Esempio n. 23
0
static void
try_create_glx_pixmap (CoglTexturePixmapX11 *tex_pixmap,
                       gboolean mipmap)
{
  Display *dpy;
  /* We have to initialize this *opaque* variable because gcc tries to
   * be too smart for its own good and warns that the variable may be
   * used uninitialized otherwise. */
  GLXFBConfig fb_config = (GLXFBConfig)0;
  int attribs[7];
  int i = 0;
  GLenum target;
  CoglXlibTrapState trap_state;

  _COGL_GET_CONTEXT (ctxt, NO_RETVAL);

  tex_pixmap->pixmap_bound = FALSE;
  tex_pixmap->glx_pixmap = None;

  if ((ctxt->winsys.feature_flags &
       COGL_WINSYS_FEATURE_TEXTURE_FROM_PIXMAP) == 0)
    return;

  dpy = _cogl_xlib_get_display ();

  if (!get_fbconfig_for_depth (tex_pixmap->depth, &fb_config,
                               &tex_pixmap->glx_can_mipmap))
    {
      COGL_NOTE (TEXTURE_PIXMAP, "No suitable FBConfig found for depth %i",
                 tex_pixmap->depth);
      return;
    }

  if (should_use_rectangle ())
    {
      target = GLX_TEXTURE_RECTANGLE_EXT;
      tex_pixmap->glx_can_mipmap = FALSE;
    }
  else
    target = GLX_TEXTURE_2D_EXT;

  if (!tex_pixmap->glx_can_mipmap)
    mipmap = FALSE;

  attribs[i++] = GLX_TEXTURE_FORMAT_EXT;

  if (tex_pixmap->depth == 24)
    attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT;
  else if (tex_pixmap->depth == 32)
    attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
  else
    return;

  attribs[i++] = GLX_MIPMAP_TEXTURE_EXT;
  attribs[i++] = mipmap;

  attribs[i++] = GLX_TEXTURE_TARGET_EXT;
  attribs[i++] = target;

  attribs[i++] = None;

  /* We need to trap errors from glXCreatePixmap because it can
     sometimes fail during normal usage. For example on NVidia it gets
     upset if you try to create two GLXPixmaps for the same
     drawable. */

  _cogl_xlib_trap_errors (&trap_state);

  tex_pixmap->glx_pixmap = glXCreatePixmap (dpy,
                                            fb_config,
                                            tex_pixmap->pixmap,
                                            attribs);
  tex_pixmap->glx_pixmap_has_mipmap = mipmap;

  XSync (dpy, False);

  if (_cogl_xlib_untrap_errors (&trap_state))
    {
      COGL_NOTE (TEXTURE_PIXMAP, "Failed to create pixmap for %p", tex_pixmap);
      _cogl_xlib_trap_errors (&trap_state);
      glXDestroyPixmap (dpy, tex_pixmap->glx_pixmap);
      XSync (dpy, False);
      _cogl_xlib_untrap_errors (&trap_state);

      tex_pixmap->glx_pixmap = None;
    }
}