Пример #1
0
static struct svga_winsys_surface *
vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
                               SVGA3dSurfaceFlags flags,
                               SVGA3dSurfaceFormat format,
                               SVGA3dSize size,
                               uint32 numFaces,
                               uint32 numMipLevels)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
   struct vmw_svga_winsys_surface *surface;

   surface = CALLOC_STRUCT(vmw_svga_winsys_surface);
   if(!surface)
      goto no_surface;

   pipe_reference_init(&surface->refcnt, 1);
   p_atomic_set(&surface->validated, 0);
   surface->screen = vws;
   surface->sid = vmw_ioctl_surface_create(vws,
                                           flags, format, size,
                                           numFaces, numMipLevels);
   if(surface->sid == SVGA3D_INVALID_ID)
      goto no_sid;

   return svga_winsys_surface(surface);

no_sid:
   FREE(surface);
no_surface:
   return NULL;
}
Пример #2
0
static void
vmw_svga_winsys_destroy(struct svga_winsys_screen *sws)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);

   vmw_winsys_destroy(vws);
}
Пример #3
0
static int
vmw_svga_winsys_fence_finish(struct svga_winsys_screen *sws,
                             struct pipe_fence_handle *fence,
                             unsigned flag)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);

   return vmw_fence_finish(vws, fence, flag);
}
Пример #4
0
static int
vmw_svga_winsys_fence_finish(struct svga_winsys_screen *sws,
                             struct pipe_fence_handle *fence,
                             unsigned flag)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
   (void)flag;
   return vmw_ioctl_fence_finish(vws, vmw_fence(fence));
}
Пример #5
0
static void
vmw_svga_winsys_fence_reference(struct svga_winsys_screen *sws,
                                struct pipe_fence_handle **pdst,
                                struct pipe_fence_handle *src)
{
    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);

    vmw_fence_reference(vws, pdst, src);
}
Пример #6
0
static void
vmw_dri1_present_locked(struct pipe_context *locked_pipe,
			struct pipe_surface *surf,
			const struct drm_clip_rect *rect,
			unsigned int num_clip,
			int x_draw, int y_draw,
			const struct drm_clip_rect *bbox,
			struct pipe_fence_handle **p_fence)
{
   struct svga_winsys_surface *srf =
      svga_screen_texture_get_winsys_surface(surf->texture);
   struct vmw_svga_winsys_surface *vsrf = vmw_svga_winsys_surface(srf);
   struct vmw_winsys_screen *vws =
      vmw_winsys_screen(svga_winsys_screen(locked_pipe->screen));
   struct drm_clip_rect clip;
   int i;
   struct
   {
      SVGA3dCmdHeader header;
      SVGA3dCmdPresent body;
      SVGA3dCopyRect rect;
   } cmd;
   boolean visible = FALSE;
   uint32_t fence_seq = 0;

   VMW_FUNC;
   cmd.header.id = SVGA_3D_CMD_PRESENT;
   cmd.header.size = sizeof cmd.body + sizeof cmd.rect;
   cmd.body.sid = vsrf->sid;

   for (i = 0; i < num_clip; ++i) {
      if (!vmw_dri1_intersect_src_bbox(&clip, x_draw, y_draw, rect++, bbox))
	 continue;

      cmd.rect.x = clip.x1;
      cmd.rect.y = clip.y1;
      cmd.rect.w = clip.x2 - clip.x1;
      cmd.rect.h = clip.y2 - clip.y1;
      cmd.rect.srcx = (int)clip.x1 - x_draw;
      cmd.rect.srcy = (int)clip.y1 - y_draw;

      vmw_printf("%s: Clip %d x %d y %d w %d h %d srcx %d srcy %d\n",
		   __FUNCTION__,
		   i,
		   cmd.rect.x,
		   cmd.rect.y,
		   cmd.rect.w, cmd.rect.h, cmd.rect.srcx, cmd.rect.srcy);

      vmw_ioctl_command(vws, &cmd, sizeof cmd.header + cmd.header.size,
                        &fence_seq);
      visible = TRUE;
   }

