static struct native_surface *
android_display_create_window_surface(struct native_display *ndpy,
                                      EGLNativeWindowType win,
                                      const struct native_config *nconf)
{
   struct android_display *adpy = android_display(ndpy);
   struct android_config *aconf = android_config(nconf);
   struct android_surface *asurf;
   enum pipe_format format;
   int val;

   if (win->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) {
      LOGE("invalid native window with magic 0x%x", win->common.magic);
      return NULL;
   }
   if (win->query(win, NATIVE_WINDOW_FORMAT, &val)) {
      LOGE("failed to query native window format");
      return NULL;
   }
   format = get_pipe_format(val);
   if (format != nconf->color_format) {
      LOGW("native window format 0x%x != config format 0x%x",
            format, nconf->color_format);
      if (!adpy->base.screen->is_format_supported(adpy->base.screen,
               format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET)) {
         LOGE("and the native window cannot be used as a render target");
         return NULL;
      }
   }

   asurf = CALLOC_STRUCT(android_surface);
   if (!asurf)
      return NULL;

   asurf->adpy = adpy;
   asurf->win = win;
   asurf->win->common.incRef(&asurf->win->common);

   /* request buffers that are for CPU access */
   if (!adpy->use_drm) {
      native_window_set_usage(asurf->win,
            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
   }

   asurf->base.destroy = android_surface_destroy;
   asurf->base.present = android_surface_present;
   asurf->base.validate = android_surface_validate;
   asurf->base.wait = android_surface_wait;

   return &asurf->base;
}
static boolean
android_display_init_configs(struct native_display *ndpy)
{
   struct android_display *adpy = android_display(ndpy);
   const int native_formats[] = {
      HAL_PIXEL_FORMAT_RGBA_8888,
      HAL_PIXEL_FORMAT_RGBX_8888,
      HAL_PIXEL_FORMAT_RGB_888,
      HAL_PIXEL_FORMAT_RGB_565,
      HAL_PIXEL_FORMAT_BGRA_8888,
   };
   int i;

   adpy->configs = (struct android_config *)
      CALLOC(Elements(native_formats), sizeof(*adpy->configs));
   if (!adpy->configs)
      return FALSE;

   for (i = 0; i < Elements(native_formats); i++) {
      enum pipe_format color_format;
      struct android_config *aconf;

      color_format = get_pipe_format(native_formats[i]);
      if (color_format == PIPE_FORMAT_NONE ||
          !adpy->base.screen->is_format_supported(adpy->base.screen,
               color_format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET)) {
         LOGI("skip unsupported native format 0x%x", native_formats[i]);
         continue;
      }

      aconf = &adpy->configs[adpy->num_configs++];
      /* only the back buffer */
      aconf->base.buffer_mask = 1 << NATIVE_ATTACHMENT_BACK_LEFT;
      aconf->base.color_format = color_format;
      aconf->base.window_bit = TRUE;

      aconf->base.native_visual_id = native_formats[i];
      aconf->base.native_visual_type = native_formats[i];
   }

   return TRUE;
}
static struct pipe_resource *
android_display_import_buffer(struct native_display *ndpy,
                              struct native_buffer *nbuf)
{
   struct android_display *adpy = android_display(ndpy);
   ANativeWindowBuffer *abuf;
   enum pipe_format format;
   struct pipe_resource templ;

   if (nbuf->type != NATIVE_BUFFER_ANDROID)
      return NULL;

   abuf = nbuf->u.android;

   if (!abuf || abuf->common.magic != ANDROID_NATIVE_BUFFER_MAGIC ||
       abuf->common.version != sizeof(*abuf)) {
      LOGE("invalid android native buffer");
      return NULL;
   }

   format = get_pipe_format(abuf->format);
   if (format == PIPE_FORMAT_NONE)
      return NULL;

   memset(&templ, 0, sizeof(templ));
   templ.target = PIPE_TEXTURE_2D;
   templ.format = format;
   /* assume for texturing only */
   templ.bind = PIPE_BIND_SAMPLER_VIEW;
   templ.width0 = abuf->width;
   templ.height0 = abuf->height;
   templ.depth0 = 1;
   templ.array_size = 1;

   return import_buffer(adpy, &templ, abuf);
}
static struct pipe_resource *
android_surface_add_cache(struct native_surface *nsurf,
                          ANativeWindowBuffer *abuf)
{
   struct android_surface *asurf = android_surface(nsurf);
   void *handle;
   int idx;

   /* how about abuf->usage? */
   if (asurf->cache_key.width != abuf->width ||
       asurf->cache_key.height != abuf->height ||
       asurf->cache_key.format != abuf->format)
      android_surface_clear_cache(&asurf->base);

   if (asurf->adpy->use_drm)
      handle = (void *) get_handle_name(abuf->handle);
   else
      handle = (void *) abuf->handle;
   /* NULL is invalid */
   if (!handle) {
      LOGE("invalid buffer native buffer %p", abuf);
      return NULL;
   }

   /* find the slot to use */
   for (idx = 0; idx < Elements(asurf->cache_handles); idx++) {
      if (asurf->cache_handles[idx] == handle || !asurf->cache_handles[idx])
         break;
   }
   if (idx == Elements(asurf->cache_handles)) {
      LOGW("cache full: buf %p, width %d, height %d, format %d, usage 0x%x",
            abuf, abuf->width, abuf->height, abuf->format, abuf->usage);
      android_surface_clear_cache(&asurf->base);
      idx = 0;
   }

   if (idx == 0) {
      asurf->cache_key.width = abuf->width;
      asurf->cache_key.height = abuf->height;
      asurf->cache_key.format = abuf->format;
   }

   if (!asurf->cache_handles[idx]) {
      struct pipe_resource templ;

      assert(!asurf->cache_resources[idx]);

      memset(&templ, 0, sizeof(templ));
      templ.target = PIPE_TEXTURE_2D;
      templ.format = get_pipe_format(asurf->buf->format);
      templ.bind = PIPE_BIND_RENDER_TARGET;
      if (!asurf->adpy->use_drm) {
         templ.bind |= PIPE_BIND_TRANSFER_WRITE |
                       PIPE_BIND_TRANSFER_READ;
      }

      templ.width0 = asurf->buf->width;
      templ.height0 = asurf->buf->height;
      templ.depth0 = 1;
      templ.array_size = 1;

      if (templ.format != PIPE_FORMAT_NONE) {
         asurf->cache_resources[idx] =
            import_buffer(asurf->adpy, &templ, asurf->buf);
      }
      else {
         asurf->cache_resources[idx] = NULL;
      }

      asurf->cache_handles[idx] = handle;
   }

   return asurf->cache_resources[idx];
}
static struct pipe_buffer *get_pipe_buffer_locked(struct pipe_manager *pm,
		const struct gralloc_drm_handle_t *handle)
{
	struct pipe_buffer *buf;
	struct pipe_resource templ;

	memset(&templ, 0, sizeof(templ));
	templ.format = get_pipe_format(handle->format);
	templ.bind = get_pipe_bind(handle->usage);
	templ.target = PIPE_TEXTURE_2D;

	if (templ.format == PIPE_FORMAT_NONE ||
	    !pm->screen->is_format_supported(pm->screen, templ.format,
				templ.target, 0, templ.bind)) {
		LOGE("unsupported format 0x%x", handle->format);
		return NULL;
	}

	buf = CALLOC(1, sizeof(*buf));
	if (!buf) {
		LOGE("failed to allocate pipe buffer");
		return NULL;
	}

	templ.width0 = handle->width;
	templ.height0 = handle->height;
	templ.depth0 = 1;
	templ.array_size = 1;

	if (handle->name) {
		buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
		buf->winsys.handle = handle->name;
		buf->winsys.stride = handle->stride;

		buf->resource = pm->screen->resource_from_handle(pm->screen,
				&templ, &buf->winsys);
		if (!buf->resource)
			goto fail;
	}
	else {
		buf->resource =
			pm->screen->resource_create(pm->screen, &templ);
		if (!buf->resource)
			goto fail;

		buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
		if (!pm->screen->resource_get_handle(pm->screen,
					buf->resource, &buf->winsys))
			goto fail;
	}

	/* need the gem handle for fb */
	if (handle->usage & GRALLOC_USAGE_HW_FB) {
		struct winsys_handle tmp;

		memset(&tmp, 0, sizeof(tmp));
		tmp.type = DRM_API_HANDLE_TYPE_KMS;
		if (!pm->screen->resource_get_handle(pm->screen,
					buf->resource, &tmp))
			goto fail;

		buf->base.fb_handle = tmp.handle;
	}

	return buf;

fail:
	LOGE("failed to allocate pipe buffer");
	if (buf->resource)
		pipe_resource_reference(&buf->resource, NULL);
	FREE(buf);

	return NULL;
}