Example #1
0
        void shoot(wl_resource *resource)
        {
            if (!wl_shm_buffer_get(resource)) {
                failed();
                return;
            }

            wl_shm_buffer *shm = wl_shm_buffer_get(resource);
            int width = wl_shm_buffer_get_width(shm);
            int height = wl_shm_buffer_get_height(shm);
            int stride = wl_shm_buffer_get_stride(shm);
            QSize size = m_surface->contentSize();

            if (stride != size.width() * 4 || height != size.height()) {
                failed();
                return;
            }

            wl_shm_buffer_begin_access(shm);

            void *data = wl_shm_buffer_get_data(shm);
            m_surface->copyContent(data, stride * height, QRect(0, 0, width, height));

            wl_shm_buffer_end_access(shm);

            orbital_surface_screenshot_send_done(m_resource);
            wl_resource_destroy(m_resource);
            delete this;
        }
Example #2
0
static bool
shm_attach(struct wlc_surface *surface, struct wlc_buffer *buffer, struct wl_shm_buffer *shm_buffer)
{
   assert(surface && buffer && shm_buffer);

   buffer->shm_buffer = shm_buffer;
   buffer->size.w = wl_shm_buffer_get_width(shm_buffer);
   buffer->size.h = wl_shm_buffer_get_height(shm_buffer);

   GLint pitch;
   GLenum gl_format, gl_pixel_type;
   switch (wl_shm_buffer_get_format(shm_buffer)) {
      case WL_SHM_FORMAT_XRGB8888:
         pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
         gl_format = GL_BGRA_EXT;
         gl_pixel_type = GL_UNSIGNED_BYTE;
         surface->format = SURFACE_RGB;
         break;
      case WL_SHM_FORMAT_ARGB8888:
         pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
         gl_format = GL_BGRA_EXT;
         gl_pixel_type = GL_UNSIGNED_BYTE;
         surface->format = SURFACE_RGBA;
         break;
      case WL_SHM_FORMAT_RGB565:
         pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;
         gl_format = GL_RGB;
         gl_pixel_type = GL_UNSIGNED_SHORT_5_6_5;
         surface->format = SURFACE_RGB;
         break;
      default:
         /* unknown shm buffer format */
         return false;
   }

   struct wlc_view *view;
   if ((view = convert_from_wlc_handle(surface->view, "view")) && view->x11.id)
      surface->format = wlc_x11_window_get_surface_format(&view->x11);

   surface_gen_textures(surface, 1);
   GL_CALL(glBindTexture(GL_TEXTURE_2D, surface->textures[0]));
   GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch));
   GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0));
   GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0));
   wl_shm_buffer_begin_access(buffer->shm_buffer);
   void *data = wl_shm_buffer_get_data(buffer->shm_buffer);
   GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, gl_format, pitch, buffer->size.h, 0, gl_format, gl_pixel_type, data));
   wl_shm_buffer_end_access(buffer->shm_buffer);
   return true;
}
Example #3
0
static gboolean
process_shm_buffer_damage (MetaWaylandBuffer *buffer,
                           CoglTexture       *texture,
                           cairo_region_t    *region,
                           GError           **error)
{
  struct wl_shm_buffer *shm_buffer;
  int i, n_rectangles;
  gboolean set_texture_failed = FALSE;

  n_rectangles = cairo_region_num_rectangles (region);

  shm_buffer = wl_shm_buffer_get (buffer->resource);
  wl_shm_buffer_begin_access (shm_buffer);

  for (i = 0; i < n_rectangles; i++)
    {
      const uint8_t *data = wl_shm_buffer_get_data (shm_buffer);
      int32_t stride = wl_shm_buffer_get_stride (shm_buffer);
      CoglPixelFormat format;
      int bpp;
      cairo_rectangle_int_t rect;

      shm_buffer_get_cogl_pixel_format (shm_buffer, &format, NULL);
      bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
      cairo_region_get_rectangle (region, i, &rect);

      if (!_cogl_texture_set_region (texture,
                                     rect.width, rect.height,
                                     format,
                                     stride,
                                     data + rect.x * bpp + rect.y * stride,
                                     rect.x, rect.y,
                                     0,
                                     error))
        {
          set_texture_failed = TRUE;
          break;
        }
    }

  wl_shm_buffer_end_access (shm_buffer);

  return !set_texture_failed;
}
Example #4
0
static void
noop_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
	struct wl_shm_buffer *shm_buffer;
	uint8_t *data;
	uint32_t size, i, width, height, stride;
	volatile unsigned char unused = 0; /* volatile so it's not optimized out */

	if (!buffer)
		return;

	shm_buffer = wl_shm_buffer_get(buffer->resource);

	if (!shm_buffer) {
		weston_log("No-op renderer supports only SHM buffers\n");
		return;
	}

	data = wl_shm_buffer_get_data(shm_buffer);
	stride = wl_shm_buffer_get_stride(shm_buffer);
	width = wl_shm_buffer_get_width(shm_buffer);
	height = wl_shm_buffer_get_height(shm_buffer);
	size = stride * height;

	/* Access the buffer data to make sure the buffer's client gets killed
	 * if the buffer size is invalid. This makes the bad_buffer test pass.
	 * This can be removed if we start reading the buffer contents
	 * somewhere else, e.g. in repaint_output(). */
	wl_shm_buffer_begin_access(shm_buffer);
	for (i = 0; i < size; i++)
		unused ^= data[i];
	wl_shm_buffer_end_access(shm_buffer);

	buffer->shm_buffer = shm_buffer;
	buffer->width = width;
	buffer->height = height;
}
Example #5
0
static void
repaint_region(struct weston_view *ev, struct weston_output *output,
	       pixman_region32_t *region, pixman_region32_t *surf_region,
	       pixman_op_t pixman_op)
{
	struct pixman_renderer *pr =
		(struct pixman_renderer *) output->compositor->renderer;
	struct pixman_surface_state *ps = get_surface_state(ev->surface);
	struct pixman_output_state *po = get_output_state(output);
	pixman_region32_t final_region;
	float view_x, view_y;
	pixman_transform_t transform;
	pixman_fixed_t fw, fh;

	/* 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
	 */
	pixman_region32_init(&final_region);
	if (surf_region) {
		pixman_region32_copy(&final_region, surf_region);

		/* Convert from surface to global coordinates */
		if (!ev->transform.enabled) {
			pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
		} else {
			weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
			pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
		}

		/* We need to paint the intersection */
		pixman_region32_intersect(&final_region, &final_region, region);
	} else {
		/* If there is no surface region, just use the global region */
		pixman_region32_copy(&final_region, region);
	}

	/* Convert from global to output coord */
	region_global_to_output(output, &final_region);

	/* And clip to it */
	pixman_image_set_clip_region32 (po->shadow_image, &final_region);

	/* Set up the source transformation based on the surface
	   position, the output position/transform/scale and the client
	   specified buffer transform/scale */
	pixman_transform_init_identity(&transform);
	pixman_transform_scale(&transform, NULL,
			       pixman_double_to_fixed ((double)1.0/output->current_scale),
			       pixman_double_to_fixed ((double)1.0/output->current_scale));

	fw = pixman_int_to_fixed(output->width);
	fh = pixman_int_to_fixed(output->height);
	switch (output->transform) {
	default:
	case WL_OUTPUT_TRANSFORM_NORMAL:
	case WL_OUTPUT_TRANSFORM_FLIPPED:
		break;
	case WL_OUTPUT_TRANSFORM_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
		pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
		pixman_transform_translate(&transform, NULL, 0, fh);
		break;
	case WL_OUTPUT_TRANSFORM_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
		pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
		pixman_transform_translate(&transform, NULL, fw, fh);
		break;
	case WL_OUTPUT_TRANSFORM_270:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
		pixman_transform_translate(&transform, NULL, fw, 0);
		break;
	}

	switch (output->transform) {
	case WL_OUTPUT_TRANSFORM_FLIPPED:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		pixman_transform_scale(&transform, NULL,
				       pixman_int_to_fixed (-1),
				       pixman_int_to_fixed (1));
		pixman_transform_translate(&transform, NULL, fw, 0);
		break;
	}

        pixman_transform_translate(&transform, NULL,
				   pixman_double_to_fixed (output->x),
				   pixman_double_to_fixed (output->y));

	if (ev->transform.enabled) {
		/* Pixman supports only 2D transform matrix, but Weston uses 3D,
		 * so we're omitting Z coordinate here
		 */
		pixman_transform_t surface_transform = {{
				{ D2F(ev->transform.matrix.d[0]),
				  D2F(ev->transform.matrix.d[4]),
				  D2F(ev->transform.matrix.d[12]),
				},
				{ D2F(ev->transform.matrix.d[1]),
				  D2F(ev->transform.matrix.d[5]),
				  D2F(ev->transform.matrix.d[13]),
				},
				{ D2F(ev->transform.matrix.d[3]),
				  D2F(ev->transform.matrix.d[7]),
				  D2F(ev->transform.matrix.d[15]),
				}
			}};

		pixman_transform_invert(&surface_transform, &surface_transform);
		pixman_transform_multiply (&transform, &surface_transform, &transform);
	} else {
		pixman_transform_translate(&transform, NULL,
					   pixman_double_to_fixed ((double)-ev->geometry.x),
					   pixman_double_to_fixed ((double)-ev->geometry.y));
	}

	if (ev->surface->buffer_viewport.scaler_set) {
		double scaler_x, scaler_y, scaler_width, scaler_height;
		double ratio_x, ratio_y;

		scaler_x = wl_fixed_to_double(ev->surface->buffer_viewport.src_x);
		scaler_y = wl_fixed_to_double(ev->surface->buffer_viewport.src_y);
		scaler_width = wl_fixed_to_double(ev->surface->buffer_viewport.src_width);
		scaler_height = wl_fixed_to_double(ev->surface->buffer_viewport.src_height);

		ratio_x = scaler_width / ev->surface->buffer_viewport.dst_width;
		ratio_y = scaler_height / ev->surface->buffer_viewport.dst_height;

		pixman_transform_scale(&transform, NULL,
				       pixman_double_to_fixed(ratio_x),
				       pixman_double_to_fixed(ratio_y));
		pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(scaler_x),
							     pixman_double_to_fixed(scaler_y));
	}

	pixman_transform_scale(&transform, NULL,
			       pixman_double_to_fixed(ev->surface->buffer_viewport.scale),
			       pixman_double_to_fixed(ev->surface->buffer_viewport.scale));

	fw = pixman_int_to_fixed(pixman_image_get_width(ps->image));
	fh = pixman_int_to_fixed(pixman_image_get_height(ps->image));

	switch (ev->surface->buffer_viewport.transform) {
	case WL_OUTPUT_TRANSFORM_FLIPPED:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		pixman_transform_scale(&transform, NULL,
				       pixman_int_to_fixed (-1),
				       pixman_int_to_fixed (1));
		pixman_transform_translate(&transform, NULL, fw, 0);
		break;
	}

	switch (ev->surface->buffer_viewport.transform) {
	default:
	case WL_OUTPUT_TRANSFORM_NORMAL:
	case WL_OUTPUT_TRANSFORM_FLIPPED:
		break;
	case WL_OUTPUT_TRANSFORM_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
		pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
		pixman_transform_translate(&transform, NULL, fh, 0);
		break;
	case WL_OUTPUT_TRANSFORM_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
		pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
		pixman_transform_translate(&transform, NULL, fw, fh);
		break;
	case WL_OUTPUT_TRANSFORM_270:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
		pixman_transform_translate(&transform, NULL, 0, fw);
		break;
	}

	pixman_image_set_transform(ps->image, &transform);

	if (ev->transform.enabled || output->current_scale != ev->surface->buffer_viewport.scale)
		pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
	else
		pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);

	if (ps->buffer_ref.buffer)
		wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);

	pixman_image_composite32(pixman_op,
				 ps->image, /* src */
				 NULL /* mask */,
				 po->shadow_image, /* dest */
				 0, 0, /* src_x, src_y */
				 0, 0, /* mask_x, mask_y */
				 0, 0, /* dest_x, dest_y */
				 pixman_image_get_width (po->shadow_image), /* width */
				 pixman_image_get_height (po->shadow_image) /* height */);

	if (ps->buffer_ref.buffer)
		wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);

	if (pr->repaint_debug)
		pixman_image_composite32(PIXMAN_OP_OVER,
					 pr->debug_color, /* src */
					 NULL /* mask */,
					 po->shadow_image, /* dest */
					 0, 0, /* src_x, src_y */
					 0, 0, /* mask_x, mask_y */
					 0, 0, /* dest_x, dest_y */
					 pixman_image_get_width (po->shadow_image), /* width */
					 pixman_image_get_height (po->shadow_image) /* height */);

	pixman_image_set_clip_region32 (po->shadow_image, NULL);

	pixman_region32_fini(&final_region);
}
Example #6
0
static gboolean
shm_buffer_attach (MetaWaylandBuffer  *buffer,
                   CoglTexture       **texture,
                   gboolean           *changed_texture,
                   GError            **error)
{
  MetaBackend *backend = meta_get_backend ();
  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
  CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
  struct wl_shm_buffer *shm_buffer;
  int stride, width, height;
  CoglPixelFormat format;
  CoglTextureComponents components;
  CoglBitmap *bitmap;
  CoglTexture *new_texture;

  shm_buffer = wl_shm_buffer_get (buffer->resource);
  stride = wl_shm_buffer_get_stride (shm_buffer);
  width = wl_shm_buffer_get_width (shm_buffer);
  height = wl_shm_buffer_get_height (shm_buffer);
  shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components);

  if (*texture &&
      cogl_texture_get_width (*texture) == width &&
      cogl_texture_get_height (*texture) == height &&
      cogl_texture_get_components (*texture) == components &&
      _cogl_texture_get_format (*texture) == format)
    {
      buffer->is_y_inverted = TRUE;
      *changed_texture = FALSE;
      return TRUE;
    }

  cogl_clear_object (texture);

  wl_shm_buffer_begin_access (shm_buffer);

  bitmap = cogl_bitmap_new_for_data (cogl_context,
                                     width, height,
                                     format,
                                     stride,
                                     wl_shm_buffer_get_data (shm_buffer));

  new_texture = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap));
  cogl_texture_set_components (new_texture, components);

  if (!cogl_texture_allocate (new_texture, error))
    {
      g_clear_pointer (&new_texture, cogl_object_unref);
      if (g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE))
        {
          CoglTexture2DSliced *texture_sliced;

          g_clear_error (error);

          texture_sliced =
            cogl_texture_2d_sliced_new_from_bitmap (bitmap,
                                                    COGL_TEXTURE_MAX_WASTE);
          new_texture = COGL_TEXTURE (texture_sliced);
          cogl_texture_set_components (new_texture, components);

          if (!cogl_texture_allocate (new_texture, error))
            g_clear_pointer (&new_texture, cogl_object_unref);
        }
    }

  cogl_object_unref (bitmap);

  wl_shm_buffer_end_access (shm_buffer);

  if (!new_texture)
    return FALSE;

  *texture = new_texture;
  *changed_texture = TRUE;
  buffer->is_y_inverted = TRUE;

  return TRUE;
}
Example #7
0
/** Paint an intersected region
 *
 * \param ev The view to be painted.
 * \param output The output being painted.
 * \param repaint_output The region to be painted in output coordinates.
 * \param source_clip The region of the source image to use, in source image
 *                    coordinates. If NULL, use the whole source image.
 * \param pixman_op Compositing operator, either SRC or OVER.
 */