   *p_fence = (visible) ? vmw_pipe_fence(fence_seq) : NULL;
   vmw_svga_winsys_surface_reference(&vsrf, NULL);
}
Пример #7
0
static SVGA3dHardwareVersion
vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);

   if (sws->have_gb_objects)
      return SVGA3D_HWVERSION_WS8_B1;

   return (SVGA3dHardwareVersion) vws->ioctl.hwversion;
}
Пример #8
0
static SVGA3dHardwareVersion
vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);

   if (!vws->ioctl.fifo_map) {
      return 0;
   }

   return vws->ioctl.fifo_map[SVGA_FIFO_3D_HWVERSION];
}
Пример #9
0
struct svga_winsys_context *
vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
   struct vmw_svga_winsys_context *vswc;

   vswc = CALLOC_STRUCT(vmw_svga_winsys_context);
   if(!vswc)
      return NULL;

   vswc->base.destroy = vmw_swc_destroy;
   vswc->base.reserve = vmw_swc_reserve;
   vswc->base.surface_relocation = vmw_swc_surface_relocation;
   vswc->base.region_relocation = vmw_swc_region_relocation;
   vswc->base.mob_relocation = vmw_swc_mob_relocation;
   vswc->base.context_relocation = vmw_swc_context_relocation;
   vswc->base.shader_relocation = vmw_swc_shader_relocation;
   vswc->base.commit = vmw_swc_commit;
   vswc->base.flush = vmw_swc_flush;
   vswc->base.surface_map = vmw_svga_winsys_surface_map;
   vswc->base.surface_unmap = vmw_svga_winsys_surface_unmap;

   vswc->base.cid = vmw_ioctl_context_create(vws);
   vswc->base.have_gb_objects = sws->have_gb_objects;

   vswc->vws = vws;

   vswc->command.size = VMW_COMMAND_SIZE;
   vswc->surface.size = VMW_SURFACE_RELOCS;
   vswc->shader.size = VMW_SHADER_RELOCS;
   vswc->region.size = VMW_REGION_RELOCS;

   vswc->validate = pb_validate_create();
   if(!vswc->validate)
      goto out_no_validate;

   vswc->hash = util_hash_table_create(vmw_hash_ptr, vmw_ptr_compare);
   if (!vswc->hash)
      goto out_no_hash;

#ifdef DEBUG
   vswc->fctx = debug_flush_ctx_create(TRUE, VMW_DEBUG_FLUSH_STACK);
#endif

   return &vswc->base;

out_no_hash:
   pb_validate_destroy(vswc->validate);
out_no_validate:
   FREE(vswc);
   return NULL;
}
Пример #10
0
static boolean
vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,
                        SVGA3dDevCapIndex index,
                        SVGA3dDevCapResult *result)
{   
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);

   if (index > vws->ioctl.num_cap_3d ||
       index >= SVGA3D_DEVCAP_MAX ||
       !vws->ioctl.cap_3d[index].has_cap)
      return FALSE;

   *result = vws->ioctl.cap_3d[index].result;
   return TRUE;
}
Пример #11
0
struct svga_winsys_gb_shader *
vmw_svga_winsys_shader_create(struct svga_winsys_screen *sws,
			      SVGA3dShaderType type,
			      const uint32 *bytecode,
			      uint32 bytecodeLen)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
   struct vmw_svga_winsys_shader *shader;
   void *code;

   shader = CALLOC_STRUCT(vmw_svga_winsys_shader);
   if(!shader)
      goto out_no_shader;

   pipe_reference_init(&shader->refcnt, 1);
   p_atomic_set(&shader->validated, 0);
   shader->screen = vws;
   shader->buf = vmw_svga_winsys_buffer_create(sws, 64,
					       SVGA_BUFFER_USAGE_SHADER,
					       bytecodeLen);
   if (!shader->buf)
      goto out_no_buf;

   code = vmw_svga_winsys_buffer_map(sws, shader->buf, PIPE_TRANSFER_WRITE);
   if (!code)
      goto out_no_buf;

   memcpy(code, bytecode, bytecodeLen);
   vmw_svga_winsys_buffer_unmap(sws, shader->buf);

   if (!sws->have_vgpu10) {
      shader->shid = vmw_ioctl_shader_create(vws, type, bytecodeLen);
      if (shader->shid == SVGA3D_INVALID_ID)
         goto out_no_shid;
   }

   return svga_winsys_shader(shader);

