X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Fdraw%2Fdraw_context.c;h=16a261c14cf6ce3390c9bf81f2003ffc2c530fd1;hb=c260175677c20ed4f11a6679c45391783d07aaeb;hp=6caa62ab31b9e431ab34afbede32bb91246c1764;hpb=2737abb44efebfa10ac84b183c20fc5818d1514e;p=mesa.git diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c index 6caa62ab31b..16a261c14cf 100644 --- a/src/gallium/auxiliary/draw/draw_context.c +++ b/src/gallium/auxiliary/draw/draw_context.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2007 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -18,7 +18,7 @@ * 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 + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -27,7 +27,7 @@ /* * Authors: - * Keith Whitwell + * Keith Whitwell */ @@ -37,7 +37,11 @@ #include "util/u_cpu_detect.h" #include "util/u_inlines.h" #include "util/u_helpers.h" +#include "util/u_prim.h" +#include "util/u_format.h" #include "draw_context.h" +#include "draw_pipe.h" +#include "draw_prim_assembler.h" #include "draw_vs.h" #include "draw_gs.h" @@ -49,20 +53,13 @@ boolean draw_get_option_use_llvm(void) { - static boolean first = TRUE; - static boolean value; - if (first) { - first = FALSE; - value = debug_get_bool_option("DRAW_USE_LLVM", TRUE); - -#ifdef PIPE_ARCH_X86 - util_cpu_detect(); - /* require SSE2 due to LLVM PR6960. */ - if (!util_cpu_caps.has_sse2) - value = FALSE; -#endif - } - return value; + return debug_get_bool_option("DRAW_USE_LLVM", TRUE); +} +#else +boolean +draw_get_option_use_llvm(void) +{ + return FALSE; } #endif @@ -71,17 +68,19 @@ draw_get_option_use_llvm(void) * Create new draw module context with gallivm state for LLVM JIT. */ static struct draw_context * -draw_create_context(struct pipe_context *pipe, boolean try_llvm) +draw_create_context(struct pipe_context *pipe, void *context, + boolean try_llvm) { struct draw_context *draw = CALLOC_STRUCT( draw_context ); - if (draw == NULL) + if (!draw) goto err_out; + /* we need correct cpu caps for disabling denorms in draw_vbo() */ + util_cpu_detect(); + #if HAVE_LLVM if (try_llvm && draw_get_option_use_llvm()) { - draw->llvm = draw_llvm_create(draw); - if (!draw->llvm) - goto err_destroy; + draw->llvm = draw_llvm_create(draw, (LLVMContextRef)context); } #endif @@ -90,6 +89,10 @@ draw_create_context(struct pipe_context *pipe, boolean try_llvm) if (!draw_init(draw)) goto err_destroy; + draw->ia = draw_prim_assembler_create(draw); + if (!draw->ia) + goto err_destroy; + return draw; err_destroy: @@ -105,17 +108,26 @@ err_out: struct draw_context * draw_create(struct pipe_context *pipe) { - return draw_create_context(pipe, TRUE); + return draw_create_context(pipe, NULL, TRUE); } +#if HAVE_LLVM +struct draw_context * +draw_create_with_llvm_context(struct pipe_context *pipe, + void *context) +{ + return draw_create_context(pipe, context, TRUE); +} +#endif + /** * Create a new draw context, without LLVM JIT. */ struct draw_context * draw_create_no_llvm(struct pipe_context *pipe) { - return draw_create_context(pipe, FALSE); + return draw_create_context(pipe, NULL, FALSE); } @@ -137,6 +149,7 @@ boolean draw_init(struct draw_context *draw) draw->clip_z = TRUE; draw->pt.user.planes = (float (*) [DRAW_TOTAL_CLIP_PLANES][4]) &(draw->plane[0]); + draw->pt.user.eltMax = ~0; if (!draw_pipeline_init( draw )) return FALSE; @@ -153,6 +166,8 @@ boolean draw_init(struct draw_context *draw) draw->quads_always_flatshade_last = !draw->pipe->screen->get_param( draw->pipe->screen, PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION); + draw->floating_point_depth = false; + return TRUE; } @@ -167,6 +182,7 @@ boolean draw_init(struct draw_context *draw) void draw_new_instance(struct draw_context *draw) { draw_geometry_shader_new_instance(draw->gs.geometry_shader); + draw_prim_assembler_new_instance(draw->ia); } @@ -200,6 +216,7 @@ void draw_destroy( struct draw_context *draw ) draw->render->destroy( draw->render ); */ + draw_prim_assembler_destroy(draw->ia); draw_pipeline_destroy( draw ); draw_pt_destroy( draw ); draw_vs_destroy( draw ); @@ -221,29 +238,65 @@ void draw_flush( struct draw_context *draw ) /** - * Specify the Minimum Resolvable Depth factor for polygon offset. + * Specify the depth stencil format for the draw pipeline. This function + * determines the Minimum Resolvable Depth factor for polygon offset. * This factor potentially depends on the number of Z buffer bits, * the rasterization algorithm and the arithmetic performed on Z - * values between vertex shading and rasterization. It will vary - * from one driver to another. + * values between vertex shading and rasterization. */ -void draw_set_mrd(struct draw_context *draw, double mrd) +void draw_set_zs_format(struct draw_context *draw, enum pipe_format format) { - draw->mrd = mrd; + const struct util_format_description *desc = util_format_description(format); + + draw->floating_point_depth = + (util_get_depth_format_type(desc) == UTIL_FORMAT_TYPE_FLOAT); + + draw->mrd = util_get_depth_format_mrd(desc); } -static void update_clip_flags( struct draw_context *draw ) +static bool +draw_is_vs_window_space(struct draw_context *draw) { - draw->clip_xy = !draw->driver.bypass_clip_xy; + if (draw->vs.vertex_shader) { + struct tgsi_shader_info *info = &draw->vs.vertex_shader->info; + + return info->properties[TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION] != 0; + } + return false; +} + + +void +draw_update_clip_flags(struct draw_context *draw) +{ + bool window_space = draw_is_vs_window_space(draw); + + draw->clip_xy = !draw->driver.bypass_clip_xy && !window_space; draw->guard_band_xy = (!draw->driver.bypass_clip_xy && draw->driver.guard_band_xy); draw->clip_z = (!draw->driver.bypass_clip_z && - draw->rasterizer && draw->rasterizer->depth_clip); + draw->rasterizer && draw->rasterizer->depth_clip) && + !window_space; draw->clip_user = draw->rasterizer && - draw->rasterizer->clip_plane_enable != 0; + draw->rasterizer->clip_plane_enable != 0 && + !window_space; + draw->guard_band_points_xy = draw->guard_band_xy || + (draw->driver.bypass_clip_points && + (draw->rasterizer && + draw->rasterizer->point_tri_clip)); } + +void +draw_update_viewport_flags(struct draw_context *draw) +{ + bool window_space = draw_is_vs_window_space(draw); + + draw->bypass_viewport = window_space || draw->identity_viewport; +} + + /** * Register new primitive rasterization/rendering state. * This causes the drawing pipeline to be rebuilt. @@ -257,7 +310,7 @@ void draw_set_rasterizer_state( struct draw_context *draw, draw->rasterizer = raster; draw->rast_handle = rast_handle; - update_clip_flags(draw); + draw_update_clip_flags(draw); } } @@ -267,18 +320,24 @@ void draw_set_rasterizer_state( struct draw_context *draw, * Some hardware can turn off clipping altogether - in particular any * hardware with a TNL unit can do its own clipping, even if it is * relying on the draw module for some other reason. + * Setting bypass_clip_points to achieve d3d-style point clipping (the driver + * will need to do the "vp scissoring") _requires_ the driver to implement + * wide points / point sprites itself (points will still be clipped if rasterizer + * point_tri_clip isn't set). Only relevant if bypass_clip_xy isn't set. */ void draw_set_driver_clipping( struct draw_context *draw, boolean bypass_clip_xy, boolean bypass_clip_z, - boolean guard_band_xy) + boolean guard_band_xy, + boolean bypass_clip_points) { draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE ); draw->driver.bypass_clip_xy = bypass_clip_xy; draw->driver.bypass_clip_z = bypass_clip_z; draw->driver.guard_band_xy = guard_band_xy; - update_clip_flags(draw); + draw->driver.bypass_clip_points = bypass_clip_points; + draw_update_clip_flags(draw); } @@ -311,21 +370,28 @@ void draw_set_clip_state( struct draw_context *draw, /** * Set the draw module's viewport state. */ -void draw_set_viewport_state( struct draw_context *draw, - const struct pipe_viewport_state *viewport ) +void draw_set_viewport_states( struct draw_context *draw, + unsigned start_slot, + unsigned num_viewports, + const struct pipe_viewport_state *vps ) { + const struct pipe_viewport_state *viewport = vps; draw_do_flush(draw, DRAW_FLUSH_PARAMETER_CHANGE); - draw->viewport = *viewport; /* struct copy */ - draw->identity_viewport = (viewport->scale[0] == 1.0f && - viewport->scale[1] == 1.0f && - viewport->scale[2] == 1.0f && - viewport->scale[3] == 1.0f && - viewport->translate[0] == 0.0f && - viewport->translate[1] == 0.0f && - viewport->translate[2] == 0.0f && - viewport->translate[3] == 0.0f); - draw_vs_set_viewport( draw, viewport ); + debug_assert(start_slot < PIPE_MAX_VIEWPORTS); + debug_assert((start_slot + num_viewports) <= PIPE_MAX_VIEWPORTS); + + memcpy(draw->viewports + start_slot, vps, + sizeof(struct pipe_viewport_state) * num_viewports); + + draw->identity_viewport = (num_viewports == 1) && + (viewport->scale[0] == 1.0f && + viewport->scale[1] == 1.0f && + viewport->scale[2] == 1.0f && + viewport->translate[0] == 0.0f && + viewport->translate[1] == 0.0f && + viewport->translate[2] == 0.0f); + draw_update_viewport_flags(draw); } @@ -364,9 +430,11 @@ draw_set_vertex_elements(struct draw_context *draw, */ void draw_set_mapped_vertex_buffer(struct draw_context *draw, - unsigned attr, const void *buffer) + unsigned attr, const void *buffer, + size_t size) { - draw->pt.user.vbuffer[attr] = buffer; + draw->pt.user.vbuffer[attr].map = buffer; + draw->pt.user.vbuffer[attr].size = size; } @@ -481,7 +549,7 @@ draw_alloc_extra_vertex_attrib(struct draw_context *draw, uint n; slot = draw_find_shader_output(draw, semantic_name, semantic_index); - if (slot > 0) { + if (slot >= 0) { return slot; } @@ -525,6 +593,28 @@ draw_get_shader_info(const struct draw_context *draw) } } +/** + * Prepare outputs slots from the draw module + * + * Certain parts of the draw module can emit additional + * outputs that can be quite useful to the backends, a good + * example of it is the process of decomposing primitives + * into wireframes (aka. lines) which normally would lose + * the face-side information, but using this method we can + * inject another shader output which passes the original + * face side information to the backend. + */ +void +draw_prepare_shader_outputs(struct draw_context *draw) +{ + draw_remove_extra_vertex_attribs(draw); + draw_prim_assembler_prepare_outputs(draw->ia); + draw_unfilled_prepare_outputs(draw, draw->pipeline.unfilled); + if (draw->pipeline.aapoint) + draw_aapoint_prepare_outputs(draw, draw->pipeline.aapoint); + if (draw->pipeline.aaline) + draw_aaline_prepare_outputs(draw, draw->pipeline.aaline); +} /** * Ask the draw module for the location/slot of the given vertex attribute in @@ -537,9 +627,10 @@ draw_get_shader_info(const struct draw_context *draw) * attributes (such as texcoords for AA lines). The driver can call this * function to find those attributes. * - * Zero is returned if the attribute is not found since this is - * a don't care / undefined situtation. Returning -1 would be a bit more - * work for the drivers. + * -1 is returned if the attribute is not found since this is + * an undefined situation. Note, that zero is valid and can + * be used by any of the attributes, because position is not + * required to be attribute 0 or even at all present. */ int draw_find_shader_output(const struct draw_context *draw, @@ -562,7 +653,7 @@ draw_find_shader_output(const struct draw_context *draw, } } - return 0; + return -1; } @@ -588,6 +679,40 @@ draw_num_shader_outputs(const struct draw_context *draw) } +/** + * Return total number of the vertex shader outputs. This function + * also counts any extra vertex output attributes that may + * be filled in by some draw stages (such as AA point, AA line, + * front face). + */ +uint +draw_total_vs_outputs(const struct draw_context *draw) +{ + const struct tgsi_shader_info *info = &draw->vs.vertex_shader->info; + + return info->num_outputs + draw->extra_shader_outputs.num; +} + +/** + * Return total number of the geometry shader outputs. This function + * also counts any extra geometry output attributes that may + * be filled in by some draw stages (such as AA point, AA line, front + * face). + */ +uint +draw_total_gs_outputs(const struct draw_context *draw) +{ + const struct tgsi_shader_info *info; + + if (!draw->gs.geometry_shader) + return 0; + + info = &draw->gs.geometry_shader->info; + + return info->num_outputs + draw->extra_shader_outputs.num; +} + + /** * Provide TGSI sampler objects for vertex/geometry shaders that use * texture fetches. This state only needs to be set once per context. @@ -625,7 +750,8 @@ void draw_set_render( struct draw_context *draw, */ void draw_set_indexes(struct draw_context *draw, - const void *elements, unsigned elem_size) + const void *elements, unsigned elem_size, + unsigned elem_buffer_space) { assert(elem_size == 0 || elem_size == 1 || @@ -633,6 +759,10 @@ draw_set_indexes(struct draw_context *draw, elem_size == 4); draw->pt.user.elts = elements; draw->pt.user.eltSizeIB = elem_size; + if (elem_size) + draw->pt.user.eltMax = elem_buffer_space / elem_size; + else + draw->pt.user.eltMax = 0; } @@ -685,20 +815,79 @@ draw_current_shader_position_output(const struct draw_context *draw) /** * Return the index of the shader output which will contain the - * vertex position. + * viewport index. + */ +uint +draw_current_shader_viewport_index_output(const struct draw_context *draw) +{ + if (draw->gs.geometry_shader) + return draw->gs.geometry_shader->viewport_index_output; + return draw->vs.vertex_shader->viewport_index_output; +} + +/** + * Returns true if there's a geometry shader bound and the geometry + * shader writes out a viewport index. + */ +boolean +draw_current_shader_uses_viewport_index(const struct draw_context *draw) +{ + if (draw->gs.geometry_shader) + return draw->gs.geometry_shader->info.writes_viewport_index; + return draw->vs.vertex_shader->info.writes_viewport_index; +} + + +/** + * Return the index of the shader output which will contain the + * clip vertex position. + * Note we don't support clipvertex output in the gs. For clipping + * to work correctly hence we return ordinary position output instead. */ uint draw_current_shader_clipvertex_output(const struct draw_context *draw) { + if (draw->gs.geometry_shader) + return draw->gs.position_output; return draw->vs.clipvertex_output; } uint draw_current_shader_clipdistance_output(const struct draw_context *draw, int index) { + debug_assert(index < PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT); + if (draw->gs.geometry_shader) + return draw->gs.geometry_shader->clipdistance_output[index]; return draw->vs.clipdistance_output[index]; } + +uint +draw_current_shader_num_written_clipdistances(const struct draw_context *draw) +{ + if (draw->gs.geometry_shader) + return draw->gs.geometry_shader->info.num_written_clipdistance; + return draw->vs.vertex_shader->info.num_written_clipdistance; +} + + +uint +draw_current_shader_culldistance_output(const struct draw_context *draw, int index) +{ + debug_assert(index < PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT); + if (draw->gs.geometry_shader) + return draw->gs.geometry_shader->culldistance_output[index]; + return draw->vs.vertex_shader->culldistance_output[index]; +} + +uint +draw_current_shader_num_written_culldistances(const struct draw_context *draw) +{ + if (draw->gs.geometry_shader) + return draw->gs.geometry_shader->info.num_written_culldistance; + return draw->vs.vertex_shader->info.num_written_culldistance; +} + /** * Return a pointer/handle for a driver/CSO rasterizer object which * disabled culling, stippling, unfilled tris, etc. @@ -837,6 +1026,8 @@ draw_get_shader_param_no_llvm(unsigned shader, enum pipe_shader_cap param) /** * XXX: Results for PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS because there are two * different ways of setting textures, and drivers typically only support one. + * Drivers requesting a draw context explicitly without llvm must call + * draw_get_shader_param_no_llvm instead. */ int draw_get_shader_param(unsigned shader, enum pipe_shader_cap param) @@ -873,3 +1064,50 @@ draw_collect_pipeline_statistics(struct draw_context *draw, { draw->collect_statistics = enable; } + +/** + * Computes clipper invocation statistics. + * + * Figures out how many primitives would have been + * sent to the clipper given the specified + * prim info data. + */ +void +draw_stats_clipper_primitives(struct draw_context *draw, + const struct draw_prim_info *prim_info) +{ + if (draw->collect_statistics) { + unsigned i; + for (i = 0; i < prim_info->primitive_count; i++) { + draw->statistics.c_invocations += + u_decomposed_prims_for_vertices(prim_info->prim, + prim_info->primitive_lengths[i]); + } + } +} + + +/** + * Returns true if the draw module will inject the frontface + * info into the outputs. + * + * Given the specified primitive and rasterizer state + * the function will figure out if the draw module + * will inject the front-face information into shader + * outputs. This is done to preserve the front-facing + * info when decomposing primitives into wireframes. + */ +boolean +draw_will_inject_frontface(const struct draw_context *draw) +{ + unsigned reduced_prim = u_reduced_prim(draw->pt.prim); + const struct pipe_rasterizer_state *rast = draw->rasterizer; + + if (reduced_prim != PIPE_PRIM_TRIANGLES) { + return FALSE; + } + + return (rast && + (rast->fill_front != PIPE_POLYGON_MODE_FILL || + rast->fill_back != PIPE_POLYGON_MODE_FILL)); +}