~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/gallium/drivers/softpipe/sp_texture.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

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