out_no_shid:
   vmw_svga_winsys_buffer_destroy(sws, shader->buf);
out_no_buf:
   FREE(shader);
out_no_shader:
   return NULL;
}
Пример #12
0
static boolean
vmw_svga_winsys_surface_can_create(struct svga_winsys_screen *sws,
                               SVGA3dSurfaceFormat format,
                               SVGA3dSize size,
                               uint32 numLayers,
                               uint32 numMipLevels)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
   uint32_t buffer_size;

   buffer_size = svga3dsurface_get_serialized_size(format, size, 
                                                   numMipLevels, 
                                                   numLayers);
   if (buffer_size > vws->ioctl.max_texture_size) {
	return FALSE;
   }
   return TRUE;
}
Пример #13
0
static struct svga_winsys_buffer *
vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,
                              unsigned alignment,
                              unsigned usage,
                              unsigned size)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
   struct vmw_buffer_desc desc;
   struct pb_manager *provider;
   struct pb_buffer *buffer;

   memset(&desc, 0, sizeof desc);
   desc.pb_desc.alignment = alignment;
   desc.pb_desc.usage = usage;

   if (usage == SVGA_BUFFER_USAGE_PINNED) {
      if (vws->pools.query_fenced == NULL && !vmw_query_pools_init(vws))
	 return NULL;
      provider = vws->pools.query_fenced;
   } else if (usage == SVGA_BUFFER_USAGE_SHADER) {
      provider = vws->pools.mob_shader_slab_fenced;
   } else
      provider = vws->pools.gmr_fenced;

   assert(provider);
   buffer = provider->create_buffer(provider, size, &desc.pb_desc);

   if(!buffer && provider == vws->pools.gmr_fenced) {

      assert(provider);
      provider = vws->pools.gmr_slab_fenced;
      buffer = provider->create_buffer(provider, size, &desc.pb_desc);
   }

   if (!buffer)
      return NULL;

   return vmw_svga_winsys_buffer_wrap(buffer);
}
Пример #14
0
static boolean
vmw_drm_surface_get_handle(struct svga_winsys_screen *sws,
			   struct svga_winsys_surface *surface,
			   unsigned stride,
			   struct winsys_handle *whandle)
{
    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    struct vmw_svga_winsys_surface *vsrf;
    int ret;

    if (!surface)
	return FALSE;

    vsrf = vmw_svga_winsys_surface(surface);
    whandle->handle = vsrf->sid;
    whandle->stride = stride;
    whandle->offset = 0;

    switch (whandle->type) {
    case DRM_API_HANDLE_TYPE_SHARED:
    case DRM_API_HANDLE_TYPE_KMS:
       whandle->handle = vsrf->sid;
       break;
    case DRM_API_HANDLE_TYPE_FD:
       ret = drmPrimeHandleToFD(vws->ioctl.drm_fd, vsrf->sid, DRM_CLOEXEC,
				(int *)&whandle->handle);
       if (ret) {
	  vmw_error("Failed to get file descriptor from prime.\n");
	  return FALSE;
       }
       break;
    default:
       vmw_error("Attempt to export unsupported handle type %d.\n",
		 whandle->type);
       return FALSE;
    }

