gallium: remove PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE
[mesa.git] / src / gallium / drivers / nv30 / nv30_miptree.c
index 280696d45039724faa5d80bf78f067b0824c79a6..d4dcacb85069fe14d6d9b084d6510ea8736e830a 100644 (file)
-#include "pipe/p_state.h"
-#include "pipe/p_defines.h"
-#include "pipe/p_inlines.h"
-
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ *
+ */
+
+#include "util/u_format.h"
+#include "util/u_inlines.h"
+#include "util/u_surface.h"
+
+#include "nouveau/nv_m2mf.xml.h"
+#include "nv30_screen.h"
 #include "nv30_context.h"
+#include "nv30_resource.h"
+#include "nv30_transfer.h"
+
+static INLINE unsigned
+layer_offset(struct pipe_resource *pt, unsigned level, unsigned layer)
+{
+   struct nv30_miptree *mt = nv30_miptree(pt);
+   struct nv30_miptree_level *lvl = &mt->level[level];
+
+   if (pt->target == PIPE_TEXTURE_CUBE)
+      return (layer * mt->layer_size) + lvl->offset;
+
+   return lvl->offset + (layer * lvl->zslice_size);
+}
+
+static boolean
+nv30_miptree_get_handle(struct pipe_screen *pscreen,
+                        struct pipe_resource *pt,
+                        struct winsys_handle *handle)
+{
+   struct nv30_miptree *mt = nv30_miptree(pt);
+   unsigned stride;
+
+   if (!mt || !mt->base.bo)
+      return FALSE;
+
+   stride = mt->level[0].pitch;
+
+   return nouveau_screen_bo_get_handle(pscreen, mt->base.bo, stride, handle);
+}
 
 static void
-nv30_miptree_layout(struct nv30_miptree *nv30mt)
+nv30_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)
+{
+   struct nv30_miptree *mt = nv30_miptree(pt);
+
+   nouveau_bo_ref(NULL, &mt->base.bo);
+   FREE(mt);
+}
+
+struct nv30_transfer {
+   struct pipe_transfer base;
+   struct nv30_rect img;
+   struct nv30_rect tmp;
+   unsigned nblocksx;
+   unsigned nblocksy;
+};
+
+static INLINE struct nv30_transfer *
+nv30_transfer(struct pipe_transfer *ptx)
 {
-       struct pipe_texture *pt = &nv30mt->base;
-       uint width = pt->width[0], height = pt->height[0], depth = pt->depth[0];
-       uint offset = 0;
-       int nr_faces, l, f;
-       uint wide_pitch = pt->tex_usage & (PIPE_TEXTURE_USAGE_SAMPLER |
-                                          PIPE_TEXTURE_USAGE_DEPTH_STENCIL |
-                                          PIPE_TEXTURE_USAGE_RENDER_TARGET |
-                                          PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
-                                          PIPE_TEXTURE_USAGE_PRIMARY);
-
-       if (pt->target == PIPE_TEXTURE_CUBE) {
-               nr_faces = 6;
-       } else
-       if (pt->target == PIPE_TEXTURE_3D) {
-               nr_faces = pt->depth[0];
-       } else {
-               nr_faces = 1;
-       }
-
-       for (l = 0; l <= pt->last_level; l++) {
-               pt->width[l] = width;
-               pt->height[l] = height;
-               pt->depth[l] = depth;
-               pt->nblocksx[l] = pf_get_nblocksx(&pt->block, width);
-               pt->nblocksy[l] = pf_get_nblocksy(&pt->block, height);
-
-               if (wide_pitch && (pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR))
-                       nv30mt->level[l].pitch = align(pt->width[0] * pt->block.size, 64);
-               else
-                       nv30mt->level[l].pitch = pt->width[l] * pt->block.size;
-
-               nv30mt->level[l].image_offset =
-                       CALLOC(nr_faces, sizeof(unsigned));
-
-               width  = MAX2(1, width  >> 1);
-               height = MAX2(1, height >> 1);
-               depth  = MAX2(1, depth  >> 1);
-       }
-
-       for (f = 0; f < nr_faces; f++) {
-               for (l = 0; l < pt->last_level; l++) {
-                       nv30mt->level[l].image_offset[f] = offset;
-
-                       if (!(pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR) &&
-                           pt->width[l + 1] > 1 && pt->height[l + 1] > 1)
-                               offset += align(nv30mt->level[l].pitch * pt->height[l], 64);
-                       else
-                               offset += nv30mt->level[l].pitch * pt->height[l];
-               }
-
-               nv30mt->level[l].image_offset[f] = offset;
-               offset += nv30mt->level[l].pitch * pt->height[l];
-       }
-
-       nv30mt->total_size = offset;
+   return (struct nv30_transfer *)ptx;
 }
 
