Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3770 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 "pipe/p_defines.h"
34
#include "util/u_inlines.h"
35
 
36
#include "util/u_format.h"
37
#include "util/u_math.h"
38
#include "util/u_memory.h"
39
#include "util/u_transfer.h"
40
 
41
#include "sp_context.h"
42
#include "sp_flush.h"
43
#include "sp_texture.h"
44
#include "sp_screen.h"
45
 
46
#include "state_tracker/sw_winsys.h"
47
 
48
 
49
/**
50
 * Conventional allocation path for non-display textures:
51
 * Use a simple, maximally packed layout.
52
 */
53
static boolean
54
softpipe_resource_layout(struct pipe_screen *screen,
55
                         struct softpipe_resource *spr,
56
                         boolean allocate)
57
{
58
   struct pipe_resource *pt = &spr->base;
59
   unsigned level;
60
   unsigned width = pt->width0;
61
   unsigned height = pt->height0;
62
   unsigned depth = pt->depth0;
63
   unsigned buffer_size = 0;
64
 
65
   for (level = 0; level <= pt->last_level; level++) {
66
      unsigned slices;
67
 
68
      if (pt->target == PIPE_TEXTURE_CUBE)
69
         slices = 6;
70
      else if (pt->target == PIPE_TEXTURE_3D)
71
         slices = depth;
72
      else
73
         slices = pt->array_size;
74
 
75
      spr->stride[level] = util_format_get_stride(pt->format, width);
76
 
77
      spr->level_offset[level] = buffer_size;
78
 
79
      buffer_size += (util_format_get_nblocksy(pt->format, height) *
80
                      slices * spr->stride[level]);
81
 
82
      width  = u_minify(width, 1);
83
      height = u_minify(height, 1);
84
      depth = u_minify(depth, 1);
85
   }
86
 
87
   if (buffer_size > SP_MAX_TEXTURE_SIZE)
88
      return FALSE;
89
 
90
   if (allocate) {
91
      spr->data = align_malloc(buffer_size, 16);
92
      return spr->data != NULL;
93
   }
94
   else {
95
      return TRUE;
96
   }
97
}
98
 
99
 
100
/**
101
 * Check the size of the texture specified by 'res'.
102
 * \return TRUE if OK, FALSE if too large.
103
 */
104
static boolean
105
softpipe_can_create_resource(struct pipe_screen *screen,
106
                             const struct pipe_resource *res)
107
{
108
   struct softpipe_resource spr;
109
   memset(&spr, 0, sizeof(spr));
110
   spr.base = *res;
111
   return softpipe_resource_layout(screen, &spr, FALSE);
112
}
113
 
114
 
115
/**
116
 * Texture layout for simple color buffers.
117
 */
118
static boolean
119
softpipe_displaytarget_layout(struct pipe_screen *screen,
120
                              struct softpipe_resource *spr)
121
{
122
   struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
123
 
124
   /* Round up the surface size to a multiple of the tile size?
125
    */
126
   spr->dt = winsys->displaytarget_create(winsys,
127
                                          spr->base.bind,
128
                                          spr->base.format,
129
                                          spr->base.width0,
130
                                          spr->base.height0,
131
                                          16,
132
                                          &spr->stride[0] );
133
 
134
   return spr->dt != NULL;
135
}
136
 
137
 
138
/**
139
 * Create new pipe_resource given the template information.
140
 */
141
static struct pipe_resource *
142
softpipe_resource_create(struct pipe_screen *screen,
143
                         const struct pipe_resource *templat)
144
{
145
   struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
146
   if (!spr)
147
      return NULL;
148
 
149
   assert(templat->format != PIPE_FORMAT_NONE);
150
 
151
   spr->base = *templat;
152
   pipe_reference_init(&spr->base.reference, 1);
153
   spr->base.screen = screen;
154
 
155
   spr->pot = (util_is_power_of_two(templat->width0) &&
156
               util_is_power_of_two(templat->height0) &&
157
               util_is_power_of_two(templat->depth0));
158
 
159
   if (spr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
160
			 PIPE_BIND_SCANOUT |
161
			 PIPE_BIND_SHARED)) {
162
      if (!softpipe_displaytarget_layout(screen, spr))
163
         goto fail;
164
   }
