llvmpipe: Fix resource_is_texture.
[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 switch (resource->target) {
59 case PIPE_BUFFER:
60 return FALSE;
61 case PIPE_TEXTURE_1D:
62 case PIPE_TEXTURE_2D:
63 case PIPE_TEXTURE_3D:
64 case PIPE_TEXTURE_CUBE:
65 return TRUE;
66 default:
67 assert(0);
68 return FALSE;
69 }
70 }
71
72
73
74 /**
75 * Allocate storage for llvmpipe_texture::layout array.
76 * The number of elements is width_in_tiles * height_in_tiles.
77 */
78 static enum lp_texture_layout *
79 alloc_layout_array(unsigned num_slices, unsigned width, unsigned height)
80 {
81 const unsigned tx = align(width, TILE_SIZE) / TILE_SIZE;
82 const unsigned ty = align(height, TILE_SIZE) / TILE_SIZE;
83
84 assert(num_slices * tx * ty > 0);
85 assert(LP_TEX_LAYOUT_NONE == 0); /* calloc'ing LP_TEX_LAYOUT_NONE here */
86
87 return (enum lp_texture_layout *)
88 calloc(num_slices * tx * ty, sizeof(enum lp_texture_layout));
89 }
90
91
92
93 /**
94 * Conventional allocation path for non-display textures:
95 * Just compute row strides here. Storage is allocated on demand later.
96 */
97 static boolean
98 llvmpipe_texture_layout(struct llvmpipe_screen *screen,
99 struct llvmpipe_resource *lpr)
100 {
101 struct pipe_resource *pt = &lpr->base;
102 unsigned level;
103 unsigned width = pt->width0;
104 unsigned height = pt->height0;
105 unsigned depth = pt->depth0;
106
107 assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
108 assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
109
110 for (level = 0; level <= pt->last_level; level++) {
111 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
112 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
113 unsigned nblocksx, num_slices;
114
115 if (lpr->base.target == PIPE_TEXTURE_CUBE)
116 num_slices = 6;
117 else if (lpr->base.target == PIPE_TEXTURE_3D)
118 num_slices = depth;
119 else
120 num_slices = 1;
121
122 /* Allocate storage for whole quads. This is particularly important
123 * for depth surfaces, which are currently stored in a swizzled format.
124 */
125 nblocksx = util_format_get_nblocksx(pt->format, align(width, TILE_SIZE));
126
127 lpr->row_stride[level] =
128 align(nblocksx * util_format_get_blocksize(pt->format), 16);
129
130 lpr->img_stride[level] = lpr->row_stride[level] * align(height, TILE_SIZE);
131
132 lpr->tiles_per_row[level] = width_t;
133 lpr->tiles_per_image[level] = width_t * height_t;
134 lpr->num_slices_faces[level] = num_slices;
135 lpr->layout[level] = alloc_layout_array(num_slices, width, height);
136
137 width = u_minify(width, 1);
138 height = u_minify(height, 1);
139 depth = u_minify(depth, 1);
140 }
141
142 return TRUE;
143 }
144
145
146
147 static boolean
148 llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
149 struct llvmpipe_resource *lpr)
150 {
151 struct sw_winsys *winsys = screen->winsys;
152
153 /* Round up the surface size to a multiple of the tile size to
154 * avoid tile clipping.
155 */
156 const unsigned width = align(lpr->base.width0, TILE_SIZE);
157 const unsigned height = align(lpr->base.height0, TILE_SIZE);
158 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
159 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
160
161 lpr->tiles_per_row[0] = width_t;
162 lpr->tiles_per_image[0] = width_t * height_t;
163 lpr->num_slices_faces[0] = 1;
164 lpr->img_stride[0] = 0;
165
166 lpr->layout[0] = alloc_layout_array(1, width, height);
167 //lpr->layout[0][0] = LP_TEX_LAYOUT_LINEAR;
168
169 lpr->dt = winsys->displaytarget_create(winsys,
170 lpr->base.bind,
171 lpr->base.format,
172 width, height,
173 16,
174 &lpr->row_stride[0] );
175
176 return lpr->dt != NULL;
177 }
178
179
180 static struct pipe_resource *
181 llvmpipe_resource_create(struct pipe_screen *_screen,
182 const struct pipe_resource *templat)
183 {
184 static unsigned id_counter = 0;
185 struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
186 struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
187 if (!lpr)
188 return NULL;
189
190 lpr->base = *templat;
191 pipe_reference_init(&lpr->base.reference, 1);
192 lpr->base.screen = &screen->base;
193
194 assert(lpr->base.bind);
195
196 if (lpr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
197 PIPE_BIND_SCANOUT |
198 PIPE_BIND_SHARED)) {
199 /* displayable surface */
200 if (!llvmpipe_displaytarget_layout(screen, lpr))
201 goto fail;
202 assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
203 }
204 else if (lpr->base.bind & (PIPE_BIND_SAMPLER_VIEW |
205 PIPE_BIND_DEPTH_STENCIL)) {
206 /* texture map */
207 if (!llvmpipe_texture_layout(screen, lpr))
208 goto fail;
209 assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
210 }
211 else {
212 /* other data (vertex buffer, const buffer, etc) */
213 const enum pipe_format format = templat->format;
214 const uint w = templat->width0 / util_format_get_blockheight(format);
215 const uint h = templat->height0 / util_format_get_blockwidth(format);
216 const uint d = templat->depth0;
217 const uint bpp = util_format_get_blocksize(format);
218 const uint bytes = w * h * d * bpp;
219 lpr->data = align_malloc(bytes, 16);
220 if (!lpr->data)
221 goto fail;
222 }
223
224 if (resource_is_texture(&lpr->base)) {
225 assert(lpr->layout[0]);
226 }
227
228 lpr->id = id_counter++;
229
230 return &lpr->base;
231
232 fail:
233 FREE(lpr);
234 return NULL;
235 }
236
237
238 static void
239 llvmpipe_resource_destroy(struct pipe_screen *pscreen,
240 struct pipe_resource *pt)
241 {
242 struct llvmpipe_screen *screen = llvmpipe_screen(pscreen);
243 struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
244
245 if (lpr->dt) {
246 /* display target */
247 struct sw_winsys *winsys = screen->winsys;
248 winsys->displaytarget_destroy(winsys, lpr->dt);
249 }
250 else if (resource_is_texture(pt)) {
251 /* regular texture */
252 uint level;
253
254 /* free linear image data */
255 for (level = 0; level < Elements(lpr->linear); level++) {
256 if (lpr->linear[level].data) {
257 align_free(lpr->linear[level].data);
258 lpr->linear[level].data = NULL;
259 }
260 }
261
262 /* free tiled image data */
263 for (level = 0; level < Elements(lpr->tiled); level++) {
264 if (lpr->tiled[level].data) {
265 align_free(lpr->tiled[level].data);
266 lpr->tiled[level].data = NULL;
267 }
268 }
269
270 /* free layout flag arrays */
271 for (level = 0; level < Elements(lpr->tiled); level++) {
272 free(lpr->layout[level]);
273 lpr->layout[level] = NULL;
274 }
275 }
276 else if (!lpr->userBuffer) {
277 assert(lpr->data);
278 align_free(lpr->data);
279 }
280
281 FREE(lpr);
282 }
283
284
285 /**
286 * Map a resource for read/write.
287 */
288 void *
289 llvmpipe_resource_map(struct pipe_resource *resource,
290 unsigned face,
291 unsigned level,
292 unsigned zslice,
293 enum lp_texture_usage tex_usage,
294 enum lp_texture_layout layout)
295 {
296 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
297 uint8_t *map;
298
299 assert(face < 6);
300 assert(level < LP_MAX_TEXTURE_LEVELS);
301
302 assert(tex_usage == LP_TEX_USAGE_READ ||
303 tex_usage == LP_TEX_USAGE_READ_WRITE ||
304 tex_usage == LP_TEX_USAGE_WRITE_ALL);
305
306 assert(layout == LP_TEX_LAYOUT_NONE ||
307 layout == LP_TEX_LAYOUT_TILED ||
308 layout == LP_TEX_LAYOUT_LINEAR);
309
310 if (lpr->dt) {
311 /* display target */
312 struct llvmpipe_screen *screen = llvmpipe_screen(resource->screen);
313 struct sw_winsys *winsys = screen->winsys;
314 unsigned dt_usage;
315 uint8_t *map2;
316
317 if (tex_usage == LP_TEX_USAGE_READ) {
318 dt_usage = PIPE_TRANSFER_READ;
319 }
320 else {
321 dt_usage = PIPE_TRANSFER_READ_WRITE;
322 }
323
324 assert(face == 0);
325 assert(level == 0);
326 assert(zslice == 0);
327
328 /* FIXME: keep map count? */
329 map = winsys->displaytarget_map(winsys, lpr->dt, dt_usage);
330
331 /* install this linear image in texture data structure */
332 lpr->linear[level].data = map;
333
334 /* make sure tiled data gets converted to linear data */
335 map2 = llvmpipe_get_texture_image(lpr, 0, 0, tex_usage, layout);
336 if (layout == LP_TEX_LAYOUT_LINEAR)
337 assert(map == map2);
338
339 return map2;
340 }
341 else if (resource_is_texture(resource)) {
342 /* regular texture */
343 if (resource->target != PIPE_TEXTURE_CUBE) {
344 assert(face == 0);
345 }
346 if (resource->target != PIPE_TEXTURE_3D) {
347 assert(zslice == 0);
348 }
349
350 map = llvmpipe_get_texture_image(lpr, face + zslice, level,
351 tex_usage, layout);
352 assert(map);
353 return map;
354 }
355 else {
356 return lpr->data;
357 }
358 }
359
360
361 /**
362 * Unmap a resource.
363 */
364 void
365 llvmpipe_resource_unmap(struct pipe_resource *resource,
366 unsigned face,
367 unsigned level,
368 unsigned zslice)
369 {
370 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
371
372 if (lpr->dt) {
373 /* display target */
374 struct llvmpipe_screen *lp_screen = llvmpipe_screen(resource->screen);
375 struct sw_winsys *winsys = lp_screen->winsys;
376
377 assert(face == 0);
378 assert(level == 0);
379 assert(zslice == 0);
380
381 /* make sure linear image is up to date */
382 (void) llvmpipe_get_texture_image(lpr, face + zslice, level,
383 LP_TEX_USAGE_READ,
384 LP_TEX_LAYOUT_LINEAR);
385
386 winsys->displaytarget_unmap(winsys, lpr->dt);
387 }
388 }
389
390
391 void *
392 llvmpipe_resource_data(struct pipe_resource *resource)
393 {
394 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
395
396 assert((lpr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
397 PIPE_BIND_SCANOUT |
398 PIPE_BIND_SHARED |
399 PIPE_BIND_SAMPLER_VIEW)) == 0);
400
401 return lpr->data;
402 }
403
404
405 static struct pipe_resource *
406 llvmpipe_resource_from_handle(struct pipe_screen *screen,
407 const struct pipe_resource *template,
408 struct winsys_handle *whandle)
409 {
410 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
411 struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
412 if (!lpr)
413 return NULL;
414
415 lpr->base = *template;
416 pipe_reference_init(&lpr->base.reference, 1);
417 lpr->base.screen = screen;
418
419 lpr->dt = winsys->displaytarget_from_handle(winsys,
420 template,
421 whandle,
422 &lpr->row_stride[0]);
423 if (!lpr->dt)
424 goto fail;
425
426 return &lpr->base;
427
428 fail:
429 FREE(lpr);
430 return NULL;
431 }
432
433
434 static boolean
435 llvmpipe_resource_get_handle(struct pipe_screen *screen,
436 struct pipe_resource *pt,
437 struct winsys_handle *whandle)
438 {
439 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
440 struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
441
442 assert(lpr->dt);
443 if (!lpr->dt)
444 return FALSE;
445
446 return winsys->displaytarget_get_handle(winsys, lpr->dt, whandle);
447 }
448
449
450 static struct pipe_surface *
451 llvmpipe_get_tex_surface(struct pipe_screen *screen,
452 struct pipe_resource *pt,
453 unsigned face, unsigned level, unsigned zslice,
454 enum lp_texture_usage usage)
455 {
456 struct pipe_surface *ps;
457
458 assert(level <= pt->last_level);
459
460 ps = CALLOC_STRUCT(pipe_surface);
461 if (ps) {
462 pipe_reference_init(&ps->reference, 1);
463 pipe_resource_reference(&ps->texture, pt);
464 ps->format = pt->format;
465 ps->width = u_minify(pt->width0, level);
466 ps->height = u_minify(pt->height0, level);
467 ps->usage = usage;
468
469 ps->face = face;
470 ps->level = level;
471 ps->zslice = zslice;
472 }
473 return ps;
474 }
475
476
477 static void
478 llvmpipe_tex_surface_destroy(struct pipe_surface *surf)
479 {
480 /* Effectively do the texture_update work here - if texture images
481 * needed post-processing to put them into hardware layout, this is
482 * where it would happen. For llvmpipe, nothing to do.
483 */
484 assert(surf->texture);
485 pipe_resource_reference(&surf->texture, NULL);
486 FREE(surf);
487 }
488
489
490 static struct pipe_transfer *
491 llvmpipe_get_transfer(struct pipe_context *pipe,
492 struct pipe_resource *resource,
493 struct pipe_subresource sr,
494 unsigned usage,
495 const struct pipe_box *box)
496 {
497 struct llvmpipe_resource *lprex = llvmpipe_resource(resource);
498 struct llvmpipe_transfer *lpr;
499
500 assert(resource);
501 assert(sr.level <= resource->last_level);
502
503 lpr = CALLOC_STRUCT(llvmpipe_transfer);
504 if (lpr) {
505 struct pipe_transfer *pt = &lpr->base;
506 pipe_resource_reference(&pt->resource, resource);
507 pt->box = *box;
508 pt->sr = sr;
509 pt->stride = lprex->row_stride[sr.level];
510 pt->usage = usage;
511
512 return pt;
513 }
514 return NULL;
515 }
516
517
518 static void
519 llvmpipe_transfer_destroy(struct pipe_context *pipe,
520 struct pipe_transfer *transfer)
521 {
522 /* Effectively do the texture_update work here - if texture images
523 * needed post-processing to put them into hardware layout, this is
524 * where it would happen. For llvmpipe, nothing to do.
525 */
526 assert (transfer->resource);
527 pipe_resource_reference(&transfer->resource, NULL);
528 FREE(transfer);
529 }
530
531
532 static void *
533 llvmpipe_transfer_map( struct pipe_context *pipe,
534 struct pipe_transfer *transfer )
535 {
536 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
537 ubyte *map;
538 struct llvmpipe_resource *lpr;
539 enum pipe_format format;
540 enum lp_texture_usage tex_usage;
541 const char *mode;
542
543 assert(transfer->sr.face < 6);
544 assert(transfer->sr.level < LP_MAX_TEXTURE_LEVELS);
545
546 /*
547 printf("tex_transfer_map(%d, %d %d x %d of %d x %d, usage %d )\n",
548 transfer->x, transfer->y, transfer->width, transfer->height,
549 transfer->texture->width0,
550 transfer->texture->height0,
551 transfer->usage);
552 */
553
554 if (transfer->usage == PIPE_TRANSFER_READ) {
555 tex_usage = LP_TEX_USAGE_READ;
556 mode = "read";
557 }
558 else {
559 tex_usage = LP_TEX_USAGE_READ_WRITE;
560 mode = "read/write";
561 }
562
563 if (0) {
564 struct llvmpipe_resource *lpr = llvmpipe_resource(transfer->resource);
565 printf("transfer map tex %u mode %s\n", lpr->id, mode);
566 }
567
568
569 assert(transfer->resource);
570 lpr = llvmpipe_resource(transfer->resource);
571 format = lpr->base.format;
572
573 /*
574 * Transfers, like other pipe operations, must happen in order, so flush the
575 * context if necessary.
576 */
577 llvmpipe_flush_texture(pipe,
578 transfer->resource,
579 transfer->sr.face,
580 transfer->sr.level,
581 0, /* flush_flags */
582 !(transfer->usage & PIPE_TRANSFER_WRITE), /* read_only */
583 TRUE, /* cpu_access */
584 FALSE); /* do_not_flush */
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 }
1003 else {
1004 lp_tiled_to_linear(other_data, target_data,
1005 x * TILE_SIZE, y * TILE_SIZE,
1006 TILE_SIZE, TILE_SIZE,
1007 lpr->base.format,
1008 lpr->row_stride[level]);
1009 }
1010 }
1011
1012 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, x, y,
1013 new_layout);
1014 }
1015 }
1016 }
1017 else {
1018 /* no other data */
1019 llvmpipe_set_texture_image_layout(lpr, face_slice, level,
1020 width_t, height_t, layout);
1021 }
1022
1023 assert(target_data);
1024
1025 return target_data;
1026 }
1027
1028
1029 /**
1030 * Return pointer to start of a texture image (1D, 2D, 3D, CUBE).
1031 * All cube faces and 3D slices will be converted to the requested
1032 * layout if needed.
1033 * This is typically used when we're about to sample from a texture.
1034 */
1035 void *
1036 llvmpipe_get_texture_image_all(struct llvmpipe_resource *lpr,
1037 unsigned level,
1038 enum lp_texture_usage usage,
1039 enum lp_texture_layout layout)
1040 {
1041 const int slices = lpr->num_slices_faces[level];
1042 int slice;
1043 void *map = NULL;
1044
1045 assert(slices > 0);
1046
1047 for (slice = slices - 1; slice >= 0; slice--) {
1048 map = llvmpipe_get_texture_image(lpr, slice, level, usage, layout);
1049 }
1050
1051 return map;
1052 }
1053
1054
1055 /**
1056 * Get pointer to a linear image (not the tile!) where the tile at (x,y)
1057 * is known to be in linear layout.
1058 * Conversion from tiled to linear will be done if necessary.
1059 * \return pointer to start of image/face (not the tile)
1060 */
1061 ubyte *
1062 llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpr,
1063 unsigned face_slice, unsigned level,
1064 enum lp_texture_usage usage,
1065 unsigned x, unsigned y)
1066 {
1067 struct llvmpipe_texture_image *linear_img = &lpr->linear[level];
1068 enum lp_texture_layout cur_layout, new_layout;
1069 const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
1070 boolean convert;
1071 uint8_t *tiled_image, *linear_image;
1072
1073 assert(resource_is_texture(&lpr->base));
1074 assert(x % TILE_SIZE == 0);
1075 assert(y % TILE_SIZE == 0);
1076
1077 if (!linear_img->data) {
1078 /* allocate memory for the linear image now */
1079 alloc_image_data(lpr, level, LP_TEX_LAYOUT_LINEAR);
1080 }
1081
1082 /* compute address of the slice/face of the image that contains the tile */
1083 tiled_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1084 LP_TEX_LAYOUT_TILED);
1085 linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1086 LP_TEX_LAYOUT_LINEAR);
1087
1088 /* get current tile layout and determine if data conversion is needed */
1089 cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty);
1090
1091 layout_logic(cur_layout, LP_TEX_LAYOUT_LINEAR, usage,
1092 &new_layout, &convert);
1093
1094 if (convert) {
1095 lp_tiled_to_linear(tiled_image, linear_image,
1096 x, y, TILE_SIZE, TILE_SIZE, lpr->base.format,
1097 lpr->row_stride[level]);
1098 }
1099
1100 if (new_layout != cur_layout)
1101 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout);
1102
1103 return linear_image;
1104 }
1105
1106
1107 /**
1108 * Get pointer to tiled data for rendering.
1109 * \return pointer to the tiled data at the given tile position
1110 */
1111 ubyte *
1112 llvmpipe_get_texture_tile(struct llvmpipe_resource *lpr,
1113 unsigned face_slice, unsigned level,
1114 enum lp_texture_usage usage,
1115 unsigned x, unsigned y)
1116 {
1117 struct llvmpipe_texture_image *tiled_img = &lpr->tiled[level];
1118 enum lp_texture_layout cur_layout, new_layout;
1119 const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
1120 boolean convert;
1121 uint8_t *tiled_image, *linear_image;
1122 unsigned tile_offset;
1123
1124 assert(x % TILE_SIZE == 0);
1125 assert(y % TILE_SIZE == 0);
1126
1127 if (!tiled_img->data) {
1128 /* allocate memory for the tiled image now */
1129 alloc_image_data(lpr, level, LP_TEX_LAYOUT_TILED);
1130 }
1131
1132 /* compute address of the slice/face of the image that contains the tile */
1133 tiled_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1134 LP_TEX_LAYOUT_TILED);
1135 linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1136 LP_TEX_LAYOUT_LINEAR);
1137
1138 /* get current tile layout and see if we need to convert the data */
1139 cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty);
1140
1141 layout_logic(cur_layout, LP_TEX_LAYOUT_TILED, usage, &new_layout, &convert);
1142 if (convert) {
1143 lp_linear_to_tiled(linear_image, tiled_image,
1144 x, y, TILE_SIZE, TILE_SIZE, lpr->base.format,
1145 lpr->row_stride[level]);
1146 }
1147
1148 if (new_layout != cur_layout)
1149 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout);
1150
1151 /* compute, return address of the 64x64 tile */
1152 tile_offset = (ty * lpr->tiles_per_row[level] + tx)
1153 * TILE_SIZE * TILE_SIZE * 4;
1154
1155 return (ubyte *) tiled_image + tile_offset;
1156 }
1157
1158
1159 void
1160 llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
1161 {
1162 screen->resource_create = llvmpipe_resource_create;
1163 screen->resource_destroy = llvmpipe_resource_destroy;
1164 screen->resource_from_handle = llvmpipe_resource_from_handle;
1165 screen->resource_get_handle = llvmpipe_resource_get_handle;
1166 screen->user_buffer_create = llvmpipe_user_buffer_create;
1167
1168 screen->get_tex_surface = llvmpipe_get_tex_surface;
1169 screen->tex_surface_destroy = llvmpipe_tex_surface_destroy;
1170 }
1171
1172
1173 void
1174 llvmpipe_init_context_resource_funcs(struct pipe_context *pipe)
1175 {
1176 pipe->get_transfer = llvmpipe_get_transfer;
1177 pipe->transfer_destroy = llvmpipe_transfer_destroy;
1178 pipe->transfer_map = llvmpipe_transfer_map;
1179 pipe->transfer_unmap = llvmpipe_transfer_unmap;
1180 pipe->is_resource_referenced = llvmpipe_is_resource_referenced;
1181
1182 pipe->transfer_flush_region = u_default_transfer_flush_region;
1183 pipe->transfer_inline_write = u_default_transfer_inline_write;
1184 }