-static struct pipe_texture *
-nv30_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *pt)
+static INLINE void
+define_rect(struct pipe_resource *pt, unsigned level, unsigned z,
+            unsigned x, unsigned y, unsigned w, unsigned h,
+            struct nv30_rect *rect)
 {
-       struct nv30_miptree *mt;
-       unsigned buf_usage = PIPE_BUFFER_USAGE_PIXEL |
-                            NOUVEAU_BUFFER_USAGE_TEXTURE;
-
-       mt = MALLOC(sizeof(struct nv30_miptree));
-       if (!mt)
-               return NULL;
-       mt->base = *pt;
-       pipe_reference_init(&mt->base.reference, 1);
-       mt->base.screen = pscreen;
-
-       /* Swizzled textures must be POT */
-       if (pt->width[0] & (pt->width[0] - 1) ||
-           pt->height[0] & (pt->height[0] - 1))
-               mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
-       else
-       if (pt->tex_usage & (PIPE_TEXTURE_USAGE_PRIMARY |
-                            PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
-                            PIPE_TEXTURE_USAGE_DEPTH_STENCIL))
-               mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
-       else
-       if (pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC)
-               mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
-       else {
-               switch (pt->format) {
-               /* TODO: Figure out which formats can be swizzled */
-               case PIPE_FORMAT_A8R8G8B8_UNORM:
-               case PIPE_FORMAT_X8R8G8B8_UNORM:
-               case PIPE_FORMAT_R16_SNORM:
-               case PIPE_FORMAT_R5G6B5_UNORM:
-               case PIPE_FORMAT_A8L8_UNORM:
-               case PIPE_FORMAT_A8_UNORM:
-               case PIPE_FORMAT_L8_UNORM:
-               case PIPE_FORMAT_I8_UNORM:
-               {
-                       if (debug_get_bool_option("NOUVEAU_NO_SWIZZLE", FALSE))
-                               mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
-                       break;
-               }
-               default:
-                       mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
-               }
-       }
-
-       if (pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC)
-               buf_usage |= PIPE_BUFFER_USAGE_CPU_READ_WRITE;
-
-       nv30_miptree_layout(mt);
-
-       mt->buffer = pscreen->buffer_create(pscreen, 256, buf_usage,
-                                      mt->total_size);
-       if (!mt->buffer) {
-               FREE(mt);
-               return NULL;
-       }
-
-       return &mt->base;
+   struct nv30_miptree *mt = nv30_miptree(pt);
+   struct nv30_miptree_level *lvl = &mt->level[level];
+
+   rect->w = u_minify(pt->width0, level) << mt->ms_x;
+   rect->w = util_format_get_nblocksx(pt->format, rect->w);
+   rect->h = u_minify(pt->height0, level) << mt->ms_y;
+   rect->h = util_format_get_nblocksy(pt->format, rect->h);
+   rect->d = 1;
+   rect->z = 0;
+   if (mt->swizzled) {
+      if (pt->target == PIPE_TEXTURE_3D) {
+         rect->d = u_minify(pt->depth0, level);
+         rect->z = z; z = 0;
+      }
+      rect->pitch = 0;
+   } else {
+      rect->pitch = lvl->pitch;
+   }
+
+   rect->bo     = mt->base.bo;
+   rect->domain = NOUVEAU_BO_VRAM;
+   rect->offset = layer_offset(pt, level, z);
+   rect->cpp    = util_format_get_blocksize(pt->format);
+
+   rect->x0     = util_format_get_nblocksx(pt->format, x) << mt->ms_x;
+   rect->y0     = util_format_get_nblocksy(pt->format, y) << mt->ms_y;
+   rect->x1     = rect->x0 + (w << mt->ms_x);
+   rect->y1     = rect->y0 + (h << mt->ms_y);
 }
 
