draw: limit the number of vertex shader variants kept around

we used to create and cache unltimited number of variant, this
change limits the number of variants kept around to a fixed number.
the change is based on a similar patch by Roland for llvmpipe fragment
shaders.
This commit is contained in:
Zack Rusin 2010-06-25 19:31:09 -04:00
parent 5cf1921e6d
commit 8ebfcf31eb
8 changed files with 325 additions and 63 deletions

View File

@ -218,7 +218,8 @@ if env['llvm']:
'gallivm/lp_bld_type.c',
'draw/draw_llvm.c',
'draw/draw_pt_fetch_shade_pipeline_llvm.c',
'draw/draw_llvm_translate.c'
'draw/draw_llvm_translate.c',
'draw/draw_vs_llvm.c'
]
gallium = env.ConvenienceLibrary(

View File

@ -1,3 +1,30 @@
/**************************************************************************
*
* Copyright 2010 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include "draw_llvm.h"
#include "draw_context.h"
@ -219,6 +246,9 @@ draw_llvm_create(struct draw_context *draw)
LLVMDumpModule(llvm->module);
}
llvm->nr_variants = 0;
make_empty_list(&llvm->vs_variants_list);
return llvm;
}
@ -231,9 +261,13 @@ draw_llvm_destroy(struct draw_llvm *llvm)
}
struct draw_llvm_variant *
draw_llvm_prepare(struct draw_llvm *llvm, int num_inputs)
draw_llvm_create_variant(struct draw_llvm *llvm, int num_inputs)
{
struct draw_llvm_variant *variant = MALLOC(sizeof(struct draw_llvm_variant));
struct llvm_vertex_shader *shader =
llvm_vertex_shader(llvm->draw->vs.vertex_shader);
variant->llvm = llvm;
draw_llvm_make_variant_key(llvm, &variant->key);
@ -242,6 +276,12 @@ draw_llvm_prepare(struct draw_llvm *llvm, int num_inputs)
draw_llvm_generate(llvm, variant);
draw_llvm_generate_elts(llvm, variant);
variant->shader = shader;
variant->list_item_global.base = variant;
variant->list_item_local.base = variant;
/*variant->no = */shader->variants_created++;
variant->list_item_global.base = variant;
return variant;
}
@ -897,3 +937,30 @@ draw_llvm_make_variant_key(struct draw_llvm *llvm,
&llvm->draw->vs.vertex_shader->state,
sizeof(struct pipe_shader_state));
}
void
draw_llvm_destroy_variant(struct draw_llvm_variant *variant)
{
struct draw_llvm *llvm = variant->llvm;
struct draw_context *draw = llvm->draw;
if (variant->function_elts) {
if (variant->function_elts)
LLVMFreeMachineCodeForFunction(draw->engine,
variant->function_elts);
LLVMDeleteFunction(variant->function_elts);
}
if (variant->function) {
if (variant->function)
LLVMFreeMachineCodeForFunction(draw->engine,
variant->function);
LLVMDeleteFunction(variant->function);
}
remove_from_list(&variant->list_item_local);
variant->shader->variants_cached--;
remove_from_list(&variant->list_item_global);
llvm->nr_variants--;
FREE(variant);
}

View File

@ -1,15 +1,48 @@
/**************************************************************************
*
* Copyright 2010 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifndef HAVE_LLVM_H
#define HAVE_LLVM_H
#include "draw/draw_private.h"
#include "draw/draw_vs.h"
#include "pipe/p_context.h"
#include "util/u_simple_list.h"
#include <llvm-c/Core.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/Target.h>
#include <llvm-c/ExecutionEngine.h>
struct draw_llvm;
struct llvm_vertex_shader;
struct draw_jit_texture
{
uint32_t width;
@ -104,11 +137,50 @@ typedef void
unsigned stride,
struct pipe_vertex_buffer *vertex_buffers);
struct draw_llvm_variant_key
{
struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS];
unsigned nr_vertex_elements;
struct pipe_shader_state vs;
};
struct draw_llvm_variant_list_item
{
struct draw_llvm_variant *base;
struct draw_llvm_variant_list_item *next, *prev;
};
struct draw_llvm_variant
{
struct draw_llvm_variant_key key;
LLVMValueRef function;
LLVMValueRef function_elts;
draw_jit_vert_func jit_func;
draw_jit_vert_func_elts jit_func_elts;
struct llvm_vertex_shader *shader;
struct draw_llvm *llvm;
struct draw_llvm_variant_list_item list_item_global;
struct draw_llvm_variant_list_item list_item_local;
};
struct llvm_vertex_shader {
struct draw_vertex_shader base;
struct draw_llvm_variant_list_item variants;
unsigned variants_created;
unsigned variants_cached;
};
struct draw_llvm {
struct draw_context *draw;
struct draw_jit_context jit_context;
struct draw_llvm_variant_list_item vs_variants_list;
int nr_variants;
LLVMModuleRef module;
LLVMExecutionEngineRef engine;
LLVMModuleProviderRef provider;
@ -121,23 +193,12 @@ struct draw_llvm {
LLVMTypeRef vb_ptr_type;
};
struct draw_llvm_variant_key
static struct llvm_vertex_shader *
llvm_vertex_shader(struct draw_vertex_shader *vs)
{
struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS];
unsigned nr_vertex_elements;
struct pipe_shader_state vs;
};
return (struct llvm_vertex_shader *)vs;
}
struct draw_llvm_variant
{
struct draw_llvm_variant_key key;
LLVMValueRef function;
LLVMValueRef function_elts;
draw_jit_vert_func jit_func;
draw_jit_vert_func_elts jit_func_elts;
struct draw_llvm_variant *next;
};
struct draw_llvm *
draw_llvm_create(struct draw_context *draw);
@ -146,7 +207,10 @@ void
draw_llvm_destroy(struct draw_llvm *llvm);
struct draw_llvm_variant *
draw_llvm_prepare(struct draw_llvm *llvm, int num_inputs);
draw_llvm_create_variant(struct draw_llvm *llvm, int num_inputs);
void
draw_llvm_destroy_variant(struct draw_llvm_variant *variant);
void
draw_llvm_make_variant_key(struct draw_llvm *llvm,
@ -156,4 +220,5 @@ LLVMValueRef
draw_llvm_translate_from(LLVMBuilderRef builder,
LLVMValueRef vbuffer,
enum pipe_format from_format);
#endif

View File

@ -81,6 +81,9 @@ struct vertex_header {
#define UNDEFINED_VERTEX_ID 0xffff
/* maximum number of shader variants we can cache */
#define DRAW_MAX_SHADER_VARIANTS 1024
/**
* Private context for the drawing module.
*/

