Beispiel #1
0
void group_cache_del(GroupCache *cache)
{
	drawable_del(cache->drawable);
	if (cache->txh.data) gf_free(cache->txh.data);
	gf_sc_texture_release(&cache->txh);
	gf_sc_texture_destroy(&cache->txh);
	gf_free(cache);
}
Beispiel #2
0
GF_EXPORT
void gf_sc_texture_destroy(GF_TextureHandler *txh)
{
	GF_Compositor *compositor = txh->compositor;
	Bool lock = gf_mx_try_lock(compositor->mx);

	gf_sc_texture_release(txh);
	if (txh->is_open) gf_sc_texture_stop(txh);
	gf_list_del_item(txh->compositor->textures, txh);

	if (lock) gf_mx_v(compositor->mx);
}
Beispiel #3
0
GF_EXPORT
GF_Err gf_sc_texture_open(GF_TextureHandler *txh, MFURL *url, Bool lock_scene_timeline)
{
	if (txh->is_open) return GF_BAD_PARAM;

	/*if existing texture in cache destroy it - we don't destroy it on stop to handle MovieTexture*/
	if (txh->tx_io) gf_sc_texture_release(txh);

	/*get media object*/
	txh->stream = gf_mo_register(txh->owner, url, lock_scene_timeline, 0);
	/*bad/Empty URL*/
	if (!txh->stream) return GF_NOT_SUPPORTED;

	return GF_OK;
}
Beispiel #4
0
GF_EXPORT
GF_Err gf_sc_texture_play_from_to(GF_TextureHandler *txh, MFURL *url, Double start_offset, Double end_offset, Bool can_loop, Bool lock_scene_timeline)
{
	if (txh->is_open) return GF_BAD_PARAM;

	/*if existing texture in cache destroy it - we don't destroy it on stop to handle MovieTexture*/
	if (txh->tx_io) gf_sc_texture_release(txh);

	/*get media object*/
	txh->stream = gf_mo_register(txh->owner, url, lock_scene_timeline, 0);
	/*bad/Empty URL*/
	if (!txh->stream) return GF_NOT_SUPPORTED;
	/*request play*/
	gf_mo_play(txh->stream, start_offset, end_offset, can_loop);

	txh->last_frame_time = (u32) (-1);
	//gf_sc_invalidate(txh->compositor, NULL);
	txh->is_open = 1;
	return GF_OK;
}
Beispiel #5
0
static void svg_traverse_filter(GF_Node *node, void *rs, Bool is_destroy)
{
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	GF_FilterStack *st = gf_node_get_private(node);
	if (is_destroy) {
		drawable_del(st->drawable);
		if (st->data) gf_free(st->data);
		st->txh.data = NULL;
		gf_sc_texture_release(&st->txh);
		gf_sc_texture_destroy(&st->txh);
		gf_free(st);
		return;
	}

	if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) {
		if (! tr_state->visual->DrawBitmap(tr_state->visual, tr_state, tr_state->ctx, NULL)) {
			visual_2d_texture_path(tr_state->visual, st->drawable->path, tr_state->ctx, tr_state);
		}
	}
}
static void composite_update(GF_TextureHandler *txh)
{
	s32 w, h;
	GF_STENCIL stencil;
	M_Background2D *back;
	GF_TraverseState *tr_state;
	Bool invalidate_all;
	u32 new_pixel_format;
	GF_Compositor *compositor = (GF_Compositor *)txh->compositor;
	CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(txh->owner);
	GF_Raster2D *raster = st->visual->compositor->rasterizer;

	if (st->unsupported) return;


/*
	if (compositor->recompute_ar) {
		gf_node_dirty_set(txh->owner, 0, 0);
		return;
	}
*/
	if (!compositor->rebuild_offscreen_textures && (!compositor->text_edit_changed || !st->visual->has_text_edit ) && !gf_node_dirty_get(txh->owner)) {
		txh->needs_refresh = 0;
		return;
	}
	gf_node_dirty_clear(st->txh.owner, 0);

	new_pixel_format = 0;
	back = gf_list_get(st->visual->back_stack, 0);
	if (back && back->isBound) new_pixel_format = GF_PIXEL_RGB_24;
	else new_pixel_format = GF_PIXEL_RGBA;


#ifdef GPAC_USE_TINYGL
	/*TinyGL pixel format is fixed at compile time, we cannot override it !*/
	if (st->visual->type_3d) new_pixel_format = GF_PIXEL_RGBA;
#else

#ifndef GPAC_DISABLE_3D
	/*no alpha support in offscreen rendering*/
	if ( (st->visual->type_3d) && !(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA))
		new_pixel_format = GF_PIXEL_RGB_24;
#endif

	/*in OpenGL_ES, only RGBA can be safelly used with glReadPixels*/
#ifdef GPAC_USE_OGL_ES
	new_pixel_format = GF_PIXEL_RGBA;
#endif

#endif

	/*FIXME - we assume RGB+Depth+bitshape, we should check with the video out module*/
#if defined(GF_SR_USE_DEPTH) && !defined(GPAC_DISABLE_3D)
	if (st->visual->type_3d && (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_DEPTH) ) new_pixel_format = GF_PIXEL_RGBDS;
#endif


#ifndef GPAC_DISABLE_3D
	if (st->visual->type_3d>1) {
		w = ((M_CompositeTexture3D*)txh->owner)->pixelWidth;
		h = ((M_CompositeTexture3D*)txh->owner)->pixelHeight;
	} else
#endif
	{
		w = ((M_CompositeTexture2D*)txh->owner)->pixelWidth;
		h = ((M_CompositeTexture2D*)txh->owner)->pixelHeight;
	}

	/*internal GPAC hacks for testing color spaces*/
	if (w<-1) {
		w = -w;
		if (h<0) {
			h = -h;
			if (new_pixel_format==GF_PIXEL_RGBA) {
				new_pixel_format=GF_PIXEL_ARGB;
			} else {
				new_pixel_format=GF_PIXEL_BGR_24;
			}
		} else {
			if (new_pixel_format==GF_PIXEL_RGB_24) {
				new_pixel_format=GF_PIXEL_RGB_32;
			}
		}
	}
	else if (h<-1) {
		h = -h;
		if (new_pixel_format==GF_PIXEL_RGB_24) {
			new_pixel_format=GF_PIXEL_RGB_32;
		}
	}

	if (w<0) w = 0;
	if (h<0) h = 0;


	if (!w || !h) {
		if (txh->tx_io) {
#ifdef GPAC_USE_TINYGL
			if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
#endif
			gf_sc_texture_release(txh);
			if (txh->data) gf_free(txh->data);
			txh->data = NULL;
			txh->width = txh->height = txh->stride = 0;
		}
		return;
	}
	invalidate_all = compositor->rebuild_offscreen_textures;

	/*rebuild stencil*/
	if (!txh->tx_io
		|| (w != (s32) txh->width) || ( h != (s32) txh->height)
		|| (new_pixel_format != txh->pixelformat)
		) {

		Bool needs_stencil = 1;
		if (txh->tx_io) {
#ifdef GPAC_USE_TINYGL
			if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
#endif
			gf_sc_texture_release(txh);
			if (txh->data) 
				gf_free(txh->data);
			txh->data = NULL;
		}

		/*we don't use rect ext because of no support for texture transforms*/
		if (1
#ifndef GPAC_DISABLE_3D
			|| compositor->gl_caps.npot_texture
#endif
			) {
			st->txh.width = w;
			st->txh.height = h;
			st->sx = st->sy = FIX_ONE;
		} else {
			st->txh.width = 2;
			while (st->txh.width<(u32)w) st->txh.width*=2;
			st->txh.height = 2;
			while (st->txh.height<(u32)h) st->txh.height*=2;

			st->sx = INT2FIX(st->txh.width) / w;
			st->sy = INT2FIX(st->txh.height) / h;
		}

		gf_sc_texture_allocate(txh);
		txh->pixelformat = new_pixel_format;
		switch (new_pixel_format) {
		case GF_PIXEL_RGBA:
		case GF_PIXEL_ARGB:
			txh->stride = txh->width * 4;
			txh->transparent = 1;
			break;
		case GF_PIXEL_RGB_565:
			txh->stride = txh->width * 2;
			txh->transparent = 0;
			break;
		case GF_PIXEL_RGBDS:
			txh->stride = txh->width * 4;
			txh->transparent = 1;
			break;
		case GF_PIXEL_RGB_24:
			txh->stride = txh->width * 3;
			txh->transparent = 0;
			break;
		}

		st->visual->width = txh->width;
		st->visual->height = txh->height;

		stencil = raster->stencil_new(raster, GF_STENCIL_TEXTURE);
		/*TODO - add support for compositeTexture3D when root is 2D visual*/
#ifndef GPAC_DISABLE_3D
		if (st->visual->type_3d) {
			GF_Compositor *compositor = st->visual->compositor;
			/*figure out what to do if main visual (eg video out) is not in OpenGL ...*/
			if (!compositor->visual->type_3d) {
				/*create an offscreen window for OpenGL rendering*/
				if ((compositor->offscreen_width < st->txh.width) || (compositor->offscreen_height < st->txh.height)) {
#ifndef GPAC_USE_TINYGL
					GF_Err e;
					GF_Event evt;
					compositor->offscreen_width = MAX(compositor->offscreen_width, st->txh.width);
					compositor->offscreen_height = MAX(compositor->offscreen_height, st->txh.height);

					evt.type = GF_EVENT_VIDEO_SETUP;
					evt.setup.width = compositor->offscreen_width;
					evt.setup.height = compositor->offscreen_height;
					evt.setup.back_buffer = 0;
					evt.setup.opengl_mode = 2;
					e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
					if (e) {
						gf_sc_texture_release(txh);
						st->unsupported = 1;
						return;
					}
					/*reload openGL ext*/
					gf_sc_load_opengl_extensions(compositor, 1);
#endif
				}
			} else {
				needs_stencil = 0;
			}
		}
#endif

		if (needs_stencil) {
			txh->data = (char*)gf_malloc(sizeof(unsigned char) * txh->stride * txh->height);
			memset(txh->data, 0, sizeof(unsigned char) * txh->stride * txh->height);
			
			/*set stencil texture - we don't check error as an image could not be supported by the rasterizer
			but still supported by the blitter (case of RGBD/RGBDS)*/
			raster->stencil_set_texture(stencil, txh->data, txh->width, txh->height, txh->stride, txh->pixelformat, txh->pixelformat, 0);

#ifdef GPAC_USE_TINYGL
			if (st->visual->type_3d && !compositor->visual->type_3d) {
				st->tgl_ctx = ostgl_create_context(txh->width, txh->height, txh->transparent ? 32 : 24, &txh->data, 1);
				GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Creating TinyGL Offscreen context %p (%d %d - pf %s)\n", st->tgl_ctx, txh->width, txh->width, gf_4cc_to_str(txh->pixelformat)));
			}
#endif

		}
		invalidate_all = 1;
		gf_sc_texture_set_stencil(txh, stencil);
	}
	if (!txh->tx_io) return;

	stencil = gf_sc_texture_get_stencil(txh);
	if (!stencil) return;

#ifdef GPAC_USE_TINYGL
	if (st->tgl_ctx) ostgl_make_current(st->tgl_ctx, 0);
#endif

	GF_SAFEALLOC(tr_state, GF_TraverseState);
	tr_state->vrml_sensors = gf_list_new();
	tr_state->visual = st->visual;
	tr_state->invalidate_all = invalidate_all;

	tr_state->immediate_draw = st->visual->compositor->traverse_state->immediate_draw;

	gf_mx2d_init(tr_state->transform);
	gf_cmx_init(&tr_state->color_mat);

	tr_state->backgrounds = st->visual->back_stack;
	tr_state->viewpoints = st->visual->view_stack;
	tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(st->txh.owner));
	tr_state->min_hsize = INT2FIX( MIN(txh->width, txh->height) ) / 2;
	tr_state->vp_size.x = INT2FIX(txh->width);
	tr_state->vp_size.y = INT2FIX(txh->height);

	composite_do_bindable(st->txh.owner, tr_state, st->first);
	st->first = 0;

	GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Entering draw cycle\n"));

	txh->needs_refresh = visual_draw_frame(st->visual, st->txh.owner, tr_state, 0);
	txh->transparent = (st->visual->last_had_back==2) ? 0 : 1;


	if (!compositor->edited_text && st->visual->has_text_edit) 
		st->visual->has_text_edit = 0;


	/*set active viewport in image coordinates top-left=(0, 0), not in BIFS*/
	if (0 && gf_list_count(st->visual->view_stack)) {
		M_Viewport *vp = (M_Viewport *)gf_list_get(st->visual->view_stack, 0);

		if (vp->isBound) {
			SFVec2f size = vp->size;
			if (size.x >=0 && size.y>=0) {
				/*FIXME - we need tracking of VP changes*/
				txh->needs_refresh = 1;
			}
		}
	}

	if (txh->needs_refresh) {
#ifndef GPAC_DISABLE_3D
		if (st->visual->camera.is_3D) {
			if (st->visual->compositor->visual->type_3d) {
#ifndef GPAC_USE_TINYGL
				gf_sc_copy_to_texture(&st->txh);
#else
				/*in TinyGL we only need to push associated bitmap to the texture*/
				gf_sc_texture_push_image(&st->txh, 0, 0);
#endif
			} else {

#ifndef GPAC_USE_TINYGL
				gf_sc_copy_to_stencil(&st->txh);

#else

				if (txh->pixelformat==GF_PIXEL_RGBDS) gf_get_tinygl_depth(&st->txh);
#endif
			}
		} else
#endif
		{
			if (raster->stencil_texture_modified) raster->stencil_texture_modified(stencil);
			gf_sc_texture_set_stencil(txh, stencil);
		}
		gf_sc_invalidate(st->txh.compositor, NULL);
	}
	gf_list_del(tr_state->vrml_sensors);
	gf_free(tr_state);
	GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Leaving draw cycle\n"));
}
Beispiel #7
0
GF_EXPORT
void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync)
{
	Bool needs_reload = 0;
	u32 size, ts;
	s32 ms_until_pres, ms_until_next;

	/*already refreshed*/
	if (txh->needs_refresh) return;

	if (!txh->stream) {
		txh->data = NULL;
		return;
	}

	/*should never happen!!*/
	if (txh->needs_release) gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);

	/*check init flag*/
	if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) {
		needs_reload = 1;
		txh->data = NULL;
		if (txh->tx_io) {
			gf_sc_texture_release(txh);
		}
	}
	txh->data = gf_mo_fetch_data(txh->stream, !disable_resync, &txh->stream_finished, &ts, &size, &ms_until_pres, &ms_until_next);

	if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) {
		needs_reload = 1;
	} else if (size && txh->size && (size != txh->size)) {
		needs_reload = 1;
	}

	if (needs_reload) {
		/*if we had a texture this means the object has changed - delete texture and resetup. Do not skip
		texture update as this may lead to an empty rendering pass (blank frame for this object), especially in DASH*/
		if (txh->tx_io) {
			gf_sc_texture_release(txh);
			txh->needs_refresh = 1;
		}
		if (gf_mo_is_private_media(txh->stream)) {
			setup_texture_object(txh, 1);
			gf_node_dirty_set(txh->owner, 0, 0);
		}
	}

	/*if no frame or muted don't draw*/
	if (!txh->data || !size) {
		GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("|Visual Texture] No output frame available \n"));
		/*TODO - check if this is needed */
		if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) {
			//txh->needs_refresh = 1;
			gf_sc_invalidate(txh->compositor, NULL);
		}
		return;
	}

	/*if setup and same frame return*/
	if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) {
		gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);
		txh->needs_release = 0;
		if (!txh->stream_finished) {
			if (ms_until_next>0 && (txh->compositor->next_frame_delay > (u32) ms_until_next))
				txh->compositor->next_frame_delay = ms_until_next;
		}
		return;
	}
	txh->needs_release = 1;
	txh->last_frame_time = ts;
	txh->size = size;
	if (txh->raw_memory) {
		gf_mo_get_raw_image_planes(txh->stream, (u8 **) &txh->data, (u8 **) &txh->pU, (u8 **) &txh->pV);
	}
	if (gf_mo_is_muted(txh->stream)) return;


	if (txh->nb_frames) {
		s32 push_delay = txh->upload_time / txh->nb_frames;
		if (push_delay > ms_until_pres) ms_until_pres = 0;
		else ms_until_pres -= push_delay;
	}

	if (txh->compositor->frame_delay < ms_until_pres)
		txh->compositor->frame_delay = ms_until_pres;

	txh->compositor->next_frame_delay = 1;

	if (!txh->tx_io) {
		setup_texture_object(txh, 0);
	}

	/*try to push texture on graphics but don't complain if failure*/
	gf_sc_texture_set_data(txh);

	txh->needs_refresh = 1;
	gf_sc_invalidate(txh->compositor, NULL);
}
Beispiel #8
0
GF_EXPORT
void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync)
{
	u32 size, ts;

	/*already refreshed*/
	if (txh->needs_refresh) return;

	if (!txh->stream) {
		txh->data = NULL;
		return;
	}

	/*should never happen!!*/
	if (txh->needs_release) gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);

	/*check init flag*/
	if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) {
		/*if we had a texture this means the object has changed - delete texture and force next frame 
		composition (this will take care of OD reuse)*/
		if (txh->tx_io) {
			gf_sc_texture_release(txh);
			txh->data = NULL;
			txh->needs_refresh = 1;
			gf_sc_invalidate(txh->compositor, NULL);
			return;
		}
		if (gf_mo_is_private_media(txh->stream)) {
			setup_texture_object(txh, 1);
			gf_node_dirty_set(txh->owner, 0, 0);
		}
	}
	txh->data = gf_mo_fetch_data(txh->stream, !disable_resync, &txh->stream_finished, &ts, &size);

	/*if no frame or muted don't draw*/
	if (!txh->data || !size) {
		/*TODO - check if this is needed */
		if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) {
			//txh->needs_refresh = 1;
			gf_sc_invalidate(txh->compositor, NULL);
		}
		return;
	}

	/*if setup and same frame return*/
	if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) {
		gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);
		txh->needs_release = 0;
		return;
	}
	txh->needs_release = 1; 
	txh->last_frame_time = ts;
	if (gf_mo_is_muted(txh->stream)) return;

	if (!txh->tx_io) {
		setup_texture_object(txh, 0);
	}

	/*try to push texture on graphics but don't complain if failure*/
	gf_sc_texture_set_data(txh);

	txh->needs_refresh = 1;
	gf_sc_invalidate(txh->compositor, NULL);
}
Beispiel #9
0
GF_EXPORT
void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync)
{
	u32 size, ts;

	/*already refreshed*/
	if (txh->needs_refresh) return;

	if (!txh->stream) {
		txh->data = NULL;
		return;
	}

	/*should never happen!!*/
	if (txh->needs_release) gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);

	/*check init flag*/
	if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) {
		/*if we had a texture this means the object has changed - delete texture and resetup. Do not skip
		texture update as this may lead to an empty rendering pass (blank frame for this object), especially in DASH*/
		if (txh->tx_io) {
			gf_sc_texture_release(txh);
			txh->data = NULL;
			txh->needs_refresh = 1;
		}
		if (gf_mo_is_private_media(txh->stream)) {
			setup_texture_object(txh, 1);
			gf_node_dirty_set(txh->owner, 0, 0);
		}
	}
	txh->data = gf_mo_fetch_data(txh->stream, !disable_resync, &txh->stream_finished, &ts, &size);

	/*if no frame or muted don't draw*/
	if (!txh->data || !size) {
		GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("No output frame available\n"));
		/*TODO - check if this is needed */
		if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) {
			//txh->needs_refresh = 1;
			gf_sc_invalidate(txh->compositor, NULL);
		}
		return;
	}

	/*if setup and same frame return*/
	if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) {
		gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0);
		txh->needs_release = 0;
		return;
	}
	txh->needs_release = 1;
	txh->last_frame_time = ts;
	if (gf_mo_is_muted(txh->stream)) return;

	if (!txh->tx_io) {
		setup_texture_object(txh, 0);
	}

	/*try to push texture on graphics but don't complain if failure*/
	gf_sc_texture_set_data(txh);

	txh->needs_refresh = 1;
	gf_sc_invalidate(txh->compositor, NULL);
}
u32 layer3d_setup_offscreen(GF_Node *node, Layer3DStack *st, GF_TraverseState *tr_state, Fixed width, Fixed height)
{
	GF_STENCIL stencil;
	u32 new_pixel_format, w, h;
	GF_Compositor *compositor = (GF_Compositor *)st->visual->compositor;

	if (st->unsupported) return 0;

#ifndef GPAC_USE_TINYGL
	/*no support for offscreen rendering*/
	if (!(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN)) {
		st->unsupported = 1;
		return 0;
	}
#endif

/*
	if (tr_state->visual->compositor->recompute_ar) {
		gf_node_dirty_set(node, 0, 0);
		return 0;
	}
*/

	new_pixel_format = GF_PIXEL_RGBA;
#ifndef GPAC_USE_TINYGL
//	if (!compositor_background_transparent(gf_list_get(tr_state->backgrounds, 0)) )
//		new_pixel_format = GF_PIXEL_RGB_24;

	/*in OpenGL_ES, only RGBA can be safelly used with glReadPixels*/
#ifdef GPAC_USE_OGL_ES
	new_pixel_format = GF_PIXEL_RGBA;
#else
	/*no support for alpha in offscreen rendering*/
	if (!(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA)) 
		new_pixel_format = GF_PIXEL_RGB_24;
#endif

#endif

	/*FIXME - we assume RGB+Depth+bitshape, we should check with the video out module*/
#if defined(GF_SR_USE_DEPTH) && !defined(GPAC_DISABLE_3D)
	if (st->visual->type_3d && (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_DEPTH) ) new_pixel_format = GF_PIXEL_RGBDS;
#endif
	
	w = (u32) FIX2INT(gf_ceil(width));
	h = (u32) FIX2INT(gf_ceil(height));

	/*1- some implementation of glReadPixel crash if w||h are not multiple of 4*/
	/*2- some implementation of glReadPixel don't behave properly here when texture is not a power of 2*/
	w = gf_get_next_pow2(w);
	if (w>1024) w = 1024;
	h = gf_get_next_pow2(h);
	if (h>1024) h = 1024;


	if (!w || !h) return 0;

	if (st->txh.tx_io
		&& (new_pixel_format == st->txh.pixelformat)
		&& (w == st->txh.width) 
		&& (h == st->txh.height) 
		&& (compositor->offscreen_width >= w) 
		&& (compositor->offscreen_height >= h)
	) 
		return 2;

	if (st->txh.tx_io) {
#ifdef GPAC_USE_TINYGL
		if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
#endif
		gf_sc_texture_release(&st->txh);
		if (st->txh.data) gf_free(st->txh.data);
		st->txh.data = NULL;
	}

	st->vp = gf_rect_center(INT2FIX(w), INT2FIX(h) );

	st->txh.width = w;
	st->txh.height = h;

	gf_sc_texture_allocate(&st->txh);
	st->txh.pixelformat = new_pixel_format;

	if (new_pixel_format==GF_PIXEL_RGBA) {
		st->txh.stride = w * 4;
		st->txh.transparent = 1;
	} 
	else if (new_pixel_format==GF_PIXEL_RGBDS) {
			st->txh.stride = w * 4;
			st->txh.transparent = 1;
	}
	else {
		st->txh.stride = w * 3;
		st->txh.transparent = 0;
	}

	st->visual->width = w;
	st->visual->height = h;


	stencil = compositor->rasterizer->stencil_new(compositor->rasterizer, GF_STENCIL_TEXTURE);

#ifndef GPAC_USE_TINYGL
	/*create an offscreen window for OpenGL rendering*/
	if ((compositor->offscreen_width < w) || (compositor->offscreen_height < h)) {
		GF_Err e;
		GF_Event evt;
		compositor->offscreen_width = MAX(compositor->offscreen_width, w);
		compositor->offscreen_height = MAX(compositor->offscreen_height, h);

		evt.type = GF_EVENT_VIDEO_SETUP;
		evt.setup.width = tr_state->visual->compositor->offscreen_width;
		evt.setup.height = tr_state->visual->compositor->offscreen_height;
		evt.setup.back_buffer = 0;
		evt.setup.opengl_mode = 2;
		e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
		if (e) {
			gf_sc_texture_release(&st->txh);
			st->unsupported = 1;
			return 0;
		}
		/*reload openGL ext*/
		gf_sc_load_opengl_extensions(compositor, 1);
	}
#endif
	st->txh.data = (char*)gf_malloc(sizeof(unsigned char) * st->txh.stride * st->txh.height);
	memset(st->txh.data, 0, sizeof(unsigned char) * st->txh.stride * st->txh.height);
	
	/*set stencil texture - we don't check error as an image could not be supported by the rasterizer
	but still supported by the blitter (case of RGBD/RGBDS)*/
	compositor->rasterizer->stencil_set_texture(stencil, st->txh.data, st->txh.width, st->txh.height, st->txh.stride, st->txh.pixelformat, st->txh.pixelformat, 0);

#ifdef GPAC_USE_TINYGL
	/*create TinyGL offscreen context*/
	st->tgl_ctx = ostgl_create_context(st->txh.width, st->txh.height, st->txh.transparent ? 32 : 24, &st->txh.data, 1);

	st->scale_x = st->scale_y = FIX_ONE;
#else
	st->scale_x = INT2FIX(w) / tr_state->visual->compositor->offscreen_width;
	st->scale_y = INT2FIX(h) / tr_state->visual->compositor->offscreen_height;
#endif

	gf_sc_texture_set_stencil(&st->txh, stencil);
	drawable_reset_path(st->drawable);
	gf_path_add_rect_center(st->drawable->path, 0, 0, st->clip.width, st->clip.height);
	return 1;
}