-static struct pipe_texture *
-nv30_miptree_blanket(struct pipe_screen *pscreen, const struct pipe_texture *pt,
-                    const unsigned *stride, struct pipe_buffer *pb)
+void
+nv30_resource_copy_region(struct pipe_context *pipe,
+                          struct pipe_resource *dstres, unsigned dst_level,
+                          unsigned dstx, unsigned dsty, unsigned dstz,
+                          struct pipe_resource *srcres, unsigned src_level,
+                          const struct pipe_box *src_box)
 {
-       struct nv30_miptree *mt;
+   struct nv30_context *nv30 = nv30_context(pipe);
+   struct nv30_rect src, dst;
+
+   if (dstres->target == PIPE_BUFFER && srcres->target == PIPE_BUFFER) {
+      util_resource_copy_region(pipe, dstres, dst_level, dstx, dsty, dstz,
+                                      srcres, src_level, src_box);
+      return;
+   }
 
-       /* Only supports 2D, non-mipmapped textures for the moment */
-       if (pt->target != PIPE_TEXTURE_2D || pt->last_level != 0 ||
-           pt->depth[0] != 1)
-               return NULL;
+   define_rect(srcres, src_level, src_box->z, src_box->x, src_box->y,
+                       src_box->width, src_box->height, &src);
+   define_rect(dstres, dst_level, dstz, dstx, dsty,
+                       src_box->width, src_box->height, &dst);
 
-       mt = CALLOC_STRUCT(nv30_miptree);
-       if (!mt)
-               return NULL;
+   nv30_transfer_rect(nv30, NEAREST, &src, &dst);
+}
 
