forked from enlightenment/efl
333 lines
8.1 KiB
Objective-C
333 lines
8.1 KiB
Objective-C
#include <Cocoa/Cocoa.h>
|
|
|
|
#include "evas_engine.h"
|
|
#include "../gl_common/evas_gl_define.h"
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#define TRACE
|
|
#undef TRACE // Remove me for intense debug
|
|
|
|
#ifdef TRACE
|
|
# define TRC(...) DBG(__VA_ARGS__)
|
|
#else
|
|
# define TRC(...)
|
|
#endif
|
|
|
|
static Outbuf *_evas_gl_cocoa_window = NULL;
|
|
static NSOpenGLContext *_evas_gl_cocoa_shared_context = nil;
|
|
static int _win_count = 0;
|
|
|
|
@interface EvasGLView : NSOpenGLView
|
|
|
|
+ (NSOpenGLPixelFormat*) basicPixelFormat;
|
|
|
|
@end
|
|
|
|
@implementation EvasGLView
|
|
|
|
+ (NSOpenGLPixelFormat*) basicPixelFormat
|
|
{
|
|
const NSOpenGLPixelFormatAttribute attributes[] = {
|
|
NSOpenGLPFAAccelerated,
|
|
NSOpenGLPFATripleBuffer,
|
|
0 /* Terminator */
|
|
};
|
|
return [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease];
|
|
}
|
|
|
|
- (id) initWithFrame: (NSRect) frameRect
|
|
{
|
|
NSOpenGLPixelFormat *pf;
|
|
NSOpenGLContext *ctx;
|
|
|
|
pf = [EvasGLView basicPixelFormat];
|
|
self = [super initWithFrame: frameRect
|
|
pixelFormat: pf];
|
|
|
|
/*
|
|
* Evas GL backend uses a global OpenGL context for all windows inside
|
|
* an application. Each window has its own texture to render its
|
|
* content. We use a singleton NSOpenGLContext shared between all
|
|
* NSOpenGLView, it solves rendering issues for multiple windows.
|
|
*/
|
|
if (!_evas_gl_cocoa_shared_context)
|
|
{
|
|
_evas_gl_cocoa_shared_context = [[NSOpenGLContext alloc] initWithFormat: pf
|
|
shareContext: nil];
|
|
ctx = _evas_gl_cocoa_shared_context;
|
|
}
|
|
else
|
|
{
|
|
ctx = [[NSOpenGLContext alloc] initWithFormat: pf
|
|
shareContext: _evas_gl_cocoa_shared_context];
|
|
}
|
|
|
|
[self setOpenGLContext: ctx];
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)unlockFocus
|
|
{
|
|
//[super unlockFocus];
|
|
}
|
|
|
|
- (void)lockFocus
|
|
{
|
|
NSOpenGLContext *context;
|
|
|
|
context = [self openGLContext];
|
|
|
|
//[super lockFocus];
|
|
if ([context view] != self) {
|
|
[context setView:self];
|
|
}
|
|
[context makeCurrentContext];
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
static void *
|
|
_dlsym(const char *sym)
|
|
{
|
|
return dlsym(RTLD_DEFAULT, sym);
|
|
}
|
|
|
|
Outbuf *
|
|
evas_outbuf_new(Evas_Engine_Info_GL_Cocoa *info,
|
|
int w,
|
|
int h)
|
|
{
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(info, NULL);
|
|
|
|
Outbuf *ob;
|
|
EvasGLView *glview;
|
|
|
|
ob = calloc(1, sizeof(*ob));
|
|
if (EINA_UNLIKELY(!ob))
|
|
{
|
|
CRI("Failed to allocate memory");
|
|
goto die;
|
|
}
|
|
|
|
ob->w = w;
|
|
ob->h = h;
|
|
ob->info = info;
|
|
ob->ns_window = info->window;
|
|
ob->rot = 0;
|
|
ob->swap_mode = MODE_TRIPLE;
|
|
|
|
glview = [[EvasGLView alloc] initWithFrame: NSMakeRect(0, 0, w, h)];
|
|
if (EINA_UNLIKELY(!glview))
|
|
{
|
|
CRI("Failed to create gl_view");
|
|
goto die;
|
|
}
|
|
ob->ns_gl_view = glview;
|
|
[[glview openGLContext] makeCurrentContext];
|
|
glsym_evas_gl_symbols(_dlsym, NULL); /* XXX: NULL is ok for now for extns
|
|
* but i need to find out howon osx to get the extension string list
|
|
* for egl/whatever */
|
|
|
|
ob->gl_context = glsym_evas_gl_common_context_new();
|
|
if (EINA_UNLIKELY(!ob->gl_context))
|
|
{
|
|
CRI("Failed to create gl_context");
|
|
goto die;
|
|
}
|
|
|
|
evas_outbuf_use(ob);
|
|
glsym_evas_gl_common_context_resize(ob->gl_context,
|
|
ob->w, ob->h, ob->rot);
|
|
_win_count++;
|
|
TRC("add: %p", ob);
|
|
return ob;
|
|
|
|
die:
|
|
if (ob) free(ob);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
evas_outbuf_free(Outbuf *ob)
|
|
{
|
|
TRC("del: %p", ob);
|
|
|
|
evas_outbuf_use(ob);
|
|
|
|
_win_count--;
|
|
if (_win_count == 0) evas_common_font_ext_clear();
|
|
|
|
if (ob == _evas_gl_cocoa_window) _evas_gl_cocoa_window = NULL;
|
|
if (ob->gl_context)
|
|
{
|
|
glsym_evas_gl_common_context_free(ob->gl_context);
|
|
[(NSOpenGLView *) ob->ns_gl_view release];
|
|
}
|
|
|
|
free(ob);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_evas_outbuf_make_current(void *data EINA_UNUSED,
|
|
void *doit EINA_UNUSED)
|
|
{
|
|
GL_COCOA_UNIMPLEMENTED_CALL_SO_RETURN(EINA_FALSE);
|
|
}
|
|
|
|
void
|
|
evas_outbuf_use(Outbuf *ob)
|
|
{
|
|
if (_evas_gl_cocoa_window != ob)
|
|
{
|
|
if (_evas_gl_cocoa_window)
|
|
{
|
|
glsym_evas_gl_common_context_use(_evas_gl_cocoa_window->gl_context);
|
|
glsym_evas_gl_common_context_flush(_evas_gl_cocoa_window->gl_context);
|
|
}
|
|
_evas_gl_cocoa_window = ob;
|
|
}
|
|
[[(NSOpenGLView* )ob->ns_gl_view openGLContext] makeCurrentContext];
|
|
glsym_evas_gl_common_context_use(ob->gl_context);
|
|
}
|
|
|
|
int
|
|
evas_outbuf_rot_get(Outbuf *ob)
|
|
{
|
|
return ob->rot;
|
|
}
|
|
|
|
Render_Output_Swap_Mode
|
|
evas_outbuf_buffer_state_get(Outbuf *ob)
|
|
{
|
|
return ob->swap_mode;
|
|
}
|
|
|
|
Evas_Engine_GL_Context *
|
|
evas_outbuf_gl_context_get(Outbuf *ob)
|
|
{
|
|
return ob->gl_context;
|
|
}
|
|
|
|
void
|
|
evas_outbuf_update_region_push(Outbuf *ob,
|
|
RGBA_Image *update EINA_UNUSED,
|
|
int x EINA_UNUSED,
|
|
int y EINA_UNUSED,
|
|
int w EINA_UNUSED,
|
|
int h EINA_UNUSED)
|
|
{
|
|
TRC("");
|
|
/* Is it really necessary to flush per region ? Shouldn't we be able to
|
|
still do that for the full canvas when doing partial update */
|
|
ob->drew = EINA_TRUE;
|
|
glsym_evas_gl_common_context_flush(ob->gl_context);
|
|
}
|
|
|
|
void *
|
|
evas_outbuf_update_region_new(Outbuf *ob,
|
|
int x,
|
|
int y,
|
|
int w,
|
|
int h,
|
|
int *cx EINA_UNUSED,
|
|
int *cy EINA_UNUSED,
|
|
int *cw EINA_UNUSED,
|
|
int *ch EINA_UNUSED)
|
|
{
|
|
TRC("x,y,w,h = %i,%i,%i,%i", x, y, w, h);
|
|
|
|
if ((w == ob->w) && (h == ob->h))
|
|
ob->gl_context->master_clip.enabled = EINA_FALSE;
|
|
else
|
|
{
|
|
ob->gl_context->master_clip.enabled = EINA_TRUE;
|
|
ob->gl_context->master_clip.x = x;
|
|
ob->gl_context->master_clip.y = y;
|
|
ob->gl_context->master_clip.w = w;
|
|
ob->gl_context->master_clip.h = h;
|
|
}
|
|
|
|
return ob->gl_context->def_surface;
|
|
}
|
|
|
|
Eina_Bool
|
|
evas_outbuf_update_region_first_rect(Outbuf *ob)
|
|
{
|
|
TRC("");
|
|
|
|
glsym_evas_gl_preload_render_lock(_evas_outbuf_make_current, ob);
|
|
evas_outbuf_use(ob);
|
|
|
|
glsym_evas_gl_common_context_resize(ob->gl_context,
|
|
ob->w, ob->h,
|
|
ob->rot);
|
|
glsym_evas_gl_common_context_flush(ob->gl_context);
|
|
glsym_evas_gl_common_context_newframe(ob->gl_context);
|
|
|
|
/* To debug partial rendering */
|
|
//glClearColor(0.2, 0.5, 1.0, 1.0);
|
|
//glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
void
|
|
evas_outbuf_flush(Outbuf *ob,
|
|
Tilebuf_Rect *surface_damage EINA_UNUSED,
|
|
Tilebuf_Rect *buffer_damage EINA_UNUSED,
|
|
Evas_Render_Mode render_mode)
|
|
{
|
|
NSOpenGLView *const view = ob->ns_gl_view;
|
|
|
|
TRC("drew is %s", ob->drew ? "true" : "false");
|
|
|
|
if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) goto end;
|
|
if (!ob->drew) goto end;
|
|
|
|
ob->drew = EINA_FALSE;
|
|
evas_outbuf_use(ob);
|
|
glsym_evas_gl_common_context_done(ob->gl_context);
|
|
|
|
[[view openGLContext] flushBuffer];
|
|
end:
|
|
glsym_evas_gl_preload_render_unlock(_evas_outbuf_make_current, ob);
|
|
}
|
|
|
|
void
|
|
evas_outbuf_reconfigure(Outbuf *ob,
|
|
int w,
|
|
int h,
|
|
int rot,
|
|
Outbuf_Depth depth EINA_UNUSED)
|
|
{
|
|
TRC("w,h = %i,%i", w, h);
|
|
|
|
ob->w = w;
|
|
ob->h = h;
|
|
ob->rot = rot;
|
|
evas_outbuf_use(ob);
|
|
[[(NSOpenGLView *)ob->ns_gl_view openGLContext] flushBuffer];
|
|
glsym_evas_gl_common_context_resize(ob->gl_context, w, h, rot);
|
|
}
|
|
|
|
void
|
|
evas_outbuf_gl_context_use(Context_3D *ctx EINA_UNUSED)
|
|
{
|
|
GL_COCOA_UNIMPLEMENTED_CALL_SO_RETURN();
|
|
}
|
|
|
|
Context_3D *
|
|
evas_outbuf_gl_context_new(Outbuf *ob EINA_UNUSED)
|
|
{
|
|
GL_COCOA_UNIMPLEMENTED_CALL_SO_RETURN(NULL);
|
|
}
|
|
|
|
void *
|
|
evas_outbuf_egl_display_get(Outbuf *ob EINA_UNUSED)
|
|
{
|
|
GL_COCOA_UNIMPLEMENTED_CALL_SO_RETURN(NULL);
|
|
}
|