+
+uint32
+vmw_ioctl_gb_surface_create(struct vmw_winsys_screen *vws,
+ SVGA3dSurfaceAllFlags flags,
+ SVGA3dSurfaceFormat format,
+ unsigned usage,
+ SVGA3dSize size,
+ uint32_t numFaces,
+ uint32_t numMipLevels,
+ unsigned sampleCount,
+ uint32_t buffer_handle,
+ SVGA3dMSPattern multisamplePattern,
+ SVGA3dMSQualityLevel qualityLevel,
+ struct vmw_region **p_region)
+{
+ struct drm_vmw_gb_surface_create_rep *rep;
+ struct vmw_region *region = NULL;
+ int ret;
+
+ vmw_printf("%s flags %d format %d\n", __FUNCTION__, flags, format);
+
+ if (p_region) {
+ region = CALLOC_STRUCT(vmw_region);
+ if (!region)
+ return SVGA3D_INVALID_ID;
+ }
+
+ if (vws->ioctl.have_drm_2_15) {
+ union drm_vmw_gb_surface_create_ext_arg s_arg;
+ struct drm_vmw_gb_surface_create_ext_req *req = &s_arg.req;
+ rep = &s_arg.rep;
+
+ memset(&s_arg, 0, sizeof(s_arg));
+
+ req->version = drm_vmw_gb_surface_v1;
+ req->multisample_pattern = multisamplePattern;
+ req->quality_level = qualityLevel;
+ req->must_be_zero = 0;
+ req->base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(flags);
+ req->svga3d_flags_upper_32_bits = SVGA3D_FLAGS_UPPER_32(flags);
+ req->base.format = (uint32_t) format;
+
+ if (usage & SVGA_SURFACE_USAGE_SCANOUT)
+ req->base.drm_surface_flags |= drm_vmw_surface_flag_scanout;
+
+ if (usage & SVGA_SURFACE_USAGE_SHARED)
+ req->base.drm_surface_flags |= drm_vmw_surface_flag_shareable;
+
+ req->base.drm_surface_flags |= drm_vmw_surface_flag_create_buffer;
+ req->base.base_size.width = size.width;
+ req->base.base_size.height = size.height;
+ req->base.base_size.depth = size.depth;
+ req->base.mip_levels = numMipLevels;
+ req->base.multisample_count = 0;
+ req->base.autogen_filter = SVGA3D_TEX_FILTER_NONE;
+
+ if (vws->base.have_vgpu10) {
+ req->base.array_size = numFaces;
+ req->base.multisample_count = sampleCount;
+ } else {
+ assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
+ DRM_VMW_MAX_MIP_LEVELS);
+ req->base.array_size = 0;
+ }
+
+ req->base.buffer_handle = buffer_handle ?
+ buffer_handle : SVGA3D_INVALID_ID;
+
+ ret = drmCommandWriteRead(vws->ioctl.drm_fd,
+ DRM_VMW_GB_SURFACE_CREATE_EXT, &s_arg,
+ sizeof(s_arg));
+
+ if (ret)
+ goto out_fail_create;
+ } else {
+ union drm_vmw_gb_surface_create_arg s_arg;
+ struct drm_vmw_gb_surface_create_req *req = &s_arg.req;
+ rep = &s_arg.rep;
+
+ memset(&s_arg, 0, sizeof(s_arg));
+ req->svga3d_flags = (uint32_t) flags;
+ req->format = (uint32_t) format;
+
+ if (usage & SVGA_SURFACE_USAGE_SCANOUT)
+ req->drm_surface_flags |= drm_vmw_surface_flag_scanout;
+
+ if (usage & SVGA_SURFACE_USAGE_SHARED)
+ req->drm_surface_flags |= drm_vmw_surface_flag_shareable;
+
+ req->drm_surface_flags |= drm_vmw_surface_flag_create_buffer;
+ req->base_size.width = size.width;
+ req->base_size.height = size.height;
+ req->base_size.depth = size.depth;
+ req->mip_levels = numMipLevels;
+ req->multisample_count = 0;
+ req->autogen_filter = SVGA3D_TEX_FILTER_NONE;
+
+ if (vws->base.have_vgpu10) {
+ req->array_size = numFaces;
+ req->multisample_count = sampleCount;
+ } else {
+ assert(numFaces * numMipLevels < DRM_VMW_MAX_SURFACE_FACES*
+ DRM_VMW_MAX_MIP_LEVELS);
+ req->array_size = 0;
+ }
+
+ req->buffer_handle = buffer_handle ?
+ buffer_handle : SVGA3D_INVALID_ID;
+
+ ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_CREATE,
+ &s_arg, sizeof(s_arg));
+
+ if (ret)
+ goto out_fail_create;
+ }
+
+ if (p_region) {
+ region->handle = rep->buffer_handle;
+ region->map_handle = rep->buffer_map_handle;
+ region->drm_fd = vws->ioctl.drm_fd;
+ region->size = rep->backup_size;
+ *p_region = region;
+ }
+
+ vmw_printf("Surface id is %d\n", rep->sid);
+ return rep->handle;
+
+out_fail_create:
+ FREE(region);
+ return SVGA3D_INVALID_ID;
+}
+
+/**
+ * vmw_ioctl_surface_req - Fill in a struct surface_req
+ *
+ * @vws: Winsys screen
+ * @whandle: Surface handle
+ * @req: The struct surface req to fill in
+ * @needs_unref: This call takes a kernel surface reference that needs to
+ * be unreferenced.
+ *
+ * Returns 0 on success, negative error type otherwise.
+ * Fills in the surface_req structure according to handle type and kernel
+ * capabilities.
+ */
+static int
+vmw_ioctl_surface_req(const struct vmw_winsys_screen *vws,
+ const struct winsys_handle *whandle,
+ struct drm_vmw_surface_arg *req,
+ boolean *needs_unref)
+{
+ int ret;
+
+ switch(whandle->type) {
+ case WINSYS_HANDLE_TYPE_SHARED:
+ case WINSYS_HANDLE_TYPE_KMS:
+ *needs_unref = FALSE;
+ req->handle_type = DRM_VMW_HANDLE_LEGACY;
+ req->sid = whandle->handle;
+ break;
+ case WINSYS_HANDLE_TYPE_FD:
+ if (!vws->ioctl.have_drm_2_6) {
+ uint32_t handle;
+
+ 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 -EINVAL;
+ }
+
+ *needs_unref = TRUE;
+ req->handle_type = DRM_VMW_HANDLE_LEGACY;
+ req->sid = handle;
+ } else {
+ *needs_unref = FALSE;
+ req->handle_type = DRM_VMW_HANDLE_PRIME;
+ req->sid = whandle->handle;
+ }
+ break;
+ default:
+ vmw_error("Attempt to import unsupported handle type %d.\n",
+ whandle->type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * vmw_ioctl_gb_surface_ref - Put a reference on a guest-backed surface and
+ * get surface information
+ *
+ * @vws: Screen to register the reference on
+ * @handle: Kernel handle of the guest-backed surface
+ * @flags: flags used when the surface was created
+ * @format: Format used when the surface was created
+ * @numMipLevels: Number of mipmap levels of the surface
+ * @p_region: On successful return points to a newly allocated
+ * struct vmw_region holding a reference to the surface backup buffer.
+ *
+ * Returns 0 on success, a system error on failure.
+ */
+int
+vmw_ioctl_gb_surface_ref(struct vmw_winsys_screen *vws,
+ const struct winsys_handle *whandle,
+ SVGA3dSurfaceAllFlags *flags,
+ SVGA3dSurfaceFormat *format,
+ uint32_t *numMipLevels,
+ uint32_t *handle,
+ struct vmw_region **p_region)
+{
+ struct vmw_region *region = NULL;
+ boolean needs_unref = FALSE;
+ int ret;
+
+ assert(p_region != NULL);
+ region = CALLOC_STRUCT(vmw_region);
+ if (!region)
+ return -ENOMEM;
+
+ if (vws->ioctl.have_drm_2_15) {
+ union drm_vmw_gb_surface_reference_ext_arg s_arg;
+ struct drm_vmw_surface_arg *req = &s_arg.req;
+ struct drm_vmw_gb_surface_ref_ext_rep *rep = &s_arg.rep;
+
+ memset(&s_arg, 0, sizeof(s_arg));
+ ret = vmw_ioctl_surface_req(vws, whandle, req, &needs_unref);
+ if (ret)
+ goto out_fail_req;
+
+ *handle = req->sid;
+ ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF_EXT,
+ &s_arg, sizeof(s_arg));
+
+ if (ret)
+ goto out_fail_ref;
+
+ region->handle = rep->crep.buffer_handle;
+ region->map_handle = rep->crep.buffer_map_handle;
+ region->drm_fd = vws->ioctl.drm_fd;
+ region->size = rep->crep.backup_size;
+ *p_region = region;
+
+ *handle = rep->crep.handle;
+ *flags = SVGA3D_FLAGS_64(rep->creq.svga3d_flags_upper_32_bits,
+ rep->creq.base.svga3d_flags);
+ *format = rep->creq.base.format;
+ *numMipLevels = rep->creq.base.mip_levels;
+ } else {
+ union drm_vmw_gb_surface_reference_arg s_arg;
+ struct drm_vmw_surface_arg *req = &s_arg.req;
+ struct drm_vmw_gb_surface_ref_rep *rep = &s_arg.rep;
+
+ memset(&s_arg, 0, sizeof(s_arg));
+ ret = vmw_ioctl_surface_req(vws, whandle, req, &needs_unref);
+ if (ret)
+ goto out_fail_req;
+
+ *handle = req->sid;
+ ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GB_SURFACE_REF,
+ &s_arg, sizeof(s_arg));
+
+ if (ret)
+ goto out_fail_ref;
+
+ region->handle = rep->crep.buffer_handle;
+ region->map_handle = rep->crep.buffer_map_handle;
+ region->drm_fd = vws->ioctl.drm_fd;
+ region->size = rep->crep.backup_size;
+ *p_region = region;
+
+ *handle = rep->crep.handle;
+ *flags = rep->creq.svga3d_flags;
+ *format = rep->creq.format;
+ *numMipLevels = rep->creq.mip_levels;
+ }
+
+ vmw_printf("%s flags %d format %d\n", __FUNCTION__, *flags, *format);
+
+ if (needs_unref)
+ vmw_ioctl_surface_destroy(vws, *handle);
+
+ return 0;
+out_fail_ref:
+ if (needs_unref)
+ vmw_ioctl_surface_destroy(vws, *handle);
+out_fail_req:
+ FREE(region);
+ return ret;
+}
+