View File

@ -52,9 +52,7 @@ struct llvm_middle_end {
unsigned opt;
struct draw_llvm *llvm;
struct draw_llvm_variant *variants;
struct draw_llvm_variant *current_variant;
int nr_variants;
};
@ -66,9 +64,11 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
{
struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
struct draw_context *draw = fpme->draw;
struct draw_vertex_shader *vs = draw->vs.vertex_shader;
struct llvm_vertex_shader *shader =
llvm_vertex_shader(draw->vs.vertex_shader);
struct draw_llvm_variant_key key;
struct draw_llvm_variant *variant = NULL;
struct draw_llvm_variant_list_item *li;
unsigned i;
unsigned instance_id_index = ~0;
@ -80,13 +80,13 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
/* Add one to num_outputs because the pipeline occasionally tags on
* an additional texcoord, eg for AA lines.
*/
unsigned nr = MAX2( vs->info.num_inputs,
vs->info.num_outputs + 1 );
unsigned nr = MAX2( shader->base.info.num_inputs,
shader->base.info.num_outputs + 1 );
/* Scan for instanceID system value.
*/
for (i = 0; i < vs->info.num_inputs; i++) {
if (vs->info.input_semantic_name[i] == TGSI_SEMANTIC_INSTANCEID) {
for (i = 0; i < shader->base.info.num_inputs; i++) {
if (shader->base.info.input_semantic_name[i] == TGSI_SEMANTIC_INSTANCEID) {
instance_id_index = i;
break;
}
@ -130,20 +130,41 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
draw_llvm_make_variant_key(fpme->llvm, &key);
variant = fpme->variants;
while(variant) {
if(memcmp(&variant->key, &key, sizeof key) == 0)
li = first_elem(&shader->variants);
while(!at_end(&shader->variants, li)) {
if(memcmp(&li->base->key, &key, sizeof key) == 0) {
variant = li->base;
break;
variant = variant->next;
}
li = next_elem(li);
}
if (!variant) {
variant = draw_llvm_prepare(fpme->llvm, nr);
variant->next = fpme->variants;
fpme->variants = variant;
++fpme->nr_variants;
if (variant) {
move_to_head(&fpme->llvm->vs_variants_list, &variant->list_item_global);
}
else {
unsigned i;
if (fpme->llvm->nr_variants >= DRAW_MAX_SHADER_VARIANTS) {
/*
* XXX: should we flush here ?
*/
for (i = 0; i < DRAW_MAX_SHADER_VARIANTS / 4; i++) {
struct draw_llvm_variant_list_item *item =
last_elem(&fpme->llvm->vs_variants_list);
draw_llvm_destroy_variant(item->base);
}
}
variant = draw_llvm_create_variant(fpme->llvm, nr);
if (variant) {
insert_at_head(&shader->variants, &variant->list_item_local);
insert_at_head(&fpme->llvm->vs_variants_list, &variant->list_item_global);
fpme->llvm->nr_variants++;
shader->variants_cached++;
}
}
fpme->current_variant = variant;
/*XXX we only support one constant buffer */
@ -358,31 +379,7 @@ static void llvm_middle_end_finish( struct draw_pt_middle_end *middle )
static void llvm_middle_end_destroy( struct draw_pt_middle_end *middle )
{
struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
struct draw_context *draw = fpme->draw;
struct draw_llvm_variant *variant = NULL;
variant = fpme->variants;
while(variant) {
struct draw_llvm_variant *next = variant->next;
if (variant->function_elts) {
if (variant->function_elts)
LLVMFreeMachineCodeForFunction(draw->engine,
variant->function_elts);
LLVMDeleteFunction(variant->function_elts);
}
if (variant->function) {
if (variant->function)
LLVMFreeMachineCodeForFunction(draw->engine,
variant->function);
LLVMDeleteFunction(variant->function);
}
FREE(variant);
variant = next;
}
if (fpme->fetch)
draw_pt_fetch_destroy( fpme->fetch );
@ -402,7 +399,8 @@ static void llvm_middle_end_destroy( struct draw_pt_middle_end *middle )
}
struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit_llvm( struct draw_context *draw )
struct draw_pt_middle_end *
draw_pt_fetch_pipeline_or_emit_llvm(struct draw_context *draw)
{
struct llvm_middle_end *fpme = 0;
@ -442,9 +440,7 @@ struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit_llvm( struct draw_cont
if (!fpme->llvm)
goto fail;
fpme->variants = NULL;
fpme->current_variant = NULL;
fpme->nr_variants = 0;
return &fpme->base;

View File

@ -98,6 +98,11 @@ draw_create_vertex_shader(struct draw_context *draw,
vs = draw_create_vs_ppc( draw, shader );
#endif
}
#if HAVE_LLVM
else {
vs = draw_create_vs_llvm(draw, shader);
}
#endif
if (!vs) {
vs = draw_create_vs_exec( draw, shader );

View File

@ -165,7 +165,6 @@ draw_create_vs_ppc(struct draw_context *draw,
const struct pipe_shader_state *templ);
struct draw_vs_varient_key;
struct draw_vertex_shader;
@ -173,6 +172,11 @@ struct draw_vs_varient *
draw_vs_create_varient_aos_sse( struct draw_vertex_shader *vs,
const struct draw_vs_varient_key *key );
#if HAVE_LLVM
struct draw_vertex_shader *
draw_create_vs_llvm(struct draw_context *draw,
const struct pipe_shader_state *state);
#endif
/********************************************************************************

View File

@ -0,0 +1,121 @@
/**************************************************************************
*
* Copyright 2010 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include "util/u_math.h"
#include "util/u_memory.h"
#include "pipe/p_shader_tokens.h"
#include "draw_private.h"
#include "draw_context.h"
#include "draw_vs.h"
#include "draw_llvm.h"
#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_scan.h"
#include "tgsi/tgsi_exec.h"
static void
vs_llvm_prepare(struct draw_vertex_shader *shader,
struct draw_context *draw)
{
/*struct llvm_vertex_shader *evs = llvm_vertex_shader(shader);*/
}
static void
vs_llvm_run_linear( struct draw_vertex_shader *shader,
const float (*input)[4],
float (*output)[4],
const void *constants[PIPE_MAX_CONSTANT_BUFFERS],
unsigned count,
unsigned input_stride,
unsigned output_stride )
{
/* we should never get here since the entire pipeline is
* generated in draw_pt_fetch_shade_pipeline_llvm.c */
debug_assert(0);
}
static void
vs_llvm_delete( struct draw_vertex_shader *dvs )
{
struct llvm_vertex_shader *shader = llvm_vertex_shader(dvs);
struct pipe_fence_handle *fence = NULL;
struct draw_llvm_variant_list_item *li;
struct pipe_context *pipe = dvs->draw->pipe;
/*
* XXX: This might be not neccessary at all.
*/
pipe->flush(pipe, 0, &fence);
if (fence) {
pipe->screen->fence_finish(pipe->screen, fence, 0);
pipe->screen->fence_reference(pipe->screen, &fence, NULL);
}
li = first_elem(&shader->variants);
while(!at_end(&shader->variants, li)) {
struct draw_llvm_variant_list_item *next = next_elem(li);
draw_llvm_destroy_variant(li->base);
li = next;
}
assert(shader->variants_cached == 0);
FREE((void*) dvs->state.tokens);
FREE( dvs );
}
struct draw_vertex_shader *
draw_create_vs_llvm(struct draw_context *draw,
const struct pipe_shader_state *state)
{
struct llvm_vertex_shader *vs = CALLOC_STRUCT( llvm_vertex_shader );
if (vs == NULL)
return NULL;
/* we make a private copy of the tokens */
vs->base.state.tokens = tgsi_dup_tokens(state->tokens);
if (!vs->base.state.tokens) {
FREE(vs);
return NULL;
}
tgsi_scan_shader(state->tokens, &vs->base.info);
vs->base.draw = draw;
vs->base.prepare = vs_llvm_prepare;
vs->base.run_linear = vs_llvm_run_linear;
vs->base.delete = vs_llvm_delete;
vs->base.create_varient = draw_vs_create_varient_generic;
make_empty_list(&vs->variants);
return &vs->base;
}