+
+
+/**
+ * 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:
+ case PIPE_TEXTURE_CUBE_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;
+}
+
+
+/**
+ * Unmap upload map transfer request
+ */
+void
+svga_texture_transfer_unmap_upload(struct svga_context *svga,
+ struct svga_transfer *st)
+{
+ struct svga_winsys_surface *srcsurf;
+ struct svga_winsys_surface *dstsurf;
+ struct pipe_resource *texture = st->base.resource;
+ struct svga_texture *tex = svga_texture(texture);
+ enum pipe_error ret;
+ unsigned subResource;
+ unsigned numMipLevels;
+ unsigned i, layer;
+ unsigned offset = st->upload.offset;
+
+ assert(svga->tex_upload);
+ assert(st->upload.buf);
+
+ /* unmap the texture upload buffer */
+ u_upload_unmap(svga->tex_upload);
+
+ srcsurf = svga_buffer_handle(svga, st->upload.buf, 0);
+ dstsurf = svga_texture(texture)->handle;
+ assert(dstsurf);
+
+ numMipLevels = texture->last_level + 1;
+
+ for (i = 0, layer = st->slice; i < st->upload.nlayers; i++, layer++) {
+ subResource = layer * numMipLevels + st->base.level;
+
+ /* send a transferFromBuffer command to update the host texture surface */
+ assert((offset & 15) == 0);
+
+ ret = SVGA3D_vgpu10_TransferFromBuffer(svga->swc, srcsurf,
+ offset,
+ st->base.stride,
+ st->base.layer_stride,
+ dstsurf, subResource,
+ &st->upload.box);
+ if (ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = SVGA3D_vgpu10_TransferFromBuffer(svga->swc, srcsurf,
+ offset,
+ st->base.stride,
+ st->base.layer_stride,
+ dstsurf, subResource,
+ &st->upload.box);
+ assert(ret == PIPE_OK);
+ }
+ offset += st->base.layer_stride;
+
+ /* Set rendered-to flag */
+ svga_set_texture_rendered_to(tex, layer, st->base.level);
+ }
+
+ pipe_resource_reference(&st->upload.buf, NULL);
+}
+
+/**
+ * Does the device format backing this surface have an
+ * alpha channel?
+ *
+ * \param texture[in] The texture whose format we're querying
+ * \return TRUE if the format has an alpha channel, FALSE otherwise
+ *
+ * For locally created textures, the device (svga) format is typically
+ * identical to svga_format(texture->format), and we can use the gallium
+ * format tests to determine whether the device format has an alpha channel
+ * or not. However, for textures backed by imported svga surfaces that is
+ * not always true, and we have to look at the SVGA3D utilities.
+ */
+boolean
+svga_texture_device_format_has_alpha(struct pipe_resource *texture)
+{
+ /* the svga_texture() call below is invalid for PIPE_BUFFER resources */
+ assert(texture->target != PIPE_BUFFER);
+
+ enum svga3d_block_desc block_desc =
+ svga3dsurface_get_desc(svga_texture(texture)->key.format)->block_desc;
+
+ return !!(block_desc & SVGA3DBLOCKDESC_ALPHA);
+}