LCOV - code coverage report
Current view: top level - compositor - compositor_2d.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 490 735 66.7 %
Date: 2021-04-29 23:48:07 Functions: 23 23 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2020
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Compositor sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : 
      28             : #include "visual_manager.h"
      29             : #include "nodes_stacks.h"
      30             : #include <gpac/options.h>
      31             : #include "texturing.h"
      32             : 
      33             : #include "gl_inc.h"
      34             : 
      35             : 
      36             : #ifndef GPAC_DISABLE_3D
      37        1769 : void compositor_2d_hybgl_clear_surface(GF_VisualManager *visual, GF_IRect *rc, u32 BackColor, u32 is_offscreen_clear)
      38             : {
      39             :         SFColor rgb;
      40        1769 :         Fixed alpha = INT2FIX( GF_COL_A(BackColor) )/255;
      41        1769 :         if (!visual->is_attached) return;
      42             : 
      43        1769 :         if (!BackColor && !visual->offscreen && !is_offscreen_clear) {
      44         571 :                 if ( !(visual->compositor->init_flags & GF_TERM_WINDOW_TRANSPARENT)) {
      45         571 :                         BackColor = visual->compositor->back_color & 0x00FFFFFF;
      46             :                 }
      47             :         }
      48        1769 :         if (is_offscreen_clear) {
      49         996 :                 gf_evg_surface_clear(visual->raster_surface, rc, BackColor);
      50             :                 //if we clear the canvas with non-0 alpha, remember the area cleared in case we have to erase it later (overlapping bitmap)
      51             :                 //if we clear dirty area of the canvas, remember the area to force gl flush 
      52         996 :                 if (GF_COL_A(BackColor) || (is_offscreen_clear==2))
      53             :                 {
      54         592 :                         ra_union_rect(&visual->hybgl_drawn, rc);
      55             :                 }
      56             :         } else {
      57         773 :                 rgb.red = INT2FIX( GF_COL_R(BackColor) ) / 255;
      58         773 :                 rgb.green = INT2FIX( GF_COL_G(BackColor) )/255;
      59         773 :                 rgb.blue = INT2FIX( GF_COL_B(BackColor) )/255;
      60         773 :                 visual_3d_clear(visual, rgb , alpha);
      61             :         }
      62             : }
      63             : 
      64             : 
      65        1963 : void compositor_2d_hybgl_flush_video(GF_Compositor *compositor, GF_IRect *area)
      66             : {
      67             :         GF_TraverseState a_tr_state;
      68             : 
      69             :         //check if texture data has changed - if so, mark texture to be updated
      70        1963 :         if (compositor->traverse_state->immediate_draw) {
      71             :                 //nothing drawn, nothing to do
      72         157 :                 if (!compositor->visual->hybgl_drawn.count) {
      73          11 :                         return;
      74             :                 }
      75             :                 //nodes where drawn on canvas, push texture
      76         146 :                 gf_sc_texture_set_data(compositor->hybgl_txh);
      77             :         } else {
      78             :                 //nodes where drawn on canvas, push texture
      79        1806 :                 if (compositor->visual->hybgl_drawn.count) {
      80             :                         //we could actually use texSubImage here, but we would need either to copy the data before pushing it or use current stride which will result in pushing too much data ...
      81        1735 :                         gf_sc_texture_set_data(compositor->hybgl_txh);
      82             :                 }
      83             :         }
      84             :         //if no object drawn since the last flush, no need to draw the texture
      85        1952 :         if (!compositor->visual->nb_objects_on_canvas_since_last_ogl_flush)
      86             :                 goto exit;
      87             : 
      88             :         memset(&a_tr_state, 0, sizeof(GF_TraverseState));
      89        1774 :         a_tr_state.color_mat.identity = 1;
      90        1774 :         a_tr_state.visual = compositor->visual;
      91        1774 :         a_tr_state.camera = &compositor->visual->camera;
      92        1774 :         gf_mx_init(a_tr_state.model_matrix);
      93             : 
      94        1774 :         visual_3d_set_state(compositor->visual, V3D_STATE_LIGHT, GF_FALSE);
      95        1774 :         visual_3d_enable_antialias(compositor->visual, GF_FALSE);
      96        1774 :         gf_sc_texture_set_blend_mode(compositor->hybgl_txh, TX_MODULATE);
      97             :         //visual_3d_set_material_2d_argb(compositor->visual, 0xFFFFFFFF);
      98        1774 :         compositor->visual->has_material_2d = GF_FALSE;
      99        1774 :         a_tr_state.mesh_num_textures = gf_sc_texture_enable(compositor->hybgl_txh, NULL);
     100        1774 :         if (a_tr_state.mesh_num_textures ) {
     101        1774 :                 if (area) {
     102             :                         u32 i;
     103             :                         Fixed umin, umax, vmin, vmax;
     104             :                         SFVec2f size, orig;
     105         740 :                         size.x = INT2FIX(area->width);
     106         740 :                         size.y = INT2FIX(area->height);
     107             : 
     108         740 :                         orig.x = INT2FIX(area->x);
     109         740 :                         orig.y = INT2FIX(area->y);
     110         740 :                         mesh_new_rectangle(compositor->hybgl_mesh, size, &orig, GF_TRUE);
     111             : 
     112         740 :                         orig.x = INT2FIX(area->x) + INT2FIX(compositor->vp_width)/2;
     113         740 :                         orig.y = INT2FIX(compositor->vp_height)/2 - INT2FIX(area->y) + INT2FIX(area->height);
     114             :                         //set our coor texture so that we update only the right part of the canvas
     115         740 :                         umin = gf_divfix(orig.x, INT2FIX(compositor->vp_width));
     116         740 :                         umax = gf_divfix(orig.x+size.x, INT2FIX(compositor->vp_width));
     117         740 :                         vmin = gf_divfix(orig.y-size.y, INT2FIX(compositor->vp_height));
     118         740 :                         vmax = gf_divfix(orig.y, INT2FIX(compositor->vp_height));
     119             : 
     120        3700 :                         for (i=0; i<compositor->hybgl_mesh->v_count; i++) {
     121        2960 :                                 if (compositor->hybgl_mesh->vertices[i].texcoords.x == FIX_ONE) {
     122        1480 :                                         compositor->hybgl_mesh->vertices[i].texcoords.x = umax;
     123             :                                 } else {
     124        1480 :                                         compositor->hybgl_mesh->vertices[i].texcoords.x = umin;
     125             :                                 }
     126        2960 :                                 if (compositor->hybgl_mesh->vertices[i].texcoords.y == FIX_ONE) {
     127        1480 :                                         compositor->hybgl_mesh->vertices[i].texcoords.y = vmax;
     128             :                                 } else {
     129        1480 :                                         compositor->hybgl_mesh->vertices[i].texcoords.y = vmin;
     130             :                                 }
     131             :                         }
     132             :                 }
     133             : 
     134        1774 :                 visual_3d_mesh_paint(&a_tr_state, compositor->hybgl_mesh);
     135        1774 :                 gf_sc_texture_disable(compositor->hybgl_txh);
     136             : 
     137        1774 :                 if (area) {
     138             :                         SFVec2f size;
     139         740 :                         size.x = INT2FIX(compositor->vp_width);
     140         740 :                         size.y = INT2FIX(compositor->vp_height);
     141         740 :                         mesh_new_rectangle(compositor->hybgl_mesh, size, NULL, GF_TRUE);
     142             :                 }
     143             :         }
     144             : 
     145        3164 : exit:
     146             :         //in immediate mode always clear the canvas
     147        1952 :         if (compositor->traverse_state->immediate_draw) {
     148         146 :                 compositor->visual->hybgl_drawn.count = 0;
     149             :                 //partial flush, reset
     150         146 :                 if (area)
     151           0 :                         memset(compositor->hybgl_txh->data, 0, compositor->hybgl_txh->stride*compositor->hybgl_txh->height);
     152             :         }
     153             :         //complete flush (end of frame)
     154        1806 :         else if (!area) {
     155         915 :                 compositor->visual->hybgl_drawn.count = 0;
     156             :         }
     157        1952 :         compositor->visual->nb_objects_on_canvas_since_last_ogl_flush = 0;
     158             : }
     159             : 
     160         697 : Bool compositor_2d_hybgl_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx)
     161             : {
     162             :         GF_Node *txtrans = NULL;
     163             :         //for anything but background use regular routines
     164         697 :         if (!(ctx->flags & CTX_IS_BACKGROUND)) return GF_FALSE;
     165             : 
     166             : #ifndef GPAC_DISABLE_VRML
     167         464 :         if (tr_state->appear ) txtrans = ((M_Appearance *)tr_state->appear)->textureTransform;
     168             : #endif
     169             : 
     170             :         /*ignore texture transform for bitmap*/
     171         464 :         tr_state->mesh_num_textures = gf_sc_texture_enable(ctx->aspect.fill_texture, txtrans);
     172             : 
     173         464 :         if (tr_state->mesh_num_textures) {
     174             :                 SFVec2f size, orig;
     175         442 :                 size.x = ctx->bi->unclip.width;
     176         442 :                 size.y = ctx->bi->unclip.height;
     177         442 :                 orig.x = ctx->bi->unclip.x ;
     178         442 :                 orig.y = ctx->bi->unclip.y;
     179         442 :                 mesh_new_rectangle(visual->compositor->hybgl_mesh_background, size, &orig, GF_FALSE);
     180             : 
     181         442 :                 visual_3d_mesh_paint(tr_state, visual->compositor->hybgl_mesh_background);
     182         442 :                 gf_sc_texture_disable(ctx->aspect.fill_texture);
     183         442 :                 tr_state->mesh_num_textures = 0;
     184             :         }
     185             :         return GF_TRUE;
     186             : }
     187             : #endif
     188             : 
     189             : #ifndef GPAC_DISABLE_3D
     190         605 : void compositor_2d_reset_gl_auto(GF_Compositor *compositor)
     191             : {
     192         605 :         if (compositor->hybgl_txh) {
     193          17 :                 if (compositor->hybgl_txh->data) {
     194          17 :                         gf_free(compositor->hybgl_txh->data);
     195          17 :                         compositor->hybgl_txh->data = NULL;
     196             :                 }
     197          17 :                 if (compositor->hybgl_txh->tx_io)
     198          17 :                         gf_sc_texture_release(compositor->hybgl_txh);
     199             : 
     200          17 :                 gf_free(compositor->hybgl_txh);
     201          17 :                 compositor->hybgl_txh = NULL;
     202             :         }
     203         605 :         if (compositor->hybgl_mesh) {
     204          17 :                 mesh_free(compositor->hybgl_mesh);
     205          17 :                 compositor->hybgl_mesh = NULL;
     206             :         }
     207         605 :         if (compositor->hybgl_mesh_background) {
     208          17 :                 mesh_free(compositor->hybgl_mesh_background);
     209          17 :                 compositor->hybgl_mesh_background = NULL;
     210             :         }
     211         605 : }
     212             : 
     213        1062 : static GF_Err compositor_2d_setup_opengl(GF_VisualManager *visual)
     214             : {
     215        1062 :         GF_Compositor *compositor = visual->compositor;
     216        1062 :         visual->is_attached = GF_TRUE;
     217             : 
     218        1062 :         visual_3d_setup(visual);
     219        1062 :         visual->compositor->traverse_state->camera = &visual->camera;
     220             : 
     221             : 
     222        1062 :         glViewport(0, 0, compositor->vp_width, compositor->vp_height);
     223             : 
     224        1062 :         visual->camera.vp.x = visual->camera.vp.y = 0;
     225        1062 :         visual->camera.vp.width = visual->camera.width = INT2FIX(compositor->vp_width);
     226        1062 :         visual->camera.vp.height = visual->camera.height = INT2FIX(compositor->vp_height);
     227        1062 :         visual->camera.up.y = FIX_ONE;
     228        1062 :         visual->camera.end_zoom = FIX_ONE;
     229        1062 :         visual->camera.position.z = INT2FIX(1000);
     230        1062 :         visual->camera.flags = CAM_IS_DIRTY;
     231             : 
     232        1062 :         camera_update(&visual->camera, NULL, visual->compositor->hybrid_opengl ? GF_TRUE : visual->center_coords);
     233             : 
     234        1062 :         visual_3d_projection_matrix_modified(visual);
     235        1062 :         return GF_OK;
     236             : }
     237             : #endif
     238             : 
     239             : #ifndef GPAC_DISABLE_3D
     240             : 
     241        1062 : static GF_Err c2d_video_access_hybrid_opengl(GF_VisualManager *visual)
     242             : {
     243             :         GF_Err e;
     244        1062 :         GF_Compositor *compositor = visual->compositor;
     245             : 
     246        1062 :         if (!compositor->hybgl_txh) {
     247          18 :                 GF_SAFEALLOC(compositor->hybgl_txh, GF_TextureHandler);
     248          18 :                 if (!compositor->hybgl_txh) return GF_IO_ERR;
     249          18 :                 compositor->hybgl_txh->compositor = compositor;
     250             :         }
     251             : 
     252        1062 :         if ((compositor->hybgl_txh->width != compositor->vp_width) || (compositor->hybgl_txh->height != compositor->vp_height)) {
     253             :                 SFVec2f size;
     254          20 :                 compositor->hybgl_txh->data = (char*)gf_realloc(compositor->hybgl_txh->data, 4*compositor->vp_width*compositor->vp_height);
     255             : 
     256          20 :                 if (compositor->hybgl_txh->tx_io)
     257           2 :                         gf_sc_texture_release(compositor->hybgl_txh);
     258             : 
     259          20 :                 compositor->hybgl_txh->width = compositor->vp_width;
     260          20 :                 compositor->hybgl_txh->height = compositor->vp_height;
     261          20 :                 compositor->hybgl_txh->stride = 4*compositor->vp_width;
     262          20 :                 compositor->hybgl_txh->pixelformat = GF_PIXEL_RGBA;
     263          20 :                 compositor->hybgl_txh->transparent = GF_TRUE;
     264          20 :                 compositor->hybgl_txh->flags = GF_SR_TEXTURE_PRIVATE_MEDIA | GF_SR_TEXTURE_NO_GL_FLIP;
     265             : 
     266          20 :                 memset(compositor->hybgl_txh->data, 0, 4*compositor->hybgl_txh->width*compositor->hybgl_txh->height);
     267          20 :                 gf_sc_texture_allocate(compositor->hybgl_txh);
     268          20 :                 gf_sc_texture_set_data(compositor->hybgl_txh);
     269             : 
     270          20 :                 if (!compositor->hybgl_mesh)
     271          18 :                         compositor->hybgl_mesh = new_mesh();
     272             : 
     273          20 :                 if (!compositor->hybgl_mesh_background)
     274          18 :                         compositor->hybgl_mesh_background = new_mesh();
     275             : 
     276          20 :                 size.x = INT2FIX(compositor->vp_width);
     277          20 :                 size.y = INT2FIX(compositor->vp_height);
     278          20 :                 mesh_new_rectangle(compositor->hybgl_mesh, size, NULL, GF_TRUE);
     279          20 :                 mesh_new_rectangle(compositor->hybgl_mesh_background, size, NULL, GF_FALSE);
     280             :         }
     281        1062 :         if (!compositor->hybgl_txh->data) return GF_IO_ERR;
     282             : 
     283        1062 :         if (visual->compositor->traverse_state->immediate_draw)
     284         126 :                 memset(compositor->hybgl_txh->data, 0, 4*compositor->hybgl_txh->width*compositor->hybgl_txh->height);
     285             : 
     286        1062 :         e = gf_evg_surface_attach_to_buffer(visual->raster_surface, compositor->hybgl_txh->data,
     287             :                 compositor->hybgl_txh->width,
     288             :                 compositor->hybgl_txh->height,
     289             :                 0,
     290        1062 :                 compositor->hybgl_txh->width * 4,
     291             :                 (GF_PixelFormat) GF_PIXEL_RGBA);
     292        1062 :         if (e) return e;
     293        1062 :         e = compositor_2d_setup_opengl(visual);
     294        1062 :         if (e) return e;
     295        1062 :         visual->ClearSurface = compositor_2d_hybgl_clear_surface;
     296        1062 :         visual->DrawBitmap = compositor_2d_hybgl_draw_bitmap;
     297        1062 :         return GF_OK;
     298             : }
     299             : #endif
     300             : 
     301       13170 : static GF_Err c2d_get_video_access_normal(GF_VisualManager *visual)
     302             : {
     303             :         GF_Err e;
     304       13170 :         GF_Compositor *compositor = visual->compositor;
     305             : 
     306       13170 :         compositor->hw_locked = GF_FALSE;
     307             : 
     308       13170 :         e = compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, GF_TRUE);
     309       13170 :         if (e==GF_OK) {
     310       13170 :                 compositor->hw_locked = GF_TRUE;
     311             : 
     312       13170 :                 e = gf_evg_surface_attach_to_buffer(visual->raster_surface, compositor->hw_surface.video_buffer,
     313             :                         compositor->hw_surface.width,
     314             :                         compositor->hw_surface.height,
     315             :                         compositor->hw_surface.pitch_x,
     316             :                         compositor->hw_surface.pitch_y,
     317       13170 :                         (GF_PixelFormat) compositor->hw_surface.pixel_format);
     318       13170 :                 if (!e) {
     319       13170 :                         visual->is_attached = GF_TRUE;
     320       13170 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface memory attached to raster - w=%d h=%d pitch_x=%d pitch_y=%d\n", compositor->hw_surface.width, compositor->hw_surface.height, compositor->hw_surface.pitch_x, compositor->hw_surface.pitch_y));
     321             :                         return GF_OK;
     322             :                 }
     323           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot attach video surface memory to raster for pixel format %s: %s\n", gf_pixel_fmt_name(compositor->hw_surface.pixel_format), gf_error_to_string(e) ));
     324           0 :                 compositor->last_error = e;
     325           0 :                 compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, GF_FALSE);
     326             :         }
     327           0 :         compositor->hw_locked = GF_FALSE;
     328           0 :         visual->is_attached = GF_FALSE;
     329             :         /*if using BlitTexture, return OK to still be able to blit images*/
     330           0 :         if (compositor->video_out->BlitTexture) e = GF_OK;
     331             :         return e;
     332             : }
     333             : 
     334       21062 : GF_Err compositor_2d_get_video_access(GF_VisualManager *visual)
     335             : {
     336       21062 :         if (!visual->raster_surface) return GF_BAD_PARAM;
     337             : 
     338             : #ifndef GPAC_DISABLE_3D
     339       21062 :         if (visual->compositor->hybrid_opengl) {
     340        1062 :                 return c2d_video_access_hybrid_opengl(visual);
     341             :         }
     342             : #endif
     343             :         //do nothing until asked to really attach
     344             :         return GF_OK;
     345             : }
     346             : 
     347      759129 : Bool compositor_2d_check_attached(GF_VisualManager *visual)
     348             : {
     349      759129 :         if (!visual->is_attached) {
     350       13170 :                 c2d_get_video_access_normal(visual);
     351             :         }
     352             : 
     353      759129 :         return visual->is_attached;
     354             : }
     355             : 
     356        2057 : void compositor_2d_clear_surface(GF_VisualManager *visual, GF_IRect *rc, u32 BackColor, u32 offscreen_clear)
     357             : {
     358             :         //visual not attached on main (direct video) visual, use texture bliting
     359        2057 :         if (!visual->is_attached && visual->compositor->video_out->Blit && (visual->compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_RGB)) {
     360             :                 char data[12];
     361             :                 GF_Err e;
     362             :                 GF_VideoSurface video_src;
     363             :                 GF_Window src_wnd, dst_wnd;
     364             : 
     365           0 :                 if (!BackColor && !visual->offscreen) {
     366           0 :                         if ( !(visual->compositor->init_flags & GF_TERM_WINDOW_TRANSPARENT)) {
     367           0 :                                 BackColor = visual->compositor->back_color;
     368             :                         }
     369             :                 }
     370             : 
     371           0 :                 data[0] = data[3] = data[6] = data[9] = GF_COL_R(BackColor);
     372           0 :                 data[1] = data[4] = data[7] = data[10] = GF_COL_G(BackColor);
     373           0 :                 data[2] = data[5] = data[8] = data[11] = GF_COL_B(BackColor);
     374             : 
     375             :                 memset(&video_src, 0, sizeof(GF_VideoSurface));
     376           0 :                 video_src.height = 2;
     377           0 :                 video_src.width = 2;
     378             :                 video_src.pitch_x = 0;
     379           0 :                 video_src.pitch_y = 6;
     380           0 :                 video_src.pixel_format = GF_PIXEL_RGB;
     381           0 :                 video_src.video_buffer = data;
     382             : 
     383           0 :                 src_wnd.x = src_wnd.y = 0;
     384           0 :                 src_wnd.w = src_wnd.h = 1;
     385           0 :                 if (rc) {
     386           0 :                         if (visual->center_coords) {
     387           0 :                                 dst_wnd.x = rc->x + visual->width/2;
     388           0 :                                 dst_wnd.y = visual->height/2 - rc->y;
     389             :                         } else {
     390           0 :                                 dst_wnd.x = rc->x;
     391           0 :                                 dst_wnd.y = rc->y - visual->height/2;
     392             :                         }
     393           0 :                         dst_wnd.w = rc->width;
     394           0 :                         dst_wnd.h = rc->height;
     395             :                 } else {
     396           0 :                         dst_wnd.x = dst_wnd.y = 0;
     397           0 :                         dst_wnd.w = visual->width;
     398           0 :                         dst_wnd.h = visual->height;
     399             :                 }
     400             : 
     401           0 :                 e = visual->compositor->video_out->Blit(visual->compositor->video_out, &video_src, &src_wnd, &dst_wnd, 0);
     402           0 :                 if (e==GF_OK) return;
     403             :         }
     404             : 
     405        2057 :         visual_2d_clear_surface(visual, rc, BackColor, offscreen_clear);
     406             : }
     407             : 
     408             : 
     409             : 
     410       21062 : void compositor_2d_release_video_access(GF_VisualManager *visual)
     411             : {
     412       21062 :         GF_Compositor *compositor = visual->compositor;
     413       21062 :         if (visual->is_attached) {
     414       14232 :                 visual->is_attached = GF_FALSE;
     415             :         }
     416             : 
     417             : #ifndef GPAC_DISABLE_3D
     418       21062 :         if (compositor->hybrid_opengl) {
     419        1062 :                 compositor_2d_hybgl_flush_video(compositor, NULL);
     420        1062 :                 return;
     421             :         }
     422             : #endif //GPAC_DISABLE_3D
     423             : 
     424       20000 :         if (compositor->hw_context) {
     425           0 :                 compositor->video_out->LockOSContext(compositor->video_out, GF_FALSE);
     426           0 :                 compositor->hw_context = NULL;
     427       20000 :         } else if (compositor->hw_locked) {
     428       13170 :                 compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, GF_FALSE);
     429       13170 :                 compositor->hw_locked = GF_FALSE;
     430             :         }
     431             : }
     432             : 
     433       23676 : static void store_blit_times(GF_TextureHandler *txh, u32 push_time)
     434             : {
     435             : #ifndef GPAC_DISABLE_LOG
     436             :         u32 ck;
     437             : #endif
     438             : 
     439       23676 :         push_time = gf_sys_clock() - push_time;
     440       23676 :         txh->nb_frames ++;
     441       23676 :         txh->upload_time += push_time;
     442             : 
     443             : #ifndef GPAC_DISABLE_LOG
     444       23676 :         gf_mo_get_object_time(txh->stream, &ck);
     445       23676 :         if (ck>txh->last_frame_time) {
     446        2987 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Bliting frame (CTS %d) %d ms too late\n", txh->last_frame_time, ck - txh->last_frame_time ));
     447             :         }
     448             : 
     449       23676 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[2D Blitter] At %u Blit texture (CTS %u) %d ms after due date - blit in %d ms - average push time %d ms\n", ck, txh->last_frame_time, ck - txh->last_frame_time, push_time, txh->upload_time / txh->nb_frames));
     450             : #endif
     451       23676 : }
     452             : 
     453       23875 : Bool compositor_texture_rectangles(GF_VisualManager *visual, GF_TextureHandler *txh, GF_IRect *clip, GF_Rect *unclip, GF_Window *src, GF_Window *dst, Bool *disable_blit, Bool *has_scale)
     454             : {
     455             :         Fixed w_scale, h_scale, tmp;
     456             :         u32 output_width, output_height;
     457       23875 :         GF_IRect clipped_final = *clip;
     458       23875 :         GF_Rect final = *unclip;
     459             :         Bool use_blit;
     460             : 
     461       23875 :         src->w = src->h = 0;
     462       23875 :         dst->w = dst->h = 0;
     463       23875 :         if (disable_blit) *disable_blit = GF_FALSE;
     464       23875 :         if (has_scale) *has_scale = GF_FALSE;
     465             : 
     466       23875 :         if (final.width<=0 || final.height <=0) return GF_FALSE;
     467       23875 :         if (txh->width==0 || txh->height==0) return GF_FALSE;
     468             : 
     469       23875 :         w_scale = final.width / txh->width;
     470       23875 :         h_scale = final.height / txh->height;
     471             : 
     472       23875 :         if ((w_scale != FIX_ONE) || (h_scale!=FIX_ONE)) {
     473       23706 :                 if (has_scale) *has_scale = GF_TRUE;
     474             :         }
     475             : 
     476       23875 :         if (visual->offscreen) {
     477           0 :                 output_width = visual->width;
     478           0 :                 output_height = visual->height;
     479             :         } else {
     480             :                 /*use entire video surface for un-centering coord system*/
     481       23875 :                 output_width = visual->compositor->vp_width;
     482       23875 :                 output_height = visual->compositor->vp_height;
     483             :         }
     484             :         /*take care of pixel rounding for odd width/height and make sure we strictly draw in the clipped bounds*/
     485       23875 :         if (visual->center_coords) {
     486       23532 :                 clipped_final.x += output_width / 2;
     487       23532 :                 final.x += INT2FIX( output_width / 2 );
     488             : 
     489       23532 :                 clipped_final.y = output_height/ 2 - clipped_final.y;
     490       23532 :                 final.y = INT2FIX( output_height / 2) - final.y;
     491             : 
     492             :         } else {
     493         343 :                 final.y -= final.height;
     494         343 :                 clipped_final.y -= clipped_final.height;
     495             :         }
     496             : 
     497             :         /*make sure we lie in the final rect (this is needed for directdraw mode)*/
     498       23875 :         if (clipped_final.x<0) {
     499           0 :                 clipped_final.width += clipped_final.x;
     500             :                 clipped_final.x = 0;
     501           0 :                 if (clipped_final.width <= 0) return GF_FALSE;
     502             :         }
     503       23875 :         if (clipped_final.y<0) {
     504           0 :                 clipped_final.height += clipped_final.y;
     505             :                 clipped_final.y = 0;
     506           0 :                 if (clipped_final.height <= 0) return GF_FALSE;
     507             :         }
     508       23875 :         if (clipped_final.x + clipped_final.width > (s32) output_width) {
     509           0 :                 clipped_final.width = output_width - clipped_final.x;
     510             :                 clipped_final.x = output_width - clipped_final.width;
     511             :         }
     512       23875 :         if (clipped_final.y + clipped_final.height > (s32) output_height) {
     513           0 :                 clipped_final.height = output_height - clipped_final.y;
     514             :                 clipped_final.y = output_height - clipped_final.height;
     515             :         }
     516             :         /*needed in direct drawing since clipping is not performed*/
     517       23875 :         if (clipped_final.width<=0 || clipped_final.height <=0)
     518             :                 return GF_FALSE;
     519             : 
     520       23875 :         if (clipped_final.width-1>= FIX2INT(final.width) ) clipped_final.width = FIX2INT(final.width);
     521       23875 :         if (clipped_final.height-1>= FIX2INT(final.height) ) clipped_final.height = FIX2INT(final.height);
     522             : 
     523             :         /*set dest window*/
     524       23875 :         dst->x = (u32) clipped_final.x;
     525       23875 :         dst->y = (u32) clipped_final.y;
     526       23875 :         dst->w = (u32) clipped_final.width;
     527       23875 :         dst->h = (u32) clipped_final.height;
     528             : 
     529       23875 :         if (!dst->w || !dst->h) return GF_FALSE;
     530             : 
     531             : #ifdef GPAC_FIXED_POINT
     532             : #define ROUND_FIX(_v)   \
     533             :         _v = FIX2INT(tmp);
     534             : #define CEILING(_v)     \
     535             :         _v = FIX2INT(tmp);      \
     536             :         if (INT2FIX(_v)!=tmp) _v++;
     537             : #else
     538             : #define ROUND_FIX(_v)   \
     539             :         _v = FIX2INT(tmp);      \
     540             :         tmp -= INT2FIX(_v);     \
     541             :         if (tmp>99*FIX_ONE/100) { _v++; tmp = 0; }   \
     542             :         if (ABS(tmp) > FIX_EPSILON) use_blit = 0;
     543             : #define CEILING(_v)     \
     544             :         _v = FIX2INT(tmp);      \
     545             :         tmp -= INT2FIX(_v);     \
     546             :         if (tmp>0) { _v++; tmp = 0; }        \
     547             :         if (ABS(tmp) > FIX_EPSILON) use_blit = 0;
     548             : #endif
     549             : 
     550             :         use_blit = GF_TRUE;
     551             : 
     552       23875 :         if (txh->data && !txh->size && (txh->width==2) && (txh->height==2) ) {
     553       16789 :                 src->x = src->y = 0;
     554       16789 :                 src->w = 1;
     555       16789 :                 src->h = 1;
     556             :         } else {
     557             :                 /*compute SRC window*/
     558        7086 :                 tmp = gf_divfix(INT2FIX(clipped_final.x) - final.x, w_scale);
     559        7086 :                 if (tmp<0) tmp=0;
     560        7086 :                 CEILING(src->x);
     561             : 
     562        7086 :                 tmp = gf_divfix(INT2FIX(clipped_final.y) - final.y, h_scale);
     563        7086 :                 if (tmp<0) tmp=0;
     564        7086 :                 CEILING(src->y);
     565             : 
     566        7086 :                 tmp = gf_divfix(INT2FIX(clip->width), w_scale);
     567        7086 :                 ROUND_FIX(src->w);
     568             : 
     569        7086 :                 tmp = gf_divfix(INT2FIX(clip->height), h_scale);
     570        7086 :                 ROUND_FIX(src->h);
     571             : 
     572             : 
     573        7086 :                 if (src->w>txh->width) src->w=txh->width;
     574        7086 :                 if (src->h>txh->height) src->h=txh->height;
     575             : 
     576        7086 :                 if (!src->w || !src->h) return GF_FALSE;
     577             : 
     578             :                 /*make sure we lie in src bounds*/
     579        7086 :                 if (src->x + src->w>txh->width) src->w = txh->width - src->x;
     580        7086 :                 if (src->y + src->h>txh->height) src->h = txh->height - src->y;
     581             :         }
     582             : #undef ROUND_FIX
     583             : 
     584       23875 :         if (disable_blit) *disable_blit = use_blit ? GF_FALSE : GF_TRUE;
     585             :         return GF_TRUE;
     586             : }
     587             : 
     588       23875 : static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHandler *txh, DrawableContext *ctx, GF_IRect *clip, GF_Rect *unclip, u8 alpha, GF_TraverseState *tr_state, Bool force_soft_blt)
     589             : {
     590             :         GF_VideoSurface video_src;
     591             :         GF_Err e;
     592             :         Bool use_soft_stretch, use_blit, flush_video, is_attached, has_scale;
     593             :         u32 overlay_type;
     594             :         GF_Window src_wnd, dst_wnd;
     595             :         u32 output_width, output_height, hw_caps;
     596             : 
     597             : 
     598       23875 :         if (!txh->data) return GF_TRUE;
     599             : 
     600       23875 :         if (!visual->compositor->has_size_info && !(visual->compositor->msg_type & GF_SR_CFG_OVERRIDE_SIZE)
     601             :                 && (visual->compositor->override_size_flags & 1)
     602         356 :                 && !(visual->compositor->override_size_flags & 2)
     603             :            ) {
     604           0 :                 if ( (visual->compositor->scene_width < txh->width)
     605           0 :                         || (visual->compositor->scene_height < txh->height)) {
     606           0 :                         visual->compositor->scene_width = txh->width;
     607           0 :                         visual->compositor->scene_height = txh->height;
     608           0 :                         visual->compositor->msg_type |= GF_SR_CFG_OVERRIDE_SIZE;
     609           0 :                         return GF_TRUE;
     610             :                 }
     611             :         }
     612             : 
     613       23875 :         if (!compositor_texture_rectangles(visual, txh, clip, unclip, &src_wnd, &dst_wnd, &use_blit, &has_scale)) return GF_TRUE;
     614             : 
     615             :         //blitter is disabled
     616       23875 :         if (txh->flags & GF_SR_TEXTURE_DISABLE_BLIT) return GF_FALSE;
     617             : 
     618             :         /*can we use hardware blitter ?*/
     619       23792 :         hw_caps = visual->compositor->video_out->hw_caps;
     620             :         overlay_type = 0;
     621             :         flush_video = GF_FALSE;
     622             :         use_soft_stretch = GF_TRUE;
     623             : 
     624       23792 :         output_width = visual->compositor->vp_width;
     625       23792 :         output_height = visual->compositor->vp_height;
     626             : 
     627       23792 :         if (visual->compositor->disable_hardware_blit) force_soft_blt = GF_TRUE;
     628             : 
     629       23792 :         if (!force_soft_blt) {
     630             : 
     631             :                 /*avoid partial redraw that don't come close to src pixels with the bliter, this leads to ugly artefacts -
     632             :                 fall back to rasterizer*/
     633             : //              if (!(ctx->flags & CTX_TEXTURE_DIRTY) && !use_blit && (src_wnd.x || src_wnd.y) )
     634             : //                      return 0;
     635             : 
     636       23792 :                 switch (txh->pixelformat) {
     637       19732 :                 case GF_PIXEL_RGB:
     638             :                 case GF_PIXEL_BGR:
     639             :                 case GF_PIXEL_RGBS:
     640             :                 case GF_PIXEL_RGBD:
     641             : //              case GF_PIXEL_RGB_555:
     642             : //              case GF_PIXEL_RGB_565:
     643       19732 :                         if ((alpha==0xFF) && (hw_caps & GF_VIDEO_HW_HAS_RGB)) {
     644             :                                 use_soft_stretch = GF_FALSE;
     645             :                         }
     646         147 :                         else if ((alpha!=0xFF) && (hw_caps & GF_VIDEO_HW_HAS_RGBA)) {
     647             :                                 use_soft_stretch = GF_FALSE;
     648             :                         }
     649             :                         break;
     650         626 :                 case GF_PIXEL_ARGB:
     651             :                 case GF_PIXEL_RGBA:
     652             :                 case GF_PIXEL_RGBAS:
     653             :                 case GF_PIXEL_RGBDS:
     654         626 :                         if (hw_caps & GF_VIDEO_HW_HAS_RGBA)
     655             :                                 use_soft_stretch = GF_FALSE;
     656             :                         break;
     657        3434 :                 default:
     658        3434 :                         if (gf_pixel_fmt_is_yuv(txh->pixelformat)) {
     659        3413 :                                 if (hw_caps & GF_VIDEO_HW_HAS_YUV) use_soft_stretch = GF_FALSE;
     660        3413 :                                 else if (hw_caps & GF_VIDEO_HW_HAS_YUV_OVERLAY) overlay_type = 1;
     661             :                         }
     662             :                         break;
     663             :                 }
     664             :                 /*disable based on settings*/
     665       23792 :                 if (!visual->compositor->yuvhw
     666       23792 :                         || (ctx->col_mat || !visual->compositor->video_out->Blit)
     667             :                    ) {
     668             :                         use_soft_stretch = GF_TRUE;
     669             :                         overlay_type = 0;
     670             :                 }
     671       23792 :                 if (!visual->compositor->blitp && ((src_wnd.w!=txh->width) || (src_wnd.h!=txh->height) )) {
     672             :                         use_soft_stretch = GF_TRUE;
     673             :                 }
     674             : 
     675             :                 /*disable HW color keying - not compatible with MPEG-4 MaterialKey*/
     676       23792 :                 if (tr_state->col_key) {
     677             :                         use_soft_stretch = GF_TRUE;
     678             :                         overlay_type = 0;
     679             :                 }
     680             : 
     681       23671 :                 if (overlay_type) {
     682             :                         /*no more than one overlay is supported at the current time*/
     683           0 :                         if (visual->overlays) {
     684           0 :                                 ctx->drawable->flags &= ~DRAWABLE_IS_OVERLAY;
     685             :                                 overlay_type = 0;
     686             :                         }
     687             :                         /*direct draw or not last context: we must queue the overlay*/
     688           0 :                         else if (tr_state->immediate_draw || (ctx->next && ctx->next->drawable)) {
     689             :                                 overlay_type = 2;
     690             :                         }
     691             :                         /*OK we can overlay this video - if full display, don't flush*/
     692             :                         if (overlay_type==1) {
     693           0 :                                 if (dst_wnd.w==visual->compositor->display_width) flush_video = GF_FALSE;
     694           0 :                                 else if (dst_wnd.h==visual->compositor->display_height) flush_video = GF_FALSE;
     695           0 :                                 else flush_video = visual->has_modif;
     696             :                         }
     697             :                         /*if no color keying, we cannot queue the overlay*/
     698           0 :                         else if (!visual->compositor->video_out->overlay_color_key) {
     699             :                                 overlay_type = 0;
     700             :                         }
     701             :                 }
     702             :         }
     703             : 
     704       23792 :         if (has_scale && !(hw_caps & GF_VIDEO_HW_HAS_STRETCH) && !overlay_type) {
     705             :                 use_soft_stretch = GF_TRUE;
     706             :         }
     707             : 
     708             :         memset(&video_src, 0, sizeof(GF_VideoSurface));
     709       23792 :         video_src.height = txh->height;
     710       23792 :         video_src.width = txh->width;
     711             :         video_src.pitch_x = 0;
     712       23792 :         if (!txh->stride)
     713           0 :                 gf_pixel_get_size_info(txh->pixelformat, txh->width, txh->height, NULL, &txh->stride, NULL, NULL, NULL);
     714       23792 :         video_src.pitch_y = txh->stride;
     715       23792 :         video_src.pixel_format = txh->pixelformat;
     716             : #ifdef GF_SR_USE_DEPTH
     717       23792 :         if (txh->pixelformat==GF_PIXEL_YUVD) video_src.pixel_format = GF_PIXEL_YUV;
     718             : #endif
     719       23792 :         video_src.video_buffer = txh->data;
     720       23792 :         if (txh->frame_ifce) {
     721             :                 u32 stride;
     722           0 :                 if (!txh->frame_ifce->get_plane) return GF_FALSE;
     723             : 
     724           0 :                 e = txh->frame_ifce->get_plane(txh->frame_ifce, 0, (const u8 **) &video_src.video_buffer, &video_src.pitch_y);
     725           0 :                 if (e) return GF_FALSE;
     726           0 :                 txh->frame_ifce->get_plane(txh->frame_ifce, 1, (const u8 **) video_src.u_ptr, &stride);
     727           0 :                 txh->frame_ifce->get_plane(txh->frame_ifce, 2, (const u8 **) video_src.v_ptr, &stride);
     728             :         }
     729       23792 :         video_src.global_alpha = alpha;
     730             : 
     731             :         //overlay queing
     732       23792 :         if (overlay_type==2) {
     733             :                 GF_IRect o_rc;
     734             :                 GF_OverlayStack *ol, *first;
     735             : 
     736             :                 /*queue overlay in order*/
     737           0 :                 GF_SAFEALLOC(ol, GF_OverlayStack);
     738           0 :                 if (!ol) {
     739             :                         return GF_FALSE;
     740             :                 }
     741           0 :                 ol->ctx = ctx;
     742           0 :                 ol->dst = dst_wnd;
     743           0 :                 ol->src = src_wnd;
     744           0 :                 first = visual->overlays;
     745           0 :                 if (first) {
     746           0 :                         while (first->next) first = first->next;
     747           0 :                         first->next = ol;
     748             :                 } else {
     749           0 :                         visual->overlays = ol;
     750             :                 }
     751             : 
     752           0 :                 if (visual->center_coords) {
     753           0 :                         o_rc.x = dst_wnd.x - output_width/2;
     754           0 :                         o_rc.y = output_height/2- dst_wnd.y;
     755             :                 } else {
     756           0 :                         o_rc.x = dst_wnd.x;
     757           0 :                         o_rc.y = dst_wnd.y + dst_wnd.h;
     758             :                 }
     759             : 
     760           0 :                 o_rc.width = dst_wnd.w;
     761           0 :                 o_rc.height = dst_wnd.h;
     762           0 :                 visual->ClearSurface(visual, &o_rc, visual->compositor->video_out->overlay_color_key, GF_FALSE);
     763           0 :                 visual->has_overlays = GF_TRUE;
     764             :                 /*mark drawable as overlay*/
     765           0 :                 ctx->drawable->flags |= DRAWABLE_IS_OVERLAY;
     766             : 
     767             :                 /*prevents this context from being removed in direct draw mode by requesting a new one
     768             :                 but not allocating it*/
     769           0 :                 if (tr_state->immediate_draw)
     770           0 :                         visual_2d_get_drawable_context(visual);
     771             : 
     772             :                 return GF_TRUE;
     773             :         }
     774             : 
     775             :         //will pause clock if first HW load
     776       23792 :         gf_sc_texture_check_pause_on_first_load(txh, GF_TRUE);
     777             : 
     778       23792 :         if (overlay_type) {
     779             :                 u32 push_time;
     780             : 
     781             :                 /*top level overlay*/
     782           0 :                 if (flush_video) {
     783             :                         GF_Window rc;
     784           0 :                         rc.x = rc.y = 0;
     785           0 :                         rc.w = visual->compositor->display_width;
     786           0 :                         rc.h = visual->compositor->display_height;
     787             : 
     788           0 :                         visual_2d_release_raster(visual);
     789           0 :                         visual->compositor->video_out->Flush(visual->compositor->video_out, &rc);
     790           0 :                         visual_2d_init_raster(visual);
     791             :                 }
     792           0 :                 visual->compositor->skip_flush = 1;
     793             : 
     794           0 :                 push_time = gf_sys_clock();
     795           0 :                 e = visual->compositor->video_out->Blit(visual->compositor->video_out, &video_src, &src_wnd, &dst_wnd, 1);
     796             : 
     797           0 :                 if (!e) {
     798           0 :                         store_blit_times(txh, push_time);
     799             :                         /*mark drawable as overlay*/
     800           0 :                         ctx->drawable->flags |= DRAWABLE_IS_OVERLAY;
     801           0 :                         visual->has_overlays = GF_TRUE;
     802             : 
     803             :                         //will resume clock if first HW load
     804           0 :                         gf_sc_texture_check_pause_on_first_load(txh, GF_FALSE);
     805           0 :                         return GF_TRUE;
     806             :                 }
     807           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Error during overlay blit - trying with soft one\n"));
     808           0 :                 visual->compositor->skip_flush = GF_FALSE;
     809             :         }
     810             : 
     811             :         /*most graphic cards can't perform bliting on locked surface - force unlock by releasing the hardware*/
     812       23792 :         is_attached = visual->is_attached;
     813       23792 :         if (is_attached) visual_2d_release_raster(visual);
     814             : 
     815       23792 :         if (!use_soft_stretch) {
     816           0 :                 u32 push_time = gf_sys_clock();
     817           0 :                 e = visual->compositor->video_out->Blit(visual->compositor->video_out, &video_src, &src_wnd, &dst_wnd, 0);
     818             : 
     819             :                 /*HW pb, try soft*/
     820           0 :                 if (e) {
     821             :                         use_soft_stretch = GF_TRUE;
     822           0 :                         if (visual->compositor->video_memory==1) {
     823           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor2D] Error during hardware blit - will use soft one\n"));
     824           0 :                                 visual->compositor->video_memory = 2;
     825             :                         }
     826             :                         /*force a reconfigure of video output*/
     827           0 :                         else if (visual->compositor->video_memory!=2) {
     828           0 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring video output to use video memory\n"));
     829           0 :                                 visual->compositor->request_video_memory = GF_TRUE;
     830           0 :                                 visual->compositor->root_visual_setup = GF_FALSE;
     831           0 :                                 gf_sc_next_frame_state(visual->compositor, GF_SC_DRAW_FRAME);
     832             :                         }
     833             :                 } else {
     834           0 :                         store_blit_times(txh, push_time);
     835             :                 }
     836             :         }
     837             : 
     838             :         //will resume clock if first HW load
     839       23792 :         gf_sc_texture_check_pause_on_first_load(txh, GF_FALSE);
     840             : 
     841       23792 :         if (use_soft_stretch) {
     842             :                 GF_VideoSurface backbuffer;
     843       23792 :                 if (!visual->compositor->softblt) {
     844         116 :                         if (is_attached) visual_2d_init_raster(visual);
     845         116 :                         txh->flags |= GF_SR_TEXTURE_DISABLE_BLIT;
     846         345 :                         return GF_FALSE;
     847             :                 }
     848             : 
     849       23676 :                 e = visual->compositor->video_out->LockBackBuffer(visual->compositor->video_out, &backbuffer, GF_TRUE);
     850       23676 :                 if (!e) {
     851       23676 :                         u32 push_time = gf_sys_clock();
     852       23676 :                         e = gf_stretch_bits(&backbuffer, &video_src, &dst_wnd, &src_wnd, alpha, GF_FALSE, tr_state->col_key, ctx->col_mat);
     853       23676 :                         store_blit_times(txh, push_time);
     854       23676 :                         visual->compositor->video_out->LockBackBuffer(visual->compositor->video_out, &backbuffer, GF_FALSE);
     855       23676 :                         if (e) {
     856         113 :                                 if (e != GF_NOT_SUPPORTED) {
     857           0 :                                         GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor2D] Cannot soft blit surface (error %s) - will try using software rasterizer\n", gf_error_to_string(e) ));
     858           0 :                                         visual->compositor->last_error = e;
     859             :                                 }
     860         113 :                                 if (is_attached) visual_2d_init_raster(visual);
     861         113 :                                 txh->flags |= GF_SR_TEXTURE_DISABLE_BLIT;
     862         113 :                                 return GF_FALSE;
     863             :                         }
     864             :                 } else {
     865           0 :                         if (e != GF_NOT_SUPPORTED) {
     866           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot lock back buffer - Error %s\n", gf_error_to_string(e) ));
     867           0 :                                 visual->compositor->last_error = e;
     868             :                         }
     869           0 :                         if (is_attached) visual_2d_init_raster(visual);
     870             :                         return GF_FALSE;
     871             :                 }
     872       23563 :                 if (!visual->compositor->video_memory) {
     873           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring video output to use video memory\n"));
     874           0 :                         visual->compositor->video_memory = 1;
     875           0 :                         visual->compositor->root_visual_setup = GF_FALSE;
     876           0 :                         gf_sc_next_frame_state(visual->compositor, GF_SC_DRAW_FRAME);
     877             :                 }
     878             :         }
     879       23563 :         visual->has_modif = GF_TRUE;
     880       23563 :         if (is_attached) visual_2d_init_raster(visual);
     881             :         return GF_TRUE;
     882             : }
     883             : 
     884             : 
     885             : 
     886       21925 : Bool compositor_2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx)
     887             : {
     888             :         u8 alpha = 0xFF;
     889             : 
     890       21925 :         if (!ctx->aspect.fill_texture) return GF_TRUE;
     891       21925 :         if ((ctx->aspect.fill_texture == visual->compositor->passthrough_txh) && visual->compositor->passthrough_inplace)
     892             :                 return GF_TRUE;
     893             :         /*check if texture is ready - if not pretend we drew it*/
     894       21896 :         if (!ctx->aspect.fill_texture->data) return GF_TRUE;
     895       21870 :         if (ctx->transform.m[0]<0) return GF_FALSE;
     896             :         /*check if the <0 value is due to a flip in he scene description or
     897             :         due to bifs<->svg... context switching*/
     898       21870 :         if (ctx->transform.m[4]<0) {
     899          11 :                 if (!(ctx->flags & CTX_FLIPED_COORDS)) return GF_FALSE;
     900             :         } else {
     901       21859 :                 if (ctx->flags & CTX_FLIPED_COORDS) return GF_FALSE;
     902             :         }
     903       21859 :         if (ctx->transform.m[1] || ctx->transform.m[3]) return GF_FALSE;
     904             : #ifndef GPAC_DISABLE_VRML
     905       21599 :         if ((ctx->flags & CTX_HAS_APPEARANCE) && ctx->appear && ((M_Appearance*)ctx->appear)->textureTransform)
     906             :                 return GF_FALSE;
     907             : #endif
     908             : 
     909       20108 :         alpha = GF_COL_A(ctx->aspect.fill_color);
     910             :         /*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/
     911       20108 :         if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color);
     912             : 
     913       20108 :         if (!alpha) return GF_TRUE;
     914             : 
     915       20108 :         switch (ctx->aspect.fill_texture->pixelformat) {
     916           0 :         case GF_PIXEL_YUVD:
     917             :         case GF_PIXEL_RGBD:
     918             :         case GF_PIXEL_RGBDS:
     919             : #ifndef GPAC_DISABLE_3D
     920             :                 /*using OpenGL to render depth images*/
     921           0 :                 if (visual->compositor->depth_gl_type) {
     922           0 :                         gf_sc_set_option(visual->compositor, GF_OPT_USE_OPENGL, 2);
     923           0 :                         return GF_TRUE;
     924             :                 }
     925             : #endif
     926             :                 //fallthrought
     927             :         default:
     928             :                 break;
     929             :         }
     930             : 
     931             :         /*direct drawing, no clippers */
     932       20108 :         if (tr_state->immediate_draw) {
     933         254 :                 if (visual->compositor->video_out->BlitTexture) {
     934           0 :                         if (! visual->compositor->video_out->BlitTexture(visual->compositor->video_out, ctx->aspect.fill_texture, &ctx->transform, &ctx->bi->clip, alpha, tr_state->col_key
     935             : #ifdef GF_SR_USE_DEPTH
     936             :                                 , ctx->depth_offset, ctx->depth_gain
     937             : #else
     938             :                                 , 0, 0
     939             : #endif
     940             :                                                                         ))
     941             :                                 return GF_FALSE;
     942             :                 } else {
     943         254 :                         if (!compositor_2d_draw_bitmap_ex(visual, ctx->aspect.fill_texture, ctx, &ctx->bi->clip, &ctx->bi->unclip, alpha, tr_state, GF_FALSE))
     944             :                                 return GF_FALSE;
     945             :                 }
     946             :         }
     947             :         /*draw bitmap for all dirty rects*/
     948             :         else {
     949             :                 u32 i;
     950             :                 GF_IRect clip;
     951       26780 :                 for (i=0; i<tr_state->visual->to_redraw.count; i++) {
     952             :                         /*there's an opaque region above, don't draw*/
     953             : #ifdef TRACK_OPAQUE_REGIONS
     954             :                         if (tr_state->visual->draw_node_index < tr_state->visual->to_redraw.list[i].opaque_node_index) continue;
     955             : #endif
     956       27014 :                         clip = ctx->bi->clip;
     957       27014 :                         gf_irect_intersect(&clip, &tr_state->visual->to_redraw.list[i].rect);
     958       27014 :                         if (clip.width && clip.height) {
     959       23621 :                                 if (visual->compositor->video_out->BlitTexture) {
     960           0 :                                         if (!visual->compositor->video_out->BlitTexture(visual->compositor->video_out, ctx->aspect.fill_texture, &ctx->transform, &ctx->bi->clip, alpha, tr_state->col_key
     961             : #ifdef GF_SR_USE_DEPTH
     962             :                                                 , ctx->depth_offset, ctx->depth_gain
     963             : #else
     964             :                                                 , 0, 0
     965             : #endif
     966             :                                                                                        ))
     967         234 :                                                 return GF_FALSE;
     968       23621 :                                 } else if (!compositor_2d_draw_bitmap_ex(visual, ctx->aspect.fill_texture, ctx, &clip, &ctx->bi->unclip, alpha, tr_state, GF_FALSE)) {
     969             :                                         return GF_FALSE;
     970             :                                 }
     971             :                         }
     972             :                 }
     973             :         }
     974       19796 :         ctx->aspect.fill_texture->flags |= GF_SR_TEXTURE_USED;
     975       19796 :         return GF_TRUE;
     976             : }
     977             : 
     978             : 
     979         584 : GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor)
     980             : {
     981             :         u32 old_vp_width, old_vp_height;
     982             :         Bool changed = GF_FALSE;
     983             :         Double ratio;
     984             :         GF_Event evt;
     985             :         GF_Err e;
     986             :         Fixed scaleX, scaleY;
     987             : 
     988         584 :         compositor->output_width = compositor->scene_width;
     989         584 :         compositor->output_height = compositor->scene_height;
     990         584 :         compositor->vp_x = compositor->vp_y = 0;
     991             :         scaleX = scaleY = FIX_ONE;
     992             : 
     993         584 :         old_vp_width = compositor->vp_width;
     994         584 :         old_vp_height = compositor->vp_height;
     995             : 
     996             :         /*force complete clean*/
     997         584 :         compositor->traverse_state->invalidate_all = GF_TRUE;
     998             : 
     999         584 :         if (!compositor->has_size_info && !(compositor->override_size_flags & 2) ) {
    1000          28 :                 compositor->output_width = compositor->display_width;
    1001          28 :                 compositor->output_height = compositor->display_height;
    1002          28 :                 compositor->vp_width = compositor->visual->width = compositor->output_width;
    1003          28 :                 compositor->vp_height = compositor->visual->height = compositor->output_height;
    1004             :         } else {
    1005         556 :                 if (compositor->rotate_mode % 2) {
    1006           0 :                         compositor->vp_height = compositor->display_width;
    1007           0 :                         compositor->vp_width = compositor->display_height;
    1008             :                 } else {
    1009         556 :                         compositor->vp_width = compositor->display_width;
    1010         556 :                         compositor->vp_height = compositor->display_height;
    1011             :                 }
    1012             : 
    1013         556 :                 switch (compositor->aspect_ratio) {
    1014             :                 case GF_ASPECT_RATIO_FILL_SCREEN:
    1015             :                         break;
    1016           0 :                 case GF_ASPECT_RATIO_16_9:
    1017           0 :                         compositor->vp_width = compositor->display_width;
    1018           0 :                         compositor->vp_height = 9 * compositor->display_width / 16;
    1019           0 :                         if (compositor->vp_height>compositor->display_height) {
    1020           0 :                                 compositor->vp_height = compositor->display_height;
    1021           0 :                                 compositor->vp_width = 16 * compositor->display_height / 9;
    1022             :                         }
    1023             :                         break;
    1024           0 :                 case GF_ASPECT_RATIO_4_3:
    1025           0 :                         compositor->vp_width = compositor->display_width;
    1026           0 :                         compositor->vp_height = 3 * compositor->display_width / 4;
    1027           0 :                         if (compositor->vp_height>compositor->display_height) {
    1028           0 :                                 compositor->vp_height = compositor->display_height;
    1029           0 :                                 compositor->vp_width = 4 * compositor->display_height / 3;
    1030             :                         }
    1031             :                         break;
    1032         556 :                 default:
    1033         556 :                         ratio = compositor->scene_height;
    1034         556 :                         ratio /= compositor->scene_width;
    1035         556 :                         if (compositor->vp_width * ratio > compositor->vp_height) {
    1036          21 :                                 compositor->vp_width = compositor->vp_height * compositor->scene_width;
    1037          21 :                                 compositor->vp_width /= compositor->scene_height;
    1038             :                         }
    1039             :                         else {
    1040         535 :                                 compositor->vp_height = compositor->vp_width * compositor->scene_height;
    1041         535 :                                 compositor->vp_height /= compositor->scene_width;
    1042             :                         }
    1043             :                         break;
    1044             :                 }
    1045         556 :                 compositor->vp_x = (compositor->display_width - compositor->vp_width) / 2;
    1046         556 :                 compositor->vp_y = (compositor->display_height - compositor->vp_height) / 2;
    1047             : 
    1048         556 :                 scaleX = gf_divfix(INT2FIX(compositor->vp_width), INT2FIX(compositor->scene_width));
    1049         556 :                 if (!scaleX) scaleX = FIX_ONE;
    1050         556 :                 scaleY = gf_divfix(INT2FIX(compositor->vp_height), INT2FIX(compositor->scene_height));
    1051         556 :                 if (!scaleY) scaleY = FIX_ONE;
    1052             : 
    1053         556 :                 if (!compositor->sz) {
    1054           0 :                         compositor->output_width = compositor->scene_width;
    1055           0 :                         compositor->output_height = compositor->scene_height;
    1056           0 :                         compositor->vp_width = FIX2INT(gf_divfix(INT2FIX(compositor->display_width), scaleX));
    1057           0 :                         compositor->vp_height = FIX2INT(gf_divfix(INT2FIX(compositor->display_height), scaleY));
    1058             : 
    1059           0 :                         compositor->vp_x = (compositor->vp_width - compositor->output_width) / 2;
    1060           0 :                         compositor->vp_y = (compositor->vp_height - compositor->output_height) / 2;
    1061             : 
    1062             :                         scaleX = scaleY = FIX_ONE;
    1063             :                 } else {
    1064         556 :                         compositor->output_width = compositor->display_width;
    1065         556 :                         compositor->output_height = compositor->display_height;
    1066         556 :                         compositor->vp_width = compositor->display_width;
    1067         556 :                         compositor->vp_height = compositor->display_height;
    1068             :                 }
    1069         556 :                 compositor->visual->width = compositor->output_width;
    1070         556 :                 compositor->visual->height = compositor->output_height;
    1071             :         }
    1072             : 
    1073             :         /*resize hardware surface*/
    1074             :         memset(&evt, 0, sizeof(GF_Event));
    1075         584 :         evt.type = GF_EVENT_VIDEO_SETUP;
    1076         584 :         evt.setup.width = compositor->vp_width;
    1077         584 :         evt.setup.height = compositor->vp_height;
    1078             :         evt.setup.use_opengl = GF_FALSE;
    1079         584 :         evt.setup.disable_vsync = compositor->bench_mode ? GF_TRUE : GF_FALSE;
    1080             :         /*copy over settings*/
    1081         584 :         evt.setup.system_memory = compositor->video_memory ? GF_FALSE : GF_TRUE;
    1082         584 :         if (compositor->request_video_memory) evt.setup.system_memory = GF_FALSE;
    1083         584 :         compositor->request_video_memory = GF_FALSE;
    1084             : 
    1085             : #ifndef GPAC_DISABLE_3D
    1086         584 :         if (compositor->hybrid_opengl) {
    1087          21 :                 evt.setup.use_opengl = GF_TRUE;
    1088          21 :                 evt.setup.system_memory = GF_FALSE;
    1089          21 :                 evt.setup.back_buffer = GF_TRUE;
    1090             :         }
    1091             : #endif
    1092             : 
    1093         584 :         if (compositor->was_system_memory != evt.setup.system_memory) changed = GF_TRUE;
    1094          90 :         else if (old_vp_width != compositor->vp_width) changed = GF_TRUE;
    1095          88 :         else if (old_vp_height != compositor->vp_height) changed = GF_TRUE;
    1096          87 :         else if (compositor->is_opengl != evt.setup.use_opengl) changed = GF_TRUE;
    1097             : 
    1098             : 
    1099             :         if (changed) {
    1100         497 :                 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring display size %d x %d - opengl %s - use %s memory\n", evt.setup.width, evt.setup.height,
    1101             :                                                      evt.setup.use_opengl ? "yes" : "no", evt.setup.system_memory ? "systems" : "video"
    1102             :                                                     ));
    1103             : 
    1104         497 :                 e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
    1105         497 :                 if (e) {
    1106             : #ifndef GPAC_DISABLE_3D
    1107           0 :                         if (!compositor->hybrid_opengl) {
    1108           0 :                                 compositor->hybrid_opengl = GF_TRUE;
    1109           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Failed to configure 2D output (%s) - retrying in OpenGL mode\n", gf_error_to_string(e) ));
    1110           0 :                                 return compositor_2d_set_aspect_ratio(compositor);
    1111             :                         }
    1112             : #endif
    1113           0 :                         compositor->video_setup_failed = GF_TRUE;
    1114             :                         memset(&evt, 0, sizeof(GF_Event));
    1115           0 :                         evt.type = GF_EVENT_QUIT;
    1116           0 :                         evt.message.error = e;
    1117           0 :                         evt.message.message = "Cannot setup video output";
    1118           0 :                         gf_sc_send_event(compositor, &evt);
    1119           0 :                         return e;
    1120             :                 }
    1121             : 
    1122         497 :                 compositor->is_opengl = evt.setup.use_opengl;
    1123         497 :                 compositor->was_system_memory = evt.setup.system_memory;
    1124             : 
    1125         497 :                 if (evt.setup.use_opengl) {
    1126          21 :                         gf_opengl_init();
    1127             :                 }
    1128             :         }
    1129         584 :         if (compositor->has_size_info) {
    1130         556 :                 compositor->traverse_state->vp_size.x = INT2FIX(compositor->scene_width);
    1131         556 :                 compositor->traverse_state->vp_size.y = INT2FIX(compositor->scene_height);
    1132             :         } else {
    1133          28 :                 compositor->traverse_state->vp_size.x = INT2FIX(compositor->output_width);
    1134          28 :                 compositor->traverse_state->vp_size.y = INT2FIX(compositor->output_height);
    1135             :         }
    1136         584 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Reconfigured display size %d x %d done\n", evt.setup.width, evt.setup.height));
    1137             : 
    1138             :         /*set scale factor*/
    1139         584 :         compositor_set_ar_scale(compositor, scaleX, scaleY);
    1140         584 :         return GF_OK;
    1141             : }
    1142             : 
    1143         682 : void compositor_send_resize_event(GF_Compositor *compositor, GF_SceneGraph *subscene, Fixed old_z, Fixed old_tx, Fixed old_ty, Bool is_resize)
    1144             : {
    1145             : #ifndef GPAC_DISABLE_SVG
    1146             :         GF_DOM_Event evt;
    1147             :         u32 i;
    1148         682 :         GF_SceneGraph *scene = (subscene ? subscene : compositor->scene);
    1149         682 :         GF_Node *root = gf_sg_get_root_node(scene);
    1150             :         /*if root node is not DOM, sent a resize event (for VRML/BIFS). Otherwise this must be handled
    1151             :         by the composition code of the node*/
    1152         682 :         if (!root || (gf_node_get_tag(root) > GF_NODE_RANGE_LAST_VRML) )
    1153          28 :                 return;
    1154             : 
    1155             :         memset(&evt, 0, sizeof(GF_DOM_Event));
    1156         654 :         evt.prev_scale = compositor->scale_x*old_z;
    1157         654 :         evt.new_scale = compositor->scale_x*compositor->zoom;
    1158         654 :         evt.bubbles = 1;
    1159             : 
    1160         654 :         if (is_resize) {
    1161         641 :                 evt.type = GF_EVENT_RESIZE;
    1162         641 :                 if (subscene == NULL) {
    1163         641 :                         evt.screen_rect.width = INT2FIX(compositor->display_width);
    1164         641 :                         evt.screen_rect.height = INT2FIX(compositor->display_height);
    1165             :                 } else {
    1166             :                         u32 w, h;
    1167           0 :                         gf_sg_get_scene_size_info(scene, &w, &h);
    1168           0 :                         evt.screen_rect.width = INT2FIX(w);
    1169           0 :                         evt.screen_rect.height = INT2FIX(h);
    1170             :                 }
    1171          13 :         } else if (evt.prev_scale == evt.new_scale) {
    1172             :                 /*cannot get params for scroll events*/
    1173          13 :                 evt.type = GF_EVENT_SCROLL;
    1174             :         } else {
    1175           0 :                 evt.screen_rect.x = INT2FIX(compositor->vp_x);
    1176           0 :                 evt.screen_rect.y = INT2FIX(compositor->vp_y);
    1177           0 :                 evt.screen_rect.width = INT2FIX(compositor->output_width);
    1178           0 :                 evt.screen_rect.height = INT2FIX(compositor->output_height);
    1179           0 :                 evt.prev_translate.x = old_tx;
    1180           0 :                 evt.prev_translate.y = old_ty;
    1181           0 :                 evt.new_translate.x = compositor->trans_x;
    1182           0 :                 evt.new_translate.y = compositor->trans_y;
    1183           0 :                 evt.type = GF_EVENT_ZOOM;
    1184           0 :                 evt.bubbles = 0;
    1185             :         }
    1186         654 :         gf_dom_event_fire(gf_sg_get_root_node(scene), &evt);
    1187             : 
    1188         654 :         i=0;
    1189        1308 :         while ((scene = (GF_SceneGraph*)gf_list_enum(compositor->extra_scenes, &i))) {
    1190           0 :                 gf_dom_event_fire(gf_sg_get_root_node(scene), &evt);
    1191             :         }
    1192             : 
    1193             : #endif
    1194             : }
    1195        3064 : void compositor_2d_set_user_transform(GF_Compositor *compositor, Fixed zoom, Fixed tx, Fixed ty, Bool is_resize)
    1196             : {
    1197             :         Fixed ratio;
    1198             :         Fixed old_tx, old_ty, old_z;
    1199             : 
    1200        3064 :         gf_sc_lock(compositor, GF_TRUE);
    1201             :         old_tx = tx;
    1202             :         old_ty = ty;
    1203        3064 :         old_z = compositor->zoom;
    1204             : 
    1205        3064 :         if (zoom <= 0) zoom = FIX_ONE/1000;
    1206        3064 :         compositor->trans_x = tx;
    1207        3064 :         compositor->trans_y = ty;
    1208             : 
    1209        3064 :         if (zoom != compositor->zoom) {
    1210           0 :                 ratio = gf_divfix(zoom, compositor->zoom);
    1211           0 :                 compositor->trans_x = gf_mulfix(compositor->trans_x, ratio);
    1212           0 :                 compositor->trans_y = gf_mulfix(compositor->trans_y, ratio);
    1213           0 :                 compositor->zoom = zoom;
    1214           0 :                 compositor->zoom_changed = GF_TRUE;
    1215             : 
    1216             :                 /*recenter visual*/
    1217           0 :                 if (!compositor->visual->center_coords) {
    1218             :                         Fixed c_x, c_y, nc_x, nc_y;
    1219           0 :                         c_x = INT2FIX(compositor->display_width/2);
    1220           0 :                         c_y = INT2FIX(compositor->display_height/2);
    1221           0 :                         nc_x = gf_mulfix(c_x, ratio);
    1222           0 :                         nc_y = gf_mulfix(c_y, ratio);
    1223           0 :                         compositor->trans_x -= (nc_x-c_x);
    1224           0 :                         compositor->trans_y -= (nc_y-c_y);
    1225             :                 }
    1226             :         }
    1227        6128 :         gf_mx2d_init(compositor->traverse_state->transform);
    1228             : 
    1229        3064 :         switch (compositor->rotate_mode) {
    1230           0 :         case 1:
    1231           0 :                 gf_mx2d_add_rotation(&compositor->traverse_state->transform, 0, 0, -GF_PI/2);
    1232           0 :                 break;
    1233           0 :         case 2:
    1234           0 :                 gf_mx2d_add_scale(&compositor->traverse_state->transform, -1, -1);
    1235           0 :                 break;
    1236           0 :         case 3:
    1237           0 :                 gf_mx2d_add_rotation(&compositor->traverse_state->transform, 0, 0, GF_PI/2);
    1238           0 :                 break;
    1239             :         }
    1240             : 
    1241        3064 :         gf_mx2d_add_scale(&compositor->traverse_state->transform, gf_mulfix(compositor->zoom,compositor->scale_x), gf_mulfix(compositor->zoom,compositor->scale_y));
    1242             : 
    1243        3064 :         gf_mx2d_add_translation(&compositor->traverse_state->transform, compositor->trans_x, compositor->trans_y);
    1244        3064 :         if (compositor->rotation) gf_mx2d_add_rotation(&compositor->traverse_state->transform, 0, 0, compositor->rotation);
    1245             : 
    1246        3064 :         if (!compositor->visual->center_coords) {
    1247          84 :                 gf_mx2d_add_translation(&compositor->traverse_state->transform, INT2FIX(compositor->vp_x), INT2FIX(compositor->vp_y));
    1248             :         }
    1249             : 
    1250        3064 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Changing Zoom (%g) and Pan (%g %g)\n", FIX2FLT(compositor->zoom), FIX2FLT(compositor->trans_x) , FIX2FLT(compositor->trans_y)));
    1251             : 
    1252             : 
    1253        3064 :         gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
    1254        3064 :         compositor->traverse_state->invalidate_all = GF_TRUE;
    1255             : 
    1256             :         /*for zoom&pan, send the event right away. For resize/scroll, wait for the frame to be drawn before sending it
    1257             :         otherwise viewport info of SVG nodes won't be correct*/
    1258        3064 :         if (!is_resize) compositor_send_resize_event(compositor, NULL, old_z, old_tx, old_ty, GF_FALSE);
    1259        3064 :         gf_sc_lock(compositor, GF_FALSE);
    1260        3064 : }
    1261             : 
    1262             : 
    1263             : 
    1264        1962 : GF_Rect compositor_2d_update_clipper(GF_TraverseState *tr_state, GF_Rect this_clip, Bool *need_restore, GF_Rect *original, Bool for_layer)
    1265             : {
    1266             :         GF_Rect clip, orig;
    1267        1962 :         if (for_layer) {
    1268         805 :                 orig = tr_state->layer_clipper;
    1269         805 :                 *need_restore = tr_state->has_layer_clip;
    1270             :         } else {
    1271        1157 :                 orig = tr_state->clipper;
    1272        1157 :                 *need_restore = tr_state->has_clip;
    1273             :         }
    1274        1962 :         *original = orig;
    1275             : 
    1276        1962 :         clip = this_clip;
    1277        1962 :         if (*need_restore) {
    1278             : #ifndef GPAC_DISABLE_3D
    1279         159 :                 if (tr_state->visual->type_3d) {
    1280             :                         GF_Matrix mx;
    1281         157 :                         gf_mx_copy(mx, tr_state->model_matrix);
    1282         157 :                         gf_mx_inverse(&mx);
    1283         157 :                         gf_mx_apply_rect(&mx, &orig);
    1284         157 :                         gf_mx_apply_rect(&tr_state->layer_matrix, &orig);
    1285             :                 } else
    1286             : #endif
    1287             :                 {
    1288             :                         GF_Matrix2D mx2d;
    1289           2 :                         gf_mx2d_copy(mx2d, tr_state->transform);
    1290           2 :                         gf_mx2d_inverse(&mx2d);
    1291           2 :                         gf_mx2d_apply_rect(&mx2d, &orig);
    1292             :                 }
    1293             : 
    1294         159 :                 if (clip.x < orig.x) {
    1295         151 :                         clip.width -= (orig.x - clip.x);
    1296             :                         clip.x = orig.x;
    1297             :                 }
    1298         159 :                 if (clip.x + clip.width > orig.x + orig.width) {
    1299           0 :                         clip.width = orig.x + orig.width - clip.x;
    1300             :                 }
    1301         159 :                 if (clip.y > orig.y) {
    1302           0 :                         clip.height -= (clip.y - orig.y);
    1303             :                         clip.y = orig.y;
    1304             :                 }
    1305         159 :                 if (clip.y - clip.height < orig.y - orig.height) {
    1306           0 :                         clip.height = clip.y - orig.y + orig.height;
    1307             :                 }
    1308             :         }
    1309        1962 :         if (for_layer) {
    1310         805 :                 tr_state->layer_clipper = clip;
    1311         805 :                 tr_state->has_layer_clip = GF_TRUE;
    1312             : #ifndef GPAC_DISABLE_3D
    1313         805 :                 if (tr_state->visual->type_3d) {
    1314         805 :                         gf_mx_copy(tr_state->layer_matrix, tr_state->model_matrix);
    1315             :                 }
    1316             : #endif
    1317             :         } else {
    1318        1157 :                 tr_state->clipper = clip;
    1319             : #ifndef GPAC_DISABLE_3D
    1320        1157 :                 if (tr_state->visual->type_3d) {
    1321             :                         /*retranslate to world coords*/
    1322         300 :                         gf_mx_apply_rect(&tr_state->model_matrix, &tr_state->clipper);
    1323             :                         /*if 2D, also update with user zoom and translation*/
    1324         300 :                         if (!tr_state->camera->is_3D)
    1325         300 :                                 gf_mx_apply_rect(&tr_state->camera->modelview, &tr_state->clipper);
    1326             :                 } else
    1327             : #endif
    1328             : 
    1329         857 :                         gf_mx2d_apply_rect(&tr_state->transform, &tr_state->clipper);
    1330             : 
    1331        1157 :                 tr_state->has_clip = GF_TRUE;
    1332             :         }
    1333        1962 :         return clip;
    1334             : }
    1335             : 
    1336             : 
    1337             : /*overlay management*/
    1338      117729 : Bool visual_2d_overlaps_overlay(GF_VisualManager *visual, DrawableContext *ctx, GF_TraverseState *tr_state)
    1339             : {
    1340             :         u32 res = 0;
    1341             :         GF_OverlayStack *ol;
    1342      117729 :         GF_Compositor *compositor = visual->compositor;
    1343      117729 :         if (compositor->visual != visual) return GF_FALSE;
    1344             : 
    1345      116157 :         ol = visual->overlays;
    1346      232314 :         while (ol) {
    1347             :                 u32 i;
    1348             :                 GF_IRect clip;
    1349           0 :                 if (ctx == ol->ctx) {
    1350           0 :                         ol = ol->next;
    1351           0 :                         continue;
    1352             :                 }
    1353           0 :                 clip = ctx->bi->clip;
    1354           0 :                 if (!ol->ra.count && !gf_irect_overlaps(&ol->ctx->bi->clip, &clip)) {
    1355           0 :                         ol = ol->next;
    1356           0 :                         continue;
    1357             :                 }
    1358             :                 /*check previsously drawn areas*/
    1359           0 :                 for (i=0; i<ol->ra.count; i++) {
    1360             :                         /*we have drawn something here, don't draw*/
    1361           0 :                         if (gf_irect_inside(&ol->ra.list[i].rect, &clip))
    1362             :                                 break;
    1363             :                 }
    1364           0 :                 res++;
    1365           0 :                 if (i<ol->ra.count) {
    1366           0 :                         ol = ol->next;
    1367           0 :                         continue;
    1368             :                 }
    1369             : 
    1370             :                 /*note that we add the entire cliper, not the intersection with the overlay one. This is a simple way
    1371             :                 to handle the case where Drawble2 overlaps Drawable1 overlaps Overlay but Drawable2 doesn't overlaps Overlay
    1372             :                 by adding the entire drawable cliper, we will postpone drawing of all interconnected regions touching the overlay*/
    1373           0 :                 ra_union_rect(&ol->ra, &clip);
    1374           0 :                 ol = ol->next;
    1375             :         }
    1376      116157 :         return res ? GF_TRUE : GF_FALSE;
    1377             : }
    1378             : 
    1379       15811 : void visual_2d_flush_overlay_areas(GF_VisualManager *visual, GF_TraverseState *tr_state)
    1380             : {
    1381             :         DrawableContext *ctx;
    1382             :         GF_OverlayStack *ol;
    1383       15811 :         GF_Compositor *compositor = visual->compositor;
    1384       15811 :         if (compositor->visual != visual) return;
    1385             : 
    1386             :         /*draw all overlays*/
    1387       14819 :         tr_state->traversing_mode = TRAVERSE_DRAW_2D;
    1388       14819 :         ol = visual->overlays;
    1389       29638 :         while (ol) {
    1390             :                 u32 i;
    1391             :                 Bool needs_draw = GF_TRUE;
    1392             :                 GF_IRect the_clip, vid_clip;
    1393             : 
    1394           0 :                 ra_refresh(&ol->ra);
    1395             : 
    1396           0 :                 for (i=0; i<ol->ra.count; i++) {
    1397           0 :                         the_clip = ol->ra.list[i].rect;
    1398             : 
    1399             :                         /*draw all objects above this overlay*/
    1400           0 :                         ctx = ol->ctx->next;
    1401           0 :                         while (ctx && ctx->drawable) {
    1402           0 :                                 if (gf_irect_overlaps(&ctx->bi->clip, &the_clip)) {
    1403           0 :                                         GF_IRect prev_clip = ctx->bi->clip;
    1404             : 
    1405           0 :                                         if (needs_draw) {
    1406             :                                                 /*if first object above is not transparent and completely covers the overlay skip video redraw*/
    1407           0 :                                                 if ((ctx->flags & CTX_IS_TRANSPARENT) || !gf_irect_inside(&prev_clip, &the_clip)) {
    1408           0 :                                                         vid_clip = ol->ra.list[i].rect;
    1409           0 :                                                         gf_irect_intersect(&vid_clip, &ol->ctx->bi->clip);
    1410           0 :                                                         compositor_2d_draw_bitmap_ex(visual, ol->ctx->aspect.fill_texture, ol->ctx, &vid_clip, &ol->ctx->bi->unclip, 0xFF, tr_state, GF_TRUE);
    1411             :                                                 }
    1412             :                                                 needs_draw = GF_FALSE;
    1413             :                                         }
    1414           0 :                                         gf_irect_intersect(&ctx->bi->clip, &the_clip);
    1415           0 :                                         tr_state->ctx = ctx;
    1416             : 
    1417           0 :                                         if (ctx->drawable->flags & DRAWABLE_USE_TRAVERSE_DRAW) {
    1418           0 :                                                 gf_node_traverse(ctx->drawable->node, tr_state);
    1419             :                                         } else {
    1420           0 :                                                 drawable_draw(ctx->drawable, tr_state);
    1421             :                                         }
    1422           0 :                                         ctx->bi->clip = prev_clip;
    1423             :                                 }
    1424           0 :                                 ctx = ctx->next;
    1425             :                         }
    1426             :                 }
    1427           0 :                 ol = ol->next;
    1428             :         }
    1429             : }
    1430             : 
    1431       26387 : void visual_2d_draw_overlays(GF_VisualManager *visual)
    1432             : {
    1433             :         GF_Err e;
    1434             :         GF_TextureHandler *txh;
    1435             :         GF_VideoSurface video_src;
    1436             : 
    1437           0 :         while (1) {
    1438       26387 :                 GF_OverlayStack *ol = visual->overlays;
    1439       52774 :                 if (!ol) return;
    1440           0 :                 visual->overlays = ol->next;
    1441             : 
    1442           0 :                 txh = ol->ctx->aspect.fill_texture;
    1443             :                 memset(&video_src, 0, sizeof(GF_VideoSurface));
    1444           0 :                 video_src.height = txh->height;
    1445           0 :                 video_src.width = txh->width;
    1446             :                 video_src.pitch_x = 0;
    1447           0 :                 video_src.pitch_y = txh->stride;
    1448           0 :                 video_src.pixel_format = txh->pixelformat;
    1449           0 :                 video_src.video_buffer = txh->data;
    1450             : 
    1451           0 :                 e = visual->compositor->video_out->Blit(visual->compositor->video_out, &video_src, &ol->src, &ol->dst, 2);
    1452           0 :                 if (e) GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Visual2D] Error %s during overlay update\n", gf_error_to_string(e) ));
    1453             : 
    1454           0 :                 ra_del(&ol->ra);
    1455           0 :                 gf_free(ol);
    1456             :         }
    1457             : }
    1458             : 
    1459         605 : void compositor_2d_init_callbacks(GF_Compositor *compositor)
    1460             : {
    1461         605 :         compositor->visual->DrawBitmap = compositor_2d_draw_bitmap;
    1462         605 : }

Generated by: LCOV version 1.13