aboutsummaryrefslogblamecommitdiffstats
path: root/src/modules/evas/engines/gl_generic/evas_engine.c
blob: 2840f51a28052493b73f8bbe59bd0cdc09b8dff1 (plain) (tree)
1
2
3
4
5
6
7
8
9


                                 
                                    
                              
                        
                          
                                     
 
                                          








                                                                           




                                   
                                 
 










                                                                        









                                           
                                                            
                                                             


                                                                                                                                         
 

                                             






























                                                              

                             







                                                 

                                                                                             













                                                        






















                                                                                    














                                                                  

                                               






                                                         
                                                                              









                                        

                                                                     
 




                                                                              
           
                                                                                                                                                  

                                      
                                       
 
                                              





                                                                  
                                                                                                                                                     

                                      
                                       
 
                                              





                                                                  
                                                                            




                                                       
                                                                 




                                                    
                                                                                                                                                             

                                      
                                       
 
                                              





                                                                  
                                                          
 
                             
 
                     



                      
                                                               
 
                             
 
                                            



                       
                                                             
 









                                            
                                  














                                                                             
                                                           



                                                                 

                                                        








                                                                
                      
                                                                    
 







                                                       
                
                                                                           
                                                                     
                                                            
 
                              
                             
               
 










































                                                                                                  
 
                                                   


                                                                  









                                                              
      














                                                                            


           
                                                                           
 






                                      
                                  
                                         


                                    
                                                                   











                                                     
                                                                   













                                                                             

                                                                  




                         
                            




                                             
                                                             


           
                              




                                            
                                    


           
                            
 





                                            
                                         
                                                                     

                                





                                
          
                                                                              











                                                           
                                                                                  










                                                           
             
                                                             

                                     






                                         
                                                  





























                                                                              
                                 
 




                                      




































                                                                             
                                                          
                                         

















                                                                     
                                                           










                             
                                                                                                 

                                      

                                 
                                                   



                                                                   
                                                                                                          

                                      
 
                                                   



                                                                                          
                                                                                                                 

                                      
 
                                                   


                                                                                                 
    
                                         
 
                      
                                  


                                    
             
                                                    






                             
           
                                                                         
 
                     





               





                                                 

                   


       

                   
      


             
                                                           

                                      



                             
                                                   



                       
                                               

                     










                                                                 
                                                   















                                               
                                                  

                                                                          
                                     



             
                                                                             
 



                                     
                                  



                                                 
                      
                                                                    

             
                      
                                      
                         

            


              









                                                  



                                               
                                                                               












                                                               



                                     

                                





                                                                                 
 

                                                                             
 
                                  


              
      
                                                                                                             
 

                                

             
                      
                                    
                                        
 
           
      
                                                
                                  

                    
 
                       
               
 

                                                                            
 
              
                                  
 
                                                              
                                                  
      



                                                 

                       
                                                                               

                                     
                                                                
                                                                               






                                                                                   
           
                                                                                 
           
                                                  




                                                                                                              



                                                                        
                                                 










                                                             


                  
                                  

      




















                                                                           
                                             


                                                     
                                 




                                                          
                                                                             

                    
                                               
                                                                        
                                       



                                       
                                                      
                                                                 
                                          


                                                     
                                       


                                             
                            


                      



                                                                                                     
      







                                                                          
      
 
                                                            
 
                         

                                     








                                                                          
                                
                            

      









                                         


                                                                            

                                                                

                               























                                                                                   

               

                                                                  



                         


                                
                                              








                                                                   

 
      
                                                                 
 




                                     
                                  












                                                       
                                                               



                                                                                 

                                                                  
                                                                

                                                                                                                  





                          


                                                                               








                                                   

                                  

                                                             


                                                                                     



                                            
                                                    














                                                          
                                                 

               
                                                                  
               



             
             
                                                                         
 
                     
                         




                                          
                                  
 

                                           
                                                                                          

                          









                                           
 
                           





                                      


                                 


                        
                                                           
 
                             
 
                                          


                     
           
                                                                                       

                              






                                
                                                                                                   


           
                                                                                                       








                                
                                             
                                                                    
                                                                             


                
                                                                                                                                                                                                                    
 
                                          
                                      
                                       



                              
 

                       
                                              
 
                                          
      
                                    
 
                                 


                                                
           


                                                                    
 
                                                  
                                                  





                                                                                   







                                                        
                                                    
                                                       
                                             

                                  
                              
                                                                                
                               








                                                                  
           


                                      














                                                                       
                                                                         




                                                               
                                                               






                                               

                                                                                                   


                                      

                                 
                                                

                                                                  
 

                                      


















                                         



                                      
                                                             











                                                                               
                                                                      



             
                                                                
 
                                      
 
                                                   
                                                                                

 
      
                                                                            
                                                               

                                                           
                                                                                       

 
           
                                                               
 
                                  


                                                      
           
                                   

                                      

                
                                                   
                           








                                                
                                            

                                      
 
                                                   


                                                     
                                                                


          
                                             




                                        
                                  
 

                
                                  






                                           
                                           
 
                                  



                                     
                                
 
                                  



                                       
                                                                        
























                                                   















                                                                          








                                                                           
                                                                                                                                                                                                                                                                           

                                      
 
                                                


                                                                  



                                                                                                         




                                                                        
                                                                        


                                                                       
                                                  
                                                                                           


                                                      


                                                   








                                                    


                                              
 
































                                                                   

 

                                                                                                      







                                                                    









                                                        

             
                                                               


                                                  

                                             

 
             
                                                                                               


                                                  

                                                                  

 
          
                                                   

                                                
                                        
 



                                           


             
                                                                     

                                                          


                                                       

                                                                                      


          
                                                   


                                                

                                        


          
                                                            
 
                                          

                                                
                                    
               
 
                                         


                                           
                                                        


                                           
                                                             





                                                        




                                             

              


             
                                                    


                     
                                              







                                                               
          
                                    
 


                                          
                                                         
                                         





                                                                

 
                   
                                           
 
                  
                                  

 
             
                                                       
 
                  
                    
 
                                            





                                                                           

                



                                                          



               
                                                                                        







                                                                   
                                         
 
                                    
                                      

                  
 
                                                   









                                                                                       


                                                  





                                                 



           
                                                                                   
 
              


                                                 
                
                                                                                                                          
 
                                          
                                         
                                                 

                                      
 
                              

                                 
                              
                                                                                                 







                                                                                      
                                              


                                      


                    
           
                                                                                    
 
                                          
 


                                                  

 
           
                                       
 




                                        



                         
                                                                



                          
                
                                                            
 

                               
                                       










                                                         
                                                              
 

                               




                           
                                                                   


                                                                
                               
                                
                


                                                      












                                                                           



                                                                          


                                                              













                                                                       












                                                                    
 

                                                  


                    

                
                                                                     
 

                                          

                                


                                  





                                                                   
                   
 
                                       
                                                                            









































































                                                                                 
                                                                            



                                                         
                                                        








                                                            
          
                                                              






                              
                                                                 
 
                                          


                             
                                                            




                             


                                    
                                                               








                                           
                                                             











                                
                                                                         












                                         
                                                                       












                                                                    
                                                                        












                                         
                                                                                                            












                                                                                           
                                                                                    















                                                                
                                                               


                              
 







                                                               
                                                          

                                      
 
                                                   




















                                                                                                                                                                                                            

                                  



































                                                                            
                                                           




























                                                                                
                               

                                      
 
                                                   



                                    






                                                 
                                                                     



                                      
                                 
 



                         
                                                                                    
                                                                      


                                    
                                
 


                                      
                                                        


                            




                            



                                                   
          
      
                                                 

                                                                              



           
                                                                                              


                                    






                                             




                                
                                             




                                    
                                                   


                                          
             
                                                        









                                               
           
                                
 
                                         






                                                                 
                                 
 
                                         






                                          
                                                       
 
                                                      







                                                                       
                                               
 
                                                      



                               
                                                                               




                                                         
                                                                 















                                                               
                                                   


           
                                                                                     

                                      

                                 
                                                

                                            
                                                      
                                        


                                                             
          





                                                                




                                                                           


                                                                          
 
                                                                           


                
                                                                                    

                                      

                                 
                                                  

                                            
                                                      
                                          



                                                                                               

                                                                              
                                                                                                
 
                                                                               
 
             
                                                              
 
                                     


           
                                                         




                                            
                                                                             




                                                      
                                                             
                                                                          




                                                      
                                                             
                                                                            




                                                      
                                                               
                                                                                          




                                                            
                                                               
                                                                                            




                                                            
                                                               

                                      
 
                                                   




                                                                               
                                                              
 
                                                  

 

                                        

                      
                                          
 


                                           
                                                 
                                                              
      
                                                                


                                                                        
                                                          
                           
      

       
                                                                      

                              
                            



                
                                                                 
 
                               

 
                     
                                                                               
 
                                    
 
                                                      
 

                                                                           
 
 


                                                                        
                     
                                                            
                                                                        
 













































                                                                                                               

 
           


                                                                                      
 
                            
      


                                          
                                       
 

                                                           
 
                                                                              
 






                                       
      

 

















                                                                                                                   
                              






































                                                                                       
           


                                                                              
 
                           
      
                         
                                      

                       
 


                                                                                    

                                                 
 
                                                            
                                                                                                     
                                                       


       
                                      
      


           




                                             
 

                            
                                      

                       
 
                                                                                     
 

                                                 
                                                                                              
                                  


                   
                                      
      

 
                
                                                                    
                                                           

                                                                           
 
                                         
                                      



                                      
 
                                                                         
 









                                                            
      

                                             
 





                                                                     
                                                                   

      






                                          
 





















                                                                      


                
                                                                                       




                                
                         



                                     
                                                                             


                               



                                                                       





                                                                                
                                                       





                            
                                                                        



                     
                                                                                                  






                                   
               


                                        
                               


            
 

















                                                 
                                                   












































                                                                             
                                                                                      
                 
                                                                               





                                                      
                                                                             




























                                                                      
                         
                                  

                                     
                         
                                  


























                                                                       
                         




















                                                                      




































                                                            
                                      


               
           
                                                        






                                           
             
                                                                    

                                      
 
                                                   
                                                                            

 


                                                    
                                                                            




                                       







                                                                                                






                           
                                                               
 
                                         
 
                                      





                                                          
                                                              
 
                                         

                                
                                           







                                                         





                                                   
                                                                             
                                   
                                                                                                   





                                                            


                                        



                                                


                    


                                 
                    
                     
 





                             



                                   
                  




                           
                              



                                   

                         
                   

                             
                                  
                             

                              










                              
                        
                            

                               




                          


                            
                             
 
                      
                                  
 



                         
                            
                      
                          
                                  








                               
                                         
                          

                           


                               
                       
                         

                                         
                              

                            
























                                          
                                           
                                       

                                         
                                             

                     





                           
                          
 

                      
                          
                         


                            




                                 


                            







                                         
                    




                                                            


















                                                                
#include "evas_common_private.h"
#include "evas_gl_core_private.h"

