r600_texture.c revision af8eb5c851a9d566059ae9e37745614cd96b9a13
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_format_s3tc.h"
31#include "util/u_math.h"
32#include "util/u_inlines.h"
33#include "util/u_memory.h"
34#include "pipebuffer/pb_buffer.h"
35#include "r600_pipe.h"
36#include "r600_resource.h"
37#include "r600d.h"
38#include "r600_formats.h"
39
40/* Copy from a full GPU texture to a transfer's staging one. */
41static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
42{
43	struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer;
44	struct pipe_resource *texture = transfer->resource;
45
46	ctx->resource_copy_region(ctx, rtransfer->staging_texture,
47				0, 0, 0, 0, texture, transfer->level,
48				&transfer->box);
49}
50
51
52/* Copy from a transfer's staging texture to a full GPU one. */
53static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
54{
55	struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer;
56	struct pipe_resource *texture = transfer->resource;
57	struct pipe_box sbox;
58
59	sbox.x = sbox.y = sbox.z = 0;
60	sbox.width = transfer->box.width;
61	sbox.height = transfer->box.height;
62	/* XXX that might be wrong */
63	sbox.depth = 1;
64	ctx->resource_copy_region(ctx, texture, transfer->level,
65				  transfer->box.x, transfer->box.y, transfer->box.z,
66				  rtransfer->staging_texture,
67				  0, &sbox);
68
69	r600_flush(ctx, NULL, RADEON_FLUSH_ASYNC);
70}
71
72unsigned r600_texture_get_offset(struct r600_resource_texture *rtex,
73					unsigned level, unsigned layer)
74{
75	unsigned offset = rtex->offset[level];
76
77	switch (rtex->resource.b.b.b.target) {
78	case PIPE_TEXTURE_3D:
79	case PIPE_TEXTURE_CUBE:
80	default:
81		return offset + layer * rtex->layer_size[level];
82	}
83}
84
85static unsigned r600_get_block_alignment(struct pipe_screen *screen,
86					 enum pipe_format format,
87					 unsigned array_mode)
88{
89	struct r600_screen* rscreen = (struct r600_screen *)screen;
90	unsigned pixsize = util_format_get_blocksize(format);
91	int p_align;
92
93	switch(array_mode) {
94	case V_038000_ARRAY_1D_TILED_THIN1:
95		p_align = MAX2(8,
96			       ((rscreen->tiling_info.group_bytes / 8 / pixsize)));
97		break;
98	case V_038000_ARRAY_2D_TILED_THIN1:
99		p_align = MAX2(rscreen->tiling_info.num_banks,
100			       (((rscreen->tiling_info.group_bytes / 8 / pixsize)) *
101				rscreen->tiling_info.num_banks)) * 8;
102		break;
103	case V_038000_ARRAY_LINEAR_ALIGNED:
104		p_align = MAX2(64, rscreen->tiling_info.group_bytes / pixsize);
105		break;
106	case V_038000_ARRAY_LINEAR_GENERAL:
107	default:
108		p_align = rscreen->tiling_info.group_bytes / pixsize;
109		break;
110	}
111	return p_align;
112}
113
114static unsigned r600_get_height_alignment(struct pipe_screen *screen,
115					  unsigned array_mode)
116{
117	struct r600_screen* rscreen = (struct r600_screen *)screen;
118	int h_align;
119
120	switch (array_mode) {
121	case V_038000_ARRAY_2D_TILED_THIN1:
122		h_align = rscreen->tiling_info.num_channels * 8;
123		break;
124	case V_038000_ARRAY_1D_TILED_THIN1:
125	case V_038000_ARRAY_LINEAR_ALIGNED:
126		h_align = 8;
127		break;
128	case V_038000_ARRAY_LINEAR_GENERAL:
129	default:
130		h_align = 1;
131		break;
132	}
133	return h_align;
134}
135
136static unsigned r600_get_base_alignment(struct pipe_screen *screen,
137					enum pipe_format format,
138					unsigned array_mode)
139{
140	struct r600_screen* rscreen = (struct r600_screen *)screen;
141	unsigned pixsize = util_format_get_blocksize(format);
142	int p_align = r600_get_block_alignment(screen, format, array_mode);
143	int h_align = r600_get_height_alignment(screen, array_mode);
144	int b_align;
145
146	switch (array_mode) {
147	case V_038000_ARRAY_2D_TILED_THIN1:
148		b_align = MAX2(rscreen->tiling_info.num_banks * rscreen->tiling_info.num_channels * 8 * 8 * pixsize,
149			       p_align * pixsize * h_align);
150		break;
151	case V_038000_ARRAY_1D_TILED_THIN1:
152	case V_038000_ARRAY_LINEAR_ALIGNED:
153	case V_038000_ARRAY_LINEAR_GENERAL:
154	default:
155		b_align = rscreen->tiling_info.group_bytes;
156		break;
157	}
158	return b_align;
159}
160
161static unsigned mip_minify(unsigned size, unsigned level)
162{
163	unsigned val;
164	val = u_minify(size, level);
165	if (level > 0)
166		val = util_next_power_of_two(val);
167	return val;
168}
169
170static unsigned r600_texture_get_nblocksx(struct pipe_screen *screen,
171					  struct r600_resource_texture *rtex,
172					  unsigned level)
173{
174	struct pipe_resource *ptex = &rtex->resource.b.b.b;
175	unsigned nblocksx, block_align, width;
176	unsigned blocksize = util_format_get_blocksize(rtex->real_format);
177
178	if (rtex->pitch_override)
179		return rtex->pitch_override / blocksize;
180
181	width = mip_minify(ptex->width0, level);
182	nblocksx = util_format_get_nblocksx(rtex->real_format, width);
183
184	block_align = r600_get_block_alignment(screen, rtex->real_format,
185					      rtex->array_mode[level]);
186	nblocksx = align(nblocksx, block_align);
187	return nblocksx;
188}
189
190static unsigned r600_texture_get_nblocksy(struct pipe_screen *screen,
191					  struct r600_resource_texture *rtex,
192					  unsigned level)
193{
194	struct pipe_resource *ptex = &rtex->resource.b.b.b;
195	unsigned height, tile_height;
196
197	height = mip_minify(ptex->height0, level);
198	height = util_format_get_nblocksy(rtex->real_format, height);
199	tile_height = r600_get_height_alignment(screen,
200						rtex->array_mode[level]);
201
202	/* XXX Hack around an alignment issue. Less tests fail with this.
203	 *
204	 * The thing is depth-stencil buffers should be tiled, i.e.
205	 * the alignment should be >=8. If I make them tiled, stencil starts
206	 * working because it no longer overlaps with the depth buffer
207	 * in memory, but texturing like drawpix-stencil breaks. */
208	if (util_format_is_depth_or_stencil(rtex->real_format) && tile_height < 8)
209		tile_height = 8;
210
211	height = align(height, tile_height);
212	return height;
213}
214
215static void r600_texture_set_array_mode(struct pipe_screen *screen,
216					struct r600_resource_texture *rtex,
217					unsigned level, unsigned array_mode)
218{
219	struct pipe_resource *ptex = &rtex->resource.b.b.b;
220
221	switch (array_mode) {
222	case V_0280A0_ARRAY_LINEAR_GENERAL:
223	case V_0280A0_ARRAY_LINEAR_ALIGNED:
224	case V_0280A0_ARRAY_1D_TILED_THIN1:
225	default:
226		rtex->array_mode[level] = array_mode;
227		break;
228	case V_0280A0_ARRAY_2D_TILED_THIN1:
229	{
230		unsigned w, h, tile_height, tile_width;
231
232		tile_height = r600_get_height_alignment(screen, array_mode);
233		tile_width = r600_get_block_alignment(screen, rtex->real_format, array_mode);
234
235		w = mip_minify(ptex->width0, level);
236		h = mip_minify(ptex->height0, level);
237		if (w <= tile_width || h <= tile_height)
238			rtex->array_mode[level] = V_0280A0_ARRAY_1D_TILED_THIN1;
239		else
240			rtex->array_mode[level] = array_mode;
241	}
242	break;
243	}
244}
245
246static void r600_setup_miptree(struct pipe_screen *screen,
247			       struct r600_resource_texture *rtex,
248			       unsigned array_mode)
249{
250	struct pipe_resource *ptex = &rtex->resource.b.b.b;
251	enum chip_class chipc = ((struct r600_screen*)screen)->chip_class;
252	unsigned size, layer_size, i, offset;
253	unsigned nblocksx, nblocksy;
254
255	for (i = 0, offset = 0; i <= ptex->last_level; i++) {
256		unsigned blocksize = util_format_get_blocksize(rtex->real_format);
257		unsigned base_align = r600_get_base_alignment(screen, rtex->real_format, array_mode);
258
259		r600_texture_set_array_mode(screen, rtex, i, array_mode);
260
261		nblocksx = r600_texture_get_nblocksx(screen, rtex, i);
262		nblocksy = r600_texture_get_nblocksy(screen, rtex, i);
263
264		if (chipc >= EVERGREEN && array_mode == V_038000_ARRAY_LINEAR_GENERAL)
265			layer_size = align(nblocksx, 64) * nblocksy * blocksize;
266		else
267			layer_size = nblocksx * nblocksy * blocksize;
268
269		if (ptex->target == PIPE_TEXTURE_CUBE) {
270			if (chipc >= R700)
271				size = layer_size * 8;
272			else
273				size = layer_size * 6;
274		}
275		else if (ptex->target == PIPE_TEXTURE_3D)
276			size = layer_size * u_minify(ptex->depth0, i);
277		else
278			size = layer_size * ptex->array_size;
279
280		/* align base image and start of miptree */
281		if ((i == 0) || (i == 1))
282			offset = align(offset, base_align);
283		rtex->offset[i] = offset;
284		rtex->layer_size[i] = layer_size;
285		rtex->pitch_in_blocks[i] = nblocksx; /* CB talks in elements */
286		rtex->pitch_in_bytes[i] = nblocksx * blocksize;
287
288		offset += size;
289	}
290	rtex->size = offset;
291}
292
293/* Figure out whether u_blitter will fallback to a transfer operation.
294 * If so, don't use a staging resource.
295 */
296static boolean permit_hardware_blit(struct pipe_screen *screen,
297					const struct pipe_resource *res)
298{
299	unsigned bind;
300
301	if (util_format_is_depth_or_stencil(res->format))
302		bind = PIPE_BIND_DEPTH_STENCIL;
303	else
304		bind = PIPE_BIND_RENDER_TARGET;
305
306	/* hackaround for S3TC */
307	if (util_format_is_compressed(res->format))
308		return TRUE;
309
310	if (!screen->is_format_supported(screen,
311				res->format,
312				res->target,
313				res->nr_samples,
314                                bind))
315		return FALSE;
316
317	if (!screen->is_format_supported(screen,
318				res->format,
319				res->target,
320				res->nr_samples,
321                                PIPE_BIND_SAMPLER_VIEW))
322		return FALSE;
323
324	switch (res->usage) {
325	case PIPE_USAGE_STREAM:
326	case PIPE_USAGE_STAGING:
327		return FALSE;
328
329	default:
330		return TRUE;
331	}
332}
333
334static boolean r600_texture_get_handle(struct pipe_screen* screen,
335					struct pipe_resource *ptex,
336					struct winsys_handle *whandle)
337{
338	struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex;
339	struct r600_resource *resource = &rtex->resource;
340	struct r600_screen *rscreen = (struct r600_screen*)screen;
341
342	return rscreen->ws->buffer_get_handle(resource->buf,
343					      rtex->pitch_in_bytes[0], whandle);
344}
345
346static void r600_texture_destroy(struct pipe_screen *screen,
347				 struct pipe_resource *ptex)
348{
349	struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex;
350	struct r600_resource *resource = &rtex->resource;
351
352	if (rtex->flushed_depth_texture)
353		pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL);
354
355	pb_reference(&resource->buf, NULL);
356	FREE(rtex);
357}
358
359static const struct u_resource_vtbl r600_texture_vtbl =
360{
361	r600_texture_get_handle,	/* get_handle */
362	r600_texture_destroy,		/* resource_destroy */
363	r600_texture_get_transfer,	/* get_transfer */
364	r600_texture_transfer_destroy,	/* transfer_destroy */
365	r600_texture_transfer_map,	/* transfer_map */
366	u_default_transfer_flush_region,/* transfer_flush_region */
367	r600_texture_transfer_unmap,	/* transfer_unmap */
368	u_default_transfer_inline_write	/* transfer_inline_write */
369};
370
371static struct r600_resource_texture *
372r600_texture_create_object(struct pipe_screen *screen,
373			   const struct pipe_resource *base,
374			   unsigned array_mode,
375			   unsigned pitch_in_bytes_override,
376			   unsigned max_buffer_size,
377			   struct pb_buffer *buf,
378			   boolean alloc_bo)
379{
380	struct r600_resource_texture *rtex;
381	struct r600_resource *resource;
382	struct r600_screen *rscreen = (struct r600_screen*)screen;
383
384	rtex = CALLOC_STRUCT(r600_resource_texture);
385	if (rtex == NULL)
386		return NULL;
387
388	resource = &rtex->resource;
389	resource->b.b.b = *base;
390	resource->b.b.vtbl = &r600_texture_vtbl;
391	pipe_reference_init(&resource->b.b.b.reference, 1);
392	resource->b.b.b.screen = screen;
393	rtex->pitch_override = pitch_in_bytes_override;
394	rtex->real_format = base->format;
395
396	/* We must split depth and stencil into two separate buffers on Evergreen. */
397	if (!(base->flags & R600_RESOURCE_FLAG_TRANSFER) &&
398	    ((struct r600_screen*)screen)->chip_class >= EVERGREEN &&
399	    util_format_is_depth_and_stencil(base->format)) {
400		struct pipe_resource stencil;
401		unsigned stencil_pitch_override = 0;
402
403		switch (base->format) {
404		case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
405			rtex->real_format = PIPE_FORMAT_Z24X8_UNORM;
406			break;
407		case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
408			rtex->real_format = PIPE_FORMAT_X8Z24_UNORM;
409			break;
410		case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
411			rtex->real_format = PIPE_FORMAT_Z32_FLOAT;
412			break;
413		default:
414			assert(0);
415			FREE(rtex);
416			return NULL;
417		}
418
419		/* Divide the pitch in bytes by 4 for stencil, because it has a smaller pixel size. */
420		if (pitch_in_bytes_override) {
421			assert(base->format == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||
422			       base->format == PIPE_FORMAT_S8_USCALED_Z24_UNORM);
423			stencil_pitch_override = pitch_in_bytes_override / 4;
424		}
425
426		/* Allocate the stencil buffer. */
427		stencil = *base;
428		stencil.format = PIPE_FORMAT_S8_USCALED;
429		rtex->stencil = r600_texture_create_object(screen, &stencil, array_mode,
430							   stencil_pitch_override,
431							   max_buffer_size, NULL, FALSE);
432		if (!rtex->stencil) {
433			FREE(rtex);
434			return NULL;
435		}
436		/* Proceed in creating the depth buffer. */
437	}
438
439	/* only mark depth textures the HW can hit as depth textures */
440	if (util_format_is_depth_or_stencil(rtex->real_format) && permit_hardware_blit(screen, base))
441		rtex->depth = 1;
442
443	r600_setup_miptree(screen, rtex, array_mode);
444
445	/* If we initialized separate stencil for Evergreen. place it after depth. */
446	if (rtex->stencil) {
447		unsigned stencil_align, stencil_offset;
448
449		stencil_align = r600_get_base_alignment(screen, rtex->stencil->real_format, array_mode);
450		stencil_offset = align(rtex->size, stencil_align);
451
452		for (unsigned i = 0; i <= rtex->stencil->resource.b.b.b.last_level; i++)
453			rtex->stencil->offset[i] += stencil_offset;
454
455		rtex->size = stencil_offset + rtex->stencil->size;
456	}
457
458	/* Now create the backing buffer. */
459	if (!buf && alloc_bo) {
460		struct pipe_resource *ptex = &rtex->resource.b.b.b;
461		unsigned base_align = r600_get_base_alignment(screen, ptex->format, array_mode);
462
463		if (!r600_init_resource(rscreen, resource, rtex->size, base_align, base->bind, base->usage)) {
464			pipe_resource_reference((struct pipe_resource**)&rtex->stencil, NULL);
465			FREE(rtex);
466			return NULL;
467		}
468	} else if (buf) {
469		resource->buf = buf;
470		resource->cs_buf = rscreen->ws->buffer_get_cs_handle(buf);
471		resource->domains = RADEON_DOMAIN_GTT | RADEON_DOMAIN_VRAM;
472	}
473
474	if (rtex->stencil) {
475		rtex->stencil->resource.buf = rtex->resource.buf;
476		rtex->stencil->resource.cs_buf = rtex->resource.cs_buf;
477		rtex->stencil->resource.domains = rtex->resource.domains;
478	}
479	return rtex;
480}
481
482DEBUG_GET_ONCE_BOOL_OPTION(tiling_enabled, "R600_TILING", FALSE);
483
484struct pipe_resource *r600_texture_create(struct pipe_screen *screen,
485						const struct pipe_resource *templ)
486{
487	struct r600_screen *rscreen = (struct r600_screen*)screen;
488	unsigned array_mode = 0;
489
490	if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER) &&
491	    !(templ->bind & PIPE_BIND_SCANOUT)) {
492		if (util_format_is_compressed(templ->format)) {
493			array_mode = V_038000_ARRAY_1D_TILED_THIN1;
494		}
495		else if (debug_get_option_tiling_enabled() &&
496			 rscreen->info.drm_minor >= 9 &&
497			 permit_hardware_blit(screen, templ)) {
498			array_mode = V_038000_ARRAY_2D_TILED_THIN1;
499		}
500	}
501
502	return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode,
503								  0, 0, NULL, TRUE);
504}
505
506static struct pipe_surface *r600_create_surface(struct pipe_context *pipe,
507						struct pipe_resource *texture,
508						const struct pipe_surface *surf_tmpl)
509{
510	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
511	struct r600_surface *surface = CALLOC_STRUCT(r600_surface);
512	unsigned level = surf_tmpl->u.tex.level;
513
514	assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
515	if (surface == NULL)
516		return NULL;
517	/* XXX no offset */
518/*	offset = r600_texture_get_offset(rtex, level, surf_tmpl->u.tex.first_layer);*/
519	pipe_reference_init(&surface->base.reference, 1);
520	pipe_resource_reference(&surface->base.texture, texture);
521	surface->base.context = pipe;
522	surface->base.format = surf_tmpl->format;
523	surface->base.width = mip_minify(texture->width0, level);
524	surface->base.height = mip_minify(texture->height0, level);
525	surface->base.usage = surf_tmpl->usage;
526	surface->base.texture = texture;
527	surface->base.u.tex.first_layer = surf_tmpl->u.tex.first_layer;
528	surface->base.u.tex.last_layer = surf_tmpl->u.tex.last_layer;
529	surface->base.u.tex.level = level;
530
531	surface->aligned_height = r600_texture_get_nblocksy(pipe->screen,
532							    rtex, level);
533	return &surface->base;
534}
535
536static void r600_surface_destroy(struct pipe_context *pipe,
537				 struct pipe_surface *surface)
538{
539	pipe_resource_reference(&surface->texture, NULL);
540	FREE(surface);
541}
542
543struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
544					       const struct pipe_resource *templ,
545					       struct winsys_handle *whandle)
546{
547	struct r600_screen *rscreen = (struct r600_screen*)screen;
548	struct pb_buffer *buf = NULL;
549	unsigned stride = 0;
550	unsigned array_mode = 0;
551	enum radeon_bo_layout micro, macro;
552
553	/* Support only 2D textures without mipmaps */
554	if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) ||
555	      templ->depth0 != 1 || templ->last_level != 0)
556		return NULL;
557
558	buf = rscreen->ws->buffer_from_handle(rscreen->ws, whandle, &stride);
559	if (!buf)
560		return NULL;
561
562	rscreen->ws->buffer_get_tiling(buf, &micro, &macro);
563
564	if (macro == RADEON_LAYOUT_TILED)
565		array_mode = V_0280A0_ARRAY_2D_TILED_THIN1;
566	else if (micro == RADEON_LAYOUT_TILED)
567		array_mode = V_0280A0_ARRAY_1D_TILED_THIN1;
568	else
569		array_mode = 0;
570
571	return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode,
572								  stride, 0, buf, FALSE);
573}
574
575int r600_texture_depth_flush(struct pipe_context *ctx,
576			     struct pipe_resource *texture, boolean just_create)
577{
578	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
579	struct pipe_resource resource;
580
581	if (rtex->flushed_depth_texture)
582		goto out;
583
584	resource.target = texture->target;
585	resource.format = texture->format;
586	resource.width0 = texture->width0;
587	resource.height0 = texture->height0;
588	resource.depth0 = texture->depth0;
589	resource.array_size = texture->array_size;
590	resource.last_level = texture->last_level;
591	resource.nr_samples = texture->nr_samples;
592	resource.usage = PIPE_USAGE_DYNAMIC;
593	resource.bind = texture->bind | PIPE_BIND_DEPTH_STENCIL;
594	resource.flags = R600_RESOURCE_FLAG_TRANSFER | texture->flags;
595
596	rtex->flushed_depth_texture = (struct r600_resource_texture *)ctx->screen->resource_create(ctx->screen, &resource);
597	if (rtex->flushed_depth_texture == NULL) {
598		R600_ERR("failed to create temporary texture to hold untiled copy\n");
599		return -ENOMEM;
600	}
601
602	((struct r600_resource_texture *)rtex->flushed_depth_texture)->is_flushing_texture = TRUE;
603out:
604	if (just_create)
605		return 0;
606
607	/* XXX: only do this if the depth texture has actually changed:
608	 */
609	r600_blit_uncompress_depth(ctx, rtex);
610	return 0;
611}
612
613/* Needs adjustment for pixelformat:
614 */
615static INLINE unsigned u_box_volume( const struct pipe_box *box )
616{
617	return box->width * box->depth * box->height;
618};
619
620struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
621						struct pipe_resource *texture,
622						unsigned level,
623						unsigned usage,
624						const struct pipe_box *box)
625{
626	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
627	struct pipe_resource resource;
628	struct r600_transfer *trans;
629	int r;
630	boolean use_staging_texture = FALSE;
631
632	/* We cannot map a tiled texture directly because the data is
633	 * in a different order, therefore we do detiling using a blit.
634	 *
635	 * Also, use a temporary in GTT memory for read transfers, as
636	 * the CPU is much happier reading out of cached system memory
637	 * than uncached VRAM.
638	 */
639	if (R600_TEX_IS_TILED(rtex, level))
640		use_staging_texture = TRUE;
641
642	if ((usage & PIPE_TRANSFER_READ) && u_box_volume(box) > 1024)
643		use_staging_texture = TRUE;
644
645	/* XXX: Use a staging texture for uploads if the underlying BO
646	 * is busy.  No interface for checking that currently? so do
647	 * it eagerly whenever the transfer doesn't require a readback
648	 * and might block.
649	 */
650	if ((usage & PIPE_TRANSFER_WRITE) &&
651			!(usage & (PIPE_TRANSFER_READ |
652					PIPE_TRANSFER_DONTBLOCK |
653					PIPE_TRANSFER_UNSYNCHRONIZED)))
654		use_staging_texture = TRUE;
655
656	if (!permit_hardware_blit(ctx->screen, texture) ||
657		(texture->flags & R600_RESOURCE_FLAG_TRANSFER))
658		use_staging_texture = FALSE;
659
660	if (use_staging_texture && (usage & PIPE_TRANSFER_MAP_DIRECTLY))
661		return NULL;
662
663	trans = CALLOC_STRUCT(r600_transfer);
664	if (trans == NULL)
665		return NULL;
666	pipe_resource_reference(&trans->transfer.resource, texture);
667	trans->transfer.level = level;
668	trans->transfer.usage = usage;
669	trans->transfer.box = *box;
670	if (rtex->depth) {
671		/* XXX: only readback the rectangle which is being mapped?
672		*/
673		/* XXX: when discard is true, no need to read back from depth texture
674		*/
675		r = r600_texture_depth_flush(ctx, texture, FALSE);
676		if (r < 0) {
677			R600_ERR("failed to create temporary texture to hold untiled copy\n");
678			pipe_resource_reference(&trans->transfer.resource, NULL);
679			FREE(trans);
680			return NULL;
681		}
682		trans->transfer.stride = rtex->flushed_depth_texture->pitch_in_bytes[level];
683		trans->offset = r600_texture_get_offset(rtex->flushed_depth_texture, level, box->z);
684		return &trans->transfer;
685	} else if (use_staging_texture) {
686		resource.target = PIPE_TEXTURE_2D;
687		resource.format = texture->format;
688		resource.width0 = box->width;
689		resource.height0 = box->height;
690		resource.depth0 = 1;
691		resource.array_size = 1;
692		resource.last_level = 0;
693		resource.nr_samples = 0;
694		resource.usage = PIPE_USAGE_STAGING;
695		resource.bind = 0;
696		resource.flags = R600_RESOURCE_FLAG_TRANSFER;
697		/* For texture reading, the temporary (detiled) texture is used as
698		 * a render target when blitting from a tiled texture. */
699		if (usage & PIPE_TRANSFER_READ) {
700			resource.bind |= PIPE_BIND_RENDER_TARGET;
701		}
702		/* For texture writing, the temporary texture is used as a sampler
703		 * when blitting into a tiled texture. */
704		if (usage & PIPE_TRANSFER_WRITE) {
705			resource.bind |= PIPE_BIND_SAMPLER_VIEW;
706		}
707		/* Create the temporary texture. */
708		trans->staging_texture = ctx->screen->resource_create(ctx->screen, &resource);
709		if (trans->staging_texture == NULL) {
710			R600_ERR("failed to create temporary texture to hold untiled copy\n");
711			pipe_resource_reference(&trans->transfer.resource, NULL);
712			FREE(trans);
713			return NULL;
714		}
715
716		trans->transfer.stride =
717			((struct r600_resource_texture *)trans->staging_texture)->pitch_in_bytes[0];
718		if (usage & PIPE_TRANSFER_READ) {
719			r600_copy_to_staging_texture(ctx, trans);
720			/* Always referenced in the blit. */
721			r600_flush(ctx, NULL, 0);
722		}
723		return &trans->transfer;
724	}
725	trans->transfer.stride = rtex->pitch_in_bytes[level];
726	trans->transfer.layer_stride = rtex->layer_size[level];
727	trans->offset = r600_texture_get_offset(rtex, level, box->z);
728	return &trans->transfer;
729}
730
731void r600_texture_transfer_destroy(struct pipe_context *ctx,
732				   struct pipe_transfer *transfer)
733{
734	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
735	struct pipe_resource *texture = transfer->resource;
736	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
737
738	if (rtransfer->staging_texture) {
739		if (transfer->usage & PIPE_TRANSFER_WRITE) {
740			r600_copy_from_staging_texture(ctx, rtransfer);
741		}
742		pipe_resource_reference(&rtransfer->staging_texture, NULL);
743	}
744
745	if (rtex->depth && !rtex->is_flushing_texture) {
746		if ((transfer->usage & PIPE_TRANSFER_WRITE) && rtex->flushed_depth_texture)
747			r600_blit_push_depth(ctx, rtex);
748	}
749
750	pipe_resource_reference(&transfer->resource, NULL);
751	FREE(transfer);
752}
753
754void* r600_texture_transfer_map(struct pipe_context *ctx,
755				struct pipe_transfer* transfer)
756{
757	struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
758	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
759	struct pb_buffer *buf;
760	enum pipe_format format = transfer->resource->format;
761	unsigned offset = 0;
762	char *map;
763
764	if (rtransfer->staging_texture) {
765		buf = ((struct r600_resource *)rtransfer->staging_texture)->buf;
766	} else {
767		struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
768
769		if (rtex->flushed_depth_texture)
770			buf = ((struct r600_resource *)rtex->flushed_depth_texture)->buf;
771		else
772			buf = ((struct r600_resource *)transfer->resource)->buf;
773
774		offset = rtransfer->offset +
775			transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
776			transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
777	}
778
779	if (!(map = rctx->ws->buffer_map(buf, rctx->ctx.cs, transfer->usage))) {
780		return NULL;
781	}
782
783	return map + offset;
784}
785
786void r600_texture_transfer_unmap(struct pipe_context *ctx,
787				 struct pipe_transfer* transfer)
788{
789	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
790	struct r600_pipe_context *rctx = (struct r600_pipe_context*)ctx;
791	struct pb_buffer *buf;
792
793	if (rtransfer->staging_texture) {
794		buf = ((struct r600_resource *)rtransfer->staging_texture)->buf;
795	} else {
796		struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
797
798		if (rtex->flushed_depth_texture) {
799			buf = ((struct r600_resource *)rtex->flushed_depth_texture)->buf;
800		} else {
801			buf = ((struct r600_resource *)transfer->resource)->buf;
802		}
803	}
804	rctx->ws->buffer_unmap(buf);
805}
806
807void r600_init_surface_functions(struct r600_pipe_context *r600)
808{
809	r600->context.create_surface = r600_create_surface;
810	r600->context.surface_destroy = r600_surface_destroy;
811}
812
813static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format,
814		const unsigned char *swizzle_view)
815{
816	unsigned i;
817	unsigned char swizzle[4];
818	unsigned result = 0;
819	const uint32_t swizzle_shift[4] = {
820		16, 19, 22, 25,
821	};
822	const uint32_t swizzle_bit[4] = {
823		0, 1, 2, 3,
824	};
825
826	if (swizzle_view) {
827		util_format_compose_swizzles(swizzle_format, swizzle_view, swizzle);
828	} else {
829		memcpy(swizzle, swizzle_format, 4);
830	}
831
832	/* Get swizzle. */
833	for (i = 0; i < 4; i++) {
834		switch (swizzle[i]) {
835		case UTIL_FORMAT_SWIZZLE_Y:
836			result |= swizzle_bit[1] << swizzle_shift[i];
837			break;
838		case UTIL_FORMAT_SWIZZLE_Z:
839			result |= swizzle_bit[2] << swizzle_shift[i];
840			break;
841		case UTIL_FORMAT_SWIZZLE_W:
842			result |= swizzle_bit[3] << swizzle_shift[i];
843			break;
844		case UTIL_FORMAT_SWIZZLE_0:
845			result |= V_038010_SQ_SEL_0 << swizzle_shift[i];
846			break;
847		case UTIL_FORMAT_SWIZZLE_1:
848			result |= V_038010_SQ_SEL_1 << swizzle_shift[i];
849			break;
850		default: /* UTIL_FORMAT_SWIZZLE_X */
851			result |= swizzle_bit[0] << swizzle_shift[i];
852		}
853	}
854	return result;
855}
856
857/* texture format translate */
858uint32_t r600_translate_texformat(struct pipe_screen *screen,
859				  enum pipe_format format,
860				  const unsigned char *swizzle_view,
861				  uint32_t *word4_p, uint32_t *yuv_format_p)
862{
863	uint32_t result = 0, word4 = 0, yuv_format = 0;
864	const struct util_format_description *desc;
865	boolean uniform = TRUE;
866	static int r600_enable_s3tc = -1;
867
868	int i;
869	const uint32_t sign_bit[4] = {
870		S_038010_FORMAT_COMP_X(V_038010_SQ_FORMAT_COMP_SIGNED),
871		S_038010_FORMAT_COMP_Y(V_038010_SQ_FORMAT_COMP_SIGNED),
872		S_038010_FORMAT_COMP_Z(V_038010_SQ_FORMAT_COMP_SIGNED),
873		S_038010_FORMAT_COMP_W(V_038010_SQ_FORMAT_COMP_SIGNED)
874	};
875	desc = util_format_description(format);
876
877	word4 |= r600_get_swizzle_combined(desc->swizzle, swizzle_view);
878
879	/* Colorspace (return non-RGB formats directly). */
880	switch (desc->colorspace) {
881		/* Depth stencil formats */
882	case UTIL_FORMAT_COLORSPACE_ZS:
883		switch (format) {
884		case PIPE_FORMAT_Z16_UNORM:
885			result = FMT_16;
886			goto out_word4;
887		case PIPE_FORMAT_X24S8_USCALED:
888			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
889		case PIPE_FORMAT_Z24X8_UNORM:
890		case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
891			result = FMT_8_24;
892			goto out_word4;
893		case PIPE_FORMAT_S8X24_USCALED:
894			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
895		case PIPE_FORMAT_X8Z24_UNORM:
896		case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
897			result = FMT_24_8;
898			goto out_word4;
899		case PIPE_FORMAT_S8_USCALED:
900			result = FMT_8;
901			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
902			goto out_word4;
903		case PIPE_FORMAT_Z32_FLOAT:
904			result = FMT_32_FLOAT;
905			goto out_word4;
906		case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
907			result = FMT_X24_8_32_FLOAT;
908			goto out_word4;
909		default:
910			goto out_unknown;
911		}
912
913	case UTIL_FORMAT_COLORSPACE_YUV:
914		yuv_format |= (1 << 30);
915		switch (format) {
916		case PIPE_FORMAT_UYVY:
917		case PIPE_FORMAT_YUYV:
918		default:
919			break;
920		}
921		goto out_unknown; /* TODO */
922
923	case UTIL_FORMAT_COLORSPACE_SRGB:
924		word4 |= S_038010_FORCE_DEGAMMA(1);
925		break;
926
927	default:
928		break;
929	}
930
931	if (r600_enable_s3tc == -1) {
932		struct r600_screen *rscreen = (struct r600_screen *)screen;
933		if (rscreen->info.drm_minor >= 9)
934			r600_enable_s3tc = 1;
935		else
936			r600_enable_s3tc = debug_get_bool_option("R600_ENABLE_S3TC", FALSE);
937	}
938
939	if (desc->layout == UTIL_FORMAT_LAYOUT_RGTC) {
940		if (!r600_enable_s3tc)
941			goto out_unknown;
942
943		switch (format) {
944		case PIPE_FORMAT_RGTC1_SNORM:
945		case PIPE_FORMAT_LATC1_SNORM:
946			word4 |= sign_bit[0];
947		case PIPE_FORMAT_RGTC1_UNORM:
948		case PIPE_FORMAT_LATC1_UNORM:
949			result = FMT_BC4;
950			goto out_word4;
951		case PIPE_FORMAT_RGTC2_SNORM:
952		case PIPE_FORMAT_LATC2_SNORM:
953			word4 |= sign_bit[0] | sign_bit[1];
954		case PIPE_FORMAT_RGTC2_UNORM:
955		case PIPE_FORMAT_LATC2_UNORM:
956			result = FMT_BC5;
957			goto out_word4;
958		default:
959			goto out_unknown;
960		}
961	}
962
963	if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
964
965		if (!r600_enable_s3tc)
966			goto out_unknown;
967
968		if (!util_format_s3tc_enabled) {
969			goto out_unknown;
970		}
971
972		switch (format) {
973		case PIPE_FORMAT_DXT1_RGB:
974		case PIPE_FORMAT_DXT1_RGBA:
975		case PIPE_FORMAT_DXT1_SRGB:
976		case PIPE_FORMAT_DXT1_SRGBA:
977			result = FMT_BC1;
978			goto out_word4;
979		case PIPE_FORMAT_DXT3_RGBA:
980		case PIPE_FORMAT_DXT3_SRGBA:
981			result = FMT_BC2;
982			goto out_word4;
983		case PIPE_FORMAT_DXT5_RGBA:
984		case PIPE_FORMAT_DXT5_SRGBA:
985			result = FMT_BC3;
986			goto out_word4;
987		default:
988			goto out_unknown;
989		}
990	}
991
992	if (format == PIPE_FORMAT_R9G9B9E5_FLOAT) {
993		result = FMT_5_9_9_9_SHAREDEXP;
994		goto out_word4;
995	} else if (format == PIPE_FORMAT_R11G11B10_FLOAT) {
996		result = FMT_10_11_11_FLOAT;
997		goto out_word4;
998	}
999
1000
1001	for (i = 0; i < desc->nr_channels; i++) {
1002		if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) {
1003			word4 |= sign_bit[i];
1004		}
1005	}
1006
1007	/* R8G8Bx_SNORM - TODO CxV8U8 */
1008
1009	/* See whether the components are of the same size. */
1010	for (i = 1; i < desc->nr_channels; i++) {
1011		uniform = uniform && desc->channel[0].size == desc->channel[i].size;
1012	}
1013
1014	/* Non-uniform formats. */
1015	if (!uniform) {
1016		switch(desc->nr_channels) {
1017		case 3:
1018			if (desc->channel[0].size == 5 &&
1019			    desc->channel[1].size == 6 &&
1020			    desc->channel[2].size == 5) {
1021				result = FMT_5_6_5;
1022				goto out_word4;
1023			}
1024			goto out_unknown;
1025		case 4:
1026			if (desc->channel[0].size == 5 &&
1027			    desc->channel[1].size == 5 &&
1028			    desc->channel[2].size == 5 &&
1029			    desc->channel[3].size == 1) {
1030				result = FMT_1_5_5_5;
1031				goto out_word4;
1032			}
1033			if (desc->channel[0].size == 10 &&
1034			    desc->channel[1].size == 10 &&
1035			    desc->channel[2].size == 10 &&
1036			    desc->channel[3].size == 2) {
1037				result = FMT_2_10_10_10;
1038				goto out_word4;
1039			}
1040			goto out_unknown;
1041		}
1042		goto out_unknown;
1043	}
1044
1045	/* Find the first non-VOID channel. */
1046	for (i = 0; i < 4; i++) {
1047		if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) {
1048			break;
1049		}
1050	}
1051
1052	if (i == 4)
1053		goto out_unknown;
1054
1055	/* uniform formats */
1056	switch (desc->channel[i].type) {
1057	case UTIL_FORMAT_TYPE_UNSIGNED:
1058	case UTIL_FORMAT_TYPE_SIGNED:
1059#if 0
1060		if (!desc->channel[i].normalized &&
1061		    desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) {
1062			goto out_unknown;
1063		}
1064#endif
1065		if (desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB &&
1066		    !desc->channel[i].normalized)
1067			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
1068
1069		switch (desc->channel[i].size) {
1070		case 4:
1071			switch (desc->nr_channels) {
1072			case 2:
1073				result = FMT_4_4;
1074				goto out_word4;
1075			case 4:
1076				result = FMT_4_4_4_4;
1077				goto out_word4;
1078			}
1079			goto out_unknown;
1080		case 8:
1081			switch (desc->nr_channels) {
1082			case 1:
1083				result = FMT_8;
1084				goto out_word4;
1085			case 2:
1086				result = FMT_8_8;
1087				goto out_word4;
1088			case 4:
1089				result = FMT_8_8_8_8;
1090				goto out_word4;
1091			}
1092			goto out_unknown;
1093		case 16:
1094			switch (desc->nr_channels) {
1095			case 1:
1096				result = FMT_16;
1097				goto out_word4;
1098			case 2:
1099				result = FMT_16_16;
1100				goto out_word4;
1101			case 4:
1102				result = FMT_16_16_16_16;
1103				goto out_word4;
1104			}
1105			goto out_unknown;
1106		case 32:
1107			switch (desc->nr_channels) {
1108			case 1:
1109				result = FMT_32;
1110				goto out_word4;
1111			case 2:
1112				result = FMT_32_32;
1113				goto out_word4;
1114			case 4:
1115				result = FMT_32_32_32_32;
1116				goto out_word4;
1117			}
1118		}
1119		goto out_unknown;
1120
1121	case UTIL_FORMAT_TYPE_FLOAT:
1122		switch (desc->channel[i].size) {
1123		case 16:
1124			switch (desc->nr_channels) {
1125			case 1:
1126				result = FMT_16_FLOAT;
1127				goto out_word4;
1128			case 2:
1129				result = FMT_16_16_FLOAT;
1130				goto out_word4;
1131			case 4:
1132				result = FMT_16_16_16_16_FLOAT;
1133				goto out_word4;
1134			}
1135			goto out_unknown;
1136		case 32:
1137			switch (desc->nr_channels) {
1138			case 1:
1139				result = FMT_32_FLOAT;
1140				goto out_word4;
1141			case 2:
1142				result = FMT_32_32_FLOAT;
1143				goto out_word4;
1144			case 4:
1145				result = FMT_32_32_32_32_FLOAT;
1146				goto out_word4;
1147			}
1148		}
1149		goto out_unknown;
1150	}
1151
1152out_word4:
1153	if (word4_p)
1154		*word4_p = word4;
1155	if (yuv_format_p)
1156		*yuv_format_p = yuv_format;
1157	return result;
1158out_unknown:
1159	/* R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format)); */
1160	return ~0;
1161}
1162