    return TRUE;
}
Пример #15
0
static struct svga_winsys_buffer *
vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,
                              unsigned alignment,
                              unsigned usage,
                              unsigned size)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
   struct pb_desc desc;
   struct pb_manager *provider;
   struct pb_buffer *buffer;

   memset(&desc, 0, sizeof desc);
   desc.alignment = alignment;
   desc.usage = usage;

   provider = vws->pools.gmr_fenced;

   assert(provider);
   buffer = provider->create_buffer(provider, size, &desc);
   if(!buffer)
      return NULL;

   return vmw_svga_winsys_buffer(buffer);
}
Пример #16
0
static boolean
vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,
                        SVGA3dDevCapIndex index,
                        SVGA3dDevCapResult *result)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
   const uint32 *capsBlock;
   const SVGA3dCapsRecord *capsRecord = NULL;
   uint32 offset;
   const SVGA3dCapPair *capArray;
   int numCaps, first, last;

   if(!vws->ioctl.fifo_map)
      return FALSE;

   if(vws->ioctl.fifo_map[SVGA_FIFO_3D_HWVERSION] < SVGA3D_HWVERSION_WS6_B1)
      return FALSE;

   /*
    * Search linearly through the caps block records for the specified type.
    */
   capsBlock = (const uint32 *)&vws->ioctl.fifo_map[SVGA_FIFO_3D_CAPS];
   for (offset = 0; capsBlock[offset] != 0; offset += capsBlock[offset]) {
      const SVGA3dCapsRecord *record;
      assert(offset < SVGA_FIFO_3D_CAPS_SIZE);
      record = (const SVGA3dCapsRecord *) (capsBlock + offset);
      if ((record->header.type >= SVGA3DCAPS_RECORD_DEVCAPS_MIN) &&
          (record->header.type <= SVGA3DCAPS_RECORD_DEVCAPS_MAX) &&
          (!capsRecord || (record->header.type > capsRecord->header.type))) {
         capsRecord = record;
      }
   }

   if(!capsRecord)
      return FALSE;

   /*
    * Calculate the number of caps from the size of the record.
    */
   capArray = (const SVGA3dCapPair *) capsRecord->data;
   numCaps = (int) ((capsRecord->header.length * sizeof(uint32) -
                     sizeof capsRecord->header) / (2 * sizeof(uint32)));

   /*
    * Binary-search for the cap with the specified index.
    */
   for (first = 0, last = numCaps - 1; first <= last; ) {
      int mid = (first + last) / 2;

      if ((SVGA3dDevCapIndex) capArray[mid][0] == index) {
         /*
          * Found it.
          */
         result->u = capArray[mid][1];
         return TRUE;
      }

      /*
       * Divide and conquer.
       */
      if ((SVGA3dDevCapIndex) capArray[mid][0] > index) {
         last = mid - 1;
      } else {
         first = mid + 1;
      }
   }

   return FALSE;
}
Пример #17
0
/**
 * vmw_drm_gb_surface_from_handle - Create a shared surface
 *
 * @sws: Screen to register the surface with.
 * @whandle: struct winsys_handle identifying the kernel surface object
 * @format: On successful return points to a value describing the
 * surface format.
 *
 * Returns a refcounted pointer to a struct svga_winsys_surface
 * embedded in a struct vmw_svga_winsys_surface on success or NULL
 * on failure.
 */
