1/********************************************************** 2 * Copyright 2008-2009 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 **********************************************************/ 25 26 27#include "util/u_helpers.h" 28#include "util/u_inlines.h" 29#include "util/u_prim.h" 30#include "util/u_prim_restart.h" 31 32#include "svga_context.h" 33#include "svga_draw.h" 34#include "svga_shader.h" 35#include "svga_surface.h" 36#include "svga_swtnl.h" 37#include "svga_debug.h" 38#include "svga_resource_buffer.h" 39 40/* Returns TRUE if we are currently using flat shading. 41 */ 42static boolean 43is_using_flat_shading(const struct svga_context *svga) 44{ 45 return 46 svga->state.hw_draw.fs ? svga->state.hw_draw.fs->uses_flat_interp : FALSE; 47} 48 49 50static enum pipe_error 51retry_draw_range_elements(struct svga_context *svga, 52 struct pipe_resource *index_buffer, 53 unsigned index_size, 54 int index_bias, 55 unsigned min_index, 56 unsigned max_index, 57 enum pipe_prim_type prim, 58 unsigned start, 59 unsigned count, 60 unsigned start_instance, 61 unsigned instance_count) 62{ 63 enum pipe_error ret; 64 65 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWELEMENTS); 66 67 for (unsigned try = 0; try < 2; try++) { 68 ret = svga_hwtnl_draw_range_elements(svga->hwtnl, 69 index_buffer, index_size, 70 index_bias, 71 min_index, max_index, 72 prim, start, count, 73 start_instance, instance_count); 74 if (ret == PIPE_OK) 75 break; 76 svga_context_flush(svga, NULL); 77 } 78 79 SVGA_STATS_TIME_POP(svga_sws(svga)); 80 return ret; 81} 82 83 84static enum pipe_error 85retry_draw_arrays(struct svga_context *svga, 86 enum pipe_prim_type prim, unsigned start, unsigned count, 87 unsigned start_instance, unsigned instance_count) 88{ 89 enum pipe_error ret; 90 91 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWARRAYS); 92 93 for (unsigned try = 0; try < 2; try++) { 94 ret = svga_hwtnl_draw_arrays(svga->hwtnl, prim, start, count, 95 start_instance, instance_count); 96 if (ret == PIPE_OK) 97 break; 98 svga_context_flush(svga, NULL); 99 } 100 101 SVGA_STATS_TIME_POP(svga_sws(svga)); 102 return ret; 103} 104 105 106/** 107 * Determine if we need to implement primitive restart with a fallback 108 * path which breaks the original primitive into sub-primitive at the 109 * restart indexes. 110 */ 111static boolean 112need_fallback_prim_restart(const struct svga_context *svga, 113 const struct pipe_draw_info *info) 114{ 115 if (info->primitive_restart && info->index_size) { 116 if (!svga_have_vgpu10(svga)) 117 return TRUE; 118 else if (!svga->state.sw.need_swtnl) { 119 if (info->index_size == 1) 120 return TRUE; /* no device support for 1-byte indexes */ 121 else if (info->index_size == 2) 122 return info->restart_index != 0xffff; 123 else 124 return info->restart_index != 0xffffffff; 125 } 126 } 127 128 return FALSE; 129} 130 131 132static void 133svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) 134{ 135 struct svga_context *svga = svga_context(pipe); 136 enum pipe_prim_type reduced_prim = u_reduced_prim(info->mode); 137 unsigned count = info->count; 138 enum pipe_error ret = 0; 139 boolean needed_swtnl; 140 struct pipe_resource *indexbuf = 141 info->has_user_indices ? NULL : info->index.resource; 142 143 SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWVBO); 144 145 svga->hud.num_draw_calls++; /* for SVGA_QUERY_NUM_DRAW_CALLS */ 146 147 if (u_reduced_prim(info->mode) == PIPE_PRIM_TRIANGLES && 148 svga->curr.rast->templ.cull_face == PIPE_FACE_FRONT_AND_BACK) 149 goto done; 150 151 /* Upload a user index buffer. */ 152 unsigned index_offset = 0; 153 if (info->index_size && info->has_user_indices && 154 !util_upload_index_buffer(pipe, info, &indexbuf, &index_offset)) { 155 goto done; 156 } 157 158 /* 159 * Mark currently bound target surfaces as dirty 160 * doesn't really matter if it is done before drawing. 161 * 162 * TODO If we ever normaly return something other then 163 * true we should not mark it as dirty then. 164 */ 165 svga_mark_surfaces_dirty(svga_context(pipe)); 166 167 if (svga->curr.reduced_prim != reduced_prim) { 168 svga->curr.reduced_prim = reduced_prim; 169 svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE; 170 } 171 172 if (need_fallback_prim_restart(svga, info)) { 173 enum pipe_error r; 174 r = util_draw_vbo_without_prim_restart(pipe, info); 175 assert(r == PIPE_OK); 176 (void) r; 177 goto done; 178 } 179 180 if (!u_trim_pipe_prim(info->mode, &count)) 181 goto done; 182 183 needed_swtnl = svga->state.sw.need_swtnl; 184 185 svga_update_state_retry(svga, SVGA_STATE_NEED_SWTNL); 186 187 if (svga->state.sw.need_swtnl) { 188 svga->hud.num_fallbacks++; /* for SVGA_QUERY_NUM_FALLBACKS */ 189 if (!needed_swtnl) { 190 /* 191 * We're switching from HW to SW TNL. SW TNL will require mapping all 192 * currently bound vertex buffers, some of which may already be 193 * referenced in the current command buffer as result of previous HW 194 * TNL. So flush now, to prevent the context to flush while a referred 195 * vertex buffer is mapped. 196 */ 197 198 svga_context_flush(svga, NULL); 199 } 200 201 /* Avoid leaking the previous hwtnl bias to swtnl */ 202 svga_hwtnl_set_index_bias(svga->hwtnl, 0); 203 ret = svga_swtnl_draw_vbo(svga, info, indexbuf, index_offset); 204 } 205 else { 206 if (!svga_update_state_retry(svga, SVGA_STATE_HW_DRAW)) { 207 static const char *msg = "State update failed, skipping draw call"; 208 debug_printf("%s\n", msg); 209 pipe_debug_message(&svga->debug.callback, INFO, "%s", msg); 210 goto done; 211 } 212 213 svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode); 214 215 /** determine if flatshade is to be used after svga_update_state() 216 * in case the fragment shader is changed. 217 */ 218 svga_hwtnl_set_flatshade(svga->hwtnl, 219 svga->curr.rast->templ.flatshade || 220 is_using_flat_shading(svga), 221 svga->curr.rast->templ.flatshade_first); 222 223 if (info->index_size && indexbuf) { 224 unsigned offset; 225 226 assert(index_offset % info->index_size == 0); 227 offset = index_offset / info->index_size; 228 229 ret = retry_draw_range_elements(svga, 230 indexbuf, 231 info->index_size, 232 info->index_bias, 233 info->min_index, 234 info->max_index, 235 info->mode, 236 info->start + offset, 237 count, 238 info->start_instance, 239 info->instance_count); 240 } 241 else { 242 ret = retry_draw_arrays(svga, info->mode, info->start, count, 243 info->start_instance, info->instance_count); 244 } 245 } 246 247 /* XXX: Silence warnings, do something sensible here? */ 248 (void)ret; 249 250 if (SVGA_DEBUG & DEBUG_FLUSH) { 251 svga_hwtnl_flush_retry(svga); 252 svga_context_flush(svga, NULL); 253 } 254 255done: 256 if (info->index_size && info->index.resource != indexbuf) 257 pipe_resource_reference(&indexbuf, NULL); 258 SVGA_STATS_TIME_POP(svga_sws(svga)); 259} 260 261 262void 263svga_init_draw_functions(struct svga_context *svga) 264{ 265 svga->pipe.draw_vbo = svga_draw_vbo; 266} 267