r600_texture.c revision 03c59e4ab16b0ee362f189b549bd13491dba71e4
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 <pipe/p_screen.h>
28#include <util/u_format.h>
29#include <util/u_math.h>
30#include <util/u_inlines.h>
31#include <util/u_memory.h>
32#include "state_tracker/drm_driver.h"
33#include "r600_screen.h"
34#include "r600_context.h"
35#include "r600_resource.h"
36#include "r600d.h"
37
38extern struct u_resource_vtbl r600_texture_vtbl;
39
40static unsigned long r600_texture_get_offset(struct r600_resource_texture *rtex,
41					unsigned level, unsigned zslice,
42					unsigned face)
43{
44	unsigned long offset = rtex->offset[level];
45
46	switch (rtex->resource.base.b.target) {
47	case PIPE_TEXTURE_3D:
48		assert(face == 0);
49		return offset + zslice * rtex->layer_size[level];
50	case PIPE_TEXTURE_CUBE:
51		assert(zslice == 0);
52		return offset + face * rtex->layer_size[level];
53	default:
54		assert(zslice == 0 && face == 0);
55		return offset;
56	}
57}
58
59static void r600_setup_miptree(struct r600_screen *rscreen, struct r600_resource_texture *rtex)
60{
61	struct pipe_resource *ptex = &rtex->resource.base.b;
62	unsigned long w, h, pitch, size, layer_size, i, offset;
63
64	rtex->bpt = util_format_get_blocksize(ptex->format);
65	for (i = 0, offset = 0; i <= ptex->last_level; i++) {
66		w = u_minify(ptex->width0, i);
67		h = u_minify(ptex->height0, i);
68		h = util_next_power_of_two(h);
69		pitch = util_format_get_stride(ptex->format, align(w, 64));
70		pitch = align(pitch, 256);
71		layer_size = pitch * h;
72		if (ptex->target == PIPE_TEXTURE_CUBE)
73			size = layer_size * 6;
74		else
75			size = layer_size * u_minify(ptex->depth0, i);
76		rtex->offset[i] = offset;
77		rtex->layer_size[i] = layer_size;
78		rtex->pitch[i] = pitch;
79		offset += size;
80	}
81	rtex->size = offset;
82}
83
84struct pipe_resource *r600_texture_create(struct pipe_screen *screen,
85						const struct pipe_resource *templ)
86{
87	struct r600_resource_texture *rtex;
88	struct r600_resource *resource;
89	struct r600_screen *rscreen = r600_screen(screen);
90
91	rtex = CALLOC_STRUCT(r600_resource_texture);
92	if (!rtex) {
93		return NULL;
94	}
95	resource = &rtex->resource;
96	resource->base.b = *templ;
97	resource->base.vtbl = &r600_texture_vtbl;
98	pipe_reference_init(&resource->base.b.reference, 1);
99	resource->base.b.screen = screen;
100	r600_setup_miptree(rscreen, rtex);
101
102	/* FIXME alignment 4096 enought ? too much ? */
103	resource->domain = r600_domain_from_usage(resource->base.b.bind);
104	resource->bo = radeon_bo(rscreen->rw, 0, rtex->size, 4096, NULL);
105	if (resource->bo == NULL) {
106		FREE(rtex);
107		return NULL;
108	}
109
110	return &resource->base.b;
111}
112
113static void r600_texture_destroy(struct pipe_screen *screen,
114				 struct pipe_resource *ptex)
115{
116	struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex;
117	struct r600_resource *resource = &rtex->resource;
118	struct r600_screen *rscreen = r600_screen(screen);
119
120	if (resource->bo) {
121		radeon_bo_decref(rscreen->rw, resource->bo);
122	}
123	FREE(rtex);
124}
125
126static struct pipe_surface *r600_get_tex_surface(struct pipe_screen *screen,
127						struct pipe_resource *texture,
128						unsigned face, unsigned level,
129						unsigned zslice, unsigned flags)
130{
131	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
132	struct pipe_surface *surface = CALLOC_STRUCT(pipe_surface);
133	unsigned long offset;
134
135	if (surface == NULL)
136		return NULL;
137	offset = r600_texture_get_offset(rtex, level, zslice, face);
138	pipe_reference_init(&surface->reference, 1);
139	pipe_resource_reference(&surface->texture, texture);
140	surface->format = texture->format;
141	surface->width = u_minify(texture->width0, level);
142	surface->height = u_minify(texture->height0, level);
143	surface->offset = offset;
144	surface->usage = flags;
145	surface->zslice = zslice;
146	surface->texture = texture;
147	surface->face = face;
148	surface->level = level;
149	return surface;
150}
151
152static void r600_tex_surface_destroy(struct pipe_surface *surface)
153{
154	pipe_resource_reference(&surface->texture, NULL);
155	FREE(surface);
156}
157
158struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
159					       const struct pipe_resource *templ,
160					       struct winsys_handle *whandle)
161{
162	struct radeon *rw = (struct radeon*)screen->winsys;
163	struct r600_resource_texture *rtex;
164	struct r600_resource *resource;
165	struct radeon_bo *bo = NULL;
166
167	bo = radeon_bo(rw, whandle->handle, 0, 0, NULL);
168	if (bo == NULL) {
169		return NULL;
170	}
171
172	/* Support only 2D textures without mipmaps */
173	if (templ->target != PIPE_TEXTURE_2D || templ->depth0 != 1 || templ->last_level != 0)
174		return NULL;
175
176	rtex = CALLOC_STRUCT(r600_resource_texture);
177	if (rtex == NULL)
178		return NULL;
179
180	resource = &rtex->resource;
181	resource->base.b = *templ;
182	resource->base.vtbl = &r600_texture_vtbl;
183	pipe_reference_init(&resource->base.b.reference, 1);
184	resource->base.b.screen = screen;
185	resource->bo = bo;
186	rtex->pitch_override = whandle->stride;
187	rtex->bpt = util_format_get_blocksize(templ->format);
188	rtex->pitch[0] = whandle->stride;
189	rtex->offset[0] = 0;
190	rtex->size = align(rtex->pitch[0] * templ->height0, 64);
191
192	return &resource->base.b;
193}
194
195static unsigned int r600_texture_is_referenced(struct pipe_context *context,
196						struct pipe_resource *texture,
197						unsigned face, unsigned level)
198{
199	/* FIXME */
200	return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
201}
202
203struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
204						struct pipe_resource *texture,
205						struct pipe_subresource sr,
206						unsigned usage,
207						const struct pipe_box *box)
208{
209	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
210	struct r600_transfer *trans;
211
212	trans = CALLOC_STRUCT(r600_transfer);
213	if (trans == NULL)
214		return NULL;
215	pipe_resource_reference(&trans->transfer.resource, texture);
216	trans->transfer.sr = sr;
217	trans->transfer.usage = usage;
218	trans->transfer.box = *box;
219	trans->transfer.stride = rtex->pitch[sr.level];
220	trans->offset = r600_texture_get_offset(rtex, sr.level, box->z, sr.face);
221	return &trans->transfer;
222}
223
224void r600_texture_transfer_destroy(struct pipe_context *ctx,
225				   struct pipe_transfer *trans)
226{
227	pipe_resource_reference(&trans->resource, NULL);
228	FREE(trans);
229}
230
231void* r600_texture_transfer_map(struct pipe_context *ctx,
232				struct pipe_transfer* transfer)
233{
234	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
235	struct r600_resource *resource;
236	enum pipe_format format = transfer->resource->format;
237	struct r600_screen *rscreen = r600_screen(ctx->screen);
238	char *map;
239
240	r600_flush(ctx, 0, NULL);
241
242	resource = (struct r600_resource *)transfer->resource;
243	if (radeon_bo_map(rscreen->rw, resource->bo)) {
244		return NULL;
245	}
246	radeon_bo_wait(rscreen->rw, resource->bo);
247
248	map = resource->bo->data;
249
250	return map + rtransfer->offset +
251		transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
252		transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
253}
254
255void r600_texture_transfer_unmap(struct pipe_context *ctx,
256				 struct pipe_transfer* transfer)
257{
258	struct r600_screen *rscreen = r600_screen(ctx->screen);
259	struct r600_resource *resource;
260
261	resource = (struct r600_resource *)transfer->resource;
262	radeon_bo_unmap(rscreen->rw, resource->bo);
263}
264
265struct u_resource_vtbl r600_texture_vtbl =
266{
267	u_default_resource_get_handle,	/* get_handle */
268	r600_texture_destroy,		/* resource_destroy */
269	r600_texture_is_referenced,	/* is_resource_referenced */
270	r600_texture_get_transfer,	/* get_transfer */
271	r600_texture_transfer_destroy,	/* transfer_destroy */
272	r600_texture_transfer_map,	/* transfer_map */
273	u_default_transfer_flush_region,/* transfer_flush_region */
274	r600_texture_transfer_unmap,	/* transfer_unmap */
275	u_default_transfer_inline_write	/* transfer_inline_write */
276};
277
278void r600_init_screen_texture_functions(struct pipe_screen *screen)
279{
280	screen->get_tex_surface = r600_get_tex_surface;
281	screen->tex_surface_destroy = r600_tex_surface_destroy;
282}
283
284static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format,
285					  const unsigned char *swizzle_view)
286{
287    unsigned i;
288    unsigned char swizzle[4];
289    unsigned result = 0;
290    const uint32_t swizzle_shift[4] = {
291	    16, 19, 22, 25,
292    };
293    const uint32_t swizzle_bit[4] = {
294	    0, 1, 2, 3,
295    };
296
297    if (swizzle_view) {
298        /* Combine two sets of swizzles. */
299        for (i = 0; i < 4; i++) {
300            swizzle[i] = swizzle_view[i] <= UTIL_FORMAT_SWIZZLE_W ?
301                         swizzle_format[swizzle_view[i]] : swizzle_view[i];
302        }
303    } else {
304        memcpy(swizzle, swizzle_format, 4);
305    }
306
307    /* Get swizzle. */
308    for (i = 0; i < 4; i++) {
309        switch (swizzle[i]) {
310            case UTIL_FORMAT_SWIZZLE_Y:
311                result |= swizzle_bit[1] << swizzle_shift[i];
312                break;
313            case UTIL_FORMAT_SWIZZLE_Z:
314                result |= swizzle_bit[2] << swizzle_shift[i];
315                break;
316            case UTIL_FORMAT_SWIZZLE_W:
317                result |= swizzle_bit[3] << swizzle_shift[i];
318                break;
319            case UTIL_FORMAT_SWIZZLE_0:
320                result |= V_038010_SQ_SEL_0 << swizzle_shift[i];
321                break;
322            case UTIL_FORMAT_SWIZZLE_1:
323                result |= V_038010_SQ_SEL_1 << swizzle_shift[i];
324                break;
325            default: /* UTIL_FORMAT_SWIZZLE_X */
326                result |= swizzle_bit[0] << swizzle_shift[i];
327        }
328    }
329    return result;
330}
331
332/* texture format translate */
333uint32_t r600_translate_texformat(enum pipe_format format,
334				  const unsigned char *swizzle_view,
335				  uint32_t *word4_p, uint32_t *yuv_format_p)
336{
337	uint32_t result = 0, word4 = 0, yuv_format = 0;
338	const struct util_format_description *desc;
339	boolean uniform = TRUE;
340	int i;
341	const uint32_t sign_bit[4] = {
342		S_038010_FORMAT_COMP_X(V_038010_SQ_FORMAT_COMP_SIGNED),
343		S_038010_FORMAT_COMP_Y(V_038010_SQ_FORMAT_COMP_SIGNED),
344		S_038010_FORMAT_COMP_Z(V_038010_SQ_FORMAT_COMP_SIGNED),
345		S_038010_FORMAT_COMP_W(V_038010_SQ_FORMAT_COMP_SIGNED)
346	};
347	desc = util_format_description(format);
348
349	/* Colorspace (return non-RGB formats directly). */
350	switch (desc->colorspace) {
351		/* Depth stencil formats */
352	case UTIL_FORMAT_COLORSPACE_ZS:
353		switch (format) {
354		case PIPE_FORMAT_Z16_UNORM:
355			result = V_028010_DEPTH_16;
356			goto out_word4;
357		case PIPE_FORMAT_Z24X8_UNORM:
358			result = V_028010_DEPTH_X8_24;
359			goto out_word4;
360		case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
361			result = V_028010_DEPTH_8_24;
362			goto out_word4;
363		default:
364			goto out_unknown;
365		}
366
367	case UTIL_FORMAT_COLORSPACE_YUV:
368		yuv_format |= (1 << 30);
369		switch (format) {
370                case PIPE_FORMAT_UYVY:
371                case PIPE_FORMAT_YUYV:
372		default:
373			break;
374		}
375		goto out_unknown; /* TODO */
376
377	case UTIL_FORMAT_COLORSPACE_SRGB:
378		word4 |= S_038010_FORCE_DEGAMMA(1);
379		if (format == PIPE_FORMAT_L8A8_SRGB || format == PIPE_FORMAT_L8_SRGB)
380			goto out_unknown; /* fails for some reason - TODO */
381		break;
382
383	default:
384		break;
385	}
386
387	word4 |= r600_get_swizzle_combined(desc->swizzle, swizzle_view);
388
389	/* S3TC formats. TODO */
390	if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
391		goto out_unknown;
392	}
393
394
395	for (i = 0; i < desc->nr_channels; i++) {
396		if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) {
397			word4 |= sign_bit[i];
398		}
399	}
400
401	/* R8G8Bx_SNORM - TODO CxV8U8 */
402
403	/* RGTC - TODO */
404
405	/* See whether the components are of the same size. */
406	for (i = 1; i < desc->nr_channels; i++) {
407		uniform = uniform && desc->channel[0].size == desc->channel[i].size;
408	}
409
410	/* Non-uniform formats. */
411	if (!uniform) {
412		switch(desc->nr_channels) {
413		case 3:
414			if (desc->channel[0].size == 5 &&
415			    desc->channel[1].size == 6 &&
416			    desc->channel[2].size == 5) {
417				result |= V_0280A0_COLOR_5_6_5;
418				goto out_word4;
419			}
420			goto out_unknown;
421		case 4:
422			if (desc->channel[0].size == 5 &&
423			    desc->channel[1].size == 5 &&
424			    desc->channel[2].size == 5 &&
425			    desc->channel[3].size == 1) {
426				result |= V_0280A0_COLOR_1_5_5_5;
427				goto out_word4;
428			}
429			if (desc->channel[0].size == 10 &&
430			    desc->channel[1].size == 10 &&
431			    desc->channel[2].size == 10 &&
432			    desc->channel[3].size == 2) {
433				result |= V_0280A0_COLOR_10_10_10_2;
434				goto out_word4;
435			}
436			goto out_unknown;
437		}
438		goto out_unknown;
439	}
440
441	/* uniform formats */
442	switch (desc->channel[0].type) {
443	case UTIL_FORMAT_TYPE_UNSIGNED:
444	case UTIL_FORMAT_TYPE_SIGNED:
445		if (!desc->channel[0].normalized &&
446		    desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) {
447			goto out_unknown;
448		}
449
450		switch (desc->channel[0].size) {
451		case 4:
452			switch (desc->nr_channels) {
453			case 2:
454				result |= V_0280A0_COLOR_4_4;
455				goto out_word4;
456			case 4:
457				result |= V_0280A0_COLOR_4_4_4_4;
458				goto out_word4;
459			}
460			goto out_unknown;
461		case 8:
462			switch (desc->nr_channels) {
463			case 1:
464				result |= V_0280A0_COLOR_8;
465				goto out_word4;
466			case 2:
467				result |= V_0280A0_COLOR_8_8;
468				goto out_word4;
469			case 4:
470				result |= V_0280A0_COLOR_8_8_8_8;
471				goto out_word4;
472			}
473			goto out_unknown;
474		case 16:
475			switch (desc->nr_channels) {
476			case 1:
477				result |= V_0280A0_COLOR_16;
478				goto out_word4;
479			case 2:
480				result |= V_0280A0_COLOR_16_16;
481				goto out_word4;
482			case 4:
483				result |= V_0280A0_COLOR_16_16_16_16;
484				goto out_word4;
485			}
486		}
487		goto out_unknown;
488
489	case UTIL_FORMAT_TYPE_FLOAT:
490		switch (desc->channel[0].size) {
491		case 16:
492			switch (desc->nr_channels) {
493			case 1:
494				result |= V_0280A0_COLOR_16_FLOAT;
495				goto out_word4;
496			case 2:
497				result |= V_0280A0_COLOR_16_16_FLOAT;
498				goto out_word4;
499			case 4:
500				result |= V_0280A0_COLOR_16_16_16_16_FLOAT;
501				goto out_word4;
502			}
503			goto out_unknown;
504		case 32:
505			switch (desc->nr_channels) {
506			case 1:
507				result |= V_0280A0_COLOR_32_FLOAT;
508				goto out_word4;
509			case 2:
510				result |= V_0280A0_COLOR_32_32_FLOAT;
511				goto out_word4;
512			case 4:
513				result |= V_0280A0_COLOR_32_32_32_32_FLOAT;
514				goto out_word4;
515			}
516		}
517
518	}
519out_word4:
520	if (word4_p)
521		*word4_p = word4;
522	if (yuv_format_p)
523		*yuv_format_p = yuv_format;
524//	fprintf(stderr,"returning %08x %08x %08x\n", result, word4, yuv_format);
525	return result;
526out_unknown:
527//	R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format));
528	return ~0;
529}
530