#include "software/Ector_Software.h"
#include "cairo/Ector_Cairo.h"
#include "gl/Ector_GL.h"
#include "evas_ector_gl.h"
#include "filters/gl_engine_filter.h"

#if defined HAVE_DLSYM && ! defined _WIN32
# include <dlfcn.h>      /* dlopen,dlclose,etc */
#else
# error gl_x11 should not get compiled if dlsym is not found on the system!
#endif

#include "../gl_common/evas_gl_common.h"

#include "Evas_Engine_GL_Generic.h"

#define EVAS_GL_NO_GL_H_CHECK 1
#include "Evas_GL.h"

#define EVAS_GL_UPDATE_TILE_SIZE 16

int _evas_engine_GL_log_dom = -1;

#undef ERR
#undef DBG
#undef INF
#undef WRN
#undef CRI
#define ERR(...) EINA_LOG_DOM_ERR(_evas_engine_GL_log_dom, __VA_ARGS__)
#define DBG(...) EINA_LOG_DOM_DBG(_evas_engine_GL_log_dom, __VA_ARGS__)
#define INF(...) EINA_LOG_DOM_INFO(_evas_engine_GL_log_dom, __VA_ARGS__)
#define WRN(...) EINA_LOG_DOM_WARN(_evas_engine_GL_log_dom, __VA_ARGS__)
#define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_GL_log_dom, __VA_ARGS__)

#ifdef GL_GLES
# ifndef GL_FRAMEBUFFER
#  define GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
# endif
#else
# ifndef GL_FRAMEBUFFER
#  define GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
# endif
#endif

static int eng_gl_image_direct_get(void *data, void *image);
static int eng_gl_surface_destroy(void *data, void *surface);
static Eina_Bool eng_gl_surface_lock(void *data, void *surface);
static Eina_Bool eng_gl_surface_unlock(void *data, void *surface);
static Eina_Bool eng_gl_surface_read_pixels(void *data, void *surface, int x, int y, int w, int h, Evas_Colorspace cspace, void *pixels);

Eina_Bool _need_context_restore = EINA_FALSE;

static Render_Output_GL_Generic *
_evgl_output_find(Render_Engine_GL_Generic *engine)
{
   Render_Output_GL_Generic *output = NULL;
   EVGL_Resource *rsc;
   Eina_List *l;

   if (engine->current)
     {
        output = engine->current;
        goto picked;
     }

   rsc = _evgl_tls_resource_get();
   if (rsc &&
       rsc->stored.data)
     {
        EINA_LIST_FOREACH(engine->software.outputs, l, output)
          if (output == rsc->stored.data) goto picked;
     }

   EINA_LIST_FOREACH(engine->software.outputs, l, output)
     {
        if (output->software.ob) goto picked;
     }
   return NULL;

 picked:
   return output;
}

static Evas_Func func, pfunc;

void
_context_restore(void)
{
   EVGL_Resource *rsc = _evgl_tls_resource_get();
   if (rsc)
     {
        if (rsc->id == evgl_engine->main_tid)
          {
             if (rsc->stored.data)
               evgl_make_current(rsc->stored.data, rsc->stored.surface, rsc->stored.context);
             _need_context_restore = EINA_FALSE;
          }
     }
}

static inline void
_context_store(void *data, void *surface, void *context)
{
   EVGL_Resource *rsc = _evgl_tls_resource_get();
   if (rsc)
     {
        if (rsc->id == evgl_engine->main_tid)
          {
             _need_context_restore = EINA_FALSE;
             rsc->stored.data = data;
             rsc->stored.surface = surface;
             rsc->stored.context = context;
          }
     }
}

static inline void
_context_stored_reset(void *data EINA_UNUSED, void *surface)
{
   EVGL_Resource *rsc = _evgl_tls_resource_get();
   if (rsc && rsc->stored.surface == surface)
     {
        _need_context_restore = EINA_FALSE;
        rsc->stored.data = NULL;
        rsc->stored.surface = NULL;
        rsc->stored.context = NULL;
     }
}

#define CONTEXT_STORE(data, surface, context) _context_store(data, surface, context)
#define CONTEXT_STORED_RESET(data, surface) _context_stored_reset(data, surface)

#ifdef GL_GLES
static void *
egl_display_get(Render_Engine_GL_Generic *engine)
{
   Render_Output_GL_Generic *output;
   Eina_List *l;

   EINA_LIST_FOREACH(engine->software.outputs, l, output)
     if (output->software.ob)
       return output->window_egl_display_get(output->software.ob);

   return NULL;
}
#endif

void eng_image_free(void *engine, void *image);

static void *
eng_engine_new(void)
{
   Render_Engine_GL_Generic *engine;

   engine = calloc(1, sizeof (Render_Engine_GL_Generic));
   if (!engine) return NULL;
   engine->software.surface_cache = generic_cache_new(engine, eng_image_free);

   return engine;
}

static void
eng_engine_free(void *engine)
{
   Render_Engine_GL_Generic *e = engine;
   Render_Output_GL_Generic *output;

   //@FIXME this causes some deadlock while freeing the engine image.
   //generic_cache_destroy(e->software.surface_cache);

   EINA_LIST_FREE(e->software.outputs, output)
     ERR("Output %p not properly cleaned before engine destruction.", output);
   free(e);
}

static void
eng_rectangle_draw(void *engine EINA_UNUSED, void *data, void *context, void *surface, int x, int y, int w, int h, Eina_Bool do_async EINA_UNUSED)
{
   Evas_Engine_GL_Context *gl_context;
   Render_Output_GL_Generic *re = data;

   gl_context = gl_generic_context_get(re, 1);
   evas_gl_common_context_target_surface_set(gl_context, surface);
   gl_context->dc = context;
   evas_gl_common_rect_draw(gl_context, x, y, w, h);
}

static void
eng_line_draw(void *engine EINA_UNUSED, void *data, void *context, void *surface, int p1x, int p1y, int p2x, int p2y, Eina_Bool do_async EINA_UNUSED)
{
   Evas_Engine_GL_Context *gl_context;
   Render_Output_GL_Generic *re = data;

   gl_context = gl_generic_context_get(re, 1);
   evas_gl_common_context_target_surface_set(gl_context, surface);
   gl_context->dc = context;
   evas_gl_common_line_draw(gl_context, p1x, p1y, p2x, p2y);
}

static void *
eng_polygon_point_add(void *engine EINA_UNUSED, void *polygon, int x, int y)
{
   return evas_gl_common_poly_point_add(polygon, x, y);
}

static void *
eng_polygon_points_clear(void *engine EINA_UNUSED, void *polygon)
{
   return evas_gl_common_poly_points_clear(polygon);
}

static void
eng_polygon_draw(void *engine EINA_UNUSED, void *data, void *context, void *surface EINA_UNUSED, void *polygon, int x, int y, Eina_Bool do_async EINA_UNUSED)
{
   Evas_Engine_GL_Context *gl_context;
   Render_Output_GL_Generic *re = data;

   gl_context = gl_generic_context_get(re, 1);
   evas_gl_common_context_target_surface_set(gl_context, surface);
   gl_context->dc = context;
   evas_gl_common_poly_draw(gl_context, polygon, x, y);
}

static int
eng_image_alpha_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *im = image;

   if (!im) return 1;
   return im->alpha;
}

static Evas_Colorspace
eng_image_colorspace_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *im = image;

   if (!im) return EVAS_COLORSPACE_ARGB8888;
   return im->cs.space;
}

static void *
eng_image_alpha_set(void *engine, void *image, int has_alpha)
{
   Evas_GL_Image *im;

   if (!image) return NULL;
   im = image;
   if (im->alpha == has_alpha) return image;
   if (im->native.data)
     {
        im->alpha = has_alpha;
        return image;
     }
   gl_generic_window_find(engine);
   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);
        evas_gl_common_image_alloc_ensure(im);
        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(engine, image),
               eng_image_colorspace_get(engine, 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);
}

static Evas_Colorspace
eng_image_file_colorspace_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *im = image;

   if (!im || !im->im) return EVAS_COLORSPACE_ARGB8888;
   if (im->im->cache_entry.cspaces)
     return im->im->cache_entry.cspaces[0];
   return im->im->cache_entry.space;
}

static Eina_Bool
eng_image_data_direct_get(void *engine EINA_UNUSED, void *image, int plane,
                          Eina_Slice *slice, Evas_Colorspace *cspace,
                          Eina_Bool load, Eina_Bool *tofree)
{
   Eina_Bool ret = EINA_FALSE;
   Evas_GL_Image *im = image;
   int bpp = 0;

   if (!slice || !im) return ret;

   /* If content hint is DYNAMIC, the im->im could be NULL. If the im->im does 
      not exist, eng_image_data_direct_get needs to return copied dyn.data to
      make functions including efl_file_save work. */
   if ((im->content_hint == EVAS_IMAGE_CONTENT_HINT_DYNAMIC) &&
       tofree &&
       (im->tex_only) && (!im->im) &&
       (im->tex) && (im->tex->pt) && (im->tex->pt->dyn.data))
     {
        *tofree = EINA_FALSE;
        switch ( im->cs.space)
          {
           case EFL_GFX_COLORSPACE_ARGB8888:
             bpp = 4;
             EINA_FALLTHROUGH;
             // falltrhough is intended
           case EFL_GFX_COLORSPACE_AGRY88:
             if (!bpp) bpp = 2;
             EINA_FALLTHROUGH;
             // falltrhough is intended
           case EFL_GFX_COLORSPACE_GRY8:
             if (!bpp) bpp = 1;
             *tofree = EINA_TRUE;
             im->im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
             im->im->cache_entry.flags.alpha = im->alpha;
             im->im->cache_entry.space = im->cs.space;
             evas_cache_image_colorspace(&im->im->cache_entry, im->cs.space);
             im->im = (RGBA_Image *)evas_cache_image_size_set(&im->im->cache_entry, im->w, im->h);

             DATA8 *pixels = (DATA8 *)im->tex->pt->dyn.data;
             for (int i = 0; i < im->tex->pt->dyn.h; i++)
               {
                  memcpy(im->im->image.data + (im->w * i),
                         pixels + (im->tex->pt->dyn.stride * i),
                         im->w * bpp);
               }
             break;
           default: break;
          }
     }

   if (!im->im) return ret;

   if (cspace) *cspace = im->im->cache_entry.space;
   if (load)
     {
        if (evas_cache_image_load_data(&im->im->cache_entry) != 0)
          {
             /* Only valid when content hint is DYNAMIC */
             if (tofree && *tofree)
               {
                  evas_cache_image_drop(&im->im->cache_entry);
                  im->im = NULL;
               }

             return ret;
          }
     }

   ret = _evas_common_rgba_image_plane_get(im->im, plane, slice);

   /* The im->im is not necessary, because it is created temporal purpose to
      get the slice used by out side of this function. */
   if (tofree && *tofree)
     {
        if (ret)
          *slice = eina_rw_slice_slice_get(eina_slice_dup(*slice));

        evas_cache_image_drop(&im->im->cache_entry);
        im->im = NULL;
     }

   return ret;
}

