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