r600_texture.c revision 7a73390f9126fd270d9891cd9d2bf38ef56d9b80
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		pitch = util_format_get_stride(ptex->format, align(w, 64));
69		layer_size = pitch * h;
70		if (ptex->target == PIPE_TEXTURE_CUBE)
71			size = layer_size * 6;
72		else
73			size = layer_size * u_minify(ptex->depth0, i);
74		rtex->offset[i] = offset;
75		rtex->layer_size[i] = layer_size;
76		rtex->pitch[i] = pitch;
77		offset += size;
78	}
79	rtex->size = offset;
80}
81
82struct pipe_resource *r600_texture_create(struct pipe_screen *screen,
83						const struct pipe_resource *templ)
84{
85	struct r600_resource_texture *rtex;
86	struct r600_resource *resource;
87	struct r600_screen *rscreen = r600_screen(screen);
88
89	rtex = CALLOC_STRUCT(r600_resource_texture);
90	if (!rtex) {
91		return NULL;
92	}
93	resource = &rtex->resource;
94	resource->base.b = *templ;
95	resource->base.vtbl = &r600_texture_vtbl;
96	pipe_reference_init(&resource->base.b.reference, 1);
97	resource->base.b.screen = screen;
98	r600_setup_miptree(rscreen, rtex);
99
100	/* FIXME alignment 4096 enought ? too much ? */
101	resource->domain = r600_domain_from_usage(resource->base.b.bind);
102	resource->bo = radeon_bo(rscreen->rw, 0, rtex->size, 4096, NULL);
103	if (resource->bo == NULL) {
104		FREE(rtex);
105		return NULL;
106	}
107
108	return &resource->base.b;
109}
110
111static void r600_texture_destroy(struct pipe_screen *screen,
112				 struct pipe_resource *ptex)
113{
114	struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex;
115	struct r600_resource *resource = &rtex->resource;
116	struct r600_screen *rscreen = r600_screen(screen);
117
118	if (resource->bo) {
119		radeon_bo_decref(rscreen->rw, resource->bo);
120	}
121	FREE(rtex);
122}
123
124static struct pipe_surface *r600_get_tex_surface(struct pipe_screen *screen,
125						struct pipe_resource *texture,
126						unsigned face, unsigned level,
127						unsigned zslice, unsigned flags)
128{
129	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
130	struct pipe_surface *surface = CALLOC_STRUCT(pipe_surface);
131	unsigned long offset;
132
133	if (surface == NULL)
134		return NULL;
135	offset = r600_texture_get_offset(rtex, level, zslice, face);
136	pipe_reference_init(&surface->reference, 1);
137	pipe_resource_reference(&surface->texture, texture);
138	surface->format = texture->format;
139	surface->width = u_minify(texture->width0, level);
140	surface->height = u_minify(texture->height0, level);
141	surface->offset = offset;
142	surface->usage = flags;
143	surface->zslice = zslice;
144	surface->texture = texture;
145	surface->face = face;
146	surface->level = level;
147	return surface;
148}
149
150static void r600_tex_surface_destroy(struct pipe_surface *surface)
151{
152	pipe_resource_reference(&surface->texture, NULL);
153	FREE(surface);
154}
155
156struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
157					       const struct pipe_resource *templ,
158					       struct winsys_handle *whandle)
159{
160	struct radeon *rw = (struct radeon*)screen->winsys;
161	struct r600_resource_texture *rtex;
162	struct r600_resource *resource;
163	struct radeon_bo *bo = NULL;
164
165	bo = radeon_bo(rw, whandle->handle, 0, 0, NULL);
166	if (bo == NULL) {
167		return NULL;
168	}
169
170	/* Support only 2D textures without mipmaps */
171	if (templ->target != PIPE_TEXTURE_2D || templ->depth0 != 1 || templ->last_level != 0)
172		return NULL;
173
174	rtex = CALLOC_STRUCT(r600_resource_texture);
175	if (rtex == NULL)
176		return NULL;
177
178	resource = &rtex->resource;
179	resource->base.b = *templ;
180	resource->base.vtbl = &r600_texture_vtbl;
181	pipe_reference_init(&resource->base.b.reference, 1);
182	resource->base.b.screen = screen;
183	resource->bo = bo;
184	rtex->pitch_override = whandle->stride;
185	rtex->bpt = util_format_get_blocksize(templ->format);
186	rtex->pitch[0] = whandle->stride;
187	rtex->offset[0] = 0;
188	rtex->size = align(rtex->pitch[0] * templ->height0, 64);
189
190	return &resource->base.b;
191}
192
193static unsigned int r600_texture_is_referenced(struct pipe_context *context,
194						struct pipe_resource *texture,
195						unsigned face, unsigned level)
196{
197	/* FIXME */
198	return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
199}
200
201struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
202						struct pipe_resource *texture,
203						struct pipe_subresource sr,
204						unsigned usage,
205						const struct pipe_box *box)
206{
207	struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
208	struct r600_transfer *trans;
209
210	trans = CALLOC_STRUCT(r600_transfer);
211	if (trans == NULL)
212		return NULL;
213	pipe_resource_reference(&trans->transfer.resource, texture);
214	trans->transfer.sr = sr;
215	trans->transfer.usage = usage;
216	trans->transfer.box = *box;
217	trans->transfer.stride = rtex->pitch[sr.level];
218	trans->offset = r600_texture_get_offset(rtex, sr.level, box->z, sr.face);
219	return &trans->transfer;
220}
221
222void r600_texture_transfer_destroy(struct pipe_context *ctx,
223				   struct pipe_transfer *trans)
224{
225	pipe_resource_reference(&trans->resource, NULL);
226	FREE(trans);
227}
228
229void* r600_texture_transfer_map(struct pipe_context *ctx,
230				struct pipe_transfer* transfer)
231{
232	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
233	struct r600_resource *resource;
234	enum pipe_format format = transfer->resource->format;
235	struct r600_screen *rscreen = r600_screen(ctx->screen);
236	char *map;
237
238	resource = (struct r600_resource *)transfer->resource;
239	if (radeon_bo_map(rscreen->rw, resource->bo)) {
240		return NULL;
241	}
242	map = resource->bo->data;
243
244	return map + rtransfer->offset +
245		transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
246		transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
247}
248
249void r600_texture_transfer_unmap(struct pipe_context *ctx,
250				 struct pipe_transfer* transfer)
251{
252	struct r600_screen *rscreen = r600_screen(ctx->screen);
253	struct r600_resource *resource;
254
255	resource = (struct r600_resource *)transfer->resource;
256	radeon_bo_unmap(rscreen->rw, resource->bo);
257}
258
259struct u_resource_vtbl r600_texture_vtbl =
260{
261	u_default_resource_get_handle,	/* get_handle */
262	r600_texture_destroy,		/* resource_destroy */
263	r600_texture_is_referenced,	/* is_resource_referenced */
264	r600_texture_get_transfer,	/* get_transfer */
265	r600_texture_transfer_destroy,	/* transfer_destroy */
266	r600_texture_transfer_map,	/* transfer_map */
267	u_default_transfer_flush_region,/* transfer_flush_region */
268	r600_texture_transfer_unmap,	/* transfer_unmap */
269	u_default_transfer_inline_write	/* transfer_inline_write */
270};
271
272void r600_init_screen_texture_functions(struct pipe_screen *screen)
273{
274	screen->get_tex_surface = r600_get_tex_surface;
275	screen->tex_surface_destroy = r600_tex_surface_destroy;
276}
277