Path: blob/21.2-virgl/src/gallium/drivers/llvmpipe/lp_scene.c
4570 views
/**************************************************************************1*2* Copyright 2009 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627#include "util/u_framebuffer.h"28#include "util/u_math.h"29#include "util/u_memory.h"30#include "util/u_inlines.h"31#include "util/simple_list.h"32#include "util/format/u_format.h"33#include "lp_scene.h"34#include "lp_fence.h"35#include "lp_debug.h"36#include "lp_context.h"37#include "lp_state_fs.h"383940#define RESOURCE_REF_SZ 324142/** List of resource references */43struct resource_ref {44struct pipe_resource *resource[RESOURCE_REF_SZ];45int count;46struct resource_ref *next;47};4849#define SHADER_REF_SZ 3250/** List of shader variant references */51struct shader_ref {52struct lp_fragment_shader_variant *variant[SHADER_REF_SZ];53int count;54struct shader_ref *next;55};565758/**59* Create a new scene object.60* \param queue the queue to put newly rendered/emptied scenes into61*/62struct lp_scene *63lp_scene_create( struct pipe_context *pipe )64{65struct lp_scene *scene = CALLOC_STRUCT(lp_scene);66if (!scene)67return NULL;6869scene->pipe = pipe;7071scene->data.head =72CALLOC_STRUCT(data_block);7374(void) mtx_init(&scene->mutex, mtx_plain);7576#ifdef DEBUG77/* Do some scene limit sanity checks here */78{79size_t maxBins = TILES_X * TILES_Y;80size_t maxCommandBytes = sizeof(struct cmd_block) * maxBins;81size_t maxCommandPlusData = maxCommandBytes + DATA_BLOCK_SIZE;82/* We'll need at least one command block per bin. Make sure that's83* less than the max allowed scene size.84*/85assert(maxCommandBytes < LP_SCENE_MAX_SIZE);86/* We'll also need space for at least one other data block */87assert(maxCommandPlusData <= LP_SCENE_MAX_SIZE);88}89#endif9091return scene;92}939495/**96* Free all data associated with the given scene, and the scene itself.97*/98void99lp_scene_destroy(struct lp_scene *scene)100{101lp_fence_reference(&scene->fence, NULL);102mtx_destroy(&scene->mutex);103assert(scene->data.head->next == NULL);104FREE(scene->data.head);105FREE(scene);106}107108109/**110* Check if the scene's bins are all empty.111* For debugging purposes.112*/113boolean114lp_scene_is_empty(struct lp_scene *scene )115{116unsigned x, y;117118for (y = 0; y < scene->tiles_y; y++) {119for (x = 0; x < scene->tiles_x; x++) {120const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);121if (bin->head) {122return FALSE;123}124}125}126return TRUE;127}128129130/* Returns true if there has ever been a failed allocation attempt in131* this scene. Used in triangle emit to avoid having to check success132* at each bin.133*/134boolean135lp_scene_is_oom(struct lp_scene *scene)136{137return scene->alloc_failed;138}139140141/* Remove all commands from a bin. Tries to reuse some of the memory142* allocated to the bin, however.143*/144void145lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)146{147struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);148149bin->last_state = NULL;150bin->head = bin->tail;151if (bin->tail) {152bin->tail->next = NULL;153bin->tail->count = 0;154}155}156157static void158init_scene_texture(struct lp_scene_surface *ssurf, struct pipe_surface *psurf)159{160if (!psurf) {161ssurf->stride = 0;162ssurf->layer_stride = 0;163ssurf->sample_stride = 0;164ssurf->nr_samples = 0;165ssurf->map = NULL;166return;167}168169if (llvmpipe_resource_is_texture(psurf->texture)) {170ssurf->stride = llvmpipe_resource_stride(psurf->texture,171psurf->u.tex.level);172ssurf->layer_stride = llvmpipe_layer_stride(psurf->texture,173psurf->u.tex.level);174ssurf->sample_stride = llvmpipe_sample_stride(psurf->texture);175176ssurf->map = llvmpipe_resource_map(psurf->texture,177psurf->u.tex.level,178psurf->u.tex.first_layer,179LP_TEX_USAGE_READ_WRITE);180ssurf->format_bytes = util_format_get_blocksize(psurf->format);181ssurf->nr_samples = util_res_sample_count(psurf->texture);182}183else {184struct llvmpipe_resource *lpr = llvmpipe_resource(psurf->texture);185unsigned pixstride = util_format_get_blocksize(psurf->format);186ssurf->stride = psurf->texture->width0;187ssurf->layer_stride = 0;188ssurf->sample_stride = 0;189ssurf->nr_samples = 1;190ssurf->map = lpr->data;191ssurf->map += psurf->u.buf.first_element * pixstride;192ssurf->format_bytes = util_format_get_blocksize(psurf->format);193}194}195196void197lp_scene_begin_rasterization(struct lp_scene *scene)198{199const struct pipe_framebuffer_state *fb = &scene->fb;200int i;201202//LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);203204for (i = 0; i < scene->fb.nr_cbufs; i++) {205struct pipe_surface *cbuf = scene->fb.cbufs[i];206init_scene_texture(&scene->cbufs[i], cbuf);207}208209if (fb->zsbuf) {210struct pipe_surface *zsbuf = scene->fb.zsbuf;211init_scene_texture(&scene->zsbuf, zsbuf);212}213}214215216217218/**219* Free all the temporary data in a scene.220*/221void222lp_scene_end_rasterization(struct lp_scene *scene )223{224int i, j;225226/* Unmap color buffers */227for (i = 0; i < scene->fb.nr_cbufs; i++) {228if (scene->cbufs[i].map) {229struct pipe_surface *cbuf = scene->fb.cbufs[i];230if (llvmpipe_resource_is_texture(cbuf->texture)) {231llvmpipe_resource_unmap(cbuf->texture,232cbuf->u.tex.level,233cbuf->u.tex.first_layer);234}235scene->cbufs[i].map = NULL;236}237}238239/* Unmap z/stencil buffer */240if (scene->zsbuf.map) {241struct pipe_surface *zsbuf = scene->fb.zsbuf;242llvmpipe_resource_unmap(zsbuf->texture,243zsbuf->u.tex.level,244zsbuf->u.tex.first_layer);245scene->zsbuf.map = NULL;246}247248/* Reset all command lists:249*/250for (i = 0; i < scene->tiles_x; i++) {251for (j = 0; j < scene->tiles_y; j++) {252struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);253bin->head = NULL;254bin->tail = NULL;255bin->last_state = NULL;256}257}258259/* If there are any bins which weren't cleared by the loop above,260* they will be caught (on debug builds at least) by this assert:261*/262assert(lp_scene_is_empty(scene));263264/* Decrement texture ref counts265*/266{267struct resource_ref *ref;268int i, j = 0;269270for (ref = scene->resources; ref; ref = ref->next) {271for (i = 0; i < ref->count; i++) {272if (LP_DEBUG & DEBUG_SETUP)273debug_printf("resource %d: %p %dx%d sz %d\n",274j,275(void *) ref->resource[i],276ref->resource[i]->width0,277ref->resource[i]->height0,278llvmpipe_resource_size(ref->resource[i]));279j++;280llvmpipe_resource_unmap(ref->resource[i], 0, 0);281pipe_resource_reference(&ref->resource[i], NULL);282}283}284285if (LP_DEBUG & DEBUG_SETUP)286debug_printf("scene %d resources, sz %d\n",287j, scene->resource_reference_size);288}289290/* Decrement shader variant ref counts291*/292{293struct shader_ref *ref;294int i, j = 0;295296for (ref = scene->frag_shaders; ref; ref = ref->next) {297for (i = 0; i < ref->count; i++) {298if (LP_DEBUG & DEBUG_SETUP)299debug_printf("shader %d: %p\n", j, (void *) ref->variant[i]);300j++;301lp_fs_variant_reference(llvmpipe_context(scene->pipe), &ref->variant[i], NULL);302}303}304}305306/* Free all scene data blocks:307*/308{309struct data_block_list *list = &scene->data;310struct data_block *block, *tmp;311312for (block = list->head->next; block; block = tmp) {313tmp = block->next;314FREE(block);315}316317list->head->next = NULL;318list->head->used = 0;319}320321lp_fence_reference(&scene->fence, NULL);322323scene->resources = NULL;324scene->frag_shaders = NULL;325scene->scene_size = 0;326scene->resource_reference_size = 0;327328scene->alloc_failed = FALSE;329330util_unreference_framebuffer_state( &scene->fb );331}332333334335336337338struct cmd_block *339lp_scene_new_cmd_block( struct lp_scene *scene,340struct cmd_bin *bin )341{342struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));343if (block) {344if (bin->tail) {345bin->tail->next = block;346bin->tail = block;347}348else {349bin->head = block;350bin->tail = block;351}352//memset(block, 0, sizeof *block);353block->next = NULL;354block->count = 0;355}356return block;357}358359360struct data_block *361lp_scene_new_data_block( struct lp_scene *scene )362{363if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) {364if (0) debug_printf("%s: failed\n", __FUNCTION__);365scene->alloc_failed = TRUE;366return NULL;367}368else {369struct data_block *block = MALLOC_STRUCT(data_block);370if (!block)371return NULL;372373scene->scene_size += sizeof *block;374375block->used = 0;376block->next = scene->data.head;377scene->data.head = block;378379return block;380}381}382383384/**385* Return number of bytes used for all bin data within a scene.386* This does not include resources (textures) referenced by the scene.387*/388static unsigned389lp_scene_data_size( const struct lp_scene *scene )390{391unsigned size = 0;392const struct data_block *block;393for (block = scene->data.head; block; block = block->next) {394size += block->used;395}396return size;397}398399400401/**402* Add a reference to a resource by the scene.403*/404boolean405lp_scene_add_resource_reference(struct lp_scene *scene,406struct pipe_resource *resource,407boolean initializing_scene)408{409struct resource_ref *ref, **last = &scene->resources;410int i;411412/* Look at existing resource blocks:413*/414for (ref = scene->resources; ref; ref = ref->next) {415last = &ref->next;416417/* Search for this resource:418*/419for (i = 0; i < ref->count; i++)420if (ref->resource[i] == resource)421return TRUE;422423if (ref->count < RESOURCE_REF_SZ) {424/* If the block is half-empty, then append the reference here.425*/426break;427}428}429430/* Create a new block if no half-empty block was found.431*/432if (!ref) {433assert(*last == NULL);434*last = lp_scene_alloc(scene, sizeof *ref);435if (*last == NULL)436return FALSE;437438ref = *last;439memset(ref, 0, sizeof *ref);440}441442/* Map resource again to increment the map count. We likely use the443* already-mapped pointer in a texture of the jit context, and that pointer444* needs to stay mapped during rasterization. This map is unmap'ed when445* finalizing scene rasterization. */446llvmpipe_resource_map(resource, 0, 0, LP_TEX_USAGE_READ);447448/* Append the reference to the reference block.449*/450pipe_resource_reference(&ref->resource[ref->count++], resource);451scene->resource_reference_size += llvmpipe_resource_size(resource);452453/* Heuristic to advise scene flushes. This isn't helpful in the454* initial setup of the scene, but after that point flush on the455* next resource added which exceeds 64MB in referenced texture456* data.457*/458if (!initializing_scene &&459scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE)460return FALSE;461462return TRUE;463}464465466/**467* Add a reference to a fragment shader variant468*/469boolean470lp_scene_add_frag_shader_reference(struct lp_scene *scene,471struct lp_fragment_shader_variant *variant)472{473struct shader_ref *ref, **last = &scene->frag_shaders;474int i;475476/* Look at existing resource blocks:477*/478for (ref = scene->frag_shaders; ref; ref = ref->next) {479last = &ref->next;480481/* Search for this resource:482*/483for (i = 0; i < ref->count; i++)484if (ref->variant[i] == variant)485return TRUE;486487if (ref->count < SHADER_REF_SZ) {488/* If the block is half-empty, then append the reference here.489*/490break;491}492}493494/* Create a new block if no half-empty block was found.495*/496if (!ref) {497assert(*last == NULL);498*last = lp_scene_alloc(scene, sizeof *ref);499if (*last == NULL)500return FALSE;501502ref = *last;503memset(ref, 0, sizeof *ref);504}505506/* Append the reference to the reference block.507*/508lp_fs_variant_reference(llvmpipe_context(scene->pipe), &ref->variant[ref->count++], variant);509510return TRUE;511}512513/**514* Does this scene have a reference to the given resource?515*/516boolean517lp_scene_is_resource_referenced(const struct lp_scene *scene,518const struct pipe_resource *resource)519{520const struct resource_ref *ref;521int i;522523for (ref = scene->resources; ref; ref = ref->next) {524for (i = 0; i < ref->count; i++)525if (ref->resource[i] == resource)526return TRUE;527}528529return FALSE;530}531532533534535/** advance curr_x,y to the next bin */536static boolean537next_bin(struct lp_scene *scene)538{539scene->curr_x++;540if (scene->curr_x >= scene->tiles_x) {541scene->curr_x = 0;542scene->curr_y++;543}544if (scene->curr_y >= scene->tiles_y) {545/* no more bins */546return FALSE;547}548return TRUE;549}550551552void553lp_scene_bin_iter_begin( struct lp_scene *scene )554{555scene->curr_x = scene->curr_y = -1;556}557558559/**560* Return pointer to next bin to be rendered.561* The lp_scene::curr_x and ::curr_y fields will be advanced.562* Multiple rendering threads will call this function to get a chunk563* of work (a bin) to work on.564*/565struct cmd_bin *566lp_scene_bin_iter_next( struct lp_scene *scene , int *x, int *y)567{568struct cmd_bin *bin = NULL;569570mtx_lock(&scene->mutex);571572if (scene->curr_x < 0) {573/* first bin */574scene->curr_x = 0;575scene->curr_y = 0;576}577else if (!next_bin(scene)) {578/* no more bins left */579goto end;580}581582bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);583*x = scene->curr_x;584*y = scene->curr_y;585586end:587/*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/588mtx_unlock(&scene->mutex);589return bin;590}591592593void lp_scene_begin_binning(struct lp_scene *scene,594struct pipe_framebuffer_state *fb)595{596int i;597unsigned max_layer = ~0;598599assert(lp_scene_is_empty(scene));600601util_copy_framebuffer_state(&scene->fb, fb);602603scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;604scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE;605assert(scene->tiles_x <= TILES_X);606assert(scene->tiles_y <= TILES_Y);607608/*609* Determine how many layers the fb has (used for clamping layer value).610* OpenGL (but not d3d10) permits different amount of layers per rt, however611* results are undefined if layer exceeds the amount of layers of ANY612* attachment hence don't need separate per cbuf and zsbuf max.613*/614for (i = 0; i < scene->fb.nr_cbufs; i++) {615struct pipe_surface *cbuf = scene->fb.cbufs[i];616if (cbuf) {617if (llvmpipe_resource_is_texture(cbuf->texture)) {618max_layer = MIN2(max_layer,619cbuf->u.tex.last_layer - cbuf->u.tex.first_layer);620}621else {622max_layer = 0;623}624}625}626if (fb->zsbuf) {627struct pipe_surface *zsbuf = scene->fb.zsbuf;628max_layer = MIN2(max_layer, zsbuf->u.tex.last_layer - zsbuf->u.tex.first_layer);629}630scene->fb_max_layer = max_layer;631scene->fb_max_samples = util_framebuffer_get_num_samples(fb);632if (scene->fb_max_samples == 4) {633for (unsigned i = 0; i < 4; i++) {634scene->fixed_sample_pos[i][0] = util_iround(lp_sample_pos_4x[i][0] * FIXED_ONE);635scene->fixed_sample_pos[i][1] = util_iround(lp_sample_pos_4x[i][1] * FIXED_ONE);636}637}638}639640641void lp_scene_end_binning( struct lp_scene *scene )642{643if (LP_DEBUG & DEBUG_SCENE) {644debug_printf("rasterize scene:\n");645debug_printf(" scene_size: %u\n",646scene->scene_size);647debug_printf(" data size: %u\n",648lp_scene_data_size(scene));649650if (0)651lp_debug_bins( scene );652}653}654655656