ilo_resource.c revision 0ac706535a07d003b9a40f8bad5445dd50f6c35b
11452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee/*
21452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * Mesa 3-D graphics library
31452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee *
41452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * Copyright (C) 2012-2013 LunarG, Inc.
51452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee *
61452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * Permission is hereby granted, free of charge, to any person obtaining a
71452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * copy of this software and associated documentation files (the "Software"),
81452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * to deal in the Software without restriction, including without limitation
91452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * the rights to use, copy, modify, merge, publish, distribute, sublicense,
101452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * and/or sell copies of the Software, and to permit persons to whom the
11ace690f5e440930d7bbad97fdbfdc3eb65e230bebuzbee * Software is furnished to do so, subject to the following conditions:
121452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee *
1350cf600419109c9cbb0686edc6f7456c13ef7f08buzbee * The above copyright notice and this permission notice shall be included
14ace690f5e440930d7bbad97fdbfdc3eb65e230bebuzbee * in all copies or substantial portions of the Software.
151452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee *
161452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
191452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
211452bee8f06b9f76a333ddf4760e4beaa82f8099buzbee * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Chia-I Wu <olv@lunarg.com>
26 */
27
28#include "ilo_layout.h"
29#include "ilo_screen.h"
30#include "ilo_resource.h"
31
32/*
33 * From the Ivy Bridge PRM, volume 1 part 1, page 105:
34 *
35 *     "In addition to restrictions on maximum height, width, and depth,
36 *      surfaces are also restricted to a maximum size in bytes. This
37 *      maximum is 2 GB for all products and all surface types."
38 */
39static const size_t ilo_max_resource_size = 1u << 31;
40
41static const char *
42resource_get_bo_name(const struct pipe_resource *templ)
43{
44   static const char *target_names[PIPE_MAX_TEXTURE_TYPES] = {
45      [PIPE_BUFFER] = "buf",
46      [PIPE_TEXTURE_1D] = "tex-1d",
47      [PIPE_TEXTURE_2D] = "tex-2d",
48      [PIPE_TEXTURE_3D] = "tex-3d",
49      [PIPE_TEXTURE_CUBE] = "tex-cube",
50      [PIPE_TEXTURE_RECT] = "tex-rect",
51      [PIPE_TEXTURE_1D_ARRAY] = "tex-1d-array",
52      [PIPE_TEXTURE_2D_ARRAY] = "tex-2d-array",
53      [PIPE_TEXTURE_CUBE_ARRAY] = "tex-cube-array",
54   };
55   const char *name = target_names[templ->target];
56
57   if (templ->target == PIPE_BUFFER) {
58      switch (templ->bind) {
59      case PIPE_BIND_VERTEX_BUFFER:
60         name = "buf-vb";
61         break;
62      case PIPE_BIND_INDEX_BUFFER:
63         name = "buf-ib";
64         break;
65      case PIPE_BIND_CONSTANT_BUFFER:
66         name = "buf-cb";
67         break;
68      case PIPE_BIND_STREAM_OUTPUT:
69         name = "buf-so";
70         break;
71      default:
72         break;
73      }
74   }
75
76   return name;
77}
78
79static bool
80resource_get_cpu_init(const struct pipe_resource *templ)
81{
82   return (templ->bind & (PIPE_BIND_DEPTH_STENCIL |
83                          PIPE_BIND_RENDER_TARGET |
84                          PIPE_BIND_STREAM_OUTPUT)) ? false : true;
85}
86
87static enum gen_surface_tiling
88winsys_to_surface_tiling(enum intel_tiling_mode tiling)
89{
90   switch (tiling) {
91   case INTEL_TILING_NONE:
92      return GEN6_TILING_NONE;
93   case INTEL_TILING_X:
94      return GEN6_TILING_X;
95   case INTEL_TILING_Y:
96      return GEN6_TILING_Y;
97   default:
98      assert(!"unknown tiling");
99      return GEN6_TILING_NONE;
100   }
101}
102
103static inline enum intel_tiling_mode
104surface_to_winsys_tiling(enum gen_surface_tiling tiling)
105{
106   switch (tiling) {
107   case GEN6_TILING_NONE:
108      return INTEL_TILING_NONE;
109   case GEN6_TILING_X:
110      return INTEL_TILING_X;
111   case GEN6_TILING_Y:
112      return INTEL_TILING_Y;
113   default:
114      assert(!"unknown tiling");
115      return GEN6_TILING_NONE;
116   }
117}
118
119static void
120tex_free_slices(struct ilo_texture *tex)
121{
122   FREE(tex->slices[0]);
123}
124
125static bool
126tex_alloc_slices(struct ilo_texture *tex)
127{
128   const struct pipe_resource *templ = &tex->base;
129   struct ilo_texture_slice *slices;
130   int depth, lv;
131
132   /* sum the depths of all levels */
133   depth = 0;
134   for (lv = 0; lv <= templ->last_level; lv++)
135      depth += u_minify(templ->depth0, lv);
136
137   /*
138    * There are (depth * tex->base.array_size) slices in total.  Either depth
139    * is one (non-3D) or templ->array_size is one (non-array), but it does
140    * not matter.
141    */
142   slices = CALLOC(depth * templ->array_size, sizeof(*slices));
143   if (!slices)
144      return false;
145
146   tex->slices[0] = slices;
147
148   /* point to the respective positions in the buffer */
149   for (lv = 1; lv <= templ->last_level; lv++) {
150      tex->slices[lv] = tex->slices[lv - 1] +
151         u_minify(templ->depth0, lv - 1) * templ->array_size;
152   }
153
154   return true;
155}
156
157static bool
158tex_import_handle(struct ilo_texture *tex,
159                  const struct winsys_handle *handle)
160{
161   struct ilo_screen *is = ilo_screen(tex->base.screen);
162   const char *name = resource_get_bo_name(&tex->base);
163   enum intel_tiling_mode tiling;
164   unsigned long pitch;
165
166   tex->bo = intel_winsys_import_handle(is->winsys, name, handle,
167         tex->layout.bo_height, &tiling, &pitch);
168   if (!tex->bo)
169      return false;
170
171   if (!ilo_layout_update_for_imported_bo(&tex->layout,
172            winsys_to_surface_tiling(tiling), pitch)) {
173      ilo_err("imported handle has incompatible tiling/pitch\n");
174      intel_bo_unreference(tex->bo);
175      tex->bo = NULL;
176      return false;
177   }
178
179   return true;
180}
181
182static bool
183tex_create_bo(struct ilo_texture *tex)
184{
185   struct ilo_screen *is = ilo_screen(tex->base.screen);
186   const char *name = resource_get_bo_name(&tex->base);
187   const bool cpu_init = resource_get_cpu_init(&tex->base);
188   enum intel_tiling_mode tiling;
189
190   /* no native support */
191   if (tex->layout.tiling == GEN8_TILING_W)
192      tiling = INTEL_TILING_NONE;
193   else
194      tiling = surface_to_winsys_tiling(tex->layout.tiling);
195
196   tex->bo = intel_winsys_alloc_bo(is->winsys, name, tiling,
197         tex->layout.bo_stride, tex->layout.bo_height, cpu_init);
198
199   return (tex->bo != NULL);
200}
201
202static bool
203tex_create_separate_stencil(struct ilo_texture *tex)
204{
205   struct pipe_resource templ = tex->base;
206   struct pipe_resource *s8;
207
208   /*
209    * Unless PIPE_BIND_DEPTH_STENCIL is set, the resource may have other
210    * tilings.  But that should be fine since it will never be bound as the
211    * stencil buffer, and our transfer code can handle all tilings.
212    */
213   templ.format = PIPE_FORMAT_S8_UINT;
214
215   s8 = tex->base.screen->resource_create(tex->base.screen, &templ);
216   if (!s8)
217      return false;
218
219   tex->separate_s8 = ilo_texture(s8);
220
221   assert(tex->separate_s8->layout.format == PIPE_FORMAT_S8_UINT);
222
223   return true;
224}
225
226static bool
227tex_create_hiz(struct ilo_texture *tex)
228{
229   const struct pipe_resource *templ = &tex->base;
230   struct ilo_screen *is = ilo_screen(tex->base.screen);
231   unsigned lv;
232
233   tex->aux_bo = intel_winsys_alloc_buffer(is->winsys, "hiz texture",
234         tex->layout.aux_stride * tex->layout.aux_height, false);
235   if (!tex->aux_bo)
236      return false;
237
238   for (lv = 0; lv <= templ->last_level; lv++) {
239      if (tex->layout.aux_enables & (1 << lv)) {
240         const unsigned num_slices = (templ->target == PIPE_TEXTURE_3D) ?
241            u_minify(templ->depth0, lv) : templ->array_size;
242         unsigned flags = ILO_TEXTURE_HIZ;
243
244         /* this will trigger a HiZ resolve */
245         if (tex->imported)
246            flags |= ILO_TEXTURE_CPU_WRITE;
247
248         ilo_texture_set_slice_flags(tex, lv, 0, num_slices, flags, flags);
249      }
250   }
251
252   return true;
253}
254
255static bool
256tex_create_mcs(struct ilo_texture *tex)
257{
258   struct ilo_screen *is = ilo_screen(tex->base.screen);
259
260   assert(tex->layout.aux_enables == (1 << (tex->base.last_level + 1)) - 1);
261
262   tex->aux_bo = intel_winsys_alloc_buffer(is->winsys, "mcs texture",
263         tex->layout.aux_stride * tex->layout.aux_height, false);
264   if (!tex->aux_bo)
265      return false;
266
267   return true;
268}
269
270static void
271tex_destroy(struct ilo_texture *tex)
272{
273   if (tex->aux_bo)
274      intel_bo_unreference(tex->aux_bo);
275
276   if (tex->separate_s8)
277      tex_destroy(tex->separate_s8);
278
279   if (tex->bo)
280      intel_bo_unreference(tex->bo);
281
282   tex_free_slices(tex);
283   FREE(tex);
284}
285
286static bool
287tex_alloc_bos(struct ilo_texture *tex,
288              const struct winsys_handle *handle)
289{
290   struct ilo_screen *is = ilo_screen(tex->base.screen);
291
292   if (handle) {
293      if (!tex_import_handle(tex, handle))
294         return false;
295   } else {
296      if (!tex_create_bo(tex))
297         return false;
298   }
299
300   /* allocate separate stencil resource */
301   if (tex->layout.separate_stencil && !tex_create_separate_stencil(tex))
302      return false;
303
304   switch (tex->layout.aux) {
305   case ILO_LAYOUT_AUX_HIZ:
306      if (!tex_create_hiz(tex)) {
307         /* Separate Stencil Buffer requires HiZ to be enabled */
308         if (ilo_dev_gen(&is->dev) == ILO_GEN(6) &&
309             tex->layout.separate_stencil)
310            return false;
311      }
312      break;
313   case ILO_LAYOUT_AUX_MCS:
314      if (!tex_create_mcs(tex))
315         return false;
316      break;
317   default:
318      break;
319   }
320
321   return true;
322}
323
324static bool
325tex_init_layout(struct ilo_texture *tex)
326{
327   struct ilo_screen *is = ilo_screen(tex->base.screen);
328   const struct pipe_resource *templ = &tex->base;
329   struct ilo_layout *layout = &tex->layout;
330
331   ilo_layout_init(layout, &is->dev, templ);
332
333   if (layout->bo_height > ilo_max_resource_size / layout->bo_stride)
334      return false;
335
336   if (templ->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) {
337      /* require on-the-fly tiling/untiling or format conversion */
338      if (layout->tiling == GEN8_TILING_W || layout->separate_stencil ||
339          layout->format != templ->format)
340         return false;
341   }
342
343   if (!tex_alloc_slices(tex))
344      return false;
345
346   return true;
347}
348
349static struct pipe_resource *
350tex_create(struct pipe_screen *screen,
351           const struct pipe_resource *templ,
352           const struct winsys_handle *handle)
353{
354   struct ilo_texture *tex;
355
356   tex = CALLOC_STRUCT(ilo_texture);
357   if (!tex)
358      return NULL;
359
360   tex->base = *templ;
361   tex->base.screen = screen;
362   pipe_reference_init(&tex->base.reference, 1);
363
364   tex->imported = (handle != NULL);
365
366   if (!tex_init_layout(tex)) {
367      FREE(tex);
368      return NULL;
369   }
370
371   if (!tex_alloc_bos(tex, handle)) {
372      tex_destroy(tex);
373      return NULL;
374   }
375
376   return &tex->base;
377}
378
379static bool
380tex_get_handle(struct ilo_texture *tex, struct winsys_handle *handle)
381{
382   struct ilo_screen *is = ilo_screen(tex->base.screen);
383   enum intel_tiling_mode tiling;
384   int err;
385
386   /* no native support */
387   if (tex->layout.tiling == GEN8_TILING_W)
388      tiling = INTEL_TILING_NONE;
389   else
390      tiling = surface_to_winsys_tiling(tex->layout.tiling);
391
392   err = intel_winsys_export_handle(is->winsys, tex->bo, tiling,
393         tex->layout.bo_stride, tex->layout.bo_height, handle);
394
395   return !err;
396}
397
398static bool
399buf_create_bo(struct ilo_buffer *buf)
400{
401   struct ilo_screen *is = ilo_screen(buf->base.screen);
402   const char *name = resource_get_bo_name(&buf->base);
403   const bool cpu_init = resource_get_cpu_init(&buf->base);
404
405   buf->bo = intel_winsys_alloc_buffer(is->winsys, name,
406         buf->bo_size, cpu_init);
407
408   return (buf->bo != NULL);
409}
410
411static void
412buf_destroy(struct ilo_buffer *buf)
413{
414   intel_bo_unreference(buf->bo);
415   FREE(buf);
416}
417
418static struct pipe_resource *
419buf_create(struct pipe_screen *screen, const struct pipe_resource *templ)
420{
421   const struct ilo_screen *is = ilo_screen(screen);
422   struct ilo_buffer *buf;
423
424   buf = CALLOC_STRUCT(ilo_buffer);
425   if (!buf)
426      return NULL;
427
428   buf->base = *templ;
429   buf->base.screen = screen;
430   pipe_reference_init(&buf->base.reference, 1);
431
432   buf->bo_size = templ->width0;
433
434   /*
435    * From the Sandy Bridge PRM, volume 1 part 1, page 118:
436    *
437    *     "For buffers, which have no inherent "height," padding requirements
438    *      are different. A buffer must be padded to the next multiple of 256
439    *      array elements, with an additional 16 bytes added beyond that to
440    *      account for the L1 cache line."
441    */
442   if (templ->bind & PIPE_BIND_SAMPLER_VIEW)
443      buf->bo_size = align(buf->bo_size, 256) + 16;
444
445   if ((templ->bind & PIPE_BIND_VERTEX_BUFFER) &&
446        ilo_dev_gen(&is->dev) < ILO_GEN(7.5)) {
447      /*
448       * As noted in ilo_translate_format(), we treat some 3-component formats
449       * as 4-component formats to work around hardware limitations.  Imagine
450       * the case where the vertex buffer holds a single
451       * PIPE_FORMAT_R16G16B16_FLOAT vertex, and buf->bo_size is 6.  The
452       * hardware would fail to fetch it at boundary check because the vertex
453       * buffer is expected to hold a PIPE_FORMAT_R16G16B16A16_FLOAT vertex
454       * and that takes at least 8 bytes.
455       *
456       * For the workaround to work, we should add 2 to the bo size.  But that
457       * would waste a page when the bo size is already page aligned.  Let's
458       * round it to page size for now and revisit this when needed.
459       */
460      buf->bo_size = align(buf->bo_size, 4096);
461   }
462
463   if (buf->bo_size < templ->width0 ||
464       buf->bo_size > ilo_max_resource_size ||
465       !buf_create_bo(buf)) {
466      FREE(buf);
467      return NULL;
468   }
469
470   return &buf->base;
471}
472
473static boolean
474ilo_can_create_resource(struct pipe_screen *screen,
475                        const struct pipe_resource *templ)
476{
477   struct ilo_layout layout;
478
479   if (templ->target == PIPE_BUFFER)
480      return (templ->width0 <= ilo_max_resource_size);
481
482   memset(&layout, 0, sizeof(layout));
483   ilo_layout_init(&layout, &ilo_screen(screen)->dev, templ);
484
485   return (layout.bo_height <= ilo_max_resource_size / layout.bo_stride);
486}
487
488static struct pipe_resource *
489ilo_resource_create(struct pipe_screen *screen,
490                    const struct pipe_resource *templ)
491{
492   if (templ->target == PIPE_BUFFER)
493      return buf_create(screen, templ);
494   else
495      return tex_create(screen, templ, NULL);
496}
497
498static struct pipe_resource *
499ilo_resource_from_handle(struct pipe_screen *screen,
500                         const struct pipe_resource *templ,
501                         struct winsys_handle *handle)
502{
503   if (templ->target == PIPE_BUFFER)
504      return NULL;
505   else
506      return tex_create(screen, templ, handle);
507}
508
509static boolean
510ilo_resource_get_handle(struct pipe_screen *screen,
511                        struct pipe_resource *res,
512                        struct winsys_handle *handle)
513{
514   if (res->target == PIPE_BUFFER)
515      return false;
516   else
517      return tex_get_handle(ilo_texture(res), handle);
518
519}
520
521static void
522ilo_resource_destroy(struct pipe_screen *screen,
523                     struct pipe_resource *res)
524{
525   if (res->target == PIPE_BUFFER)
526      buf_destroy(ilo_buffer(res));
527   else
528      tex_destroy(ilo_texture(res));
529}
530
531/**
532 * Initialize resource-related functions.
533 */
534void
535ilo_init_resource_functions(struct ilo_screen *is)
536{
537   is->base.can_create_resource = ilo_can_create_resource;
538   is->base.resource_create = ilo_resource_create;
539   is->base.resource_from_handle = ilo_resource_from_handle;
540   is->base.resource_get_handle = ilo_resource_get_handle;
541   is->base.resource_destroy = ilo_resource_destroy;
542}
543
544bool
545ilo_buffer_rename_bo(struct ilo_buffer *buf)
546{
547   struct intel_bo *old_bo = buf->bo;
548
549   if (buf_create_bo(buf)) {
550      intel_bo_unreference(old_bo);
551      return true;
552   }
553   else {
554      buf->bo = old_bo;
555      return false;
556   }
557}
558
559bool
560ilo_texture_rename_bo(struct ilo_texture *tex)
561{
562   struct intel_bo *old_bo = tex->bo;
563
564   /* an imported texture cannot be renamed */
565   if (tex->imported)
566      return false;
567
568   if (tex_create_bo(tex)) {
569      intel_bo_unreference(old_bo);
570      return true;
571   }
572   else {
573      tex->bo = old_bo;
574      return false;
575   }
576}
577