-       mt->base = *pt;
-       pipe_reference_init(&mt->base.reference, 1);
-       mt->base.screen = pscreen;
-       mt->level[0].pitch = stride[0];
-       mt->level[0].image_offset = CALLOC(1, sizeof(unsigned));
+void
+nv30_resource_resolve(struct pipe_context *pipe,
+                      const struct pipe_resolve_info *info)
+{
+#if 0
+   struct nv30_context *nv30 = nv30_context(pipe);
+   struct nv30_rect src, dst;
 
-       /* Assume whoever created this buffer expects it to be linear for now */
-       mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
+   define_rect(info->src.res, 0, 0, info->src.x0, info->src.y0,
+               info->src.x1 - info->src.x0, info->src.y1 - info->src.y0, &src);
+   define_rect(info->dst.res, info->dst.level, 0, info->dst.x0, info->dst.y0,
+               info->dst.x1 - info->dst.x0, info->dst.y1 - info->dst.y0, &dst);
 
-       pipe_buffer_reference(&mt->buffer, pb);
-       return &mt->base;
+   nv30_transfer_rect(nv30, BILINEAR, &src, &dst);
+#endif
+}
+
+void
+nv30_blit(struct pipe_context *pipe,
+          const struct pipe_blit_info *blit_info)
+{
+   struct nv30_context *nv30 = nv30_context(pipe);
+   struct pipe_blit_info info = *blit_info;
+
+   if (info.src.resource->nr_samples > 1 &&
+       info.dst.resource->nr_samples <= 1 &&
+       !util_format_is_depth_or_stencil(info.src.resource->format) &&
+       !util_format_is_pure_integer(info.src.resource->format)) {
+      debug_printf("nv30: color resolve unimplemented\n");
+      return;
+   }
+
+   if (util_try_blit_via_copy_region(pipe, &info)) {
+      return; /* done */
+   }
+
+   if (info.mask & PIPE_MASK_S) {
+      debug_printf("nv30: cannot blit stencil, skipping\n");
+      info.mask &= ~PIPE_MASK_S;
+   }
+
+   if (!util_blitter_is_blit_supported(nv30->blitter, &info)) {
+      debug_printf("nv30: blit unsupported %s -> %s\n",
+                   util_format_short_name(info.src.resource->format),
+                   util_format_short_name(info.dst.resource->format));
+      return;
+   }
+
+   /* XXX turn off occlusion queries */
+
+   util_blitter_save_vertex_buffer_slot(nv30->blitter, nv30->vtxbuf);
+   util_blitter_save_vertex_elements(nv30->blitter, nv30->vertex);
+   util_blitter_save_vertex_shader(nv30->blitter, nv30->vertprog.program);
+   util_blitter_save_rasterizer(nv30->blitter, nv30->rast);
+   util_blitter_save_viewport(nv30->blitter, &nv30->viewport);
+   util_blitter_save_scissor(nv30->blitter, &nv30->scissor);
+   util_blitter_save_fragment_shader(nv30->blitter, nv30->fragprog.program);
+   util_blitter_save_blend(nv30->blitter, nv30->blend);
+   util_blitter_save_depth_stencil_alpha(nv30->blitter,
+                                         nv30->zsa);
+   util_blitter_save_stencil_ref(nv30->blitter, &nv30->stencil_ref);
+   util_blitter_save_sample_mask(nv30->blitter, nv30->sample_mask);
+   util_blitter_save_framebuffer(nv30->blitter, &nv30->framebuffer);
+   util_blitter_save_fragment_sampler_states(nv30->blitter,
+                     nv30->fragprog.num_samplers,
+                     (void**)nv30->fragprog.samplers);
+   util_blitter_save_fragment_sampler_views(nv30->blitter,
+                     nv30->fragprog.num_textures, nv30->fragprog.textures);
+   util_blitter_save_render_condition(nv30->blitter, nv30->render_cond_query,
+                                      nv30->render_cond_mode);
+   util_blitter_blit(nv30->blitter, &info);
+}
+
+static void *
+nv30_miptree_transfer_map(struct pipe_context *pipe, struct pipe_resource *pt,
+                          unsigned level, unsigned usage,
+                          const struct pipe_box *box,
+                          struct pipe_transfer **ptransfer)
+{
+   struct nv30_context *nv30 = nv30_context(pipe);
+   struct nouveau_device *dev = nv30->screen->base.device;
+   struct nv30_transfer *tx;
+   unsigned access = 0;
+   int ret;
+
+   tx = CALLOC_STRUCT(nv30_transfer);
+   if (!tx)
+      return NULL;
+   pipe_resource_reference(&tx->base.resource, pt);
+   tx->base.level = level;
+   tx->base.usage = usage;
+   tx->base.box = *box;
+   tx->base.stride = util_format_get_nblocksx(pt->format, box->width) *
+                     util_format_get_blocksize(pt->format);
+   tx->base.layer_stride = util_format_get_nblocksy(pt->format, box->height) *
+                           tx->base.stride;
+
+   tx->nblocksx = util_format_get_nblocksx(pt->format, box->width);
+   tx->nblocksy = util_format_get_nblocksy(pt->format, box->height);
+
+   define_rect(pt, level, box->z, box->x, box->y,
+                   tx->nblocksx, tx->nblocksy, &tx->img);
+
+   ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
+                        tx->base.layer_stride, NULL, &tx->tmp.bo);
+   if (ret) {
+      pipe_resource_reference(&tx->base.resource, NULL);
+      FREE(tx);
+      return NULL;
+   }
+
+   tx->tmp.domain = NOUVEAU_BO_GART;
+   tx->tmp.offset = 0;
+   tx->tmp.pitch  = tx->base.stride;
+   tx->tmp.cpp    = tx->img.cpp;
+   tx->tmp.w      = tx->nblocksx;
+   tx->tmp.h      = tx->nblocksy;
+   tx->tmp.d      = 1;
+   tx->tmp.x0     = 0;
+   tx->tmp.y0     = 0;
+   tx->tmp.x1     = tx->tmp.w;
+   tx->tmp.y1     = tx->tmp.h;
+   tx->tmp.z      = 0;
+
+   if (usage & PIPE_TRANSFER_READ)
+      nv30_transfer_rect(nv30, NEAREST, &tx->img, &tx->tmp);
+
+   if (tx->tmp.bo->map) {
+      *ptransfer = &tx->base;
+      return tx->tmp.bo->map;
+   }
+
+   if (usage & PIPE_TRANSFER_READ)
+      access |= NOUVEAU_BO_RD;
+   if (usage & PIPE_TRANSFER_WRITE)
+      access |= NOUVEAU_BO_WR;
+
+   ret = nouveau_bo_map(tx->tmp.bo, access, nv30->base.client);
+   if (ret) {
+      pipe_resource_reference(&tx->base.resource, NULL);
+      FREE(tx);
+      return NULL;
+   }
+
+   *ptransfer = &tx->base;
+   return tx->tmp.bo->map;
 }
 
 static void
-nv30_miptree_destroy(struct pipe_texture *pt)
+nv30_miptree_transfer_unmap(struct pipe_context *pipe,
+                            struct pipe_transfer *ptx)
 {
-       struct nv30_miptree *mt = (struct nv30_miptree *)pt;
-       int l;
+   struct nv30_context *nv30 = nv30_context(pipe);
+   struct nv30_transfer *tx = nv30_transfer(ptx);
 
-       pipe_buffer_reference(&mt->buffer, NULL);
-       for (l = 0; l <= pt->last_level; l++) {
-               if (mt->level[l].image_offset)
-                       FREE(mt->level[l].image_offset);
-       }
+   if (ptx->usage & PIPE_TRANSFER_WRITE)
+      nv30_transfer_rect(nv30, NEAREST, &tx->tmp, &tx->img);
 
-       FREE(mt);
+   nouveau_bo_ref(NULL, &tx->tmp.bo);
+   pipe_resource_reference(&ptx->resource, NULL);
+   FREE(tx);
 }
 
