#include "evas_common.h" /* Also includes international specific stuff */ #include "evas_engine.h" #include "evas_private.h" #include /* dlopen,dlclose,etc */ #define EVAS_GL_NO_GL_H_CHECK 1 #include "Evas_GL.h" typedef struct _Render_Engine Render_Engine; typedef struct _Render_Engine_GL_Surface Render_Engine_GL_Surface; typedef struct _Render_Engine_GL_Context Render_Engine_GL_Context; struct _Render_Engine { Evas_GL_Cocoa_Window *win; int end; }; struct _Render_Engine_GL_Surface { int initialized; int fbo_attached; int w, h; int depth_bits; int stencil_bits; // Render target texture/buffers GLuint rt_tex; GLint rt_internal_fmt; GLenum rt_fmt; GLuint rb_depth; GLenum rb_depth_fmt; GLuint rb_stencil; GLenum rb_stencil_fmt; Render_Engine_GL_Context *current_ctx; }; struct _Render_Engine_GL_Context { int initialized; // EGLContext context; GLuint fbo; Render_Engine_GL_Surface *current_sfc; }; int _evas_engine_gl_cocoa_log_dom = -1; /* function tables - filled in later (func and parent func) */ static Evas_Func func, pfunc; /* Function table for GL APIs */ static Evas_GL_API gl_funcs; static void * eng_info(Evas *e EINA_UNUSED) { Evas_Engine_Info_GL_Cocoa *info; info = calloc(1, sizeof(Evas_Engine_Info_GL_Cocoa)); DBG("Info %p", info); if (!info) return NULL; info->magic.magic = rand(); return info; } static void eng_info_free(Evas *e EINA_UNUSED, void *info) { Evas_Engine_Info_GL_Cocoa *in; DBG("Info %p", info); eina_log_domain_unregister(_evas_engine_gl_cocoa_log_dom); in = (Evas_Engine_Info_GL_Cocoa *)info; free(in); } static int eng_setup(Evas *eo_e, void *in) { Evas_Public_Data *e = eo_data_get(eo_e, EVAS_CLASS); Render_Engine *re; Evas_Engine_Info_GL_Cocoa *info; DBG("Engine Setup"); info = (Evas_Engine_Info_GL_Cocoa *)in; if (!e->engine.data.output) { re = calloc(1, sizeof(Render_Engine)); if (!re) return 0; e->engine.data.output = re; re->win = eng_window_new(info->window, e->output.w, e->output.h); info->view = re->win->view; if (!re->win) { free(re); e->engine.data.output = NULL; return 0; } evas_common_cpu_init(); evas_common_blend_init(); evas_common_image_init(); evas_common_convert_init(); evas_common_scale_init(); evas_common_rectangle_init(); evas_common_polygon_init(); evas_common_line_init(); evas_common_font_init(); evas_common_draw_init(); evas_common_tilebuf_init(); } else { re = e->engine.data.output; eng_window_free(re->win); re->win = eng_window_new(info->window, e->output.w, e->output.h); info->view = re->win->view; } if (!e->engine.data.output) return 0; if (!e->engine.data.context) e->engine.data.context = e->engine.func->context_new(e->engine.data.output); eng_window_use(re->win); return 1; } static void eng_output_free(void *data) { Render_Engine *re; DBG("Output free"); re = (Render_Engine *)data; eng_window_free(re->win); free(re); evas_common_font_shutdown(); evas_common_image_shutdown(); } static void eng_output_resize(void *data, int w, int h) { Render_Engine *re; DBG("Output Resize %d %d", w, h); re = (Render_Engine *)data; re->win->width = w; re->win->height = h; eng_window_resize(re->win, w, h); evas_gl_common_context_resize(re->win->gl_context, w, h, 0); } static void eng_output_tile_size_set(void *data EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED) { DBG("tile size set"); } static void eng_output_redraws_rect_add(void *data, int x, int y, int w, int h) { Render_Engine *re; DBG("Redraw rect %d %d %d %d", x, y, w, h); re = (Render_Engine *)data; evas_gl_common_context_resize(re->win->gl_context, re->win->width, re->win->height, 0); /* simple bounding box */ RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, re->win->width, re->win->height); if ((w <= 0) || (h <= 0)) return; if (!re->win->draw.redraw) { #if 0 re->win->draw.x1 = x; re->win->draw.y1 = y; re->win->draw.x2 = x + w - 1; re->win->draw.y2 = y + h - 1; #else re->win->draw.x1 = 0; re->win->draw.y1 = 0; re->win->draw.x2 = re->win->width - 1; re->win->draw.y2 = re->win->height - 1; #endif } else { if (x < re->win->draw.x1) re->win->draw.x1 = x; if (y < re->win->draw.y1) re->win->draw.y1 = y; if ((x + w - 1) > re->win->draw.x2) re->win->draw.x2 = x + w - 1; if ((y + h - 1) > re->win->draw.y2) re->win->draw.y2 = y + h - 1; } re->win->draw.redraw = 1; } static void eng_output_redraws_rect_del(void *data EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED) { } static void eng_output_redraws_clear(void *data) { Render_Engine *re; re = (Render_Engine *)data; re->win->draw.redraw = 0; } //#define SLOW_GL_COPY_RECT 1 /* vsync games - not for now though */ #define VSYNC_TO_SCREEN 1 static void * eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch) { Render_Engine *re; re = (Render_Engine *)data; evas_gl_common_context_flush(re->win->gl_context); /* get the upate rect surface - return engine data as dummy */ if (!re->win->draw.redraw) { // printf("GL: NO updates!\n"); return NULL; } // printf("GL: update....!\n"); #ifdef SLOW_GL_COPY_RECT /* if any update - just return the whole canvas - works with swap * buffers then */ if (x) *x = 0; if (y) *y = 0; if (w) *w = re->win->width; if (h) *h = re->win->height; if (cx) *cx = 0; if (cy) *cy = 0; if (cw) *cw = re->win->width; if (ch) *ch = re->win->height; #else /* 1 update - INCREDIBLY SLOW if combined with swap_rect in flush. a gl * problem where there just is no hardware path for somethnig that * obviously SHOULD be there */ /* only 1 update to minimise gl context games and rendering multiple update * regions as evas does with other engines */ if (x) *x = re->win->draw.x1; if (y) *y = re->win->draw.y1; if (w) *w = re->win->draw.x2 - re->win->draw.x1 + 1; if (h) *h = re->win->draw.y2 - re->win->draw.y1 + 1; if (cx) *cx = re->win->draw.x1; if (cy) *cy = re->win->draw.y1; if (cw) *cw = re->win->draw.x2 - re->win->draw.x1 + 1; if (ch) *ch = re->win->draw.y2 - re->win->draw.y1 + 1; #endif // clear buffer. only needed for dest alpha // glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // glClear(GL_COLOR_BUFFER_BIT); //x// printf("frame -> new\n"); return re->win->gl_context->def_surface; } static void eng_output_redraws_next_update_push(void *data, void *surface EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, Evas_Render_Mode render_mode) { Render_Engine *re; if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return; re = (Render_Engine *)data; /* put back update surface.. in this case just unflag redraw */ re->win->draw.redraw = 0; re->win->draw.drew = 1; evas_gl_common_context_flush(re->win->gl_context); } static void eng_output_flush(void *data, Evas_Render_Mode render_mode) { Render_Engine *re; if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return; re = (Render_Engine *)data; if (!re->win->draw.drew) return; re->win->draw.drew = 0; eng_window_use(re->win); #ifdef VSYNC_TO_SCREEN eng_window_vsync_set(1); #endif eng_window_swap_buffers(re->win); } static void eng_output_idle_flush(void *data EINA_UNUSED) { } static void eng_context_cutout_add(void *data EINA_UNUSED, void *context, int x, int y, int w, int h) { evas_common_draw_context_add_cutout(context, x, y, w, h); } static void eng_context_cutout_clear(void *data EINA_UNUSED, void *context) { evas_common_draw_context_clear_cutouts(context); } static void eng_rectangle_draw(void *data, void *context, void *surface, int x, int y, int w, int h) { Render_Engine *re; re = (Render_Engine *)data; eng_window_use(re->win); evas_gl_common_context_target_surface_set(re->win->gl_context, surface); re->win->gl_context->dc = context; evas_gl_common_rect_draw(re->win->gl_context, x, y, w, h); } static void eng_line_draw(void *data, void *context, void *surface, int x1, int y1, int x2, int y2) { Render_Engine *re; re = (Render_Engine *)data; eng_window_use(re->win); evas_gl_common_context_target_surface_set(re->win->gl_context, surface); re->win->gl_context->dc = context; evas_gl_common_line_draw(re->win->gl_context, x1, y1, x2, y2); } static void * eng_polygon_point_add(void *data, void *context EINA_UNUSED, void *polygon, int x, int y) { Render_Engine *re; re = (Render_Engine *)data; return evas_gl_common_poly_point_add(polygon, x, y); } static void * eng_polygon_points_clear(void *data, void *context EINA_UNUSED, void *polygon) { Render_Engine *re; re = (Render_Engine *)data; return evas_gl_common_poly_points_clear(polygon); } static void eng_polygon_draw(void *data, void *context, void *surface EINA_UNUSED, void *polygon, int x, int y) { Render_Engine *re; re = (Render_Engine *)data; eng_window_use(re->win); evas_gl_common_context_target_surface_set(re->win->gl_context, surface); re->win->gl_context->dc = context; evas_gl_common_poly_draw(re->win->gl_context, polygon, x, y); } static int eng_image_alpha_get(void *data EINA_UNUSED, void *image) { // Render_Engine *re; Evas_GL_Image *im; // re = (Render_Engine *)data; if (!image) return 1; im = image; return im->alpha; } static int eng_image_colorspace_get(void *data EINA_UNUSED, void *image) { // Render_Engine *re; Evas_GL_Image *im; // re = (Render_Engine *)data; if (!image) return EVAS_COLORSPACE_ARGB8888; im = image; return im->cs.space; } static void eng_image_mask_create(void *data EINA_UNUSED, void *image) { Evas_GL_Image *im; if (!image) return; im = image; if (!im->im->image.data) evas_cache_image_load_data(&im->im->cache_entry); if (!im->tex) im->tex = evas_gl_common_texture_new(im->gc, im->im); } static void * eng_image_alpha_set(void *data, void *image, int has_alpha) { Render_Engine *re; Evas_GL_Image *im; re = (Render_Engine *)data; if (!image) return NULL; im = image; if (im->alpha == has_alpha) return image; if (im->native.data) { im->alpha = has_alpha; return image; } eng_window_use(re->win); if ((im->tex) && (im->tex->pt->dyn.img)) { im->alpha = has_alpha; im->tex->alpha = im->alpha; return image; } /* FIXME: can move to gl_common */ if (im->cs.space != EVAS_COLORSPACE_ARGB8888) return im; if ((has_alpha) && (im->im->cache_entry.flags.alpha)) return image; else if ((!has_alpha) && (!im->im->cache_entry.flags.alpha)) return image; if (im->references > 1) { Evas_GL_Image *im_new; if (!im->im->image.data) evas_cache_image_load_data(&im->im->cache_entry); im_new = evas_gl_common_image_new_from_copied_data (im->gc, im->im->cache_entry.w, im->im->cache_entry.h, im->im->image.data, eng_image_alpha_get(data, image), eng_image_colorspace_get(data, image)); if (!im_new) return im; evas_gl_common_image_free(im); im = im_new; } else evas_gl_common_image_dirty(im, 0, 0, 0, 0); return evas_gl_common_image_alpha_set(im, has_alpha ? 1 : 0); // im->im->cache_entry.flags.alpha = has_alpha ? 1 : 0; // return image; } static void * eng_image_border_set(void *data EINA_UNUSED, void *image, int l EINA_UNUSED, int r EINA_UNUSED, int t EINA_UNUSED, int b EINA_UNUSED) { // Render_Engine *re; // // re = (Render_Engine *)data; return image; } static void eng_image_border_get(void *data EINA_UNUSED, void *image EINA_UNUSED, int *l EINA_UNUSED, int *r EINA_UNUSED, int *t EINA_UNUSED, int *b EINA_UNUSED) { // Render_Engine *re; // // re = (Render_Engine *)data; } static char * eng_image_comment_get(void *data EINA_UNUSED, void *image, char *key EINA_UNUSED) { // Render_Engine *re; Evas_GL_Image *im; // re = (Render_Engine *)data; if (!image) return NULL; im = image; if (!im->im) return NULL; return im->im->info.comment; } static char * eng_image_format_get(void *data EINA_UNUSED, void *image) { // Render_Engine *re; Evas_GL_Image *im; // re = (Render_Engine *)data; im = image; return NULL; } static void eng_image_colorspace_set(void *data, void *image, int cspace) { Render_Engine *re; Evas_GL_Image *im; re = (Render_Engine *)data; if (!image) return; im = image; if (im->native.data) return; /* FIXME: can move to gl_common */ if (im->cs.space == cspace) return; eng_window_use(re->win); evas_cache_image_colorspace(&im->im->cache_entry, cspace); switch (cspace) { case EVAS_COLORSPACE_ARGB8888: if (im->cs.data) { if (!im->cs.no_free) free(im->cs.data); im->cs.data = NULL; im->cs.no_free = 0; } break; case EVAS_COLORSPACE_YCBCR422P601_PL: case EVAS_COLORSPACE_YCBCR422P709_PL: if (im->tex) evas_gl_common_texture_free(im->tex); im->tex = NULL; if (im->cs.data) { if (!im->cs.no_free) free(im->cs.data); } if (im->im->cache_entry.h > 0) im->cs.data = calloc(1, im->im->cache_entry.h * sizeof(unsigned char *) * 2); else im->cs.data = NULL; im->cs.no_free = 0; break; default: abort(); break; } im->cs.space = cspace; } ///////////////////////////////////////////////////////////////////////// // // // FIXME: this is enabled so updates happen - but its SLOOOOOOOOOOOOOOOW // (i am sure this is the reason) not to mention seemingly superfluous. but // i need to enable it for it to work on fglrx at least. havent tried nvidia. // // why is this the case? does anyone know? has anyone tried it on other gfx // drivers? // //#define GLX_TEX_PIXMAP_RECREATE 1 // // ///////////////////////////////////////////////////////////////////////// static void * eng_image_load(void *data, const char *file, const char *key, int *error, Evas_Image_Load_Opts *lo) { Render_Engine *re; re = (Render_Engine *)data; *error = EVAS_LOAD_ERROR_NONE; eng_window_use(re->win); return evas_gl_common_image_load(re->win->gl_context, file, key, lo, error); } static void * eng_image_new_from_data(void *data, int w, int h, DATA32 *image_data, int alpha, int cspace) { Render_Engine *re; re = (Render_Engine *)data; eng_window_use(re->win); return evas_gl_common_image_new_from_data(re->win->gl_context, w, h, image_data, alpha, cspace); } static void * eng_image_new_from_copied_data(void *data, int w, int h, DATA32 *image_data, int alpha, int cspace) { Render_Engine *re; re = (Render_Engine *)data; eng_window_use(re->win); return evas_gl_common_image_new_from_copied_data(re->win->gl_context, w, h, image_data, alpha, cspace); } static void eng_image_free(void *data, void *image) { Render_Engine *re; re = (Render_Engine *)data; if (!image) return; eng_window_use(re->win); evas_gl_common_image_free(image); } static void eng_image_size_get(void *data EINA_UNUSED, void *image, int *w, int *h) { if (!image) { *w = 0; *h = 0; return; } if (w) *w = ((Evas_GL_Image *)image)->w; if (h) *h = ((Evas_GL_Image *)image)->h; } static void * eng_image_size_set(void *data, void *image, int w, int h) { Render_Engine *re; Evas_GL_Image *im = image; Evas_GL_Image *im_old; re = (Render_Engine *)data; if (!im) return NULL; if (im->native.data) { im->w = w; im->h = h; return image; } eng_window_use(re->win); if ((im->tex) && (im->tex->pt->dyn.img)) { evas_gl_common_texture_free(im->tex); im->tex = NULL; im->w = w; im->h = h; im->tex = evas_gl_common_texture_dynamic_new(im->gc, im); return image; } im_old = image; switch (eng_image_colorspace_get(data, image)) { case EVAS_COLORSPACE_YCBCR422P601_PL: case EVAS_COLORSPACE_YCBCR422P709_PL: case EVAS_COLORSPACE_YCBCR422601_PL: case EVAS_COLORSPACE_YCBCR420NV12601_PL: case EVAS_COLORSPACE_YCBCR420TM12601_PL: w &= ~0x1; break; } if ((im_old->im) && ((int)im_old->im->cache_entry.w == w) && ((int)im_old->im->cache_entry.h == h)) return image; if (im_old) { im = evas_gl_common_image_new(re->win->gl_context, w, h, eng_image_alpha_get(data, image), eng_image_colorspace_get(data, image)); /* evas_common_load_image_data_from_file(im_old->im); if (im_old->im->image->data) { evas_common_blit_rectangle(im_old->im, im->im, 0, 0, w, h, 0, 0); evas_common_cpu_end_opt(); } */ evas_gl_common_image_free(im_old); } else im = evas_gl_common_image_new(re->win->gl_context, w, h, 1, EVAS_COLORSPACE_ARGB8888); return im; } static void * eng_image_dirty_region(void *data, void *image, int x, int y, int w, int h) { Render_Engine *re; Evas_GL_Image *im = image; re = (Render_Engine *)data; if (!image) return NULL; if (im->native.data) return image; eng_window_use(re->win); evas_gl_common_image_dirty(image, x, y, w, h); return image; } static void * eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, int *err) { Render_Engine *re; Evas_GL_Image *im; int error; re = (Render_Engine *)data; if (!image) { *image_data = NULL; if (err) *err = EVAS_LOAD_ERROR_GENERIC; return NULL; } im = image; if (im->native.data) { *image_data = NULL; if (err) *err = EVAS_LOAD_ERROR_NONE; return im; } if ((im->tex) && (im->tex->pt) && (im->tex->pt->dyn.data)) { *image_data = im->tex->pt->dyn.data; if (err) *err = EVAS_LOAD_ERROR_NONE; return im; } eng_window_use(re->win); error = evas_cache_image_load_data(&im->im->cache_entry); switch (im->cs.space) { case EVAS_COLORSPACE_ARGB8888: if (to_write) { if (im->references > 1) { Evas_GL_Image *im_new; im_new = evas_gl_common_image_new_from_copied_data (im->gc, im->im->cache_entry.w, im->im->cache_entry.h, im->im->image.data, eng_image_alpha_get(data, image), eng_image_colorspace_get(data, image)); if (!im_new) { *image_data = NULL; if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; return im; } evas_gl_common_image_free(im); im = im_new; } else evas_gl_common_image_dirty(im, 0, 0, 0, 0); } *image_data = im->im->image.data; break; case EVAS_COLORSPACE_YCBCR422P601_PL: case EVAS_COLORSPACE_YCBCR422P709_PL: *image_data = im->cs.data; break; default: abort(); break; } if (err) *err = error; return im; } static void * eng_image_data_put(void *data, void *image, DATA32 *image_data) { Render_Engine *re; Evas_GL_Image *im, *im2; re = (Render_Engine *)data; if (!image) return NULL; im = image; if (im->native.data) return image; eng_window_use(re->win); if ((im->tex) && (im->tex->pt) && (im->tex->pt->dyn.data)) { if (im->tex->pt->dyn.data == image_data) { return image; } else { int w, h; w = im->im->cache_entry.w; h = im->im->cache_entry.h; im2 = eng_image_new_from_data(data, w, h, image_data, eng_image_alpha_get(data, image), eng_image_colorspace_get(data, image)); if (!im2) return im; evas_gl_common_image_free(im); im = im2; evas_gl_common_image_dirty(im, 0, 0, 0, 0); return im; } } switch (im->cs.space) { case EVAS_COLORSPACE_ARGB8888: if (image_data != im->im->image.data) { int w, h; w = im->im->cache_entry.w; h = im->im->cache_entry.h; im2 = eng_image_new_from_data(data, w, h, image_data, eng_image_alpha_get(data, image), eng_image_colorspace_get(data, image)); if (!im2) return im; evas_gl_common_image_free(im); im = im2; } break; case EVAS_COLORSPACE_YCBCR422P601_PL: case EVAS_COLORSPACE_YCBCR422P709_PL: if (image_data != im->cs.data) { if (im->cs.data) { if (!im->cs.no_free) free(im->cs.data); } im->cs.data = image_data; } break; default: abort(); break; } /* hmmm - but if we wrote... why bother? */ evas_gl_common_image_dirty(im, 0, 0, 0, 0); return im; } static void eng_image_data_preload_request(void *data EINA_UNUSED, void *image, const void *target) { Evas_GL_Image *gim = image; RGBA_Image *im; if (!gim) return; if (gim->native.data) return; im = (RGBA_Image *)gim->im; if (!im) return; evas_cache_image_preload_data(&im->cache_entry, target); } static void eng_image_data_preload_cancel(void *data EINA_UNUSED, void *image, const void *target) { Evas_GL_Image *gim = image; RGBA_Image *im; if (!gim) return; if (gim->native.data) return; im = (RGBA_Image *)gim->im; if (!im) return; evas_cache_image_preload_cancel(&im->cache_entry, target); } static Eina_Bool eng_image_draw(void *data, void *context, void *surface, void *image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int smooth) { Render_Engine *re; re = (Render_Engine *)data; if (!image) return EINA_FALSE; eng_window_use(re->win); evas_gl_common_context_target_surface_set(re->win->gl_context, surface); re->win->gl_context->dc = context; evas_gl_common_image_draw(re->win->gl_context, image, src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, dst_h, smooth); return EINA_FALSE; } static void eng_image_scale_hint_set(void *data EINA_UNUSED, void *image, int hint) { if (image) evas_gl_common_image_scale_hint_set(image, hint); } static int eng_image_scale_hint_get(void *data EINA_UNUSED, void *image) { Evas_GL_Image *gim = image; if (!gim) return EVAS_IMAGE_SCALE_HINT_NONE; return gim->scale_hint; } static Eina_Bool eng_image_map_draw(void *data EINA_UNUSED, void *context, void *surface, void *image, RGBA_Map *m, int smooth, int level) { Evas_GL_Image *gim = image; Render_Engine *re; re = (Render_Engine *)data; if (!image) return EINA_FALSE; eng_window_use(re->win); evas_gl_common_context_target_surface_set(re->win->gl_context, surface); re->win->gl_context->dc = context; if (m->count != 4) { // FIXME: nash - you didn't fix this abort(); } if ((m->pts[0].x == m->pts[3].x) && (m->pts[1].x == m->pts[2].x) && (m->pts[0].y == m->pts[1].y) && (m->pts[3].y == m->pts[2].y) && (m->pts[0].x <= m->pts[1].x) && (m->pts[0].y <= m->pts[2].y) && (m->pts[0].u == 0) && (m->pts[0].v == 0) && (m->pts[1].u == (gim->w << FP)) && (m->pts[1].v == 0) && (m->pts[2].u == (gim->w << FP)) && (m->pts[2].v == (gim->h << FP)) && (m->pts[3].u == 0) && (m->pts[3].v == (gim->h << FP)) && (m->pts[0].col == 0xffffffff) && (m->pts[1].col == 0xffffffff) && (m->pts[2].col == 0xffffffff) && (m->pts[3].col == 0xffffffff)) { int dx, dy, dw, dh; dx = m->pts[0].x >> FP; dy = m->pts[0].y >> FP; dw = (m->pts[2].x >> FP) - dx; dh = (m->pts[2].y >> FP) - dy; eng_image_draw(data, context, surface, image, 0, 0, gim->w, gim->h, dx, dy, dw, dh, smooth); } else { evas_gl_common_image_map_draw(re->win->gl_context, image, m->count, &m->pts[0], smooth, level); } return EINA_FALSE; } static void * eng_image_map_surface_new(void *data EINA_UNUSED, int w, int h, int alpha) { Render_Engine *re; re = (Render_Engine *)data; return evas_gl_common_image_surface_new(re->win->gl_context, w, h, alpha); } static void eng_image_map_surface_free(void *data EINA_UNUSED, void *surface) { evas_gl_common_image_free(surface); } static void eng_image_content_hint_set(void *data EINA_UNUSED, void *image, int hint) { if (image) evas_gl_common_image_content_hint_set(image, hint); } static int eng_image_content_hint_get(void *data EINA_UNUSED, void *image) { Evas_GL_Image *gim = image; if (!gim) return EVAS_IMAGE_CONTENT_HINT_NONE; return gim->content_hint; } static void eng_image_cache_flush(void *data EINA_UNUSED) { Render_Engine *re; int tmp_size; re = (Render_Engine *)data; tmp_size = evas_common_image_get_cache(); evas_common_image_set_cache(0); evas_common_rgba_image_scalecache_flush(); evas_gl_common_image_cache_flush(re->win->gl_context); evas_common_image_set_cache(tmp_size); } static void eng_image_cache_set(void *data EINA_UNUSED, int bytes) { Render_Engine *re; re = (Render_Engine *)data; evas_common_image_set_cache(bytes); evas_common_rgba_image_scalecache_size_set(bytes); evas_gl_common_image_cache_flush(re->win->gl_context); } static int eng_image_cache_get(void *data EINA_UNUSED) { Render_Engine *re; re = (Render_Engine *)data; return evas_common_image_get_cache(); } static void eng_image_stride_get(void *data EINA_UNUSED, void *image, int *stride) { Evas_GL_Image *im = image; *stride = im->w * 4; if ((im->tex) && (im->tex->pt->dyn.img)) { *stride = im->tex->pt->dyn.w * 4; // FIXME: for other image formats (yuv etc.) different stride needed } } static Eina_Bool eng_font_draw(void *data, void *context, void *surface, Evas_Font_Set *font, int x, int y, int w EINA_UNUSED, int h EINA_UNUSED, int ow EINA_UNUSED, int oh EINA_UNUSED, Evas_Text_Props *intl_props) { Render_Engine *re; re = (Render_Engine *)data; eng_window_use(re->win); evas_gl_common_context_target_surface_set(re->win->gl_context, surface); re->win->gl_context->dc = context; { // FIXME: put im into context so we can free it static RGBA_Image *im = NULL; if (!im) im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get()); im->cache_entry.w = re->win->width; im->cache_entry.h = re->win->height; evas_common_draw_context_font_ext_set(context, re->win->gl_context, evas_gl_font_texture_new, evas_gl_font_texture_free, evas_gl_font_texture_draw); evas_common_font_draw_prepare(intl_props); evas_common_font_draw(im, context, x, y, intl_props); evas_common_draw_context_font_ext_set(context, NULL, NULL, NULL, NULL); } return EINA_FALSE; } static Eina_Bool eng_canvas_alpha_get(void *data EINA_UNUSED, void *info EINA_UNUSED) { // FIXME: support ARGB gl targets!!! return EINA_FALSE; } #if 1 static void evgl_glBindFramebuffer(GLenum target, GLuint framebuffer) { // Add logic to take care when framebuffer=0 glBindFramebuffer(target, framebuffer); } static void evgl_glBindRenderbuffer(GLenum target, GLuint renderbuffer) { // Add logic to take care when renderbuffer=0 glBindRenderbuffer(target, renderbuffer); } static void evgl_glClearDepthf(GLclampf depth) { #ifdef GL_GLES glClearDepthf(depth); #else glClearDepth(depth); #endif } static void evgl_glDepthRangef(GLclampf zNear, GLclampf zFar) { #ifdef GL_GLES glDepthRangef(zNear, zFar); #else glDepthRange(zNear, zFar); #endif } static void evgl_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { #ifdef GL_GLES glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision); #else if (range) { range[0] = -126; // floor(log2(FLT_MIN)) range[1] = 127; // floor(log2(FLT_MAX)) } if (precision) { precision[0] = 24; // floor(-log2((1.0/16777218.0))); } return; shadertype = precisiontype = 0; #endif } static void evgl_glReleaseShaderCompiler(void) { #ifdef GL_GLES glReleaseShaderCompiler(); #else #endif } static void evgl_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length) { #ifdef GL_GLES glShaderBinary(n, shaders, binaryformat, binary, length); #else // FIXME: need to dlsym/getprocaddress for this return; n = binaryformat = length = 0; shaders = binary = 0; #endif } #endif static void * eng_gl_api_get(void *data) { Render_Engine *re; re = (Render_Engine *)data; gl_funcs.version = EVAS_GL_API_VERSION; #if 1 #define ORD(f) EVAS_API_OVERRIDE(f, &gl_funcs, ) ORD(glActiveTexture); ORD(glAttachShader); ORD(glBindAttribLocation); ORD(glBindBuffer); ORD(glBindTexture); ORD(glBlendColor); ORD(glBlendEquation); ORD(glBlendEquationSeparate); ORD(glBlendFunc); ORD(glBlendFuncSeparate); ORD(glBufferData); ORD(glBufferSubData); ORD(glCheckFramebufferStatus); ORD(glClear); ORD(glClearColor); // ORD(glClearDepthf); ORD(glClearStencil); ORD(glColorMask); ORD(glCompileShader); ORD(glCompressedTexImage2D); ORD(glCompressedTexSubImage2D); ORD(glCopyTexImage2D); ORD(glCopyTexSubImage2D); ORD(glCreateProgram); ORD(glCreateShader); ORD(glCullFace); ORD(glDeleteBuffers); ORD(glDeleteFramebuffers); ORD(glDeleteProgram); ORD(glDeleteRenderbuffers); ORD(glDeleteShader); ORD(glDeleteTextures); ORD(glDepthFunc); ORD(glDepthMask); // ORD(glDepthRangef); ORD(glDetachShader); ORD(glDisable); ORD(glDisableVertexAttribArray); ORD(glDrawArrays); ORD(glDrawElements); ORD(glEnable); ORD(glEnableVertexAttribArray); ORD(glFinish); ORD(glFlush); ORD(glFramebufferRenderbuffer); ORD(glFramebufferTexture2D); ORD(glFrontFace); ORD(glGenBuffers); ORD(glGenerateMipmap); ORD(glGenFramebuffers); ORD(glGenRenderbuffers); ORD(glGenTextures); ORD(glGetActiveAttrib); ORD(glGetActiveUniform); ORD(glGetAttachedShaders); ORD(glGetAttribLocation); ORD(glGetBooleanv); ORD(glGetBufferParameteriv); ORD(glGetError); ORD(glGetFloatv); ORD(glGetFramebufferAttachmentParameteriv); ORD(glGetIntegerv); ORD(glGetProgramiv); ORD(glGetProgramInfoLog); ORD(glGetRenderbufferParameteriv); ORD(glGetShaderiv); ORD(glGetShaderInfoLog); // ORD(glGetShaderPrecisionFormat); ORD(glGetShaderSource); ORD(glGetString); ORD(glGetTexParameterfv); ORD(glGetTexParameteriv); ORD(glGetUniformfv); ORD(glGetUniformiv); ORD(glGetUniformLocation); ORD(glGetVertexAttribfv); ORD(glGetVertexAttribiv); ORD(glGetVertexAttribPointerv); ORD(glHint); ORD(glIsBuffer); ORD(glIsEnabled); ORD(glIsFramebuffer); ORD(glIsProgram); ORD(glIsRenderbuffer); ORD(glIsShader); ORD(glIsTexture); ORD(glLineWidth); ORD(glLinkProgram); ORD(glPixelStorei); ORD(glPolygonOffset); ORD(glReadPixels); // ORD(glReleaseShaderCompiler); ORD(glRenderbufferStorage); ORD(glSampleCoverage); ORD(glScissor); // ORD(glShaderBinary); ORD(glShaderSource); ORD(glStencilFunc); ORD(glStencilFuncSeparate); ORD(glStencilMask); ORD(glStencilMaskSeparate); ORD(glStencilOp); ORD(glStencilOpSeparate); ORD(glTexImage2D); ORD(glTexParameterf); ORD(glTexParameterfv); ORD(glTexParameteri); ORD(glTexParameteriv); ORD(glTexSubImage2D); ORD(glUniform1f); ORD(glUniform1fv); ORD(glUniform1i); ORD(glUniform1iv); ORD(glUniform2f); ORD(glUniform2fv); ORD(glUniform2i); ORD(glUniform2iv); ORD(glUniform3f); ORD(glUniform3fv); ORD(glUniform3i); ORD(glUniform3iv); ORD(glUniform4f); ORD(glUniform4fv); ORD(glUniform4i); ORD(glUniform4iv); ORD(glUniformMatrix2fv); ORD(glUniformMatrix3fv); ORD(glUniformMatrix4fv); ORD(glUseProgram); ORD(glValidateProgram); ORD(glVertexAttrib1f); ORD(glVertexAttrib1fv); ORD(glVertexAttrib2f); ORD(glVertexAttrib2fv); ORD(glVertexAttrib3f); ORD(glVertexAttrib3fv); ORD(glVertexAttrib4f); ORD(glVertexAttrib4fv); ORD(glVertexAttribPointer); ORD(glViewport); #undef ORD // Override functions wrapped by Evas_GL #define ORD(f) EVAS_API_OVERRIDE(f, &gl_funcs, evgl_) ORD(glBindFramebuffer); ORD(glBindRenderbuffer); // GLES2.0 API compat on top of desktop gl ORD(glClearDepthf); ORD(glDepthRangef); ORD(glGetShaderPrecisionFormat); ORD(glReleaseShaderCompiler); ORD(glShaderBinary); #undef ORD #endif return &gl_funcs; } static int eng_image_load_error_get(void *data EINA_UNUSED, void *image) { Evas_GL_Image *im; if (!image) return EVAS_LOAD_ERROR_NONE; im = image; return im->im->cache_entry.load_error; } static int module_open(Evas_Module *em) { if (!em) return 0; /* get whatever engine module we inherit from */ if (!_evas_module_engine_inherit(&pfunc, "software_generic")) return 0; _evas_engine_gl_cocoa_log_dom = eina_log_domain_register("EvasGLCocoa", EVAS_DEFAULT_LOG_COLOR); if(_evas_engine_gl_cocoa_log_dom < 0) { EINA_LOG_ERR("Impossible to create a log domain for GL (Cocoa) engine."); return 0; } /* store it for later use */ func = pfunc; /* now to override methods */ #define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_) ORD(info); ORD(info_free); ORD(setup); ORD(canvas_alpha_get); ORD(output_free); ORD(output_resize); ORD(output_tile_size_set); ORD(output_redraws_rect_add); ORD(output_redraws_rect_del); ORD(output_redraws_clear); ORD(output_redraws_next_update_get); ORD(output_redraws_next_update_push); ORD(context_cutout_add); ORD(context_cutout_clear); ORD(output_flush); ORD(output_idle_flush); // ORD(output_dump); ORD(rectangle_draw); ORD(line_draw); ORD(polygon_point_add); ORD(polygon_points_clear); ORD(polygon_draw); ORD(image_load); ORD(image_new_from_data); ORD(image_new_from_copied_data); ORD(image_free); ORD(image_size_get); ORD(image_size_set); ORD(image_dirty_region); ORD(image_data_get); ORD(image_data_put); ORD(image_data_preload_request); ORD(image_data_preload_cancel); ORD(image_alpha_set); ORD(image_alpha_get); ORD(image_border_set); ORD(image_border_get); ORD(image_draw); ORD(image_comment_get); ORD(image_format_get); ORD(image_colorspace_set); ORD(image_colorspace_get); ORD(image_mask_create); // ORD(image_native_set); // ORD(image_native_get); ORD(font_draw); ORD(image_scale_hint_set); ORD(image_scale_hint_get); ORD(image_stride_get); ORD(image_map_draw); ORD(image_map_surface_new); ORD(image_map_surface_free); ORD(image_content_hint_set); ORD(image_content_hint_get); ORD(image_cache_flush); ORD(image_cache_set); ORD(image_cache_get); ORD(gl_api_get); ORD(image_load_error_get); /* now advertise out own api */ em->functions = (void *)(&func); return 1; } static void module_close(Evas_Module *em) { eina_log_domain_unregister(_evas_engine_gl_cocoa_log_dom); } static Evas_Module_Api evas_modapi = { EVAS_MODULE_API_VERSION, "gl_cocoa", "none", { module_open, module_close } }; EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, gl_cocoa); #ifndef EVAS_STATIC_BUILD_GL_COCOA EVAS_EINA_MODULE_DEFINE(engine, gl_cocoa); #endif