From 51a59b7f7f9b134791d3b09673063e4c45ea9eee Mon Sep 17 00:00:00 2001 From: marha Date: Wed, 9 Feb 2011 07:47:31 +0000 Subject: libX11 mesa git update 9 Feb 2011 --- mesalib/src/mesa/state_tracker/st_context.c | 584 +++--- mesalib/src/mesa/state_tracker/st_draw_feedback.c | 557 ++--- mesalib/src/mesa/state_tracker/st_program.c | 2319 +++++++++++---------- 3 files changed, 1736 insertions(+), 1724 deletions(-) (limited to 'mesalib/src/mesa/state_tracker') diff --git a/mesalib/src/mesa/state_tracker/st_context.c b/mesalib/src/mesa/state_tracker/st_context.c index 593da8fa6..dccbff3c1 100644 --- a/mesalib/src/mesa/state_tracker/st_context.c +++ b/mesalib/src/mesa/state_tracker/st_context.c @@ -1,292 +1,292 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * 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 TUNGSTEN GRAPHICS 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 "main/imports.h" -#include "main/context.h" -#include "main/shaderobj.h" -#include "program/prog_cache.h" -#include "vbo/vbo.h" -#include "glapi/glapi.h" -#include "st_context.h" -#include "st_debug.h" -#include "st_cb_accum.h" -#include "st_cb_bitmap.h" -#include "st_cb_blit.h" -#include "st_cb_bufferobjects.h" -#include "st_cb_clear.h" -#include "st_cb_condrender.h" -#include "st_cb_drawpixels.h" -#include "st_cb_rasterpos.h" -#include "st_cb_drawtex.h" -#include "st_cb_eglimage.h" -#include "st_cb_fbo.h" -#include "st_cb_feedback.h" -#include "st_cb_program.h" -#include "st_cb_queryobj.h" -#include "st_cb_readpixels.h" -#include "st_cb_texture.h" -#include "st_cb_xformfb.h" -#include "st_cb_flush.h" -#include "st_cb_strings.h" -#include "st_cb_viewport.h" -#include "st_atom.h" -#include "st_draw.h" -#include "st_extensions.h" -#include "st_gen_mipmap.h" -#include "st_program.h" -#include "pipe/p_context.h" -#include "util/u_inlines.h" -#include "cso_cache/cso_context.h" - - -DEBUG_GET_ONCE_BOOL_OPTION(mesa_mvp_dp4, "MESA_MVP_DP4", FALSE) - - -/** - * Called via ctx->Driver.UpdateState() - */ -void st_invalidate_state(struct gl_context * ctx, GLuint new_state) -{ - struct st_context *st = st_context(ctx); - - st->dirty.mesa |= new_state; - st->dirty.st |= ST_NEW_MESA; - - /* This is the only core Mesa module we depend upon. - * No longer use swrast, swsetup, tnl. - */ - _vbo_InvalidateState(ctx, new_state); -} - - -/** - * Check for multisample env var override. - */ -int -st_get_msaa(void) -{ - const char *msaa = _mesa_getenv("__GL_FSAA_MODE"); - if (msaa) - return atoi(msaa); - return 0; -} - - -static struct st_context * -st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe ) -{ - uint i; - struct st_context *st = ST_CALLOC_STRUCT( st_context ); - - ctx->st = st; - - st->ctx = ctx; - st->pipe = pipe; - - /* XXX: this is one-off, per-screen init: */ - st_debug_init(); - - /* state tracker needs the VBO module */ - _vbo_CreateContext(ctx); - - st->dirty.mesa = ~0; - st->dirty.st = ~0; - - st->cso_context = cso_create_context(pipe); - - st_init_atoms( st ); - st_init_bitmap(st); - st_init_clear(st); - st_init_draw( st ); - st_init_generate_mipmap(st); - st_init_blit(st); - - if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES)) - st->internal_target = PIPE_TEXTURE_2D; - else - st->internal_target = PIPE_TEXTURE_RECT; - - for (i = 0; i < PIPE_MAX_SAMPLERS; i++) - st->state.sampler_list[i] = &st->state.samplers[i]; - - for (i = 0; i < 3; i++) { - memset(&st->velems_util_draw[i], 0, sizeof(struct pipe_vertex_element)); - st->velems_util_draw[i].src_offset = i * 4 * sizeof(float); - st->velems_util_draw[i].instance_divisor = 0; - st->velems_util_draw[i].vertex_buffer_index = 0; - st->velems_util_draw[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; - } - - /* we want all vertex data to be placed in buffer objects */ - vbo_use_buffer_objects(ctx); - - /* Need these flags: - */ - st->ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; - - st->ctx->VertexProgram._MaintainTnlProgram = GL_TRUE; - - st->pixel_xfer.cache = _mesa_new_program_cache(); - - st->force_msaa = st_get_msaa(); - - /* GL limits and extensions */ - st_init_limits(st); - st_init_extensions(st); - - return st; -} - - -struct st_context *st_create_context(gl_api api, struct pipe_context *pipe, - const struct gl_config *visual, - struct st_context *share) -{ - struct gl_context *ctx; - struct gl_context *shareCtx = share ? share->ctx : NULL; - struct dd_function_table funcs; - - /* Sanity checks */ - assert(MESA_SHADER_VERTEX == PIPE_SHADER_VERTEX); - assert(MESA_SHADER_FRAGMENT == PIPE_SHADER_FRAGMENT); - assert(MESA_SHADER_GEOMETRY == PIPE_SHADER_GEOMETRY); - - memset(&funcs, 0, sizeof(funcs)); - st_init_driver_functions(&funcs); - - ctx = _mesa_create_context_for_api(api, visual, shareCtx, &funcs, NULL); - - /* XXX: need a capability bit in gallium to query if the pipe - * driver prefers DP4 or MUL/MAD for vertex transformation. - */ - if (debug_get_option_mesa_mvp_dp4()) - _mesa_set_mvp_with_dp4( ctx, GL_TRUE ); - - return st_create_context_priv(ctx, pipe); -} - - -static void st_destroy_context_priv( struct st_context *st ) -{ - uint i; - - st_destroy_atoms( st ); - st_destroy_draw( st ); - st_destroy_generate_mipmap(st); - st_destroy_blit(st); - st_destroy_clear(st); - st_destroy_bitmap(st); - st_destroy_drawpix(st); - st_destroy_drawtex(st); - - for (i = 0; i < Elements(st->state.sampler_views); i++) { - pipe_sampler_view_reference(&st->state.sampler_views[i], NULL); - } - - if (st->default_texture) { - st->ctx->Driver.DeleteTexture(st->ctx, st->default_texture); - st->default_texture = NULL; - } - - free( st ); -} - - -void st_destroy_context( struct st_context *st ) -{ - struct pipe_context *pipe = st->pipe; - struct cso_context *cso = st->cso_context; - struct gl_context *ctx = st->ctx; - GLuint i; - - /* need to unbind and destroy CSO objects before anything else */ - cso_release_all(st->cso_context); - - st_reference_fragprog(st, &st->fp, NULL); - st_reference_vertprog(st, &st->vp, NULL); - - /* release framebuffer surfaces */ - for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { - pipe_surface_reference(&st->state.framebuffer.cbufs[i], NULL); - } - pipe_surface_reference(&st->state.framebuffer.zsbuf, NULL); - - pipe->set_index_buffer(pipe, NULL); - - for (i = 0; i < PIPE_SHADER_TYPES; i++) { - pipe->set_constant_buffer(pipe, i, 0, NULL); - } - - _mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache); - - _vbo_DestroyContext(st->ctx); - - st_destroy_program_variants(st); - - _mesa_free_context_data(ctx); - - st_destroy_context_priv(st); - - cso_destroy_context(cso); - - pipe->destroy( pipe ); - - free(ctx); -} - - -void st_init_driver_functions(struct dd_function_table *functions) -{ - _mesa_init_shader_object_functions(functions); - - st_init_accum_functions(functions); - st_init_blit_functions(functions); - st_init_bufferobject_functions(functions); - st_init_clear_functions(functions); - st_init_bitmap_functions(functions); - st_init_drawpixels_functions(functions); - st_init_rasterpos_functions(functions); - - st_init_drawtex_functions(functions); - - st_init_eglimage_functions(functions); - - st_init_fbo_functions(functions); - st_init_feedback_functions(functions); - st_init_program_functions(functions); - st_init_query_functions(functions); - st_init_cond_render_functions(functions); - st_init_readpixels_functions(functions); - st_init_texture_functions(functions); - st_init_flush_functions(functions); - st_init_string_functions(functions); - st_init_viewport_functions(functions); - - st_init_xformfb_functions(functions); - - functions->UpdateState = st_invalidate_state; -} +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 "main/imports.h" +#include "main/context.h" +#include "main/shaderobj.h" +#include "program/prog_cache.h" +#include "vbo/vbo.h" +#include "glapi/glapi.h" +#include "st_context.h" +#include "st_debug.h" +#include "st_cb_accum.h" +#include "st_cb_bitmap.h" +#include "st_cb_blit.h" +#include "st_cb_bufferobjects.h" +#include "st_cb_clear.h" +#include "st_cb_condrender.h" +#include "st_cb_drawpixels.h" +#include "st_cb_rasterpos.h" +#include "st_cb_drawtex.h" +#include "st_cb_eglimage.h" +#include "st_cb_fbo.h" +#include "st_cb_feedback.h" +#include "st_cb_program.h" +#include "st_cb_queryobj.h" +#include "st_cb_readpixels.h" +#include "st_cb_texture.h" +#include "st_cb_xformfb.h" +#include "st_cb_flush.h" +#include "st_cb_strings.h" +#include "st_cb_viewport.h" +#include "st_atom.h" +#include "st_draw.h" +#include "st_extensions.h" +#include "st_gen_mipmap.h" +#include "st_program.h" +#include "pipe/p_context.h" +#include "util/u_inlines.h" +#include "cso_cache/cso_context.h" + + +DEBUG_GET_ONCE_BOOL_OPTION(mesa_mvp_dp4, "MESA_MVP_DP4", FALSE) + + +/** + * Called via ctx->Driver.UpdateState() + */ +void st_invalidate_state(struct gl_context * ctx, GLuint new_state) +{ + struct st_context *st = st_context(ctx); + + st->dirty.mesa |= new_state; + st->dirty.st |= ST_NEW_MESA; + + /* This is the only core Mesa module we depend upon. + * No longer use swrast, swsetup, tnl. + */ + _vbo_InvalidateState(ctx, new_state); +} + + +/** + * Check for multisample env var override. + */ +int +st_get_msaa(void) +{ + const char *msaa = _mesa_getenv("__GL_FSAA_MODE"); + if (msaa) + return atoi(msaa); + return 0; +} + + +static struct st_context * +st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe ) +{ + uint i; + struct st_context *st = ST_CALLOC_STRUCT( st_context ); + + ctx->st = st; + + st->ctx = ctx; + st->pipe = pipe; + + /* XXX: this is one-off, per-screen init: */ + st_debug_init(); + + /* state tracker needs the VBO module */ + _vbo_CreateContext(ctx); + + st->dirty.mesa = ~0; + st->dirty.st = ~0; + + st->cso_context = cso_create_context(pipe); + + st_init_atoms( st ); + st_init_bitmap(st); + st_init_clear(st); + st_init_draw( st ); + st_init_generate_mipmap(st); + st_init_blit(st); + + if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES)) + st->internal_target = PIPE_TEXTURE_2D; + else + st->internal_target = PIPE_TEXTURE_RECT; + + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) + st->state.sampler_list[i] = &st->state.samplers[i]; + + for (i = 0; i < 3; i++) { + memset(&st->velems_util_draw[i], 0, sizeof(struct pipe_vertex_element)); + st->velems_util_draw[i].src_offset = i * 4 * sizeof(float); + st->velems_util_draw[i].instance_divisor = 0; + st->velems_util_draw[i].vertex_buffer_index = 0; + st->velems_util_draw[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + } + + /* we want all vertex data to be placed in buffer objects */ + vbo_use_buffer_objects(ctx); + + /* Need these flags: + */ + st->ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; + + st->ctx->VertexProgram._MaintainTnlProgram = GL_TRUE; + + st->pixel_xfer.cache = _mesa_new_program_cache(); + + st->force_msaa = st_get_msaa(); + + /* GL limits and extensions */ + st_init_limits(st); + st_init_extensions(st); + + return st; +} + + +struct st_context *st_create_context(gl_api api, struct pipe_context *pipe, + const struct gl_config *visual, + struct st_context *share) +{ + struct gl_context *ctx; + struct gl_context *shareCtx = share ? share->ctx : NULL; + struct dd_function_table funcs; + + /* Sanity checks */ + assert(MESA_SHADER_VERTEX == PIPE_SHADER_VERTEX); + assert(MESA_SHADER_FRAGMENT == PIPE_SHADER_FRAGMENT); + assert(MESA_SHADER_GEOMETRY == PIPE_SHADER_GEOMETRY); + + memset(&funcs, 0, sizeof(funcs)); + st_init_driver_functions(&funcs); + + ctx = _mesa_create_context(api, visual, shareCtx, &funcs, NULL); + + /* XXX: need a capability bit in gallium to query if the pipe + * driver prefers DP4 or MUL/MAD for vertex transformation. + */ + if (debug_get_option_mesa_mvp_dp4()) + _mesa_set_mvp_with_dp4( ctx, GL_TRUE ); + + return st_create_context_priv(ctx, pipe); +} + + +static void st_destroy_context_priv( struct st_context *st ) +{ + uint i; + + st_destroy_atoms( st ); + st_destroy_draw( st ); + st_destroy_generate_mipmap(st); + st_destroy_blit(st); + st_destroy_clear(st); + st_destroy_bitmap(st); + st_destroy_drawpix(st); + st_destroy_drawtex(st); + + for (i = 0; i < Elements(st->state.sampler_views); i++) { + pipe_sampler_view_reference(&st->state.sampler_views[i], NULL); + } + + if (st->default_texture) { + st->ctx->Driver.DeleteTexture(st->ctx, st->default_texture); + st->default_texture = NULL; + } + + free( st ); +} + + +void st_destroy_context( struct st_context *st ) +{ + struct pipe_context *pipe = st->pipe; + struct cso_context *cso = st->cso_context; + struct gl_context *ctx = st->ctx; + GLuint i; + + /* need to unbind and destroy CSO objects before anything else */ + cso_release_all(st->cso_context); + + st_reference_fragprog(st, &st->fp, NULL); + st_reference_vertprog(st, &st->vp, NULL); + + /* release framebuffer surfaces */ + for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { + pipe_surface_reference(&st->state.framebuffer.cbufs[i], NULL); + } + pipe_surface_reference(&st->state.framebuffer.zsbuf, NULL); + + pipe->set_index_buffer(pipe, NULL); + + for (i = 0; i < PIPE_SHADER_TYPES; i++) { + pipe->set_constant_buffer(pipe, i, 0, NULL); + } + + _mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache); + + _vbo_DestroyContext(st->ctx); + + st_destroy_program_variants(st); + + _mesa_free_context_data(ctx); + + st_destroy_context_priv(st); + + cso_destroy_context(cso); + + pipe->destroy( pipe ); + + free(ctx); +} + + +void st_init_driver_functions(struct dd_function_table *functions) +{ + _mesa_init_shader_object_functions(functions); + + st_init_accum_functions(functions); + st_init_blit_functions(functions); + st_init_bufferobject_functions(functions); + st_init_clear_functions(functions); + st_init_bitmap_functions(functions); + st_init_drawpixels_functions(functions); + st_init_rasterpos_functions(functions); + + st_init_drawtex_functions(functions); + + st_init_eglimage_functions(functions); + + st_init_fbo_functions(functions); + st_init_feedback_functions(functions); + st_init_program_functions(functions); + st_init_query_functions(functions); + st_init_cond_render_functions(functions); + st_init_readpixels_functions(functions); + st_init_texture_functions(functions); + st_init_flush_functions(functions); + st_init_string_functions(functions); + st_init_viewport_functions(functions); + + st_init_xformfb_functions(functions); + + functions->UpdateState = st_invalidate_state; +} diff --git a/mesalib/src/mesa/state_tracker/st_draw_feedback.c b/mesalib/src/mesa/state_tracker/st_draw_feedback.c index 72ed75e73..c11c7696e 100644 --- a/mesalib/src/mesa/state_tracker/st_draw_feedback.c +++ b/mesalib/src/mesa/state_tracker/st_draw_feedback.c @@ -1,278 +1,279 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * 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 TUNGSTEN GRAPHICS 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 "main/imports.h" -#include "main/image.h" -#include "main/macros.h" -#include "main/mfeatures.h" - -#include "vbo/vbo.h" - -#include "st_context.h" -#include "st_atom.h" -#include "st_cb_bufferobjects.h" -#include "st_draw.h" -#include "st_program.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "util/u_inlines.h" - -#include "draw/draw_private.h" -#include "draw/draw_context.h" - - -#if FEATURE_feedback || FEATURE_rastpos - -/** - * Set the (private) draw module's post-transformed vertex format when in - * GL_SELECT or GL_FEEDBACK mode or for glRasterPos. - */ -static void -set_feedback_vertex_format(struct gl_context *ctx) -{ -#if 0 - struct st_context *st = st_context(ctx); - struct vertex_info vinfo; - GLuint i; - - memset(&vinfo, 0, sizeof(vinfo)); - - if (ctx->RenderMode == GL_SELECT) { - assert(ctx->RenderMode == GL_SELECT); - vinfo.num_attribs = 1; - vinfo.format[0] = FORMAT_4F; - vinfo.interp_mode[0] = INTERP_LINEAR; - } - else { - /* GL_FEEDBACK, or glRasterPos */ - /* emit all attribs (pos, color, texcoord) as GLfloat[4] */ - vinfo.num_attribs = st->state.vs->cso->state.num_outputs; - for (i = 0; i < vinfo.num_attribs; i++) { - vinfo.format[i] = FORMAT_4F; - vinfo.interp_mode[i] = INTERP_LINEAR; - } - } - - draw_set_vertex_info(st->draw, &vinfo); -#endif -} - - -/** - * Called by VBO to draw arrays when in selection or feedback mode and - * to implement glRasterPos. - * This is very much like the normal draw_vbo() function above. - * Look at code refactoring some day. - * Might move this into the failover module some day. - */ -void -st_feedback_draw_vbo(struct gl_context *ctx, - const struct gl_client_array **arrays, - const struct _mesa_prim *prims, - GLuint nr_prims, - const struct _mesa_index_buffer *ib, - GLboolean index_bounds_valid, - GLuint min_index, - GLuint max_index) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct draw_context *draw = st->draw; - const struct st_vertex_program *vp; - const struct pipe_shader_state *vs; - struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; - struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; - struct pipe_index_buffer ibuffer; - struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; - struct pipe_transfer *ib_transfer = NULL; - GLuint attr, i; - const void *mapped_indices = NULL; - - assert(draw); - - st_validate_state(st); - - if (!index_bounds_valid) - vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); - - /* must get these after state validation! */ - vp = st->vp; - vs = &st->vp_variant->tgsi; - - if (!st->vp_variant->draw_shader) { - st->vp_variant->draw_shader = draw_create_vertex_shader(draw, vs); - } - - /* - * Set up the draw module's state. - * - * We'd like to do this less frequently, but the normal state-update - * code sends state updates to the pipe, not to our private draw module. - */ - assert(draw); - draw_set_viewport_state(draw, &st->state.viewport); - draw_set_clip_state(draw, &st->state.clip); - draw_set_rasterizer_state(draw, &st->state.rasterizer, NULL); - draw_bind_vertex_shader(draw, st->vp_variant->draw_shader); - set_feedback_vertex_format(ctx); - - /* loop over TGSI shader inputs to determine vertex buffer - * and attribute info - */ - for (attr = 0; attr < vp->num_inputs; attr++) { - const GLuint mesaAttr = vp->index_to_input[attr]; - struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; - void *map; - - if (bufobj && bufobj->Name) { - /* Attribute data is in a VBO. - * Recall that for VBOs, the gl_client_array->Ptr field is - * really an offset from the start of the VBO, not a pointer. - */ - struct st_buffer_object *stobj = st_buffer_object(bufobj); - assert(stobj->buffer); - - vbuffers[attr].buffer = NULL; - pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer); - vbuffers[attr].buffer_offset = pointer_to_offset(arrays[0]->Ptr); - velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr; - } - else { - /* attribute data is in user-space memory, not a VBO */ - uint bytes = (arrays[mesaAttr]->Size - * _mesa_sizeof_type(arrays[mesaAttr]->Type) - * (max_index + 1)); - - /* wrap user data */ - vbuffers[attr].buffer - = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, - bytes, - PIPE_BIND_VERTEX_BUFFER); - vbuffers[attr].buffer_offset = 0; - velements[attr].src_offset = 0; - } - - /* common-case setup */ - vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ - vbuffers[attr].max_index = max_index; - velements[attr].instance_divisor = 0; - velements[attr].vertex_buffer_index = attr; - velements[attr].src_format = - st_pipe_vertex_format(arrays[mesaAttr]->Type, - arrays[mesaAttr]->Size, - arrays[mesaAttr]->Format, - arrays[mesaAttr]->Normalized); - assert(velements[attr].src_format); - - /* tell draw about this attribute */ -#if 0 - draw_set_vertex_buffer(draw, attr, &vbuffer[attr]); -#endif - - /* map the attrib buffer */ - map = pipe_buffer_map(pipe, vbuffers[attr].buffer, - PIPE_TRANSFER_READ, - &vb_transfer[attr]); - draw_set_mapped_vertex_buffer(draw, attr, map); - } - - draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); - draw_set_vertex_elements(draw, vp->num_inputs, velements); - - memset(&ibuffer, 0, sizeof(ibuffer)); - if (ib) { - struct gl_buffer_object *bufobj = ib->obj; - - switch (ib->type) { - case GL_UNSIGNED_INT: - ibuffer.index_size = 4; - break; - case GL_UNSIGNED_SHORT: - ibuffer.index_size = 2; - break; - case GL_UNSIGNED_BYTE: - ibuffer.index_size = 1; - break; - default: - assert(0); - return; - } - - if (bufobj && bufobj->Name) { - struct st_buffer_object *stobj = st_buffer_object(bufobj); - - pipe_resource_reference(&ibuffer.buffer, stobj->buffer); - ibuffer.offset = pointer_to_offset(ib->ptr); - - mapped_indices = pipe_buffer_map(pipe, stobj->buffer, - PIPE_TRANSFER_READ, &ib_transfer); - } - else { - /* skip setting ibuffer.buffer as the draw module does not use it */ - mapped_indices = ib->ptr; - } - - draw_set_index_buffer(draw, &ibuffer); - draw_set_mapped_index_buffer(draw, mapped_indices); - } - - /* set the constant buffer */ - draw_set_mapped_constant_buffer(st->draw, PIPE_SHADER_VERTEX, 0, - st->state.constants[PIPE_SHADER_VERTEX].ptr, - st->state.constants[PIPE_SHADER_VERTEX].size); - - - /* draw here */ - for (i = 0; i < nr_prims; i++) { - draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); - } - - - /* - * unmap vertex/index buffers - */ - for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { - if (draw->pt.vertex_buffer[i].buffer) { - pipe_buffer_unmap(pipe, vb_transfer[i]); - pipe_resource_reference(&draw->pt.vertex_buffer[i].buffer, NULL); - draw_set_mapped_vertex_buffer(draw, i, NULL); - } - } - - if (ib) { - draw_set_mapped_index_buffer(draw, NULL); - draw_set_index_buffer(draw, NULL); - - if (ib_transfer) - pipe_buffer_unmap(pipe, ib_transfer); - pipe_resource_reference(&ibuffer.buffer, NULL); - } -} - -#endif /* FEATURE_feedback || FEATURE_rastpos */ - +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 "main/imports.h" +#include "main/image.h" +#include "main/macros.h" +#include "main/mfeatures.h" + +#include "vbo/vbo.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_bufferobjects.h" +#include "st_draw.h" +#include "st_program.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "util/u_inlines.h" + +#include "draw/draw_private.h" +#include "draw/draw_context.h" + + +#if FEATURE_feedback || FEATURE_rastpos + +/** + * Set the (private) draw module's post-transformed vertex format when in + * GL_SELECT or GL_FEEDBACK mode or for glRasterPos. + */ +static void +set_feedback_vertex_format(struct gl_context *ctx) +{ +#if 0 + struct st_context *st = st_context(ctx); + struct vertex_info vinfo; + GLuint i; + + memset(&vinfo, 0, sizeof(vinfo)); + + if (ctx->RenderMode == GL_SELECT) { + assert(ctx->RenderMode == GL_SELECT); + vinfo.num_attribs = 1; + vinfo.format[0] = FORMAT_4F; + vinfo.interp_mode[0] = INTERP_LINEAR; + } + else { + /* GL_FEEDBACK, or glRasterPos */ + /* emit all attribs (pos, color, texcoord) as GLfloat[4] */ + vinfo.num_attribs = st->state.vs->cso->state.num_outputs; + for (i = 0; i < vinfo.num_attribs; i++) { + vinfo.format[i] = FORMAT_4F; + vinfo.interp_mode[i] = INTERP_LINEAR; + } + } + + draw_set_vertex_info(st->draw, &vinfo); +#endif +} + + +/** + * Called by VBO to draw arrays when in selection or feedback mode and + * to implement glRasterPos. + * This is very much like the normal draw_vbo() function above. + * Look at code refactoring some day. + * Might move this into the failover module some day. + */ +void +st_feedback_draw_vbo(struct gl_context *ctx, + const struct gl_client_array **arrays, + const struct _mesa_prim *prims, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, + GLuint min_index, + GLuint max_index) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct draw_context *draw = st->draw; + const struct st_vertex_program *vp; + const struct pipe_shader_state *vs; + struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; + struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; + struct pipe_index_buffer ibuffer; + struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; + struct pipe_transfer *ib_transfer = NULL; + GLuint attr, i; + const void *mapped_indices = NULL; + + assert(draw); + + st_validate_state(st); + + if (!index_bounds_valid) + vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); + + /* must get these after state validation! */ + vp = st->vp; + vs = &st->vp_variant->tgsi; + + if (!st->vp_variant->draw_shader) { + st->vp_variant->draw_shader = draw_create_vertex_shader(draw, vs); + } + + /* + * Set up the draw module's state. + * + * We'd like to do this less frequently, but the normal state-update + * code sends state updates to the pipe, not to our private draw module. + */ + assert(draw); + draw_set_viewport_state(draw, &st->state.viewport); + draw_set_clip_state(draw, &st->state.clip); + draw_set_rasterizer_state(draw, &st->state.rasterizer, NULL); + draw_bind_vertex_shader(draw, st->vp_variant->draw_shader); + set_feedback_vertex_format(ctx); + + /* loop over TGSI shader inputs to determine vertex buffer + * and attribute info + */ + for (attr = 0; attr < vp->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; + void *map; + + if (bufobj && bufobj->Name) { + /* Attribute data is in a VBO. + * Recall that for VBOs, the gl_client_array->Ptr field is + * really an offset from the start of the VBO, not a pointer. + */ + struct st_buffer_object *stobj = st_buffer_object(bufobj); + assert(stobj->buffer); + + vbuffers[attr].buffer = NULL; + pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer); + vbuffers[attr].buffer_offset = pointer_to_offset(arrays[0]->Ptr); + velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr; + } + else { + /* attribute data is in user-space memory, not a VBO */ + uint bytes = (arrays[mesaAttr]->Size + * _mesa_sizeof_type(arrays[mesaAttr]->Type) + * (max_index + 1)); + + /* wrap user data */ + vbuffers[attr].buffer + = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, + bytes, + PIPE_BIND_VERTEX_BUFFER); + vbuffers[attr].buffer_offset = 0; + velements[attr].src_offset = 0; + } + + /* common-case setup */ + vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ + vbuffers[attr].max_index = max_index; + velements[attr].instance_divisor = 0; + velements[attr].vertex_buffer_index = attr; + velements[attr].src_format = + st_pipe_vertex_format(arrays[mesaAttr]->Type, + arrays[mesaAttr]->Size, + arrays[mesaAttr]->Format, + arrays[mesaAttr]->Normalized); + assert(velements[attr].src_format); + + /* tell draw about this attribute */ +#if 0 + draw_set_vertex_buffer(draw, attr, &vbuffer[attr]); +#endif + + /* map the attrib buffer */ + map = pipe_buffer_map(pipe, vbuffers[attr].buffer, + PIPE_TRANSFER_READ, + &vb_transfer[attr]); + draw_set_mapped_vertex_buffer(draw, attr, map); + } + + draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); + draw_set_vertex_elements(draw, vp->num_inputs, velements); + + memset(&ibuffer, 0, sizeof(ibuffer)); + if (ib) { + struct gl_buffer_object *bufobj = ib->obj; + + switch (ib->type) { + case GL_UNSIGNED_INT: + ibuffer.index_size = 4; + break; + case GL_UNSIGNED_SHORT: + ibuffer.index_size = 2; + break; + case GL_UNSIGNED_BYTE: + ibuffer.index_size = 1; + break; + default: + assert(0); + return; + } + + if (bufobj && bufobj->Name) { + struct st_buffer_object *stobj = st_buffer_object(bufobj); + + pipe_resource_reference(&ibuffer.buffer, stobj->buffer); + ibuffer.offset = pointer_to_offset(ib->ptr); + + mapped_indices = pipe_buffer_map(pipe, stobj->buffer, + PIPE_TRANSFER_READ, &ib_transfer); + } + else { + /* skip setting ibuffer.buffer as the draw module does not use it */ + mapped_indices = ib->ptr; + } + + draw_set_index_buffer(draw, &ibuffer); + draw_set_mapped_index_buffer(draw, mapped_indices); + } + + /* set the constant buffer */ + draw_set_mapped_constant_buffer(st->draw, PIPE_SHADER_VERTEX, 0, + st->state.constants[PIPE_SHADER_VERTEX].ptr, + st->state.constants[PIPE_SHADER_VERTEX].size); + + + /* draw here */ + for (i = 0; i < nr_prims; i++) { + draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); + } + + + /* + * unmap vertex/index buffers + */ + for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { + if (draw->pt.vertex_buffer[i].buffer) { + pipe_buffer_unmap(pipe, vb_transfer[i]); + pipe_resource_reference(&draw->pt.vertex_buffer[i].buffer, NULL); + draw_set_mapped_vertex_buffer(draw, i, NULL); + pipe_resource_reference(&vbuffers[i].buffer, NULL); + } + } + + if (ib) { + draw_set_mapped_index_buffer(draw, NULL); + draw_set_index_buffer(draw, NULL); + + if (ib_transfer) + pipe_buffer_unmap(pipe, ib_transfer); + pipe_resource_reference(&ibuffer.buffer, NULL); + } +} + +#endif /* FEATURE_feedback || FEATURE_rastpos */ + diff --git a/mesalib/src/mesa/state_tracker/st_program.c b/mesalib/src/mesa/state_tracker/st_program.c index f70e5005f..fc1dfb3ef 100644 --- a/mesalib/src/mesa/state_tracker/st_program.c +++ b/mesalib/src/mesa/state_tracker/st_program.c @@ -1,1154 +1,1165 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * 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 TUNGSTEN GRAPHICS 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. - * - **************************************************************************/ - /* - * Authors: - * Keith Whitwell - * Brian Paul - */ - - -#include "main/imports.h" -#include "main/hash.h" -#include "main/mfeatures.h" -#include "main/mtypes.h" -#include "program/prog_parameter.h" -#include "program/prog_print.h" -#include "program/programopt.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "pipe/p_shader_tokens.h" -#include "draw/draw_context.h" -#include "tgsi/tgsi_dump.h" -#include "tgsi/tgsi_ureg.h" - -#include "st_debug.h" -#include "st_cb_bitmap.h" -#include "st_cb_drawpixels.h" -#include "st_context.h" -#include "st_program.h" -#include "st_mesa_to_tgsi.h" -#include "cso_cache/cso_context.h" - - - -/** - * Delete a vertex program variant. Note the caller must unlink - * the variant from the linked list. - */ -static void -delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv) -{ - if (vpv->driver_shader) - cso_delete_vertex_shader(st->cso_context, vpv->driver_shader); - -#if FEATURE_feedback || FEATURE_rastpos - if (vpv->draw_shader) - draw_delete_vertex_shader( st->draw, vpv->draw_shader ); -#endif - - if (vpv->tgsi.tokens) - st_free_tokens(vpv->tgsi.tokens); - - FREE( vpv ); -} - - - -/** - * Clean out any old compilations: - */ -void -st_release_vp_variants( struct st_context *st, - struct st_vertex_program *stvp ) -{ - struct st_vp_variant *vpv; - - for (vpv = stvp->variants; vpv; ) { - struct st_vp_variant *next = vpv->next; - delete_vp_variant(st, vpv); - vpv = next; - } - - stvp->variants = NULL; -} - - - -/** - * Delete a fragment program variant. Note the caller must unlink - * the variant from the linked list. - */ -static void -delete_fp_variant(struct st_context *st, struct st_fp_variant *fpv) -{ - if (fpv->driver_shader) - cso_delete_fragment_shader(st->cso_context, fpv->driver_shader); - - FREE(fpv); -} - - -/** - * Free all variants of a fragment program. - */ -void -st_release_fp_variants(struct st_context *st, struct st_fragment_program *stfp) -{ - struct st_fp_variant *fpv; - - for (fpv = stfp->variants; fpv; ) { - struct st_fp_variant *next = fpv->next; - delete_fp_variant(st, fpv); - fpv = next; - } - - stfp->variants = NULL; -} - - -/** - * Delete a geometry program variant. Note the caller must unlink - * the variant from the linked list. - */ -static void -delete_gp_variant(struct st_context *st, struct st_gp_variant *gpv) -{ - if (gpv->driver_shader) - cso_delete_geometry_shader(st->cso_context, gpv->driver_shader); - - FREE(gpv); -} - - -/** - * Free all variants of a geometry program. - */ -void -st_release_gp_variants(struct st_context *st, struct st_geometry_program *stgp) -{ - struct st_gp_variant *gpv; - - for (gpv = stgp->variants; gpv; ) { - struct st_gp_variant *next = gpv->next; - delete_gp_variant(st, gpv); - gpv = next; - } - - stgp->variants = NULL; -} - - - - -/** - * Translate a Mesa vertex shader into a TGSI shader. - * \param outputMapping to map vertex program output registers (VERT_RESULT_x) - * to TGSI output slots - * \param tokensOut destination for TGSI tokens - * \return pointer to cached pipe_shader object. - */ -static void -st_prepare_vertex_program(struct st_context *st, - struct st_vertex_program *stvp) -{ - GLuint attr; - - stvp->num_inputs = 0; - stvp->num_outputs = 0; - - if (stvp->Base.IsPositionInvariant) - _mesa_insert_mvp_code(st->ctx, &stvp->Base); - - assert(stvp->Base.Base.NumInstructions > 1); - - /* - * Determine number of inputs, the mappings between VERT_ATTRIB_x - * and TGSI generic input indexes, plus input attrib semantic info. - */ - for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { - if (stvp->Base.Base.InputsRead & (1 << attr)) { - stvp->input_to_index[attr] = stvp->num_inputs; - stvp->index_to_input[stvp->num_inputs] = attr; - stvp->num_inputs++; - } - } - /* bit of a hack, presetup potentially unused edgeflag input */ - stvp->input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs; - stvp->index_to_input[stvp->num_inputs] = VERT_ATTRIB_EDGEFLAG; - - /* Compute mapping of vertex program outputs to slots. - */ - for (attr = 0; attr < VERT_RESULT_MAX; attr++) { - if ((stvp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) == 0) { - stvp->result_to_output[attr] = ~0; - } - else { - unsigned slot = stvp->num_outputs++; - - stvp->result_to_output[attr] = slot; - - switch (attr) { - case VERT_RESULT_HPOS: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_COL0: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_COL1: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stvp->output_semantic_index[slot] = 1; - break; - case VERT_RESULT_BFC0: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_BFC1: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - stvp->output_semantic_index[slot] = 1; - break; - case VERT_RESULT_FOGC: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_PSIZ: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_EDGE: - assert(0); - break; - - case VERT_RESULT_TEX0: - case VERT_RESULT_TEX1: - case VERT_RESULT_TEX2: - case VERT_RESULT_TEX3: - case VERT_RESULT_TEX4: - case VERT_RESULT_TEX5: - case VERT_RESULT_TEX6: - case VERT_RESULT_TEX7: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stvp->output_semantic_index[slot] = attr - VERT_RESULT_TEX0; - break; - - case VERT_RESULT_VAR0: - default: - assert(attr < VERT_RESULT_MAX); - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stvp->output_semantic_index[slot] = (FRAG_ATTRIB_VAR0 - - FRAG_ATTRIB_TEX0 + - attr - - VERT_RESULT_VAR0); - break; - } - } - } - /* similar hack to above, presetup potentially unused edgeflag output */ - stvp->result_to_output[VERT_RESULT_EDGE] = stvp->num_outputs; - stvp->output_semantic_name[stvp->num_outputs] = TGSI_SEMANTIC_EDGEFLAG; - stvp->output_semantic_index[stvp->num_outputs] = 0; -} - - -/** - * Translate a vertex program to create a new variant. - */ -static struct st_vp_variant * -st_translate_vertex_program(struct st_context *st, - struct st_vertex_program *stvp, - const struct st_vp_variant_key *key) -{ - struct st_vp_variant *vpv = CALLOC_STRUCT(st_vp_variant); - struct pipe_context *pipe = st->pipe; - struct ureg_program *ureg; - enum pipe_error error; - unsigned num_outputs; - - st_prepare_vertex_program( st, stvp ); - - _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT); - _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_VARYING); - - ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); - if (ureg == NULL) { - FREE(vpv); - return NULL; - } - - vpv->key = *key; - - vpv->num_inputs = stvp->num_inputs; - num_outputs = stvp->num_outputs; - if (key->passthrough_edgeflags) { - vpv->num_inputs++; - num_outputs++; - } - - if (ST_DEBUG & DEBUG_MESA) { - _mesa_print_program(&stvp->Base.Base); - _mesa_print_program_parameters(st->ctx, &stvp->Base.Base); - debug_printf("\n"); - } - - error = st_translate_mesa_program(st->ctx, - TGSI_PROCESSOR_VERTEX, - ureg, - &stvp->Base.Base, - /* inputs */ - vpv->num_inputs, - stvp->input_to_index, - NULL, /* input semantic name */ - NULL, /* input semantic index */ - NULL, - /* outputs */ - num_outputs, - stvp->result_to_output, - stvp->output_semantic_name, - stvp->output_semantic_index, - key->passthrough_edgeflags ); - - if (error) - goto fail; - - vpv->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - if (!vpv->tgsi.tokens) - goto fail; - - ureg_destroy( ureg ); - - vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi); - - if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump( vpv->tgsi.tokens, 0 ); - debug_printf("\n"); - } - - return vpv; - -fail: - debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__); - _mesa_print_program(&stvp->Base.Base); - debug_assert(0); - - ureg_destroy( ureg ); - return NULL; -} - - -/** - * Find/create a vertex program variant. - */ -struct st_vp_variant * -st_get_vp_variant(struct st_context *st, - struct st_vertex_program *stvp, - const struct st_vp_variant_key *key) -{ - struct st_vp_variant *vpv; - - /* Search for existing variant */ - for (vpv = stvp->variants; vpv; vpv = vpv->next) { - if (memcmp(&vpv->key, key, sizeof(*key)) == 0) { - break; - } - } - - if (!vpv) { - /* create now */ - vpv = st_translate_vertex_program(st, stvp, key); - if (vpv) { - /* insert into list */ - vpv->next = stvp->variants; - stvp->variants = vpv; - } - } - - return vpv; -} - - -/** - * Translate a Mesa fragment shader into a TGSI shader using extra info in - * the key. - * \return new fragment program variant - */ -static struct st_fp_variant * -st_translate_fragment_program(struct st_context *st, - struct st_fragment_program *stfp, - const struct st_fp_variant_key *key) -{ - struct pipe_context *pipe = st->pipe; - struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant); - - if (!variant) - return NULL; - - assert(!(key->bitmap && key->drawpixels)); - -#if FEATURE_drawpix - if (key->bitmap) { - /* glBitmap drawing */ - struct gl_fragment_program *fp; - - st_make_bitmap_fragment_program(st, &stfp->Base, - &fp, &variant->bitmap_sampler); - - variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); - stfp = st_fragment_program(fp); - } - else if (key->drawpixels) { - /* glDrawPixels drawing */ - struct gl_fragment_program *fp; - - if (key->drawpixels_z || key->drawpixels_stencil) { - fp = st_make_drawpix_z_stencil_program(st, key->drawpixels_z, - key->drawpixels_stencil); - } - else { - /* RGBA */ - st_make_drawpix_fragment_program(st, &stfp->Base, &fp); - variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); - } - stfp = st_fragment_program(fp); - } -#endif - - if (!stfp->tgsi.tokens) { - /* need to translate Mesa instructions to TGSI now */ - GLuint outputMapping[FRAG_RESULT_MAX]; - GLuint inputMapping[FRAG_ATTRIB_MAX]; - GLuint interpMode[PIPE_MAX_SHADER_INPUTS]; /* XXX size? */ - GLuint attr; - enum pipe_error error; - const GLbitfield inputsRead = stfp->Base.Base.InputsRead; - struct ureg_program *ureg; - GLboolean write_all = GL_FALSE; - - ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; - ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; - uint fs_num_inputs = 0; - - ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; - ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; - uint fs_num_outputs = 0; - - - _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT); - - /* - * Convert Mesa program inputs to TGSI input register semantics. - */ - for (attr = 0; attr < FRAG_ATTRIB_MAX; attr++) { - if (inputsRead & (1 << attr)) { - const GLuint slot = fs_num_inputs++; - - inputMapping[attr] = slot; - - switch (attr) { - case FRAG_ATTRIB_WPOS: - input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - break; - case FRAG_ATTRIB_COL0: - input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - break; - case FRAG_ATTRIB_COL1: - input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - input_semantic_index[slot] = 1; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - break; - case FRAG_ATTRIB_FOGC: - input_semantic_name[slot] = TGSI_SEMANTIC_FOG; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; - break; - case FRAG_ATTRIB_FACE: - input_semantic_name[slot] = TGSI_SEMANTIC_FACE; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; - break; - /* In most cases, there is nothing special about these - * inputs, so adopt a convention to use the generic - * semantic name and the mesa FRAG_ATTRIB_ number as the - * index. - * - * All that is required is that the vertex shader labels - * its own outputs similarly, and that the vertex shader - * generates at least every output required by the - * fragment shader plus fixed-function hardware (such as - * BFC). - * - * There is no requirement that semantic indexes start at - * zero or be restricted to a particular range -- nobody - * should be building tables based on semantic index. - */ - case FRAG_ATTRIB_PNTC: - case FRAG_ATTRIB_TEX0: - case FRAG_ATTRIB_TEX1: - case FRAG_ATTRIB_TEX2: - case FRAG_ATTRIB_TEX3: - case FRAG_ATTRIB_TEX4: - case FRAG_ATTRIB_TEX5: - case FRAG_ATTRIB_TEX6: - case FRAG_ATTRIB_TEX7: - case FRAG_ATTRIB_VAR0: - default: - /* Actually, let's try and zero-base this just for - * readability of the generated TGSI. - */ - assert(attr >= FRAG_ATTRIB_TEX0); - input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0); - input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - if (attr == FRAG_ATTRIB_PNTC) - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - else - interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; - break; - } - } - else { - inputMapping[attr] = -1; - } - } - - /* - * Semantics and mapping for outputs - */ - { - uint numColors = 0; - GLbitfield64 outputsWritten = stfp->Base.Base.OutputsWritten; - - /* if z is written, emit that first */ - if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { - fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_POSITION; - fs_output_semantic_index[fs_num_outputs] = 0; - outputMapping[FRAG_RESULT_DEPTH] = fs_num_outputs; - fs_num_outputs++; - outputsWritten &= ~(1 << FRAG_RESULT_DEPTH); - } - - if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) { - fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_STENCIL; - fs_output_semantic_index[fs_num_outputs] = 0; - outputMapping[FRAG_RESULT_STENCIL] = fs_num_outputs; - fs_num_outputs++; - outputsWritten &= ~(1 << FRAG_RESULT_STENCIL); - } - - /* handle remaning outputs (color) */ - for (attr = 0; attr < FRAG_RESULT_MAX; attr++) { - if (outputsWritten & BITFIELD64_BIT(attr)) { - switch (attr) { - case FRAG_RESULT_DEPTH: - case FRAG_RESULT_STENCIL: - /* handled above */ - assert(0); - break; - case FRAG_RESULT_COLOR: - write_all = GL_TRUE; /* fallthrough */ - default: - assert(attr == FRAG_RESULT_COLOR || - (FRAG_RESULT_DATA0 <= attr && attr < FRAG_RESULT_MAX)); - fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_COLOR; - fs_output_semantic_index[fs_num_outputs] = numColors; - outputMapping[attr] = fs_num_outputs; - numColors++; - break; - } - - fs_num_outputs++; - } - } - } - - ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); - if (ureg == NULL) - return NULL; - - if (ST_DEBUG & DEBUG_MESA) { - _mesa_print_program(&stfp->Base.Base); - _mesa_print_program_parameters(st->ctx, &stfp->Base.Base); - debug_printf("\n"); - } - if (write_all == GL_TRUE) - ureg_property_fs_color0_writes_all_cbufs(ureg, 1); - - error = st_translate_mesa_program(st->ctx, - TGSI_PROCESSOR_FRAGMENT, - ureg, - &stfp->Base.Base, - /* inputs */ - fs_num_inputs, - inputMapping, - input_semantic_name, - input_semantic_index, - interpMode, - /* outputs */ - fs_num_outputs, - outputMapping, - fs_output_semantic_name, - fs_output_semantic_index, FALSE ); - - stfp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - ureg_destroy( ureg ); - } - - /* fill in variant */ - variant->driver_shader = pipe->create_fs_state(pipe, &stfp->tgsi); - variant->key = *key; - - if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump( stfp->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/ ); - debug_printf("\n"); - } - - return variant; -} - - -/** - * Translate fragment program if needed. - */ -struct st_fp_variant * -st_get_fp_variant(struct st_context *st, - struct st_fragment_program *stfp, - const struct st_fp_variant_key *key) -{ - struct st_fp_variant *fpv; - - /* Search for existing variant */ - for (fpv = stfp->variants; fpv; fpv = fpv->next) { - if (memcmp(&fpv->key, key, sizeof(*key)) == 0) { - break; - } - } - - if (!fpv) { - /* create new */ - fpv = st_translate_fragment_program(st, stfp, key); - if (fpv) { - /* insert into list */ - fpv->next = stfp->variants; - stfp->variants = fpv; - } - } - - return fpv; -} - - -/** - * Translate a geometry program to create a new variant. - */ -static struct st_gp_variant * -st_translate_geometry_program(struct st_context *st, - struct st_geometry_program *stgp, - const struct st_gp_variant_key *key) -{ - GLuint inputMapping[GEOM_ATTRIB_MAX]; - GLuint outputMapping[GEOM_RESULT_MAX]; - struct pipe_context *pipe = st->pipe; - enum pipe_error error; - GLuint attr; - const GLbitfield inputsRead = stgp->Base.Base.InputsRead; - GLuint vslot = 0; - GLuint num_generic = 0; - - uint gs_num_inputs = 0; - uint gs_builtin_inputs = 0; - uint gs_array_offset = 0; - - ubyte gs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; - ubyte gs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; - uint gs_num_outputs = 0; - - GLint i; - GLuint maxSlot = 0; - struct ureg_program *ureg; - - struct st_gp_variant *gpv; - - gpv = CALLOC_STRUCT(st_gp_variant); - if (!gpv) - return NULL; - - _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_OUTPUT); - _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_VARYING); - - ureg = ureg_create( TGSI_PROCESSOR_GEOMETRY ); - if (ureg == NULL) { - FREE(gpv); - return NULL; - } - - /* which vertex output goes to the first geometry input */ - vslot = 0; - - memset(inputMapping, 0, sizeof(inputMapping)); - memset(outputMapping, 0, sizeof(outputMapping)); - - /* - * Convert Mesa program inputs to TGSI input register semantics. - */ - for (attr = 0; attr < GEOM_ATTRIB_MAX; attr++) { - if (inputsRead & (1 << attr)) { - const GLuint slot = gs_num_inputs; - - gs_num_inputs++; - - inputMapping[attr] = slot; - - stgp->input_map[slot + gs_array_offset] = vslot - gs_builtin_inputs; - stgp->input_to_index[attr] = vslot; - stgp->index_to_input[vslot] = attr; - ++vslot; - - if (attr != GEOM_ATTRIB_PRIMITIVE_ID) { - gs_array_offset += 2; - } else - ++gs_builtin_inputs; - -#if 0 - debug_printf("input map at %d = %d\n", - slot + gs_array_offset, stgp->input_map[slot + gs_array_offset]); -#endif - - switch (attr) { - case GEOM_ATTRIB_PRIMITIVE_ID: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_POSITION: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_COLOR0: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_COLOR1: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stgp->input_semantic_index[slot] = 1; - break; - case GEOM_ATTRIB_FOG_FRAG_COORD: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_TEX_COORD: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stgp->input_semantic_index[slot] = num_generic++; - break; - case GEOM_ATTRIB_VAR0: - /* fall-through */ - default: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stgp->input_semantic_index[slot] = num_generic++; - } - } - } - - /* initialize output semantics to defaults */ - for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) { - gs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC; - gs_output_semantic_index[i] = 0; - } - - num_generic = 0; - /* - * Determine number of outputs, the (default) output register - * mapping and the semantic information for each output. - */ - for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { - if (stgp->Base.Base.OutputsWritten & (1 << attr)) { - GLuint slot; - - slot = gs_num_outputs; - gs_num_outputs++; - outputMapping[attr] = slot; - - switch (attr) { - case GEOM_RESULT_POS: - assert(slot == 0); - gs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_COL0: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_COL1: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - gs_output_semantic_index[slot] = 1; - break; - case GEOM_RESULT_SCOL0: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_SCOL1: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - gs_output_semantic_index[slot] = 1; - break; - case GEOM_RESULT_FOGC: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_PSIZ: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_TEX0: - case GEOM_RESULT_TEX1: - case GEOM_RESULT_TEX2: - case GEOM_RESULT_TEX3: - case GEOM_RESULT_TEX4: - case GEOM_RESULT_TEX5: - case GEOM_RESULT_TEX6: - case GEOM_RESULT_TEX7: - /* fall-through */ - case GEOM_RESULT_VAR0: - /* fall-through */ - default: - assert(slot < Elements(gs_output_semantic_name)); - /* use default semantic info */ - gs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - gs_output_semantic_index[slot] = num_generic++; - } - } - } - - assert(gs_output_semantic_name[0] == TGSI_SEMANTIC_POSITION); - - /* find max output slot referenced to compute gs_num_outputs */ - for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { - if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot) - maxSlot = outputMapping[attr]; - } - gs_num_outputs = maxSlot + 1; - -#if 0 /* debug */ - { - GLuint i; - printf("outputMapping? %d\n", outputMapping ? 1 : 0); - if (outputMapping) { - printf("attr -> slot\n"); - for (i = 0; i < 16; i++) { - printf(" %2d %3d\n", i, outputMapping[i]); - } - } - printf("slot sem_name sem_index\n"); - for (i = 0; i < gs_num_outputs; i++) { - printf(" %2d %d %d\n", - i, - gs_output_semantic_name[i], - gs_output_semantic_index[i]); - } - } -#endif - - /* free old shader state, if any */ - if (stgp->tgsi.tokens) { - st_free_tokens(stgp->tgsi.tokens); - stgp->tgsi.tokens = NULL; - } - - ureg_property_gs_input_prim(ureg, stgp->Base.InputType); - ureg_property_gs_output_prim(ureg, stgp->Base.OutputType); - ureg_property_gs_max_vertices(ureg, stgp->Base.VerticesOut); - - error = st_translate_mesa_program(st->ctx, - TGSI_PROCESSOR_GEOMETRY, - ureg, - &stgp->Base.Base, - /* inputs */ - gs_num_inputs, - inputMapping, - stgp->input_semantic_name, - stgp->input_semantic_index, - NULL, - /* outputs */ - gs_num_outputs, - outputMapping, - gs_output_semantic_name, - gs_output_semantic_index, - FALSE); - - stgp->num_inputs = gs_num_inputs; - stgp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - ureg_destroy( ureg ); - - /* fill in new variant */ - gpv->driver_shader = pipe->create_gs_state(pipe, &stgp->tgsi); - gpv->key = *key; - - if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) { - _mesa_print_program(&stgp->Base.Base); - debug_printf("\n"); - } - - if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump(stgp->tgsi.tokens, 0); - debug_printf("\n"); - } - - return gpv; -} - - -/** - * Get/create geometry program variant. - */ -struct st_gp_variant * -st_get_gp_variant(struct st_context *st, - struct st_geometry_program *stgp, - const struct st_gp_variant_key *key) -{ - struct st_gp_variant *gpv; - - /* Search for existing variant */ - for (gpv = stgp->variants; gpv; gpv = gpv->next) { - if (memcmp(&gpv->key, key, sizeof(*key)) == 0) { - break; - } - } - - if (!gpv) { - /* create new */ - gpv = st_translate_geometry_program(st, stgp, key); - if (gpv) { - /* insert into list */ - gpv->next = stgp->variants; - stgp->variants = gpv; - } - } - - return gpv; -} - - - - -/** - * Debug- print current shader text - */ -void -st_print_shaders(struct gl_context *ctx) -{ - struct gl_shader_program *shProg[3] = { - ctx->Shader.CurrentVertexProgram, - ctx->Shader.CurrentGeometryProgram, - ctx->Shader.CurrentFragmentProgram, - }; - unsigned j; - - for (j = 0; j < 3; j++) { - unsigned i; - - if (shProg[j] == NULL) - continue; - - for (i = 0; i < shProg[j]->NumShaders; i++) { - struct gl_shader *sh; - - switch (shProg[j]->Shaders[i]->Type) { - case GL_VERTEX_SHADER: - sh = (i != 0) ? NULL : shProg[j]->Shaders[i]; - break; - case GL_GEOMETRY_SHADER_ARB: - sh = (i != 1) ? NULL : shProg[j]->Shaders[i]; - break; - case GL_FRAGMENT_SHADER: - sh = (i != 2) ? NULL : shProg[j]->Shaders[i]; - break; - default: - assert(0); - sh = NULL; - break; - } - - if (sh != NULL) { - printf("GLSL shader %u of %u:\n", i, shProg[j]->NumShaders); - printf("%s\n", sh->Source); - } - } - } -} - - -/** - * Vert/Geom/Frag programs have per-context variants. Free all the - * variants attached to the given program which match the given context. - */ -static void -destroy_program_variants(struct st_context *st, struct gl_program *program) -{ - if (!program) - return; - - switch (program->Target) { - case GL_VERTEX_PROGRAM_ARB: - { - struct st_vertex_program *stvp = (struct st_vertex_program *) program; - struct st_vp_variant *vpv, **prevPtr = &stvp->variants; - - for (vpv = stvp->variants; vpv; ) { - struct st_vp_variant *next = vpv->next; - if (vpv->key.st == st) { - /* unlink from list */ - *prevPtr = next; - /* destroy this variant */ - delete_vp_variant(st, vpv); - } - else { - prevPtr = &vpv->next; - } - vpv = next; - } - } - break; - case GL_FRAGMENT_PROGRAM_ARB: - { - struct st_fragment_program *stfp = - (struct st_fragment_program *) program; - struct st_fp_variant *fpv, **prevPtr = &stfp->variants; - - for (fpv = stfp->variants; fpv; ) { - struct st_fp_variant *next = fpv->next; - if (fpv->key.st == st) { - /* unlink from list */ - *prevPtr = next; - /* destroy this variant */ - delete_fp_variant(st, fpv); - } - else { - prevPtr = &fpv->next; - } - fpv = next; - } - } - break; - case MESA_GEOMETRY_PROGRAM: - { - struct st_geometry_program *stgp = - (struct st_geometry_program *) program; - struct st_gp_variant *gpv, **prevPtr = &stgp->variants; - - for (gpv = stgp->variants; gpv; ) { - struct st_gp_variant *next = gpv->next; - if (gpv->key.st == st) { - /* unlink from list */ - *prevPtr = next; - /* destroy this variant */ - delete_gp_variant(st, gpv); - } - else { - prevPtr = &gpv->next; - } - gpv = next; - } - } - break; - default: - _mesa_problem(NULL, "Unexpected program target in " - "destroy_program_variants_cb()"); - } -} - - -/** - * Callback for _mesa_HashWalk. Free all the shader's program variants - * which match the given context. - */ -static void -destroy_shader_program_variants_cb(GLuint key, void *data, void *userData) -{ - struct st_context *st = (struct st_context *) userData; - struct gl_shader *shader = (struct gl_shader *) data; - - switch (shader->Type) { - case GL_SHADER_PROGRAM_MESA: - { - struct gl_shader_program *shProg = (struct gl_shader_program *) data; - GLuint i; - - for (i = 0; i < shProg->NumShaders; i++) { - destroy_program_variants(st, shProg->Shaders[i]->Program); - } - - destroy_program_variants(st, (struct gl_program *) - shProg->VertexProgram); - destroy_program_variants(st, (struct gl_program *) - shProg->FragmentProgram); - destroy_program_variants(st, (struct gl_program *) - shProg->GeometryProgram); - } - break; - case GL_VERTEX_SHADER: - case GL_FRAGMENT_SHADER: - case GL_GEOMETRY_SHADER: - { - destroy_program_variants(st, shader->Program); - } - break; - default: - assert(0); - } -} - - -/** - * Callback for _mesa_HashWalk. Free all the program variants which match - * the given context. - */ -static void -destroy_program_variants_cb(GLuint key, void *data, void *userData) -{ - struct st_context *st = (struct st_context *) userData; - struct gl_program *program = (struct gl_program *) data; - destroy_program_variants(st, program); -} - - -/** - * Walk over all shaders and programs to delete any variants which - * belong to the given context. - * This is called during context tear-down. - */ -void -st_destroy_program_variants(struct st_context *st) -{ - /* ARB vert/frag program */ - _mesa_HashWalk(st->ctx->Shared->Programs, - destroy_program_variants_cb, st); - - /* GLSL vert/frag/geom shaders */ - _mesa_HashWalk(st->ctx->Shared->ShaderObjects, - destroy_shader_program_variants_cb, st); -} +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + * + **************************************************************************/ + /* + * Authors: + * Keith Whitwell + * Brian Paul + */ + + +#include "main/imports.h" +#include "main/hash.h" +#include "main/mfeatures.h" +#include "main/mtypes.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/programopt.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_shader_tokens.h" +#include "draw/draw_context.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_ureg.h" + +#include "st_debug.h" +#include "st_cb_bitmap.h" +#include "st_cb_drawpixels.h" +#include "st_context.h" +#include "st_program.h" +#include "st_mesa_to_tgsi.h" +#include "cso_cache/cso_context.h" + + + +/** + * Delete a vertex program variant. Note the caller must unlink + * the variant from the linked list. + */ +static void +delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv) +{ + if (vpv->driver_shader) + cso_delete_vertex_shader(st->cso_context, vpv->driver_shader); + +#if FEATURE_feedback || FEATURE_rastpos + if (vpv->draw_shader) + draw_delete_vertex_shader( st->draw, vpv->draw_shader ); +#endif + + if (vpv->tgsi.tokens) + st_free_tokens(vpv->tgsi.tokens); + + FREE( vpv ); +} + + + +/** + * Clean out any old compilations: + */ +void +st_release_vp_variants( struct st_context *st, + struct st_vertex_program *stvp ) +{ + struct st_vp_variant *vpv; + + for (vpv = stvp->variants; vpv; ) { + struct st_vp_variant *next = vpv->next; + delete_vp_variant(st, vpv); + vpv = next; + } + + stvp->variants = NULL; +} + + + +/** + * Delete a fragment program variant. Note the caller must unlink + * the variant from the linked list. + */ +static void +delete_fp_variant(struct st_context *st, struct st_fp_variant *fpv) +{ + if (fpv->driver_shader) + cso_delete_fragment_shader(st->cso_context, fpv->driver_shader); + if (fpv->parameters) + _mesa_free_parameter_list(fpv->parameters); + + FREE(fpv); +} + + +/** + * Free all variants of a fragment program. + */ +void +st_release_fp_variants(struct st_context *st, struct st_fragment_program *stfp) +{ + struct st_fp_variant *fpv; + + for (fpv = stfp->variants; fpv; ) { + struct st_fp_variant *next = fpv->next; + delete_fp_variant(st, fpv); + fpv = next; + } + + stfp->variants = NULL; +} + + +/** + * Delete a geometry program variant. Note the caller must unlink + * the variant from the linked list. + */ +static void +delete_gp_variant(struct st_context *st, struct st_gp_variant *gpv) +{ + if (gpv->driver_shader) + cso_delete_geometry_shader(st->cso_context, gpv->driver_shader); + + FREE(gpv); +} + + +/** + * Free all variants of a geometry program. + */ +void +st_release_gp_variants(struct st_context *st, struct st_geometry_program *stgp) +{ + struct st_gp_variant *gpv; + + for (gpv = stgp->variants; gpv; ) { + struct st_gp_variant *next = gpv->next; + delete_gp_variant(st, gpv); + gpv = next; + } + + stgp->variants = NULL; +} + + + + +/** + * Translate a Mesa vertex shader into a TGSI shader. + * \param outputMapping to map vertex program output registers (VERT_RESULT_x) + * to TGSI output slots + * \param tokensOut destination for TGSI tokens + * \return pointer to cached pipe_shader object. + */ +static void +st_prepare_vertex_program(struct st_context *st, + struct st_vertex_program *stvp) +{ + GLuint attr; + + stvp->num_inputs = 0; + stvp->num_outputs = 0; + + if (stvp->Base.IsPositionInvariant) + _mesa_insert_mvp_code(st->ctx, &stvp->Base); + + assert(stvp->Base.Base.NumInstructions > 1); + + /* + * Determine number of inputs, the mappings between VERT_ATTRIB_x + * and TGSI generic input indexes, plus input attrib semantic info. + */ + for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { + if (stvp->Base.Base.InputsRead & (1 << attr)) { + stvp->input_to_index[attr] = stvp->num_inputs; + stvp->index_to_input[stvp->num_inputs] = attr; + stvp->num_inputs++; + } + } + /* bit of a hack, presetup potentially unused edgeflag input */ + stvp->input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs; + stvp->index_to_input[stvp->num_inputs] = VERT_ATTRIB_EDGEFLAG; + + /* Compute mapping of vertex program outputs to slots. + */ + for (attr = 0; attr < VERT_RESULT_MAX; attr++) { + if ((stvp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) == 0) { + stvp->result_to_output[attr] = ~0; + } + else { + unsigned slot = stvp->num_outputs++; + + stvp->result_to_output[attr] = slot; + + switch (attr) { + case VERT_RESULT_HPOS: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_COL0: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_COL1: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stvp->output_semantic_index[slot] = 1; + break; + case VERT_RESULT_BFC0: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_BFC1: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + stvp->output_semantic_index[slot] = 1; + break; + case VERT_RESULT_FOGC: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_PSIZ: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_EDGE: + assert(0); + break; + + case VERT_RESULT_TEX0: + case VERT_RESULT_TEX1: + case VERT_RESULT_TEX2: + case VERT_RESULT_TEX3: + case VERT_RESULT_TEX4: + case VERT_RESULT_TEX5: + case VERT_RESULT_TEX6: + case VERT_RESULT_TEX7: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stvp->output_semantic_index[slot] = attr - VERT_RESULT_TEX0; + break; + + case VERT_RESULT_VAR0: + default: + assert(attr < VERT_RESULT_MAX); + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stvp->output_semantic_index[slot] = (FRAG_ATTRIB_VAR0 - + FRAG_ATTRIB_TEX0 + + attr - + VERT_RESULT_VAR0); + break; + } + } + } + /* similar hack to above, presetup potentially unused edgeflag output */ + stvp->result_to_output[VERT_RESULT_EDGE] = stvp->num_outputs; + stvp->output_semantic_name[stvp->num_outputs] = TGSI_SEMANTIC_EDGEFLAG; + stvp->output_semantic_index[stvp->num_outputs] = 0; +} + + +/** + * Translate a vertex program to create a new variant. + */ +static struct st_vp_variant * +st_translate_vertex_program(struct st_context *st, + struct st_vertex_program *stvp, + const struct st_vp_variant_key *key) +{ + struct st_vp_variant *vpv = CALLOC_STRUCT(st_vp_variant); + struct pipe_context *pipe = st->pipe; + struct ureg_program *ureg; + enum pipe_error error; + unsigned num_outputs; + + st_prepare_vertex_program( st, stvp ); + + _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT); + _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_VARYING); + + ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); + if (ureg == NULL) { + FREE(vpv); + return NULL; + } + + vpv->key = *key; + + vpv->num_inputs = stvp->num_inputs; + num_outputs = stvp->num_outputs; + if (key->passthrough_edgeflags) { + vpv->num_inputs++; + num_outputs++; + } + + if (ST_DEBUG & DEBUG_MESA) { + _mesa_print_program(&stvp->Base.Base); + _mesa_print_program_parameters(st->ctx, &stvp->Base.Base); + debug_printf("\n"); + } + + error = st_translate_mesa_program(st->ctx, + TGSI_PROCESSOR_VERTEX, + ureg, + &stvp->Base.Base, + /* inputs */ + vpv->num_inputs, + stvp->input_to_index, + NULL, /* input semantic name */ + NULL, /* input semantic index */ + NULL, + /* outputs */ + num_outputs, + stvp->result_to_output, + stvp->output_semantic_name, + stvp->output_semantic_index, + key->passthrough_edgeflags ); + + if (error) + goto fail; + + vpv->tgsi.tokens = ureg_get_tokens( ureg, NULL ); + if (!vpv->tgsi.tokens) + goto fail; + + ureg_destroy( ureg ); + + vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi); + + if (ST_DEBUG & DEBUG_TGSI) { + tgsi_dump( vpv->tgsi.tokens, 0 ); + debug_printf("\n"); + } + + return vpv; + +fail: + debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__); + _mesa_print_program(&stvp->Base.Base); + debug_assert(0); + + ureg_destroy( ureg ); + return NULL; +} + + +/** + * Find/create a vertex program variant. + */ +struct st_vp_variant * +st_get_vp_variant(struct st_context *st, + struct st_vertex_program *stvp, + const struct st_vp_variant_key *key) +{ + struct st_vp_variant *vpv; + + /* Search for existing variant */ + for (vpv = stvp->variants; vpv; vpv = vpv->next) { + if (memcmp(&vpv->key, key, sizeof(*key)) == 0) { + break; + } + } + + if (!vpv) { + /* create now */ + vpv = st_translate_vertex_program(st, stvp, key); + if (vpv) { + /* insert into list */ + vpv->next = stvp->variants; + stvp->variants = vpv; + } + } + + return vpv; +} + + +/** + * Translate a Mesa fragment shader into a TGSI shader using extra info in + * the key. + * \return new fragment program variant + */ +static struct st_fp_variant * +st_translate_fragment_program(struct st_context *st, + struct st_fragment_program *stfp, + const struct st_fp_variant_key *key) +{ + struct pipe_context *pipe = st->pipe; + struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant); + GLboolean deleteFP = GL_FALSE; + + if (!variant) + return NULL; + + assert(!(key->bitmap && key->drawpixels)); + +#if FEATURE_drawpix + if (key->bitmap) { + /* glBitmap drawing */ + struct gl_fragment_program *fp; /* we free this temp program below */ + + st_make_bitmap_fragment_program(st, &stfp->Base, + &fp, &variant->bitmap_sampler); + + variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); + stfp = st_fragment_program(fp); + deleteFP = GL_TRUE; + } + else if (key->drawpixels) { + /* glDrawPixels drawing */ + struct gl_fragment_program *fp; /* we free this temp program below */ + + if (key->drawpixels_z || key->drawpixels_stencil) { + fp = st_make_drawpix_z_stencil_program(st, key->drawpixels_z, + key->drawpixels_stencil); + } + else { + /* RGBA */ + st_make_drawpix_fragment_program(st, &stfp->Base, &fp); + variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); + deleteFP = GL_TRUE; + } + stfp = st_fragment_program(fp); + } +#endif + + if (!stfp->tgsi.tokens) { + /* need to translate Mesa instructions to TGSI now */ + GLuint outputMapping[FRAG_RESULT_MAX]; + GLuint inputMapping[FRAG_ATTRIB_MAX]; + GLuint interpMode[PIPE_MAX_SHADER_INPUTS]; /* XXX size? */ + GLuint attr; + enum pipe_error error; + const GLbitfield inputsRead = stfp->Base.Base.InputsRead; + struct ureg_program *ureg; + GLboolean write_all = GL_FALSE; + + ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; + ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; + uint fs_num_inputs = 0; + + ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; + ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; + uint fs_num_outputs = 0; + + + _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT); + + /* + * Convert Mesa program inputs to TGSI input register semantics. + */ + for (attr = 0; attr < FRAG_ATTRIB_MAX; attr++) { + if (inputsRead & (1 << attr)) { + const GLuint slot = fs_num_inputs++; + + inputMapping[attr] = slot; + + switch (attr) { + case FRAG_ATTRIB_WPOS: + input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_COL0: + input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_COL1: + input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + input_semantic_index[slot] = 1; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_FOGC: + input_semantic_name[slot] = TGSI_SEMANTIC_FOG; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; + break; + case FRAG_ATTRIB_FACE: + input_semantic_name[slot] = TGSI_SEMANTIC_FACE; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; + break; + /* In most cases, there is nothing special about these + * inputs, so adopt a convention to use the generic + * semantic name and the mesa FRAG_ATTRIB_ number as the + * index. + * + * All that is required is that the vertex shader labels + * its own outputs similarly, and that the vertex shader + * generates at least every output required by the + * fragment shader plus fixed-function hardware (such as + * BFC). + * + * There is no requirement that semantic indexes start at + * zero or be restricted to a particular range -- nobody + * should be building tables based on semantic index. + */ + case FRAG_ATTRIB_PNTC: + case FRAG_ATTRIB_TEX0: + case FRAG_ATTRIB_TEX1: + case FRAG_ATTRIB_TEX2: + case FRAG_ATTRIB_TEX3: + case FRAG_ATTRIB_TEX4: + case FRAG_ATTRIB_TEX5: + case FRAG_ATTRIB_TEX6: + case FRAG_ATTRIB_TEX7: + case FRAG_ATTRIB_VAR0: + default: + /* Actually, let's try and zero-base this just for + * readability of the generated TGSI. + */ + assert(attr >= FRAG_ATTRIB_TEX0); + input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0); + input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + if (attr == FRAG_ATTRIB_PNTC) + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + else + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; + break; + } + } + else { + inputMapping[attr] = -1; + } + } + + /* + * Semantics and mapping for outputs + */ + { + uint numColors = 0; + GLbitfield64 outputsWritten = stfp->Base.Base.OutputsWritten; + + /* if z is written, emit that first */ + if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_POSITION; + fs_output_semantic_index[fs_num_outputs] = 0; + outputMapping[FRAG_RESULT_DEPTH] = fs_num_outputs; + fs_num_outputs++; + outputsWritten &= ~(1 << FRAG_RESULT_DEPTH); + } + + if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) { + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_STENCIL; + fs_output_semantic_index[fs_num_outputs] = 0; + outputMapping[FRAG_RESULT_STENCIL] = fs_num_outputs; + fs_num_outputs++; + outputsWritten &= ~(1 << FRAG_RESULT_STENCIL); + } + + /* handle remaning outputs (color) */ + for (attr = 0; attr < FRAG_RESULT_MAX; attr++) { + if (outputsWritten & BITFIELD64_BIT(attr)) { + switch (attr) { + case FRAG_RESULT_DEPTH: + case FRAG_RESULT_STENCIL: + /* handled above */ + assert(0); + break; + case FRAG_RESULT_COLOR: + write_all = GL_TRUE; /* fallthrough */ + default: + assert(attr == FRAG_RESULT_COLOR || + (FRAG_RESULT_DATA0 <= attr && attr < FRAG_RESULT_MAX)); + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_COLOR; + fs_output_semantic_index[fs_num_outputs] = numColors; + outputMapping[attr] = fs_num_outputs; + numColors++; + break; + } + + fs_num_outputs++; + } + } + } + + ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); + if (ureg == NULL) + return NULL; + + if (ST_DEBUG & DEBUG_MESA) { + _mesa_print_program(&stfp->Base.Base); + _mesa_print_program_parameters(st->ctx, &stfp->Base.Base); + debug_printf("\n"); + } + if (write_all == GL_TRUE) + ureg_property_fs_color0_writes_all_cbufs(ureg, 1); + + error = st_translate_mesa_program(st->ctx, + TGSI_PROCESSOR_FRAGMENT, + ureg, + &stfp->Base.Base, + /* inputs */ + fs_num_inputs, + inputMapping, + input_semantic_name, + input_semantic_index, + interpMode, + /* outputs */ + fs_num_outputs, + outputMapping, + fs_output_semantic_name, + fs_output_semantic_index, FALSE ); + + stfp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); + ureg_destroy( ureg ); + } + + /* fill in variant */ + variant->driver_shader = pipe->create_fs_state(pipe, &stfp->tgsi); + variant->key = *key; + + if (ST_DEBUG & DEBUG_TGSI) { + tgsi_dump( stfp->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/ ); + debug_printf("\n"); + } + + if (deleteFP) { + /* Free the temporary program made above */ + struct gl_fragment_program *fp = &stfp->Base; + _mesa_reference_fragprog(st->ctx, &fp, NULL); + } + + return variant; +} + + +/** + * Translate fragment program if needed. + */ +struct st_fp_variant * +st_get_fp_variant(struct st_context *st, + struct st_fragment_program *stfp, + const struct st_fp_variant_key *key) +{ + struct st_fp_variant *fpv; + + /* Search for existing variant */ + for (fpv = stfp->variants; fpv; fpv = fpv->next) { + if (memcmp(&fpv->key, key, sizeof(*key)) == 0) { + break; + } + } + + if (!fpv) { + /* create new */ + fpv = st_translate_fragment_program(st, stfp, key); + if (fpv) { + /* insert into list */ + fpv->next = stfp->variants; + stfp->variants = fpv; + } + } + + return fpv; +} + + +/** + * Translate a geometry program to create a new variant. + */ +static struct st_gp_variant * +st_translate_geometry_program(struct st_context *st, + struct st_geometry_program *stgp, + const struct st_gp_variant_key *key) +{ + GLuint inputMapping[GEOM_ATTRIB_MAX]; + GLuint outputMapping[GEOM_RESULT_MAX]; + struct pipe_context *pipe = st->pipe; + enum pipe_error error; + GLuint attr; + const GLbitfield inputsRead = stgp->Base.Base.InputsRead; + GLuint vslot = 0; + GLuint num_generic = 0; + + uint gs_num_inputs = 0; + uint gs_builtin_inputs = 0; + uint gs_array_offset = 0; + + ubyte gs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; + ubyte gs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; + uint gs_num_outputs = 0; + + GLint i; + GLuint maxSlot = 0; + struct ureg_program *ureg; + + struct st_gp_variant *gpv; + + gpv = CALLOC_STRUCT(st_gp_variant); + if (!gpv) + return NULL; + + _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_OUTPUT); + _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_VARYING); + + ureg = ureg_create( TGSI_PROCESSOR_GEOMETRY ); + if (ureg == NULL) { + FREE(gpv); + return NULL; + } + + /* which vertex output goes to the first geometry input */ + vslot = 0; + + memset(inputMapping, 0, sizeof(inputMapping)); + memset(outputMapping, 0, sizeof(outputMapping)); + + /* + * Convert Mesa program inputs to TGSI input register semantics. + */ + for (attr = 0; attr < GEOM_ATTRIB_MAX; attr++) { + if (inputsRead & (1 << attr)) { + const GLuint slot = gs_num_inputs; + + gs_num_inputs++; + + inputMapping[attr] = slot; + + stgp->input_map[slot + gs_array_offset] = vslot - gs_builtin_inputs; + stgp->input_to_index[attr] = vslot; + stgp->index_to_input[vslot] = attr; + ++vslot; + + if (attr != GEOM_ATTRIB_PRIMITIVE_ID) { + gs_array_offset += 2; + } else + ++gs_builtin_inputs; + +#if 0 + debug_printf("input map at %d = %d\n", + slot + gs_array_offset, stgp->input_map[slot + gs_array_offset]); +#endif + + switch (attr) { + case GEOM_ATTRIB_PRIMITIVE_ID: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_POSITION: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_COLOR0: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_COLOR1: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stgp->input_semantic_index[slot] = 1; + break; + case GEOM_ATTRIB_FOG_FRAG_COORD: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_TEX_COORD: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stgp->input_semantic_index[slot] = num_generic++; + break; + case GEOM_ATTRIB_VAR0: + /* fall-through */ + default: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stgp->input_semantic_index[slot] = num_generic++; + } + } + } + + /* initialize output semantics to defaults */ + for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) { + gs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC; + gs_output_semantic_index[i] = 0; + } + + num_generic = 0; + /* + * Determine number of outputs, the (default) output register + * mapping and the semantic information for each output. + */ + for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { + if (stgp->Base.Base.OutputsWritten & (1 << attr)) { + GLuint slot; + + slot = gs_num_outputs; + gs_num_outputs++; + outputMapping[attr] = slot; + + switch (attr) { + case GEOM_RESULT_POS: + assert(slot == 0); + gs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_COL0: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_COL1: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + gs_output_semantic_index[slot] = 1; + break; + case GEOM_RESULT_SCOL0: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_SCOL1: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + gs_output_semantic_index[slot] = 1; + break; + case GEOM_RESULT_FOGC: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_PSIZ: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_TEX0: + case GEOM_RESULT_TEX1: + case GEOM_RESULT_TEX2: + case GEOM_RESULT_TEX3: + case GEOM_RESULT_TEX4: + case GEOM_RESULT_TEX5: + case GEOM_RESULT_TEX6: + case GEOM_RESULT_TEX7: + /* fall-through */ + case GEOM_RESULT_VAR0: + /* fall-through */ + default: + assert(slot < Elements(gs_output_semantic_name)); + /* use default semantic info */ + gs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + gs_output_semantic_index[slot] = num_generic++; + } + } + } + + assert(gs_output_semantic_name[0] == TGSI_SEMANTIC_POSITION); + + /* find max output slot referenced to compute gs_num_outputs */ + for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { + if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot) + maxSlot = outputMapping[attr]; + } + gs_num_outputs = maxSlot + 1; + +#if 0 /* debug */ + { + GLuint i; + printf("outputMapping? %d\n", outputMapping ? 1 : 0); + if (outputMapping) { + printf("attr -> slot\n"); + for (i = 0; i < 16; i++) { + printf(" %2d %3d\n", i, outputMapping[i]); + } + } + printf("slot sem_name sem_index\n"); + for (i = 0; i < gs_num_outputs; i++) { + printf(" %2d %d %d\n", + i, + gs_output_semantic_name[i], + gs_output_semantic_index[i]); + } + } +#endif + + /* free old shader state, if any */ + if (stgp->tgsi.tokens) { + st_free_tokens(stgp->tgsi.tokens); + stgp->tgsi.tokens = NULL; + } + + ureg_property_gs_input_prim(ureg, stgp->Base.InputType); + ureg_property_gs_output_prim(ureg, stgp->Base.OutputType); + ureg_property_gs_max_vertices(ureg, stgp->Base.VerticesOut); + + error = st_translate_mesa_program(st->ctx, + TGSI_PROCESSOR_GEOMETRY, + ureg, + &stgp->Base.Base, + /* inputs */ + gs_num_inputs, + inputMapping, + stgp->input_semantic_name, + stgp->input_semantic_index, + NULL, + /* outputs */ + gs_num_outputs, + outputMapping, + gs_output_semantic_name, + gs_output_semantic_index, + FALSE); + + stgp->num_inputs = gs_num_inputs; + stgp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); + ureg_destroy( ureg ); + + /* fill in new variant */ + gpv->driver_shader = pipe->create_gs_state(pipe, &stgp->tgsi); + gpv->key = *key; + + if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) { + _mesa_print_program(&stgp->Base.Base); + debug_printf("\n"); + } + + if (ST_DEBUG & DEBUG_TGSI) { + tgsi_dump(stgp->tgsi.tokens, 0); + debug_printf("\n"); + } + + return gpv; +} + + +/** + * Get/create geometry program variant. + */ +struct st_gp_variant * +st_get_gp_variant(struct st_context *st, + struct st_geometry_program *stgp, + const struct st_gp_variant_key *key) +{ + struct st_gp_variant *gpv; + + /* Search for existing variant */ + for (gpv = stgp->variants; gpv; gpv = gpv->next) { + if (memcmp(&gpv->key, key, sizeof(*key)) == 0) { + break; + } + } + + if (!gpv) { + /* create new */ + gpv = st_translate_geometry_program(st, stgp, key); + if (gpv) { + /* insert into list */ + gpv->next = stgp->variants; + stgp->variants = gpv; + } + } + + return gpv; +} + + + + +/** + * Debug- print current shader text + */ +void +st_print_shaders(struct gl_context *ctx) +{ + struct gl_shader_program *shProg[3] = { + ctx->Shader.CurrentVertexProgram, + ctx->Shader.CurrentGeometryProgram, + ctx->Shader.CurrentFragmentProgram, + }; + unsigned j; + + for (j = 0; j < 3; j++) { + unsigned i; + + if (shProg[j] == NULL) + continue; + + for (i = 0; i < shProg[j]->NumShaders; i++) { + struct gl_shader *sh; + + switch (shProg[j]->Shaders[i]->Type) { + case GL_VERTEX_SHADER: + sh = (i != 0) ? NULL : shProg[j]->Shaders[i]; + break; + case GL_GEOMETRY_SHADER_ARB: + sh = (i != 1) ? NULL : shProg[j]->Shaders[i]; + break; + case GL_FRAGMENT_SHADER: + sh = (i != 2) ? NULL : shProg[j]->Shaders[i]; + break; + default: + assert(0); + sh = NULL; + break; + } + + if (sh != NULL) { + printf("GLSL shader %u of %u:\n", i, shProg[j]->NumShaders); + printf("%s\n", sh->Source); + } + } + } +} + + +/** + * Vert/Geom/Frag programs have per-context variants. Free all the + * variants attached to the given program which match the given context. + */ +static void +destroy_program_variants(struct st_context *st, struct gl_program *program) +{ + if (!program) + return; + + switch (program->Target) { + case GL_VERTEX_PROGRAM_ARB: + { + struct st_vertex_program *stvp = (struct st_vertex_program *) program; + struct st_vp_variant *vpv, **prevPtr = &stvp->variants; + + for (vpv = stvp->variants; vpv; ) { + struct st_vp_variant *next = vpv->next; + if (vpv->key.st == st) { + /* unlink from list */ + *prevPtr = next; + /* destroy this variant */ + delete_vp_variant(st, vpv); + } + else { + prevPtr = &vpv->next; + } + vpv = next; + } + } + break; + case GL_FRAGMENT_PROGRAM_ARB: + { + struct st_fragment_program *stfp = + (struct st_fragment_program *) program; + struct st_fp_variant *fpv, **prevPtr = &stfp->variants; + + for (fpv = stfp->variants; fpv; ) { + struct st_fp_variant *next = fpv->next; + if (fpv->key.st == st) { + /* unlink from list */ + *prevPtr = next; + /* destroy this variant */ + delete_fp_variant(st, fpv); + } + else { + prevPtr = &fpv->next; + } + fpv = next; + } + } + break; + case MESA_GEOMETRY_PROGRAM: + { + struct st_geometry_program *stgp = + (struct st_geometry_program *) program; + struct st_gp_variant *gpv, **prevPtr = &stgp->variants; + + for (gpv = stgp->variants; gpv; ) { + struct st_gp_variant *next = gpv->next; + if (gpv->key.st == st) { + /* unlink from list */ + *prevPtr = next; + /* destroy this variant */ + delete_gp_variant(st, gpv); + } + else { + prevPtr = &gpv->next; + } + gpv = next; + } + } + break; + default: + _mesa_problem(NULL, "Unexpected program target in " + "destroy_program_variants_cb()"); + } +} + + +/** + * Callback for _mesa_HashWalk. Free all the shader's program variants + * which match the given context. + */ +static void +destroy_shader_program_variants_cb(GLuint key, void *data, void *userData) +{ + struct st_context *st = (struct st_context *) userData; + struct gl_shader *shader = (struct gl_shader *) data; + + switch (shader->Type) { + case GL_SHADER_PROGRAM_MESA: + { + struct gl_shader_program *shProg = (struct gl_shader_program *) data; + GLuint i; + + for (i = 0; i < shProg->NumShaders; i++) { + destroy_program_variants(st, shProg->Shaders[i]->Program); + } + + destroy_program_variants(st, (struct gl_program *) + shProg->VertexProgram); + destroy_program_variants(st, (struct gl_program *) + shProg->FragmentProgram); + destroy_program_variants(st, (struct gl_program *) + shProg->GeometryProgram); + } + break; + case GL_VERTEX_SHADER: + case GL_FRAGMENT_SHADER: + case GL_GEOMETRY_SHADER: + { + destroy_program_variants(st, shader->Program); + } + break; + default: + assert(0); + } +} + + +/** + * Callback for _mesa_HashWalk. Free all the program variants which match + * the given context. + */ +static void +destroy_program_variants_cb(GLuint key, void *data, void *userData) +{ + struct st_context *st = (struct st_context *) userData; + struct gl_program *program = (struct gl_program *) data; + destroy_program_variants(st, program); +} + + +/** + * Walk over all shaders and programs to delete any variants which + * belong to the given context. + * This is called during context tear-down. + */ +void +st_destroy_program_variants(struct st_context *st) +{ + /* ARB vert/frag program */ + _mesa_HashWalk(st->ctx->Shared->Programs, + destroy_program_variants_cb, st); + + /* GLSL vert/frag/geom shaders */ + _mesa_HashWalk(st->ctx->Shared->ShaderObjects, + destroy_shader_program_variants_cb, st); +} -- cgit v1.2.3