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