llvmpipe: integrate memory allocation into llvmpipe_texture_layout
[mesa.git] / src / gallium / drivers / llvmpipe / lp_texture.c
1 /**************************************************************************
2 *
3 * Copyright 2006 VMware, Inc.
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 VMWARE 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 <keithw@vmware.com>
30 * Michel Dänzer <daenzer@vmware.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_cpu_detect.h"
40 #include "util/u_format.h"
41 #include "util/u_math.h"
42 #include "util/u_memory.h"
43 #include "util/u_simple_list.h"
44 #include "util/u_transfer.h"
45
46 #include "lp_context.h"
47 #include "lp_flush.h"
48 #include "lp_screen.h"
49 #include "lp_texture.h"
50 #include "lp_setup.h"
51 #include "lp_state.h"
52 #include "lp_rast.h"
53
54 #include "state_tracker/sw_winsys.h"
55
56
57 #ifdef DEBUG
58 static struct llvmpipe_resource resource_list;
59 #endif
60 static unsigned id_counter = 0;
61
62
63 /**
64 * Conventional allocation path for non-display textures:
65 * Compute strides and allocate data (unless asked not to).
66 */
67 static boolean
68 llvmpipe_texture_layout(struct llvmpipe_screen *screen,
69 struct llvmpipe_resource *lpr,
70 boolean allocate)
71 {
72 struct pipe_resource *pt = &lpr->base;
73 unsigned level;
74 unsigned width = pt->width0;
75 unsigned height = pt->height0;
76 unsigned depth = pt->depth0;
77 uint64_t total_size = 0;
78 unsigned layers = pt->array_size;
79 /* XXX:
80 * This alignment here (same for displaytarget) was added for the purpose of
81 * ARB_map_buffer_alignment. I am not convinced it's needed for non-buffer
82 * resources. Otherwise we'd want the max of cacheline size and 16 (max size
83 * of a block for all formats) though this should not be strictly necessary
84 * neither. In any case it can only affect compressed or 1d textures.
85 */
86 unsigned mip_align = MAX2(64, util_cpu_caps.cacheline);
87
88 assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
89 assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
90
91 for (level = 0; level <= pt->last_level; level++) {
92 uint64_t mipsize;
93
94 /* Row stride and image stride */
95 {
96 unsigned align_x, align_y, nblocksx, nblocksy, block_size;
97
98 /* For non-compressed formats we need 4x4 pixel alignment
99 * so we can read/write LP_RASTER_BLOCK_SIZE when rendering to them.
100 * We also want cache line size in x direction,
101 * otherwise same cache line could end up in multiple threads.
102 * For explicit 1d resources however we reduce this to 4x1 and
103 * handle specially in render output code (as we need to do special
104 * handling there for buffers in any case).
105 */
106 if (util_format_is_compressed(pt->format))
107 align_x = align_y = 1;
108 else {
109 align_x = LP_RASTER_BLOCK_SIZE;
110 if (llvmpipe_resource_is_1d(&lpr->base))
111 align_y = 1;
112 else
113 align_y = LP_RASTER_BLOCK_SIZE;
114 }
115
116 nblocksx = util_format_get_nblocksx(pt->format,
117 align(width, align_x));
118 nblocksy = util_format_get_nblocksy(pt->format,
119 align(height, align_y));
120 block_size = util_format_get_blocksize(pt->format);
121
122 if (util_format_is_compressed(pt->format))
123 lpr->row_stride[level] = nblocksx * block_size;
124 else
125 lpr->row_stride[level] = align(nblocksx * block_size, util_cpu_caps.cacheline);
126
127 /* if row_stride * height > LP_MAX_TEXTURE_SIZE */
128 if ((uint64_t)lpr->row_stride[level] * nblocksy > LP_MAX_TEXTURE_SIZE) {
129 /* image too large */
130 goto fail;
131 }
132
133 lpr->img_stride[level] = lpr->row_stride[level] * nblocksy;
134 }
135
136 /* Number of 3D image slices, cube faces or texture array layers */
137 {
138 unsigned num_slices;
139
140 if (lpr->base.target == PIPE_TEXTURE_CUBE)
141 num_slices = 6;
142 else if (lpr->base.target == PIPE_TEXTURE_3D)
143 num_slices = depth;
144 else if (lpr->base.target == PIPE_TEXTURE_1D_ARRAY ||
145 lpr->base.target == PIPE_TEXTURE_2D_ARRAY)
146 num_slices = layers;
147 else
148 num_slices = 1;
149
150 lpr->num_slices_faces[level] = num_slices;
151 }
152
153 /* if img_stride * num_slices_faces > LP_MAX_TEXTURE_SIZE */
154 mipsize = (uint64_t)lpr->num_slices_faces[level] * lpr->img_stride[level];
155 if (mipsize > LP_MAX_TEXTURE_SIZE) {
156 /* volume too large */
157 goto fail;
158 }
159
160 lpr->mip_offsets[level] = total_size;
161
162 total_size += align((unsigned)mipsize, mip_align);
163 if (total_size > LP_MAX_TEXTURE_SIZE) {
164 goto fail;
165 }
166
167 /* Compute size of next mipmap level */
168 width = u_minify(width, 1);
169 height = u_minify(height, 1);
170 depth = u_minify(depth, 1);
171 }
172
173 if (allocate) {
174 lpr->tex_data = align_malloc(total_size, mip_align);
175 if (!lpr->tex_data) {
176 return FALSE;
177 }
178 else {
179 memset(lpr->tex_data, 0, total_size);
180 }
181 }
182
183 return TRUE;
184
185 fail:
186 return FALSE;
187 }
188
189
190 /**
191 * Check the size of the texture specified by 'res'.
192 * \return TRUE if OK, FALSE if too large.
193 */
194 static boolean
195 llvmpipe_can_create_resource(struct pipe_screen *screen,
196 const struct pipe_resource *res)
197 {
198 struct llvmpipe_resource lpr;
199 memset(&lpr, 0, sizeof(lpr));
200 lpr.base = *res;
201 return llvmpipe_texture_layout(llvmpipe_screen(screen), &lpr, false);
202 }
203
204
205 static boolean
206 llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
207 struct llvmpipe_resource *lpr)
208 {
209 struct sw_winsys *winsys = screen->winsys;
210
211 /* Round up the surface size to a multiple of the tile size to
212 * avoid tile clipping.
213 */
214 const unsigned width = MAX2(1, align(lpr->base.width0, TILE_SIZE));
215 const unsigned height = MAX2(1, align(lpr->base.height0, TILE_SIZE));
216
217 lpr->num_slices_faces[0] = 1;
218 lpr->img_stride[0] = 0;
219
220 lpr->dt = winsys->displaytarget_create(winsys,
221 lpr->base.bind,
222 lpr->base.format,
223 width, height,
224 64,
225 &lpr->row_stride[0] );
226
227 if (lpr->dt == NULL)
228 return FALSE;
229
230 {
231 void *map = winsys->displaytarget_map(winsys, lpr->dt,
232 PIPE_TRANSFER_WRITE);
233
234 if (map)
235 memset(map, 0, height * lpr->row_stride[0]);
236
237 winsys->displaytarget_unmap(winsys, lpr->dt);
238 }
239
240 return TRUE;
241 }
242
243
244 static struct pipe_resource *
245 llvmpipe_resource_create(struct pipe_screen *_screen,
246 const struct pipe_resource *templat)
247 {
248 struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
249 struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
250 if (!lpr)
251 return NULL;
252
253 lpr->base = *templat;
254 pipe_reference_init(&lpr->base.reference, 1);
255 lpr->base.screen = &screen->base;
256
257 /* assert(lpr->base.bind); */
258
259 if (llvmpipe_resource_is_texture(&lpr->base)) {
260 if (lpr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
261 PIPE_BIND_SCANOUT |
262 PIPE_BIND_SHARED)) {
263 /* displayable surface */
264 if (!llvmpipe_displaytarget_layout(screen, lpr))
265 goto fail;
266 }
267 else {
268 /* texture map */
269 if (!llvmpipe_texture_layout(screen, lpr, true))
270 goto fail;
271 }
272 }
273 else {
274 /* other data (vertex buffer, const buffer, etc) */
275 const uint bytes = templat->width0;
276 assert(util_format_get_blocksize(templat->format) == 1);
277 assert(templat->height0 == 1);
278 assert(templat->depth0 == 1);
279 assert(templat->last_level == 0);
280 /*
281 * Reserve some extra storage since if we'd render to a buffer we
282 * read/write always LP_RASTER_BLOCK_SIZE pixels, but the element
283 * offset doesn't need to be aligned to LP_RASTER_BLOCK_SIZE.
284 */
285 lpr->data = align_malloc(bytes + (LP_RASTER_BLOCK_SIZE - 1) * 4 * sizeof(float), 64);
286 /*
287 * buffers don't really have stride but it's probably safer
288 * (for code doing same calculations for buffers and textures)
289 * to put something sane in there.
290 */
291 lpr->row_stride[0] = bytes;
292 if (!lpr->data)
293 goto fail;
294 memset(lpr->data, 0, bytes);
295 }
296
297 lpr->id = id_counter++;
298
299 #ifdef DEBUG
300 insert_at_tail(&resource_list, lpr);
301 #endif
302
303 return &lpr->base;
304
305 fail:
306 FREE(lpr);
307 return NULL;
308 }
309
310
311 static void
312 llvmpipe_resource_destroy(struct pipe_screen *pscreen,
313 struct pipe_resource *pt)
314 {
315 struct llvmpipe_screen *screen = llvmpipe_screen(pscreen);
316 struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
317
318 if (lpr->dt) {
319 /* display target */
320 struct sw_winsys *winsys = screen->winsys;
321 winsys->displaytarget_destroy(winsys, lpr->dt);
322 }
323 else if (llvmpipe_resource_is_texture(pt)) {
324 /* free linear image data */
325 if (lpr->tex_data) {
326 align_free(lpr->tex_data);
327 lpr->tex_data = NULL;
328 }
329 }
330 else if (!lpr->userBuffer) {
331 assert(lpr->data);
332 align_free(lpr->data);
333 }
334
335 #ifdef DEBUG
336 if (lpr->next)
337 remove_from_list(lpr);
338 #endif
339
340 FREE(lpr);
341 }
342
343
344 /**
345 * Map a resource for read/write.
346 */
347 void *
348 llvmpipe_resource_map(struct pipe_resource *resource,
349 unsigned level,
350 unsigned layer,
351 enum lp_texture_usage tex_usage)
352 {
353 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
354 uint8_t *map;
355
356 assert(level < LP_MAX_TEXTURE_LEVELS);
357 assert(layer < (u_minify(resource->depth0, level) + resource->array_size - 1));
358
359 assert(tex_usage == LP_TEX_USAGE_READ ||
360 tex_usage == LP_TEX_USAGE_READ_WRITE ||
361 tex_usage == LP_TEX_USAGE_WRITE_ALL);
362
363 if (lpr->dt) {
364 /* display target */
365 struct llvmpipe_screen *screen = llvmpipe_screen(resource->screen);
366 struct sw_winsys *winsys = screen->winsys;
367 unsigned dt_usage;
368
369 if (tex_usage == LP_TEX_USAGE_READ) {
370 dt_usage = PIPE_TRANSFER_READ;
371 }
372 else {
373 dt_usage = PIPE_TRANSFER_READ_WRITE;
374 }
375
376 assert(level == 0);
377 assert(layer == 0);
378
379 /* FIXME: keep map count? */
380 map = winsys->displaytarget_map(winsys, lpr->dt, dt_usage);
381
382 /* install this linear image in texture data structure */
383 lpr->tex_data = map;
384
385 return map;
386 }
387 else if (llvmpipe_resource_is_texture(resource)) {
388
389 map = llvmpipe_get_texture_image_address(lpr, layer, level);
390 return map;
391 }
392 else {
393 return lpr->data;
394 }
395 }
396
397
398 /**
399 * Unmap a resource.
400 */
401 void
402 llvmpipe_resource_unmap(struct pipe_resource *resource,
403 unsigned level,
404 unsigned layer)
405 {
406 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
407
408 if (lpr->dt) {
409 /* display target */
410 struct llvmpipe_screen *lp_screen = llvmpipe_screen(resource->screen);
411 struct sw_winsys *winsys = lp_screen->winsys;
412
413 assert(level == 0);
414 assert(layer == 0);
415
416 winsys->displaytarget_unmap(winsys, lpr->dt);
417 }
418 }
419
420
421 void *
422 llvmpipe_resource_data(struct pipe_resource *resource)
423 {
424 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
425
426 assert(!llvmpipe_resource_is_texture(resource));
427
428 return lpr->data;
429 }
430
431
432 static struct pipe_resource *
433 llvmpipe_resource_from_handle(struct pipe_screen *screen,
434 const struct pipe_resource *template,
435 struct winsys_handle *whandle)
436 {
437 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
438 struct llvmpipe_resource *lpr;
439
440 /* XXX Seems like from_handled depth textures doesn't work that well */
441
442 lpr = CALLOC_STRUCT(llvmpipe_resource);
443 if (!lpr) {
444 goto no_lpr;
445 }
446
447 lpr->base = *template;
448 pipe_reference_init(&lpr->base.reference, 1);
449 lpr->base.screen = screen;
450
451 /*
452 * Looks like unaligned displaytargets work just fine,
453 * at least sampler/render ones.
454 */
455 #if 0
456 assert(lpr->base.width0 == width);
457 assert(lpr->base.height0 == height);
458 #endif
459
460 lpr->num_slices_faces[0] = 1;
461 lpr->img_stride[0] = 0;
462
463 lpr->dt = winsys->displaytarget_from_handle(winsys,
464 template,
465 whandle,
466 &lpr->row_stride[0]);
467 if (!lpr->dt) {
468 goto no_dt;
469 }
470
471 lpr->id = id_counter++;
472
473 #ifdef DEBUG
474 insert_at_tail(&resource_list, lpr);
475 #endif
476
477 return &lpr->base;
478
479 no_dt:
480 FREE(lpr);
481 no_lpr:
482 return NULL;
483 }
484
485
486 static boolean
487 llvmpipe_resource_get_handle(struct pipe_screen *screen,
488 struct pipe_resource *pt,
489 struct winsys_handle *whandle)
490 {
491 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
492 struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
493
494 assert(lpr->dt);
495 if (!lpr->dt)
496 return FALSE;
497
498 return winsys->displaytarget_get_handle(winsys, lpr->dt, whandle);
499 }
500
501
502 static void *
503 llvmpipe_transfer_map( struct pipe_context *pipe,
504 struct pipe_resource *resource,
505 unsigned level,
506 unsigned usage,
507 const struct pipe_box *box,
508 struct pipe_transfer **transfer )
509 {
510 struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
511 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
512 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
513 struct llvmpipe_transfer *lpt;
514 struct pipe_transfer *pt;
515 ubyte *map;
516 enum pipe_format format;
517 enum lp_texture_usage tex_usage;
518 const char *mode;
519
520 assert(resource);
521 assert(level <= resource->last_level);
522
523 /*
524 * Transfers, like other pipe operations, must happen in order, so flush the
525 * context if necessary.
526 */
527 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
528 boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
529 boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
530 if (!llvmpipe_flush_resource(pipe, resource,
531 level,
532 read_only,
533 TRUE, /* cpu_access */
534 do_not_block,
535 __FUNCTION__)) {
536 /*
537 * It would have blocked, but state tracker requested no to.
538 */
539 assert(do_not_block);
540 return NULL;
541 }
542 }
543
544 /* Check if we're mapping the current constant buffer */
545 if ((usage & PIPE_TRANSFER_WRITE) &&
546 (resource->bind & PIPE_BIND_CONSTANT_BUFFER)) {
547 unsigned i;
548 for (i = 0; i < Elements(llvmpipe->constants[PIPE_SHADER_FRAGMENT]); ++i) {
549 if (resource == llvmpipe->constants[PIPE_SHADER_FRAGMENT][i].buffer) {
550 /* constants may have changed */
551 llvmpipe->dirty |= LP_NEW_CONSTANTS;
552 break;
553 }
554 }
555 }
556
557 lpt = CALLOC_STRUCT(llvmpipe_transfer);
558 if (!lpt)
559 return NULL;
560 pt = &lpt->base;
561 pipe_resource_reference(&pt->resource, resource);
562 pt->box = *box;
563 pt->level = level;
564 pt->stride = lpr->row_stride[level];
565 pt->layer_stride = lpr->img_stride[level];
566 pt->usage = usage;
567 *transfer = pt;
568
569 assert(level < LP_MAX_TEXTURE_LEVELS);
570
571 /*
572 printf("tex_transfer_map(%d, %d %d x %d of %d x %d, usage %d )\n",
573 transfer->x, transfer->y, transfer->width, transfer->height,
574 transfer->texture->width0,
575 transfer->texture->height0,
576 transfer->usage);
577 */
578
579 if (usage == PIPE_TRANSFER_READ) {
580 tex_usage = LP_TEX_USAGE_READ;
581 mode = "read";
582 }
583 else {
584 tex_usage = LP_TEX_USAGE_READ_WRITE;
585 mode = "read/write";
586 }
587
588 if (0) {
589 printf("transfer map tex %u mode %s\n", lpr->id, mode);
590 }
591
592 format = lpr->base.format;
593
594 map = llvmpipe_resource_map(resource,
595 level,
596 box->z,
597 tex_usage);
598
599
600 /* May want to do different things here depending on read/write nature
601 * of the map:
602 */
603 if (usage & PIPE_TRANSFER_WRITE) {
604 /* Do something to notify sharing contexts of a texture change.
605 */
606 screen->timestamp++;
607 }
608
609 map +=
610 box->y / util_format_get_blockheight(format) * pt->stride +
611 box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
612
613 return map;
614 }
615
616
617 static void
618 llvmpipe_transfer_unmap(struct pipe_context *pipe,
619 struct pipe_transfer *transfer)
620 {
621 assert(transfer->resource);
622
623 llvmpipe_resource_unmap(transfer->resource,
624 transfer->level,
625 transfer->box.z);
626
627 /* Effectively do the texture_update work here - if texture images
628 * needed post-processing to put them into hardware layout, this is
629 * where it would happen. For llvmpipe, nothing to do.
630 */
631 assert (transfer->resource);
632 pipe_resource_reference(&transfer->resource, NULL);
633 FREE(transfer);
634 }
635
636 unsigned int
637 llvmpipe_is_resource_referenced( struct pipe_context *pipe,
638 struct pipe_resource *presource,
639 unsigned level)
640 {
641 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
642
643 /*
644 * XXX checking only resources with the right bind flags
645 * is unsafe since with opengl state tracker we can end up
646 * with resources bound to places they weren't supposed to be
647 * (buffers bound as sampler views is one possibility here).
648 */
649 if (!(presource->bind & (PIPE_BIND_DEPTH_STENCIL |
650 PIPE_BIND_RENDER_TARGET |
651 PIPE_BIND_SAMPLER_VIEW)))
652 return LP_UNREFERENCED;
653
654 return lp_setup_is_resource_referenced(llvmpipe->setup, presource);
655 }
656
657
658 /**
659 * Returns the largest possible alignment for a format in llvmpipe
660 */
661 unsigned
662 llvmpipe_get_format_alignment( enum pipe_format format )
663 {
664 const struct util_format_description *desc = util_format_description(format);
665 unsigned size = 0;
666 unsigned bytes;
667 unsigned i;
668
669 for (i = 0; i < desc->nr_channels; ++i) {
670 size += desc->channel[i].size;
671 }
672
673 bytes = size / 8;
674
675 if (!util_is_power_of_two(bytes)) {
676 bytes /= desc->nr_channels;
677 }
678
679 if (bytes % 2 || bytes < 1) {
680 return 1;
681 } else {
682 return bytes;
683 }
684 }
685
686
687 /**
688 * Create buffer which wraps user-space data.
689 */
690 struct pipe_resource *
691 llvmpipe_user_buffer_create(struct pipe_screen *screen,
692 void *ptr,
693 unsigned bytes,
694 unsigned bind_flags)
695 {
696 struct llvmpipe_resource *buffer;
697
698 buffer = CALLOC_STRUCT(llvmpipe_resource);
699 if(!buffer)
700 return NULL;
701
702 pipe_reference_init(&buffer->base.reference, 1);
703 buffer->base.screen = screen;
704 buffer->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
705 buffer->base.bind = bind_flags;
706 buffer->base.usage = PIPE_USAGE_IMMUTABLE;
707 buffer->base.flags = 0;
708 buffer->base.width0 = bytes;
709 buffer->base.height0 = 1;
710 buffer->base.depth0 = 1;
711 buffer->base.array_size = 1;
712 buffer->userBuffer = TRUE;
713 buffer->data = ptr;
714
715 return &buffer->base;
716 }
717
718
719 /**
720 * Compute size (in bytes) need to store a texture image / mipmap level,
721 * for just one cube face, one array layer or one 3D texture slice
722 */
723 static unsigned
724 tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level)
725 {
726 return lpr->img_stride[level];
727 }
728
729
730 /**
731 * Compute size (in bytes) need to store a texture image / mipmap level,
732 * including all cube faces or 3D image slices
733 */
734 static unsigned
735 tex_image_size(const struct llvmpipe_resource *lpr, unsigned level)
736 {
737 const unsigned buf_size = tex_image_face_size(lpr, level);
738 return buf_size * lpr->num_slices_faces[level];
739 }
740
741
742 /**
743 * Return pointer to a 2D texture image/face/slice.
744 * No tiled/linear conversion is done.
745 */
746 ubyte *
747 llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpr,
748 unsigned face_slice, unsigned level)
749 {
750 unsigned offset;
751
752 assert(llvmpipe_resource_is_texture(&lpr->base));
753
754 offset = lpr->mip_offsets[level];
755
756 if (face_slice > 0)
757 offset += face_slice * tex_image_face_size(lpr, level);
758
759 return (ubyte *) lpr->tex_data + offset;
760 }
761
762
763 /**
764 * Return size of resource in bytes
765 */
766 unsigned
767 llvmpipe_resource_size(const struct pipe_resource *resource)
768 {
769 const struct llvmpipe_resource *lpr = llvmpipe_resource_const(resource);
770 unsigned lvl, size = 0;
771
772 if (llvmpipe_resource_is_texture(resource)) {
773 for (lvl = 0; lvl <= lpr->base.last_level; lvl++) {
774 if (lpr->tex_data)
775 size += tex_image_size(lpr, lvl);
776 }
777 }
778 else {
779 size = resource->width0;
780 }
781
782 return size;
783 }
784
785
786 #ifdef DEBUG
787 void
788 llvmpipe_print_resources(void)
789 {
790 struct llvmpipe_resource *lpr;
791 unsigned n = 0, total = 0;
792
793 debug_printf("LLVMPIPE: current resources:\n");
794 foreach(lpr, &resource_list) {
795 unsigned size = llvmpipe_resource_size(&lpr->base);
796 debug_printf("resource %u at %p, size %ux%ux%u: %u bytes, refcount %u\n",
797 lpr->id, (void *) lpr,
798 lpr->base.width0, lpr->base.height0, lpr->base.depth0,
799 size, lpr->base.reference.count);
800 total += size;
801 n++;
802 }
803 debug_printf("LLVMPIPE: total size of %u resources: %u\n", n, total);
804 }
805 #endif
806
807
808 void
809 llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
810 {
811 #ifdef DEBUG
812 /* init linked list for tracking resources */
813 {
814 static boolean first_call = TRUE;
815 if (first_call) {
816 memset(&resource_list, 0, sizeof(resource_list));
817 make_empty_list(&resource_list);
818 first_call = FALSE;
819 }
820 }
821 #endif
822
823 screen->resource_create = llvmpipe_resource_create;
824 screen->resource_destroy = llvmpipe_resource_destroy;
825 screen->resource_from_handle = llvmpipe_resource_from_handle;
826 screen->resource_get_handle = llvmpipe_resource_get_handle;
827 screen->can_create_resource = llvmpipe_can_create_resource;
828 }
829
830
831 void
832 llvmpipe_init_context_resource_funcs(struct pipe_context *pipe)
833 {
834 pipe->transfer_map = llvmpipe_transfer_map;
835 pipe->transfer_unmap = llvmpipe_transfer_unmap;
836
837 pipe->transfer_flush_region = u_default_transfer_flush_region;
838 pipe->transfer_inline_write = u_default_transfer_inline_write;
839 }