165
   else {
166
      if (!softpipe_resource_layout(screen, spr, TRUE))
167
         goto fail;
168
   }
169
 
170
   return &spr->base;
171
 
172
 fail:
173
   FREE(spr);
174
   return NULL;
175
}
176
 
177
 
178
static void
179
softpipe_resource_destroy(struct pipe_screen *pscreen,
180
			  struct pipe_resource *pt)
181
{
182
   struct softpipe_screen *screen = softpipe_screen(pscreen);
183
   struct softpipe_resource *spr = softpipe_resource(pt);
184
 
185
   if (spr->dt) {
186
      /* display target */
187
      struct sw_winsys *winsys = screen->winsys;
188
      winsys->displaytarget_destroy(winsys, spr->dt);
189
   }
190
   else if (!spr->userBuffer) {
191
      /* regular texture */
192
      align_free(spr->data);
193
   }
194
 
195
   FREE(spr);
196
}
197
 
198
 
199
static struct pipe_resource *
200
softpipe_resource_from_handle(struct pipe_screen *screen,
201
                              const struct pipe_resource *templat,
202
                              struct winsys_handle *whandle)
203
{
204
   struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
205
   struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
206
   if (!spr)
207
      return NULL;
208
 
209
   spr->base = *templat;
210
   pipe_reference_init(&spr->base.reference, 1);
211
   spr->base.screen = screen;
212
 
213
   spr->pot = (util_is_power_of_two(templat->width0) &&
214
               util_is_power_of_two(templat->height0) &&
215
               util_is_power_of_two(templat->depth0));
216
 
217
   spr->dt = winsys->displaytarget_from_handle(winsys,
218
                                               templat,
219
                                               whandle,
220
                                               &spr->stride[0]);
221
   if (!spr->dt)
222
      goto fail;
223
 
224
   return &spr->base;
225
 
226
 fail:
227
   FREE(spr);
228
   return NULL;
229
}
230
 
231
 
232
static boolean
233
softpipe_resource_get_handle(struct pipe_screen *screen,
234
                             struct pipe_resource *pt,
235
                             struct winsys_handle *whandle)
236
{
237
   struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
238
   struct softpipe_resource *spr = softpipe_resource(pt);
239
 
240
   assert(spr->dt);
241
   if (!spr->dt)
242
      return FALSE;
243
 
244
   return winsys->displaytarget_get_handle(winsys, spr->dt, whandle);
245
}
246
 
247
 
248
/**
249
 * Helper function to compute offset (in bytes) for a particular
250
 * texture level/face/slice from the start of the buffer.
251
 */
252
static unsigned
253
sp_get_tex_image_offset(const struct softpipe_resource *spr,
254
                        unsigned level, unsigned layer)
255
{
256
   const unsigned hgt = u_minify(spr->base.height0, level);
257
   const unsigned nblocksy = util_format_get_nblocksy(spr->base.format, hgt);
258
   unsigned offset = spr->level_offset[level];
259
 
260
   if (spr->base.target == PIPE_TEXTURE_CUBE ||
261
       spr->base.target == PIPE_TEXTURE_CUBE_ARRAY ||
262
       spr->base.target == PIPE_TEXTURE_3D ||
263
       spr->base.target == PIPE_TEXTURE_2D_ARRAY) {
264
      offset += layer * nblocksy * spr->stride[level];
265
   }
266
   else if (spr->base.target == PIPE_TEXTURE_1D_ARRAY) {
267
      offset += layer * spr->stride[level];
268
   }
269
   else {
270
      assert(layer == 0);
271
   }
272
 
273
   return offset;
274
}
275
 
276
 
277
/**
278
 * Get a pipe_surface "view" into a texture resource.
279
 */
280
static struct pipe_surface *
281
softpipe_create_surface(struct pipe_context *pipe,
282
                        struct pipe_resource *pt,
283
                        const struct pipe_surface *surf_tmpl)
