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