r600_texture.c revision f2bae9456f141f8c1104ef2a0aab31f6190ae5f0
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	struct radeon *radeon = ((struct r600_screen*)screen)->radeon;
252	enum chip_class chipc = r600_get_family_class(radeon);
253	unsigned size, layer_size, i, offset;
254	unsigned nblocksx, nblocksy;
255
256	for (i = 0, offset = 0; i <= ptex->last_level; i++) {
257		unsigned blocksize = util_format_get_blocksize(rtex->real_format);
258		unsigned base_align = r600_get_base_alignment(screen, rtex->real_format, array_mode);
259
260		r600_texture_set_array_mode(screen, rtex, i, array_mode);
261
262		nblocksx = r600_texture_get_nblocksx(screen, rtex, i);
263		nblocksy = r600_texture_get_nblocksy(screen, rtex, i);
264
265		if (chipc >= EVERGREEN && array_mode == V_038000_ARRAY_LINEAR_GENERAL)
266			layer_size = align(nblocksx, 64) * nblocksy * blocksize;
267		else
268			layer_size = nblocksx * nblocksy * blocksize;
269
270		if (ptex->target == PIPE_TEXTURE_CUBE) {
271			if (chipc >= R700)
272				size = layer_size * 8;
273			else
274				size = layer_size * 6;
275		}
276		else if (ptex->target == PIPE_TEXTURE_3D)
277			size = layer_size * u_minify(ptex->depth0, i);
278		else
279			size = layer_size * ptex->array_size;
280
281		/* align base image and start of miptree */
282		if ((i == 0) || (i == 1))
283			offset = align(offset, base_align);
284		rtex->offset[i] = offset;
285		rtex->layer_size[i] = layer_size;
286		rtex->pitch_in_blocks[i] = nblocksx; /* CB talks in elements */
287		rtex->pitch_in_bytes[i] = nblocksx * blocksize;
288
289		offset += size;
290	}
291	rtex->size = offset;
292}
293
294/* Figure out whether u_blitter will fallback to a transfer operation.
295 * If so, don't use a staging resource.
296 */
297static boolean permit_hardware_blit(struct pipe_screen *screen,
298					const struct pipe_resource *res)
299{
300	unsigned bind;
301
302	if (util_format_is_depth_or_stencil(res->format))
303		bind = PIPE_BIND_DEPTH_STENCIL;
304	else
305		bind = PIPE_BIND_RENDER_TARGET;
306
307	/* hackaround for S3TC */
308	if (util_format_is_compressed(res->format))
309		return TRUE;
310
311	if (!screen->is_format_supported(screen,
312				res->format,
313				res->target,
314				res->nr_samples,
315                                bind))
316		return FALSE;
317
318	if (!screen->is_format_supported(screen,
319				res->format,
320				res->target,
321				res->nr_samples,
322                                PIPE_BIND_SAMPLER_VIEW))
323		return FALSE;
324
325	switch (res->usage) {
326	case PIPE_USAGE_STREAM:
327	case PIPE_USAGE_STAGING:
328		return FALSE;
329
330	default:
331		return TRUE;
332	}
333}
334
335static boolean r600_texture_get_handle(struct pipe_screen* screen,
336					struct pipe_resource *ptex,
337					struct winsys_handle *whandle)
338{
339	struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex;
340	struct r600_resource *resource = &rtex->resource;
341	struct radeon *radeon = ((struct r600_screen*)screen)->radeon;
342
343	return r600_bo_get_winsys_handle(radeon, resource->bo,
344			rtex->pitch_in_bytes[0], whandle);
345}
346
347static void r600_texture_destroy(struct pipe_screen *screen,
348				 struct pipe_resource *ptex)
349{
350	struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex;
351	struct r600_resource *resource = &rtex->resource;
352
353	if (rtex->flushed_depth_texture)
354		pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL);
355
356	if (resource->bo) {
357		r600_bo_reference(&resource->bo, NULL);
358	}
359	FREE(rtex);
360}
361
362static const struct u_resource_vtbl r600_texture_vtbl =
363{
364	r600_texture_get_handle,	/* get_handle */
365	r600_texture_destroy,		/* resource_destroy */
366	r600_texture_get_transfer,	/* get_transfer */
367	r600_texture_transfer_destroy,	/* transfer_destroy */
368	r600_texture_transfer_map,	/* transfer_map */
369	u_default_transfer_flush_region,/* transfer_flush_region */
370	r600_texture_transfer_unmap,	/* transfer_unmap */
371	u_default_transfer_inline_write	/* transfer_inline_write */
372};
373
374static struct r600_resource_texture *
375r600_texture_create_object(struct pipe_screen *screen,
376			   const struct pipe_resource *base,
377			   unsigned array_mode,
378			   unsigned pitch_in_bytes_override,
379			   unsigned max_buffer_size,
380			   struct r600_bo *bo,
381			   boolean alloc_bo)
382{
383	struct r600_resource_texture *rtex;
384	struct r600_resource *resource;
385	struct radeon *radeon = ((struct r600_screen*)screen)->radeon;
386
387	rtex = CALLOC_STRUCT(r600_resource_texture);
388	if (rtex == NULL)
389		return NULL;
390
391	resource = &rtex->resource;
392	resource->b.b.b = *base;
393	resource->b.b.vtbl = &r600_texture_vtbl;
394	pipe_reference_init(&resource->b.b.b.reference, 1);
395	resource->b.b.b.screen = screen;
396	resource->bo = bo;
397	rtex->pitch_override = pitch_in_bytes_override;
398	rtex->real_format = base->format;
399
400	/* We must split depth and stencil into two separate buffers on Evergreen. */
401	if (!(base->flags & R600_RESOURCE_FLAG_TRANSFER) &&
402	    r600_get_family_class(((struct r600_screen*)screen)->radeon) >= EVERGREEN &&
403	    util_format_is_depth_and_stencil(base->format)) {
404		struct pipe_resource stencil;
405		unsigned stencil_pitch_override = 0;
406
407		switch (base->format) {
408		case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
409			rtex->real_format = PIPE_FORMAT_Z24X8_UNORM;
410			break;
411		case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
412			rtex->real_format = PIPE_FORMAT_X8Z24_UNORM;
413			break;
414		case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
415			rtex->real_format = PIPE_FORMAT_Z32_FLOAT;
416			break;
417		default:
418			assert(0);
419			FREE(rtex);
420			return NULL;
421		}
422
423		/* Divide the pitch in bytes by 4 for stencil, because it has a smaller pixel size. */
424		if (pitch_in_bytes_override) {
425			assert(base->format == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||
426			       base->format == PIPE_FORMAT_S8_USCALED_Z24_UNORM);
427			stencil_pitch_override = pitch_in_bytes_override / 4;
428		}
429
430		/* Allocate the stencil buffer. */
431		stencil = *base;
432		stencil.format = PIPE_FORMAT_S8_USCALED;
433		rtex->stencil = r600_texture_create_object(screen, &stencil, array_mode,
434							   stencil_pitch_override,
435							   max_buffer_size, NULL, FALSE);
436		if (!rtex->stencil) {
437			FREE(rtex);
438			return NULL;
439		}
440		/* Proceed in creating the depth buffer. */
441	}
442
443	/* only mark depth textures the HW can hit as depth textures */
444	if (util_format_is_depth_or_stencil(rtex->real_format) && permit_hardware_blit(screen, base))
445		rtex->depth = 1;
446
447	r600_setup_miptree(screen, rtex, array_mode);
448
449	/* If we initialized separate stencil for Evergreen. place it after depth. */
450	if (rtex->stencil) {
451		unsigned stencil_align, stencil_offset;
452
453		stencil_align = r600_get_base_alignment(screen, rtex->stencil->real_format, array_mode);
454		stencil_offset = align(rtex->size, stencil_align);
455
456		for (unsigned i = 0; i <= rtex->stencil->resource.b.b.b.last_level; i++)
457			rtex->stencil->offset[i] += stencil_offset;
458
459		rtex->size = stencil_offset + rtex->stencil->size;
460	}
461
462	resource->size = rtex->size;
463
464	/* Now create the backing buffer. */
465	if (!resource->bo && alloc_bo) {
466		struct pipe_resource *ptex = &rtex->resource.b.b.b;
467		unsigned base_align = r600_get_base_alignment(screen, ptex->format, array_mode);
468
469		resource->bo = r600_bo(radeon, rtex->size, base_align, base->bind, base->usage);
470		if (!resource->bo) {
471			pipe_resource_reference((struct pipe_resource**)&rtex->stencil, NULL);
472			FREE(rtex);
473			return NULL;
474		}
475	}
476
477	if (rtex->stencil)
478		rtex->stencil->resource.bo = rtex->resource.bo;
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
543
544struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
545					       const struct pipe_resource *templ,
546					       struct winsys_handle *whandle)
547{
548	struct radeon *rw = ((struct r600_screen*)screen)->radeon;
549	struct r600_bo *bo = NULL;
550	unsigned stride = 0;
551	unsigned array_mode = 0;
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	bo = r600_bo_handle(rw, whandle, &stride, &array_mode);
559	if (bo == NULL) {
560		return NULL;
561	}
562
563	return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode,
564								  stride, 0, bo, FALSE);
565}
566
567int r600_texture_depth_flush(struct pipe_context *ctx,
568			     struct pipe_resource *texture, boolean just_create)
569{
570	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
571	struct pipe_resource resource;
572
573	if (rtex->flushed_depth_texture)
574		goto out;
575
576	resource.target = texture->target;
577	resource.format = texture->format;
578	resource.width0 = texture->width0;
579	resource.height0 = texture->height0;
580	resource.depth0 = texture->depth0;
581	resource.array_size = texture->array_size;
582	resource.last_level = texture->last_level;
583	resource.nr_samples = texture->nr_samples;
584	resource.usage = PIPE_USAGE_DYNAMIC;
585	resource.bind = texture->bind | PIPE_BIND_DEPTH_STENCIL;
586	resource.flags = R600_RESOURCE_FLAG_TRANSFER | texture->flags;
587
588	rtex->flushed_depth_texture = (struct r600_resource_texture *)ctx->screen->resource_create(ctx->screen, &resource);
589	if (rtex->flushed_depth_texture == NULL) {
590		R600_ERR("failed to create temporary texture to hold untiled copy\n");
591		return -ENOMEM;
592	}
593
594	((struct r600_resource_texture *)rtex->flushed_depth_texture)->is_flushing_texture = TRUE;
595out:
596	if (just_create)
597		return 0;
598
599	/* XXX: only do this if the depth texture has actually changed:
600	 */
601	r600_blit_uncompress_depth(ctx, rtex);
602	return 0;
603}
604
605/* Needs adjustment for pixelformat:
606 */
607static INLINE unsigned u_box_volume( const struct pipe_box *box )
608{
609	return box->width * box->depth * box->height;
610};
611
612struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
613						struct pipe_resource *texture,
614						unsigned level,
615						unsigned usage,
616						const struct pipe_box *box)
617{
618	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
619	struct pipe_resource resource;
620	struct r600_transfer *trans;
621	int r;
622	boolean use_staging_texture = FALSE;
623
624	/* We cannot map a tiled texture directly because the data is
625	 * in a different order, therefore we do detiling using a blit.
626	 *
627	 * Also, use a temporary in GTT memory for read transfers, as
628	 * the CPU is much happier reading out of cached system memory
629	 * than uncached VRAM.
630	 */
631	if (R600_TEX_IS_TILED(rtex, level))
632		use_staging_texture = TRUE;
633
634	if ((usage & PIPE_TRANSFER_READ) && u_box_volume(box) > 1024)
635		use_staging_texture = TRUE;
636
637	/* XXX: Use a staging texture for uploads if the underlying BO
638	 * is busy.  No interface for checking that currently? so do
639	 * it eagerly whenever the transfer doesn't require a readback
640	 * and might block.
641	 */
642	if ((usage & PIPE_TRANSFER_WRITE) &&
643			!(usage & (PIPE_TRANSFER_READ |
644					PIPE_TRANSFER_DONTBLOCK |
645					PIPE_TRANSFER_UNSYNCHRONIZED)))
646		use_staging_texture = TRUE;
647
648	if (!permit_hardware_blit(ctx->screen, texture) ||
649		(texture->flags & R600_RESOURCE_FLAG_TRANSFER))
650		use_staging_texture = FALSE;
651
652	if (use_staging_texture && (usage & PIPE_TRANSFER_MAP_DIRECTLY))
653		return NULL;
654
655	trans = CALLOC_STRUCT(r600_transfer);
656	if (trans == NULL)
657		return NULL;
658	pipe_resource_reference(&trans->transfer.resource, texture);
659	trans->transfer.level = level;
660	trans->transfer.usage = usage;
661	trans->transfer.box = *box;
662	if (rtex->depth) {
663		/* XXX: only readback the rectangle which is being mapped?
664		*/
665		/* XXX: when discard is true, no need to read back from depth texture
666		*/
667		r = r600_texture_depth_flush(ctx, texture, FALSE);
668		if (r < 0) {
669			R600_ERR("failed to create temporary texture to hold untiled copy\n");
670			pipe_resource_reference(&trans->transfer.resource, NULL);
671			FREE(trans);
672			return NULL;
673		}
674		trans->transfer.stride = rtex->flushed_depth_texture->pitch_in_bytes[level];
675		trans->offset = r600_texture_get_offset(rtex->flushed_depth_texture, level, box->z);
676		return &trans->transfer;
677	} else if (use_staging_texture) {
678		resource.target = PIPE_TEXTURE_2D;
679		resource.format = texture->format;
680		resource.width0 = box->width;
681		resource.height0 = box->height;
682		resource.depth0 = 1;
683		resource.array_size = 1;
684		resource.last_level = 0;
685		resource.nr_samples = 0;
686		resource.usage = PIPE_USAGE_STAGING;
687		resource.bind = 0;
688		resource.flags = R600_RESOURCE_FLAG_TRANSFER;
689		/* For texture reading, the temporary (detiled) texture is used as
690		 * a render target when blitting from a tiled texture. */
691		if (usage & PIPE_TRANSFER_READ) {
692			resource.bind |= PIPE_BIND_RENDER_TARGET;
693		}
694		/* For texture writing, the temporary texture is used as a sampler
695		 * when blitting into a tiled texture. */
696		if (usage & PIPE_TRANSFER_WRITE) {
697			resource.bind |= PIPE_BIND_SAMPLER_VIEW;
698		}
699		/* Create the temporary texture. */
700		trans->staging_texture = ctx->screen->resource_create(ctx->screen, &resource);
701		if (trans->staging_texture == NULL) {
702			R600_ERR("failed to create temporary texture to hold untiled copy\n");
703			pipe_resource_reference(&trans->transfer.resource, NULL);
704			FREE(trans);
705			return NULL;
706		}
707
708		trans->transfer.stride =
709			((struct r600_resource_texture *)trans->staging_texture)->pitch_in_bytes[0];
710		if (usage & PIPE_TRANSFER_READ) {
711			r600_copy_to_staging_texture(ctx, trans);
712			/* Always referenced in the blit. */
713			r600_flush(ctx, NULL, 0);
714		}
715		return &trans->transfer;
716	}
717	trans->transfer.stride = rtex->pitch_in_bytes[level];
718	trans->transfer.layer_stride = rtex->layer_size[level];
719	trans->offset = r600_texture_get_offset(rtex, level, box->z);
720	return &trans->transfer;
721}
722
723void r600_texture_transfer_destroy(struct pipe_context *ctx,
724				   struct pipe_transfer *transfer)
725{
726	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
727	struct pipe_resource *texture = transfer->resource;
728	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
729
730	if (rtransfer->staging_texture) {
731		if (transfer->usage & PIPE_TRANSFER_WRITE) {
732			r600_copy_from_staging_texture(ctx, rtransfer);
733		}
734		pipe_resource_reference(&rtransfer->staging_texture, NULL);
735	}
736
737	if (rtex->depth && !rtex->is_flushing_texture) {
738		if ((transfer->usage & PIPE_TRANSFER_WRITE) && rtex->flushed_depth_texture)
739			r600_blit_push_depth(ctx, rtex);
740	}
741
742	pipe_resource_reference(&transfer->resource, NULL);
743	FREE(transfer);
744}
745
746void* r600_texture_transfer_map(struct pipe_context *ctx,
747				struct pipe_transfer* transfer)
748{
749	struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
750	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
751	struct r600_bo *bo;
752	enum pipe_format format = transfer->resource->format;
753	struct radeon *radeon = rctx->screen->radeon;
754	unsigned offset = 0;
755	char *map;
756
757	if (rtransfer->staging_texture) {
758		bo = ((struct r600_resource *)rtransfer->staging_texture)->bo;
759	} else {
760		struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
761
762		if (rtex->flushed_depth_texture)
763			bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo;
764		else
765			bo = ((struct r600_resource *)transfer->resource)->bo;
766
767		offset = rtransfer->offset +
768			transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
769			transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
770	}
771
772	if (!(map = r600_bo_map(radeon, bo, rctx->ctx.cs, transfer->usage))) {
773		return NULL;
774	}
775
776	return map + offset;
777}
778
779void r600_texture_transfer_unmap(struct pipe_context *ctx,
780				 struct pipe_transfer* transfer)
781{
782	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
783	struct radeon *radeon = ((struct r600_screen*)ctx->screen)->radeon;
784	struct r600_bo *bo;
785
786	if (rtransfer->staging_texture) {
787		bo = ((struct r600_resource *)rtransfer->staging_texture)->bo;
788	} else {
789		struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
790
791		if (rtex->flushed_depth_texture) {
792			bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo;
793		} else {
794			bo = ((struct r600_resource *)transfer->resource)->bo;
795		}
796	}
797	r600_bo_unmap(radeon, bo);
798}
799
800void r600_init_surface_functions(struct r600_pipe_context *r600)
801{
802	r600->context.create_surface = r600_create_surface;
803	r600->context.surface_destroy = r600_surface_destroy;
804}
805
806static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format,
807		const unsigned char *swizzle_view)
808{
809	unsigned i;
810	unsigned char swizzle[4];
811	unsigned result = 0;
812	const uint32_t swizzle_shift[4] = {
813		16, 19, 22, 25,
814	};
815	const uint32_t swizzle_bit[4] = {
816		0, 1, 2, 3,
817	};
818
819	if (swizzle_view) {
820		util_format_compose_swizzles(swizzle_format, swizzle_view, swizzle);
821	} else {
822		memcpy(swizzle, swizzle_format, 4);
823	}
824
825	/* Get swizzle. */
826	for (i = 0; i < 4; i++) {
827		switch (swizzle[i]) {
828		case UTIL_FORMAT_SWIZZLE_Y:
829			result |= swizzle_bit[1] << swizzle_shift[i];
830			break;
831		case UTIL_FORMAT_SWIZZLE_Z:
832			result |= swizzle_bit[2] << swizzle_shift[i];
833			break;
834		case UTIL_FORMAT_SWIZZLE_W:
835			result |= swizzle_bit[3] << swizzle_shift[i];
836			break;
837		case UTIL_FORMAT_SWIZZLE_0:
838			result |= V_038010_SQ_SEL_0 << swizzle_shift[i];
839			break;
840		case UTIL_FORMAT_SWIZZLE_1:
841			result |= V_038010_SQ_SEL_1 << swizzle_shift[i];
842			break;
843		default: /* UTIL_FORMAT_SWIZZLE_X */
844			result |= swizzle_bit[0] << swizzle_shift[i];
845		}
846	}
847	return result;
848}
849
850/* texture format translate */
851uint32_t r600_translate_texformat(struct pipe_screen *screen,
852				  enum pipe_format format,
853				  const unsigned char *swizzle_view,
854				  uint32_t *word4_p, uint32_t *yuv_format_p)
855{
856	uint32_t result = 0, word4 = 0, yuv_format = 0;
857	const struct util_format_description *desc;
858	boolean uniform = TRUE;
859	static int r600_enable_s3tc = -1;
860
861	int i;
862	const uint32_t sign_bit[4] = {
863		S_038010_FORMAT_COMP_X(V_038010_SQ_FORMAT_COMP_SIGNED),
864		S_038010_FORMAT_COMP_Y(V_038010_SQ_FORMAT_COMP_SIGNED),
865		S_038010_FORMAT_COMP_Z(V_038010_SQ_FORMAT_COMP_SIGNED),
866		S_038010_FORMAT_COMP_W(V_038010_SQ_FORMAT_COMP_SIGNED)
867	};
868	desc = util_format_description(format);
869
870	word4 |= r600_get_swizzle_combined(desc->swizzle, swizzle_view);
871
872	/* Colorspace (return non-RGB formats directly). */
873	switch (desc->colorspace) {
874		/* Depth stencil formats */
875	case UTIL_FORMAT_COLORSPACE_ZS:
876		switch (format) {
877		case PIPE_FORMAT_Z16_UNORM:
878			result = FMT_16;
879			goto out_word4;
880		case PIPE_FORMAT_X24S8_USCALED:
881			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
882		case PIPE_FORMAT_Z24X8_UNORM:
883		case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
884			result = FMT_8_24;
885			goto out_word4;
886		case PIPE_FORMAT_S8X24_USCALED:
887			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
888		case PIPE_FORMAT_X8Z24_UNORM:
889		case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
890			result = FMT_24_8;
891			goto out_word4;
892		case PIPE_FORMAT_S8_USCALED:
893			result = FMT_8;
894			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
895			goto out_word4;
896		case PIPE_FORMAT_Z32_FLOAT:
897			result = FMT_32_FLOAT;
898			goto out_word4;
899		case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
900			result = FMT_X24_8_32_FLOAT;
901			goto out_word4;
902		default:
903			goto out_unknown;
904		}
905
906	case UTIL_FORMAT_COLORSPACE_YUV:
907		yuv_format |= (1 << 30);
908		switch (format) {
909		case PIPE_FORMAT_UYVY:
910		case PIPE_FORMAT_YUYV:
911		default:
912			break;
913		}
914		goto out_unknown; /* TODO */
915
916	case UTIL_FORMAT_COLORSPACE_SRGB:
917		word4 |= S_038010_FORCE_DEGAMMA(1);
918		break;
919
920	default:
921		break;
922	}
923
924	if (r600_enable_s3tc == -1) {
925		struct r600_screen *rscreen = (struct r600_screen *)screen;
926		if (rscreen->info.drm_minor >= 9)
927			r600_enable_s3tc = 1;
928		else
929			r600_enable_s3tc = debug_get_bool_option("R600_ENABLE_S3TC", FALSE);
930	}
931
932	if (desc->layout == UTIL_FORMAT_LAYOUT_RGTC) {
933		if (!r600_enable_s3tc)
934			goto out_unknown;
935
936		switch (format) {
937		case PIPE_FORMAT_RGTC1_SNORM:
938		case PIPE_FORMAT_LATC1_SNORM:
939			word4 |= sign_bit[0];
940		case PIPE_FORMAT_RGTC1_UNORM:
941		case PIPE_FORMAT_LATC1_UNORM:
942			result = FMT_BC4;
943			goto out_word4;
944		case PIPE_FORMAT_RGTC2_SNORM:
945		case PIPE_FORMAT_LATC2_SNORM:
946			word4 |= sign_bit[0] | sign_bit[1];
947		case PIPE_FORMAT_RGTC2_UNORM:
948		case PIPE_FORMAT_LATC2_UNORM:
949			result = FMT_BC5;
950			goto out_word4;
951		default:
952			goto out_unknown;
953		}
954	}
955
956	if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
957
958		if (!r600_enable_s3tc)
959			goto out_unknown;
960
961		if (!util_format_s3tc_enabled) {
962			goto out_unknown;
963		}
964
965		switch (format) {
966		case PIPE_FORMAT_DXT1_RGB:
967		case PIPE_FORMAT_DXT1_RGBA:
968		case PIPE_FORMAT_DXT1_SRGB:
969		case PIPE_FORMAT_DXT1_SRGBA:
970			result = FMT_BC1;
971			goto out_word4;
972		case PIPE_FORMAT_DXT3_RGBA:
973		case PIPE_FORMAT_DXT3_SRGBA:
974			result = FMT_BC2;
975			goto out_word4;
976		case PIPE_FORMAT_DXT5_RGBA:
977		case PIPE_FORMAT_DXT5_SRGBA:
978			result = FMT_BC3;
979			goto out_word4;
980		default:
981			goto out_unknown;
982		}
983	}
984
985	if (format == PIPE_FORMAT_R9G9B9E5_FLOAT) {
986		result = FMT_5_9_9_9_SHAREDEXP;
987		goto out_word4;
988	} else if (format == PIPE_FORMAT_R11G11B10_FLOAT) {
989		result = FMT_10_11_11_FLOAT;
990		goto out_word4;
991	}
992
993
994	for (i = 0; i < desc->nr_channels; i++) {
995		if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) {
996			word4 |= sign_bit[i];
997		}
998	}
999
1000	/* R8G8Bx_SNORM - TODO CxV8U8 */
1001
1002	/* See whether the components are of the same size. */
1003	for (i = 1; i < desc->nr_channels; i++) {
1004		uniform = uniform && desc->channel[0].size == desc->channel[i].size;
1005	}
1006
1007	/* Non-uniform formats. */
1008	if (!uniform) {
1009		switch(desc->nr_channels) {
1010		case 3:
1011			if (desc->channel[0].size == 5 &&
1012			    desc->channel[1].size == 6 &&
1013			    desc->channel[2].size == 5) {
1014				result = FMT_5_6_5;
1015				goto out_word4;
1016			}
1017			goto out_unknown;
1018		case 4:
1019			if (desc->channel[0].size == 5 &&
1020			    desc->channel[1].size == 5 &&
1021			    desc->channel[2].size == 5 &&
1022			    desc->channel[3].size == 1) {
1023				result = FMT_1_5_5_5;
1024				goto out_word4;
1025			}
1026			if (desc->channel[0].size == 10 &&
1027			    desc->channel[1].size == 10 &&
1028			    desc->channel[2].size == 10 &&
1029			    desc->channel[3].size == 2) {
1030				result = FMT_2_10_10_10;
1031				goto out_word4;
1032			}
1033			goto out_unknown;
1034		}
1035		goto out_unknown;
1036	}
1037
1038	/* Find the first non-VOID channel. */
1039	for (i = 0; i < 4; i++) {
1040		if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) {
1041			break;
1042		}
1043	}
1044
1045	if (i == 4)
1046		goto out_unknown;
1047
1048	/* uniform formats */
1049	switch (desc->channel[i].type) {
1050	case UTIL_FORMAT_TYPE_UNSIGNED:
1051	case UTIL_FORMAT_TYPE_SIGNED:
1052#if 0
1053		if (!desc->channel[i].normalized &&
1054		    desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) {
1055			goto out_unknown;
1056		}
1057#endif
1058		if (desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB &&
1059		    !desc->channel[i].normalized)
1060			word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
1061
1062		switch (desc->channel[i].size) {
1063		case 4:
1064			switch (desc->nr_channels) {
1065			case 2:
1066				result = FMT_4_4;
1067				goto out_word4;
1068			case 4:
1069				result = FMT_4_4_4_4;
1070				goto out_word4;
1071			}
1072			goto out_unknown;
1073		case 8:
1074			switch (desc->nr_channels) {
1075			case 1:
1076				result = FMT_8;
1077				goto out_word4;
1078			case 2:
1079				result = FMT_8_8;
1080				goto out_word4;
1081			case 4:
1082				result = FMT_8_8_8_8;
1083				goto out_word4;
1084			}
1085			goto out_unknown;
1086		case 16:
1087			switch (desc->nr_channels) {
1088			case 1:
1089				result = FMT_16;
1090				goto out_word4;
1091			case 2:
1092				result = FMT_16_16;
1093				goto out_word4;
1094			case 4:
1095				result = FMT_16_16_16_16;
1096				goto out_word4;
1097			}
1098			goto out_unknown;
1099		case 32:
1100			switch (desc->nr_channels) {
1101			case 1:
1102				result = FMT_32;
1103				goto out_word4;
1104			case 2:
1105				result = FMT_32_32;
1106				goto out_word4;
1107			case 4:
1108				result = FMT_32_32_32_32;
1109				goto out_word4;
1110			}
1111		}
1112		goto out_unknown;
1113
1114	case UTIL_FORMAT_TYPE_FLOAT:
1115		switch (desc->channel[i].size) {
1116		case 16:
1117			switch (desc->nr_channels) {
1118			case 1:
1119				result = FMT_16_FLOAT;
1120				goto out_word4;
1121			case 2:
1122				result = FMT_16_16_FLOAT;
1123				goto out_word4;
1124			case 4:
1125				result = FMT_16_16_16_16_FLOAT;
1126				goto out_word4;
1127			}
1128			goto out_unknown;
1129		case 32:
1130			switch (desc->nr_channels) {
1131			case 1:
1132				result = FMT_32_FLOAT;
1133				goto out_word4;
1134			case 2:
1135				result = FMT_32_32_FLOAT;
1136				goto out_word4;
1137			case 4:
1138				result = FMT_32_32_32_32_FLOAT;
1139				goto out_word4;
1140			}
1141		}
1142		goto out_unknown;
1143	}
1144
1145out_word4:
1146	if (word4_p)
1147		*word4_p = word4;
1148	if (yuv_format_p)
1149		*yuv_format_p = yuv_format;
1150	return result;
1151out_unknown:
1152	/* R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format)); */
1153	return ~0;
1154}
1155