static void
eng_image_colorspace_set(void *engine, void *image, Evas_Colorspace cspace)
{
   Evas_GL_Image *im;

   if (!image) return;
   im = image;
   if (im->native.data) return;
   /* FIXME: can move to gl_common */
   if (im->cs.space == cspace) return;
   gl_generic_window_find(engine);
   evas_gl_common_image_alloc_ensure(im);
   switch (cspace)
     {
      case EVAS_COLORSPACE_ARGB8888:
         evas_cache_image_colorspace(&im->im->cache_entry, cspace);
         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:
      case EVAS_COLORSPACE_YCBCR422601_PL:
      case EVAS_COLORSPACE_YCBCR420NV12601_PL:
      case EVAS_COLORSPACE_YCBCR420TM12601_PL:
         evas_cache_image_colorspace(&im->im->cache_entry, cspace);
         if (im->tex) evas_gl_common_texture_free(im->tex, EINA_TRUE);
         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:
         ERR("colorspace %d is not supported here", im->cs.space);
         return;
     }
   im->cs.space = cspace;
}

static void
_native_bind_cb(void *image)
{
   Evas_GL_Image *im = image;
   Evas_Native_Surface *n = im->native.data;

   if (n->type == EVAS_NATIVE_SURFACE_OPENGL)
     glBindTexture(GL_TEXTURE_2D, n->data.opengl.texture_id);
}

static void
_native_unbind_cb(void *image)
{
  Evas_GL_Image *im = image;
  Evas_Native_Surface *n = im->native.data;

  if (n->type == EVAS_NATIVE_SURFACE_OPENGL)
    glBindTexture(GL_TEXTURE_2D, 0);
}

static void
_native_free_cb(void *image)
{
  Evas_GL_Image *im = image;
  Evas_Native_Surface *n = im->native.data;
  uint32_t texid;

  if (n->type == EVAS_NATIVE_SURFACE_OPENGL)
    {
       texid = n->data.opengl.texture_id;
       eina_hash_del(im->native.shared->native_tex_hash, &texid, im);
    }
  im->native.data        = NULL;
  im->native.func.bind   = NULL;
  im->native.func.unbind = NULL;
  im->native.func.free   = NULL;
  free(n);
}

static int
eng_image_native_init(void *engine EINA_UNUSED, Evas_Native_Surface_Type type)
{
   switch (type)
     {
      case EVAS_NATIVE_SURFACE_OPENGL:
        return 1;
      default:
        ERR("Native surface type %d not supported!", type);
        return 0;
     }
}

static void
eng_image_native_shutdown(void *engine EINA_UNUSED, Evas_Native_Surface_Type type)
{
   switch (type)
     {
      case EVAS_NATIVE_SURFACE_OPENGL:
        return;
      default:
        ERR("Native surface type %d not supported!", type);
        return;
     }
}

static void *
eng_image_native_set(void *engine, void *image, void *native)
{
  Evas_Engine_GL_Context *gl_context;
  Evas_Native_Surface *ns = native;
  Evas_GL_Image *im = image, *im2 = NULL;
  uint32_t texid;
  Evas_Native_Surface *n;
  unsigned int tex = 0;
  unsigned int fbo = 0;

  gl_context = gl_generic_context_find(engine, 1);

  if (!im)
    {
       if ((ns) && (ns->type == EVAS_NATIVE_SURFACE_OPENGL))
         {
            im = evas_gl_common_image_new_from_data(gl_context,
                                                    ns->data.opengl.w,
                                                    ns->data.opengl.h,
                                                    NULL, 1,
                                                    EVAS_COLORSPACE_ARGB8888);
         }
       else
         return NULL;
    }

  if (ns)
    {
      if (ns->type == EVAS_NATIVE_SURFACE_OPENGL)
        {
          tex = ns->data.opengl.texture_id;
          fbo = ns->data.opengl.framebuffer_id;
          if (im->native.data)
            {
              Evas_Native_Surface *ens = im->native.data;
              if ((ens->data.opengl.texture_id == tex) &&
                  (ens->data.opengl.framebuffer_id == fbo))
                return im;
            }
        }
    }
  gl_generic_window_find(engine);

   if (!ns)
     {
        evas_gl_common_image_free(im);
        return NULL;
     }

  if (ns->type == EVAS_NATIVE_SURFACE_OPENGL)
    {
       texid = tex;
       im2 = eina_hash_find(gl_context->shared->native_tex_hash, &texid);
       if (im2 == im) return im;
       if (im2)
         {
            n = im2->native.data;
            if (n)
              {
                 evas_gl_common_image_ref(im2);
                 evas_gl_common_image_free(im);
                 return im2;
              }
         }

    }
  im2 = evas_gl_common_image_new_from_data(gl_context,
                                           im->w, im->h, NULL, im->alpha,
                                           EVAS_COLORSPACE_ARGB8888);
  evas_gl_common_image_free(im);
  im = im2;
  if (!im) return NULL;
  if (ns->type == EVAS_NATIVE_SURFACE_OPENGL)
    {
      if (native)
        {
          n = calloc(1, sizeof(Evas_Native_Surface));
          if (n)
            {
              memcpy(n, ns, sizeof(Evas_Native_Surface));

              eina_hash_add(gl_context->shared->native_tex_hash, &texid, im);

              im->native.yinvert     = 0;
              im->native.loose       = 0;
              im->native.shared      = gl_context->shared;
              im->native.data        = n;
              im->native.func.bind   = _native_bind_cb;
              im->native.func.unbind = _native_unbind_cb;
              im->native.func.free   = _native_free_cb;
              im->native.target      = GL_TEXTURE_2D;
              im->native.mipmap      = 0;

              // FIXME: need to implement mapping sub texture regions
              // x, y, w, h for possible texture atlasing

              evas_gl_common_image_native_enable(im);
            }
        }

    }
   return im;
}

static void *
eng_image_native_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *im = image;
   Evas_Native_Surface *n;

   if (!im) return NULL;
   n = im->native.data;
   if (!n) return NULL;
   return n;
}

static void *
eng_image_mmap(void *engine, Eina_File *f, const char *key, int *error, Evas_Image_Load_Opts *lo)
{
   Evas_Engine_GL_Context *gl_context;

   *error = EVAS_LOAD_ERROR_NONE;
   gl_context = gl_generic_context_find(engine, 1);
   return evas_gl_common_image_mmap(gl_context, f, key, lo, error);
}

static void *
eng_image_new_from_data(void *engine, int w, int h, DATA32 *image_data, int alpha, Evas_Colorspace cspace)
{
   Evas_Engine_GL_Context *gl_context;

   gl_context = gl_generic_context_find(engine, 1);
   return evas_gl_common_image_new_from_data(gl_context, w, h, image_data, alpha, cspace);
}

static void *
eng_image_new_from_copied_data(void *engine, int w, int h, DATA32 *image_data, int alpha, Evas_Colorspace cspace)
{
   Evas_Engine_GL_Context *gl_context;

   gl_context = gl_generic_context_find(engine, 1);
   return evas_gl_common_image_new_from_copied_data(gl_context, w, h, image_data, alpha, cspace);
}

void
eng_image_free(void *engine, void *image)
{
   if (!image) return;
   gl_generic_window_find(engine);
   evas_gl_common_image_free(image);
}

static void *
eng_image_ref(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *im = image;
   if (!im) return NULL;
   im->references++;
   return im;
}

static void
eng_image_size_get(void *engine EINA_UNUSED, void *image, int *w, int *h)
{
   Evas_GL_Image *im;
   if (!image)
     {
        *w = 0;
        *h = 0;
        return;
     }
   im = image;
   if (im->orient == EVAS_IMAGE_ORIENT_90 ||
       im->orient == EVAS_IMAGE_ORIENT_270 ||
       im->orient == EVAS_IMAGE_FLIP_TRANSPOSE ||
       im->orient == EVAS_IMAGE_FLIP_TRANSVERSE)
     {
        *w = im->h;
        *h = im->w;
     }
   else
     {
        *w = im->w;
        *h = im->h;
     }
}

