llvmpipe: consolidate texture memory allocation code
[mesa.git] / src / gallium / drivers / llvmpipe / lp_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 <stdio.h>
34
35 #include "pipe/p_context.h"
36 #include "pipe/p_defines.h"
37
38 #include "util/u_inlines.h"
39 #include "util/u_format.h"
40 #include "util/u_math.h"
41 #include "util/u_memory.h"
42 #include "util/u_transfer.h"
43
44 #include "lp_context.h"
45 #include "lp_flush.h"
46 #include "lp_screen.h"
47 #include "lp_tile_image.h"
48 #include "lp_texture.h"
49 #include "lp_setup.h"
50 #include "lp_tile_size.h"
51
52 #include "state_tracker/sw_winsys.h"
53
54
55 static INLINE boolean
56 resource_is_texture(const struct pipe_resource *resource)
57 {
58 const unsigned tex_binds = (PIPE_BIND_DISPLAY_TARGET |
59 PIPE_BIND_SCANOUT |
60 PIPE_BIND_SHARED |
61 PIPE_BIND_DEPTH_STENCIL |
62 PIPE_BIND_SAMPLER_VIEW);
63 const struct llvmpipe_resource *lpr = llvmpipe_resource_const(resource);
64
65 return (lpr->base.bind & tex_binds) ? TRUE : FALSE;
66 }
67
68
69
70 /**
71 * Allocate storage for llvmpipe_texture::layout array.
72 * The number of elements is width_in_tiles * height_in_tiles.
73 */
74 static enum lp_texture_layout *
75 alloc_layout_array(unsigned num_slices, unsigned width, unsigned height)
76 {
77 const unsigned tx = align(width, TILE_SIZE) / TILE_SIZE;
78 const unsigned ty = align(height, TILE_SIZE) / TILE_SIZE;
79
80 assert(num_slices * tx * ty > 0);
81 assert(LP_TEX_LAYOUT_NONE == 0); /* calloc'ing LP_TEX_LAYOUT_NONE here */
82
83 return (enum lp_texture_layout *)
84 calloc(num_slices * tx * ty, sizeof(enum lp_texture_layout));
85 }
86
87
88
89 /**
90 * Conventional allocation path for non-display textures:
91 * Just compute row strides here. Storage is allocated on demand later.
92 */
93 static boolean
94 llvmpipe_texture_layout(struct llvmpipe_screen *screen,
95 struct llvmpipe_resource *lpr)
96 {
97 struct pipe_resource *pt = &lpr->base;
98 unsigned level;
99 unsigned width = pt->width0;
100 unsigned height = pt->height0;
101 unsigned depth = pt->depth0;
102
103 assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
104 assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
105
106 for (level = 0; level <= pt->last_level; level++) {
107 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
108 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
109 unsigned nblocksx, num_slices;
110
111 if (lpr->base.target == PIPE_TEXTURE_CUBE)
112 num_slices = 6;
113 else if (lpr->base.target == PIPE_TEXTURE_3D)
114 num_slices = depth;
115 else
116 num_slices = 1;
117
118 /* Allocate storage for whole quads. This is particularly important
119 * for depth surfaces, which are currently stored in a swizzled format.
120 */
121 nblocksx = util_format_get_nblocksx(pt->format, align(width, TILE_SIZE));
122
123 lpr->row_stride[level] =
124 align(nblocksx * util_format_get_blocksize(pt->format), 16);
125
126 lpr->img_stride[level] = lpr->row_stride[level] * align(height, TILE_SIZE);
127
128 lpr->tiles_per_row[level] = width_t;
129 lpr->tiles_per_image[level] = width_t * height_t;
130 lpr->num_slices_faces[level] = num_slices;
131 lpr->layout[level] = alloc_layout_array(num_slices, width, height);
132
133 width = u_minify(width, 1);
134 height = u_minify(height, 1);
135 depth = u_minify(depth, 1);
136 }
137
138 return TRUE;
139 }
140
141
142
143 static boolean
144 llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
145 struct llvmpipe_resource *lpr)
146 {
147 struct sw_winsys *winsys = screen->winsys;
148
149 /* Round up the surface size to a multiple of the tile size to
150 * avoid tile clipping.
151 */
152 const unsigned width = align(lpr->base.width0, TILE_SIZE);
153 const unsigned height = align(lpr->base.height0, TILE_SIZE);
154 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
155 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
156
157 lpr->tiles_per_row[0] = width_t;
158 lpr->tiles_per_image[0] = width_t * height_t;
159 lpr->num_slices_faces[0] = 1;
160 lpr->img_stride[0] = 0;
161
162 lpr->layout[0] = alloc_layout_array(1, width, height);
163 //lpr->layout[0][0] = LP_TEX_LAYOUT_LINEAR;
164
165 lpr->dt = winsys->displaytarget_create(winsys,
166 lpr->base.bind,
167 lpr->base.format,
168 width, height,
169 16,
170 &lpr->row_stride[0] );
171
172 return lpr->dt != NULL;
173 }
174
175
176 static struct pipe_resource *
177 llvmpipe_resource_create(struct pipe_screen *_screen,
178 const struct pipe_resource *templat)
179 {
180 static unsigned id_counter = 0;
181 struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
182 struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
183 if (!lpr)
184 return NULL;
185
186 lpr->base = *templat;
187 pipe_reference_init(&lpr->base.reference, 1);
188 lpr->base.screen = &screen->base;
189
190 assert(lpr->base.bind);
191
192 if (lpr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
193 PIPE_BIND_SCANOUT |
194 PIPE_BIND_SHARED)) {
195 /* displayable surface */
196 if (!llvmpipe_displaytarget_layout(screen, lpr))
197 goto fail;
198 assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
199 }
200 else if (lpr->base.bind & (PIPE_BIND_SAMPLER_VIEW |
201 PIPE_BIND_DEPTH_STENCIL)) {
202 /* texture map */
203 if (!llvmpipe_texture_layout(screen, lpr))
204 goto fail;
205 assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
206 }
207 else {
208 /* other data (vertex buffer, const buffer, etc) */
209 const enum pipe_format format = templat->format;
210 const uint w = templat->width0 / util_format_get_blockheight(format);
211 const uint h = templat->height0 / util_format_get_blockwidth(format);
212 const uint d = templat->depth0;
213 const uint bpp = util_format_get_blocksize(format);
214 const uint bytes = w * h * d * bpp;
215 lpr->data = align_malloc(bytes, 16);
216 if (!lpr->data)
217 goto fail;
218 }
219
220 if (resource_is_texture(&lpr->base)) {
221 assert(lpr->layout[0]);
222 }
223
224 lpr->id = id_counter++;
225
226 return &lpr->base;
227
228 fail:
229 FREE(lpr);
230 return NULL;
231 }
232
233
234 static void
235 llvmpipe_resource_destroy(struct pipe_screen *pscreen,
236 struct pipe_resource *pt)
237 {
238 struct llvmpipe_screen *screen = llvmpipe_screen(pscreen);
239 struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
240
241 if (lpr->dt) {
242 /* display target */
243 struct sw_winsys *winsys = screen->winsys;
244 winsys->displaytarget_destroy(winsys, lpr->dt);
245 }
246 else if (resource_is_texture(pt)) {
247 /* regular texture */
248 uint level;
249
250 /* free linear image data */
251 for (level = 0; level < Elements(lpr->linear); level++) {
252 if (lpr->linear[level].data) {
253 align_free(lpr->linear[level].data);
254 lpr->linear[level].data = NULL;
255 }
256 }
257
258 /* free tiled image data */
259 for (level = 0; level < Elements(lpr->tiled); level++) {
260 if (lpr->tiled[level].data) {
261 align_free(lpr->tiled[level].data);
262 lpr->tiled[level].data = NULL;
263 }
264 }
265
266 /* free layout flag arrays */
267 for (level = 0; level < Elements(lpr->tiled); level++) {
268 free(lpr->layout[level]);
269 lpr->layout[level] = NULL;
270 }
271 }
272 else if (!lpr->userBuffer) {
273 assert(lpr->data);
274 align_free(lpr->data);
275 }
276
277 FREE(lpr);
278 }
279
280
281 /**
282 * Map a resource for read/write.
283 */
284 void *
285 llvmpipe_resource_map(struct pipe_resource *resource,
286 unsigned face,
287 unsigned level,
288 unsigned zslice,
289 enum lp_texture_usage tex_usage,
290 enum lp_texture_layout layout)
291 {
292 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
293 uint8_t *map;
294
295 assert(face < 6);
296 assert(level < LP_MAX_TEXTURE_LEVELS);
297
298 assert(tex_usage == LP_TEX_USAGE_READ ||
299 tex_usage == LP_TEX_USAGE_READ_WRITE ||
300 tex_usage == LP_TEX_USAGE_WRITE_ALL);
301
302 assert(layout == LP_TEX_LAYOUT_NONE ||
303 layout == LP_TEX_LAYOUT_TILED ||
304 layout == LP_TEX_LAYOUT_LINEAR);
305
306 if (lpr->dt) {
307 /* display target */
308 struct llvmpipe_screen *screen = llvmpipe_screen(resource->screen);
309 struct sw_winsys *winsys = screen->winsys;
310 unsigned dt_usage;
311 uint8_t *map2;
312
313 if (tex_usage == LP_TEX_USAGE_READ) {
314 dt_usage = PIPE_TRANSFER_READ;
315 }
316 else {
317 dt_usage = PIPE_TRANSFER_READ_WRITE;
318 }
319
320 assert(face == 0);
321 assert(level == 0);
322 assert(zslice == 0);
323
324 /* FIXME: keep map count? */
325 map = winsys->displaytarget_map(winsys, lpr->dt, dt_usage);
326
327 /* install this linear image in texture data structure */
328 lpr->linear[level].data = map;
329
330 /* make sure tiled data gets converted to linear data */
331 map2 = llvmpipe_get_texture_image(lpr, 0, 0, tex_usage, layout);
332 if (layout == LP_TEX_LAYOUT_LINEAR)
333 assert(map == map2);
334
335 return map2;
336 }
337 else if (resource_is_texture(resource)) {
338 /* regular texture */
339 if (resource->target != PIPE_TEXTURE_CUBE) {
340 assert(face == 0);
341 }
342 if (resource->target != PIPE_TEXTURE_3D) {
343 assert(zslice == 0);
344 }
345
346 map = llvmpipe_get_texture_image(lpr, face + zslice, level,
347 tex_usage, layout);
348 assert(map);
349 return map;
350 }
351 else {
352 return lpr->data;
353 }
354 }
355
356
357 /**
358 * Unmap a resource.
359 */
360 void
361 llvmpipe_resource_unmap(struct pipe_resource *resource,
362 unsigned face,
363 unsigned level,
364 unsigned zslice)
365 {
366 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
367
368 if (lpr->dt) {
369 /* display target */
370 struct llvmpipe_screen *lp_screen = llvmpipe_screen(resource->screen);
371 struct sw_winsys *winsys = lp_screen->winsys;
372
373 assert(face == 0);
374 assert(level == 0);
375 assert(zslice == 0);
376
377 /* make sure linear image is up to date */
378 (void) llvmpipe_get_texture_image(lpr, face + zslice, level,
379 LP_TEX_USAGE_READ,
380 LP_TEX_LAYOUT_LINEAR);
381
382 winsys->displaytarget_unmap(winsys, lpr->dt);
383 }
384 }
385
386
387 void *
388 llvmpipe_resource_data(struct pipe_resource *resource)
389 {
390 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
391
392 assert((lpr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
393 PIPE_BIND_SCANOUT |
394 PIPE_BIND_SHARED |
395 PIPE_BIND_SAMPLER_VIEW)) == 0);
396
397 return lpr->data;
398 }
399
400
401 static struct pipe_resource *
402 llvmpipe_resource_from_handle(struct pipe_screen *screen,
403 const struct pipe_resource *template,
404 struct winsys_handle *whandle)
405 {
406 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
407 struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
408 if (!lpr)
409 return NULL;
410
411 lpr->base = *template;
412 pipe_reference_init(&lpr->base.reference, 1);
413 lpr->base.screen = screen;
414
415 lpr->dt = winsys->displaytarget_from_handle(winsys,
416 template,
417 whandle,
418 &lpr->row_stride[0]);
419 if (!lpr->dt)
420 goto fail;
421
422 return &lpr->base;
423
424 fail:
425 FREE(lpr);
426 return NULL;
427 }
428
429
430 static boolean
431 llvmpipe_resource_get_handle(struct pipe_screen *screen,
432 struct pipe_resource *pt,
433 struct winsys_handle *whandle)
434 {
435 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
436 struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
437
438 assert(lpr->dt);
439 if (!lpr->dt)
440 return FALSE;
441
442 return winsys->displaytarget_get_handle(winsys, lpr->dt, whandle);
443 }
444
445
446 static struct pipe_surface *
447 llvmpipe_get_tex_surface(struct pipe_screen *screen,
448 struct pipe_resource *pt,
449 unsigned face, unsigned level, unsigned zslice,
450 enum lp_texture_usage usage)
451 {
452 struct pipe_surface *ps;
453
454 assert(level <= pt->last_level);
455
456 ps = CALLOC_STRUCT(pipe_surface);
457 if (ps) {
458 pipe_reference_init(&ps->reference, 1);
459 pipe_resource_reference(&ps->texture, pt);
460 ps->format = pt->format;
461 ps->width = u_minify(pt->width0, level);
462 ps->height = u_minify(pt->height0, level);
463 ps->usage = usage;
464
465 ps->face = face;
466 ps->level = level;
467 ps->zslice = zslice;
468 }
469 return ps;
470 }
471
472
473 static void
474 llvmpipe_tex_surface_destroy(struct pipe_surface *surf)
475 {
476 /* Effectively do the texture_update work here - if texture images
477 * needed post-processing to put them into hardware layout, this is
478 * where it would happen. For llvmpipe, nothing to do.
479 */
480 assert(surf->texture);
481 pipe_resource_reference(&surf->texture, NULL);
482 FREE(surf);
483 }
484
485
486 static struct pipe_transfer *
487 llvmpipe_get_transfer(struct pipe_context *pipe,
488 struct pipe_resource *resource,
489 struct pipe_subresource sr,
490 unsigned usage,
491 const struct pipe_box *box)
492 {
493 struct llvmpipe_resource *lprex = llvmpipe_resource(resource);
494 struct llvmpipe_transfer *lpr;
495
496 assert(resource);
497 assert(sr.level <= resource->last_level);
498
499 lpr = CALLOC_STRUCT(llvmpipe_transfer);
500 if (lpr) {
501 struct pipe_transfer *pt = &lpr->base;
502 pipe_resource_reference(&pt->resource, resource);
503 pt->box = *box;
504 pt->sr = sr;
505 pt->stride = lprex->row_stride[sr.level];
506 pt->usage = usage;
507
508 return pt;
509 }
510 return NULL;
511 }
512
513
514 static void
515 llvmpipe_transfer_destroy(struct pipe_context *pipe,
516 struct pipe_transfer *transfer)
517 {
518 /* Effectively do the texture_update work here - if texture images
519 * needed post-processing to put them into hardware layout, this is
520 * where it would happen. For llvmpipe, nothing to do.
521 */
522 assert (transfer->resource);
523 pipe_resource_reference(&transfer->resource, NULL);
524 FREE(transfer);
525 }
526
527
528 static void *
529 llvmpipe_transfer_map( struct pipe_context *pipe,
530 struct pipe_transfer *transfer )
531 {
532 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
533 ubyte *map;
534 struct llvmpipe_resource *lpr;
535 enum pipe_format format;
536 enum lp_texture_usage tex_usage;
537 const char *mode;
538
539 assert(transfer->sr.face < 6);
540 assert(transfer->sr.level < LP_MAX_TEXTURE_LEVELS);
541
542 /*
543 printf("tex_transfer_map(%d, %d %d x %d of %d x %d, usage %d )\n",
544 transfer->x, transfer->y, transfer->width, transfer->height,
545 transfer->texture->width0,
546 transfer->texture->height0,
547 transfer->usage);
548 */
549
550 if (transfer->usage == PIPE_TRANSFER_READ) {
551 tex_usage = LP_TEX_USAGE_READ;
552 mode = "read";
553 }
554 else {
555 tex_usage = LP_TEX_USAGE_READ_WRITE;
556 mode = "read/write";
557 }
558
559 if (0) {
560 struct llvmpipe_resource *lpr = llvmpipe_resource(transfer->resource);
561 printf("transfer map tex %u mode %s\n", lpr->id, mode);
562 }
563
564
565 assert(transfer->resource);
566 lpr = llvmpipe_resource(transfer->resource);
567 format = lpr->base.format;
568
569 /*
570 * Transfers, like other pipe operations, must happen in order, so flush the
571 * context if necessary.
572 */
573 llvmpipe_flush_texture(pipe,
574 transfer->resource,
575 transfer->sr.face,
576 transfer->sr.level,
577 0, /* flush_flags */
578 !(transfer->usage & PIPE_TRANSFER_WRITE), /* read_only */
579 TRUE, /* cpu_access */
580 FALSE); /* do_not_flush */
581
582 map = llvmpipe_resource_map(transfer->resource,
583 transfer->sr.face,
584 transfer->sr.level,
585 transfer->box.z,
586 tex_usage, LP_TEX_LAYOUT_LINEAR);
587
588
589 /* May want to do different things here depending on read/write nature
590 * of the map:
591 */
592 if (transfer->usage & PIPE_TRANSFER_WRITE) {
593 /* Do something to notify sharing contexts of a texture change.
594 */
595 screen->timestamp++;
596 }
597
598 map +=
599 transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
600 transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
601
602 return map;
603 }
604
605
606 static void
607 llvmpipe_transfer_unmap(struct pipe_context *pipe,
608 struct pipe_transfer *transfer)
609 {
610 assert(transfer->resource);
611
612 llvmpipe_resource_unmap(transfer->resource,
613 transfer->sr.face,
614 transfer->sr.level,
615 transfer->box.z);
616 }
617
618 static unsigned int
619 llvmpipe_is_resource_referenced( struct pipe_context *pipe,
620 struct pipe_resource *presource,
621 unsigned face, unsigned level)
622 {
623 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
624
625 if (presource->target == PIPE_BUFFER)
626 return PIPE_UNREFERENCED;
627
628 return lp_setup_is_resource_referenced(llvmpipe->setup, presource);
629 }
630
631
632
633 /**
634 * Create buffer which wraps user-space data.
635 */
636 static struct pipe_resource *
637 llvmpipe_user_buffer_create(struct pipe_screen *screen,
638 void *ptr,
639 unsigned bytes,
640 unsigned bind_flags)
641 {
642 struct llvmpipe_resource *buffer;
643
644 buffer = CALLOC_STRUCT(llvmpipe_resource);
645 if(!buffer)
646 return NULL;
647
648 pipe_reference_init(&buffer->base.reference, 1);
649 buffer->base.screen = screen;
650 buffer->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
651 buffer->base.bind = bind_flags;
652 buffer->base.usage = PIPE_USAGE_IMMUTABLE;
653 buffer->base.flags = 0;
654 buffer->base.width0 = bytes;
655 buffer->base.height0 = 1;
656 buffer->base.depth0 = 1;
657 buffer->userBuffer = TRUE;
658 buffer->data = ptr;
659
660 return &buffer->base;
661 }
662
663
664 /**
665 * Compute size (in bytes) need to store a texture image / mipmap level,
666 * for just one cube face or one 3D texture slice
667 */
668 static unsigned
669 tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level,
670 enum lp_texture_layout layout)
671 {
672 const unsigned width = u_minify(lpr->base.width0, level);
673 const unsigned height = u_minify(lpr->base.height0, level);
674
675 assert(layout == LP_TEX_LAYOUT_TILED ||
676 layout == LP_TEX_LAYOUT_LINEAR);
677
678 if (layout == LP_TEX_LAYOUT_TILED) {
679 /* for tiled layout, force a 32bpp format */
680 const enum pipe_format format = PIPE_FORMAT_B8G8R8A8_UNORM;
681 const unsigned block_size = util_format_get_blocksize(format);
682 const unsigned nblocksy =
683 util_format_get_nblocksy(format, align(height, TILE_SIZE));
684 const unsigned nblocksx =
685 util_format_get_nblocksx(format, align(width, TILE_SIZE));
686 const unsigned buffer_size = block_size * nblocksy * nblocksx;
687 return buffer_size;
688 }
689 else {
690 const enum pipe_format format = lpr->base.format;
691 const unsigned nblocksy =
692 util_format_get_nblocksy(format, align(height, TILE_SIZE));
693 const unsigned buffer_size = nblocksy * lpr->row_stride[level];
694 return buffer_size;
695 }
696 }
697
698
699 /**
700 * Compute size (in bytes) need to store a texture image / mipmap level,
701 * including all cube faces or 3D image slices
702 */
703 static unsigned
704 tex_image_size(const struct llvmpipe_resource *lpr, unsigned level,
705 enum lp_texture_layout layout)
706 {
707 const unsigned buf_size = tex_image_face_size(lpr, level, layout);
708 return buf_size * lpr->num_slices_faces[level];
709 }
710
711
712 /**
713 * This function encapsulates some complicated logic for determining
714 * how to convert a tile of image data from linear layout to tiled
715 * layout, or vice versa.
716 * \param cur_layout the current tile layout
717 * \param target_layout the desired tile layout
718 * \param usage how the tile will be accessed (R/W vs. read-only, etc)
719 * \param new_layout_return returns the new layout mode
720 * \param convert_return returns TRUE if image conversion is needed
721 */
722 static void
723 layout_logic(enum lp_texture_layout cur_layout,
724 enum lp_texture_layout target_layout,
725 enum lp_texture_usage usage,
726 enum lp_texture_layout *new_layout_return,
727 boolean *convert)
728 {
729 enum lp_texture_layout other_layout, new_layout;
730
731 *convert = FALSE;
732
733 new_layout = 99; /* debug check */
734
735 if (target_layout == LP_TEX_LAYOUT_LINEAR) {
736 other_layout = LP_TEX_LAYOUT_TILED;
737 }
738 else {
739 assert(target_layout == LP_TEX_LAYOUT_TILED);
740 other_layout = LP_TEX_LAYOUT_LINEAR;
741 }
742
743 new_layout = target_layout; /* may get changed below */
744
745 if (cur_layout == LP_TEX_LAYOUT_BOTH) {
746 if (usage == LP_TEX_USAGE_READ) {
747 new_layout = LP_TEX_LAYOUT_BOTH;
748 }
749 }
750 else if (cur_layout == other_layout) {
751 if (usage != LP_TEX_USAGE_WRITE_ALL) {
752 /* need to convert tiled data to linear or vice versa */
753 *convert = TRUE;
754
755 if (usage == LP_TEX_USAGE_READ)
756 new_layout = LP_TEX_LAYOUT_BOTH;
757 }
758 }
759 else {
760 assert(cur_layout == LP_TEX_LAYOUT_NONE ||
761 cur_layout == target_layout);
762 }
763
764 assert(new_layout == LP_TEX_LAYOUT_BOTH ||
765 new_layout == target_layout);
766
767 *new_layout_return = new_layout;
768 }
769
770
771 /**
772 * Return pointer to a 2D texture image/face/slice.
773 * No tiled/linear conversion is done.
774 */
775 ubyte *
776 llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpr,
777 unsigned face_slice, unsigned level,
778 enum lp_texture_layout layout)
779 {
780 struct llvmpipe_texture_image *img;
781 unsigned offset;
782
783 if (layout == LP_TEX_LAYOUT_LINEAR) {
784 img = &lpr->linear[level];
785 }
786 else {
787 assert (layout == LP_TEX_LAYOUT_TILED);
788 img = &lpr->tiled[level];
789 }
790
791 if (face_slice > 0)
792 offset = face_slice * tex_image_face_size(lpr, level, layout);
793 else
794 offset = 0;
795
796 return (ubyte *) img->data + offset;
797 }
798
799
800 static INLINE enum lp_texture_layout
801 llvmpipe_get_texture_tile_layout(const struct llvmpipe_resource *lpr,
802 unsigned face_slice, unsigned level,
803 unsigned x, unsigned y)
804 {
805 uint i;
806 assert(resource_is_texture(&lpr->base));
807 assert(x < lpr->tiles_per_row[level]);
808 i = face_slice * lpr->tiles_per_image[level]
809 + y * lpr->tiles_per_row[level] + x;
810 return lpr->layout[level][i];
811 }
812
813
814 static INLINE void
815 llvmpipe_set_texture_tile_layout(struct llvmpipe_resource *lpr,
816 unsigned face_slice, unsigned level,
817 unsigned x, unsigned y,
818 enum lp_texture_layout layout)
819 {
820 uint i;
821 assert(resource_is_texture(&lpr->base));
822 assert(x < lpr->tiles_per_row[level]);
823 i = face_slice * lpr->tiles_per_image[level]
824 + y * lpr->tiles_per_row[level] + x;
825 lpr->layout[level][i] = layout;
826 }
827
828
829 /**
830 * Set the layout mode for all tiles in a particular image.
831 */
832 static INLINE void
833 llvmpipe_set_texture_image_layout(struct llvmpipe_resource *lpr,
834 unsigned face_slice, unsigned level,
835 unsigned width_t, unsigned height_t,
836 enum lp_texture_layout layout)
837 {
838 const unsigned start = face_slice * lpr->tiles_per_image[level];
839 unsigned i;
840
841 for (i = 0; i < width_t * height_t; i++) {
842 lpr->layout[level][start + i] = layout;
843 }
844 }
845
846
847 /**
848 * Allocate storage for a linear or tile texture image (all cube
849 * faces and all 3D slices.
850 */
851 static void
852 alloc_image_data(struct llvmpipe_resource *lpr, unsigned level,
853 enum lp_texture_layout layout)
854 {
855 if (lpr->dt)
856 assert(level == 0);
857
858 if (layout == LP_TEX_LAYOUT_TILED) {
859 /* tiled data is stored in regular memory */
860 uint buffer_size = tex_image_size(lpr, level, layout);
861 lpr->tiled[level].data = align_malloc(buffer_size, 16);
862 }
863 else {
864 assert(layout == LP_TEX_LAYOUT_LINEAR);
865 if (lpr->dt) {
866 /* we get the linear memory from the winsys */
867 struct llvmpipe_screen *screen = llvmpipe_screen(lpr->base.screen);
868 struct sw_winsys *winsys = screen->winsys;
869
870 lpr->linear[0].data =
871 winsys->displaytarget_map(winsys, lpr->dt,
872 PIPE_TRANSFER_READ_WRITE);
873 }
874 else {
875 /* not a display target - allocate regular memory */
876 uint buffer_size = tex_image_size(lpr, level, LP_TEX_LAYOUT_LINEAR);
877 lpr->linear[level].data = align_malloc(buffer_size, 16);
878 }
879 }
880 }
881
882
883
884 /**
885 * Return pointer to texture image data (either linear or tiled layout)
886 * for a particular cube face or 3D texture slice.
887 *
888 * \param face_slice the cube face or 3D slice of interest
889 * \param usage one of LP_TEX_USAGE_READ/WRITE_ALL/READ_WRITE
890 * \param layout either LP_TEX_LAYOUT_LINEAR or _TILED or _NONE
891 */
892 void *
893 llvmpipe_get_texture_image(struct llvmpipe_resource *lpr,
894 unsigned face_slice, unsigned level,
895 enum lp_texture_usage usage,
896 enum lp_texture_layout layout)
897 {
898 /*
899 * 'target' refers to the image which we're retrieving (either in
900 * tiled or linear layout).
901 * 'other' refers to the same image but in the other layout. (it may
902 * or may not exist.
903 */
904 struct llvmpipe_texture_image *target_img;
905 struct llvmpipe_texture_image *other_img;
906 void *target_data;
907 void *other_data;
908 const unsigned width = u_minify(lpr->base.width0, level);
909 const unsigned height = u_minify(lpr->base.height0, level);
910 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
911 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
912 enum lp_texture_layout other_layout;
913 boolean only_allocate;
914
915 assert(layout == LP_TEX_LAYOUT_NONE ||
916 layout == LP_TEX_LAYOUT_TILED ||
917 layout == LP_TEX_LAYOUT_LINEAR);
918
919 assert(usage == LP_TEX_USAGE_READ ||
920 usage == LP_TEX_USAGE_READ_WRITE ||
921 usage == LP_TEX_USAGE_WRITE_ALL);
922
923 /* check for the special case of layout == LP_TEX_LAYOUT_NONE */
924 if (layout == LP_TEX_LAYOUT_NONE) {
925 only_allocate = TRUE;
926 layout = LP_TEX_LAYOUT_TILED;
927 }
928 else {
929 only_allocate = FALSE;
930 }
931
932 if (lpr->dt) {
933 assert(lpr->linear[level].data);
934 }
935
936 /* which is target? which is other? */
937 if (layout == LP_TEX_LAYOUT_LINEAR) {
938 target_img = &lpr->linear[level];
939 other_img = &lpr->tiled[level];
940 other_layout = LP_TEX_LAYOUT_TILED;
941 }
942 else {
943 target_img = &lpr->tiled[level];
944 other_img = &lpr->linear[level];
945 other_layout = LP_TEX_LAYOUT_LINEAR;
946 }
947
948 target_data = target_img->data;
949 other_data = other_img->data;
950
951 if (!target_data) {
952 /* allocate memory for the target image now */
953 alloc_image_data(lpr, level, layout);
954 target_data = target_img->data;
955 }
956
957 if (face_slice > 0) {
958 unsigned target_offset, other_offset;
959
960 target_offset = face_slice * tex_image_face_size(lpr, level, layout);
961 other_offset = face_slice * tex_image_face_size(lpr, level, other_layout);
962 if (target_data) {
963 target_data = (uint8_t *) target_data + target_offset;
964 }
965 if (other_data) {
966 other_data = (uint8_t *) other_data + other_offset;
967 }
968 }
969
970 if (only_allocate) {
971 /* Just allocating tiled memory. Don't initialize it from the
972 * linear data if it exists.
973 */
974 return target_data;
975 }
976
977 if (other_data) {
978 /* may need to convert other data to the requested layout */
979 enum lp_texture_layout new_layout;
980 unsigned x, y;
981
982 /* loop over all image tiles, doing layout conversion where needed */
983 for (y = 0; y < height_t; y++) {
984 for (x = 0; x < width_t; x++) {
985 enum lp_texture_layout cur_layout =
986 llvmpipe_get_texture_tile_layout(lpr, face_slice, level, x, y);
987 boolean convert;
988
989 layout_logic(cur_layout, layout, usage, &new_layout, &convert);
990
991 if (convert) {
992 if (layout == LP_TEX_LAYOUT_TILED) {
993 lp_linear_to_tiled(other_data, target_data,
994 x * TILE_SIZE, y * TILE_SIZE,
995 TILE_SIZE, TILE_SIZE,
996 lpr->base.format,
997 lpr->row_stride[level]);
998 }
999 else {
1000 lp_tiled_to_linear(other_data, target_data,
1001 x * TILE_SIZE, y * TILE_SIZE,
1002 TILE_SIZE, TILE_SIZE,
1003 lpr->base.format,
1004 lpr->row_stride[level]);
1005 }
1006 }
1007
1008 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, x, y,
1009 new_layout);
1010 }
1011 }
1012 }
1013 else {
1014 /* no other data */
1015 llvmpipe_set_texture_image_layout(lpr, face_slice, level,
1016 width_t, height_t, layout);
1017 }
1018
1019 assert(target_data);
1020
1021 return target_data;
1022 }
1023
1024
1025 /**
1026 * Return pointer to start of a texture image (1D, 2D, 3D, CUBE).
1027 * All cube faces and 3D slices will be converted to the requested
1028 * layout if needed.
1029 * This is typically used when we're about to sample from a texture.
1030 */
1031 void *
1032 llvmpipe_get_texture_image_all(struct llvmpipe_resource *lpr,
1033 unsigned level,
1034 enum lp_texture_usage usage,
1035 enum lp_texture_layout layout)
1036 {
1037 const int slices = lpr->num_slices_faces[level];
1038 int slice;
1039 void *map = NULL;
1040
1041 assert(slices > 0);
1042
1043 for (slice = slices - 1; slice >= 0; slice--) {
1044 map = llvmpipe_get_texture_image(lpr, slice, level, usage, layout);
1045 }
1046
1047 return map;
1048 }
1049
1050
1051 /**
1052 * Get pointer to a linear image (not the tile!) where the tile at (x,y)
1053 * is known to be in linear layout.
1054 * Conversion from tiled to linear will be done if necessary.
1055 * \return pointer to start of image/face (not the tile)
1056 */
1057 ubyte *
1058 llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpr,
1059 unsigned face_slice, unsigned level,
1060 enum lp_texture_usage usage,
1061 unsigned x, unsigned y)
1062 {
1063 struct llvmpipe_texture_image *linear_img = &lpr->linear[level];
1064 enum lp_texture_layout cur_layout, new_layout;
1065 const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
1066 boolean convert;
1067 uint8_t *tiled_image, *linear_image;
1068
1069 assert(resource_is_texture(&lpr->base));
1070 assert(x % TILE_SIZE == 0);
1071 assert(y % TILE_SIZE == 0);
1072
1073 if (!linear_img->data) {
1074 /* allocate memory for the linear image now */
1075 alloc_image_data(lpr, level, LP_TEX_LAYOUT_LINEAR);
1076 }
1077
1078 /* compute address of the slice/face of the image that contains the tile */
1079 tiled_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1080 LP_TEX_LAYOUT_TILED);
1081 linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1082 LP_TEX_LAYOUT_LINEAR);
1083
1084 /* get current tile layout and determine if data conversion is needed */
1085 cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty);
1086
1087 layout_logic(cur_layout, LP_TEX_LAYOUT_LINEAR, usage,
1088 &new_layout, &convert);
1089
1090 if (convert) {
1091 lp_tiled_to_linear(tiled_image, linear_image,
1092 x, y, TILE_SIZE, TILE_SIZE, lpr->base.format,
1093 lpr->row_stride[level]);
1094 }
1095
1096 if (new_layout != cur_layout)
1097 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout);
1098
1099 return linear_image;
1100 }
1101
1102
1103 /**
1104 * Get pointer to tiled data for rendering.
1105 * \return pointer to the tiled data at the given tile position
1106 */
1107 ubyte *
1108 llvmpipe_get_texture_tile(struct llvmpipe_resource *lpr,
1109 unsigned face_slice, unsigned level,
1110 enum lp_texture_usage usage,
1111 unsigned x, unsigned y)
1112 {
1113 struct llvmpipe_texture_image *tiled_img = &lpr->tiled[level];
1114 enum lp_texture_layout cur_layout, new_layout;
1115 const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
1116 boolean convert;
1117 uint8_t *tiled_image, *linear_image;
1118 unsigned tile_offset;
1119
1120 assert(x % TILE_SIZE == 0);
1121 assert(y % TILE_SIZE == 0);
1122
1123 if (!tiled_img->data) {
1124 /* allocate memory for the tiled image now */
1125 alloc_image_data(lpr, level, LP_TEX_LAYOUT_TILED);
1126 }
1127
1128 /* compute address of the slice/face of the image that contains the tile */
1129 tiled_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1130 LP_TEX_LAYOUT_TILED);
1131 linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1132 LP_TEX_LAYOUT_LINEAR);
1133
1134 /* get current tile layout and see if we need to convert the data */
1135 cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty);
1136
1137 layout_logic(cur_layout, LP_TEX_LAYOUT_TILED, usage, &new_layout, &convert);
1138 if (convert) {
1139 lp_linear_to_tiled(linear_image, tiled_image,
1140 x, y, TILE_SIZE, TILE_SIZE, lpr->base.format,
1141 lpr->row_stride[level]);
1142 }
1143
1144 if (new_layout != cur_layout)
1145 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout);
1146
1147 /* compute, return address of the 64x64 tile */
1148 tile_offset = (ty * lpr->tiles_per_row[level] + tx)
1149 * TILE_SIZE * TILE_SIZE * 4;
1150
1151 return (ubyte *) tiled_image + tile_offset;
1152 }
1153
1154
1155 void
1156 llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
1157 {
1158 screen->resource_create = llvmpipe_resource_create;
1159 screen->resource_destroy = llvmpipe_resource_destroy;
1160 screen->resource_from_handle = llvmpipe_resource_from_handle;
1161 screen->resource_get_handle = llvmpipe_resource_get_handle;
1162 screen->user_buffer_create = llvmpipe_user_buffer_create;
1163
1164 screen->get_tex_surface = llvmpipe_get_tex_surface;
1165 screen->tex_surface_destroy = llvmpipe_tex_surface_destroy;
1166 }
1167
1168
1169 void
1170 llvmpipe_init_context_resource_funcs(struct pipe_context *pipe)
1171 {
1172 pipe->get_transfer = llvmpipe_get_transfer;
1173 pipe->transfer_destroy = llvmpipe_transfer_destroy;
1174 pipe->transfer_map = llvmpipe_transfer_map;
1175 pipe->transfer_unmap = llvmpipe_transfer_unmap;
1176 pipe->is_resource_referenced = llvmpipe_is_resource_referenced;
1177
1178 pipe->transfer_flush_region = u_default_transfer_flush_region;
1179 pipe->transfer_inline_write = u_default_transfer_inline_write;
1180 }