display: weston: opaque region笔记

client的设置方法:

region = wl_compositor_create_region(window->display->compositor);
wl_region_add(region, 0, 0,
	      window->geometry.width,
	      window->geometry.height);
wl_surface_set_opaque_region(window->surface, region);
wl_region_destroy(region);

server的对应操作:


static void
compositor_create_region(struct wl_client *client,
			 struct wl_resource *resource, uint32_t id)
{
	struct weston_region *region;
    //创建region对象
	region = malloc(sizeof *region);
...
	pixman_region32_init(&region->region);
    //通过pixman对region进行初始化
	region->resource =
		wl_resource_create(client, &wl_region_interface, 1, id);
    //真正创建weston里面的object,初始化。
...
	wl_resource_set_implementation(region->resource, &region_interface,
				       region, destroy_region);
    //任然是初始化的一部分。
}
初始化weston_region以及他的resource

static void
region_add(struct wl_client *client, struct wl_resource *resource,
	   int32_t x, int32_t y, int32_t width, int32_t height)
{
	struct weston_region *region = wl_resource_get_user_data(resource);

	pixman_region32_union_rect(&region->region, &region->region,
				   x, y, width, height);
}
//其实就是通过pixman对region创建一个矩形区域。

static void
surface_set_opaque_region(struct wl_client *client,
			  struct wl_resource *resource,
			  struct wl_resource *region_resource)
{
	struct weston_surface *surface = wl_resource_get_user_data(resource);
	struct weston_region *region;

	if (region_resource) {
		region = wl_resource_get_user_data(region_resource);
		pixman_region32_copy(&surface->pending.opaque,
				     &region->region);
	} else {
		pixman_region32_clear(&surface->pending.opaque);
	}
}
//把surface与region进行一个绑定,如果region参数为null。则清空surface的region区域;
当然现在还是更新的pending部分,没有实际应用。不commit都是pending
理论上这个值只设置一次就可以。但是建议在不性能考虑的时候每次commit都设置一下。
static void
region_destroy(struct wl_client *client, struct wl_resource *resource)
{
	wl_resource_destroy(resource);
}
//释放resource

总的来说很简单,client遵循完全一致的操作逻辑,server这边也是中规中矩的简单操作。后面就要看commit以及后续怎么处理region,如下是commit以后server对pending state的处理

	/* wl_surface.set_opaque_region */
	pixman_region32_init(&opaque);
	pixman_region32_intersect_rect(&opaque, &state->opaque,
				       0, 0, surface->width, surface->height);
    //主要是和surface的区域做一个交集的动作,取交集部分作为不透明区域
	if (!pixman_region32_equal(&opaque, &surface->opaque)) {
		pixman_region32_copy(&surface->opaque, &opaque);
    //把对应的区域拷贝到surface里面,而不是pending的了。
		wl_list_for_each(view, &surface->views, surface_link)
			weston_view_geometry_dirty(view);
            //简单也简单,就是view->transform.dirty = 1;属性
	}

	pixman_region32_fini(&opaque);

pending 的不透明区域并不会因为一帧完整的commit而消失,所以理论上设置一次即可。

关于region这块区域要从头开始,先是在view的创建过程中创建region:

WL_EXPORT struct weston_view *
weston_view_create(struct weston_surface *surface)
{
	struct weston_view *view;
...
	view->surface = surface;
	view->plane = &surface->compositor->primary_plane;

	/* Assign to surface */
	wl_list_insert(&surface->views, &view->surface_link);

	wl_signal_init(&view->destroy_signal);
	wl_list_init(&view->link);
	wl_list_init(&view->layer_link.link);

	pixman_region32_init(&view->clip);

	view->alpha = 1.0;
	pixman_region32_init(&view->transform.opaque);

	wl_list_init(&view->geometry.transformation_list);
	wl_list_insert(&view->geometry.transformation_list,
		       &view->transform.position.link);
	weston_matrix_init(&view->transform.position.matrix);
	wl_list_init(&view->geometry.child_list);
	pixman_region32_init(&view->geometry.scissor);
	pixman_region32_init(&view->transform.boundingbox);
	view->transform.dirty = 1;

	return view;
}

 boundingbox区域(view的全局坐标):

    
weston_view_update_transform_enable:

pixman_region32_init_rect(&surfregion, 0, 0,
              view->surface->width, view->surface->height);

weston_view_update_transform_scissor(view, &surfregion);
surfbox = pixman_region32_extents(&surfregion);