284
{
285
   struct pipe_surface *ps;
286
 
287
   ps = CALLOC_STRUCT(pipe_surface);
288
   if (ps) {
289
      pipe_reference_init(&ps->reference, 1);
290
      pipe_resource_reference(&ps->texture, pt);
291
      ps->context = pipe;
292
      ps->format = surf_tmpl->format;
293
      if (pt->target != PIPE_BUFFER) {
294
         assert(surf_tmpl->u.tex.level <= pt->last_level);
295
         ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
296
         ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
297
         ps->u.tex.level = surf_tmpl->u.tex.level;
298
         ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
299
         ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
300
         if (ps->u.tex.first_layer != ps->u.tex.last_layer) {
301
            debug_printf("creating surface with multiple layers, rendering to first layer only\n");
302
         }
303
      }
304
      else {
305
         /* setting width as number of elements should get us correct renderbuffer width */
306
         ps->width = surf_tmpl->u.buf.last_element - surf_tmpl->u.buf.first_element + 1;
307
         ps->height = pt->height0;
308
         ps->u.buf.first_element = surf_tmpl->u.buf.first_element;
309
         ps->u.buf.last_element = surf_tmpl->u.buf.last_element;
310
         assert(ps->u.buf.first_element <= ps->u.buf.last_element);
311
         assert(ps->u.buf.last_element < ps->width);
312
      }
313
   }
314
   return ps;
315
}
316
 
317
 
318
/**
319
 * Free a pipe_surface which was created with softpipe_create_surface().
320
 */
321
static void
322
softpipe_surface_destroy(struct pipe_context *pipe,
323
                         struct pipe_surface *surf)
324
{
325
   /* Effectively do the texture_update work here - if texture images
326
    * needed post-processing to put them into hardware layout, this is
327
    * where it would happen.  For softpipe, nothing to do.
328
    */
329
   assert(surf->texture);
330
   pipe_resource_reference(&surf->texture, NULL);
331
   FREE(surf);
332
}
333
 
334
 
335
/**
336
 * Geta pipe_transfer object which is used for moving data in/out of
337
 * a resource object.
338
 * \param pipe  rendering context
339
 * \param resource  the resource to transfer in/out of
340
 * \param level  which mipmap level
341
 * \param usage  bitmask of PIPE_TRANSFER_x flags
342
 * \param box  the 1D/2D/3D region of interest
343
 */
344
static void *
345
softpipe_transfer_map(struct pipe_context *pipe,
346
                      struct pipe_resource *resource,
347
                      unsigned level,
348
                      unsigned usage,
349
                      const struct pipe_box *box,
350
                      struct pipe_transfer **transfer)
351
{
352
   struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
353
   struct softpipe_resource *spr = softpipe_resource(resource);
354
   struct softpipe_transfer *spt;
355
   struct pipe_transfer *pt;
356
   enum pipe_format format = resource->format;
357
   const unsigned hgt = u_minify(spr->base.height0, level);
358
   const unsigned nblocksy = util_format_get_nblocksy(format, hgt);
359
   uint8_t *map;
360
 
361
   assert(resource);
362
   assert(level <= resource->last_level);
363
 
364
   /* make sure the requested region is in the image bounds */
365
   assert(box->x + box->width <= u_minify(resource->width0, level));
366
   if (resource->target == PIPE_TEXTURE_1D_ARRAY) {
367
      assert(box->y + box->height <= resource->array_size);
368
   }
369
   else {
370
      assert(box->y + box->height <= u_minify(resource->height0, level));
371
      if (resource->target == PIPE_TEXTURE_2D_ARRAY) {
372
         assert(box->z + box->depth <= resource->array_size);
373
      }
374
      else if (resource->target == PIPE_TEXTURE_CUBE) {
375
         assert(box->z < 6);
376
      }
377
      else if (resource->target == PIPE_TEXTURE_CUBE_ARRAY) {
378
         assert(box->z <= resource->array_size);
379
      }
380
      else {
381
         assert(box->z + box->depth <= (u_minify(resource->depth0, level)));
382
      }
383
   }
384
 
385
   /*
386
    * Transfers, like other pipe operations, must happen in order, so flush the
387
    * context if necessary.
388
    */
389
   if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
390
      boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
391
      boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
392
      if (!softpipe_flush_resource(pipe, resource,
393
                                   level, box->depth > 1 ? -1 : box->z,
394
                                   0, /* flush_flags */
395
                                   read_only,
396
                                   TRUE, /* cpu_access */
397
                                   do_not_block)) {
398
         /*
399
          * It would have blocked, but state tracker requested no to.
400
          */
401
         assert(do_not_block);
402
         return NULL;
403
      }
404
   }
