1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2009 VMware, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "util/u_framebuffer.h"
29bf215546Sopenharmony_ci#include "util/u_math.h"
30bf215546Sopenharmony_ci#include "util/u_memory.h"
31bf215546Sopenharmony_ci#include "util/reallocarray.h"
32bf215546Sopenharmony_ci#include "util/u_inlines.h"
33bf215546Sopenharmony_ci#include "util/format/u_format.h"
34bf215546Sopenharmony_ci#include "lp_scene.h"
35bf215546Sopenharmony_ci#include "lp_fence.h"
36bf215546Sopenharmony_ci#include "lp_debug.h"
37bf215546Sopenharmony_ci#include "lp_context.h"
38bf215546Sopenharmony_ci#include "lp_state_fs.h"
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci#include "lp_setup_context.h"
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci#define RESOURCE_REF_SZ 32
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci/** List of resource references */
45bf215546Sopenharmony_cistruct resource_ref {
46bf215546Sopenharmony_ci   struct pipe_resource *resource[RESOURCE_REF_SZ];
47bf215546Sopenharmony_ci   int count;
48bf215546Sopenharmony_ci   struct resource_ref *next;
49bf215546Sopenharmony_ci};
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci#define SHADER_REF_SZ 32
52bf215546Sopenharmony_ci/** List of shader variant references */
53bf215546Sopenharmony_cistruct shader_ref {
54bf215546Sopenharmony_ci   struct lp_fragment_shader_variant *variant[SHADER_REF_SZ];
55bf215546Sopenharmony_ci   int count;
56bf215546Sopenharmony_ci   struct shader_ref *next;
57bf215546Sopenharmony_ci};
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci/**
61bf215546Sopenharmony_ci * Create a new scene object.
62bf215546Sopenharmony_ci * \param queue  the queue to put newly rendered/emptied scenes into
63bf215546Sopenharmony_ci */
64bf215546Sopenharmony_cistruct lp_scene *
65bf215546Sopenharmony_cilp_scene_create(struct lp_setup_context *setup)
66bf215546Sopenharmony_ci{
67bf215546Sopenharmony_ci   struct lp_scene *scene = slab_alloc_st(&setup->scene_slab);
68bf215546Sopenharmony_ci   if (!scene)
69bf215546Sopenharmony_ci      return NULL;
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   memset(scene, 0, sizeof(struct lp_scene));
72bf215546Sopenharmony_ci   scene->pipe = setup->pipe;
73bf215546Sopenharmony_ci   scene->setup = setup;
74bf215546Sopenharmony_ci   scene->data.head = &scene->data.first;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   (void) mtx_init(&scene->mutex, mtx_plain);
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci#ifdef DEBUG
79bf215546Sopenharmony_ci   /* Do some scene limit sanity checks here */
80bf215546Sopenharmony_ci   {
81bf215546Sopenharmony_ci      size_t maxBins = TILES_X * TILES_Y;
82bf215546Sopenharmony_ci      size_t maxCommandBytes = sizeof(struct cmd_block) * maxBins;
83bf215546Sopenharmony_ci      size_t maxCommandPlusData = maxCommandBytes + DATA_BLOCK_SIZE;
84bf215546Sopenharmony_ci      /* We'll need at least one command block per bin.  Make sure that's
85bf215546Sopenharmony_ci       * less than the max allowed scene size.
86bf215546Sopenharmony_ci       */
87bf215546Sopenharmony_ci      assert(maxCommandBytes < LP_SCENE_MAX_SIZE);
88bf215546Sopenharmony_ci      /* We'll also need space for at least one other data block */
89bf215546Sopenharmony_ci      assert(maxCommandPlusData <= LP_SCENE_MAX_SIZE);
90bf215546Sopenharmony_ci   }
91bf215546Sopenharmony_ci#endif
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci   return scene;
94bf215546Sopenharmony_ci}
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci/**
98bf215546Sopenharmony_ci * Free all data associated with the given scene, and the scene itself.
99bf215546Sopenharmony_ci */
100bf215546Sopenharmony_civoid
101bf215546Sopenharmony_cilp_scene_destroy(struct lp_scene *scene)
102bf215546Sopenharmony_ci{
103bf215546Sopenharmony_ci   lp_scene_end_rasterization(scene);
104bf215546Sopenharmony_ci   mtx_destroy(&scene->mutex);
105bf215546Sopenharmony_ci   free(scene->tiles);
106bf215546Sopenharmony_ci   assert(scene->data.head == &scene->data.first);
107bf215546Sopenharmony_ci   slab_free_st(&scene->setup->scene_slab, scene);
108bf215546Sopenharmony_ci}
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci/**
112bf215546Sopenharmony_ci * Check if the scene's bins are all empty.
113bf215546Sopenharmony_ci * For debugging purposes.
114bf215546Sopenharmony_ci */
115bf215546Sopenharmony_ciboolean
116bf215546Sopenharmony_cilp_scene_is_empty(struct lp_scene *scene )
117bf215546Sopenharmony_ci{
118bf215546Sopenharmony_ci   unsigned x, y;
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   for (y = 0; y < scene->tiles_y; y++) {
121bf215546Sopenharmony_ci      for (x = 0; x < scene->tiles_x; x++) {
122bf215546Sopenharmony_ci         const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
123bf215546Sopenharmony_ci         if (bin->head) {
124bf215546Sopenharmony_ci            return FALSE;
125bf215546Sopenharmony_ci         }
126bf215546Sopenharmony_ci      }
127bf215546Sopenharmony_ci   }
128bf215546Sopenharmony_ci   return TRUE;
129bf215546Sopenharmony_ci}
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci/* Returns true if there has ever been a failed allocation attempt in
133bf215546Sopenharmony_ci * this scene.  Used in triangle/rectangle emit to avoid having to
134bf215546Sopenharmony_ci * check success at each bin.
135bf215546Sopenharmony_ci */
136bf215546Sopenharmony_ciboolean
137bf215546Sopenharmony_cilp_scene_is_oom(struct lp_scene *scene)
138bf215546Sopenharmony_ci{
139bf215546Sopenharmony_ci   return scene->alloc_failed;
140bf215546Sopenharmony_ci}
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci/* Remove all commands from a bin.  Tries to reuse some of the memory
144bf215546Sopenharmony_ci * allocated to the bin, however.
145bf215546Sopenharmony_ci */
146bf215546Sopenharmony_civoid
147bf215546Sopenharmony_cilp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
148bf215546Sopenharmony_ci{
149bf215546Sopenharmony_ci   struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci   bin->last_state = NULL;
152bf215546Sopenharmony_ci   bin->head = bin->tail;
153bf215546Sopenharmony_ci   if (bin->tail) {
154bf215546Sopenharmony_ci      bin->tail->next = NULL;
155bf215546Sopenharmony_ci      bin->tail->count = 0;
156bf215546Sopenharmony_ci   }
157bf215546Sopenharmony_ci}
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_cistatic void
160bf215546Sopenharmony_ciinit_scene_texture(struct lp_scene_surface *ssurf, struct pipe_surface *psurf)
161bf215546Sopenharmony_ci{
162bf215546Sopenharmony_ci   if (!psurf) {
163bf215546Sopenharmony_ci      ssurf->stride = 0;
164bf215546Sopenharmony_ci      ssurf->layer_stride = 0;
165bf215546Sopenharmony_ci      ssurf->sample_stride = 0;
166bf215546Sopenharmony_ci      ssurf->nr_samples = 0;
167bf215546Sopenharmony_ci      ssurf->map = NULL;
168bf215546Sopenharmony_ci      return;
169bf215546Sopenharmony_ci   }
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   if (llvmpipe_resource_is_texture(psurf->texture)) {
172bf215546Sopenharmony_ci      ssurf->stride = llvmpipe_resource_stride(psurf->texture,
173bf215546Sopenharmony_ci                                               psurf->u.tex.level);
174bf215546Sopenharmony_ci      ssurf->layer_stride = llvmpipe_layer_stride(psurf->texture,
175bf215546Sopenharmony_ci                                                           psurf->u.tex.level);
176bf215546Sopenharmony_ci      ssurf->sample_stride = llvmpipe_sample_stride(psurf->texture);
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci      ssurf->map = llvmpipe_resource_map(psurf->texture,
179bf215546Sopenharmony_ci                                         psurf->u.tex.level,
180bf215546Sopenharmony_ci                                         psurf->u.tex.first_layer,
181bf215546Sopenharmony_ci                                         LP_TEX_USAGE_READ_WRITE);
182bf215546Sopenharmony_ci      ssurf->format_bytes = util_format_get_blocksize(psurf->format);
183bf215546Sopenharmony_ci      ssurf->nr_samples = util_res_sample_count(psurf->texture);
184bf215546Sopenharmony_ci   }
185bf215546Sopenharmony_ci   else {
186bf215546Sopenharmony_ci      struct llvmpipe_resource *lpr = llvmpipe_resource(psurf->texture);
187bf215546Sopenharmony_ci      unsigned pixstride = util_format_get_blocksize(psurf->format);
188bf215546Sopenharmony_ci      ssurf->stride = psurf->texture->width0;
189bf215546Sopenharmony_ci      ssurf->layer_stride = 0;
190bf215546Sopenharmony_ci      ssurf->sample_stride = 0;
191bf215546Sopenharmony_ci      ssurf->nr_samples = 1;
192bf215546Sopenharmony_ci      ssurf->map = lpr->data;
193bf215546Sopenharmony_ci      ssurf->map += psurf->u.buf.first_element * pixstride;
194bf215546Sopenharmony_ci      ssurf->format_bytes = util_format_get_blocksize(psurf->format);
195bf215546Sopenharmony_ci   }
196bf215546Sopenharmony_ci}
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_civoid
199bf215546Sopenharmony_cilp_scene_begin_rasterization(struct lp_scene *scene)
200bf215546Sopenharmony_ci{
201bf215546Sopenharmony_ci   const struct pipe_framebuffer_state *fb = &scene->fb;
202bf215546Sopenharmony_ci   int i;
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   //LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   for (i = 0; i < scene->fb.nr_cbufs; i++) {
207bf215546Sopenharmony_ci      struct pipe_surface *cbuf = scene->fb.cbufs[i];
208bf215546Sopenharmony_ci      init_scene_texture(&scene->cbufs[i], cbuf);
209bf215546Sopenharmony_ci   }
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci   if (fb->zsbuf) {
212bf215546Sopenharmony_ci      struct pipe_surface *zsbuf = scene->fb.zsbuf;
213bf215546Sopenharmony_ci      init_scene_texture(&scene->zsbuf, zsbuf);
214bf215546Sopenharmony_ci   }
215bf215546Sopenharmony_ci}
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci/**
219bf215546Sopenharmony_ci * Free all the temporary data in a scene.
220bf215546Sopenharmony_ci */
221bf215546Sopenharmony_civoid
222bf215546Sopenharmony_cilp_scene_end_rasterization(struct lp_scene *scene )
223bf215546Sopenharmony_ci{
224bf215546Sopenharmony_ci   int i;
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci   /* Unmap color buffers */
227bf215546Sopenharmony_ci   for (i = 0; i < scene->fb.nr_cbufs; i++) {
228bf215546Sopenharmony_ci      if (scene->cbufs[i].map) {
229bf215546Sopenharmony_ci         struct pipe_surface *cbuf = scene->fb.cbufs[i];
230bf215546Sopenharmony_ci         if (llvmpipe_resource_is_texture(cbuf->texture)) {
231bf215546Sopenharmony_ci            llvmpipe_resource_unmap(cbuf->texture,
232bf215546Sopenharmony_ci                                    cbuf->u.tex.level,
233bf215546Sopenharmony_ci                                    cbuf->u.tex.first_layer);
234bf215546Sopenharmony_ci         }
235bf215546Sopenharmony_ci         scene->cbufs[i].map = NULL;
236bf215546Sopenharmony_ci      }
237bf215546Sopenharmony_ci   }
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci   /* Unmap z/stencil buffer */
240bf215546Sopenharmony_ci   if (scene->zsbuf.map) {
241bf215546Sopenharmony_ci      struct pipe_surface *zsbuf = scene->fb.zsbuf;
242bf215546Sopenharmony_ci      llvmpipe_resource_unmap(zsbuf->texture,
243bf215546Sopenharmony_ci                              zsbuf->u.tex.level,
244bf215546Sopenharmony_ci                              zsbuf->u.tex.first_layer);
245bf215546Sopenharmony_ci      scene->zsbuf.map = NULL;
246bf215546Sopenharmony_ci   }
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   /* Reset all command lists:
249bf215546Sopenharmony_ci    */
250bf215546Sopenharmony_ci   memset(scene->tiles, 0, sizeof(struct cmd_bin) * scene->num_alloced_tiles);
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci   /* Decrement texture ref counts
253bf215546Sopenharmony_ci    */
254bf215546Sopenharmony_ci   int j = 0;
255bf215546Sopenharmony_ci   for (struct resource_ref *ref = scene->resources; ref; ref = ref->next) {
256bf215546Sopenharmony_ci      for (int i = 0; i < ref->count; i++) {
257bf215546Sopenharmony_ci         if (LP_DEBUG & DEBUG_SETUP)
258bf215546Sopenharmony_ci            debug_printf("resource %d: %p %dx%d sz %d\n",
259bf215546Sopenharmony_ci                         j,
260bf215546Sopenharmony_ci                         (void *) ref->resource[i],
261bf215546Sopenharmony_ci                         ref->resource[i]->width0,
262bf215546Sopenharmony_ci                         ref->resource[i]->height0,
263bf215546Sopenharmony_ci                         llvmpipe_resource_size(ref->resource[i]));
264bf215546Sopenharmony_ci         j++;
265bf215546Sopenharmony_ci         llvmpipe_resource_unmap(ref->resource[i], 0, 0);
266bf215546Sopenharmony_ci         pipe_resource_reference(&ref->resource[i], NULL);
267bf215546Sopenharmony_ci      }
268bf215546Sopenharmony_ci   }
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   for (struct resource_ref *ref = scene->writeable_resources; ref;
271bf215546Sopenharmony_ci        ref = ref->next) {
272bf215546Sopenharmony_ci      for (int i = 0; i < ref->count; i++) {
273bf215546Sopenharmony_ci         if (LP_DEBUG & DEBUG_SETUP)
274bf215546Sopenharmony_ci            debug_printf("resource %d: %p %dx%d sz %d\n",
275bf215546Sopenharmony_ci                         j,
276bf215546Sopenharmony_ci                         (void *) ref->resource[i],
277bf215546Sopenharmony_ci                         ref->resource[i]->width0,
278bf215546Sopenharmony_ci                            ref->resource[i]->height0,
279bf215546Sopenharmony_ci                         llvmpipe_resource_size(ref->resource[i]));
280bf215546Sopenharmony_ci         j++;
281bf215546Sopenharmony_ci         llvmpipe_resource_unmap(ref->resource[i], 0, 0);
282bf215546Sopenharmony_ci         pipe_resource_reference(&ref->resource[i], NULL);
283bf215546Sopenharmony_ci      }
284bf215546Sopenharmony_ci   }
285bf215546Sopenharmony_ci
286bf215546Sopenharmony_ci   if (LP_DEBUG & DEBUG_SETUP) {
287bf215546Sopenharmony_ci      debug_printf("scene %d resources, sz %d\n",
288bf215546Sopenharmony_ci                   j, scene->resource_reference_size);
289bf215546Sopenharmony_ci   }
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci   /* Decrement shader variant ref counts
292bf215546Sopenharmony_ci    */
293bf215546Sopenharmony_ci   j = 0;
294bf215546Sopenharmony_ci   for (struct shader_ref *ref = scene->frag_shaders; ref; ref = ref->next) {
295bf215546Sopenharmony_ci      for (i = 0; i < ref->count; i++) {
296bf215546Sopenharmony_ci         if (LP_DEBUG & DEBUG_SETUP)
297bf215546Sopenharmony_ci            debug_printf("shader %d: %p\n", j, (void *) ref->variant[i]);
298bf215546Sopenharmony_ci         j++;
299bf215546Sopenharmony_ci         lp_fs_variant_reference(llvmpipe_context(scene->pipe),
300bf215546Sopenharmony_ci                                 &ref->variant[i], NULL);
301bf215546Sopenharmony_ci      }
302bf215546Sopenharmony_ci   }
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   /* Free all scene data blocks:
305bf215546Sopenharmony_ci    */
306bf215546Sopenharmony_ci   {
307bf215546Sopenharmony_ci      struct data_block_list *list = &scene->data;
308bf215546Sopenharmony_ci      struct data_block *block, *tmp;
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci      for (block = list->head; block; block = tmp) {
311bf215546Sopenharmony_ci         tmp = block->next;
312bf215546Sopenharmony_ci         if (block != &list->first)
313bf215546Sopenharmony_ci            FREE(block);
314bf215546Sopenharmony_ci      }
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_ci      list->head = &list->first;
317bf215546Sopenharmony_ci      list->head->next = NULL;
318bf215546Sopenharmony_ci   }
319bf215546Sopenharmony_ci
320bf215546Sopenharmony_ci   lp_fence_reference(&scene->fence, NULL);
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci   scene->resources = NULL;
323bf215546Sopenharmony_ci   scene->writeable_resources = NULL;
324bf215546Sopenharmony_ci   scene->frag_shaders = NULL;
325bf215546Sopenharmony_ci   scene->scene_size = 0;
326bf215546Sopenharmony_ci   scene->resource_reference_size = 0;
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci   scene->alloc_failed = FALSE;
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci   util_unreference_framebuffer_state( &scene->fb );
331bf215546Sopenharmony_ci}
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_cistruct cmd_block *
339bf215546Sopenharmony_cilp_scene_new_cmd_block( struct lp_scene *scene,
340bf215546Sopenharmony_ci                        struct cmd_bin *bin )
341bf215546Sopenharmony_ci{
342bf215546Sopenharmony_ci   struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));
343bf215546Sopenharmony_ci   if (block) {
344bf215546Sopenharmony_ci      if (bin->tail) {
345bf215546Sopenharmony_ci         bin->tail->next = block;
346bf215546Sopenharmony_ci         bin->tail = block;
347bf215546Sopenharmony_ci      }
348bf215546Sopenharmony_ci      else {
349bf215546Sopenharmony_ci         bin->head = block;
350bf215546Sopenharmony_ci         bin->tail = block;
351bf215546Sopenharmony_ci      }
352bf215546Sopenharmony_ci      //memset(block, 0, sizeof *block);
353bf215546Sopenharmony_ci      block->next = NULL;
354bf215546Sopenharmony_ci      block->count = 0;
355bf215546Sopenharmony_ci   }
356bf215546Sopenharmony_ci   return block;
357bf215546Sopenharmony_ci}
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_cistruct data_block *
361bf215546Sopenharmony_cilp_scene_new_data_block( struct lp_scene *scene )
362bf215546Sopenharmony_ci{
363bf215546Sopenharmony_ci   if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) {
364bf215546Sopenharmony_ci      if (0) debug_printf("%s: failed\n", __FUNCTION__);
365bf215546Sopenharmony_ci      scene->alloc_failed = TRUE;
366bf215546Sopenharmony_ci      return NULL;
367bf215546Sopenharmony_ci   }
368bf215546Sopenharmony_ci   else {
369bf215546Sopenharmony_ci      struct data_block *block = MALLOC_STRUCT(data_block);
370bf215546Sopenharmony_ci      if (!block)
371bf215546Sopenharmony_ci         return NULL;
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_ci      scene->scene_size += sizeof *block;
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci      block->used = 0;
376bf215546Sopenharmony_ci      block->next = scene->data.head;
377bf215546Sopenharmony_ci      scene->data.head = block;
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_ci      return block;
380bf215546Sopenharmony_ci   }
381bf215546Sopenharmony_ci}
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci/**
385bf215546Sopenharmony_ci * Return number of bytes used for all bin data within a scene.
386bf215546Sopenharmony_ci * This does not include resources (textures) referenced by the scene.
387bf215546Sopenharmony_ci */
388bf215546Sopenharmony_cistatic unsigned
389bf215546Sopenharmony_cilp_scene_data_size( const struct lp_scene *scene )
390bf215546Sopenharmony_ci{
391bf215546Sopenharmony_ci   unsigned size = 0;
392bf215546Sopenharmony_ci   const struct data_block *block;
393bf215546Sopenharmony_ci   for (block = scene->data.head; block; block = block->next) {
394bf215546Sopenharmony_ci      size += block->used;
395bf215546Sopenharmony_ci   }
396bf215546Sopenharmony_ci   return size;
397bf215546Sopenharmony_ci}
398bf215546Sopenharmony_ci
399bf215546Sopenharmony_ci
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_ci/**
402bf215546Sopenharmony_ci * Add a reference to a resource by the scene.
403bf215546Sopenharmony_ci */
404bf215546Sopenharmony_ciboolean
405bf215546Sopenharmony_cilp_scene_add_resource_reference(struct lp_scene *scene,
406bf215546Sopenharmony_ci                                struct pipe_resource *resource,
407bf215546Sopenharmony_ci                                boolean initializing_scene,
408bf215546Sopenharmony_ci                                boolean writeable)
409bf215546Sopenharmony_ci{
410bf215546Sopenharmony_ci   struct resource_ref *ref;
411bf215546Sopenharmony_ci   int i;
412bf215546Sopenharmony_ci   struct resource_ref **list = writeable ? &scene->writeable_resources : &scene->resources;
413bf215546Sopenharmony_ci   struct resource_ref **last = list;
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci   /* Look at existing resource blocks:
416bf215546Sopenharmony_ci    */
417bf215546Sopenharmony_ci   for (ref = *list; ref; ref = ref->next) {
418bf215546Sopenharmony_ci      last = &ref->next;
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci      /* Search for this resource:
421bf215546Sopenharmony_ci       */
422bf215546Sopenharmony_ci      for (i = 0; i < ref->count; i++)
423bf215546Sopenharmony_ci         if (ref->resource[i] == resource)
424bf215546Sopenharmony_ci            return TRUE;
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_ci      if (ref->count < RESOURCE_REF_SZ) {
427bf215546Sopenharmony_ci         /* If the block is half-empty, then append the reference here.
428bf215546Sopenharmony_ci          */
429bf215546Sopenharmony_ci         break;
430bf215546Sopenharmony_ci      }
431bf215546Sopenharmony_ci   }
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   /* Create a new block if no half-empty block was found.
434bf215546Sopenharmony_ci    */
435bf215546Sopenharmony_ci   if (!ref) {
436bf215546Sopenharmony_ci      assert(*last == NULL);
437bf215546Sopenharmony_ci      *last = lp_scene_alloc(scene, sizeof *ref);
438bf215546Sopenharmony_ci      if (*last == NULL)
439bf215546Sopenharmony_ci          return FALSE;
440bf215546Sopenharmony_ci
441bf215546Sopenharmony_ci      ref = *last;
442bf215546Sopenharmony_ci      memset(ref, 0, sizeof *ref);
443bf215546Sopenharmony_ci   }
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci   /* Map resource again to increment the map count. We likely use the
446bf215546Sopenharmony_ci    * already-mapped pointer in a texture of the jit context, and that pointer
447bf215546Sopenharmony_ci    * needs to stay mapped during rasterization. This map is unmap'ed when
448bf215546Sopenharmony_ci    * finalizing scene rasterization. */
449bf215546Sopenharmony_ci   llvmpipe_resource_map(resource, 0, 0, LP_TEX_USAGE_READ);
450bf215546Sopenharmony_ci
451bf215546Sopenharmony_ci   /* Append the reference to the reference block.
452bf215546Sopenharmony_ci    */
453bf215546Sopenharmony_ci   pipe_resource_reference(&ref->resource[ref->count++], resource);
454bf215546Sopenharmony_ci   scene->resource_reference_size += llvmpipe_resource_size(resource);
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   /* Heuristic to advise scene flushes.  This isn't helpful in the
457bf215546Sopenharmony_ci    * initial setup of the scene, but after that point flush on the
458bf215546Sopenharmony_ci    * next resource added which exceeds 64MB in referenced texture
459bf215546Sopenharmony_ci    * data.
460bf215546Sopenharmony_ci    */
461bf215546Sopenharmony_ci   if (!initializing_scene &&
462bf215546Sopenharmony_ci       scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE)
463bf215546Sopenharmony_ci      return FALSE;
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci   return TRUE;
466bf215546Sopenharmony_ci}
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ci/**
470bf215546Sopenharmony_ci * Add a reference to a fragment shader variant
471bf215546Sopenharmony_ci * Return FALSE if out of memory, TRUE otherwise.
472bf215546Sopenharmony_ci */
473bf215546Sopenharmony_ciboolean
474bf215546Sopenharmony_cilp_scene_add_frag_shader_reference(struct lp_scene *scene,
475bf215546Sopenharmony_ci                                   struct lp_fragment_shader_variant *variant)
476bf215546Sopenharmony_ci{
477bf215546Sopenharmony_ci   struct shader_ref *ref, **last = &scene->frag_shaders;
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_ci   /* Look at existing resource blocks:
480bf215546Sopenharmony_ci    */
481bf215546Sopenharmony_ci   for (ref = scene->frag_shaders; ref; ref = ref->next) {
482bf215546Sopenharmony_ci      last = &ref->next;
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ci      /* Search for this resource:
485bf215546Sopenharmony_ci       */
486bf215546Sopenharmony_ci      for (int i = 0; i < ref->count; i++)
487bf215546Sopenharmony_ci         if (ref->variant[i] == variant)
488bf215546Sopenharmony_ci            return TRUE;
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_ci      if (ref->count < SHADER_REF_SZ) {
491bf215546Sopenharmony_ci         /* If the block is half-empty, then append the reference here.
492bf215546Sopenharmony_ci          */
493bf215546Sopenharmony_ci         break;
494bf215546Sopenharmony_ci      }
495bf215546Sopenharmony_ci   }
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci   /* Create a new block if no half-empty block was found.
498bf215546Sopenharmony_ci    */
499bf215546Sopenharmony_ci   if (!ref) {
500bf215546Sopenharmony_ci      assert(*last == NULL);
501bf215546Sopenharmony_ci      *last = lp_scene_alloc(scene, sizeof *ref);
502bf215546Sopenharmony_ci      if (*last == NULL)
503bf215546Sopenharmony_ci          return FALSE;
504bf215546Sopenharmony_ci
505bf215546Sopenharmony_ci      ref = *last;
506bf215546Sopenharmony_ci      memset(ref, 0, sizeof *ref);
507bf215546Sopenharmony_ci   }
508bf215546Sopenharmony_ci
509bf215546Sopenharmony_ci   /* Append the reference to the reference block.
510bf215546Sopenharmony_ci    */
511bf215546Sopenharmony_ci   lp_fs_variant_reference(llvmpipe_context(scene->pipe), &ref->variant[ref->count++], variant);
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci   return TRUE;
514bf215546Sopenharmony_ci}
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_ci/**
517bf215546Sopenharmony_ci * Does this scene have a reference to the given resource?
518bf215546Sopenharmony_ci */
519bf215546Sopenharmony_ciunsigned
520bf215546Sopenharmony_cilp_scene_is_resource_referenced(const struct lp_scene *scene,
521bf215546Sopenharmony_ci                                const struct pipe_resource *resource)
522bf215546Sopenharmony_ci{
523bf215546Sopenharmony_ci   const struct resource_ref *ref;
524bf215546Sopenharmony_ci   int i;
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_ci   for (ref = scene->resources; ref; ref = ref->next) {
527bf215546Sopenharmony_ci      for (i = 0; i < ref->count; i++)
528bf215546Sopenharmony_ci         if (ref->resource[i] == resource)
529bf215546Sopenharmony_ci            return LP_REFERENCED_FOR_READ;
530bf215546Sopenharmony_ci   }
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_ci   for (ref = scene->writeable_resources; ref; ref = ref->next) {
533bf215546Sopenharmony_ci      for (i = 0; i < ref->count; i++)
534bf215546Sopenharmony_ci         if (ref->resource[i] == resource)
535bf215546Sopenharmony_ci            return LP_REFERENCED_FOR_READ | LP_REFERENCED_FOR_WRITE;
536bf215546Sopenharmony_ci   }
537bf215546Sopenharmony_ci
538bf215546Sopenharmony_ci   return 0;
539bf215546Sopenharmony_ci}
540bf215546Sopenharmony_ci
541bf215546Sopenharmony_ci
542bf215546Sopenharmony_ci
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_ci/** advance curr_x,y to the next bin */
545bf215546Sopenharmony_cistatic boolean
546bf215546Sopenharmony_cinext_bin(struct lp_scene *scene)
547bf215546Sopenharmony_ci{
548bf215546Sopenharmony_ci   scene->curr_x++;
549bf215546Sopenharmony_ci   if (scene->curr_x >= scene->tiles_x) {
550bf215546Sopenharmony_ci      scene->curr_x = 0;
551bf215546Sopenharmony_ci      scene->curr_y++;
552bf215546Sopenharmony_ci   }
553bf215546Sopenharmony_ci   if (scene->curr_y >= scene->tiles_y) {
554bf215546Sopenharmony_ci      /* no more bins */
555bf215546Sopenharmony_ci      return FALSE;
556bf215546Sopenharmony_ci   }
557bf215546Sopenharmony_ci   return TRUE;
558bf215546Sopenharmony_ci}
559bf215546Sopenharmony_ci
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_civoid
562bf215546Sopenharmony_cilp_scene_bin_iter_begin( struct lp_scene *scene )
563bf215546Sopenharmony_ci{
564bf215546Sopenharmony_ci   scene->curr_x = scene->curr_y = -1;
565bf215546Sopenharmony_ci}
566bf215546Sopenharmony_ci
567bf215546Sopenharmony_ci
568bf215546Sopenharmony_ci/**
569bf215546Sopenharmony_ci * Return pointer to next bin to be rendered.
570bf215546Sopenharmony_ci * The lp_scene::curr_x and ::curr_y fields will be advanced.
571bf215546Sopenharmony_ci * Multiple rendering threads will call this function to get a chunk
572bf215546Sopenharmony_ci * of work (a bin) to work on.
573bf215546Sopenharmony_ci */
574bf215546Sopenharmony_cistruct cmd_bin *
575bf215546Sopenharmony_cilp_scene_bin_iter_next( struct lp_scene *scene , int *x, int *y)
576bf215546Sopenharmony_ci{
577bf215546Sopenharmony_ci   struct cmd_bin *bin = NULL;
578bf215546Sopenharmony_ci
579bf215546Sopenharmony_ci   mtx_lock(&scene->mutex);
580bf215546Sopenharmony_ci
581bf215546Sopenharmony_ci   if (scene->curr_x < 0) {
582bf215546Sopenharmony_ci      /* first bin */
583bf215546Sopenharmony_ci      scene->curr_x = 0;
584bf215546Sopenharmony_ci      scene->curr_y = 0;
585bf215546Sopenharmony_ci   }
586bf215546Sopenharmony_ci   else if (!next_bin(scene)) {
587bf215546Sopenharmony_ci      /* no more bins left */
588bf215546Sopenharmony_ci      goto end;
589bf215546Sopenharmony_ci   }
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci   bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
592bf215546Sopenharmony_ci   *x = scene->curr_x;
593bf215546Sopenharmony_ci   *y = scene->curr_y;
594bf215546Sopenharmony_ci
595bf215546Sopenharmony_ciend:
596bf215546Sopenharmony_ci   /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
597bf215546Sopenharmony_ci   mtx_unlock(&scene->mutex);
598bf215546Sopenharmony_ci   return bin;
599bf215546Sopenharmony_ci}
600bf215546Sopenharmony_ci
601bf215546Sopenharmony_ci
602bf215546Sopenharmony_civoid lp_scene_begin_binning(struct lp_scene *scene,
603bf215546Sopenharmony_ci                            struct pipe_framebuffer_state *fb)
604bf215546Sopenharmony_ci{
605bf215546Sopenharmony_ci   int i;
606bf215546Sopenharmony_ci   unsigned max_layer = ~0;
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci   assert(lp_scene_is_empty(scene));
609bf215546Sopenharmony_ci
610bf215546Sopenharmony_ci   util_copy_framebuffer_state(&scene->fb, fb);
611bf215546Sopenharmony_ci
612bf215546Sopenharmony_ci   scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;
613bf215546Sopenharmony_ci   scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE;
614bf215546Sopenharmony_ci   assert(scene->tiles_x <= TILES_X);
615bf215546Sopenharmony_ci   assert(scene->tiles_y <= TILES_Y);
616bf215546Sopenharmony_ci
617bf215546Sopenharmony_ci   unsigned num_required_tiles = scene->tiles_x * scene->tiles_y;
618bf215546Sopenharmony_ci   if (scene->num_alloced_tiles < num_required_tiles) {
619bf215546Sopenharmony_ci      scene->tiles = reallocarray(scene->tiles, num_required_tiles, sizeof(struct cmd_bin));
620bf215546Sopenharmony_ci      if (!scene->tiles)
621bf215546Sopenharmony_ci         return;
622bf215546Sopenharmony_ci      memset(scene->tiles, 0, sizeof(struct cmd_bin) * num_required_tiles);
623bf215546Sopenharmony_ci      scene->num_alloced_tiles = num_required_tiles;
624bf215546Sopenharmony_ci   }
625bf215546Sopenharmony_ci
626bf215546Sopenharmony_ci   /*
627bf215546Sopenharmony_ci    * Determine how many layers the fb has (used for clamping layer value).
628bf215546Sopenharmony_ci    * OpenGL (but not d3d10) permits different amount of layers per rt, however
629bf215546Sopenharmony_ci    * results are undefined if layer exceeds the amount of layers of ANY
630bf215546Sopenharmony_ci    * attachment hence don't need separate per cbuf and zsbuf max.
631bf215546Sopenharmony_ci    */
632bf215546Sopenharmony_ci   for (i = 0; i < scene->fb.nr_cbufs; i++) {
633bf215546Sopenharmony_ci      struct pipe_surface *cbuf = scene->fb.cbufs[i];
634bf215546Sopenharmony_ci      if (cbuf) {
635bf215546Sopenharmony_ci         if (llvmpipe_resource_is_texture(cbuf->texture)) {
636bf215546Sopenharmony_ci            max_layer = MIN2(max_layer,
637bf215546Sopenharmony_ci                             cbuf->u.tex.last_layer - cbuf->u.tex.first_layer);
638bf215546Sopenharmony_ci         }
639bf215546Sopenharmony_ci         else {
640bf215546Sopenharmony_ci            max_layer = 0;
641bf215546Sopenharmony_ci         }
642bf215546Sopenharmony_ci      }
643bf215546Sopenharmony_ci   }
644bf215546Sopenharmony_ci   if (fb->zsbuf) {
645bf215546Sopenharmony_ci      struct pipe_surface *zsbuf = scene->fb.zsbuf;
646bf215546Sopenharmony_ci      max_layer = MIN2(max_layer, zsbuf->u.tex.last_layer - zsbuf->u.tex.first_layer);
647bf215546Sopenharmony_ci   }
648bf215546Sopenharmony_ci   scene->fb_max_layer = max_layer;
649bf215546Sopenharmony_ci   scene->fb_max_samples = util_framebuffer_get_num_samples(fb);
650bf215546Sopenharmony_ci   if (scene->fb_max_samples == 4) {
651bf215546Sopenharmony_ci      for (unsigned i = 0; i < 4; i++) {
652bf215546Sopenharmony_ci         scene->fixed_sample_pos[i][0] = util_iround(lp_sample_pos_4x[i][0] * FIXED_ONE);
653bf215546Sopenharmony_ci         scene->fixed_sample_pos[i][1] = util_iround(lp_sample_pos_4x[i][1] * FIXED_ONE);
654bf215546Sopenharmony_ci      }
655bf215546Sopenharmony_ci   }
656bf215546Sopenharmony_ci}
657bf215546Sopenharmony_ci
658bf215546Sopenharmony_ci
659bf215546Sopenharmony_civoid lp_scene_end_binning( struct lp_scene *scene )
660bf215546Sopenharmony_ci{
661bf215546Sopenharmony_ci   if (LP_DEBUG & DEBUG_SCENE) {
662bf215546Sopenharmony_ci      debug_printf("rasterize scene:\n");
663bf215546Sopenharmony_ci      debug_printf("  scene_size: %u\n",
664bf215546Sopenharmony_ci                   scene->scene_size);
665bf215546Sopenharmony_ci      debug_printf("  data size: %u\n",
666bf215546Sopenharmony_ci                   lp_scene_data_size(scene));
667bf215546Sopenharmony_ci
668bf215546Sopenharmony_ci      if (0)
669bf215546Sopenharmony_ci         lp_debug_bins( scene );
670bf215546Sopenharmony_ci   }
671bf215546Sopenharmony_ci}
672