view_compute_bbox(view, surfbox, &view->transform.boundingbox);
pixman_region32_fini(&surfregion);

先创建一个完整的surface区域:0,0,w,h。
如果有裁剪,则对surface区域做一个裁剪,此时任然是局部的。

static void
view_compute_bbox(struct weston_view *view, const pixman_box32_t *inbox,
          pixman_region32_t *bbox)
{
    float min_x = HUGE_VALF,  min_y = HUGE_VALF;
    float max_x = -HUGE_VALF, max_y = -HUGE_VALF;
    int32_t s[4][2] = {
        { inbox->x1, inbox->y1 },
        { inbox->x1, inbox->y2 },
        { inbox->x2, inbox->y1 },
        { inbox->x2, inbox->y2 },
    };
    //确立矩形区域

    float int_x, int_y;
    int i;

    if (inbox->x1 == inbox->x2 || inbox->y1 == inbox->y2) {
        /* avoid rounding empty bbox to 1x1 */
        pixman_region32_init(bbox);
        return;
    }
    //如果x1与x2相等,就是没宽度,如果y1与y2相等,就是没长度,也就是个0

    for (i = 0; i < 4; ++i) {
        float x, y;
        weston_view_to_global_float(view, s[i][0], s[i][1], &x, &y);
        if (x < min_x)
            min_x = x;
        if (x > max_x)
            max_x = x;
        if (y < min_y)
            min_y = y;
        if (y > max_y)
            max_y = y;
    }

    int_x = floorf(min_x);
    int_y = floorf(min_y);
    pixman_region32_init_rect(bbox, int_x, int_y,
                  ceilf(max_x) - int_x, ceilf(max_y) - int_y);
    //基本上就是 surface.x + view->geomerty.x 与 surface.y + view->geomerty.y和对应的w,h。
}

WL_EXPORT void
weston_view_to_global_float(struct weston_view *view,
                float sx, float sy, float *x, float *y)
{
    if (view->transform.enabled) {
        struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };

        weston_matrix_transform(&view->transform.matrix, &v);

        if (fabsf(v.f[3]) < 1e-6) {
            weston_log("warning: numerical instability in "
                "%s(), divisor = %g\n", __func__,
                v.f[3]);
            *x = 0;
            *y = 0;
            return;
        }

        *x = v.f[0] / v.f[3];
        *y = v.f[1] / v.f[3];
    } else {
        *x = sx + view->geometry.x;
        *y = sy + view->geometry.y;
    }
    //如果有变化,就要做对应的变化,如果没有,就是surface的x或y + view->geomerty,x或y。
}

weston_view_from_global_float
正好和上面的相反。

weston_view_set_position:设置view的绝对坐标。

weston_view_damage_below
 view->transform.boundingbox - view->clip = damage
计算全局的view坐标减去clip的坐标,得到真正需要处理的属于此view的坐标大小,送给plane->damage
clip坐标为其他覆盖在此view上的不透明区域。

weston_surface_assign_output
 view->transform,boundingbox & view->output->region
让view的output坐标和 boundingbox坐标取交集。
说是重新计算surface的view在哪些output上面。注意,是通过view所在的outputmask来得到surface所在的output。

weston_view_assign_output
 view->transform.boundingbox & output->region
让view的boundingbox坐标和 output坐标取交集,注意这部分是通过output做的遍历。
重新计算view在哪些output上面。

一般是先执行weston_view_assign_output决定了view在哪些output上,然后再调用
weston_surface_assgin_output

weston_view_update_transform_disable
weston_view_update_transform_enable
暂时还不明确用途。

weston_view_update_transform

weston_view_matches_output_entirely
确认view的boundingbox是否覆盖了对应的output的所有区域,如果是返回true,否则返回false。

weston_compositor_pick_view

weston_view_destroy
如名字

view_accumulate_damage

讲述一下gl_renderer_repaint_output


/* NOTE: We now allow falling back to ARGB gl visuals when XRGB is
 * unavailable, so we're assuming the background has no transparency
 * and that everything with a blend, like drop shadows, will have something
 * opaque (like the background) drawn underneath it.
 *
 * Depending on the underlying hardware, violating that assumption could
 * result in seeing through to another display plane.
 */