-static struct pipe_surface *
-nv30_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
-                        unsigned face, unsigned level, unsigned zslice,
-                        unsigned flags)
+const struct u_resource_vtbl nv30_miptree_vtbl = {
+   nv30_miptree_get_handle,
+   nv30_miptree_destroy,
+   nv30_miptree_transfer_map,
+   u_default_transfer_flush_region,
+   nv30_miptree_transfer_unmap,
+   u_default_transfer_inline_write
+};
+
+struct pipe_resource *
+nv30_miptree_create(struct pipe_screen *pscreen,
+                    const struct pipe_resource *tmpl)
 {
-       struct nv30_miptree *nv30mt = (struct nv30_miptree *)pt;
-       struct nv04_surface *ns;
-
-       ns = CALLOC_STRUCT(nv04_surface);
-       if (!ns)
-               return NULL;
-       pipe_texture_reference(&ns->base.texture, pt);
-       ns->base.format = pt->format;
-       ns->base.width = pt->width[level];
-       ns->base.height = pt->height[level];
-       ns->base.usage = flags;
-       pipe_reference_init(&ns->base.reference, 1);
-       ns->base.face = face;
-       ns->base.level = level;
-       ns->base.zslice = zslice;
-       ns->pitch = nv30mt->level[level].pitch;
-
-       if (pt->target == PIPE_TEXTURE_CUBE) {
-               ns->base.offset = nv30mt->level[level].image_offset[face];
-       } else
-       if (pt->target == PIPE_TEXTURE_3D) {
-               ns->base.offset = nv30mt->level[level].image_offset[zslice];
-       } else {
-               ns->base.offset = nv30mt->level[level].image_offset[0];
-       }
-
-       return &ns->base;
+   struct nouveau_device *dev = nouveau_screen(pscreen)->device;
+   struct nv30_miptree *mt = CALLOC_STRUCT(nv30_miptree);
+   struct pipe_resource *pt = &mt->base.base;
+   unsigned blocksz, size;
+   unsigned w, h, d, l;
+   int ret;
+
+   switch (tmpl->nr_samples) {
+   case 4:
+      mt->ms_mode = 0x00004000;
+      mt->ms_x = 1;
+      mt->ms_y = 1;
+      break;
+   case 2:
+      mt->ms_mode = 0x00003000;
+      mt->ms_x = 1;
+      mt->ms_y = 0;
+      break;
+   default:
+      mt->ms_mode = 0x00000000;
+      mt->ms_x = 0;
+      mt->ms_y = 0;
+      break;
+   }
+
+   mt->base.vtbl = &nv30_miptree_vtbl;
+   *pt = *tmpl;
+   pipe_reference_init(&pt->reference, 1);
+   pt->screen = pscreen;
+
+   w = pt->width0 << mt->ms_x;
+   h = pt->height0 << mt->ms_y;
+   d = (pt->target == PIPE_TEXTURE_3D) ? pt->depth0 : 1;
+   blocksz = util_format_get_blocksize(pt->format);
+
+   if ((pt->target == PIPE_TEXTURE_RECT) ||
+       !util_is_power_of_two(pt->width0) ||
+       !util_is_power_of_two(pt->height0) ||
+       !util_is_power_of_two(pt->depth0) ||
+       util_format_is_compressed(pt->format) ||
+       util_format_is_float(pt->format) || mt->ms_mode) {
+      mt->uniform_pitch = util_format_get_nblocksx(pt->format, w) * blocksz;
+      mt->uniform_pitch = align(mt->uniform_pitch, 64);
+   }
+
+   if (!mt->uniform_pitch)
+      mt->swizzled = TRUE;
+
+   size = 0;
+   for (l = 0; l <= pt->last_level; l++) {
+      struct nv30_miptree_level *lvl = &mt->level[l];
+      unsigned nbx = util_format_get_nblocksx(pt->format, w);
+      unsigned nby = util_format_get_nblocksx(pt->format, h);
+
+      lvl->offset = size;
+      lvl->pitch  = mt->uniform_pitch;
+      if (!lvl->pitch)
+         lvl->pitch = nbx * blocksz;
+
+      lvl->zslice_size = lvl->pitch * nby;
+      size += lvl->zslice_size * d;
+
+      w = u_minify(w, 1);
+      h = u_minify(h, 1);
+      d = u_minify(d, 1);
+   }
+
+   mt->layer_size = size;
+   if (pt->target == PIPE_TEXTURE_CUBE) {
+      if (!mt->uniform_pitch)
+         mt->layer_size = align(mt->layer_size, 128);
+      size = mt->layer_size * 6;
+   }
+
+   ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 256, size, NULL, &mt->base.bo);
+   if (ret) {
+      FREE(mt);
+      return NULL;
+   }
+
+   mt->base.domain = NOUVEAU_BO_VRAM;
+   return &mt->base.base;
 }
 