405
 
406
   spt = CALLOC_STRUCT(softpipe_transfer);
407
   if (!spt)
408
      return NULL;
409
 
410
   pt = &spt->base;
411
 
412
   pipe_resource_reference(&pt->resource, resource);
413
   pt->level = level;
414
   pt->usage = usage;
415
   pt->box = *box;
416
   pt->stride = spr->stride[level];
417
   pt->layer_stride = pt->stride * nblocksy;
418
 
419
   spt->offset = sp_get_tex_image_offset(spr, level, box->z);
420
 
421
   spt->offset +=
422
         box->y / util_format_get_blockheight(format) * spt->base.stride +
423
         box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
424
 
425
   /* resources backed by display target treated specially:
426
    */
427
   if (spr->dt) {
428
      map = winsys->displaytarget_map(winsys, spr->dt, usage);
429
   }
430
   else {
431
      map = spr->data;
432
   }
433
 
434
   if (map == NULL) {
435
      pipe_resource_reference(&pt->resource, NULL);
436
      FREE(spt);
437
      return NULL;
438
   }
439
 
440
   *transfer = pt;
441
   return map + spt->offset;
442
}
443
 
444
 
445
/**
446
 * Unmap memory mapping for given pipe_transfer object.
447
 */
448
static void
449
softpipe_transfer_unmap(struct pipe_context *pipe,
450
                        struct pipe_transfer *transfer)
451
{
452
   struct softpipe_resource *spr;
453
 
454
   assert(transfer->resource);
455
   spr = softpipe_resource(transfer->resource);
456
 
457
   if (spr->dt) {
458
      /* display target */
459
      struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
460
      winsys->displaytarget_unmap(winsys, spr->dt);
461
   }
462
 
463
   if (transfer->usage & PIPE_TRANSFER_WRITE) {
464
      /* Mark the texture as dirty to expire the tile caches. */
465
      spr->timestamp++;
466
   }
467
 
468
   pipe_resource_reference(&transfer->resource, NULL);
469
   FREE(transfer);
470
}
471
 
472
/**
473
 * Create buffer which wraps user-space data.
474
 */
475
struct pipe_resource *
476
softpipe_user_buffer_create(struct pipe_screen *screen,
477
                            void *ptr,
478
                            unsigned bytes,
479
			    unsigned bind_flags)
480
{
481
   struct softpipe_resource *spr;
482
 
483
   spr = CALLOC_STRUCT(softpipe_resource);
484
   if (!spr)
485
      return NULL;
486
 
487
   pipe_reference_init(&spr->base.reference, 1);
488
   spr->base.screen = screen;
489
   spr->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
490
   spr->base.bind = bind_flags;
491
   spr->base.usage = PIPE_USAGE_IMMUTABLE;
492
   spr->base.flags = 0;
493
   spr->base.width0 = bytes;
494
   spr->base.height0 = 1;
495
   spr->base.depth0 = 1;
496
   spr->base.array_size = 1;
497
   spr->userBuffer = TRUE;
498
   spr->data = ptr;
499
 
500
   return &spr->base;
501
}
502
 
503
 
504
void
505
softpipe_init_texture_funcs(struct pipe_context *pipe)
506
{
507
   pipe->transfer_map = softpipe_transfer_map;
508
   pipe->transfer_unmap = softpipe_transfer_unmap;
509
 
510
   pipe->transfer_flush_region = u_default_transfer_flush_region;
511
   pipe->transfer_inline_write = u_default_transfer_inline_write;
512
 
513
   pipe->create_surface = softpipe_create_surface;
514
   pipe->surface_destroy = softpipe_surface_destroy;
515
}
516
 
517
 
518
void
519
softpipe_init_screen_texture_funcs(struct pipe_screen *screen)
520
{
521
   screen->resource_create = softpipe_resource_create;
522
   screen->resource_destroy = softpipe_resource_destroy;
523
   screen->resource_from_handle = softpipe_resource_from_handle;
524
   screen->resource_get_handle = softpipe_resource_get_handle;
525
   screen->can_create_resource = softpipe_can_create_resource;
526
}