static void
gl_renderer_repaint_output(struct weston_output *output,
			   pixman_region32_t *output_damage)
{
	weston_log("%s+++\n",  __func__);
	struct gl_output_state *go = get_output_state(output);
	struct weston_compositor *compositor = output->compositor;
	struct gl_renderer *gr = get_renderer(compositor);
	EGLBoolean ret;
	static int errored;
	/* areas we've damaged since we last used this buffer */
	pixman_region32_t previous_damage;
	/* total area we need to repaint this time */
	pixman_region32_t total_damage;
	enum gl_border_status border_status = BORDER_STATUS_CLEAN;
	struct weston_view *view;

	if (use_output(output) < 0)  //本质就是调用eglMakeCurrent,详细见:https://www.zybuluo.com/SR1s/note/650099
		return;

	/* Clear the used_in_output_repaint flag, so that we can properly track
	 * which surfaces were used in this output repaint. */
	wl_list_for_each_reverse(view, &compositor->view_list, link) {
		if (view->plane == &compositor->primary_plane) {
			struct gl_surface_state *gs =
				get_surface_state(view->surface);
			gs->used_in_output_repaint = false;
		}
	}
    //设置这个used_in_output_repaint标志位。这个标志位在调用gpu函数进行绘画时置为true。
而绘画完成后置为false。主要用于说明对应surface所处状态。正在被output_repaint所用。

	if (go->begin_render_sync != EGL_NO_SYNC_KHR)
		gr->destroy_sync(gr->egl_display, go->begin_render_sync);
	if (go->end_render_sync != EGL_NO_SYNC_KHR)
		gr->destroy_sync(gr->egl_display, go->end_render_sync);
    //名副其实的render sync机制,后面需要学习一下,看上去是用来保证个glrender的开始和结束状态。

	go->begin_render_sync = create_render_sync(gr);

	/* Calculate the global GL matrix */
	go->output_matrix = output->matrix;
	weston_matrix_translate(&go->output_matrix,
				-(output->current_mode->width / 2.0),
				-(output->current_mode->height / 2.0), 0);
	weston_matrix_scale(&go->output_matrix,
			    2.0 / output->current_mode->width,
			    -2.0 / output->current_mode->height, 1);

	/* If using shadow, redirect all drawing to it first. */
	if (shadow_exists(go)) {
		/* XXX: Shadow code does not support resizing. */
		assert(output->current_mode->width == go->shadow.width);
		assert(output->current_mode->height == go->shadow.height);

		glBindFramebuffer(GL_FRAMEBUFFER, go->shadow.fbo);
		glViewport(0, 0, go->shadow.width, go->shadow.height);
	} else {
		glBindFramebuffer(GL_FRAMEBUFFER, 0);
		glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
			   go->borders[GL_RENDERER_BORDER_BOTTOM].height,
			   output->current_mode->width,
			   output->current_mode->height);
	}

	/* In fan debug mode, redraw everything to make sure that we clear any
	 * fans left over from previous draws on this buffer.
	 * This precludes the use of EGL_EXT_swap_buffers_with_damage and
	 * EGL_KHR_partial_update, since we damage the whole area. */
	if (gr->fan_debug) {
		pixman_region32_t undamaged;
		pixman_region32_init(&undamaged);
		pixman_region32_subtract(&undamaged, &output->region,
					 output_damage);
		gr->fan_debug = false;
		repaint_views(output, &undamaged);
		gr->fan_debug = true;
		pixman_region32_fini(&undamaged);
	}

	/* previous_damage covers regions damaged in previous paints since we
	 * last used this buffer */
	pixman_region32_init(&previous_damage);
	pixman_region32_init(&total_damage); /* total area to redraw */

	/* Update previous_damage using buffer_age (if available), and store
	 * current damaged region for future use. */
	output_get_damage(output, &previous_damage, &border_status);
	output_rotate_damage(output, output_damage, go->border_status);

	/* Redraw both areas which have changed since we last used this buffer,
	 * as well as the areas we now want to repaint, to make sure the
	 * buffer is up to date. */
	pixman_region32_union(&total_damage, &previous_damage, output_damage);
	border_status |= go->border_status;

	if (gr->has_egl_partial_update && !gr->fan_debug) {
		int n_egl_rects;
		EGLint *egl_rects;

		/* For partial_update, we need to pass the region which has
		 * changed since we last rendered into this specific buffer;
		 * this is total_damage. */
		pixman_region_to_egl_y_invert(output, &total_damage,
					      &egl_rects, &n_egl_rects);
		gr->set_damage_region(gr->egl_display, go->egl_surface,
				      egl_rects, n_egl_rects);
		free(egl_rects);
	}

	if (shadow_exists(go)) {
		/* Repaint into shadow. */
		if (compositor->test_data.test_quirks.gl_force_full_redraw_of_shadow_fb)
			repaint_views(output, &output->region);
		else
			repaint_views(output, output_damage);

		glBindFramebuffer(GL_FRAMEBUFFER, 0);
		glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
			   go->borders[GL_RENDERER_BORDER_BOTTOM].height,
			   output->current_mode->width,
			   output->current_mode->height);
		blit_shadow_to_output(output, &total_damage);
	} else {
		repaint_views(output, &total_damage);
	}

	pixman_region32_fini(&total_damage);
	pixman_region32_fini(&previous_damage);

	draw_output_borders(output, border_status);

	wl_signal_emit(&output->frame_signal, output_damage);

	go->end_render_sync = create_render_sync(gr);

	if (gr->swap_buffers_with_damage && !gr->fan_debug) {
		int n_egl_rects;
		EGLint *egl_rects;

		/* For swap_buffers_with_damage, we need to pass the region
		 * which has changed since the previous SwapBuffers on this
		 * surface - this is output_damage. */
		pixman_region_to_egl_y_invert(output, output_damage,
					      &egl_rects, &n_egl_rects);
		ret = gr->swap_buffers_with_damage(gr->egl_display,
						   go->egl_surface,
						   egl_rects, n_egl_rects);
		free(egl_rects);
	} else {
		ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
	}

	if (ret == EGL_FALSE && !errored) {
		errored = 1;
		weston_log("Failed in eglSwapBuffers.\n");
		gl_renderer_print_egl_error_state();
	}

	go->border_status = BORDER_STATUS_CLEAN;

	/* We have to submit the render sync objects after swap buffers, since
	 * the objects get assigned a valid sync file fd only after a gl flush.
	 */
	timeline_submit_render_sync(gr, output, go->begin_render_sync,
				    TIMELINE_RENDER_POINT_TYPE_BEGIN);
	timeline_submit_render_sync(gr, output, go->end_render_sync,
				    TIMELINE_RENDER_POINT_TYPE_END);

	update_buffer_release_fences(compositor, output);

	gl_renderer_garbage_collect_programs(gr);
	weston_log("%s---\n",  __func__);
}

