Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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