r600_texture.c revision ee07e0e39ad1c4d13d540b23220fecc564d07b16
1/*
2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 *      Jerome Glisse
25 *      Corbin Simpson
26 */
27#include <errno.h>
28#include <pipe/p_screen.h>
29#include <util/u_format.h>
30#include <util/u_math.h>
31#include <util/u_inlines.h>
32#include <util/u_memory.h>
33#include "state_tracker/drm_driver.h"
34#include "pipebuffer/pb_buffer.h"
35#include "r600_pipe.h"
36#include "r600_resource.h"
37#include "r600_state_inlines.h"
38#include "r600d.h"
39#include "r600_formats.h"
40
41extern struct u_resource_vtbl r600_texture_vtbl;
42
43/* Copy from a full GPU texture to a transfer's staging one. */
44static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
45{
46	struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer;
47	struct pipe_resource *texture = transfer->resource;
48	struct pipe_subresource subdst;
49
50	subdst.face = 0;
51	subdst.level = 0;
52	ctx->resource_copy_region(ctx, rtransfer->staging_texture,
53				subdst, 0, 0, 0, texture, transfer->sr,
54				transfer->box.x, transfer->box.y, transfer->box.z,
55				transfer->box.width, transfer->box.height);
56}
57
58
59/* Copy from a transfer's staging texture to a full GPU one. */
60static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
61{
62	struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer;
63	struct pipe_resource *texture = transfer->resource;
64	struct pipe_subresource subsrc;
65
66	subsrc.face = 0;
67	subsrc.level = 0;
68	ctx->resource_copy_region(ctx, texture, transfer->sr,
69				  transfer->box.x, transfer->box.y, transfer->box.z,
70				  rtransfer->staging_texture, subsrc,
71				  0, 0, 0,
72				  transfer->box.width, transfer->box.height);
73
74	ctx->flush(ctx, 0, NULL);
75}
76
77static unsigned r600_texture_get_offset(struct r600_resource_texture *rtex,
78					unsigned level, unsigned zslice,
79					unsigned face)
80{
81	unsigned offset = rtex->offset[level];
82
83	switch (rtex->resource.base.b.target) {
84	case PIPE_TEXTURE_3D:
85		assert(face == 0);
86		return offset + zslice * rtex->layer_size[level];
87	case PIPE_TEXTURE_CUBE:
88		assert(zslice == 0);
89		return offset + face * rtex->layer_size[level];
90	default:
91		assert(zslice == 0 && face == 0);
92		return offset;
93	}
94}
95
96static unsigned r600_get_pixel_alignment(struct pipe_screen *screen,
97					 enum pipe_format format,
98					 unsigned array_mode)
99{
100	struct r600_screen* rscreen = (struct r600_screen *)screen;
101	unsigned pixsize = util_format_get_blocksize(format);
102	int p_align;
103
104	switch(array_mode) {
105	case V_038000_ARRAY_1D_TILED_THIN1:
106		p_align = MAX2(8,
107			       ((rscreen->tiling_info->group_bytes / 8 / pixsize)));
108		break;
109	case V_038000_ARRAY_2D_TILED_THIN1:
110		p_align = MAX2(rscreen->tiling_info->num_banks,
111			       (((rscreen->tiling_info->group_bytes / 8 / pixsize)) *
112				rscreen->tiling_info->num_banks));
113		break;
114	case 0:
115	default:
116		p_align = 64;
117		break;
118	}
119	return p_align;
120}
121
122static unsigned r600_get_height_alignment(struct pipe_screen *screen,
123					  unsigned array_mode)
124{
125	struct r600_screen* rscreen = (struct r600_screen *)screen;
126	int h_align;
127
128	switch (array_mode) {
129	case V_038000_ARRAY_2D_TILED_THIN1:
130		h_align = rscreen->tiling_info->num_channels * 8;
131		break;
132	case V_038000_ARRAY_1D_TILED_THIN1:
133		h_align = 8;
134		break;
135	default:
136		h_align = 1;
137		break;
138	}
139	return h_align;
140}
141
142static unsigned mip_minify(unsigned size, unsigned level)
143{
144	unsigned val;
145	val = u_minify(size, level);
146	if (level > 0)
147		val = util_next_power_of_two(val);
148	return val;
149}
150
151static unsigned r600_texture_get_stride(struct pipe_screen *screen,
152					struct r600_resource_texture *rtex,
153					unsigned level)
154{
155	struct pipe_resource *ptex = &rtex->resource.base.b;
156	struct radeon *radeon = (struct radeon *)screen->winsys;
157	enum chip_class chipc = r600_get_family_class(radeon);
158	unsigned width, stride, tile_width;
159
160	if (rtex->pitch_override)
161		return rtex->pitch_override;
162
163	width = mip_minify(ptex->width0, level);
164	if (util_format_is_plain(ptex->format)) {
165		tile_width = r600_get_pixel_alignment(screen, ptex->format,
166						      rtex->array_mode[level]);
167		width = align(width, tile_width);
168	}
169	stride = util_format_get_stride(ptex->format, width);
170	if (chipc == EVERGREEN)
171		stride = align(stride, 512);
172	return stride;
173}
174
175static unsigned r600_texture_get_nblocksy(struct pipe_screen *screen,
176					  struct r600_resource_texture *rtex,
177					  unsigned level)
178{
179	struct pipe_resource *ptex = &rtex->resource.base.b;
180	unsigned height, tile_height;
181
182	height = mip_minify(ptex->height0, level);
183	if (util_format_is_plain(ptex->format)) {
184		tile_height = r600_get_height_alignment(screen,
185							rtex->array_mode[level]);
186		height = align(height, tile_height);
187	}
188	return util_format_get_nblocksy(ptex->format, height);
189}
190
191/* Get a width in pixels from a stride in bytes. */
192static unsigned pitch_to_width(enum pipe_format format,
193                                unsigned pitch_in_bytes)
194{
195    return (pitch_in_bytes / util_format_get_blocksize(format)) *
196            util_format_get_blockwidth(format);
197}
198
199static void r600_texture_set_array_mode(struct pipe_screen *screen,
200					struct r600_resource_texture *rtex,
201					unsigned level, unsigned array_mode)
202{
203	struct pipe_resource *ptex = &rtex->resource.base.b;
204
205	switch (array_mode) {
206	case V_0280A0_ARRAY_LINEAR_GENERAL:
207	case V_0280A0_ARRAY_LINEAR_ALIGNED:
208	case V_0280A0_ARRAY_1D_TILED_THIN1:
209	default:
210		rtex->array_mode[level] = array_mode;
211		break;
212	case V_0280A0_ARRAY_2D_TILED_THIN1:
213	{
214		unsigned w, h, tile_height, tile_width;
215
216		tile_height = r600_get_height_alignment(screen, array_mode);
217		tile_width = r600_get_pixel_alignment(screen, ptex->format, array_mode);
218
219		w = mip_minify(ptex->width0, level);
220		h = mip_minify(ptex->height0, level);
221		if (w < tile_width || h < tile_height)
222			rtex->array_mode[level] = V_0280A0_ARRAY_1D_TILED_THIN1;
223		else
224			rtex->array_mode[level] = array_mode;
225	}
226	break;
227	}
228}
229
230static void r600_setup_miptree(struct pipe_screen *screen,
231			       struct r600_resource_texture *rtex,
232			       unsigned array_mode)
233{
234	struct pipe_resource *ptex = &rtex->resource.base.b;
235	struct radeon *radeon = (struct radeon *)screen->winsys;
236	enum chip_class chipc = r600_get_family_class(radeon);
237	unsigned pitch, size, layer_size, i, offset;
238	unsigned nblocksy;
239
240	for (i = 0, offset = 0; i <= ptex->last_level; i++) {
241		r600_texture_set_array_mode(screen, rtex, i, array_mode);
242
243		pitch = r600_texture_get_stride(screen, rtex, i);
244		nblocksy = r600_texture_get_nblocksy(screen, rtex, i);
245
246		layer_size = pitch * nblocksy;
247
248		if (ptex->target == PIPE_TEXTURE_CUBE) {
249			if (chipc >= R700)
250				size = layer_size * 8;
251			else
252				size = layer_size * 6;
253		}
254		else
255			size = layer_size * u_minify(ptex->depth0, i);
256		rtex->offset[i] = offset;
257		rtex->layer_size[i] = layer_size;
258		rtex->pitch_in_bytes[i] = pitch;
259		rtex->pitch_in_pixels[i] = pitch_to_width(ptex->format, pitch);
260		offset += size;
261	}
262	rtex->size = offset;
263}
264
265static struct r600_resource_texture *
266r600_texture_create_object(struct pipe_screen *screen,
267			   const struct pipe_resource *base,
268			   unsigned array_mode,
269			   unsigned pitch_in_bytes_override,
270			   unsigned max_buffer_size,
271			   struct r600_bo *bo)
272{
273	struct r600_resource_texture *rtex;
274	struct r600_resource *resource;
275	struct radeon *radeon = (struct radeon *)screen->winsys;
276
277	rtex = CALLOC_STRUCT(r600_resource_texture);
278	if (rtex == NULL)
279		return NULL;
280
281	resource = &rtex->resource;
282	resource->base.b = *base;
283	resource->base.vtbl = &r600_texture_vtbl;
284	pipe_reference_init(&resource->base.b.reference, 1);
285	resource->base.b.screen = screen;
286	resource->bo = bo;
287	rtex->pitch_override = pitch_in_bytes_override;
288
289	if (array_mode)
290		rtex->tiled = 1;
291	r600_setup_miptree(screen, rtex, array_mode);
292
293	resource->size = rtex->size;
294
295	if (!resource->bo) {
296		resource->bo = r600_bo(radeon, rtex->size, 4096, base->bind, base->usage);
297		if (!resource->bo) {
298			FREE(rtex);
299			return NULL;
300		}
301	}
302	return rtex;
303}
304
305struct pipe_resource *r600_texture_create(struct pipe_screen *screen,
306						const struct pipe_resource *templ)
307{
308	unsigned array_mode = 0;
309        static int force_tiling = -1;
310
311        /* Would like some magic "get_bool_option_once" routine.
312	 */
313	if (force_tiling == -1)
314                force_tiling = debug_get_bool_option("R600_FORCE_TILING", FALSE);
315
316	if (force_tiling) {
317		if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER) &&
318		    !(templ->bind & PIPE_BIND_SCANOUT)) {
319			array_mode = V_038000_ARRAY_2D_TILED_THIN1;
320		}
321	}
322
323	return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode,
324								  0, 0, NULL);
325
326}
327
328static void r600_texture_destroy(struct pipe_screen *screen,
329				 struct pipe_resource *ptex)
330{
331	struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex;
332	struct r600_resource *resource = &rtex->resource;
333	struct radeon *radeon = (struct radeon *)screen->winsys;
334
335	if (rtex->flushed_depth_texture)
336		pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL);
337
338	if (resource->bo) {
339		r600_bo_reference(radeon, &resource->bo, NULL);
340	}
341	FREE(rtex);
342}
343
344static struct pipe_surface *r600_get_tex_surface(struct pipe_screen *screen,
345						struct pipe_resource *texture,
346						unsigned face, unsigned level,
347						unsigned zslice, unsigned flags)
348{
349	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
350	struct r600_surface *surface = CALLOC_STRUCT(r600_surface);
351	unsigned offset, tile_height;
352
353	if (surface == NULL)
354		return NULL;
355	offset = r600_texture_get_offset(rtex, level, zslice, face);
356	pipe_reference_init(&surface->base.reference, 1);
357	pipe_resource_reference(&surface->base.texture, texture);
358	surface->base.format = texture->format;
359	surface->base.width = mip_minify(texture->width0, level);
360	surface->base.height = mip_minify(texture->height0, level);
361	surface->base.offset = offset;
362	surface->base.usage = flags;
363	surface->base.zslice = zslice;
364	surface->base.texture = texture;
365	surface->base.face = face;
366	surface->base.level = level;
367
368	tile_height = r600_get_height_alignment(screen, rtex->array_mode[level]);
369	surface->aligned_height = align(surface->base.height, tile_height);
370	return &surface->base;
371}
372
373static void r600_tex_surface_destroy(struct pipe_surface *surface)
374{
375	pipe_resource_reference(&surface->texture, NULL);
376	FREE(surface);
377}
378
379
380struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
381					       const struct pipe_resource *templ,
382					       struct winsys_handle *whandle)
383{
384	struct radeon *rw = (struct radeon*)screen->winsys;
385	struct r600_bo *bo = NULL;
386	unsigned array_mode = 0;
387
388	/* Support only 2D textures without mipmaps */
389	if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) ||
390	      templ->depth0 != 1 || templ->last_level != 0)
391		return NULL;
392
393	bo = r600_bo_handle(rw, whandle->handle, &array_mode);
394	if (bo == NULL) {
395		return NULL;
396	}
397
398	return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode,
399								  whandle->stride,
400								  0,
401								  bo);
402}
403
404static unsigned int r600_texture_is_referenced(struct pipe_context *context,
405						struct pipe_resource *texture,
406						unsigned face, unsigned level)
407{
408	/* FIXME */
409	return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
410}
411
412int (*r600_blit_uncompress_depth_ptr)(struct pipe_context *ctx, struct r600_resource_texture *texture);
413
414int r600_texture_depth_flush(struct pipe_context *ctx,
415			     struct pipe_resource *texture)
416{
417	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
418	struct pipe_resource resource;
419
420	if (rtex->flushed_depth_texture)
421		goto out;
422
423	resource.target = PIPE_TEXTURE_2D;
424	resource.format = texture->format;
425	resource.width0 = texture->width0;
426	resource.height0 = texture->height0;
427	resource.depth0 = 1;
428	resource.last_level = 0;
429	resource.nr_samples = 0;
430	resource.usage = PIPE_USAGE_DYNAMIC;
431	resource.bind = 0;
432	resource.flags = R600_RESOURCE_FLAG_TRANSFER;
433
434	resource.bind |= PIPE_BIND_DEPTH_STENCIL;
435
436	rtex->flushed_depth_texture = (struct r600_resource_texture *)ctx->screen->resource_create(ctx->screen, &resource);
437	if (rtex->flushed_depth_texture == NULL) {
438		R600_ERR("failed to create temporary texture to hold untiled copy\n");
439		return -ENOMEM;
440	}
441
442out:
443	/* XXX: only do this if the depth texture has actually changed:
444	 */
445	r600_blit_uncompress_depth_ptr(ctx, rtex);
446	return 0;
447}
448
449/* Needs adjustment for pixelformat:
450 */
451static INLINE unsigned u_box_volume( const struct pipe_box *box )
452{
453        return box->width * box->depth * box->height;
454};
455
456
457struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
458						struct pipe_resource *texture,
459						struct pipe_subresource sr,
460						unsigned usage,
461						const struct pipe_box *box)
462{
463	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
464	struct pipe_resource resource;
465	struct r600_transfer *trans;
466	int r;
467	boolean use_staging_texture = FALSE;
468	boolean discard = FALSE;
469
470	if (!(usage & PIPE_TRANSFER_READ) && (usage & PIPE_TRANSFER_DISCARD))
471		discard = TRUE;
472
473	/* We cannot map a tiled texture directly because the data is
474	 * in a different order, therefore we do detiling using a blit.
475	 *
476	 * Also, use a temporary in GTT memory for read transfers, as
477	 * the CPU is much happier reading out of cached system memory
478	 * than uncached VRAM.
479	 */
480	if (rtex->tiled)
481		use_staging_texture = TRUE;
482
483        if (usage & PIPE_TRANSFER_READ &&
484            u_box_volume(box) > 1024)
485                use_staging_texture = TRUE;
486
487        /* XXX: Use a staging texture for uploads if the underlying BO
488         * is busy.  No interface for checking that currently? so do
489         * it eagerly whenever the transfer doesn't require a readback
490         * and might block.
491         */
492        if ((usage & PIPE_TRANSFER_WRITE) &&
493            discard &&
494            !(usage & (PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_UNSYNCHRONIZED)))
495                use_staging_texture = TRUE;
496
497	trans = CALLOC_STRUCT(r600_transfer);
498	if (trans == NULL)
499		return NULL;
500	pipe_resource_reference(&trans->transfer.resource, texture);
501	trans->transfer.sr = sr;
502	trans->transfer.usage = usage;
503	trans->transfer.box = *box;
504	if (rtex->depth) {
505                /* XXX: only readback the rectangle which is being mapped?
506                 */
507                /* XXX: when discard is true, no need to read back from depth texture
508                 */
509		r = r600_texture_depth_flush(ctx, texture);
510		if (r < 0) {
511			R600_ERR("failed to create temporary texture to hold untiled copy\n");
512			pipe_resource_reference(&trans->transfer.resource, NULL);
513			FREE(trans);
514			return NULL;
515		}
516	} else if (use_staging_texture) {
517		resource.target = PIPE_TEXTURE_2D;
518		resource.format = texture->format;
519		resource.width0 = box->width;
520		resource.height0 = box->height;
521		resource.depth0 = 1;
522		resource.last_level = 0;
523		resource.nr_samples = 0;
524		resource.usage = PIPE_USAGE_STAGING;
525		resource.bind = 0;
526		resource.flags = R600_RESOURCE_FLAG_TRANSFER;
527		/* For texture reading, the temporary (detiled) texture is used as
528		 * a render target when blitting from a tiled texture. */
529		if (usage & PIPE_TRANSFER_READ) {
530			resource.bind |= PIPE_BIND_RENDER_TARGET;
531		}
532		/* For texture writing, the temporary texture is used as a sampler
533		 * when blitting into a tiled texture. */
534		if (usage & PIPE_TRANSFER_WRITE) {
535			resource.bind |= PIPE_BIND_SAMPLER_VIEW;
536		}
537		/* Create the temporary texture. */
538		trans->staging_texture = ctx->screen->resource_create(ctx->screen, &resource);
539		if (trans->staging_texture == NULL) {
540			R600_ERR("failed to create temporary texture to hold untiled copy\n");
541			pipe_resource_reference(&trans->transfer.resource, NULL);
542			FREE(trans);
543			return NULL;
544		}
545
546		trans->transfer.stride =
547                        ((struct r600_resource_texture *)trans->staging_texture)->pitch_in_bytes[0];
548		if (!discard) {
549			r600_copy_to_staging_texture(ctx, trans);
550			/* Always referenced in the blit. */
551			ctx->flush(ctx, 0, NULL);
552		}
553		return &trans->transfer;
554	}
555	trans->transfer.stride = rtex->pitch_in_bytes[sr.level];
556	trans->offset = r600_texture_get_offset(rtex, sr.level, box->z, sr.face);
557	return &trans->transfer;
558}
559
560void r600_texture_transfer_destroy(struct pipe_context *ctx,
561				   struct pipe_transfer *transfer)
562{
563	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
564	struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
565
566	if (rtransfer->staging_texture) {
567		if (transfer->usage & PIPE_TRANSFER_WRITE) {
568			r600_copy_from_staging_texture(ctx, rtransfer);
569		}
570		pipe_resource_reference(&rtransfer->staging_texture, NULL);
571	}
572	if (rtex->flushed_depth_texture) {
573		pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL);
574	}
575	pipe_resource_reference(&transfer->resource, NULL);
576	FREE(transfer);
577}
578
579void* r600_texture_transfer_map(struct pipe_context *ctx,
580				struct pipe_transfer* transfer)
581{
582	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
583	struct r600_bo *bo;
584	enum pipe_format format = transfer->resource->format;
585	struct radeon *radeon = (struct radeon *)ctx->screen->winsys;
586	unsigned offset = 0;
587	unsigned usage = 0;
588	char *map;
589
590	if (rtransfer->staging_texture) {
591		bo = ((struct r600_resource *)rtransfer->staging_texture)->bo;
592	} else {
593		struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
594
595		if (rtex->flushed_depth_texture)
596			bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo;
597		else
598			bo = ((struct r600_resource *)transfer->resource)->bo;
599
600		offset = rtransfer->offset +
601			transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
602			transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
603	}
604
605	if (transfer->usage & PIPE_TRANSFER_WRITE) {
606		usage |= PB_USAGE_CPU_WRITE;
607
608		if (transfer->usage & PIPE_TRANSFER_DISCARD) {
609		}
610
611		if (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) {
612		}
613	}
614
615	if (transfer->usage & PIPE_TRANSFER_READ) {
616		usage |= PB_USAGE_CPU_READ;
617	}
618
619	if (transfer->usage & PIPE_TRANSFER_DONTBLOCK) {
620		usage |= PB_USAGE_DONTBLOCK;
621	}
622
623	if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) {
624		usage |= PB_USAGE_UNSYNCHRONIZED;
625	}
626
627	map = r600_bo_map(radeon, bo, usage, ctx);
628	if (!map) {
629		return NULL;
630	}
631
632	return map + offset;
633}
634
635void r600_texture_transfer_unmap(struct pipe_context *ctx,
636				 struct pipe_transfer* transfer)
637{
638	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
639	struct radeon *radeon = (struct radeon *)ctx->screen->winsys;
640	struct r600_bo *bo;
641
642	if (rtransfer->staging_texture) {
643		bo = ((struct r600_resource *)rtransfer->staging_texture)->bo;
644	} else {
645		struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
646
647		if (rtex->flushed_depth_texture) {
648			bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo;
649		} else {
650			bo = ((struct r600_resource *)transfer->resource)->bo;
651		}
652	}
653	r600_bo_unmap(radeon, bo);
654}
655
656struct u_resource_vtbl r600_texture_vtbl =
657{
658	u_default_resource_get_handle,	/* get_handle */
659	r600_texture_destroy,		/* resource_destroy */
660	r600_texture_is_referenced,	/* is_resource_referenced */
661	r600_texture_get_transfer,	/* get_transfer */
662	r600_texture_transfer_destroy,	/* transfer_destroy */
663	r600_texture_transfer_map,	/* transfer_map */
664	u_default_transfer_flush_region,/* transfer_flush_region */
665	r600_texture_transfer_unmap,	/* transfer_unmap */
666	u_default_transfer_inline_write	/* transfer_inline_write */
667};
668
669void r600_init_screen_texture_functions(struct pipe_screen *screen)
670{
671	screen->get_tex_surface = r600_get_tex_surface;
672	screen->tex_surface_destroy = r600_tex_surface_destroy;
673}
674
675static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format,
676		const unsigned char *swizzle_view)
677{
678	unsigned i;
679	unsigned char swizzle[4];
680	unsigned result = 0;
681	const uint32_t swizzle_shift[4] = {
682		16, 19, 22, 25,
683	};
684	const uint32_t swizzle_bit[4] = {
685		0, 1, 2, 3,
686	};
687
688	if (swizzle_view) {
689		/* Combine two sets of swizzles. */
690		for (i = 0; i < 4; i++) {
691			swizzle[i] = swizzle_view[i] <= UTIL_FORMAT_SWIZZLE_W ?
692				swizzle_format[swizzle_view[i]] : swizzle_view[i];
693		}
694	} else {
695		memcpy(swizzle, swizzle_format, 4);
696	}
697
698	/* Get swizzle. */
699	for (i = 0; i < 4; i++) {
700		switch (swizzle[i]) {
701		case UTIL_FORMAT_SWIZZLE_Y:
702			result |= swizzle_bit[1] << swizzle_shift[i];
703			break;
704		case UTIL_FORMAT_SWIZZLE_Z:
705			result |= swizzle_bit[2] << swizzle_shift[i];
706			break;
707		case UTIL_FORMAT_SWIZZLE_W:
708			result |= swizzle_bit[3] << swizzle_shift[i];
709			break;
710		case UTIL_FORMAT_SWIZZLE_0:
711			result |= V_038010_SQ_SEL_0 << swizzle_shift[i];
712			break;
713		case UTIL_FORMAT_SWIZZLE_1:
714			result |= V_038010_SQ_SEL_1 << swizzle_shift[i];
715			break;
716		default: /* UTIL_FORMAT_SWIZZLE_X */
717			result |= swizzle_bit[0] << swizzle_shift[i];
718		}
719	}
720	return result;
721}
722
723/* texture format translate */
724uint32_t r600_translate_texformat(enum pipe_format format,
725				  const unsigned char *swizzle_view,
726				  uint32_t *word4_p, uint32_t *yuv_format_p)
727{
728	uint32_t result = 0, word4 = 0, yuv_format = 0;
729	const struct util_format_description *desc;
730	boolean uniform = TRUE;
731	int i;
732	const uint32_t sign_bit[4] = {
733		S_038010_FORMAT_COMP_X(V_038010_SQ_FORMAT_COMP_SIGNED),
734		S_038010_FORMAT_COMP_Y(V_038010_SQ_FORMAT_COMP_SIGNED),
735		S_038010_FORMAT_COMP_Z(V_038010_SQ_FORMAT_COMP_SIGNED),
736		S_038010_FORMAT_COMP_W(V_038010_SQ_FORMAT_COMP_SIGNED)
737	};
738	desc = util_format_description(format);
739
740	word4 |= r600_get_swizzle_combined(desc->swizzle, swizzle_view);
741
742	/* Colorspace (return non-RGB formats directly). */
743	switch (desc->colorspace) {
744		/* Depth stencil formats */
745	case UTIL_FORMAT_COLORSPACE_ZS:
746		switch (format) {
747		case PIPE_FORMAT_Z16_UNORM:
748			result = FMT_16;
749			goto out_word4;
750		case PIPE_FORMAT_X24S8_USCALED:
751			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
752		case PIPE_FORMAT_Z24X8_UNORM:
753		case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
754			result = FMT_8_24;
755			goto out_word4;
756		case PIPE_FORMAT_S8X24_USCALED:
757			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
758		case PIPE_FORMAT_X8Z24_UNORM:
759		case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
760			result = FMT_24_8;
761			goto out_word4;
762		case PIPE_FORMAT_S8_USCALED:
763			result = V_0280A0_COLOR_8;
764			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
765			goto out_word4;
766		default:
767			goto out_unknown;
768		}
769
770	case UTIL_FORMAT_COLORSPACE_YUV:
771		yuv_format |= (1 << 30);
772		switch (format) {
773                case PIPE_FORMAT_UYVY:
774                case PIPE_FORMAT_YUYV:
775		default:
776			break;
777		}
778		goto out_unknown; /* TODO */
779
780	case UTIL_FORMAT_COLORSPACE_SRGB:
781		word4 |= S_038010_FORCE_DEGAMMA(1);
782		if (format == PIPE_FORMAT_L8A8_SRGB || format == PIPE_FORMAT_L8_SRGB)
783			goto out_unknown; /* fails for some reason - TODO */
784		break;
785
786	default:
787		break;
788	}
789
790	/* S3TC formats. TODO */
791	if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
792		goto out_unknown;
793	}
794
795
796	for (i = 0; i < desc->nr_channels; i++) {
797		if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) {
798			word4 |= sign_bit[i];
799		}
800	}
801
802	/* R8G8Bx_SNORM - TODO CxV8U8 */
803
804	/* RGTC - TODO */
805
806	/* See whether the components are of the same size. */
807	for (i = 1; i < desc->nr_channels; i++) {
808		uniform = uniform && desc->channel[0].size == desc->channel[i].size;
809	}
810
811	/* Non-uniform formats. */
812	if (!uniform) {
813		switch(desc->nr_channels) {
814		case 3:
815			if (desc->channel[0].size == 5 &&
816			    desc->channel[1].size == 6 &&
817			    desc->channel[2].size == 5) {
818				result = FMT_5_6_5;
819				goto out_word4;
820			}
821			goto out_unknown;
822		case 4:
823			if (desc->channel[0].size == 5 &&
824			    desc->channel[1].size == 5 &&
825			    desc->channel[2].size == 5 &&
826			    desc->channel[3].size == 1) {
827				result = FMT_1_5_5_5;
828				goto out_word4;
829			}
830			if (desc->channel[0].size == 10 &&
831			    desc->channel[1].size == 10 &&
832			    desc->channel[2].size == 10 &&
833			    desc->channel[3].size == 2) {
834				result = FMT_10_10_10_2;
835				goto out_word4;
836			}
837			goto out_unknown;
838		}
839		goto out_unknown;
840	}
841
842	/* Find the first non-VOID channel. */
843	for (i = 0; i < 4; i++) {
844		if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) {
845			break;
846		}
847	}
848
849	if (i == 4)
850		goto out_unknown;
851
852	/* uniform formats */
853	switch (desc->channel[i].type) {
854	case UTIL_FORMAT_TYPE_UNSIGNED:
855	case UTIL_FORMAT_TYPE_SIGNED:
856		if (!desc->channel[i].normalized &&
857		    desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) {
858			goto out_unknown;
859		}
860
861		switch (desc->channel[i].size) {
862		case 4:
863			switch (desc->nr_channels) {
864			case 2:
865				result = FMT_4_4;
866				goto out_word4;
867			case 4:
868				result = FMT_4_4_4_4;
869				goto out_word4;
870			}
871			goto out_unknown;
872		case 8:
873			switch (desc->nr_channels) {
874			case 1:
875				result = FMT_8;
876				goto out_word4;
877			case 2:
878				result = FMT_8_8;
879				goto out_word4;
880			case 4:
881				result = FMT_8_8_8_8;
882				goto out_word4;
883			}
884			goto out_unknown;
885		case 16:
886			switch (desc->nr_channels) {
887			case 1:
888				result = FMT_16;
889				goto out_word4;
890			case 2:
891				result = FMT_16_16;
892				goto out_word4;
893			case 4:
894				result = FMT_16_16_16_16;
895				goto out_word4;
896			}
897		}
898		goto out_unknown;
899
900	case UTIL_FORMAT_TYPE_FLOAT:
901		switch (desc->channel[i].size) {
902		case 16:
903			switch (desc->nr_channels) {
904			case 1:
905				result = FMT_16_FLOAT;
906				goto out_word4;
907			case 2:
908				result = FMT_16_16_FLOAT;
909				goto out_word4;
910			case 4:
911				result = FMT_16_16_16_16_FLOAT;
912				goto out_word4;
913			}
914			goto out_unknown;
915		case 32:
916			switch (desc->nr_channels) {
917			case 1:
918				result = FMT_32_FLOAT;
919				goto out_word4;
920			case 2:
921				result = FMT_32_32_FLOAT;
922				goto out_word4;
923			case 4:
924				result = FMT_32_32_32_32_FLOAT;
925				goto out_word4;
926			}
927		}
928
929	}
930out_word4:
931	if (word4_p)
932		*word4_p = word4;
933	if (yuv_format_p)
934		*yuv_format_p = yuv_format;
935	return result;
936out_unknown:
937//	R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format));
938	return ~0;
939}
940