随后的调用就在draw_view也就是合成的地方了

/* repaint bounding region in global coordinates: */
pixman_region32_t repaint;
/* opaque region in surface coordinates: */
pixman_region32_t surface_opaque;
/* non-opaque region in surface coordinates: */
pixman_region32_t surface_blend;
//总共三个区域,一个是全局的repaint。
//另外两个则是相对surface的 surface opaque和surface blend


pixman_region32_init(&repaint);
pixman_region32_intersect(&repaint,
				  &ev->transform.boundingbox, damage);
pixman_region32_subtract(&repaint, &repaint, &ev->clip);
//以上是以全局坐标去考虑区域的。也就是repaint的区域是全局中的damage区域。再减去一个view的clip区域,
//注意这个是绝对坐标哦!也就是全局坐标

/* blended region is whole surface minus opaque region: */
pixman_region32_init_rect(&surface_blend, 0, 0,
				  ev->surface->width, ev->surface->height);
//先假设全部区域都是可混合的,再找到最终和混合区域
	if (ev->geometry.scissor_enabled)
		pixman_region32_intersect(&surface_blend, &surface_blend,
					  &ev->geometry.scissor);
	pixman_region32_subtract(&surface_blend, &surface_blend,
				 &ev->surface->opaque);
//合成的时候是从下往上画的。上面用到opaque region也很简单,这个view哪些部分是blend区域,
//哪部分是opaque区域。注意这个坐标是对应surface自己的相对坐标哦!

	/* XXX: Should we be using ev->transform.opaque here? */
	pixman_region32_init(&surface_opaque);
	if (ev->geometry.scissor_enabled)
		pixman_region32_intersect(&surface_opaque,
					  &ev->surface->opaque,
					  &ev->geometry.scissor);
	else
		pixman_region32_copy(&surface_opaque, &ev->surface->opaque);
    //同样的,找到相对应surface的相对的不透明区域