static struct svga_winsys_surface *
vmw_drm_gb_surface_from_handle(struct svga_winsys_screen *sws,
                               struct winsys_handle *whandle,
                               SVGA3dSurfaceFormat *format)
{
    struct vmw_svga_winsys_surface *vsrf;
    struct svga_winsys_surface *ssrf;
    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    SVGA3dSurfaceFlags flags;
    uint32_t mip_levels;
    struct vmw_buffer_desc desc;
    struct pb_manager *provider = vws->pools.gmr;
    struct pb_buffer *pb_buf;
    uint32_t handle;
    int ret;

    if (whandle->offset != 0) {
       fprintf(stderr, "Attempt to import unsupported winsys offset %u\n",
               whandle->offset);
       return NULL;
    }

    ret = vmw_ioctl_gb_surface_ref(vws, whandle, &flags, format,
                                   &mip_levels, &handle, &desc.region);

    if (ret) {
	fprintf(stderr, "Failed referencing shared surface. SID %d.\n"
		"Error %d (%s).\n",
		whandle->handle, ret, strerror(-ret));
	return NULL;
    }

    if (mip_levels != 1) {
       fprintf(stderr, "Incorrect number of mipmap levels on shared surface."
               " SID %d, levels %d\n",
               whandle->handle, mip_levels);
       goto out_mip;
    }

    vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface);
    if (!vsrf)
	goto out_mip;

    pipe_reference_init(&vsrf->refcnt, 1);
    p_atomic_set(&vsrf->validated, 0);
    vsrf->screen = vws;
    vsrf->sid = handle;
    vsrf->size = vmw_region_size(desc.region);

    /*
     * Synchronize backing buffers of shared surfaces using the
     * kernel, since we don't pass fence objects around between
     * processes.
     */
    desc.pb_desc.alignment = 4096;
    desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED | VMW_BUFFER_USAGE_SYNC;
    pb_buf = provider->create_buffer(provider, vsrf->size, &desc.pb_desc);
    vsrf->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
    if (!vsrf->buf)
       goto out_no_buf;
    ssrf = svga_winsys_surface(vsrf);

    return ssrf;

out_no_buf:
    FREE(vsrf);
out_mip:
    vmw_ioctl_region_destroy(desc.region);
    vmw_ioctl_surface_destroy(vws, whandle->handle);
    return NULL;
}
Пример #18
0
static struct svga_winsys_surface *
vmw_drm_surface_from_handle(struct svga_winsys_screen *sws,
                            struct winsys_handle *whandle,
			    SVGA3dSurfaceFormat *format)
{
    struct vmw_svga_winsys_surface *vsrf;
    struct svga_winsys_surface *ssrf;
    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
    union drm_vmw_surface_reference_arg arg;
    struct drm_vmw_surface_arg *req = &arg.req;
    struct drm_vmw_surface_create_req *rep = &arg.rep;
    uint32_t handle = 0;
    struct drm_vmw_size size;
    SVGA3dSize base_size;
    int ret;
    int i;

    if (whandle->offset != 0) {
       fprintf(stderr, "Attempt to import unsupported winsys offset %u\n",
               whandle->offset);
       return NULL;
    }

    switch (whandle->type) {
    case DRM_API_HANDLE_TYPE_SHARED:
    case DRM_API_HANDLE_TYPE_KMS:
       handle = whandle->handle;
       break;
    case DRM_API_HANDLE_TYPE_FD:
       ret = drmPrimeFDToHandle(vws->ioctl.drm_fd, whandle->handle,
                                &handle);
       if (ret) {
	  vmw_error("Failed to get handle from prime fd %d.\n",
		    (int) whandle->handle);
	  return NULL;
       }
       break;
    default:
       vmw_error("Attempt to import unsupported handle type %d.\n",
                 whandle->type);
       return NULL;
    }

    memset(&arg, 0, sizeof(arg));
    req->sid = handle;
    rep->size_addr = (unsigned long)&size;

    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_REF_SURFACE,
			      &arg, sizeof(arg));

    /*
     * Need to close the handle we got from prime.
     */
    if (whandle->type == DRM_API_HANDLE_TYPE_FD)
       vmw_ioctl_surface_destroy(vws, handle);

    if (ret) {
       /*
        * Any attempt to share something other than a surface, like a dumb
        * kms buffer, should fail here.
        */
       vmw_error("Failed referencing shared surface. SID %d.\n"
                 "Error %d (%s).\n",
                 handle, ret, strerror(-ret));
       return NULL;
    }

    if (rep->mip_levels[0] != 1) {
        vmw_error("Incorrect number of mipmap levels on shared surface."
                  " SID %d, levels %d\n",
                  handle, rep->mip_levels[0]);
	goto out_mip;
    }

    for (i=1; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
	if (rep->mip_levels[i] != 0) {
            vmw_error("Incorrect number of faces levels on shared surface."
                      " SID %d, face %d present.\n",
                      handle, i);
	    goto out_mip;
	}
   }

    vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface);
    if (!vsrf)
	goto out_mip;

    pipe_reference_init(&vsrf->refcnt, 1);
    p_atomic_set(&vsrf->validated, 0);
    vsrf->screen = vws;
    vsrf->sid = handle;
    ssrf = svga_winsys_surface(vsrf);
    *format = rep->format;

    /* Estimate usage, for early flushing. */

    base_size.width = size.width;
    base_size.height = size.height;
    base_size.depth = size.depth;
    vsrf->size = svga3dsurface_get_serialized_size(rep->format, base_size,
                                                   rep->mip_levels[0],
                                                   FALSE);

    return ssrf;

