2daed2022e98081bfdf73c00bb802de87a7a1a03
[mesa.git] / src / gallium / drivers / softpipe / sp_texture.c
1 /**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27 /*
28 * Authors:
29 * Keith Whitwell <keith@tungstengraphics.com>
30 * Michel Dänzer <michel@tungstengraphics.com>
31 */
32
33 #include "pipe/p_defines.h"
34 #include "util/u_inlines.h"
35
36 #include "util/u_format.h"
37 #include "util/u_math.h"
38 #include "util/u_memory.h"
39 #include "util/u_transfer.h"
40
41 #include "sp_context.h"
42 #include "sp_flush.h"
43 #include "sp_texture.h"
44 #include "sp_screen.h"
45
46 #include "state_tracker/sw_winsys.h"
47
48
49 /**
50 * Conventional allocation path for non-display textures:
51 * Use a simple, maximally packed layout.
52 */
53 static boolean
54 softpipe_resource_layout(struct pipe_screen *screen,
55 struct softpipe_resource *spr)
56 {
57 struct pipe_resource *pt = &spr->base;
58 unsigned level;
59 unsigned width = pt->width0;
60 unsigned height = pt->height0;
61 unsigned depth = pt->depth0;
62 unsigned buffer_size = 0;
63
64 for (level = 0; level <= pt->last_level; level++) {
65 spr->stride[level] = util_format_get_stride(pt->format, width);
66
67 spr->level_offset[level] = buffer_size;
68
69 buffer_size += (util_format_get_nblocksy(pt->format, height) *
70 ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) *
71 spr->stride[level]);
72
73 width = u_minify(width, 1);
74 height = u_minify(height, 1);
75 depth = u_minify(depth, 1);
76 }
77
78 spr->data = align_malloc(buffer_size, 16);
79
80 return spr->data != NULL;
81 }
82
83
84 /**
85 * Texture layout for simple color buffers.
86 */
87 static boolean
88 softpipe_displaytarget_layout(struct pipe_screen *screen,
89 struct softpipe_resource *spr)
90 {
91 struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
92
93 /* Round up the surface size to a multiple of the tile size?
94 */
95 spr->dt = winsys->displaytarget_create(winsys,
96 spr->base.bind,
97 spr->base.format,
98 spr->base.width0,
99 spr->base.height0,
100 16,
101 &spr->stride[0] );
102
103 return spr->dt != NULL;
104 }
105
106
107 /**
108 * Create new pipe_resource given the template information.
109 */
110 static struct pipe_resource *
111 softpipe_resource_create(struct pipe_screen *screen,
112 const struct pipe_resource *templat)
113 {
114 struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
115 if (!spr)
116 return NULL;
117
118 assert(templat->format != PIPE_FORMAT_NONE);
119
120 spr->base = *templat;
121 pipe_reference_init(&spr->base.reference, 1);
122 spr->base.screen = screen;
123
124 spr->pot = (util_is_power_of_two(templat->width0) &&
125 util_is_power_of_two(templat->height0) &&
126 util_is_power_of_two(templat->depth0));
127
128 if (spr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
129 PIPE_BIND_SCANOUT |
130 PIPE_BIND_SHARED)) {
131 if (!softpipe_displaytarget_layout(screen, spr))
132 goto fail;
133 }
134 else {
135 if (!softpipe_resource_layout(screen, spr))
136 goto fail;
137 }
138
139 return &spr->base;
140
141 fail:
142 FREE(spr);
143 return NULL;
144 }
145
146
147 static void
148 softpipe_resource_destroy(struct pipe_screen *pscreen,
149 struct pipe_resource *pt)
150 {
151 struct softpipe_screen *screen = softpipe_screen(pscreen);
152 struct softpipe_resource *spr = softpipe_resource(pt);
153
154 if (spr->dt) {
155 /* display target */
156 struct sw_winsys *winsys = screen->winsys;
157 winsys->displaytarget_destroy(winsys, spr->dt);
158 }
159 else if (!spr->userBuffer) {
160 /* regular texture */
161 align_free(spr->data);
162 }
163
164 FREE(spr);
165 }
166
167
168 static struct pipe_resource *
169 softpipe_resource_from_handle(struct pipe_screen *screen,
170 const struct pipe_resource *templat,
171 struct winsys_handle *whandle)
172 {
173 struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
174 struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
175 if (!spr)
176 return NULL;
177
178 spr->base = *templat;
179 pipe_reference_init(&spr->base.reference, 1);
180 spr->base.screen = screen;
181
182 spr->pot = (util_is_power_of_two(templat->width0) &&
183 util_is_power_of_two(templat->height0) &&
184 util_is_power_of_two(templat->depth0));
185
186 spr->dt = winsys->displaytarget_from_handle(winsys,
187 templat,
188 whandle,
189 &spr->stride[0]);
190 if (!spr->dt)
191 goto fail;
192
193 return &spr->base;
194
195 fail:
196 FREE(spr);
197 return NULL;
198 }
199
200
201 static boolean
202 softpipe_resource_get_handle(struct pipe_screen *screen,
203 struct pipe_resource *pt,
204 struct winsys_handle *whandle)
205 {
206 struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
207 struct softpipe_resource *spr = softpipe_resource(pt);
208
209 assert(spr->dt);
210 if (!spr->dt)
211 return FALSE;
212
213 return winsys->displaytarget_get_handle(winsys, spr->dt, whandle);
214 }
215
216
217 /**
218 * Helper function to compute offset (in bytes) for a particular
219 * texture level/face/slice from the start of the buffer.
220 */
221 static unsigned
222 sp_get_tex_image_offset(const struct softpipe_resource *spr,
223 unsigned level, unsigned layer)
224 {
225 const unsigned hgt = u_minify(spr->base.height0, level);
226 const unsigned nblocksy = util_format_get_nblocksy(spr->base.format, hgt);
227 unsigned offset = spr->level_offset[level];
228
229 if (spr->base.target == PIPE_TEXTURE_CUBE ||
230 spr->base.target == PIPE_TEXTURE_3D ||
231 spr->base.target == PIPE_TEXTURE_2D_ARRAY) {
232 offset += layer * nblocksy * spr->stride[level];
233 }
234 else if (spr->base.target == PIPE_TEXTURE_1D_ARRAY) {
235 offset += layer * spr->stride[level];
236 }
237 else {
238 assert(layer == 0);
239 }
240
241 return offset;
242 }
243
244
245 /**
246 * Get a pipe_surface "view" into a texture resource.
247 */
248 static struct pipe_surface *
249 softpipe_create_surface(struct pipe_context *pipe,
250 struct pipe_resource *pt,
251 const struct pipe_surface *surf_tmpl)
252 {
253 struct pipe_surface *ps;
254 unsigned level = surf_tmpl->u.tex.level;
255
256 assert(level <= pt->last_level);
257 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
258
259 ps = CALLOC_STRUCT(pipe_surface);
260 if (ps) {
261 pipe_reference_init(&ps->reference, 1);
262 pipe_resource_reference(&ps->texture, pt);
263 ps->context = pipe;
264 ps->format = surf_tmpl->format;
265 ps->width = u_minify(pt->width0, level);
266 ps->height = u_minify(pt->height0, level);
267 ps->usage = surf_tmpl->usage;
268
269 ps->u.tex.level = level;
270 ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
271 ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
272 }
273 return ps;
274 }
275
276
277 /**
278 * Free a pipe_surface which was created with softpipe_create_surface().
279 */
280 static void
281 softpipe_surface_destroy(struct pipe_context *pipe,
282 struct pipe_surface *surf)
283 {
284 /* Effectively do the texture_update work here - if texture images
285 * needed post-processing to put them into hardware layout, this is
286 * where it would happen. For softpipe, nothing to do.
287 */
288 assert(surf->texture);
289 pipe_resource_reference(&surf->texture, NULL);
290 FREE(surf);
291 }
292
293
294 /**
295 * Geta pipe_transfer object which is used for moving data in/out of
296 * a resource object.
297 * \param pipe rendering context
298 * \param resource the resource to transfer in/out of
299 * \param sr indicates cube face or 3D texture slice
300 * \param usage bitmask of PIPE_TRANSFER_x flags
301 * \param box the 1D/2D/3D region of interest
302 */
303 static struct pipe_transfer *
304 softpipe_get_transfer(struct pipe_context *pipe,
305 struct pipe_resource *resource,
306 unsigned level,
307 unsigned usage,
308 const struct pipe_box *box)
309 {
310 struct softpipe_resource *spr = softpipe_resource(resource);
311 struct softpipe_transfer *spt;
312
313 assert(resource);
314 assert(level <= resource->last_level);
315
316 /* make sure the requested region is in the image bounds */
317 assert(box->x + box->width <= u_minify(resource->width0, level));
318 assert(box->y + box->height <= u_minify(resource->height0, level));
319 assert(box->z + box->depth <= (u_minify(resource->depth0, level) + resource->array_size - 1));
320
321 /*
322 * Transfers, like other pipe operations, must happen in order, so flush the
323 * context if necessary.
324 */
325 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
326 boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
327 boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
328 if (!softpipe_flush_resource(pipe, resource,
329 level, box->depth > 1 ? -1 : box->z,
330 0, /* flush_flags */
331 read_only,
332 TRUE, /* cpu_access */
333 do_not_block)) {
334 /*
335 * It would have blocked, but state tracker requested no to.
336 */
337 assert(do_not_block);
338 return NULL;
339 }
340 }
341
342 spt = CALLOC_STRUCT(softpipe_transfer);
343 if (spt) {
344 struct pipe_transfer *pt = &spt->base;
345 enum pipe_format format = resource->format;
346 const unsigned hgt = u_minify(spr->base.height0, level);
347 const unsigned nblocksy = util_format_get_nblocksy(format, hgt);
348
349 pipe_resource_reference(&pt->resource, resource);
350 pt->level = level;
351 pt->usage = usage;
352 pt->box = *box;
353 pt->stride = spr->stride[level];
354 pt->layer_stride = pt->stride * nblocksy;
355
356 spt->offset = sp_get_tex_image_offset(spr, level, box->z);
357
358 spt->offset +=
359 box->y / util_format_get_blockheight(format) * spt->base.stride +
360 box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
361
362 return pt;
363 }
364 return NULL;
365 }
366
367
368 /**
369 * Free a pipe_transfer object which was created with
370 * softpipe_get_transfer().
371 */
372 static void
373 softpipe_transfer_destroy(struct pipe_context *pipe,
374 struct pipe_transfer *transfer)
375 {
376 pipe_resource_reference(&transfer->resource, NULL);
377 FREE(transfer);
378 }
379
380
381 /**
382 * Create memory mapping for given pipe_transfer object.
383 */
384 static void *
385 softpipe_transfer_map(struct pipe_context *pipe,
386 struct pipe_transfer *transfer)
387 {
388 struct softpipe_transfer *spt = softpipe_transfer(transfer);
389 struct softpipe_resource *spr = softpipe_resource(transfer->resource);
390 struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
391 uint8_t *map;
392
393 /* resources backed by display target treated specially:
394 */
395 if (spr->dt) {
396 map = winsys->displaytarget_map(winsys, spr->dt, transfer->usage);
397 }
398 else {
399 map = spr->data;
400 }
401
402 if (map == NULL)
403 return NULL;
404 else
405 return map + spt->offset;
406 }
407
408
409 /**
410 * Unmap memory mapping for given pipe_transfer object.
411 */
412 static void
413 softpipe_transfer_unmap(struct pipe_context *pipe,
414 struct pipe_transfer *transfer)
415 {
416 struct softpipe_resource *spr;
417
418 assert(transfer->resource);
419 spr = softpipe_resource(transfer->resource);
420
421 if (spr->dt) {
422 /* display target */
423 struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
424 winsys->displaytarget_unmap(winsys, spr->dt);
425 }
426
427 if (transfer->usage & PIPE_TRANSFER_WRITE) {
428 /* Mark the texture as dirty to expire the tile caches. */
429 spr->timestamp++;
430 }
431 }
432
433 /**
434 * Create buffer which wraps user-space data.
435 */
436 static struct pipe_resource *
437 softpipe_user_buffer_create(struct pipe_screen *screen,
438 void *ptr,
439 unsigned bytes,
440 unsigned bind_flags)
441 {
442 struct softpipe_resource *spr;
443
444 spr = CALLOC_STRUCT(softpipe_resource);
445 if (!spr)
446 return NULL;
447
448 pipe_reference_init(&spr->base.reference, 1);
449 spr->base.screen = screen;
450 spr->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
451 spr->base.bind = bind_flags;
452 spr->base.usage = PIPE_USAGE_IMMUTABLE;
453 spr->base.flags = 0;
454 spr->base.width0 = bytes;
455 spr->base.height0 = 1;
456 spr->base.depth0 = 1;
457 spr->base.array_size = 1;
458 spr->userBuffer = TRUE;
459 spr->data = ptr;
460
461 return &spr->base;
462 }
463
464
465 void
466 softpipe_init_texture_funcs(struct pipe_context *pipe)
467 {
468 pipe->get_transfer = softpipe_get_transfer;
469 pipe->transfer_destroy = softpipe_transfer_destroy;
470 pipe->transfer_map = softpipe_transfer_map;
471 pipe->transfer_unmap = softpipe_transfer_unmap;
472
473 pipe->transfer_flush_region = u_default_transfer_flush_region;
474 pipe->transfer_inline_write = u_default_transfer_inline_write;
475
476 pipe->create_surface = softpipe_create_surface;
477 pipe->surface_destroy = softpipe_surface_destroy;
478 }
479
480
481 void
482 softpipe_init_screen_texture_funcs(struct pipe_screen *screen)
483 {
484 screen->resource_create = softpipe_resource_create;
485 screen->resource_destroy = softpipe_resource_destroy;
486 screen->resource_from_handle = softpipe_resource_from_handle;
487 screen->resource_get_handle = softpipe_resource_get_handle;
488 screen->user_buffer_create = softpipe_user_buffer_create;
489
490 }