388 lines
11 KiB
C
388 lines
11 KiB
C
#include "e.h"
|
|
|
|
typedef struct _E_Renderer_Output_State E_Renderer_Output_State;
|
|
typedef struct _E_Renderer_Surface_State E_Renderer_Surface_State;
|
|
|
|
struct _E_Renderer_Output_State
|
|
{
|
|
#ifdef HAVE_WAYLAND_EGL
|
|
EGLSurface surface;
|
|
pixman_region32_t buffer[2];
|
|
#endif
|
|
pixman_image_t *shadow;
|
|
void *shadow_buffer;
|
|
pixman_image_t *hw_buffer;
|
|
};
|
|
|
|
struct _E_Renderer_Surface_State
|
|
{
|
|
#ifdef HAVE_WAYLAND_EGL
|
|
GLfloat color[4];
|
|
GLuint textures[3];
|
|
GLenum target;
|
|
|
|
EGLImageKHR images[3];
|
|
|
|
E_Shader *shader;
|
|
|
|
pixman_region32_t texture_damage;
|
|
|
|
int num_text;
|
|
int num_images;
|
|
int pitch, height;
|
|
#endif
|
|
pixman_image_t *image;
|
|
E_Buffer_Reference buffer_reference;
|
|
};
|
|
|
|
/* local function prototypes */
|
|
static void _e_renderer_region_repaint(E_Surface *surface, E_Output *output, pixman_region32_t *region, pixman_region32_t *surface_region, pixman_op_t pixman_op);
|
|
static void _e_renderer_surfaces_repaint(E_Output *output, pixman_region32_t *damage);
|
|
static void _e_renderer_surface_draw(E_Surface *surface, E_Output *output, pixman_region32_t *damage);
|
|
static Eina_Bool _e_renderer_cb_pixels_read(E_Output *output, int format, void *pixels, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h);
|
|
static void _e_renderer_cb_output_buffer_set(E_Output *output, pixman_image_t *buffer);
|
|
static void _e_renderer_cb_output_repaint(E_Output *output, pixman_region32_t *damage);
|
|
static void _e_renderer_cb_damage_flush(E_Surface *surface);
|
|
static void _e_renderer_cb_attach(E_Surface *surface, E_Buffer *buffer);
|
|
static Eina_Bool _e_renderer_cb_output_create(E_Output *output, unsigned int window);
|
|
static void _e_renderer_cb_output_destroy(E_Output *output);
|
|
static Eina_Bool _e_renderer_cb_surface_create(E_Surface *surface);
|
|
static void _e_renderer_cb_surface_destroy(E_Surface *surface);
|
|
static void _e_renderer_cb_surface_color_set(E_Surface *surface, int r, int g, int b, int a);
|
|
static void _e_renderer_cb_destroy(E_Compositor *comp);
|
|
|
|
EAPI Eina_Bool
|
|
e_renderer_create(E_Compositor *comp)
|
|
{
|
|
E_Renderer *rend;
|
|
|
|
/* try to allocate space for new renderer */
|
|
if (!(rend = E_NEW(E_Renderer, 1))) return EINA_FALSE;
|
|
|
|
/* FIXME: Vary these based on software or gl
|
|
* NB: This code current ONLY does software */
|
|
|
|
/* setup renderer functions */
|
|
rend->pixels_read = _e_renderer_cb_pixels_read;
|
|
rend->output_buffer_set = _e_renderer_cb_output_buffer_set;
|
|
rend->output_repaint = _e_renderer_cb_output_repaint;
|
|
rend->damage_flush = _e_renderer_cb_damage_flush;
|
|
rend->attach = _e_renderer_cb_attach;
|
|
rend->output_create = _e_renderer_cb_output_create;
|
|
rend->output_destroy = _e_renderer_cb_output_destroy;
|
|
rend->surface_create = _e_renderer_cb_surface_create;
|
|
rend->surface_destroy = _e_renderer_cb_surface_destroy;
|
|
rend->surface_color_set = _e_renderer_cb_surface_color_set;
|
|
rend->destroy = _e_renderer_cb_destroy;
|
|
|
|
comp->renderer = rend;
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI void
|
|
e_renderer_destroy(E_Compositor *comp)
|
|
{
|
|
/* check for valid renderer and call the destroy function */
|
|
if ((comp->renderer) && (comp->renderer->destroy))
|
|
comp->renderer->destroy(comp);
|
|
}
|
|
|
|
/* local functions */
|
|
static void
|
|
_e_renderer_region_repaint(E_Surface *surface, E_Output *output, pixman_region32_t *region, pixman_region32_t *surf_region, pixman_op_t pixman_op)
|
|
{
|
|
// E_Renderer *rend;
|
|
E_Renderer_Output_State *out_state;
|
|
E_Renderer_Surface_State *surf_state;
|
|
pixman_region32_t fregion;
|
|
/* pixman_box32_t *ext = NULL; */
|
|
|
|
out_state = output->state;
|
|
surf_state = surface->state;
|
|
|
|
pixman_region32_init(&fregion);
|
|
if (surf_region)
|
|
{
|
|
pixman_region32_copy(&fregion, surf_region);
|
|
pixman_region32_translate(&fregion,
|
|
surface->geometry.x, surface->geometry.y);
|
|
pixman_region32_intersect(&fregion, &fregion, region);
|
|
}
|
|
else
|
|
pixman_region32_copy(&fregion, region);
|
|
|
|
/* ext = pixman_region32_extents(&fregion); */
|
|
/* printf("\tRepainting Region: %d %d %d %d\n", */
|
|
/* ext->x1, ext->y1, (ext->x2 - ext->x1), */
|
|
/* (ext->y2 - ext->y1)); */
|
|
|
|
/* global to output ? */
|
|
|
|
pixman_image_set_clip_region32(out_state->shadow, &fregion);
|
|
pixman_image_set_filter(surf_state->image, PIXMAN_FILTER_NEAREST, NULL, 0);
|
|
|
|
pixman_image_composite32(pixman_op, surf_state->image, NULL,
|
|
out_state->shadow, 0, 0, 0, 0, 0, 0,
|
|
pixman_image_get_width(out_state->shadow),
|
|
pixman_image_get_height(out_state->shadow));
|
|
pixman_image_set_clip_region32(out_state->shadow, NULL);
|
|
pixman_region32_fini(&fregion);
|
|
}
|
|
|
|
static void
|
|
_e_renderer_surfaces_repaint(E_Output *output, pixman_region32_t *damage)
|
|
{
|
|
E_Compositor *comp;
|
|
Eina_List *l;
|
|
E_Surface *es;
|
|
|
|
comp = output->compositor;
|
|
EINA_LIST_FOREACH(comp->surfaces, l, es)
|
|
{
|
|
if (es->plane == &comp->plane)
|
|
_e_renderer_surface_draw(es, output, damage);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_renderer_surface_draw(E_Surface *surface, E_Output *output, pixman_region32_t *damage)
|
|
{
|
|
E_Renderer_Surface_State *state;
|
|
pixman_region32_t repaint, blend;
|
|
|
|
if (!surface) return;
|
|
if (!surface->output) surface->output = output;
|
|
if (surface->output != output) return;
|
|
|
|
if (!(state = surface->state)) return;
|
|
if (!state->image) return;
|
|
|
|
pixman_region32_init(&repaint);
|
|
pixman_region32_intersect(&repaint, &surface->opaque, damage);
|
|
pixman_region32_subtract(&repaint, &repaint, &surface->clip);
|
|
|
|
if (!pixman_region32_not_empty(&repaint))
|
|
{
|
|
pixman_region32_fini(&repaint);
|
|
return;
|
|
}
|
|
|
|
/* TODO: handle transforms ? */
|
|
|
|
pixman_region32_init_rect(&blend, 0, 0,
|
|
surface->geometry.w, surface->geometry.h);
|
|
pixman_region32_subtract(&blend, &blend, &surface->opaque);
|
|
|
|
if (pixman_region32_not_empty(&surface->opaque))
|
|
_e_renderer_region_repaint(surface, output, &repaint,
|
|
&surface->opaque, PIXMAN_OP_SRC);
|
|
|
|
if (pixman_region32_not_empty(&blend))
|
|
_e_renderer_region_repaint(surface, output, &repaint,
|
|
&blend, PIXMAN_OP_OVER);
|
|
|
|
pixman_region32_fini(&blend);
|
|
pixman_region32_fini(&repaint);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_e_renderer_cb_pixels_read(E_Output *output, int format, void *pixels, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
|
|
{
|
|
E_Renderer_Output_State *state;
|
|
pixman_image_t *buffer;
|
|
|
|
if (!(state = output->state)) return EINA_FALSE;
|
|
if (!state->hw_buffer) return EINA_FALSE;
|
|
|
|
buffer =
|
|
pixman_image_create_bits(format, w, h, pixels,
|
|
(PIXMAN_FORMAT_BPP(format) / 8) * w);
|
|
|
|
pixman_image_composite32(PIXMAN_OP_SRC, state->hw_buffer, NULL,
|
|
buffer, 0, 0, 0, 0, 0, 0,
|
|
pixman_image_get_width(state->hw_buffer),
|
|
pixman_image_get_height(state->hw_buffer));
|
|
pixman_image_set_transform(state->hw_buffer, NULL);
|
|
pixman_image_unref(buffer);
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
_e_renderer_cb_output_buffer_set(E_Output *output, pixman_image_t *buffer)
|
|
{
|
|
E_Renderer_Output_State *state;
|
|
|
|
state = output->state;
|
|
if (state->hw_buffer) pixman_image_unref(state->hw_buffer);
|
|
state->hw_buffer = buffer;
|
|
if (state->hw_buffer)
|
|
{
|
|
/* output->compositor->read_format; */
|
|
pixman_image_ref(state->hw_buffer);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_renderer_cb_output_repaint(E_Output *output, pixman_region32_t *damage)
|
|
{
|
|
E_Renderer_Output_State *state;
|
|
pixman_region32_t region;
|
|
|
|
state = output->state;
|
|
if (!state->hw_buffer) return;
|
|
|
|
/* repaint surfaces */
|
|
_e_renderer_surfaces_repaint(output, damage);
|
|
|
|
/* copy to hw */
|
|
pixman_region32_init(®ion);
|
|
pixman_region32_copy(®ion, damage);
|
|
|
|
/* global to output ? */
|
|
|
|
pixman_image_set_clip_region32(state->hw_buffer, ®ion);
|
|
pixman_image_composite32(PIXMAN_OP_SRC, state->shadow, NULL,
|
|
state->hw_buffer, 0, 0, 0, 0, 0, 0,
|
|
pixman_image_get_width(state->hw_buffer),
|
|
pixman_image_get_height(state->hw_buffer));
|
|
pixman_image_set_clip_region32(state->hw_buffer, NULL);
|
|
|
|
pixman_region32_copy(&output->repaint.prev_damage, damage);
|
|
wl_signal_emit(&output->signals.frame, output);
|
|
}
|
|
|
|
static void
|
|
_e_renderer_cb_damage_flush(E_Surface *surface)
|
|
{
|
|
|
|
}
|
|
|
|
static void
|
|
_e_renderer_cb_attach(E_Surface *surface, E_Buffer *buffer)
|
|
{
|
|
E_Renderer_Surface_State *state;
|
|
pixman_format_code_t format = 0;
|
|
Evas_Coord w = 0, h = 0;
|
|
void *data;
|
|
int stride = 0;
|
|
struct wl_shm_buffer *shm_buffer;
|
|
|
|
state = surface->state;
|
|
|
|
e_buffer_reference(&state->buffer_reference, buffer);
|
|
|
|
if (state->image) pixman_image_unref(state->image);
|
|
state->image = NULL;
|
|
|
|
if (!buffer) return;
|
|
|
|
if (!(shm_buffer = wl_shm_buffer_get(buffer->wl.resource)))
|
|
{
|
|
e_buffer_reference(&state->buffer_reference, NULL);
|
|
return;
|
|
}
|
|
|
|
switch (wl_shm_buffer_get_format(shm_buffer))
|
|
{
|
|
case WL_SHM_FORMAT_XRGB8888:
|
|
format = PIXMAN_x8r8g8b8;
|
|
break;
|
|
case WL_SHM_FORMAT_ARGB8888:
|
|
format = PIXMAN_a8r8g8b8;
|
|
break;
|
|
default:
|
|
e_buffer_reference(&state->buffer_reference, NULL);
|
|
return;
|
|
break;
|
|
}
|
|
|
|
buffer->shm_buffer = shm_buffer;
|
|
buffer->w = wl_shm_buffer_get_width(shm_buffer);
|
|
buffer->h = wl_shm_buffer_get_height(shm_buffer);
|
|
data = wl_shm_buffer_get_data(shm_buffer);
|
|
stride = wl_shm_buffer_get_stride(shm_buffer);
|
|
|
|
state->image =
|
|
pixman_image_create_bits(format, buffer->w, buffer->h, data, stride);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_e_renderer_cb_output_create(E_Output *output, unsigned int window)
|
|
{
|
|
E_Renderer_Output_State *state;
|
|
Evas_Coord w = 0, h = 0;
|
|
|
|
/* try to allocate space for output state */
|
|
if (!(state = E_NEW(E_Renderer_Output_State, 1)))
|
|
return EINA_FALSE;
|
|
|
|
w = output->current->w;
|
|
h = output->current->h;
|
|
|
|
state->shadow_buffer = malloc(w * h * sizeof(int));
|
|
if (!state->shadow_buffer) return EINA_FALSE;
|
|
|
|
state->shadow =
|
|
pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h, state->shadow_buffer,
|
|
w * sizeof(int));
|
|
if (!state->shadow)
|
|
{
|
|
free(state->shadow_buffer);
|
|
free(state);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
output->state = state;
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
_e_renderer_cb_output_destroy(E_Output *output)
|
|
{
|
|
|
|
}
|
|
|
|
static Eina_Bool
|
|
_e_renderer_cb_surface_create(E_Surface *surface)
|
|
{
|
|
E_Renderer_Surface_State *state;
|
|
|
|
if (!(state = E_NEW(E_Renderer_Surface_State, 1)))
|
|
return EINA_FALSE;
|
|
|
|
surface->state = state;
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
_e_renderer_cb_surface_destroy(E_Surface *surface)
|
|
{
|
|
E_Renderer_Surface_State *state;
|
|
|
|
if ((state = surface->state))
|
|
{
|
|
if (state->image) pixman_image_unref(state->image);
|
|
state->image = NULL;
|
|
}
|
|
|
|
e_buffer_reference(&state->buffer_reference, NULL);
|
|
|
|
E_FREE(state);
|
|
}
|
|
|
|
static void
|
|
_e_renderer_cb_surface_color_set(E_Surface *surface, int r, int g, int b, int a)
|
|
{
|
|
|
|
}
|
|
|
|
static void
|
|
_e_renderer_cb_destroy(E_Compositor *comp)
|
|
{
|
|
|
|
}
|