....
....
	if (pixman_region32_not_empty(&surface_opaque)) {
		struct gl_shader_config alt = sconf;

		if (alt.req.variant == SHADER_VARIANT_RGBA) {
			/* Special case for RGBA textures with possibly
			 * bad data in alpha channel: use the shader
			 * that forces texture alpha = 1.0.
			 * Xwayland surfaces need this.
			 */
			alt.req.variant = SHADER_VARIANT_RGBX;
		}

		if (ev->alpha < 1.0)
			glEnable(GL_BLEND);
		else
			glDisable(GL_BLEND);

		repaint_region(gr, ev, &repaint, &surface_opaque, &alt);
		gs->used_in_output_repaint = true;
	}

	if (pixman_region32_not_empty(&surface_blend)) {
		glEnable(GL_BLEND);
		repaint_region(gr, ev, &repaint, &surface_blend, &sconf);
		gs->used_in_output_repaint = true;
	}
//先画不透明的区域,然后画除此之外的blending区域,那传入的一个是全局坐标,
//一个是相对surface的坐标,是如何真正完成绘画的呢?

要绘制的最后一个区域是“region”和“surf_region”的交集。 但是,'region' 在全局坐标中,'surf_region' 在表面局部坐标中。 texture_region() 将迭代来自两个区域的所有矩形对,计算每对矩形的交集多边形,如果它具有非零区域(实际上至少有 3 个顶点),则将其存储为三角形扇形。 

static void
repaint_region(struct gl_renderer *gr,
	       struct weston_view *ev,
	       pixman_region32_t *region,
	       pixman_region32_t *surf_region,
	       const struct gl_shader_config *sconf)
{
	GLfloat *v;
	unsigned int *vtxcnt;
	int i, first, nfans;

	/* The final region to be painted is the intersection of
	 * 'region' and 'surf_region'. However, 'region' is in the global
	 * coordinates, and 'surf_region' is in the surface-local
	 * coordinates. texture_region() will iterate over all pairs of
	 * rectangles from both regions, compute the intersection
	 * polygon for each pair, and store it as a triangle fan if
	 * it has a non-zero area (at least 3 vertices, actually).
	 */
	nfans = texture_region(ev, region, surf_region);

	v = gr->vertices.data;
	vtxcnt = gr->vtxcnt.data;

	/* position: */
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
	glEnableVertexAttribArray(0);

	/* texcoord: */
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
	glEnableVertexAttribArray(1);

	if (!gl_renderer_use_program(gr, sconf)) {
		gl_renderer_send_shader_error(ev);
		/* continue drawing with the fallback shader */
	}

	for (i = 0, first = 0; i < nfans; i++) {
		glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
		if (gr->fan_debug)
			triangle_fan_debug(gr, sconf, first, vtxcnt[i]);
		first += vtxcnt[i];
	}

	glDisableVertexAttribArray(1);
	glDisableVertexAttribArray(0);

	gr->vertices.size = 0;
	gr->vtxcnt.size = 0;
}

NOTE:

build view list的时候是从上到下的顺序(先塞入的在view list的最下面)。draw view的时候,是从下到上。
下,即离我们最远的,如bakcground开始。
上,即离我们最近的,如focus。

