lp_scene.c revision 848b8605
1/**************************************************************************
2 *
3 * Copyright 2009 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#include "util/u_framebuffer.h"
29#include "util/u_math.h"
30#include "util/u_memory.h"
31#include "util/u_inlines.h"
32#include "util/u_simple_list.h"
33#include "util/u_format.h"
34#include "lp_scene.h"
35#include "lp_fence.h"
36#include "lp_debug.h"
37
38
39#define RESOURCE_REF_SZ 32
40
41/** List of resource references */
42struct resource_ref {
43   struct pipe_resource *resource[RESOURCE_REF_SZ];
44   int count;
45   struct resource_ref *next;
46};
47
48
49/**
50 * Create a new scene object.
51 * \param queue  the queue to put newly rendered/emptied scenes into
52 */
53struct lp_scene *
54lp_scene_create( struct pipe_context *pipe )
55{
56   struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
57   if (!scene)
58      return NULL;
59
60   scene->pipe = pipe;
61
62   scene->data.head =
63      CALLOC_STRUCT(data_block);
64
65   pipe_mutex_init(scene->mutex);
66
67#ifdef DEBUG
68   /* Do some scene limit sanity checks here */
69   {
70      size_t maxBins = TILES_X * TILES_Y;
71      size_t maxCommandBytes = sizeof(struct cmd_block) * maxBins;
72      size_t maxCommandPlusData = maxCommandBytes + DATA_BLOCK_SIZE;
73      /* We'll need at least one command block per bin.  Make sure that's
74       * less than the max allowed scene size.
75       */
76      assert(maxCommandBytes < LP_SCENE_MAX_SIZE);
77      /* We'll also need space for at least one other data block */
78      assert(maxCommandPlusData <= LP_SCENE_MAX_SIZE);
79   }
80#endif
81
82   return scene;
83}
84
85
86/**
87 * Free all data associated with the given scene, and the scene itself.
88 */
89void
90lp_scene_destroy(struct lp_scene *scene)
91{
92   lp_fence_reference(&scene->fence, NULL);
93   pipe_mutex_destroy(scene->mutex);
94   assert(scene->data.head->next == NULL);
95   FREE(scene->data.head);
96   FREE(scene);
97}
98
99
100/**
101 * Check if the scene's bins are all empty.
102 * For debugging purposes.
103 */
104boolean
105lp_scene_is_empty(struct lp_scene *scene )
106{
107   unsigned x, y;
108
109   for (y = 0; y < TILES_Y; y++) {
110      for (x = 0; x < TILES_X; x++) {
111         const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
112         if (bin->head) {
113            return FALSE;
114         }
115      }
116   }
117   return TRUE;
118}
119
120
121/* Returns true if there has ever been a failed allocation attempt in
122 * this scene.  Used in triangle emit to avoid having to check success
123 * at each bin.
124 */
125boolean
126lp_scene_is_oom(struct lp_scene *scene)
127{
128   return scene->alloc_failed;
129}
130
131
132/* Remove all commands from a bin.  Tries to reuse some of the memory
133 * allocated to the bin, however.
134 */
135void
136lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
137{
138   struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
139
140   bin->last_state = NULL;
141   bin->head = bin->tail;
142   if (bin->tail) {
143      bin->tail->next = NULL;
144      bin->tail->count = 0;
145   }
146}
147
148
149void
150lp_scene_begin_rasterization(struct lp_scene *scene)
151{
152   const struct pipe_framebuffer_state *fb = &scene->fb;
153   int i;
154
155   //LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
156
157   for (i = 0; i < scene->fb.nr_cbufs; i++) {
158      struct pipe_surface *cbuf = scene->fb.cbufs[i];
159
160      if (!cbuf) {
161         scene->cbufs[i].stride = 0;
162         scene->cbufs[i].layer_stride = 0;
163         scene->cbufs[i].map = NULL;
164         continue;
165      }
166
167      if (llvmpipe_resource_is_texture(cbuf->texture)) {
168         scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture,
169                                                           cbuf->u.tex.level);
170         scene->cbufs[i].layer_stride = llvmpipe_layer_stride(cbuf->texture,
171                                                              cbuf->u.tex.level);
172
173         scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture,
174                                                     cbuf->u.tex.level,
175                                                     cbuf->u.tex.first_layer,
176                                                     LP_TEX_USAGE_READ_WRITE);
177      }
178      else {
179         struct llvmpipe_resource *lpr = llvmpipe_resource(cbuf->texture);
180         unsigned pixstride = util_format_get_blocksize(cbuf->format);
181         scene->cbufs[i].stride = cbuf->texture->width0;
182         scene->cbufs[i].layer_stride = 0;
183         scene->cbufs[i].map = lpr->data;
184         scene->cbufs[i].map += cbuf->u.buf.first_element * pixstride;
185      }
186   }
187
188   if (fb->zsbuf) {
189      struct pipe_surface *zsbuf = scene->fb.zsbuf;
190      scene->zsbuf.stride = llvmpipe_resource_stride(zsbuf->texture, zsbuf->u.tex.level);
191      scene->zsbuf.layer_stride = llvmpipe_layer_stride(zsbuf->texture, zsbuf->u.tex.level);
192
193      scene->zsbuf.map = llvmpipe_resource_map(zsbuf->texture,
194                                               zsbuf->u.tex.level,
195                                               zsbuf->u.tex.first_layer,
196                                               LP_TEX_USAGE_READ_WRITE);
197   }
198}
199
200
201
202
203/**
204 * Free all the temporary data in a scene.
205 */
206void
207lp_scene_end_rasterization(struct lp_scene *scene )
208{
209   int i, j;
210
211   /* Unmap color buffers */
212   for (i = 0; i < scene->fb.nr_cbufs; i++) {
213      if (scene->cbufs[i].map) {
214         struct pipe_surface *cbuf = scene->fb.cbufs[i];
215         if (llvmpipe_resource_is_texture(cbuf->texture)) {
216            llvmpipe_resource_unmap(cbuf->texture,
217                                    cbuf->u.tex.level,
218                                    cbuf->u.tex.first_layer);
219         }
220         scene->cbufs[i].map = NULL;
221      }
222   }
223
224   /* Unmap z/stencil buffer */
225   if (scene->zsbuf.map) {
226      struct pipe_surface *zsbuf = scene->fb.zsbuf;
227      llvmpipe_resource_unmap(zsbuf->texture,
228                              zsbuf->u.tex.level,
229                              zsbuf->u.tex.first_layer);
230      scene->zsbuf.map = NULL;
231   }
232
233   /* Reset all command lists:
234    */
235   for (i = 0; i < scene->tiles_x; i++) {
236      for (j = 0; j < scene->tiles_y; j++) {
237         struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
238         bin->head = NULL;
239         bin->tail = NULL;
240         bin->last_state = NULL;
241      }
242   }
243
244   /* If there are any bins which weren't cleared by the loop above,
245    * they will be caught (on debug builds at least) by this assert:
246    */
247   assert(lp_scene_is_empty(scene));
248
249   /* Decrement texture ref counts
250    */
251   {
252      struct resource_ref *ref;
253      int i, j = 0;
254
255      for (ref = scene->resources; ref; ref = ref->next) {
256         for (i = 0; i < ref->count; i++) {
257            if (LP_DEBUG & DEBUG_SETUP)
258               debug_printf("resource %d: %p %dx%d sz %d\n",
259                            j,
260                            (void *) ref->resource[i],
261                            ref->resource[i]->width0,
262                            ref->resource[i]->height0,
263                            llvmpipe_resource_size(ref->resource[i]));
264            j++;
265            pipe_resource_reference(&ref->resource[i], NULL);
266         }
267      }
268
269      if (LP_DEBUG & DEBUG_SETUP)
270         debug_printf("scene %d resources, sz %d\n",
271                      j, scene->resource_reference_size);
272   }
273
274   /* Free all scene data blocks:
275    */
276   {
277      struct data_block_list *list = &scene->data;
278      struct data_block *block, *tmp;
279
280      for (block = list->head->next; block; block = tmp) {
281         tmp = block->next;
282	 FREE(block);
283      }
284
285      list->head->next = NULL;
286      list->head->used = 0;
287   }
288
289   lp_fence_reference(&scene->fence, NULL);
290
291   scene->resources = NULL;
292   scene->scene_size = 0;
293   scene->resource_reference_size = 0;
294
295   scene->alloc_failed = FALSE;
296
297   util_unreference_framebuffer_state( &scene->fb );
298}
299
300
301
302
303
304
305struct cmd_block *
306lp_scene_new_cmd_block( struct lp_scene *scene,
307                        struct cmd_bin *bin )
308{
309   struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));
310   if (block) {
311      if (bin->tail) {
312         bin->tail->next = block;
313         bin->tail = block;
314      }
315      else {
316         bin->head = block;
317         bin->tail = block;
318      }
319      //memset(block, 0, sizeof *block);
320      block->next = NULL;
321      block->count = 0;
322   }
323   return block;
324}
325
326
327struct data_block *
328lp_scene_new_data_block( struct lp_scene *scene )
329{
330   if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) {
331      if (0) debug_printf("%s: failed\n", __FUNCTION__);
332      scene->alloc_failed = TRUE;
333      return NULL;
334   }
335   else {
336      struct data_block *block = MALLOC_STRUCT(data_block);
337      if (block == NULL)
338         return NULL;
339
340      scene->scene_size += sizeof *block;
341
342      block->used = 0;
343      block->next = scene->data.head;
344      scene->data.head = block;
345
346      return block;
347   }
348}
349
350
351/**
352 * Return number of bytes used for all bin data within a scene.
353 * This does not include resources (textures) referenced by the scene.
354 */
355static unsigned
356lp_scene_data_size( const struct lp_scene *scene )
357{
358   unsigned size = 0;
359   const struct data_block *block;
360   for (block = scene->data.head; block; block = block->next) {
361      size += block->used;
362   }
363   return size;
364}
365
366
367
368/**
369 * Add a reference to a resource by the scene.
370 */
371boolean
372lp_scene_add_resource_reference(struct lp_scene *scene,
373                                struct pipe_resource *resource,
374                                boolean initializing_scene)
375{
376   struct resource_ref *ref, **last = &scene->resources;
377   int i;
378
379   /* Look at existing resource blocks:
380    */
381   for (ref = scene->resources; ref; ref = ref->next) {
382      last = &ref->next;
383
384      /* Search for this resource:
385       */
386      for (i = 0; i < ref->count; i++)
387         if (ref->resource[i] == resource)
388            return TRUE;
389
390      if (ref->count < RESOURCE_REF_SZ) {
391         /* If the block is half-empty, then append the reference here.
392          */
393         break;
394      }
395   }
396
397   /* Create a new block if no half-empty block was found.
398    */
399   if (!ref) {
400      assert(*last == NULL);
401      *last = lp_scene_alloc(scene, sizeof *ref);
402      if (*last == NULL)
403          return FALSE;
404
405      ref = *last;
406      memset(ref, 0, sizeof *ref);
407   }
408
409   /* Append the reference to the reference block.
410    */
411   pipe_resource_reference(&ref->resource[ref->count++], resource);
412   scene->resource_reference_size += llvmpipe_resource_size(resource);
413
414   /* Heuristic to advise scene flushes.  This isn't helpful in the
415    * initial setup of the scene, but after that point flush on the
416    * next resource added which exceeds 64MB in referenced texture
417    * data.
418    */
419   if (!initializing_scene &&
420       scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE)
421      return FALSE;
422
423   return TRUE;
424}
425
426
427/**
428 * Does this scene have a reference to the given resource?
429 */
430boolean
431lp_scene_is_resource_referenced(const struct lp_scene *scene,
432                                const struct pipe_resource *resource)
433{
434   const struct resource_ref *ref;
435   int i;
436
437   for (ref = scene->resources; ref; ref = ref->next) {
438      for (i = 0; i < ref->count; i++)
439         if (ref->resource[i] == resource)
440            return TRUE;
441   }
442
443   return FALSE;
444}
445
446
447
448
449/** advance curr_x,y to the next bin */
450static boolean
451next_bin(struct lp_scene *scene)
452{
453   scene->curr_x++;
454   if (scene->curr_x >= scene->tiles_x) {
455      scene->curr_x = 0;
456      scene->curr_y++;
457   }
458   if (scene->curr_y >= scene->tiles_y) {
459      /* no more bins */
460      return FALSE;
461   }
462   return TRUE;
463}
464
465
466void
467lp_scene_bin_iter_begin( struct lp_scene *scene )
468{
469   scene->curr_x = scene->curr_y = -1;
470}
471
472
473/**
474 * Return pointer to next bin to be rendered.
475 * The lp_scene::curr_x and ::curr_y fields will be advanced.
476 * Multiple rendering threads will call this function to get a chunk
477 * of work (a bin) to work on.
478 */
479struct cmd_bin *
480lp_scene_bin_iter_next( struct lp_scene *scene , int *x, int *y)
481{
482   struct cmd_bin *bin = NULL;
483
484   pipe_mutex_lock(scene->mutex);
485
486   if (scene->curr_x < 0) {
487      /* first bin */
488      scene->curr_x = 0;
489      scene->curr_y = 0;
490   }
491   else if (!next_bin(scene)) {
492      /* no more bins left */
493      goto end;
494   }
495
496   bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
497   *x = scene->curr_x;
498   *y = scene->curr_y;
499
500end:
501   /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
502   pipe_mutex_unlock(scene->mutex);
503   return bin;
504}
505
506
507void lp_scene_begin_binning( struct lp_scene *scene,
508                             struct pipe_framebuffer_state *fb, boolean discard )
509{
510   int i;
511   unsigned max_layer = ~0;
512
513   assert(lp_scene_is_empty(scene));
514
515   scene->discard = discard;
516   util_copy_framebuffer_state(&scene->fb, fb);
517
518   scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;
519   scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE;
520   assert(scene->tiles_x <= TILES_X);
521   assert(scene->tiles_y <= TILES_Y);
522
523   /*
524    * Determine how many layers the fb has (used for clamping layer value).
525    * OpenGL (but not d3d10) permits different amount of layers per rt, however
526    * results are undefined if layer exceeds the amount of layers of ANY
527    * attachment hence don't need separate per cbuf and zsbuf max.
528    */
529   for (i = 0; i < scene->fb.nr_cbufs; i++) {
530      struct pipe_surface *cbuf = scene->fb.cbufs[i];
531      if (cbuf) {
532         if (llvmpipe_resource_is_texture(cbuf->texture)) {
533            max_layer = MIN2(max_layer,
534                             cbuf->u.tex.last_layer - cbuf->u.tex.first_layer);
535         }
536         else {
537            max_layer = 0;
538         }
539      }
540   }
541   if (fb->zsbuf) {
542      struct pipe_surface *zsbuf = scene->fb.zsbuf;
543      max_layer = MIN2(max_layer, zsbuf->u.tex.last_layer - zsbuf->u.tex.first_layer);
544   }
545   scene->fb_max_layer = max_layer;
546}
547
548
549void lp_scene_end_binning( struct lp_scene *scene )
550{
551   if (LP_DEBUG & DEBUG_SCENE) {
552      debug_printf("rasterize scene:\n");
553      debug_printf("  scene_size: %u\n",
554                   scene->scene_size);
555      debug_printf("  data size: %u\n",
556                   lp_scene_data_size(scene));
557
558      if (0)
559         lp_debug_bins( scene );
560   }
561}
562