out_mip:
    vmw_ioctl_surface_destroy(vws, handle);

    return NULL;
}
Пример #19
0
static struct pipe_buffer *
vmw_drm_buffer_from_handle(struct drm_api *drm_api,
                           struct pipe_screen *screen,
			   const char *name,
			   unsigned handle)
{
    struct vmw_svga_winsys_surface *vsrf;
    struct svga_winsys_surface *ssrf;
    struct vmw_winsys_screen *vws =
	vmw_winsys_screen(svga_winsys_screen(screen));
    struct pipe_buffer *buf;
    union drm_vmw_surface_reference_arg arg;
    struct drm_vmw_surface_arg *req = &arg.req;
    struct drm_vmw_surface_create_req *rep = &arg.rep;
    int ret;
    int i;

    /**
     * The vmware device specific handle is the hardware SID.
     * FIXME: We probably want to move this to the ioctl implementations.
     */

    memset(&arg, 0, sizeof(arg));
    req->sid = handle;

    ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_REF_SURFACE,
			      &arg, sizeof(arg));

    if (ret) {
	fprintf(stderr, "Failed referencing shared surface. SID %d.\n"
		"Error %d (%s).\n",
		handle, ret, strerror(-ret));
	return NULL;
    }

    if (rep->mip_levels[0] != 1) {
	fprintf(stderr, "Incorrect number of mipmap levels on shared surface."
		" SID %d, levels %d\n",
		handle, rep->mip_levels[0]);
	goto out_mip;
    }

    for (i=1; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
	if (rep->mip_levels[i] != 0) {
	    fprintf(stderr, "Incorrect number of faces levels on shared surface."
		    " SID %d, face %d present.\n",
		    handle, i);
	    goto out_mip;
	}
    }

    vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface);
    if (!vsrf)
	goto out_mip;

    pipe_reference_init(&vsrf->refcnt, 1);
    p_atomic_set(&vsrf->validated, 0);
    vsrf->sid = handle;
    ssrf = svga_winsys_surface(vsrf);
    buf = svga_screen_buffer_wrap_surface(screen, rep->format, ssrf);
    if (!buf)
	vmw_svga_winsys_surface_reference(&vsrf, NULL);

    return buf;
  out_mip:
    vmw_ioctl_surface_destroy(vws, handle);
    return NULL;
}
Пример #20
0
static struct svga_winsys_surface *
vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
                               SVGA3dSurfaceFlags flags,
                               SVGA3dSurfaceFormat format,
                               unsigned usage,
                               SVGA3dSize size,
                               uint32 numLayers,
                               uint32 numMipLevels,
                               unsigned sampleCount)
{
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
   struct vmw_svga_winsys_surface *surface;
   struct vmw_buffer_desc desc;
   struct pb_manager *provider;
   uint32_t buffer_size;

   memset(&desc, 0, sizeof(desc));
   surface = CALLOC_STRUCT(vmw_svga_winsys_surface);
   if(!surface)
      goto no_surface;

   pipe_reference_init(&surface->refcnt, 1);
   p_atomic_set(&surface->validated, 0);
   surface->screen = vws;
   pipe_mutex_init(surface->mutex);
   surface->shared = !!(usage & SVGA_SURFACE_USAGE_SHARED);
   provider = (surface->shared) ? vws->pools.gmr : vws->pools.mob_fenced;

   /*
    * Used for the backing buffer GB surfaces, and to approximate
    * when to flush on non-GB hosts.
    */
   buffer_size = svga3dsurface_get_serialized_size(format, size, numMipLevels, 
                                                   numLayers);
   if (flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)
      buffer_size += sizeof(SVGA3dDXSOState);

   if (buffer_size > vws->ioctl.max_texture_size) {
      goto no_sid;
   }

   if (sws->have_gb_objects) {
      SVGAGuestPtr ptr = {0,0};

      /*
       * If the backing buffer size is small enough, try to allocate a
       * buffer out of the buffer cache. Otherwise, let the kernel allocate
       * a suitable buffer for us.
       */
      if (buffer_size < VMW_TRY_CACHED_SIZE && !surface->shared) {
         struct pb_buffer *pb_buf;

         surface->size = buffer_size;
         desc.pb_desc.alignment = 4096;
         desc.pb_desc.usage = 0;
         pb_buf = provider->create_buffer(provider, buffer_size, &desc.pb_desc);
         surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
         if (surface->buf && !vmw_gmr_bufmgr_region_ptr(pb_buf, &ptr))
            assert(0);
      }

      surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
                                                 size, numLayers,
                                                 numMipLevels, sampleCount,
                                                 ptr.gmrId,
                                                 surface->buf ? NULL :
						 &desc.region);

      if (surface->sid == SVGA3D_INVALID_ID && surface->buf) {

         /*
          * Kernel refused to allocate a surface for us.
          * Perhaps something was wrong with our buffer?
          * This is really a guard against future new size requirements
          * on the backing buffers.
          */
         vmw_svga_winsys_buffer_destroy(sws, surface->buf);
         surface->buf = NULL;
         surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
                                                    size, numLayers,
                                                    numMipLevels, sampleCount,
                                                    0, &desc.region);
         if (surface->sid == SVGA3D_INVALID_ID)
            goto no_sid;
      }

      /*
       * If the kernel created the buffer for us, wrap it into a
       * vmw_svga_winsys_buffer.
       */
      if (surface->buf == NULL) {
         struct pb_buffer *pb_buf;

         surface->size = vmw_region_size(desc.region);
         desc.pb_desc.alignment = 4096;
         desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED;
         pb_buf = provider->create_buffer(provider, surface->size,
                                          &desc.pb_desc);
         surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
         if (surface->buf == NULL) {
            vmw_ioctl_region_destroy(desc.region);
            vmw_ioctl_surface_destroy(vws, surface->sid);
            goto no_sid;
         }
      }
   } else {
      surface->sid = vmw_ioctl_surface_create(vws, flags, format, usage,
                                              size, numLayers, numMipLevels,
                                              sampleCount);
      if(surface->sid == SVGA3D_INVALID_ID)
         goto no_sid;

      /* Best estimate for surface size, used for early flushing. */
      surface->size = buffer_size;
      surface->buf = NULL; 
   }      

   return svga_winsys_surface(surface);

no_sid:
   if (surface->buf)
      vmw_svga_winsys_buffer_destroy(sws, surface->buf);

   FREE(surface);
no_surface:
   return NULL;
}