+ FREE(spr);
+}
+
+
+static struct pipe_resource *
+softpipe_resource_from_handle(struct pipe_screen *screen,
+ const struct pipe_resource *templat,
+ struct winsys_handle *whandle)
+{
+ struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
+ struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
+ if (!spr)
+ return NULL;
+
+ spr->base = *templat;
+ pipe_reference_init(&spr->base.reference, 1);
+ spr->base.screen = screen;
+
+ spr->pot = (util_is_power_of_two(templat->width0) &&
+ util_is_power_of_two(templat->height0) &&
+ util_is_power_of_two(templat->depth0));
+
+ spr->dt = winsys->displaytarget_from_handle(winsys,
+ templat,
+ whandle,
+ &spr->stride[0]);
+ if (!spr->dt)
+ goto fail;
+
+ return &spr->base;
+
+ fail:
+ FREE(spr);
+ return NULL;
+}
+
+
+static boolean
+softpipe_resource_get_handle(struct pipe_screen *screen,
+ struct pipe_resource *pt,
+ struct winsys_handle *whandle)
+{
+ struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
+ struct softpipe_resource *spr = softpipe_resource(pt);
+
+ assert(spr->dt);
+ if (!spr->dt)
+ return FALSE;
+
+ return winsys->displaytarget_get_handle(winsys, spr->dt, whandle);
+}
+
+
+/**
+ * Helper function to compute offset (in bytes) for a particular
+ * texture level/face/slice from the start of the buffer.
+ */
+static unsigned
+sp_get_tex_image_offset(const struct softpipe_resource *spr,
+ unsigned level, unsigned face, unsigned zslice)
+{
+ const unsigned hgt = u_minify(spr->base.height0, level);
+ const unsigned nblocksy = util_format_get_nblocksy(spr->base.format, hgt);
+ unsigned offset = spr->level_offset[level];
+
+ if (spr->base.target == PIPE_TEXTURE_CUBE) {
+ assert(zslice == 0);
+ offset += face * nblocksy * spr->stride[level];
+ }
+ else if (spr->base.target == PIPE_TEXTURE_3D) {
+ assert(face == 0);
+ offset += zslice * nblocksy * spr->stride[level];
+ }
+ else {
+ assert(face == 0);
+ assert(zslice == 0);
+ }
+
+ return offset;