2 * Copyright © 2012 Intel Corporation
3 * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29 #include "pixman-renderer.h"
31 #include <linux/input.h>
33 struct pixman_output_state {
35 pixman_image_t *shadow_image;
36 pixman_image_t *hw_buffer;
39 struct pixman_surface_state {
40 struct weston_surface *surface;
42 pixman_image_t *image;
43 struct weston_buffer_reference buffer_ref;
45 struct wl_listener buffer_destroy_listener;
46 struct wl_listener surface_destroy_listener;
47 struct wl_listener renderer_destroy_listener;
50 struct pixman_renderer {
51 struct weston_renderer base;
54 pixman_image_t *debug_color;
55 struct weston_binding *debug_binding;
57 struct wl_signal destroy_signal;
60 static inline struct pixman_output_state *
61 get_output_state(struct weston_output *output)
63 return (struct pixman_output_state *)output->renderer_state;
67 pixman_renderer_create_surface(struct weston_surface *surface);
69 static inline struct pixman_surface_state *
70 get_surface_state(struct weston_surface *surface)
72 if (!surface->renderer_state)
73 pixman_renderer_create_surface(surface);
75 return (struct pixman_surface_state *)surface->renderer_state;
78 static inline struct pixman_renderer *
79 get_renderer(struct weston_compositor *ec)
81 return (struct pixman_renderer *)ec->renderer;
85 pixman_renderer_read_pixels(struct weston_output *output,
86 pixman_format_code_t format, void *pixels,
87 uint32_t x, uint32_t y,
88 uint32_t width, uint32_t height)
90 struct pixman_output_state *po = get_output_state(output);
91 pixman_transform_t transform;
92 pixman_image_t *out_buf;
99 out_buf = pixman_image_create_bits(format,
103 (PIXMAN_FORMAT_BPP(format) / 8) * width);
105 /* Caller expects vflipped source image */
106 pixman_transform_init_translate(&transform,
107 pixman_int_to_fixed (x),
108 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
109 pixman_transform_scale(&transform, NULL,
111 pixman_fixed_minus_1);
112 pixman_image_set_transform(po->hw_buffer, &transform);
114 pixman_image_composite32(PIXMAN_OP_SRC,
115 po->hw_buffer, /* src */
118 0, 0, /* src_x, src_y */
119 0, 0, /* mask_x, mask_y */
120 0, 0, /* dest_x, dest_y */
121 pixman_image_get_width (po->hw_buffer), /* width */
122 pixman_image_get_height (po->hw_buffer) /* height */);
123 pixman_image_set_transform(po->hw_buffer, NULL);
125 pixman_image_unref(out_buf);
131 region_global_to_output(struct weston_output *output, pixman_region32_t *region)
133 pixman_region32_translate(region, -output->x, -output->y);
134 weston_transformed_region(output->width, output->height,
135 output->transform, output->current_scale,
139 #define D2F(v) pixman_double_to_fixed((double)v)
142 transform_apply_viewport(pixman_transform_t *transform,
143 struct weston_surface *surface)
145 struct weston_buffer_viewport *vp = &surface->buffer_viewport;
146 double src_width, src_height;
149 if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
150 if (vp->surface.width == -1)
155 src_width = surface->width_from_buffer;
156 src_height = surface->height_from_buffer;
158 src_x = wl_fixed_to_double(vp->buffer.src_x);
159 src_y = wl_fixed_to_double(vp->buffer.src_y);
160 src_width = wl_fixed_to_double(vp->buffer.src_width);
161 src_height = wl_fixed_to_double(vp->buffer.src_height);
164 pixman_transform_scale(transform, NULL,
165 D2F(src_width / surface->width),
166 D2F(src_height / surface->height));
167 pixman_transform_translate(transform, NULL, D2F(src_x), D2F(src_y));
171 repaint_region(struct weston_view *ev, struct weston_output *output,
172 pixman_region32_t *region, pixman_region32_t *surf_region,
173 pixman_op_t pixman_op)
175 struct pixman_renderer *pr =
176 (struct pixman_renderer *) output->compositor->renderer;
177 struct pixman_surface_state *ps = get_surface_state(ev->surface);
178 struct pixman_output_state *po = get_output_state(output);
179 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
180 pixman_region32_t final_region;
181 float view_x, view_y;
182 pixman_transform_t transform;
183 pixman_fixed_t fw, fh;
184 pixman_image_t *mask_image;
185 pixman_color_t mask = { 0, };
187 /* The final region to be painted is the intersection of
188 * 'region' and 'surf_region'. However, 'region' is in the global
189 * coordinates, and 'surf_region' is in the surface-local
192 pixman_region32_init(&final_region);
194 pixman_region32_copy(&final_region, surf_region);
196 /* Convert from surface to global coordinates */
197 if (!ev->transform.enabled) {
198 pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
200 weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
201 pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
204 /* We need to paint the intersection */
205 pixman_region32_intersect(&final_region, &final_region, region);
207 /* If there is no surface region, just use the global region */
208 pixman_region32_copy(&final_region, region);
211 /* Convert from global to output coord */
212 region_global_to_output(output, &final_region);
215 pixman_image_set_clip_region32 (po->shadow_image, &final_region);
217 /* Set up the source transformation based on the surface
218 position, the output position/transform/scale and the client
219 specified buffer transform/scale */
220 pixman_transform_init_identity(&transform);
221 pixman_transform_scale(&transform, NULL,
222 pixman_double_to_fixed ((double)1.0/output->current_scale),
223 pixman_double_to_fixed ((double)1.0/output->current_scale));
225 fw = pixman_int_to_fixed(output->width);
226 fh = pixman_int_to_fixed(output->height);
227 switch (output->transform) {
229 case WL_OUTPUT_TRANSFORM_NORMAL:
230 case WL_OUTPUT_TRANSFORM_FLIPPED:
232 case WL_OUTPUT_TRANSFORM_90:
233 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
234 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
235 pixman_transform_translate(&transform, NULL, 0, fh);
237 case WL_OUTPUT_TRANSFORM_180:
238 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
239 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
240 pixman_transform_translate(&transform, NULL, fw, fh);
242 case WL_OUTPUT_TRANSFORM_270:
243 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
244 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
245 pixman_transform_translate(&transform, NULL, fw, 0);
249 switch (output->transform) {
250 case WL_OUTPUT_TRANSFORM_FLIPPED:
251 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
252 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
253 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
254 pixman_transform_scale(&transform, NULL,
255 pixman_int_to_fixed (-1),
256 pixman_int_to_fixed (1));
257 pixman_transform_translate(&transform, NULL, fw, 0);
261 pixman_transform_translate(&transform, NULL,
262 pixman_double_to_fixed (output->x),
263 pixman_double_to_fixed (output->y));
265 if (ev->transform.enabled) {
266 /* Pixman supports only 2D transform matrix, but Weston uses 3D,
267 * so we're omitting Z coordinate here
269 pixman_transform_t surface_transform = {{
270 { D2F(ev->transform.matrix.d[0]),
271 D2F(ev->transform.matrix.d[4]),
272 D2F(ev->transform.matrix.d[12]),
274 { D2F(ev->transform.matrix.d[1]),
275 D2F(ev->transform.matrix.d[5]),
276 D2F(ev->transform.matrix.d[13]),
278 { D2F(ev->transform.matrix.d[3]),
279 D2F(ev->transform.matrix.d[7]),
280 D2F(ev->transform.matrix.d[15]),
284 pixman_transform_invert(&surface_transform, &surface_transform);
285 pixman_transform_multiply (&transform, &surface_transform, &transform);
287 pixman_transform_translate(&transform, NULL,
288 pixman_double_to_fixed ((double)-ev->geometry.x),
289 pixman_double_to_fixed ((double)-ev->geometry.y));
292 transform_apply_viewport(&transform, ev->surface);
294 fw = pixman_int_to_fixed(ev->surface->width_from_buffer);
295 fh = pixman_int_to_fixed(ev->surface->height_from_buffer);
297 switch (vp->buffer.transform) {
298 case WL_OUTPUT_TRANSFORM_FLIPPED:
299 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
300 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
301 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
302 pixman_transform_scale(&transform, NULL,
303 pixman_int_to_fixed (-1),
304 pixman_int_to_fixed (1));
305 pixman_transform_translate(&transform, NULL, fw, 0);
309 switch (vp->buffer.transform) {
311 case WL_OUTPUT_TRANSFORM_NORMAL:
312 case WL_OUTPUT_TRANSFORM_FLIPPED:
314 case WL_OUTPUT_TRANSFORM_90:
315 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
316 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
317 pixman_transform_translate(&transform, NULL, fh, 0);
319 case WL_OUTPUT_TRANSFORM_180:
320 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
321 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
322 pixman_transform_translate(&transform, NULL, fw, fh);
324 case WL_OUTPUT_TRANSFORM_270:
325 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
326 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
327 pixman_transform_translate(&transform, NULL, 0, fw);
331 pixman_transform_scale(&transform, NULL,
332 pixman_double_to_fixed(vp->buffer.scale),
333 pixman_double_to_fixed(vp->buffer.scale));
335 pixman_image_set_transform(ps->image, &transform);
337 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
338 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
340 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
342 if (ps->buffer_ref.buffer)
343 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
345 if (ev->alpha < 1.0) {
346 mask.alpha = 0xffff * ev->alpha;
347 mask_image = pixman_image_create_solid_fill(&mask);
352 pixman_image_composite32(pixman_op,
354 mask_image, /* mask */
355 po->shadow_image, /* dest */
356 0, 0, /* src_x, src_y */
357 0, 0, /* mask_x, mask_y */
358 0, 0, /* dest_x, dest_y */
359 pixman_image_get_width (po->shadow_image), /* width */
360 pixman_image_get_height (po->shadow_image) /* height */);
363 pixman_image_unref(mask_image);
365 if (ps->buffer_ref.buffer)
366 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
368 if (pr->repaint_debug)
369 pixman_image_composite32(PIXMAN_OP_OVER,
370 pr->debug_color, /* src */
372 po->shadow_image, /* dest */
373 0, 0, /* src_x, src_y */
374 0, 0, /* mask_x, mask_y */
375 0, 0, /* dest_x, dest_y */
376 pixman_image_get_width (po->shadow_image), /* width */
377 pixman_image_get_height (po->shadow_image) /* height */);
379 pixman_image_set_clip_region32 (po->shadow_image, NULL);
381 pixman_region32_fini(&final_region);
385 draw_view(struct weston_view *ev, struct weston_output *output,
386 pixman_region32_t *damage) /* in global coordinates */
388 struct pixman_surface_state *ps = get_surface_state(ev->surface);
389 /* repaint bounding region in global coordinates: */
390 pixman_region32_t repaint;
391 /* non-opaque region in surface coordinates: */
392 pixman_region32_t surface_blend;
394 /* No buffer attached */
398 pixman_region32_init(&repaint);
399 pixman_region32_intersect(&repaint,
400 &ev->transform.masked_boundingbox, damage);
401 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
403 if (!pixman_region32_not_empty(&repaint))
406 if (output->zoom.active) {
407 weston_log("pixman renderer does not support zoom\n");
411 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
412 if (ev->alpha != 1.0 ||
413 (ev->transform.enabled &&
414 ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE)) {
415 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
417 /* blended region is whole surface minus opaque region: */
418 pixman_region32_init_rect(&surface_blend, 0, 0,
419 ev->surface->width, ev->surface->height);
420 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
422 if (pixman_region32_not_empty(&ev->surface->opaque)) {
423 repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
426 if (pixman_region32_not_empty(&surface_blend)) {
427 repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
429 pixman_region32_fini(&surface_blend);
434 pixman_region32_fini(&repaint);
437 repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
439 struct weston_compositor *compositor = output->compositor;
440 struct weston_view *view;
442 wl_list_for_each_reverse(view, &compositor->view_list, link)
443 if (view->plane == &compositor->primary_plane)
444 draw_view(view, output, damage);
448 copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
450 struct pixman_output_state *po = get_output_state(output);
451 pixman_region32_t output_region;
453 pixman_region32_init(&output_region);
454 pixman_region32_copy(&output_region, region);
456 region_global_to_output(output, &output_region);
458 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
460 pixman_image_composite32(PIXMAN_OP_SRC,
461 po->shadow_image, /* src */
463 po->hw_buffer, /* dest */
464 0, 0, /* src_x, src_y */
465 0, 0, /* mask_x, mask_y */
466 0, 0, /* dest_x, dest_y */
467 pixman_image_get_width (po->hw_buffer), /* width */
468 pixman_image_get_height (po->hw_buffer) /* height */);
470 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
474 pixman_renderer_repaint_output(struct weston_output *output,
475 pixman_region32_t *output_damage)
477 struct pixman_output_state *po = get_output_state(output);
482 repaint_surfaces(output, output_damage);
483 copy_to_hw_buffer(output, output_damage);
485 pixman_region32_copy(&output->previous_damage, output_damage);
486 wl_signal_emit(&output->frame_signal, output);
488 /* Actual flip should be done by caller */
492 pixman_renderer_flush_damage(struct weston_surface *surface)
494 /* No-op for pixman renderer */
498 buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
500 struct pixman_surface_state *ps;
502 ps = container_of(listener, struct pixman_surface_state,
503 buffer_destroy_listener);
506 pixman_image_unref(ps->image);
510 ps->buffer_destroy_listener.notify = NULL;
514 pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
516 struct pixman_surface_state *ps = get_surface_state(es);
517 struct wl_shm_buffer *shm_buffer;
518 pixman_format_code_t pixman_format;
520 weston_buffer_reference(&ps->buffer_ref, buffer);
522 if (ps->buffer_destroy_listener.notify) {
523 wl_list_remove(&ps->buffer_destroy_listener.link);
524 ps->buffer_destroy_listener.notify = NULL;
528 pixman_image_unref(ps->image);
535 shm_buffer = wl_shm_buffer_get(buffer->resource);
538 weston_log("Pixman renderer supports only SHM buffers\n");
539 weston_buffer_reference(&ps->buffer_ref, NULL);
543 switch (wl_shm_buffer_get_format(shm_buffer)) {
544 case WL_SHM_FORMAT_XRGB8888:
545 pixman_format = PIXMAN_x8r8g8b8;
547 case WL_SHM_FORMAT_ARGB8888:
548 pixman_format = PIXMAN_a8r8g8b8;
550 case WL_SHM_FORMAT_RGB565:
551 pixman_format = PIXMAN_r5g6b5;
554 weston_log("Unsupported SHM buffer format\n");
555 weston_buffer_reference(&ps->buffer_ref, NULL);
560 buffer->shm_buffer = shm_buffer;
561 buffer->width = wl_shm_buffer_get_width(shm_buffer);
562 buffer->height = wl_shm_buffer_get_height(shm_buffer);
564 ps->image = pixman_image_create_bits(pixman_format,
565 buffer->width, buffer->height,
566 wl_shm_buffer_get_data(shm_buffer),
567 wl_shm_buffer_get_stride(shm_buffer));
569 ps->buffer_destroy_listener.notify =
570 buffer_state_handle_buffer_destroy;
571 wl_signal_add(&buffer->destroy_signal,
572 &ps->buffer_destroy_listener);
576 pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
578 wl_list_remove(&ps->surface_destroy_listener.link);
579 wl_list_remove(&ps->renderer_destroy_listener.link);
580 if (ps->buffer_destroy_listener.notify) {
581 wl_list_remove(&ps->buffer_destroy_listener.link);
582 ps->buffer_destroy_listener.notify = NULL;
585 ps->surface->renderer_state = NULL;
588 pixman_image_unref(ps->image);
591 weston_buffer_reference(&ps->buffer_ref, NULL);
596 surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
598 struct pixman_surface_state *ps;
600 ps = container_of(listener, struct pixman_surface_state,
601 surface_destroy_listener);
603 pixman_renderer_surface_state_destroy(ps);
607 surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
609 struct pixman_surface_state *ps;
611 ps = container_of(listener, struct pixman_surface_state,
612 renderer_destroy_listener);
614 pixman_renderer_surface_state_destroy(ps);
618 pixman_renderer_create_surface(struct weston_surface *surface)
620 struct pixman_surface_state *ps;
621 struct pixman_renderer *pr = get_renderer(surface->compositor);
623 ps = calloc(1, sizeof *ps);
627 surface->renderer_state = ps;
629 ps->surface = surface;
631 ps->surface_destroy_listener.notify =
632 surface_state_handle_surface_destroy;
633 wl_signal_add(&surface->destroy_signal,
634 &ps->surface_destroy_listener);
636 ps->renderer_destroy_listener.notify =
637 surface_state_handle_renderer_destroy;
638 wl_signal_add(&pr->destroy_signal,
639 &ps->renderer_destroy_listener);
645 pixman_renderer_surface_set_color(struct weston_surface *es,
646 float red, float green, float blue, float alpha)
648 struct pixman_surface_state *ps = get_surface_state(es);
649 pixman_color_t color;
651 color.red = red * 0xffff;
652 color.green = green * 0xffff;
653 color.blue = blue * 0xffff;
654 color.alpha = alpha * 0xffff;
657 pixman_image_unref(ps->image);
661 ps->image = pixman_image_create_solid_fill(&color);
665 pixman_renderer_destroy(struct weston_compositor *ec)
667 struct pixman_renderer *pr = get_renderer(ec);
669 wl_signal_emit(&pr->destroy_signal, pr);
670 weston_binding_destroy(pr->debug_binding);
677 debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
680 struct weston_compositor *ec = data;
681 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
683 pr->repaint_debug ^= 1;
685 if (pr->repaint_debug) {
686 pixman_color_t red = {
687 0x3fff, 0x0000, 0x0000, 0x3fff
690 pr->debug_color = pixman_image_create_solid_fill(&red);
692 pixman_image_unref(pr->debug_color);
693 weston_compositor_damage_all(ec);
698 pixman_renderer_init(struct weston_compositor *ec)
700 struct pixman_renderer *renderer;
702 renderer = calloc(1, sizeof *renderer);
703 if (renderer == NULL)
706 renderer->repaint_debug = 0;
707 renderer->debug_color = NULL;
708 renderer->base.read_pixels = pixman_renderer_read_pixels;
709 renderer->base.repaint_output = pixman_renderer_repaint_output;
710 renderer->base.flush_damage = pixman_renderer_flush_damage;
711 renderer->base.attach = pixman_renderer_attach;
712 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
713 renderer->base.destroy = pixman_renderer_destroy;
714 ec->renderer = &renderer->base;
715 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
716 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
718 renderer->debug_binding =
719 weston_compositor_add_debug_binding(ec, KEY_R,
722 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
724 wl_signal_init(&renderer->destroy_signal);
730 pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
732 struct pixman_output_state *po = get_output_state(output);
735 pixman_image_unref(po->hw_buffer);
736 po->hw_buffer = buffer;
739 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
740 pixman_image_ref(po->hw_buffer);
745 pixman_renderer_output_create(struct weston_output *output)
747 struct pixman_output_state *po = calloc(1, sizeof *po);
753 /* set shadow image transformation */
754 w = output->current_mode->width;
755 h = output->current_mode->height;
757 po->shadow_buffer = malloc(w * h * 4);
759 if (!po->shadow_buffer) {
765 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
766 po->shadow_buffer, w * 4);
768 if (!po->shadow_image) {
769 free(po->shadow_buffer);
774 output->renderer_state = po;
780 pixman_renderer_output_destroy(struct weston_output *output)
782 struct pixman_output_state *po = get_output_state(output);
784 pixman_image_unref(po->shadow_image);
787 pixman_image_unref(po->hw_buffer);
789 po->shadow_image = NULL;
790 po->hw_buffer = NULL;