static void
repaint_region(struct weston_view *ev, struct weston_output *output,
	       pixman_region32_t *repaint_output,
	       pixman_region32_t *source_clip,
	       pixman_op_t pixman_op)
{
	struct pixman_renderer *pr =
		(struct pixman_renderer *) output->compositor->renderer;
	struct pixman_surface_state *ps = get_surface_state(ev->surface);
	struct pixman_output_state *po = get_output_state(output);
	struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
	pixman_transform_t transform;
	pixman_filter_t filter;
	pixman_image_t *mask_image;
	pixman_color_t mask = { 0, };

	/* Clip rendering to the damaged output region */
	pixman_image_set_clip_region32(po->shadow_image, repaint_output);

	pixman_renderer_compute_transform(&transform, ev, output);

	if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
		filter = PIXMAN_FILTER_BILINEAR;
	else
		filter = PIXMAN_FILTER_NEAREST;

	if (ps->buffer_ref.buffer)
		wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);

	if (ev->alpha < 1.0) {
		mask.alpha = 0xffff * ev->alpha;
		mask_image = pixman_image_create_solid_fill(&mask);
	} else {
		mask_image = NULL;
	}

	if (source_clip)
		composite_clipped(ps->image, mask_image, po->shadow_image,
				  &transform, filter, source_clip);
	else
		composite_whole(pixman_op, ps->image, mask_image,
				po->shadow_image, &transform, filter);

	if (mask_image)
		pixman_image_unref(mask_image);

	if (ps->buffer_ref.buffer)
		wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);

	if (pr->repaint_debug)
		pixman_image_composite32(PIXMAN_OP_OVER,
					 pr->debug_color, /* src */
					 NULL /* mask */,
					 po->shadow_image, /* dest */
					 0, 0, /* src_x, src_y */
					 0, 0, /* mask_x, mask_y */
					 0, 0, /* dest_x, dest_y */
					 pixman_image_get_width (po->shadow_image), /* width */
					 pixman_image_get_height (po->shadow_image) /* height */);

	pixman_image_set_clip_region32 (po->shadow_image, NULL);
}
static void wstRendererNXCommitShm( WstRendererNX *renderer, WstRenderSurface *surface, struct wl_resource *resource )
{
   struct wl_shm_buffer *shmBuffer;
   int width, height, stride;
   int pixelFormat, i;
   void *data;
   NEXUS_SurfaceMemory mem;
   NEXUS_SurfaceComposition composition;            
   NEXUS_SurfaceHandle nexusSurface= 0;

   shmBuffer= wl_shm_buffer_get( resource );
   if ( shmBuffer )
   {
      width= wl_shm_buffer_get_width(shmBuffer);
      height= wl_shm_buffer_get_height(shmBuffer);
      stride= wl_shm_buffer_get_stride(shmBuffer);

      // The SHM formats describe the structure of the color channels for a pixel as
      // they would appear in a machine register not the byte order in memory.  For 
      // example WL_SHM_FORMAT_ARGB8888 is a 32 bit pixel with alpha in the 8 most significant
      // bits and blue in the 8 list significant bits.  On a little endian machine the
      // byte order in memory would be B, G, R, A.
      switch( wl_shm_buffer_get_format(shmBuffer) )
      {
         case WL_SHM_FORMAT_ARGB8888:
            pixelFormat= NEXUS_PixelFormat_eA8_R8_G8_B8;
            break;
         case WL_SHM_FORMAT_XRGB8888:
            pixelFormat= NEXUS_PixelFormat_eX8_R8_G8_B8;
            break;
         case WL_SHM_FORMAT_BGRA8888:
            pixelFormat= NEXUS_PixelFormat_eB8_G8_R8_A8;
            break;
         case WL_SHM_FORMAT_BGRX8888:
            pixelFormat= NEXUS_PixelFormat_eB8_G8_R8_X8;
            break;
         case WL_SHM_FORMAT_RGB565:
            pixelFormat= NEXUS_PixelFormat_eR5_G6_B5;
            break;
         case WL_SHM_FORMAT_ARGB4444:
            pixelFormat= NEXUS_PixelFormat_eA4_R4_G4_B4;
            break;
         default:
            pixelFormat= NEXUS_PixelFormat_eUnknown;
            break;
      }
      if ( pixelFormat != NEXUS_PixelFormat_eUnknown )
      {
         wl_shm_buffer_begin_access(shmBuffer);
         data= wl_shm_buffer_get_data(shmBuffer);
         
         if ( 
              (surface->surfaceWidth != width) ||
              (surface->surfaceHeight != height) ||
              (surface->surfacePixelFormat != pixelFormat)
            )
         {
            wstRendererAllocSurfaces( renderer, surface, width, height, pixelFormat );
         }
         
         nexusSurface= surface->surface[surface->back];
         if ( nexusSurface )
         {            
            unsigned char *src, *dest;
            
            NEXUS_Surface_GetMemory( nexusSurface, &mem );

            src= (unsigned char *)data;
            dest= (unsigned char *)mem.buffer;

            if ( mem.pitch == stride )
            {
               memcpy( dest, src, height*stride );
               dest += height*mem.pitch;
            }
            else
            {               
               for( i= 0; i < height; ++i )
               {
                  memcpy( dest, src, stride );
                  if ( stride < mem.pitch )
                  {
                     memset( dest+stride, 0, (mem.pitch-stride) );
                  }
                  dest += mem.pitch;
                  src += stride;
               }
            }
            if ( height < surface->surfaceHeight )
            {
               memset( dest, 0, mem.pitch*(surface->surfaceHeight-height) );
            }
            NEXUS_Surface_Flush( nexusSurface );

            if ( !surface->sizeOverride )
            {
               surface->width= surface->surfaceWidth;
               surface->height= surface->surfaceHeight;
            }

            if ( !renderer->isDelegate )
            {
               NxClient_GetSurfaceClientComposition(surface->allocResults.surfaceClient[0].id, &composition);
               composition.position.width= surface->width;
               composition.position.height= surface->height;
               NxClient_SetSurfaceClientComposition(surface->allocResults.surfaceClient[0].id, &composition);
            }

            unsigned n= 0;
            do
            {
               NEXUS_SurfaceHandle surface_list[10];
               int rc = NEXUS_SurfaceClient_RecycleSurface(surface->gfxSurfaceClient, surface_list, 10, &n);
               if (rc) break;
            }
            while (n >= 10);

            surface->surfacePending= nexusSurface;
         }

         wl_shm_buffer_end_access(shmBuffer);
         
         ++surface->back;
         if ( surface->back >= NUM_SURFACES )
         {
            surface->back= 0;
         }
      }
   }
}