static void *
eng_image_size_set(void *engine, void *image, int w, int h)
{
   Evas_Engine_GL_Context *gl_context;
   Evas_GL_Image *im = image;
   Evas_GL_Image *im_old;

   if (!im) return NULL;
   gl_context = gl_generic_context_find(engine, 1);
   if (im->native.data)
     {
        im->w = w;
        im->h = h;
        evas_gl_common_image_native_enable(im);
        return image;
     }
   if ((im->tex) && (im->tex->pt->dyn.img))
     {
        evas_gl_common_texture_free(im->tex, EINA_TRUE);
        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(engine, 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;
      default: break;
     }

   evas_gl_common_image_alloc_ensure(im_old);
   if ((im_old->im) &&
       ((int)im_old->im->cache_entry.w == w) &&
       ((int)im_old->im->cache_entry.h == h))
     return image;
   im = evas_gl_common_image_new(gl_context, w, h,
                                 eng_image_alpha_get(engine, image),
                                 eng_image_colorspace_get(engine, image));
   evas_gl_common_image_free(im_old);
   return im;
}

static void *
eng_image_dirty_region(void *engine, void *image, int x, int y, int w, int h)
{
   Evas_GL_Image *im = image;

   if (!image) return NULL;
   if (im->native.data) return image;
   gl_generic_window_find(engine);
   evas_gl_common_image_dirty(image, x, y, w, h);
   return image;
}

static Evas_GL_Image *
_rotate_image_data(Render_Engine_GL_Generic *re, Evas_GL_Image *im1)
{
   int alpha;
   Evas_GL_Image *im2;
   Evas_Engine_GL_Context *gl_context;
   RGBA_Draw_Context *dc;
   int w, h;


   w = im1->w;
   h = im1->h;

   if (im1->orient == EVAS_IMAGE_ORIENT_90 ||
       im1->orient == EVAS_IMAGE_ORIENT_270 ||
       im1->orient == EVAS_IMAGE_FLIP_TRANSPOSE ||
       im1->orient == EVAS_IMAGE_FLIP_TRANSVERSE)
     {
        w = im1->h;
        h = im1->w;
     }

   if ((w * h) <= 0) return NULL;

   alpha = eng_image_alpha_get(re, im1);
   gl_context = gl_generic_context_find(re, 1);
   im2 = evas_gl_common_image_surface_new(gl_context, w, h, alpha, EINA_FALSE);

   evas_gl_common_context_target_surface_set(gl_context, im2);

   // Create a new and temporary context
   dc = evas_common_draw_context_new();
   evas_common_draw_context_set_clip(dc, 0, 0, im2->w, im2->h);
   gl_context->dc = dc;

   // Image draw handle the rotation magically for us
   evas_gl_common_image_draw(gl_context, im1,
                             0, 0, w, h,
                             0, 0, im2->w, im2->h,
                             0);

   gl_context->dc = NULL;
   evas_common_draw_context_free(dc);

   // flush everything
   eng_gl_surface_lock(re, im2);

   // Rely on Evas_GL_Image infrastructure to allocate pixels
   im2->im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
   if (!im2->im) return NULL;
   im2->im->cache_entry.flags.alpha = !!alpha;
   evas_gl_common_image_alloc_ensure(im2);

   eng_gl_surface_read_pixels(re, im2, 0, 0, im2->w, im2->h,
                              EVAS_COLORSPACE_ARGB8888, im2->im->image.data);

   eng_gl_surface_unlock(re, im2);
   return im2;
}

void *
eng_image_data_get(void *engine, void *image, int to_write, DATA32 **image_data, int *err, Eina_Bool *tofree)
{
   Evas_GL_Image *im_new = NULL;
   Evas_GL_Image *im = image;
   int error;

   *image_data = NULL;
   if (tofree) *tofree = EINA_FALSE;
   if (err) *err = EVAS_LOAD_ERROR_NONE;

   if (!im)
     {
        if (err) *err = EVAS_LOAD_ERROR_GENERIC;
        ERR("No image provided.");
        return NULL;
     }

   if (im->native.data)
     return im;

   if ((tofree != NULL) && im->im && (im->orient != EVAS_IMAGE_ORIENT_NONE))
     goto rotate_image;

#ifdef GL_GLES
   gl_generic_window_find(engine);

   if ((im->tex) && (im->tex->pt) && (im->tex->pt->dyn.img) &&
       (im->cs.space == EVAS_COLORSPACE_ARGB8888))
     {
        if (im->tex->pt->dyn.checked_out > 0)
          {
             im->tex->pt->dyn.checked_out++;
             *image_data = im->tex->pt->dyn.data;
             return im;
          }
        if ((im->gc->shared->info.sec_tbm_surface) && (secsym_tbm_surface_map))
          {
             tbm_surface_info_s info;
             if (secsym_tbm_surface_map(im->tex->pt->dyn.buffer,
                                    TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE,
                                    &info))
               {
                  ERR("tbm_surface_map failed!");
                  *image_data = im->tex->pt->dyn.data = NULL;
               }
             else
               *image_data = im->tex->pt->dyn.data = (DATA32 *) info.planes[0].ptr;
          }
        else if ((im->gc->shared->info.sec_image_map) && (secsym_eglMapImageSEC))
          {
             void *disp = egl_display_get(engine);
             *image_data = im->tex->pt->dyn.data = secsym_eglMapImageSEC(disp,
                                                                         im->tex->pt->dyn.img,
                                                                         EGL_MAP_GL_TEXTURE_DEVICE_CPU_SEC,
                                                                         EGL_MAP_GL_TEXTURE_OPTION_WRITE_SEC);
          }

        if (!im->tex->pt->dyn.data)
          {
             if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
             ERR("Ressource allocation failed.");
             return im;
          }
        im->tex->pt->dyn.checked_out++;

        if (err) *err = EVAS_LOAD_ERROR_NONE;
        return im;
     }
#else
   if ((im->tex) && (im->tex->pt) && (im->tex->pt->dyn.data))
     {
        *image_data = im->tex->pt->dyn.data;
        return im;
     }

   gl_generic_window_find(engine);
#endif

   /* use glReadPixels for FBOs (assume fbo > 0) */
   if (!im->im && im->tex && im->tex->pt && im->tex->pt->fb)
     {
        Eina_Bool ok;

        if (to_write)
          {
             // This could be implemented, but can't be efficient at all.
             // Apps should avoid this situation.
             ERR("Can not retrieve image data from FBO to write it back.");
             if (err) *err = EVAS_LOAD_ERROR_GENERIC;
             return NULL;
          }

        if (!tofree)
          {
             ERR("FBO image must be freed after image_data_get.");
             if (err) *err = EVAS_LOAD_ERROR_GENERIC;
             return NULL;
          }

        ok = eng_gl_surface_lock(engine, im);
        if (!ok)
          {
             if (err) *err = EVAS_LOAD_ERROR_GENERIC;
             ERR("Lock failed.");
             return NULL;
          }

        im_new = evas_gl_common_image_new_from_copied_data
              (im->gc, im->tex->w, im->tex->h, NULL,
               eng_image_alpha_get(engine, image), EVAS_COLORSPACE_ARGB8888);
        if (!im_new)
          {
             eng_gl_surface_unlock(engine, im);
             if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
             ERR("Allocation failed.");
             return NULL;
          }

        ok = eng_gl_surface_read_pixels
              (engine, im, 0, 0, im_new->w, im_new->h,
               EVAS_COLORSPACE_ARGB8888, im_new->im->image.data);
        eng_gl_surface_unlock(engine, im);
        if (!ok)
          {
             if (err) *err = EVAS_LOAD_ERROR_GENERIC;
             ERR("ReadPixels failed.");
             return NULL;
          }
        *image_data = im_new->im->image.data;
        *tofree = EINA_TRUE;
        return im_new;
     }

   /* Engine can be fail to create texture after cache drop like eng_image_content_hint_set function,
        so it is need to add code which check im->im's NULL value*/

   if (!im->im)
     {
        if (tofree)
          goto rotate_image;
        else
          {
             ERR("GL image has no source data, failed to get pixel data");
             if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
             return NULL;
          }
     }

   error = evas_cache_image_load_data(&im->im->cache_entry);

   if (err) *err = error;
   if (error != EVAS_LOAD_ERROR_NONE)
     {
        if (!im->im->image.data ||
            (im->im->cache_entry.allocated.w != (unsigned) im->w) ||
            (im->im->cache_entry.allocated.h != (unsigned) im->h))
          {
             ERR("GL image has no source data, failed to get pixel data");
             *image_data = NULL;
             return im;
          }

        if (tofree && !to_write)
          goto rotate_image;
     }

   evas_gl_common_image_alloc_ensure(im);
   switch (im->cs.space)
     {
      case EVAS_COLORSPACE_ARGB8888:
      case EVAS_COLORSPACE_AGRY88:
      case EVAS_COLORSPACE_GRY8:
         if (to_write)
           {
              if (im->references > 1)
                {
                   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(engine, image),
                       eng_image_colorspace_get(engine, image));
                   if (!im_new)
                     {
                        if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
                        return NULL;
                     }
                   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:
      case EVAS_COLORSPACE_YCBCR422601_PL:
      case EVAS_COLORSPACE_YCBCR420NV12601_PL:
      case EVAS_COLORSPACE_YCBCR420TM12601_PL:
         *image_data = im->cs.data;
         break;
      case EVAS_COLORSPACE_ETC1:
      case EVAS_COLORSPACE_RGB8_ETC2:
      case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
      case EVAS_COLORSPACE_ETC1_ALPHA:
         ERR("This image is encoded in ETC1 or ETC2, not returning any data");
         error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
         break;
      default:
         ERR("colorspace %d is not supported here", im->cs.space);
         error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
         break;
     }
   if (err) *err = error;
   return im;

rotate_image:
   // rotate data for image save
   im_new = _rotate_image_data(engine, image);
   if (!im_new)
     {
        if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
        ERR("Image rotation failed.");
        return im;
     }
   *tofree = EINA_TRUE;
   *image_data = im_new->im->image.data;
   return im_new;
}

void *
eng_image_data_put(void *engine, void *image, DATA32 *image_data)
{
   Evas_GL_Image *im, *im2;

   if (!image) return NULL;
   im = image;
   if (im->native.data) return image;
   gl_generic_window_find(engine);
   evas_gl_common_image_alloc_ensure(im);
   if ((im->tex) && (im->tex->pt)
       && (im->tex->pt->dyn.data)
       && (im->cs.space == EVAS_COLORSPACE_ARGB8888))
     {
        if (im->tex->pt->dyn.data == image_data)
          {
             if (im->tex->pt->dyn.checked_out > 0)
               {
                 im->tex->pt->dyn.checked_out--;
#ifdef GL_GLES
                 if (im->tex->pt->dyn.checked_out == 0)
                   {
                      if (im->gc->shared->info.sec_tbm_surface)
                        {
                           if (secsym_tbm_surface_unmap(im->tex->pt->dyn.buffer))
                             ERR("tbm_surface_unmap failed!");
                        }
                      else if (im->gc->shared->info.sec_image_map)
                        {
                           void *disp = egl_display_get(engine);
                           secsym_eglUnmapImageSEC(disp, im->tex->pt->dyn.img, EGL_MAP_GL_TEXTURE_DEVICE_CPU_SEC);
                        }
                   }
#endif
               }

             return image;
          }
        im2 = eng_image_new_from_data(engine, im->w, im->h, image_data,
                                      eng_image_alpha_get(engine, image),
                                      eng_image_colorspace_get(engine, 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:
      case EVAS_COLORSPACE_AGRY88:
      case EVAS_COLORSPACE_GRY8:
         if ((!im->im) || (image_data != im->im->image.data))
           {
              im2 = eng_image_new_from_data(engine, im->w, im->h, image_data,
                                            eng_image_alpha_get(engine, image),
                                            eng_image_colorspace_get(engine, image));
              if (!im2) return im;
              evas_gl_common_image_free(im);
              im = im2;
           }
         evas_gl_common_image_dirty(im, 0, 0, 0, 0);
         break;
      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:
         if (image_data != im->cs.data)
           {
              if (im->cs.data)
                {
                   if (!im->cs.no_free) free(im->cs.data);
                }
              im->cs.data = image_data;
           }
         evas_gl_common_image_dirty(im, 0, 0, 0, 0);
         evas_gl_common_image_update(im->gc, im);
         break;
      default:
         ERR("colorspace %d is not supported here", im->cs.space);
         break;
     }
   return im;
}

static void *
eng_image_orient_set(void *engine, void *image, Evas_Image_Orient orient)
{
   Evas_GL_Image *im;
   Evas_GL_Image *im_new;

   if (!image) return NULL;
   im = image;
   if (im->orient == orient) return image;

   gl_generic_window_find(engine);

   evas_gl_common_image_update(im->gc, im);

   im_new = evas_gl_common_image_new_from_rgbaimage(im->gc, im->im, &im->load_opts, NULL);
   if (!im_new) return im;

   im_new->load_opts = im->load_opts;
   im_new->scaled = im->scaled;
   im_new->scale_hint = im->scale_hint;
   im_new->content_hint = im->content_hint;
   im_new->csize = im->csize;
   im_new->alpha = im->alpha;
   im_new->tex_only = im->tex_only;
   im_new->locked = im->locked;
   im_new->direct = im->direct;
   im_new->cached = EINA_FALSE;

   im_new->orient = orient;
   if (im->tex)
     {
        im_new->tex = im->tex;
        im_new->tex->references++;
        im_new->tex->pt->references++;
     }

   evas_gl_common_image_free(im);
   return im_new;
}

static Evas_Image_Orient
eng_image_orient_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *im = image;

   if (!im) return EVAS_IMAGE_ORIENT_NONE;
   return im->orient;
}

static void
eng_image_data_preload_request(void *engine EINA_UNUSED, void *image, const Eo *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, evas_gl_common_image_preload_done, gim);
}

static void
eng_image_data_preload_cancel(void *engine EINA_UNUSED, void *image, const Eo *target, Eina_Bool force)
{
   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_gl_common_image_preload_unwatch(gim);
   evas_cache_image_preload_cancel(&im->cache_entry, target, force);
//   if (gim->tex) evas_gl_preload_target_unregister(gim->tex, (Eo*) target);
}

static Eina_Bool
eng_image_draw(void *eng, 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, Eina_Bool do_async EINA_UNUSED)
{
   Render_Engine_GL_Generic *engine = eng;
   Evas_Engine_GL_Context *gl_context;
   Render_Output_GL_Generic *re = data;
   Evas_GL_Image *im = image;
   Evas_Native_Surface *n;

   if (!im) return EINA_FALSE;

   n = im->native.data;

   gl_context = gl_generic_context_get(re, 1);

   if (eng_gl_image_direct_get(re, image))
     {
        void *direct_surface = NULL;

        gl_context->dc = context;
        if ((gl_context->master_clip.enabled) &&
            (gl_context->master_clip.w > 0) &&
            (gl_context->master_clip.h > 0))
          {
             // Pass the preserve flag info the evas_gl
             evgl_direct_partial_info_set(gl_context->preserve_bit);
          }

        if (n->type == EVAS_NATIVE_SURFACE_EVASGL)
          direct_surface = n->data.evasgl.surface;
        else
          {
             ERR("This native surface type is not supported for direct rendering");
             return EINA_FALSE;
          }

        // Set necessary info for direct rendering
        evgl_direct_info_set(gl_context->w,
                             gl_context->h,
                             gl_context->rot,
                             dst_x, dst_y, dst_w, dst_h,
                             gl_context->dc->clip.x,
                             gl_context->dc->clip.y,
                             gl_context->dc->clip.w,
                             gl_context->dc->clip.h,
                             gl_context->dc->render_op,
                             direct_surface);

        // Call pixel get function
        evgl_get_pixels_pre();
        engine->func.get_pixels(engine->func.get_pixels_data, engine->func.obj);
        evgl_get_pixels_post();

        // Call end tile if it's being used
        if ((gl_context->master_clip.enabled) &&
            (gl_context->master_clip.w > 0) &&
            (gl_context->master_clip.h > 0))
          {
             evgl_direct_partial_render_end();
             evgl_direct_partial_info_clear();
             gl_context->preserve_bit = GL_COLOR_BUFFER_BIT0_QCOM;
          }

        // Reset direct rendering info
        evgl_direct_info_clear();
     }
   else
     {
        evas_gl_common_context_target_surface_set(gl_context, surface);
        gl_context->dc = context;
        evas_gl_common_image_draw(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 *engine 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 *engine 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 *engine EINA_UNUSED, void *data, void *context, void *surface, void *image,
                   RGBA_Map *m, int smooth, int level, Eina_Bool do_async EINA_UNUSED)
{
   Evas_Engine_GL_Context *gl_context;
   Evas_GL_Image *gim = image;

   if (!image) return EINA_FALSE;
   gl_context = gl_generic_context_get(data, 1);
   evas_gl_common_context_target_surface_set(gl_context, surface);
   gl_context->dc = context;

   if (!gl_context->msaa &&
       (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(engine, data, context, surface, image,
                       0, 0, gim->w, gim->h, dx, dy, dw, dh, smooth, do_async);
     }
   else
     {
        evas_gl_common_image_map_draw(gl_context, image, m->count, &m->pts[0],
                                      smooth, level);
     }

   return EINA_FALSE;
}

static void
eng_image_map_clean(void *engine EINA_UNUSED, RGBA_Map *m EINA_UNUSED)
{
}

static void *
eng_image_map_surface_new(void *engine, int w, int h, int alpha)
{
   Evas_Engine_GL_Context *gl_context;

   gl_context = gl_generic_context_find(engine, 1);
   return evas_gl_common_image_surface_new(gl_context, w, h, alpha, EINA_FALSE);
}

void *
eng_image_scaled_update(void *engine EINA_UNUSED, void *scaled, void *image,
                        int dst_w, int dst_h, Eina_Bool smooth,
                        Evas_Colorspace cspace EINA_UNUSED)
{
   return evas_gl_common_image_virtual_scaled_get(scaled, image, dst_w, dst_h, smooth);
}

static void
eng_image_content_hint_set(void *engine, void *image, int hint)
{
   gl_generic_window_find(engine);
   evas_gl_common_image_content_hint_set(image, hint);
}

static void
eng_image_cache_flush(void *engine)
{
   Evas_Engine_GL_Context *gl_context;
   int tmp_size;

   gl_context = gl_generic_context_find(engine, 1);
   if (!gl_context) return;

   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(gl_context);
   evas_common_image_set_cache(tmp_size);
}

static void
eng_image_cache_set(void *engine, int bytes)
{
   Evas_Engine_GL_Context *gl_context;

   gl_context = gl_generic_context_find(engine, 1);

   evas_common_image_set_cache(bytes);
   evas_common_rgba_image_scalecache_size_set(bytes);
   if (gl_context) evas_gl_common_image_cache_flush(gl_context);
}

static int
eng_image_cache_get(void *engine EINA_UNUSED)
{
   return evas_common_image_get_cache();
}

static void
eng_font_cache_flush(void *engine)
{
   int tmp_size;

   gl_generic_window_find(engine);
   tmp_size = evas_common_font_cache_get();
   evas_common_font_cache_set(0);
   evas_common_font_flush();
   evas_common_font_cache_set(tmp_size);
}

static void
eng_font_cache_set(void *engine, int bytes)
{
   gl_generic_window_find(engine);
   evas_common_font_cache_set(bytes);
}

static int
eng_font_cache_get(void *engine)
{
   gl_generic_window_find(engine);
   return evas_common_font_cache_get();
}

static void
eng_image_stride_get(void *engine EINA_UNUSED, void *image, int *stride)
{
   Evas_GL_Image *im = image;

   if ((im->tex) && (im->tex->pt->dyn.img))
     *stride = im->tex->pt->dyn.stride;
   else
     {
        switch (im->cs.space)
          {
           case EVAS_COLORSPACE_ARGB8888:
             *stride = im->w * 4;
             return;
           case EVAS_COLORSPACE_AGRY88:
             *stride = im->w * 2;
             return;
           case EVAS_COLORSPACE_GRY8:
             *stride = im->w * 1;
             return;
           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:
             *stride = im->w * 1;
             return;
             /* the strides below are approximations, since stride doesn't
              * really make sense for ETC & S3TC */
           case EVAS_COLORSPACE_ETC1:
           case EVAS_COLORSPACE_RGB8_ETC2:
           case EVAS_COLORSPACE_RGB_S3TC_DXT1:
           case EVAS_COLORSPACE_RGBA_S3TC_DXT1:
             *stride = (im->w + 2 + 3) / 4 * (8 / 4);
             return;
           case EVAS_COLORSPACE_ETC1_ALPHA:
           case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
           case EVAS_COLORSPACE_RGBA_S3TC_DXT2:
           case EVAS_COLORSPACE_RGBA_S3TC_DXT3:
           case EVAS_COLORSPACE_RGBA_S3TC_DXT4:
           case EVAS_COLORSPACE_RGBA_S3TC_DXT5:
             *stride = (im->w + 2 + 3) / 4 * (16 / 4);
             return;
           default:
             ERR("Requested stride on an invalid format %d", im->cs.space);
             *stride = 0;
             return;
          }
     }
}

static Eina_Bool
eng_font_draw(void *engine EINA_UNUSED, void *data, void *context, void *surface, Evas_Font_Set *font EINA_UNUSED, 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, Eina_Bool do_async EINA_UNUSED)
{
   Evas_Engine_GL_Context *gl_context;

   gl_context = gl_generic_context_get(data, 1);
   evas_gl_common_context_target_surface_set(gl_context, surface);
   gl_context->dc = context;
     {
        if (!gl_context->font_surface)
          gl_context->font_surface = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
        gl_context->font_surface->cache_entry.w = gl_context->shared->w;
        gl_context->font_surface->cache_entry.h = gl_context->shared->h;

        evas_common_draw_context_font_ext_set(context,
                                              gl_context,
                                              evas_gl_font_texture_new,
                                              evas_gl_font_texture_free,
                                              evas_gl_font_texture_draw,
                                              evas_gl_font_image_new,
                                              evas_gl_font_image_free,
                                              evas_gl_font_image_draw);
        evas_common_font_draw_prepare(intl_props);
        evas_common_font_draw(gl_context->font_surface, context, x, y, intl_props->glyphs);
        evas_common_draw_context_font_ext_set(context,
                                              NULL,
                                              NULL,
                                              NULL,
                                              NULL,
                                              NULL,
                                              NULL,
                                              NULL);
     }

   return EINA_FALSE;
}

//--------------------------------//
// Evas GL Related Code
static inline Eina_Bool
evgl_init_do(Render_Engine_GL_Generic *engine,
             Render_Output_GL_Generic *output)
{
   if (engine->evgl_initted) return EINA_TRUE;
   if (!evgl_engine_init(output, output->evgl_funcs))
     return EINA_FALSE;
   engine->current = output;
   engine->evgl_initted = EINA_TRUE;
   return EINA_TRUE;
}

static Render_Output_GL_Generic *
evgl_init(Render_Engine_GL_Generic *engine)
{
   Render_Output_GL_Generic *output = NULL;
   Eina_List *l;

   if (engine->evgl_initted)
     {
        if (engine->current) return engine->current;

        EINA_LIST_FOREACH(engine->software.outputs, l, output)
          if (output->software.ob) return output;

        ERR("Evas_GL backend initializeod, but no window found !");
        return NULL;
     }

   EINA_LIST_FOREACH(engine->software.outputs, l, output)
     {
        if (!output->software.ob) continue;
        if (evgl_init_do(engine, output))
          return output;
     }

   return NULL;
}

#define EVGLINIT(_ret) Render_Output_GL_Generic *re; if ((re = evgl_init(engine)) == NULL) return _ret

static Eina_Bool
eng_gl_supports_evas_gl(void *engine EINA_UNUSED)
{
   // Evas GL should always work... But let's do a full init anyway.
   EVGLINIT(EINA_FALSE);
   return EINA_TRUE;
}

static void *
eng_gl_output_set(void *eng, void *output)
{
   Render_Engine_GL_Generic *engine = eng;
   Render_Output_GL_Generic *previous = engine->current;

   engine->current = output;

   return previous;
}

static void *
eng_gl_surface_create(void *engine, void *config, int w, int h)
{
   Evas_GL_Config *cfg = (Evas_GL_Config *)config;

   EVGLINIT(NULL);
   return evgl_surface_create(re, cfg, w, h);
}

static void *
eng_gl_pbuffer_surface_create(void *engine, void *config, int w, int h, const int *attrib_list)
{
   Evas_GL_Config *cfg = (Evas_GL_Config *)config;

   EVGLINIT(NULL);
   return evgl_pbuffer_surface_create(re, cfg, w, h, attrib_list);
}

static int
eng_gl_surface_destroy(void *engine, void *surface)
{
   EVGL_Surface  *sfc = (EVGL_Surface *)surface;
   Render_Engine_GL_Generic *e = engine;

   EVGLINIT(0);
   if (e->current == re) e->current = NULL;
   CONTEXT_STORED_RESET(re, surface);
   return evgl_surface_destroy(re, sfc);
}

static void *
eng_gl_context_create(void *engine, void *share_context, int version,
                      void *(*native_context_get)(void *),
                      void *(*engine_data_get)(void *))
{
   EVGL_Context  *sctx = (EVGL_Context *)share_context;

   EVGLINIT(NULL);
   return evgl_context_create(re, sctx, version, native_context_get, engine_data_get);
}

static int
eng_gl_context_destroy(void *engine, void *context)
{
   EVGL_Context  *ctx = (EVGL_Context *)context;

   EVGLINIT(0);
   return evgl_context_destroy(re, ctx);
}

static int
eng_gl_make_current(void *eng, void *surface, void *context)
{
   Render_Engine_GL_Generic *engine = eng;
   EVGL_Surface  *sfc = (EVGL_Surface *)surface;
   EVGL_Context  *ctx = (EVGL_Context *)context;
   Render_Output_GL_Generic *output;
   int ret = 0;

   if (sfc && ctx && eina_main_loop_is())
     {
        Evas_Engine_GL_Context *gl_context;

        gl_context = gl_generic_context_find(engine, 0);
        if ((gl_context->havestuff) ||
            (gl_context->master_clip.used))
          {
             gl_context = gl_generic_context_find(engine, 1);
             evas_gl_common_context_flush(gl_context);
             if (gl_context->master_clip.used)
                evas_gl_common_context_done(gl_context);
          }
     }

   output = _evgl_output_find(engine);
   if (!output) return ret;

   ret = evgl_make_current(output, sfc, ctx);
   CONTEXT_STORE(output, surface, context);

   return ret;
}

static void *
eng_gl_current_surface_get(void *engine EINA_UNUSED)
{
   EVGL_Context *ctx;

   ctx = evas_gl_common_current_context_get();
   if (!ctx)
     return NULL;

   // Note: We could verify with a call to eglGetCurrentSurface

   return ctx->current_sfc;
}

static int
eng_gl_rotation_angle_get(void *eng)
{
   Render_Engine_GL_Generic *engine = eng;
   Render_Output_GL_Generic *output;

   if (!evgl_engine->funcs->rotation_angle_get) return 0;
   if (!_evgl_direct_enabled()) return 0;

   // It would be better if that this API was called Evas Output
   output = _evgl_output_find(engine);
   if (!output) return 0;

   return evgl_engine->funcs->rotation_angle_get(output);
}

static const char *
eng_gl_string_query(void *engine, int name)
{
   EVGLINIT(NULL);
   return evgl_string_query(name);
}

static void *
eng_gl_proc_address_get(void *engine, const char *name)
{
   EVGLINIT(NULL);
   void *fun = NULL;

   if (!evgl_safe_extension_get(name, &fun))
     {
        DBG("The extension '%s' is not safe to use with Evas GL or is not "
            "supported on this platform.", name);
        return NULL;
     }

   if (fun)
     return fun;

   if (re->evgl_funcs && re->evgl_funcs->proc_address_get)
     return re->evgl_funcs->proc_address_get(name);

   return NULL;
}

static int
eng_gl_native_surface_get(void *engine EINA_UNUSED, void *surface, void *native_surface)
{
   EVGL_Surface  *sfc = (EVGL_Surface *)surface;
   Evas_Native_Surface *ns = (Evas_Native_Surface *)native_surface;

   return evgl_native_surface_get(sfc, ns);
}

static void *
eng_gl_api_get(void *engine, int version)
{
   Render_Output_GL_Generic *output;
   Evas_Engine_GL_Context *gl_context;
   void *ret;
   EVGLINIT(NULL);

   gl_context = gl_generic_context_find(engine, 0);
   if (!gl_context)
     {
        ERR("Invalid context!");
        return NULL;
     }
   if ((version == EVAS_GL_GLES_3_X) && (gl_context->gles_version != EVAS_GL_GLES_3_X))
     {
        ERR("Version not supported!");
        return NULL;
     }

   output = _evgl_output_find(engine);
   ret = evgl_api_get(output, version, EINA_TRUE);

   //Disable GLES3 support if symbols not present
   if ((!ret) && (version == EVAS_GL_GLES_3_X))
     gl_context->gles_version--;

   return ret;
}


static void
eng_gl_direct_override_get(void *engine, Eina_Bool *override, Eina_Bool *force_off)
{
   EVGLINIT();
   evgl_direct_override_get(override, force_off);
}

static Eina_Bool
eng_gl_surface_direct_renderable_get(void *eng, void *output, Evas_Native_Surface *ns, Eina_Bool *override, void *surface)
{
   Render_Engine_GL_Generic *engine = eng;
   Render_Output_GL_Generic *re = output;
   Eina_Bool direct_render, client_side_rotation;
   Evas_Engine_GL_Context *gl_context;
   Evas_GL_Image *sfc = surface;

   if (!re) return EINA_FALSE;
   if (!evgl_init_do(engine, re))
     return EINA_FALSE;
   if (!ns) return EINA_FALSE;
   if (!evgl_native_surface_direct_opts_get(ns, &direct_render, &client_side_rotation, override))
     return EINA_FALSE;

   if (!direct_render)
     return EINA_FALSE;

   if ((re->software.outbuf_get_rot(re->software.ob) != 0) && (!client_side_rotation))
     return EINA_FALSE;

   gl_context = gl_generic_context_get(re, 0);
   if (gl_context->def_surface != sfc)
     return EINA_FALSE;

   return EINA_TRUE;
}

static void
eng_gl_get_pixels_set(void *eng, void *get_pixels, void *get_pixels_data, void *obj)
{
   Render_Engine_GL_Generic *engine = eng;

   engine->func.get_pixels = get_pixels;
   engine->func.get_pixels_data = get_pixels_data;
   engine->func.obj = (Evas_Object*)obj;
}

static void
eng_gl_get_pixels_pre(void *e, void *o)
{
   Render_Engine_GL_Generic *engine = e;
   Render_Output_GL_Generic *output = o;

   if (!evgl_init_do(engine, output))
     return ;
   evgl_get_pixels_pre();
}

static void
eng_gl_get_pixels_post(void *e EINA_UNUSED, void *o EINA_UNUSED)
{
   evgl_get_pixels_post();
}

static Eina_Bool
eng_gl_surface_lock(void *engine EINA_UNUSED, void *surface)
{
   Evas_GL_Image *im = surface;

   if (!im || !im->tex || !im->tex->pt)
     {
        ERR("Can not lock image that is not a surface!");
        return EINA_FALSE;
     }

   evas_gl_common_context_flush(im->gc);
   im->locked = EINA_TRUE;
   return EINA_TRUE;
}

static Eina_Bool
eng_gl_surface_unlock(void *engine EINA_UNUSED, void *surface)
{
   Evas_GL_Image *im = surface;

   im->locked = EINA_FALSE;
   return EINA_TRUE;
}

static Eina_Bool
eng_gl_surface_read_pixels(void *engine EINA_UNUSED, void *surface,
                           int x, int y, int w, int h,
                           Evas_Colorspace cspace, void *pixels)
{
   Evas_GL_Image *im = surface;
   GLint fmt = GL_BGRA, fbo = 0;
   int done = 0;

   EINA_SAFETY_ON_NULL_RETURN_VAL(pixels, EINA_FALSE);

   if (!im->locked)
     {
        // For now, this is useless, but let's force clients to lock :)
        CRI("The surface must be locked before reading its pixels!");
        return EINA_FALSE;
     }

   if (cspace != EVAS_COLORSPACE_ARGB8888)
     {
        ERR("Conversion to colorspace %d is not supported!", (int) cspace);
        return EINA_FALSE;
     }

   /* Since this is an FBO, the pixels are already in the right Y order.
    * But some devices don't support GL_BGRA, so we still need to convert.
    */

   glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
   if (fbo != (GLint) im->tex->pt->fb)
     glsym_glBindFramebuffer(GL_FRAMEBUFFER, im->tex->pt->fb);
   glPixelStorei(GL_PACK_ALIGNMENT, 4);

   // With GLX we will try to read BGRA even if the driver reports RGBA
#if defined(GL_GLES) && defined(GL_IMPLEMENTATION_COLOR_READ_FORMAT)
   glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &fmt);
#endif

   if ((im->tex->pt->format == GL_BGRA) && (fmt == GL_BGRA))
     {
        glReadPixels(x, y, w, h, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
        done = (glGetError() == GL_NO_ERROR);
     }

   if (!done)
     {
        DATA32 *ptr = pixels;
        int k;

        glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
        for (k = w * h; k; --k)
          {
             const DATA32 v = *ptr;
             *ptr++ = (v & 0xFF00FF00)
                   | ((v & 0x00FF0000) >> 16)
                   | ((v & 0x000000FF) << 16);
          }
     }

   if (fbo != (GLint) im->tex->pt->fb)
     glsym_glBindFramebuffer(GL_FRAMEBUFFER, fbo);

   return EINA_TRUE;
}

static Eina_Bool
eng_gl_surface_query(void *eng, void *surface, int attr, void *value)
{
   Render_Engine_GL_Generic *engine = eng;
   Render_Output_GL_Generic *re;
   EVGL_Surface  *sfc = surface;

   re = _evgl_output_find(engine);
   if (!re) return EINA_FALSE;

#ifdef GL_GLES
   if (sfc->pbuffer.is_pbuffer)
     {
        // This is a real EGL surface, let's just call EGL directly
        int val;
        Eina_Bool ok;
        void *disp;

        disp = egl_display_get(engine);
        ok = eglQuerySurface(disp, sfc->pbuffer.native_surface, attr, &val);
        if (!ok) return EINA_FALSE;
        switch (attr)
          {
           case EVAS_GL_TEXTURE_FORMAT:
             if (val == EGL_TEXTURE_RGB)
               *((int *) value) = EVAS_GL_RGB_888;
             else if (val == EGL_TEXTURE_RGBA)
               *((int *) value) = EVAS_GL_RGBA_8888;
             else // if (val == EGL_NO_TEXTURE)
               *((int *) value) = EVAS_GL_NO_FBO;
             break;
           case EVAS_GL_TEXTURE_TARGET:
             if (val == EGL_TEXTURE_2D)
               *((int *) value) = val;
             else
               *((int *) value) = 0;
             break;
           default:
             *((int *) value) = val;
             break;
          }
        return EINA_TRUE;
     }
   else
     {
        // Since this is a fake surface (shared with evas), we must filter the
        // queries...
        switch (attr)
          {
           // TODO: Add support for whole config get
           /*
           case EVAS_GL_CONFIG_ID:
             *((int *) value) = sfc->cfg_index;
             return EINA_TRUE;
             */
           case EVAS_GL_WIDTH:
             *((int *) value) = sfc->w;
             return EINA_TRUE;
           case EVAS_GL_HEIGHT:
             *((int *) value) = sfc->h;
             return EINA_TRUE;
           case EVAS_GL_TEXTURE_FORMAT:
             // FIXME: Check the possible color formats
             if (sfc->color_buf)
               {
                  if ((sfc->color_fmt == GL_RGBA) || (sfc->color_fmt == GL_BGRA))
                    {
                       *((Evas_GL_Color_Format *) value) = EVAS_GL_RGBA_8888;
                       return EINA_TRUE;
                    }
                  else if (sfc->color_fmt == GL_RGB)
                    {
                       *((Evas_GL_Color_Format *) value) = EVAS_GL_RGB_888;
                       return EINA_TRUE;
                    }
               }
             *((Evas_GL_Color_Format *) value) = EVAS_GL_NO_FBO;
             return EINA_TRUE;
           case EVAS_GL_TEXTURE_TARGET:
             if (sfc->color_buf)
               *((int *) value) = EVAS_GL_TEXTURE_2D;
             else
               *((int *) value) = 0;
             return EINA_TRUE;
           // TODO: Add support for this:
           /*
           case EVAS_GL_MULTISAMPLE_RESOLVE:
             *((int *) value) = sfc->msaa_samples;
             return EINA_TRUE;
             */
           // TODO: Add support for mipmaps
           /*
           case EVAS_GL_MIPMAP_TEXTURE:
           case EVAS_GL_MIPMAP_LEVEL:
             return eglQuerySurface(re->win->egl_disp, re->win->egl_surface,
                                    attr, (int *) value);
             */
           default: break;
          }
        evas_gl_common_error_set(EVAS_GL_BAD_ATTRIBUTE);
        return EINA_FALSE;
     }
#else
   (void) re; (void) sfc; (void) attr; (void) value;
   ERR("GLX support for surface_query is not implemented!");
   return EINA_FALSE;
#endif
}

static int
eng_gl_image_direct_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *im = image;
   if (!im) return EINA_FALSE;
   return im->direct;
}

static void
eng_gl_image_direct_set(void *eng, void *image, Eina_Bool direct)
{
   Render_Engine_GL_Generic *engine = eng;
   Evas_GL_Image *im = image;

   if (!im) return;
   if (im->native.data && direct && engine->func.get_pixels)
     im->direct = EINA_TRUE;
   else
     im->direct = EINA_FALSE;
}

//--------------------------------//

static int
eng_image_load_error_get(void *engine 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 Eina_Bool
eng_image_animated_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *gim = image;
   Image_Entry *im;

   if (!gim) return EINA_FALSE;
   im = (Image_Entry *)gim->im;
   if (!im) return EINA_FALSE;

   return im->animated.animated;
}

static int
eng_image_animated_frame_count_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *gim = image;
   Image_Entry *im;

   if (!gim) return -1;
   im = (Image_Entry *)gim->im;
   if (!im) return -1;

   if (!im->animated.animated) return -1;
   return im->animated.frame_count;
}

static Evas_Image_Animated_Loop_Hint
eng_image_animated_loop_type_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *gim = image;
   Image_Entry *im;

   if (!gim) return EVAS_IMAGE_ANIMATED_HINT_NONE;
   im = (Image_Entry *)gim->im;
   if (!im) return EVAS_IMAGE_ANIMATED_HINT_NONE;

   if (!im->animated.animated) return EVAS_IMAGE_ANIMATED_HINT_NONE;
   return im->animated.loop_hint;
}

static int
eng_image_animated_loop_count_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *gim = image;
   Image_Entry *im;

   if (!gim) return -1;
   im = (Image_Entry *)gim->im;
   if (!im) return -1;

   if (!im->animated.animated) return -1;
   return im->animated.loop_count;
}

static double
eng_image_animated_frame_duration_get(void *engine EINA_UNUSED, void *image, int start_frame, int frame_num)
{
   Evas_GL_Image *gim = image;
   Image_Entry *im;

   if (!gim) return -1;
   im = (Image_Entry *)gim->im;
   if (!im) return -1;

   if (!im->animated.animated) return -1;
   return evas_common_load_rgba_image_frame_duration_from_file(im, start_frame, frame_num);
}

static Eina_Bool
eng_image_animated_frame_set(void *engine EINA_UNUSED, void *image, int frame_index)
{
   Evas_GL_Image *gim = image;
   Image_Entry *im;

   if (!gim) return EINA_FALSE;
   im = (Image_Entry *)gim->im;
   if (!im) return EINA_FALSE;

   if (!im->animated.animated) return EINA_FALSE;
   if (im->animated.cur_frame == frame_index) return EINA_FALSE;

   im->animated.cur_frame = frame_index;
   return EINA_TRUE;
}

static Eina_Bool
eng_image_can_region_get(void *engine EINA_UNUSED, void *image)
{
   Evas_GL_Image *gim = image;
   Image_Entry *im;

   if (!gim) return EINA_FALSE;
   im = (Image_Entry *)gim->im;
   if (!im) return EINA_FALSE;
   return ((Evas_Image_Load_Func*) im->info.loader)->do_region;
}


static void
eng_image_max_size_get(void *engine, int *maxw, int *maxh)
{
   Evas_Engine_GL_Context *gl_context;

   gl_context = gl_generic_context_find(engine, 0);
   if (maxw) *maxw = gl_context->shared->info.max_texture_size;
   if (maxh) *maxh = gl_context->shared->info.max_texture_size;
}

static Eina_Bool
eng_pixel_alpha_get(void *image, int x, int y, DATA8 *alpha, int src_region_x, int src_region_y, int src_region_w, int src_region_h, int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h)
{
   Evas_GL_Image *im = image;
   int px, py, dx, dy, sx, sy, src_w, src_h;
   double scale_w, scale_h;

   if (!im) return EINA_FALSE;

   if ((dst_region_x > x) || (x >= (dst_region_x + dst_region_w)) ||
       (dst_region_y > y) || (y >= (dst_region_y + dst_region_h)))
     {
        *alpha = 0;
        return EINA_FALSE;
     }

   evas_gl_common_image_alloc_ensure(im);
   if (!im->im) return EINA_FALSE;

   src_w = im->im->cache_entry.w;
   src_h = im->im->cache_entry.h;
   if ((src_w == 0) || (src_h == 0))
     {
        *alpha = 0;
        return EINA_TRUE;
     }

   EINA_SAFETY_ON_TRUE_GOTO(src_region_x < 0, error_oob);
   EINA_SAFETY_ON_TRUE_GOTO(src_region_y < 0, error_oob);
   EINA_SAFETY_ON_TRUE_GOTO(src_region_x + src_region_w > src_w, error_oob);
   EINA_SAFETY_ON_TRUE_GOTO(src_region_y + src_region_h > src_h, error_oob);

   scale_w = (double)dst_region_w / (double)src_region_w;
   scale_h = (double)dst_region_h / (double)src_region_h;

   /* point at destination */
   dx = x - dst_region_x;
   dy = y - dst_region_y;

   /* point at source */
   sx = dx / scale_w;
   sy = dy / scale_h;

   /* pixel point (translated) */
   px = src_region_x + sx;
   py = src_region_y + sy;
   EINA_SAFETY_ON_TRUE_GOTO(px >= src_w, error_oob);
   EINA_SAFETY_ON_TRUE_GOTO(py >= src_h, error_oob);

   switch (im->im->cache_entry.space)
     {
     case EVAS_COLORSPACE_ARGB8888:
       {
          DATA32 *pixel;

          evas_cache_image_load_data(&im->im->cache_entry);
          if (!im->im->cache_entry.flags.loaded)
            {
               ERR("im %p has no pixels loaded yet", im);
               return EINA_FALSE;
            }

          pixel = im->im->image.data;
          pixel += ((py * src_w) + px);
          *alpha = ((*pixel) >> 24) & 0xff;
       }
       break;

     default:
        ERR("Colorspace %d not supported.", im->im->cache_entry.space);
        *alpha = 0;
     }

   return EINA_TRUE;

 error_oob:
   ERR("Invalid region src=(%d, %d, %d, %d), dst=(%d, %d, %d, %d), image=%dx%d",
       src_region_x, src_region_y, src_region_w, src_region_h,
       dst_region_x, dst_region_y, dst_region_w, dst_region_h,
       src_w, src_h);
   *alpha = 0;
   return EINA_TRUE;
}

static void
eng_context_flush(void *engine)
{
   Evas_Engine_GL_Context *gl_context;

   gl_context = gl_generic_context_find(engine, 1);

   if ((gl_context->havestuff) ||
     (gl_context->master_clip.used))
   {
      evas_gl_common_context_flush(gl_context);
      if (gl_context->master_clip.used)
         evas_gl_common_context_done(gl_context);
   }
}

static void
eng_context_clip_image_unset(void *engine EINA_UNUSED, void *context)
{
   RGBA_Draw_Context *ctx = context;
   Evas_GL_Image *im = ctx->clip.mask;

   evas_gl_common_image_free(im);

   ctx->clip.mask = NULL;
}

static void
eng_context_clip_image_set(void *engine, void *context, void *surface, int x, int y,
                           Evas_Public_Data *evas, Eina_Bool do_async)
{
   RGBA_Draw_Context *ctx = context;
   Evas_GL_Image *im = surface;
   Eina_Bool noinc = EINA_FALSE;

   if (ctx->clip.mask)
     {
        if (ctx->clip.mask != surface)
          eng_context_clip_image_unset(engine, context);
        else
          noinc = EINA_TRUE;
     }

   ctx->clip.mask = surface;
   ctx->clip.mask_x = x;
   ctx->clip.mask_y = y;

   // useless in gl since the engines are sync only
   ctx->clip.evas = evas;
   ctx->clip.async = do_async;

   if (im)
     {
        if (!noinc) evas_gl_common_image_ref(im);
        RECTS_CLIP_TO_RECT(ctx->clip.x, ctx->clip.y, ctx->clip.w, ctx->clip.h,
                           x, y, im->w, im->h);
     }
}

static void
eng_context_clip_image_get(void *engine EINA_UNUSED, void *context, void **ie, int *x, int *y)
{
   RGBA_Draw_Context *ctx = context;

   if (ie)
     {
        Evas_GL_Image *im = ctx->clip.mask;

        *ie = im;
        if (im) evas_gl_common_image_ref(im);
     }
   if (x) *x = ctx->clip.mask_x;
   if (y) *y = ctx->clip.mask_y;
}

static void
eng_context_free(void *engine, void *context)
{
   RGBA_Draw_Context *ctx = context;

   if (!ctx) return;
   if (ctx->clip.mask)
     eng_context_clip_image_unset(engine, context);
   evas_common_draw_context_free(context);
}

static void *
eng_context_dup(void *engine EINA_UNUSED, void *context)
{
   RGBA_Draw_Context *ctx;

   ctx = evas_common_draw_context_dup(context);
   if (ctx->clip.mask)
     evas_gl_common_image_ref(ctx->clip.mask);

   return ctx;
}

static void
eng_context_3d_use(void *output)
{
   Render_Output_GL_Generic *re = output;

   if (!re->context_3d)
     re->context_3d = re->window_gl_context_new(re->software.ob);
   if (re->context_3d) re->window_gl_context_use(re->context_3d);
}

static E3D_Renderer *
eng_renderer_3d_get(void *output)
{
   Render_Output_GL_Generic *re = output;

   if (!re->renderer_3d)
     re->renderer_3d = e3d_renderer_new();
   return re->renderer_3d;
}

static void *
eng_drawable_new(void *engine, int w, int h, int alpha)
{
   eng_context_3d_use(gl_generic_output_find(engine));
#ifdef GL_GLES
   return e3d_drawable_new(w, h, alpha, GL_DEPTH_STENCIL_OES, GL_NONE);
#else
   return e3d_drawable_new(w, h, alpha, GL_DEPTH24_STENCIL8, GL_NONE);
#endif
}

static void
eng_drawable_free(void *engine, void *drawable)
{
   eng_context_3d_use(gl_generic_output_find(engine));
   e3d_drawable_free(drawable);
}

static void
eng_drawable_size_get(void *engine EINA_UNUSED, void *drawable, int *w, int *h)
{
   e3d_drawable_size_get((E3D_Drawable *)drawable, w, h);
}

static void *
eng_image_drawable_set(void *engine, void *image, void *drawable)
{
   E3D_Drawable *d = drawable;
   Evas_Native_Surface ns;
   int w, h;

   ns.type = EVAS_NATIVE_SURFACE_OPENGL;
   ns.data.opengl.texture_id = e3d_drawable_texture_id_get(d);
   ns.data.opengl.framebuffer_id = 0;
   ns.data.opengl.internal_format = e3d_drawable_format_get(d);
   ns.data.opengl.format = e3d_drawable_format_get(d);
   ns.data.opengl.x = 0;
   ns.data.opengl.y = 0;
   e3d_drawable_size_get(d, &w, &h);
   ns.data.opengl.w = w;
   ns.data.opengl.h = h;

   return eng_image_native_set(engine, image, &ns);
}

static void
eng_drawable_scene_render(void *engine, void *data, void *drawable, void *scene_data)
{
   Evas_Engine_GL_Context *gl_context;
   E3D_Renderer *renderer = NULL;

   gl_context = gl_generic_context_get(data, 1);
   evas_gl_common_context_flush(gl_context);

   eng_context_3d_use(gl_generic_output_find(engine));
   renderer = eng_renderer_3d_get(data);
   e3d_drawable_scene_render(drawable, renderer, scene_data);
}

static int
eng_drawable_texture_target_id_get(void *drawable)
{
   return e3d_drawable_texture_id_get((E3D_Drawable *)drawable);
}

static int
eng_drawable_texture_color_pick_id_get(void *drawable)
{
   return e3d_drawable_texture_color_pick_id_get((E3D_Drawable *)drawable);
}

static void
eng_drawable_texture_pixel_color_get(GLuint tex EINA_UNUSED, int x, int y,
                                     Evas_Color *color, void *drawable)
{
   return e3d_drawable_texture_pixel_color_get(tex, x, y, color, drawable);
}

static Eina_Bool
eng_drawable_scene_render_to_texture(void *engine, void *drawable, void *scene_data)
{
   Evas_Engine_GL_Context *gl_context;
   E3D_Renderer *renderer = NULL;

   gl_context = gl_generic_context_get(engine, 1);
   evas_gl_common_context_flush(gl_context);

   eng_context_3d_use(gl_generic_output_find(engine));
   renderer = eng_renderer_3d_get(engine);

   return e3d_drawable_scene_render_to_texture((E3D_Drawable *)drawable, renderer, scene_data);
}

static void
eng_drawable_texture_rendered_pixels_get(GLuint tex EINA_UNUSED, int x, int y,
                                         int w, int h, void *drawable EINA_UNUSED, void *engine)
{
   e3d_drawable_texture_rendered_pixels_get(tex, x, y, w, h, drawable, engine);
}
static void *
eng_texture_new(void *engine EINA_UNUSED, Eina_Bool use_atlas)
{
   return e3d_texture_new(use_atlas);
}

static void
eng_texture_free(void *engine EINA_UNUSED, void *texture)
{
   e3d_texture_free((E3D_Texture *)texture);
}

static void
eng_texture_size_get(void *engine EINA_UNUSED, void *texture, int *w, int *h)
{
   e3d_texture_size_get((E3D_Texture *)texture, w, h);
}

static void
eng_texture_wrap_set(void *engine EINA_UNUSED, void *texture,
                     Evas_Canvas3D_Wrap_Mode s, Evas_Canvas3D_Wrap_Mode t)
{
   e3d_texture_wrap_set((E3D_Texture *)texture, s, t);
}

static void
eng_texture_wrap_get(void *engine EINA_UNUSED, void *texture,
                     Evas_Canvas3D_Wrap_Mode *s, Evas_Canvas3D_Wrap_Mode *t)
{
   e3d_texture_wrap_get((E3D_Texture *)texture, s, t);
}

static void
eng_texture_filter_set(void *engine EINA_UNUSED, void *texture,
                       Evas_Canvas3D_Texture_Filter min, Evas_Canvas3D_Texture_Filter mag)
{
   e3d_texture_filter_set((E3D_Texture *)texture, min, mag);
}

static void
eng_texture_filter_get(void *engine EINA_UNUSED, void *texture,
                       Evas_Canvas3D_Texture_Filter *min, Evas_Canvas3D_Texture_Filter *mag)
{
   e3d_texture_filter_get((E3D_Texture *)texture, min, mag);
}

static void
eng_texture_image_set(void *engine, void *texture, void *image)
{
   Evas_Engine_GL_Context *gl_context;

   gl_context = gl_generic_context_find(engine, 1);

   e3d_texture_set(gl_context, (E3D_Texture *)texture, (Evas_GL_Image *)image);
}

static void *
eng_texture_image_get(void *engine EINA_UNUSED, void *texture)
{
   return e3d_texture_get((E3D_Texture *)texture);
}

static Eina_Bool use_cairo = EINA_FALSE;
static Eina_Bool use_gl = EINA_FALSE;

static Ector_Surface *
eng_ector_create(void *engine EINA_UNUSED)
{
   Ector_Surface *ector;
   const char *ector_backend;
   ector_backend = getenv("ECTOR_BACKEND");
   efl_domain_current_push(EFL_ID_DOMAIN_SHARED);
   if (ector_backend && !strcasecmp(ector_backend, "default"))
     {
        ector = efl_add_ref(ECTOR_SOFTWARE_SURFACE_CLASS, NULL);
     }
   else if (ector_backend && !strcasecmp(ector_backend, "experimental"))
     {
        ector = efl_add_ref(ECTOR_GL_SURFACE_CLASS, NULL);
        use_gl = EINA_TRUE;
     }
   else
     {
        ector = efl_add_ref(ECTOR_CAIRO_SOFTWARE_SURFACE_CLASS, NULL);
        use_cairo = EINA_TRUE;
     }
   efl_domain_current_pop();
   return ector;
}

static void
eng_ector_destroy(void *engine EINA_UNUSED, Ector_Surface *ector)
{
   if (ector) efl_unref(ector);
}

static Ector_Buffer *
eng_ector_buffer_wrap(void *engine EINA_UNUSED, Evas *evas, void *engine_image)
{
   Evas_GL_Image *im = engine_image;

   EINA_SAFETY_ON_NULL_RETURN_VAL(engine_image, NULL);

   return efl_add(EVAS_ECTOR_GL_IMAGE_BUFFER_CLASS, evas,
                  evas_ector_buffer_engine_image_set(efl_added, evas, im));
}

//FIXME: Currently Ector GL doens't work properly. Use software instead.
#include "../software_generic/evas_ector_software.h"

static Ector_Buffer *
eng_ector_buffer_new(void *engine, Evas *evas, int w, int h,
                     Efl_Gfx_Colorspace cspace, Ector_Buffer_Flag flags)
{
   /* FIXME: This condition is tricky, this buffer could be used for masking
    * buffer by vector, Require to use software drawing.
    */
   if (flags != (ECTOR_BUFFER_FLAG_DRAWABLE | ECTOR_BUFFER_FLAG_CPU_READABLE | ECTOR_BUFFER_FLAG_CPU_WRITABLE))
      {
         return efl_add(EVAS_ECTOR_GL_BUFFER_CLASS, evas,
                        evas_ector_gl_buffer_prepare(efl_added, engine, w, h, cspace, flags));
      }
   else
     {
        Ector_Buffer *buf;
        Image_Entry *ie;
        void *pixels;
        int pxs;

        if (cspace == EFL_GFX_COLORSPACE_ARGB8888)
          pxs = 4;
        else if (cspace == EFL_GFX_COLORSPACE_GRY8)
          pxs = 1;
        else
          {
             ERR("Unsupported colorspace: %d", (int) cspace);
             return NULL;
          }

        // alloc buffer
        ie = evas_cache_image_copied_data(evas_common_image_cache_get(), w, h,
                                          NULL, EINA_TRUE, cspace);
        if (!ie) return NULL;
        pixels = ((RGBA_Image *) ie)->image.data;
        memset(pixels, 0, w * h * pxs);

        if (!efl_domain_current_push(EFL_ID_DOMAIN_SHARED))
          {
             evas_cache_image_drop(ie);
             return NULL;
          }

        buf = efl_add_ref(EVAS_ECTOR_SOFTWARE_BUFFER_CLASS, NULL,
                          evas_ector_buffer_engine_image_set(efl_added, engine, ie));
        efl_domain_current_pop();

        evas_cache_image_drop(ie);

        return buf;
     }
}

static void
eng_ector_renderer_draw(void *engine EINA_UNUSED, void *surface,