1 /* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2013 LunarG, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Chia-I Wu <olv (at) lunarg.com> 26 */ 27 28 #include "genhw/genhw.h" 29 #include "core/ilo_builder.h" 30 #include "core/ilo_builder_mi.h" 31 #include "core/ilo_builder_render.h" 32 #include "core/intel_winsys.h" 33 #include "util/u_prim.h" 34 35 #include "ilo_query.h" 36 #include "ilo_render_gen.h" 37 38 struct ilo_render * 39 ilo_render_create(struct ilo_builder *builder) 40 { 41 struct ilo_render *render; 42 43 render = CALLOC_STRUCT(ilo_render); 44 if (!render) 45 return NULL; 46 47 render->dev = builder->dev; 48 render->builder = builder; 49 50 render->workaround_bo = intel_winsys_alloc_bo(builder->winsys, 51 "PIPE_CONTROL workaround", 4096, false); 52 if (!render->workaround_bo) { 53 ilo_warn("failed to allocate PIPE_CONTROL workaround bo\n"); 54 FREE(render); 55 return NULL; 56 } 57 58 ilo_state_sample_pattern_init_default(&render->sample_pattern, 59 render->dev); 60 61 ilo_render_invalidate_hw(render); 62 ilo_render_invalidate_builder(render); 63 64 return render; 65 } 66 67 void 68 ilo_render_destroy(struct ilo_render *render) 69 { 70 intel_bo_unref(render->vs_scratch.bo); 71 intel_bo_unref(render->gs_scratch.bo); 72 intel_bo_unref(render->fs_scratch.bo); 73 74 intel_bo_unref(render->workaround_bo); 75 FREE(render); 76 } 77 78 static bool 79 resize_scratch_space(struct ilo_render *render, 80 struct ilo_render_scratch_space *scratch, 81 const char *name, int new_size) 82 { 83 struct intel_bo *bo; 84 85 if (scratch->size >= new_size) 86 return true; 87 88 bo = intel_winsys_alloc_bo(render->builder->winsys, name, new_size, false); 89 if (!bo) 90 return false; 91 92 intel_bo_unref(scratch->bo); 93 scratch->bo = bo; 94 scratch->size = new_size; 95 96 return true; 97 } 98 99 bool 100 ilo_render_prepare_scratch_spaces(struct ilo_render *render, 101 int vs_scratch_size, 102 int gs_scratch_size, 103 int fs_scratch_size) 104 { 105 return (resize_scratch_space(render, &render->vs_scratch, 106 "vs scratch", vs_scratch_size) && 107 resize_scratch_space(render, &render->gs_scratch, 108 "gs scratch", gs_scratch_size) && 109 resize_scratch_space(render, &render->fs_scratch, 110 "fs scratch", fs_scratch_size)); 111 } 112 113 void 114 ilo_render_get_sample_position(const struct ilo_render *render, 115 unsigned sample_count, 116 unsigned sample_index, 117 float *x, float *y) 118 { 119 uint8_t off_x, off_y; 120 121 ilo_state_sample_pattern_get_offset(&render->sample_pattern, render->dev, 122 sample_count, sample_index, &off_x, &off_y); 123 124 *x = (float) off_x / 16.0f; 125 *y = (float) off_y / 16.0f; 126 } 127 128 void 129 ilo_render_invalidate_hw(struct ilo_render *render) 130 { 131 render->hw_ctx_changed = true; 132 } 133 134 void 135 ilo_render_invalidate_builder(struct ilo_render *render) 136 { 137 render->batch_bo_changed = true; 138 render->state_bo_changed = true; 139 render->instruction_bo_changed = true; 140 141 /* Kernel flushes everything. Shouldn't we set all bits here? */ 142 render->state.current_pipe_control_dw1 = 0; 143 } 144 145 /** 146 * Return the command length of ilo_render_emit_flush(). 147 */ 148 int 149 ilo_render_get_flush_len(const struct ilo_render *render) 150 { 151 int len; 152 153 ILO_DEV_ASSERT(render->dev, 6, 8); 154 155 len = GEN6_PIPE_CONTROL__SIZE; 156 157 /* plus gen6_wa_pre_pipe_control() */ 158 if (ilo_dev_gen(render->dev) == ILO_GEN(6)) 159 len *= 3; 160 161 return len; 162 } 163 164 /** 165 * Emit PIPE_CONTROLs to flush all caches. 166 */ 167 void 168 ilo_render_emit_flush(struct ilo_render *render) 169 { 170 const uint32_t dw1 = GEN6_PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE | 171 GEN6_PIPE_CONTROL_RENDER_CACHE_FLUSH | 172 GEN6_PIPE_CONTROL_DEPTH_CACHE_FLUSH | 173 GEN6_PIPE_CONTROL_VF_CACHE_INVALIDATE | 174 GEN6_PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | 175 GEN6_PIPE_CONTROL_CS_STALL; 176 const unsigned batch_used = ilo_builder_batch_used(render->builder); 177 178 ILO_DEV_ASSERT(render->dev, 6, 8); 179 180 if (ilo_dev_gen(render->dev) == ILO_GEN(6)) 181 gen6_wa_pre_pipe_control(render, dw1); 182 183 ilo_render_pipe_control(render, dw1); 184 185 assert(ilo_builder_batch_used(render->builder) <= batch_used + 186 ilo_render_get_flush_len(render)); 187 } 188 189 /** 190 * Return the command length of ilo_render_emit_query(). 191 */ 192 int 193 ilo_render_get_query_len(const struct ilo_render *render, 194 unsigned query_type) 195 { 196 int len; 197 198 ILO_DEV_ASSERT(render->dev, 6, 8); 199 200 /* always a flush or a variant of flush */ 201 len = ilo_render_get_flush_len(render); 202 203 switch (query_type) { 204 case PIPE_QUERY_OCCLUSION_COUNTER: 205 case PIPE_QUERY_OCCLUSION_PREDICATE: 206 case PIPE_QUERY_TIMESTAMP: 207 case PIPE_QUERY_TIME_ELAPSED: 208 /* no reg */ 209 break; 210 case PIPE_QUERY_PRIMITIVES_GENERATED: 211 case PIPE_QUERY_PRIMITIVES_EMITTED: 212 len += GEN6_MI_STORE_REGISTER_MEM__SIZE * 2; 213 break; 214 case PIPE_QUERY_PIPELINE_STATISTICS: 215 { 216 const int num_regs = 217 (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 10 : 8; 218 const int num_pads = 219 (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 1 : 3; 220 221 len += GEN6_MI_STORE_REGISTER_MEM__SIZE * 2 * num_regs + 222 GEN6_MI_STORE_DATA_IMM__SIZE * num_pads; 223 } 224 break; 225 default: 226 len = 0; 227 break; 228 } 229 230 return len; 231 } 232 233 /** 234 * Emit PIPE_CONTROLs or MI_STORE_REGISTER_MEMs to store register values. 235 */ 236 void 237 ilo_render_emit_query(struct ilo_render *render, 238 struct ilo_query *q, uint32_t offset) 239 { 240 const uint32_t pipeline_statistics_regs[11] = { 241 GEN6_REG_IA_VERTICES_COUNT, 242 GEN6_REG_IA_PRIMITIVES_COUNT, 243 GEN6_REG_VS_INVOCATION_COUNT, 244 GEN6_REG_GS_INVOCATION_COUNT, 245 GEN6_REG_GS_PRIMITIVES_COUNT, 246 GEN6_REG_CL_INVOCATION_COUNT, 247 GEN6_REG_CL_PRIMITIVES_COUNT, 248 GEN6_REG_PS_INVOCATION_COUNT, 249 (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 250 GEN7_REG_HS_INVOCATION_COUNT : 0, 251 (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 252 GEN7_REG_DS_INVOCATION_COUNT : 0, 253 0, 254 }; 255 const uint32_t primitives_generated_reg = 256 (ilo_dev_gen(render->dev) >= ILO_GEN(7) && q->index > 0) ? 257 GEN7_REG_SO_PRIM_STORAGE_NEEDED(q->index) : 258 GEN6_REG_CL_INVOCATION_COUNT; 259 const uint32_t primitives_emitted_reg = 260 (ilo_dev_gen(render->dev) >= ILO_GEN(7)) ? 261 GEN7_REG_SO_NUM_PRIMS_WRITTEN(q->index) : 262 GEN6_REG_SO_NUM_PRIMS_WRITTEN; 263 const unsigned batch_used = ilo_builder_batch_used(render->builder); 264 const uint32_t *regs; 265 int reg_count = 0, i; 266 uint32_t pipe_control_dw1 = 0; 267 268 ILO_DEV_ASSERT(render->dev, 6, 8); 269 270 switch (q->type) { 271 case PIPE_QUERY_OCCLUSION_COUNTER: 272 case PIPE_QUERY_OCCLUSION_PREDICATE: 273 pipe_control_dw1 = GEN6_PIPE_CONTROL_DEPTH_STALL | 274 GEN6_PIPE_CONTROL_WRITE_PS_DEPTH_COUNT; 275 break; 276 case PIPE_QUERY_TIMESTAMP: 277 case PIPE_QUERY_TIME_ELAPSED: 278 pipe_control_dw1 = GEN6_PIPE_CONTROL_WRITE_TIMESTAMP; 279 break; 280 case PIPE_QUERY_PRIMITIVES_GENERATED: 281 regs = &primitives_generated_reg; 282 reg_count = 1; 283 break; 284 case PIPE_QUERY_PRIMITIVES_EMITTED: 285 regs = &primitives_emitted_reg; 286 reg_count = 1; 287 break; 288 case PIPE_QUERY_PIPELINE_STATISTICS: 289 regs = pipeline_statistics_regs; 290 reg_count = ARRAY_SIZE(pipeline_statistics_regs); 291 break; 292 default: 293 break; 294 } 295 296 if (pipe_control_dw1) { 297 assert(!reg_count); 298 299 if (ilo_dev_gen(render->dev) == ILO_GEN(6)) 300 gen6_wa_pre_pipe_control(render, pipe_control_dw1); 301 302 gen6_PIPE_CONTROL(render->builder, pipe_control_dw1, q->bo, offset, 0); 303 304 render->state.current_pipe_control_dw1 |= pipe_control_dw1; 305 render->state.deferred_pipe_control_dw1 &= ~pipe_control_dw1; 306 } else if (reg_count) { 307 ilo_render_emit_flush(render); 308 } 309 310 for (i = 0; i < reg_count; i++) { 311 if (regs[i]) { 312 /* store lower 32 bits */ 313 gen6_MI_STORE_REGISTER_MEM(render->builder, regs[i], q->bo, offset); 314 /* store higher 32 bits */ 315 gen6_MI_STORE_REGISTER_MEM(render->builder, regs[i] + 4, 316 q->bo, offset + 4); 317 } else { 318 gen6_MI_STORE_DATA_IMM(render->builder, q->bo, offset, 0); 319 } 320 321 offset += 8; 322 } 323 324 assert(ilo_builder_batch_used(render->builder) <= batch_used + 325 ilo_render_get_query_len(render, q->type)); 326 } 327 328 int 329 ilo_render_get_rectlist_len(const struct ilo_render *render, 330 const struct ilo_blitter *blitter) 331 { 332 ILO_DEV_ASSERT(render->dev, 6, 8); 333 334 return ilo_render_get_rectlist_dynamic_states_len(render, blitter) + 335 ilo_render_get_rectlist_commands_len(render, blitter); 336 } 337 338 void 339 ilo_render_emit_rectlist(struct ilo_render *render, 340 const struct ilo_blitter *blitter) 341 { 342 struct ilo_render_rectlist_session session; 343 344 ILO_DEV_ASSERT(render->dev, 6, 8); 345 346 memset(&session, 0, sizeof(session)); 347 ilo_render_emit_rectlist_dynamic_states(render, blitter, &session); 348 ilo_render_emit_rectlist_commands(render, blitter, &session); 349 } 350 351 int 352 ilo_render_get_draw_len(const struct ilo_render *render, 353 const struct ilo_state_vector *vec) 354 { 355 ILO_DEV_ASSERT(render->dev, 6, 8); 356 357 return ilo_render_get_draw_dynamic_states_len(render, vec) + 358 ilo_render_get_draw_surface_states_len(render, vec) + 359 ilo_render_get_draw_commands_len(render, vec); 360 } 361 362 static void 363 draw_session_prepare(struct ilo_render *render, 364 const struct ilo_state_vector *vec, 365 struct ilo_render_draw_session *session) 366 { 367 memset(session, 0, sizeof(*session)); 368 session->pipe_dirty = vec->dirty; 369 session->reduced_prim = u_reduced_prim(vec->draw->mode); 370 371 if (render->hw_ctx_changed) { 372 /* these should be enough to make everything uploaded */ 373 render->batch_bo_changed = true; 374 render->state_bo_changed = true; 375 render->instruction_bo_changed = true; 376 377 session->prim_changed = true; 378 379 ilo_state_urb_full_delta(&vec->urb, render->dev, &session->urb_delta); 380 ilo_state_vf_full_delta(&vec->ve->vf, render->dev, &session->vf_delta); 381 382 ilo_state_raster_full_delta(&vec->rasterizer->rs, render->dev, 383 &session->rs_delta); 384 385 ilo_state_viewport_full_delta(&vec->viewport.vp, render->dev, 386 &session->vp_delta); 387 388 ilo_state_cc_full_delta(&vec->blend->cc, render->dev, 389 &session->cc_delta); 390 } else { 391 session->prim_changed = 392 (render->state.reduced_prim != session->reduced_prim); 393 394 ilo_state_urb_get_delta(&vec->urb, render->dev, 395 &render->state.urb, &session->urb_delta); 396 397 if (vec->dirty & ILO_DIRTY_VE) { 398 ilo_state_vf_full_delta(&vec->ve->vf, render->dev, 399 &session->vf_delta); 400 } 401 402 if (vec->dirty & ILO_DIRTY_RASTERIZER) { 403 ilo_state_raster_get_delta(&vec->rasterizer->rs, render->dev, 404 &render->state.rs, &session->rs_delta); 405 } 406 407 if (vec->dirty & ILO_DIRTY_VIEWPORT) { 408 ilo_state_viewport_full_delta(&vec->viewport.vp, render->dev, 409 &session->vp_delta); 410 } 411 412 if (vec->dirty & ILO_DIRTY_BLEND) { 413 ilo_state_cc_get_delta(&vec->blend->cc, render->dev, 414 &render->state.cc, &session->cc_delta); 415 } 416 } 417 } 418 419 static void 420 draw_session_end(struct ilo_render *render, 421 const struct ilo_state_vector *vec, 422 struct ilo_render_draw_session *session) 423 { 424 render->hw_ctx_changed = false; 425 426 render->batch_bo_changed = false; 427 render->state_bo_changed = false; 428 render->instruction_bo_changed = false; 429 430 render->state.reduced_prim = session->reduced_prim; 431 432 render->state.urb = vec->urb; 433 render->state.rs = vec->rasterizer->rs; 434 render->state.cc = vec->blend->cc; 435 } 436 437 void 438 ilo_render_emit_draw(struct ilo_render *render, 439 const struct ilo_state_vector *vec) 440 { 441 struct ilo_render_draw_session session; 442 443 ILO_DEV_ASSERT(render->dev, 6, 8); 444 445 draw_session_prepare(render, vec, &session); 446 447 /* force all states to be uploaded if the state bo changed */ 448 if (render->state_bo_changed) 449 session.pipe_dirty = ILO_DIRTY_ALL; 450 else 451 session.pipe_dirty = vec->dirty; 452 453 ilo_render_emit_draw_dynamic_states(render, vec, &session); 454 ilo_render_emit_draw_surface_states(render, vec, &session); 455 456 /* force all commands to be uploaded if the HW context changed */ 457 if (render->hw_ctx_changed) 458 session.pipe_dirty = ILO_DIRTY_ALL; 459 else 460 session.pipe_dirty = vec->dirty; 461 462 ilo_render_emit_draw_commands(render, vec, &session); 463 464 draw_session_end(render, vec, &session); 465 } 466 467 int 468 ilo_render_get_launch_grid_len(const struct ilo_render *render, 469 const struct ilo_state_vector *vec) 470 { 471 ILO_DEV_ASSERT(render->dev, 7, 7.5); 472 473 return ilo_render_get_launch_grid_surface_states_len(render, vec) + 474 ilo_render_get_launch_grid_dynamic_states_len(render, vec) + 475 ilo_render_get_launch_grid_commands_len(render, vec); 476 } 477 478 void 479 ilo_render_emit_launch_grid(struct ilo_render *render, 480 const struct ilo_state_vector *vec, 481 const unsigned thread_group_offset[3], 482 const unsigned thread_group_dim[3], 483 unsigned thread_group_size, 484 const struct pipe_constant_buffer *input, 485 uint32_t pc) 486 { 487 struct ilo_render_launch_grid_session session; 488 489 ILO_DEV_ASSERT(render->dev, 7, 7.5); 490 491 assert(input->buffer); 492 493 memset(&session, 0, sizeof(session)); 494 495 session.thread_group_offset = thread_group_offset; 496 session.thread_group_dim = thread_group_dim; 497 session.thread_group_size = thread_group_size; 498 session.input = input; 499 session.pc = pc; 500 501 ilo_render_emit_launch_grid_surface_states(render, vec, &session); 502 ilo_render_emit_launch_grid_dynamic_states(render, vec, &session); 503 ilo_render_emit_launch_grid_commands(render, vec, &session); 504 } 505