+
+fail:
+ if (tex->defined)
+ FREE(tex->defined);
+ if (tex->rendered_to)
+ FREE(tex->rendered_to);
+ if (tex->dirty)
+ FREE(tex->dirty);
+ FREE(tex);
+ return NULL;
+}
+
+boolean
+svga_texture_generate_mipmap(struct pipe_context *pipe,
+ struct pipe_resource *pt,
+ enum pipe_format format,
+ unsigned base_level,
+ unsigned last_level,
+ unsigned first_layer,
+ unsigned last_layer)
+{
+ struct pipe_sampler_view templ, *psv;
+ struct svga_pipe_sampler_view *sv;
+ struct svga_context *svga = svga_context(pipe);
+ struct svga_texture *tex = svga_texture(pt);
+ enum pipe_error ret;
+
+ assert(svga_have_vgpu10(svga));
+
+ /* Only support 2D texture for now */
+ if (pt->target != PIPE_TEXTURE_2D)
+ return FALSE;
+
+ /* Fallback to the mipmap generation utility for those formats that
+ * do not support hw generate mipmap
+ */
+ if (!svga_format_support_gen_mips(format))
+ return FALSE;
+
+ /* Make sure the texture surface was created with
+ * SVGA3D_SURFACE_BIND_RENDER_TARGET
+ */
+ if (!tex->handle || !(tex->key.flags & SVGA3D_SURFACE_BIND_RENDER_TARGET))
+ return FALSE;
+
+ templ.format = format;
+ templ.u.tex.first_layer = first_layer;
+ templ.u.tex.last_layer = last_layer;
+ templ.u.tex.first_level = base_level;
+ templ.u.tex.last_level = last_level;
+
+ psv = pipe->create_sampler_view(pipe, pt, &templ);
+ if (psv == NULL)
+ return FALSE;
+
+ sv = svga_pipe_sampler_view(psv);
+ ret = svga_validate_pipe_sampler_view(svga, sv);
+ if (ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = svga_validate_pipe_sampler_view(svga, sv);
+ assert(ret == PIPE_OK);
+ }
+
+ ret = SVGA3D_vgpu10_GenMips(svga->swc, sv->id, tex->handle);
+ if (ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = SVGA3D_vgpu10_GenMips(svga->swc, sv->id, tex->handle);
+ }
+ pipe_sampler_view_reference(&psv, NULL);
+
+ svga->hud.num_generate_mipmap++;
+
+ return TRUE;
+}
+
+
+/* texture upload buffer default size in bytes */
+#define TEX_UPLOAD_DEFAULT_SIZE (1024 * 1024)
+
+/**
+ * Create a texture upload buffer
+ */
+boolean
+svga_texture_transfer_map_upload_create(struct svga_context *svga)
+{
+ svga->tex_upload = u_upload_create(&svga->pipe, TEX_UPLOAD_DEFAULT_SIZE,
+ 0, PIPE_USAGE_STAGING);
+ return svga->tex_upload != NULL;
+}
+
+
+/**
+ * Destroy the texture upload buffer
+ */
+void
+svga_texture_transfer_map_upload_destroy(struct svga_context *svga)
+{
+ u_upload_destroy(svga->tex_upload);
+}
+
+
+/**
+ * Returns true if this transfer map request can use the upload buffer.
+ */
+boolean
+svga_texture_transfer_map_can_upload(const struct svga_screen *svgascreen,
+ const struct pipe_resource *texture)
+{
+ if (svgascreen->sws->have_transfer_from_buffer_cmd == FALSE)
+ return FALSE;
+
+ /* TransferFromBuffer command is not well supported with multi-samples surface */
+ if (texture->nr_samples > 1)
+ return FALSE;
+
+ if (util_format_is_compressed(texture->format)) {
+ /* XXX Need to take a closer look to see why texture upload
+ * with 3D texture with compressed format fails
+ */
+ if (texture->target == PIPE_TEXTURE_3D)
+ return FALSE;
+ }
+ else if (texture->format == PIPE_FORMAT_R9G9B9E5_FLOAT) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * Use upload buffer for the transfer map request.
+ */
+void *
+svga_texture_transfer_map_upload(struct svga_context *svga,
+ struct svga_transfer *st)
+{
+ struct pipe_resource *texture = st->base.resource;
+ struct pipe_resource *tex_buffer = NULL;
+ void *tex_map;
+ unsigned nblocksx, nblocksy;
+ unsigned offset;
+ unsigned upload_size;
+
+ assert(svga->tex_upload);
+
+ st->upload.box.x = st->base.box.x;
+ st->upload.box.y = st->base.box.y;
+ st->upload.box.z = st->base.box.z;
+ st->upload.box.w = st->base.box.width;
+ st->upload.box.h = st->base.box.height;
+ st->upload.box.d = st->base.box.depth;
+ st->upload.nlayers = 1;
+
+ switch (texture->target) {
+ case PIPE_TEXTURE_CUBE:
+ st->upload.box.z = 0;
+ break;
+ case PIPE_TEXTURE_2D_ARRAY:
+ st->upload.nlayers = st->base.box.depth;
+ st->upload.box.z = 0;
+ st->upload.box.d = 1;
+ break;
+ case PIPE_TEXTURE_1D_ARRAY:
+ st->upload.nlayers = st->base.box.depth;
+ st->upload.box.y = st->upload.box.z = 0;
+ st->upload.box.d = 1;
+ break;
+ default:
+ break;
+ }
+
+ nblocksx = util_format_get_nblocksx(texture->format, st->base.box.width);
+ nblocksy = util_format_get_nblocksy(texture->format, st->base.box.height);
+
+ st->base.stride = nblocksx * util_format_get_blocksize(texture->format);
+ st->base.layer_stride = st->base.stride * nblocksy;
+
+ /* In order to use the TransferFromBuffer command to update the
+ * texture content from the buffer, the layer stride for a multi-layers
+ * surface needs to be in multiples of 16 bytes.
+ */
+ if (st->upload.nlayers > 1 && st->base.layer_stride & 15)
+ return NULL;
+
+ upload_size = st->base.layer_stride * st->base.box.depth;
+ upload_size = align(upload_size, 16);
+
+#ifdef DEBUG
+ if (util_format_is_compressed(texture->format)) {
+ struct svga_texture *tex = svga_texture(texture);
+ unsigned blockw, blockh, bytesPerBlock;
+
+ svga_format_size(tex->key.format, &blockw, &blockh, &bytesPerBlock);
+
+ /* dest box must start on block boundary */
+ assert((st->base.box.x % blockw) == 0);
+ assert((st->base.box.y % blockh) == 0);
+ }
+#endif
+
+ /* If the upload size exceeds the default buffer size, the
+ * upload buffer manager code will try to allocate a new buffer
+ * with the new buffer size.
+ */
+ u_upload_alloc(svga->tex_upload, 0, upload_size, 16,
+ &offset, &tex_buffer, &tex_map);
+
+ if (!tex_map) {
+ return NULL;
+ }
+
+ st->upload.buf = tex_buffer;
+ st->upload.map = tex_map;
+ st->upload.offset = offset;
+
+ return tex_map;