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   return scene;
68}
69
70
71/**
72 * Free all data associated with the given scene, and the scene itself.
73 */
74void
75lp_scene_destroy(struct lp_scene *scene)
76{
77   lp_fence_reference(&scene->fence, NULL);
78   pipe_mutex_destroy(scene->mutex);
79   assert(scene->data.head->next == NULL);
80   FREE(scene->data.head);
81   FREE(scene);
82}
83
84
85/**
86 * Check if the scene's bins are all empty.
87 * For debugging purposes.
88 */
89boolean
90lp_scene_is_empty(struct lp_scene *scene )
91{
92   unsigned x, y;
93
94   for (y = 0; y < TILES_Y; y++) {
95      for (x = 0; x < TILES_X; x++) {
96         const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
97         if (bin->head) {
98            return FALSE;
99         }
100      }
101   }
102   return TRUE;
103}
104
105
106/* Returns true if there has ever been a failed allocation attempt in
107 * this scene.  Used in triangle emit to avoid having to check success
108 * at each bin.
109 */
110boolean
111lp_scene_is_oom(struct lp_scene *scene)
112{
113   return scene->alloc_failed;
114}
115
116
117/* Remove all commands from a bin.  Tries to reuse some of the memory
118 * allocated to the bin, however.
119 */
120void
121lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
122{
123   struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
124
125   bin->last_state = NULL;
126   bin->head = bin->tail;
127   if (bin->tail) {
128      bin->tail->next = NULL;
129      bin->tail->count = 0;
130   }
131}
132
133
134void
135lp_scene_begin_rasterization(struct lp_scene *scene)
136{
137   const struct pipe_framebuffer_state *fb = &scene->fb;
138   int i;
139
140   //LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
141
142   for (i = 0; i < scene->fb.nr_cbufs; i++) {
143      struct pipe_surface *cbuf = scene->fb.cbufs[i];
144      assert(cbuf->u.tex.first_layer == cbuf->u.tex.last_layer);
145      scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture,
146                                                        cbuf->u.tex.level);
147
148      scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture,
149                                                  cbuf->u.tex.level,
150                                                  cbuf->u.tex.first_layer,
151                                                  LP_TEX_USAGE_READ_WRITE,
152                                                  LP_TEX_LAYOUT_LINEAR);
153   }
154
155   if (fb->zsbuf) {
156      struct pipe_surface *zsbuf = scene->fb.zsbuf;
157      assert(zsbuf->u.tex.first_layer == zsbuf->u.tex.last_layer);
158      scene->zsbuf.stride = llvmpipe_resource_stride(zsbuf->texture, zsbuf->u.tex.level);
159      scene->zsbuf.blocksize =
160         util_format_get_blocksize(zsbuf->texture->format);
161
162      scene->zsbuf.map = llvmpipe_resource_map(zsbuf->texture,
163                                               zsbuf->u.tex.level,
164                                               zsbuf->u.tex.first_layer,
165                                               LP_TEX_USAGE_READ_WRITE,
166                                               LP_TEX_LAYOUT_NONE);
167   }
168}
169
170
171
172
173/**
174 * Free all the temporary data in a scene.
175 */
176void
177lp_scene_end_rasterization(struct lp_scene *scene )
178{
179   int i, j;
180
181   /* Unmap color buffers */
182   for (i = 0; i < scene->fb.nr_cbufs; i++) {
183      if (scene->cbufs[i].map) {
184         struct pipe_surface *cbuf = scene->fb.cbufs[i];
185         llvmpipe_resource_unmap(cbuf->texture,
186                                 cbuf->u.tex.level,
187                                 cbuf->u.tex.first_layer);
188         scene->cbufs[i].map = NULL;
189      }
190   }
191
192   /* Unmap z/stencil buffer */
193   if (scene->zsbuf.map) {
194      struct pipe_surface *zsbuf = scene->fb.zsbuf;
195      llvmpipe_resource_unmap(zsbuf->texture,
196                              zsbuf->u.tex.level,
197                              zsbuf->u.tex.first_layer);
198      scene->zsbuf.map = NULL;
199   }
200
201   /* Reset all command lists:
202    */
203   for (i = 0; i < scene->tiles_x; i++) {
204      for (j = 0; j < scene->tiles_y; j++) {
205         struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
206         bin->head = NULL;
207         bin->tail = NULL;
208         bin->last_state = NULL;
209      }
210   }
211
212   /* If there are any bins which weren't cleared by the loop above,
213    * they will be caught (on debug builds at least) by this assert:
214    */
215   assert(lp_scene_is_empty(scene));
216
217   /* Decrement texture ref counts
218    */
219   {
220      struct resource_ref *ref;
221      int i, j = 0;
222
223      for (ref = scene->resources; ref; ref = ref->next) {
224         for (i = 0; i < ref->count; i++) {
225            if (LP_DEBUG & DEBUG_SETUP)
226               debug_printf("resource %d: %p %dx%d sz %d\n",
227                            j,
228                            (void *) ref->resource[i],
229                            ref->resource[i]->width0,
230                            ref->resource[i]->height0,
231                            llvmpipe_resource_size(ref->resource[i]));
232            j++;
233            pipe_resource_reference(&ref->resource[i], NULL);
234         }
235      }
236
237      if (LP_DEBUG & DEBUG_SETUP)
238         debug_printf("scene %d resources, sz %d\n",
239                      j, scene->resource_reference_size);
240   }
241
242   /* Free all scene data blocks:
243    */
244   {
245      struct data_block_list *list = &scene->data;
246      struct data_block *block, *tmp;
247
248      for (block = list->head->next; block; block = tmp) {
249         tmp = block->next;
250	 FREE(block);
251      }
252
253      list->head->next = NULL;
254      list->head->used = 0;
255   }
256
257   lp_fence_reference(&scene->fence, NULL);
258
259   scene->resources = NULL;
260   scene->scene_size = 0;
261   scene->resource_reference_size = 0;
262
263   scene->has_depthstencil_clear = FALSE;
264   scene->alloc_failed = FALSE;
265
266   util_unreference_framebuffer_state( &scene->fb );
267}
268
269
270
271
272
273
274struct cmd_block *
275lp_scene_new_cmd_block( struct lp_scene *scene,
276                        struct cmd_bin *bin )
277{
278   struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));
279   if (block) {
280      if (bin->tail) {
281         bin->tail->next = block;
282         bin->tail = block;
283      }
284      else {
285         bin->head = block;
286         bin->tail = block;
287      }
288      //memset(block, 0, sizeof *block);
289      block->next = NULL;
290      block->count = 0;
291   }
292   return block;
293}
294
295
296struct data_block *
297lp_scene_new_data_block( struct lp_scene *scene )
298{
299   if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) {
300      if (0) debug_printf("%s: failed\n", __FUNCTION__);
301      scene->alloc_failed = TRUE;
302      return NULL;
303   }
304   else {
305      struct data_block *block = MALLOC_STRUCT(data_block);
306      if (block == NULL)
307         return NULL;
308
309      scene->scene_size += sizeof *block;
310
311      block->used = 0;
312      block->next = scene->data.head;
313      scene->data.head = block;
314
315      return block;
316   }
317}
318
319
320/**
321 * Return number of bytes used for all bin data within a scene.
322 * This does not include resources (textures) referenced by the scene.
323 */
324static unsigned
325lp_scene_data_size( const struct lp_scene *scene )
326{
327   unsigned size = 0;
328   const struct data_block *block;
329   for (block = scene->data.head; block; block = block->next) {
330      size += block->used;
331   }
332   return size;
333}
334
335
336
337/**
338 * Add a reference to a resource by the scene.
339 */
340boolean
341lp_scene_add_resource_reference(struct lp_scene *scene,
342                                struct pipe_resource *resource,
343                                boolean initializing_scene)
344{
345   struct resource_ref *ref, **last = &scene->resources;
346   int i;
347
348   /* Look at existing resource blocks:
349    */
350   for (ref = scene->resources; ref; ref = ref->next) {
351      last = &ref->next;
352
353      /* Search for this resource:
354       */
355      for (i = 0; i < ref->count; i++)
356         if (ref->resource[i] == resource)
357            return TRUE;
358
359      if (ref->count < RESOURCE_REF_SZ) {
360         /* If the block is half-empty, then append the reference here.
361          */
362         break;
363      }
364   }
365
366   /* Create a new block if no half-empty block was found.
367    */
368   if (!ref) {
369      assert(*last == NULL);
370      *last = lp_scene_alloc(scene, sizeof *ref);
371      if (*last == NULL)
372          return FALSE;
373
374      ref = *last;
375      memset(ref, 0, sizeof *ref);
376   }
377
378   /* Append the reference to the reference block.
379    */
380   pipe_resource_reference(&ref->resource[ref->count++], resource);
381   scene->resource_reference_size += llvmpipe_resource_size(resource);
382
383   /* Heuristic to advise scene flushes.  This isn't helpful in the
384    * initial setup of the scene, but after that point flush on the
385    * next resource added which exceeds 64MB in referenced texture
386    * data.
387    */
388   if (!initializing_scene &&
389       scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE)
390      return FALSE;
391
392   return TRUE;
393}
394
395
396/**
397 * Does this scene have a reference to the given resource?
398 */
399boolean
400lp_scene_is_resource_referenced(const struct lp_scene *scene,
401                                const struct pipe_resource *resource)
402{
403   const struct resource_ref *ref;
404   int i;
405
406   for (ref = scene->resources; ref; ref = ref->next) {
407      for (i = 0; i < ref->count; i++)
408         if (ref->resource[i] == resource)
409            return TRUE;
410   }
411
412   return FALSE;
413}
414
415
416
417
418/** advance curr_x,y to the next bin */
419static boolean
420next_bin(struct lp_scene *scene)
421{
422   scene->curr_x++;
423   if (scene->curr_x >= scene->tiles_x) {
424      scene->curr_x = 0;
425      scene->curr_y++;
426   }
427   if (scene->curr_y >= scene->tiles_y) {
428      /* no more bins */
429      return FALSE;
430   }
431   return TRUE;
432}
433
434
435void
436lp_scene_bin_iter_begin( struct lp_scene *scene )
437{
438   scene->curr_x = scene->curr_y = -1;
439}
440
441
442/**
443 * Return pointer to next bin to be rendered.
444 * The lp_scene::curr_x and ::curr_y fields will be advanced.
445 * Multiple rendering threads will call this function to get a chunk
446 * of work (a bin) to work on.
447 */
448struct cmd_bin *
449lp_scene_bin_iter_next( struct lp_scene *scene )
450{
451   struct cmd_bin *bin = NULL;
452
453   pipe_mutex_lock(scene->mutex);
454
455   if (scene->curr_x < 0) {
456      /* first bin */
457      scene->curr_x = 0;
458      scene->curr_y = 0;
459   }
460   else if (!next_bin(scene)) {
461      /* no more bins left */
462      goto end;
463   }
464
465   bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
466
467end:
468   /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
469   pipe_mutex_unlock(scene->mutex);
470   return bin;
471}
472
473
474void lp_scene_begin_binning( struct lp_scene *scene,
475                             struct pipe_framebuffer_state *fb )
476{
477   assert(lp_scene_is_empty(scene));
478
479   util_copy_framebuffer_state(&scene->fb, fb);
480
481   scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;
482   scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE;
483
484   assert(scene->tiles_x <= TILES_X);
485   assert(scene->tiles_y <= TILES_Y);
486}
487
488
489void lp_scene_end_binning( struct lp_scene *scene )
490{
491   if (LP_DEBUG & DEBUG_SCENE) {
492      debug_printf("rasterize scene:\n");
493      debug_printf("  scene_size: %u\n",
494                   scene->scene_size);
495      debug_printf("  data size: %u\n",
496                   lp_scene_data_size(scene));
497
498      if (0)
499         lp_debug_bins( scene );
500   }
501}
502