1/************************************************************************** 2 * 3 * Copyright 2012-2021 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 * USE OR OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * The above copyright notice and this permission notice (including the 23 * next paragraph) shall be included in all copies or substantial portions 24 * of the Software. 25 * 26 **************************************************************************/ 27 28/* 29 * Draw.h -- 30 * Functions that render 3D primitives. 31 */ 32 33 34#include "Draw.h" 35#include "State.h" 36#include "Shader.h" 37 38#include "Debug.h" 39 40#include "util/u_draw.h" 41#include "util/u_memory.h" 42 43static unsigned 44ClampedUAdd(unsigned a, 45 unsigned b) 46{ 47 unsigned c = a + b; 48 if (c < a) { 49 return 0xffffffff; 50 } 51 return c; 52} 53 54 55/* 56 * We have to resolve the stream output state for empty geometry shaders. 57 * In particular we've remapped the output indices when translating the 58 * shaders so now the register_index variables in the stream output 59 * state are incorrect and we need to remap them back to the correct 60 * state. 61 */ 62static void 63ResolveState(Device *pDevice) 64{ 65 if (pDevice->bound_empty_gs && pDevice->bound_vs && 66 pDevice->bound_vs->state.tokens) { 67 Shader *gs = pDevice->bound_empty_gs; 68 Shader *vs = pDevice->bound_vs; 69 boolean remapped = FALSE; 70 struct pipe_context *pipe = pDevice->pipe; 71 if (!gs->output_resolved) { 72 for (unsigned i = 0; i < gs->state.stream_output.num_outputs; ++i) { 73 unsigned mapping = 74 ShaderFindOutputMapping(vs, gs->state.stream_output.output[i].register_index); 75 if (mapping != gs->state.stream_output.output[i].register_index) { 76 gs->state.stream_output.output[i].register_index = mapping; 77 remapped = TRUE; 78 } 79 } 80 if (remapped) { 81 pipe->delete_gs_state(pipe, gs->handle); 82 gs->handle = pipe->create_gs_state(pipe, &gs->state); 83 } 84 gs->output_resolved = TRUE; 85 } 86 pipe->bind_gs_state(pipe, gs->handle); 87 } 88} 89 90 91static struct pipe_resource * 92create_null_index_buffer(struct pipe_context *ctx, uint num_indices, 93 unsigned *restart_index, unsigned *index_size, 94 unsigned *ib_offset) 95{ 96 unsigned buf_size = num_indices * sizeof(unsigned); 97 unsigned *buf = (unsigned*)MALLOC(buf_size); 98 struct pipe_resource *ibuf; 99 100 memset(buf, 0, buf_size); 101 102 ibuf = pipe_buffer_create_with_data(ctx, 103 PIPE_BIND_INDEX_BUFFER, 104 PIPE_USAGE_IMMUTABLE, 105 buf_size, buf); 106 *index_size = 4; 107 *restart_index = 0xffffffff; 108 *ib_offset = 0; 109 110 FREE(buf); 111 112 return ibuf; 113} 114 115/* 116 * ---------------------------------------------------------------------- 117 * 118 * Draw -- 119 * 120 * The Draw function draws nonindexed primitives. 121 * 122 * ---------------------------------------------------------------------- 123 */ 124 125void APIENTRY 126Draw(D3D10DDI_HDEVICE hDevice, // IN 127 UINT VertexCount, // IN 128 UINT StartVertexLocation) // IN 129{ 130 LOG_ENTRYPOINT(); 131 132 Device *pDevice = CastDevice(hDevice); 133 134 ResolveState(pDevice); 135 136 assert(pDevice->primitive < PIPE_PRIM_MAX); 137 util_draw_arrays(pDevice->pipe, 138 pDevice->primitive, 139 StartVertexLocation, 140 VertexCount); 141} 142 143 144/* 145 * ---------------------------------------------------------------------- 146 * 147 * DrawIndexed -- 148 * 149 * The DrawIndexed function draws indexed primitives. 150 * 151 * ---------------------------------------------------------------------- 152 */ 153 154void APIENTRY 155DrawIndexed(D3D10DDI_HDEVICE hDevice, // IN 156 UINT IndexCount, // IN 157 UINT StartIndexLocation, // IN 158 INT BaseVertexLocation) // IN 159{ 160 LOG_ENTRYPOINT(); 161 162 Device *pDevice = CastDevice(hDevice); 163 struct pipe_draw_info info; 164 struct pipe_draw_start_count_bias draw; 165 struct pipe_resource *null_ib = NULL; 166 unsigned restart_index = pDevice->restart_index; 167 unsigned index_size = pDevice->index_size; 168 unsigned ib_offset = pDevice->ib_offset; 169 170 assert(pDevice->primitive < PIPE_PRIM_MAX); 171 172 /* XXX I don't think draw still needs this? */ 173 if (!pDevice->index_buffer) { 174 null_ib = 175 create_null_index_buffer(pDevice->pipe, 176 StartIndexLocation + IndexCount, 177 &restart_index, &index_size, &ib_offset); 178 } 179 180 ResolveState(pDevice); 181 182 util_draw_init_info(&info); 183 info.index_size = index_size; 184 info.mode = pDevice->primitive; 185 draw.start = ClampedUAdd(StartIndexLocation, ib_offset / index_size); 186 draw.count = IndexCount; 187 info.index.resource = null_ib ? null_ib : pDevice->index_buffer; 188 draw.index_bias = BaseVertexLocation; 189 info.primitive_restart = TRUE; 190 info.restart_index = restart_index; 191 192 pDevice->pipe->draw_vbo(pDevice->pipe, &info, 0, NULL, &draw, 1); 193 194 if (null_ib) { 195 pipe_resource_reference(&null_ib, NULL); 196 } 197} 198 199 200/* 201 * ---------------------------------------------------------------------- 202 * 203 * DrawInstanced -- 204 * 205 * The DrawInstanced function draws particular instances 206 * of nonindexed primitives. 207 * 208 * ---------------------------------------------------------------------- 209 */ 210 211void APIENTRY 212DrawInstanced(D3D10DDI_HDEVICE hDevice, // IN 213 UINT VertexCountPerInstance, // IN 214 UINT InstanceCount, // IN 215 UINT StartVertexLocation, // IN 216 UINT StartInstanceLocation) // IN 217{ 218 LOG_ENTRYPOINT(); 219 220 Device *pDevice = CastDevice(hDevice); 221 222 if (!InstanceCount) { 223 return; 224 } 225 226 ResolveState(pDevice); 227 228 assert(pDevice->primitive < PIPE_PRIM_MAX); 229 util_draw_arrays_instanced(pDevice->pipe, 230 pDevice->primitive, 231 StartVertexLocation, 232 VertexCountPerInstance, 233 StartInstanceLocation, 234 InstanceCount); 235} 236 237 238/* 239 * ---------------------------------------------------------------------- 240 * 241 * DrawIndexedInstanced -- 242 * 243 * The DrawIndexedInstanced function draws particular 244 * instances of indexed primitives. 245 * 246 * ---------------------------------------------------------------------- 247 */ 248 249void APIENTRY 250DrawIndexedInstanced(D3D10DDI_HDEVICE hDevice, // IN 251 UINT IndexCountPerInstance, // IN 252 UINT InstanceCount, // IN 253 UINT StartIndexLocation, // IN 254 INT BaseVertexLocation, // IN 255 UINT StartInstanceLocation) // IN 256{ 257 LOG_ENTRYPOINT(); 258 259 Device *pDevice = CastDevice(hDevice); 260 struct pipe_draw_info info; 261 struct pipe_draw_start_count_bias draw; 262 struct pipe_resource *null_ib = NULL; 263 unsigned restart_index = pDevice->restart_index; 264 unsigned index_size = pDevice->index_size; 265 unsigned ib_offset = pDevice->ib_offset; 266 267 assert(pDevice->primitive < PIPE_PRIM_MAX); 268 269 if (!InstanceCount) { 270 return; 271 } 272 273 /* XXX I don't think draw still needs this? */ 274 if (!pDevice->index_buffer) { 275 null_ib = 276 create_null_index_buffer(pDevice->pipe, 277 StartIndexLocation + IndexCountPerInstance, 278 &restart_index, &index_size, &ib_offset); 279 } 280 281 ResolveState(pDevice); 282 283 util_draw_init_info(&info); 284 info.index_size = index_size; 285 info.mode = pDevice->primitive; 286 draw.start = ClampedUAdd(StartIndexLocation, ib_offset / index_size); 287 draw.count = IndexCountPerInstance; 288 info.index.resource = null_ib ? null_ib : pDevice->index_buffer; 289 draw.index_bias = BaseVertexLocation; 290 info.start_instance = StartInstanceLocation; 291 info.instance_count = InstanceCount; 292 info.primitive_restart = TRUE; 293 info.restart_index = restart_index; 294 295 pDevice->pipe->draw_vbo(pDevice->pipe, &info, 0, NULL, &draw, 1); 296 297 if (null_ib) { 298 pipe_resource_reference(&null_ib, NULL); 299 } 300} 301 302 303/* 304 * ---------------------------------------------------------------------- 305 * 306 * DrawAuto -- 307 * 308 * The DrawAuto function works similarly to the Draw function, 309 * except DrawAuto is used for the special case where vertex 310 * data is written through the stream-output unit and then 311 * recycled as a vertex buffer. The driver determines the number 312 * of primitives, in part, by how much data was written to the 313 * buffer through stream output. 314 * 315 * ---------------------------------------------------------------------- 316 */ 317 318void APIENTRY 319DrawAuto(D3D10DDI_HDEVICE hDevice) // IN 320{ 321 LOG_ENTRYPOINT(); 322 323 Device *pDevice = CastDevice(hDevice); 324 struct pipe_draw_info info; 325 struct pipe_draw_indirect_info indirect; 326 327 328 if (!pDevice->draw_so_target) { 329 LOG_UNSUPPORTED("DrawAuto without a set source buffer!"); 330 return; 331 } 332 333 assert(pDevice->primitive < PIPE_PRIM_MAX); 334 335 ResolveState(pDevice); 336 337 util_draw_init_info(&info); 338 info.mode = pDevice->primitive; 339 memset(&indirect, 0, sizeof indirect); 340 indirect.count_from_stream_output = pDevice->draw_so_target; 341 342 pDevice->pipe->draw_vbo(pDevice->pipe, &info, 0, &indirect, NULL, 1); 343} 344