-static void
-nv30_miptree_surface_del(struct pipe_surface *ps)
+struct pipe_resource *
+nv30_miptree_from_handle(struct pipe_screen *pscreen,
+                         const struct pipe_resource *tmpl,
+                         struct winsys_handle *handle)
 {
-       pipe_texture_reference(&ps->texture, NULL);
-       FREE(ps);
+   struct nv30_miptree *mt;
+   unsigned stride;
+
+   /* only supports 2D, non-mipmapped textures for the moment */
+   if ((tmpl->target != PIPE_TEXTURE_2D &&
+        tmpl->target != PIPE_TEXTURE_RECT) ||
+       tmpl->last_level != 0 ||
+       tmpl->depth0 != 1 ||
+       tmpl->array_size > 1)
+      return NULL;
+
+   mt = CALLOC_STRUCT(nv30_miptree);
+   if (!mt)
+      return NULL;
+
+   mt->base.bo = nouveau_screen_bo_from_handle(pscreen, handle, &stride);
+   if (mt->base.bo == NULL) {
+      FREE(mt);
+      return NULL;
+   }
+
+   mt->base.base = *tmpl;
+   mt->base.vtbl = &nv30_miptree_vtbl;
+   pipe_reference_init(&mt->base.base.reference, 1);
+   mt->base.base.screen = pscreen;
+   mt->uniform_pitch = stride;
+   mt->level[0].pitch = mt->uniform_pitch;
+   mt->level[0].offset = 0;
+
+   /* no need to adjust bo reference count */
+   return &mt->base.base;
+}
+
+struct pipe_surface *
+nv30_miptree_surface_new(struct pipe_context *pipe,
+                         struct pipe_resource *pt,
+                         const struct pipe_surface *tmpl)
+{
+   struct nv30_miptree *mt = nv30_miptree(pt); /* guaranteed */
+   struct nv30_surface *ns;
+   struct pipe_surface *ps;
+   struct nv30_miptree_level *lvl = &mt->level[tmpl->u.tex.level];
+
+   ns = CALLOC_STRUCT(nv30_surface);
+   if (!ns)
+      return NULL;
+   ps = &ns->base;
+
+   pipe_reference_init(&ps->reference, 1);
+   pipe_resource_reference(&ps->texture, pt);
+   ps->context = pipe;
+   ps->format = tmpl->format;
+   ps->u.tex.level = tmpl->u.tex.level;
+   ps->u.tex.first_layer = tmpl->u.tex.first_layer;
+   ps->u.tex.last_layer = tmpl->u.tex.last_layer;
+
+   ns->width = u_minify(pt->width0, ps->u.tex.level);
+   ns->height = u_minify(pt->height0, ps->u.tex.level);
+   ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
+   ns->offset = layer_offset(pt, ps->u.tex.level, ps->u.tex.first_layer);
+   if (mt->swizzled)
+      ns->pitch = 4096; /* random, just something the hw won't reject.. */
+   else
+      ns->pitch = lvl->pitch;
+
+   /* comment says there are going to be removed, but they're used by the st */
+   ps->width = ns->width;
+   ps->height = ns->height;
+   return ps;
 }
 
 void
-nv30_screen_init_miptree_functions(struct pipe_screen *pscreen)
+nv30_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps)
 {
-       pscreen->texture_create = nv30_miptree_create;
-       pscreen->texture_blanket = nv30_miptree_blanket;
-       pscreen->texture_destroy = nv30_miptree_destroy;
-       pscreen->get_tex_surface = nv30_miptree_surface_new;
-       pscreen->tex_surface_destroy = nv30_miptree_surface_del;
+   struct nv30_surface *ns = nv30_surface(ps);
+
+   pipe_resource_reference(&ps->texture, NULL);
+   FREE(ns);
 }