[21:27:53.413] weston_compositor_build_view_list : ++++
[21:27:53.413] view_list_add : view:0x5619cd4097c0++++
[21:27:53.413] weston_view_update_transform : view:0x5619cd4097c0++++
[21:27:53.413] view_list_add : view:0x5619cd2149d0++++
[21:27:53.413] weston_view_update_transform : view:0x5619cd2149d0++++
[21:27:53.413] view_list_add : view:0x5619cd401d80++++
[21:27:53.413] weston_view_update_transform : view:0x5619cd401d80++++
[21:27:53.413] weston_view_damage_below : view:0x5619cd401d80++++
[21:27:53.413] weston_view_damage_below : view:0x5619cd401d80----
[21:27:53.413] weston_view_update_transform_enable : view:0x5619cd401d80++++
[21:27:53.413] view_compute_bbox++++
[21:27:53.413] view_compute_bbox----
[21:27:53.413] weston_view_update_transform_enable : view:0x5619cd401d80----
[21:27:53.413] weston_view_damage_below : view:0x5619cd401d80++++
[21:27:53.413] weston_view_damage_below : view:0x5619cd401d80----
[21:27:53.413] weston_view_assign_output : view:0x5619cd401d80++++
[21:27:53.413] weston_surface_assign_output : surface:0x5619cd365ae0++++
[21:27:53.413] weston_surface_assign_output : surface:0x5619cd365ae0----
[21:27:53.413] weston_view_assign_output : view:0x5619cd401d80----
[21:27:53.413] weston_view_update_transform : view:0x5619cd401d80----
[21:27:53.413] view_list_add : view:0x5619cd235680++++
[21:27:53.413] weston_view_update_transform : view:0x5619cd235680++++
[21:27:53.413] weston_compositor_build_view_list : ----
[21:27:53.413] output_accumulate_damage : ++++
[21:27:53.413] view_accumulate_damage : view:0x5619cd4097c0++++
[21:27:53.414] view_accumulate_damage : view:0x5619cd4097c0----
[21:27:53.414] view_accumulate_damage : view:0x5619cd2149d0++++
[21:27:53.414] view_accumulate_damage : view:0x5619cd2149d0----
[21:27:53.414] view_accumulate_damage : view:0x5619cd401d80++++
[21:27:53.414] view_compute_bbox++++
[21:27:53.414] view_accumulate_damage : view:0x5619cd401d80----
[21:27:53.414] view_accumulate_damage : view:0x5619cd235680++++
[21:27:53.414] view_accumulate_damage : view:0x5619cd235680----
[21:27:53.414] output_accumulate_damage : ---
[21:27:53.414] gl_renderer_repaint_output+++
[21:27:53.414] repaint_views
[21:27:53.414] repaint_views:plane 0 0 
[21:27:53.414] draw_view : view:0x5619cd235680++++
[21:27:53.414] damage region 0 0 1024 640
[21:27:53.414] boundingbox region 0 0 1024 640
[21:27:53.414] repaint region= boundingbox & damage 0 0 1024 640
[21:27:53.414] surface blend region 0 0 0 0
[21:27:53.414] surface opaque region 0 0 1024 640
[21:27:53.414] repaint opaque region++
[21:27:53.414] repaint_region:region 0 0 1024 640
[21:27:53.414] repaint_region:surf region 0 0 1024 640
[21:27:53.414] repaint opaque region--
[21:27:53.414] draw_view : view:0x5619cd235680----

[21:27:53.414] repaint_views:plane 0 0 
[21:27:53.414] draw_view : view:0x5619cd401d80++++
[21:27:53.414] damage region 0 0 1024 640
[21:27:53.414] boundingbox region 175 93 981 584
[21:27:53.414] repaint region= boundingbox & damage 175 93 981 584
[21:27:53.414] surface blend region 0 0 806 491
[21:27:53.414] surface opaque region 35 35 771 456
[21:27:53.414] repaint opaque region++
[21:27:53.414] repaint_region:region 175 93 981 584
[21:27:53.414] repaint_region:surf region 35 35 771 456
[21:27:53.414] repaint opaque region--
[21:27:53.414] repaint blend region++
[21:27:53.414] repaint_region:region 175 93 981 584
[21:27:53.414] repaint_region:surf region 0 0 806 491
[21:27:53.414] repaint blend region--
[21:27:53.414] draw_view : view:0x5619cd401d80----

[21:27:53.414] repaint_views:plane 0 0 
[21:27:53.414] draw_view : view:0x5619cd2149d0++++
[21:27:53.414] damage region 0 0 1024 640
[21:27:53.414] boundingbox region 0 0 1024 32
[21:27:53.414] repaint region= boundingbox & damage 0 0 1024 32
[21:27:53.414] surface blend region 0 0 1024 32
[21:27:53.414] surface opaque region 0 0 0 0
[21:27:53.414] repaint blend region++
[21:27:53.414] repaint_region:region 0 0 1024 32
[21:27:53.414] repaint_region:surf region 0 0 1024 32
[21:27:53.414] repaint blend region--
[21:27:53.414] draw_view : view:0x5619cd2149d0----

[21:27:53.414] repaint_views:plane 0 0 
[21:27:53.414] draw_view : view:0x5619cd4097c0++++
[21:27:53.414] damage region 0 0 1024 640
[21:27:53.414] boundingbox region 1003 -3 1035 29
[21:27:53.414] repaint region= boundingbox & damage 1003 0 1024 29
[21:27:53.414] surface blend region 0 0 32 32
[21:27:53.414] surface opaque region 0 0 0 0
[21:27:53.414] repaint blend region++
[21:27:53.414] repaint_region:region 1003 0 1024 29
[21:27:53.414] repaint_region:surf region 0 0 32 32
[21:27:53.414] repaint blend region--
[21:27:53.414] draw_view : view:0x5619cd4097c0----

[21:27:53.421] gl_renderer_repaint_output---

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值