1 /* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2014 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 #ifndef ILO_BUILDER_H 29 #define ILO_BUILDER_H 30 31 #include "intel_winsys.h" 32 33 #include "ilo_core.h" 34 #include "ilo_debug.h" 35 #include "ilo_dev.h" 36 37 enum ilo_builder_writer_type { 38 ILO_BUILDER_WRITER_BATCH, 39 ILO_BUILDER_WRITER_INSTRUCTION, 40 41 ILO_BUILDER_WRITER_COUNT, 42 }; 43 44 enum ilo_builder_item_type { 45 /* for dynamic buffer */ 46 ILO_BUILDER_ITEM_BLOB, 47 ILO_BUILDER_ITEM_CLIP_VIEWPORT, 48 ILO_BUILDER_ITEM_SF_VIEWPORT, 49 ILO_BUILDER_ITEM_SCISSOR_RECT, 50 ILO_BUILDER_ITEM_CC_VIEWPORT, 51 ILO_BUILDER_ITEM_COLOR_CALC, 52 ILO_BUILDER_ITEM_DEPTH_STENCIL, 53 ILO_BUILDER_ITEM_BLEND, 54 ILO_BUILDER_ITEM_SAMPLER, 55 ILO_BUILDER_ITEM_INTERFACE_DESCRIPTOR, 56 57 /* for surface buffer */ 58 ILO_BUILDER_ITEM_SURFACE, 59 ILO_BUILDER_ITEM_BINDING_TABLE, 60 61 /* for instruction buffer */ 62 ILO_BUILDER_ITEM_KERNEL, 63 64 ILO_BUILDER_ITEM_COUNT, 65 }; 66 67 struct ilo_builder_item { 68 enum ilo_builder_item_type type; 69 unsigned offset; 70 unsigned size; 71 }; 72 73 struct ilo_builder_writer { 74 /* internal flags */ 75 unsigned flags; 76 77 unsigned size; 78 struct intel_bo *bo; 79 void *ptr; 80 81 /* data written to the bottom */ 82 unsigned used; 83 /* data written to the top */ 84 unsigned stolen; 85 86 /* for decoding */ 87 struct ilo_builder_item *items; 88 unsigned item_alloc; 89 unsigned item_used; 90 }; 91 92 /** 93 * A snapshot of the writer state. 94 */ 95 struct ilo_builder_snapshot { 96 unsigned reloc_count; 97 98 unsigned used; 99 unsigned stolen; 100 unsigned item_used; 101 }; 102 103 struct ilo_builder { 104 const struct ilo_dev *dev; 105 struct intel_winsys *winsys; 106 uint32_t mocs; 107 108 struct ilo_builder_writer writers[ILO_BUILDER_WRITER_COUNT]; 109 bool unrecoverable_error; 110 111 /* for writers that have their data appended */ 112 unsigned begin_used[ILO_BUILDER_WRITER_COUNT]; 113 114 /* for STATE_BASE_ADDRESS */ 115 unsigned sba_instruction_pos; 116 }; 117 118 void 119 ilo_builder_init(struct ilo_builder *builder, 120 const struct ilo_dev *dev, 121 struct intel_winsys *winsys); 122 123 void 124 ilo_builder_reset(struct ilo_builder *builder); 125 126 void 127 ilo_builder_decode(struct ilo_builder *builder); 128 129 bool 130 ilo_builder_begin(struct ilo_builder *builder); 131 132 struct intel_bo * 133 ilo_builder_end(struct ilo_builder *builder, unsigned *used); 134 135 bool 136 ilo_builder_validate(struct ilo_builder *builder, 137 unsigned bo_count, struct intel_bo **bos); 138 139 /** 140 * Return true if the builder has a relocation entry for \p bo. 141 */ 142 static inline bool 143 ilo_builder_has_reloc(const struct ilo_builder *builder, 144 struct intel_bo *bo) 145 { 146 int i; 147 148 for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) { 149 const struct ilo_builder_writer *writer = &builder->writers[i]; 150 if (intel_bo_has_reloc(writer->bo, bo)) 151 return true; 152 } 153 154 return false; 155 } 156 157 void 158 ilo_builder_writer_discard(struct ilo_builder *builder, 159 enum ilo_builder_writer_type which); 160 161 bool 162 ilo_builder_writer_grow(struct ilo_builder *builder, 163 enum ilo_builder_writer_type which, 164 unsigned new_size, bool preserve); 165 166 bool 167 ilo_builder_writer_record(struct ilo_builder *builder, 168 enum ilo_builder_writer_type which, 169 enum ilo_builder_item_type type, 170 unsigned offset, unsigned size); 171 172 static inline void 173 ilo_builder_writer_checked_record(struct ilo_builder *builder, 174 enum ilo_builder_writer_type which, 175 enum ilo_builder_item_type item, 176 unsigned offset, unsigned size) 177 { 178 if (unlikely(ilo_debug & (ILO_DEBUG_BATCH | ILO_DEBUG_HANG))) { 179 if (!ilo_builder_writer_record(builder, which, item, offset, size)) { 180 builder->unrecoverable_error = true; 181 builder->writers[which].item_used = 0; 182 } 183 } 184 } 185 186 /** 187 * Return an offset to a region that is aligned to \p alignment and has at 188 * least \p size bytes. The region is reserved from the bottom. 189 */ 190 static inline unsigned 191 ilo_builder_writer_reserve_bottom(struct ilo_builder *builder, 192 enum ilo_builder_writer_type which, 193 unsigned alignment, unsigned size) 194 { 195 struct ilo_builder_writer *writer = &builder->writers[which]; 196 unsigned offset; 197 198 assert(alignment && util_is_power_of_two(alignment)); 199 offset = align(writer->used, alignment); 200 201 if (unlikely(offset + size > writer->size - writer->stolen)) { 202 if (!ilo_builder_writer_grow(builder, which, 203 offset + size + writer->stolen, true)) { 204 builder->unrecoverable_error = true; 205 ilo_builder_writer_discard(builder, which); 206 offset = 0; 207 } 208 209 assert(offset + size <= writer->size - writer->stolen); 210 } 211 212 return offset; 213 } 214 215 /** 216 * Similar to ilo_builder_writer_reserve_bottom(), but reserve from the top. 217 */ 218 static inline unsigned 219 ilo_builder_writer_reserve_top(struct ilo_builder *builder, 220 enum ilo_builder_writer_type which, 221 unsigned alignment, unsigned size) 222 { 223 struct ilo_builder_writer *writer = &builder->writers[which]; 224 unsigned offset; 225 226 assert(alignment && util_is_power_of_two(alignment)); 227 offset = (writer->size - writer->stolen - size) & ~(alignment - 1); 228 229 if (unlikely(offset < writer->used || 230 size > writer->size - writer->stolen)) { 231 if (!ilo_builder_writer_grow(builder, which, 232 align(writer->used, alignment) + size + writer->stolen, true)) { 233 builder->unrecoverable_error = true; 234 ilo_builder_writer_discard(builder, which); 235 } 236 237 offset = (writer->size - writer->stolen - size) & ~(alignment - 1); 238 assert(offset + size <= writer->size - writer->stolen); 239 } 240 241 return offset; 242 } 243 244 /** 245 * Add a relocation entry to the writer. 246 */ 247 static inline void 248 ilo_builder_writer_reloc(struct ilo_builder *builder, 249 enum ilo_builder_writer_type which, 250 unsigned offset, struct intel_bo *bo, 251 unsigned bo_offset, unsigned reloc_flags, 252 bool write_presumed_offset_hi) 253 { 254 struct ilo_builder_writer *writer = &builder->writers[which]; 255 uint64_t presumed_offset; 256 int err; 257 258 if (write_presumed_offset_hi) 259 ILO_DEV_ASSERT(builder->dev, 8, 8); 260 else 261 ILO_DEV_ASSERT(builder->dev, 6, 7.5); 262 263 assert(offset + sizeof(uint32_t) <= writer->used || 264 (offset >= writer->size - writer->stolen && 265 offset + sizeof(uint32_t) <= writer->size)); 266 267 err = intel_bo_add_reloc(writer->bo, offset, bo, bo_offset, 268 reloc_flags, &presumed_offset); 269 if (unlikely(err)) 270 builder->unrecoverable_error = true; 271 272 if (write_presumed_offset_hi) { 273 *((uint64_t *) ((char *) writer->ptr + offset)) = presumed_offset; 274 } else { 275 /* 32-bit addressing */ 276 assert(presumed_offset == (uint64_t) ((uint32_t) presumed_offset)); 277 *((uint32_t *) ((char *) writer->ptr + offset)) = presumed_offset; 278 } 279 } 280 281 /** 282 * Reserve a region from the dynamic buffer. Both the offset, in bytes, and 283 * the pointer to the reserved region are returned. The pointer is only valid 284 * until the next reserve call. 285 * 286 * Note that \p alignment is in bytes and \p len is in DWords. 287 */ 288 static inline uint32_t 289 ilo_builder_dynamic_pointer(struct ilo_builder *builder, 290 enum ilo_builder_item_type item, 291 unsigned alignment, unsigned len, 292 uint32_t **dw) 293 { 294 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 295 const unsigned size = len << 2; 296 const unsigned offset = ilo_builder_writer_reserve_top(builder, 297 which, alignment, size); 298 struct ilo_builder_writer *writer = &builder->writers[which]; 299 300 /* all states are at least aligned to 32-bytes */ 301 if (item != ILO_BUILDER_ITEM_BLOB) 302 assert(alignment % 32 == 0); 303 304 *dw = (uint32_t *) ((char *) writer->ptr + offset); 305 306 writer->stolen = writer->size - offset; 307 308 ilo_builder_writer_checked_record(builder, which, item, offset, size); 309 310 return offset; 311 } 312 313 /** 314 * Write a dynamic state to the dynamic buffer. 315 */ 316 static inline uint32_t 317 ilo_builder_dynamic_write(struct ilo_builder *builder, 318 enum ilo_builder_item_type item, 319 unsigned alignment, unsigned len, 320 const uint32_t *dw) 321 { 322 uint32_t offset, *dst; 323 324 offset = ilo_builder_dynamic_pointer(builder, item, alignment, len, &dst); 325 memcpy(dst, dw, len << 2); 326 327 return offset; 328 } 329 330 /** 331 * Reserve some space from the top (for prefetches). 332 */ 333 static inline void 334 ilo_builder_dynamic_pad_top(struct ilo_builder *builder, unsigned len) 335 { 336 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 337 const unsigned size = len << 2; 338 struct ilo_builder_writer *writer = &builder->writers[which]; 339 340 if (writer->stolen < size) { 341 ilo_builder_writer_reserve_top(builder, which, 342 1, size - writer->stolen); 343 writer->stolen = size; 344 } 345 } 346 347 static inline unsigned 348 ilo_builder_dynamic_used(const struct ilo_builder *builder) 349 { 350 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 351 const struct ilo_builder_writer *writer = &builder->writers[which]; 352 353 return writer->stolen >> 2; 354 } 355 356 /** 357 * Reserve a region from the surface buffer. Both the offset, in bytes, and 358 * the pointer to the reserved region are returned. The pointer is only valid 359 * until the next reserve call. 360 * 361 * Note that \p alignment is in bytes and \p len is in DWords. 362 */ 363 static inline uint32_t 364 ilo_builder_surface_pointer(struct ilo_builder *builder, 365 enum ilo_builder_item_type item, 366 unsigned alignment, unsigned len, 367 uint32_t **dw) 368 { 369 assert(item == ILO_BUILDER_ITEM_SURFACE || 370 item == ILO_BUILDER_ITEM_BINDING_TABLE); 371 372 return ilo_builder_dynamic_pointer(builder, item, alignment, len, dw); 373 } 374 375 /** 376 * Add a relocation entry for a DWord of a surface state. 377 */ 378 static inline void 379 ilo_builder_surface_reloc(struct ilo_builder *builder, 380 uint32_t offset, unsigned dw_index, 381 struct intel_bo *bo, unsigned bo_offset, 382 unsigned reloc_flags) 383 { 384 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 385 386 ilo_builder_writer_reloc(builder, which, offset + (dw_index << 2), 387 bo, bo_offset, reloc_flags, false); 388 } 389 390 static inline void 391 ilo_builder_surface_reloc64(struct ilo_builder *builder, 392 uint32_t offset, unsigned dw_index, 393 struct intel_bo *bo, unsigned bo_offset, 394 unsigned reloc_flags) 395 { 396 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 397 398 ilo_builder_writer_reloc(builder, which, offset + (dw_index << 2), 399 bo, bo_offset, reloc_flags, true); 400 } 401 402 static inline unsigned 403 ilo_builder_surface_used(const struct ilo_builder *builder) 404 { 405 return ilo_builder_dynamic_used(builder); 406 } 407 408 /** 409 * Write a kernel to the instruction buffer. The offset, in bytes, of the 410 * kernel is returned. 411 */ 412 static inline uint32_t 413 ilo_builder_instruction_write(struct ilo_builder *builder, 414 unsigned size, const void *kernel) 415 { 416 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_INSTRUCTION; 417 /* 418 * From the Sandy Bridge PRM, volume 4 part 2, page 112: 419 * 420 * "Due to prefetch of the instruction stream, the EUs may attempt to 421 * access up to 8 instructions (128 bytes) beyond the end of the 422 * kernel program - possibly into the next memory page. Although 423 * these instructions will not be executed, software must account for 424 * the prefetch in order to avoid invalid page access faults." 425 */ 426 const unsigned reserved_size = size + 128; 427 /* kernels are aligned to 64 bytes */ 428 const unsigned alignment = 64; 429 const unsigned offset = ilo_builder_writer_reserve_bottom(builder, 430 which, alignment, reserved_size); 431 struct ilo_builder_writer *writer = &builder->writers[which]; 432 433 memcpy((char *) writer->ptr + offset, kernel, size); 434 435 writer->used = offset + size; 436 437 ilo_builder_writer_checked_record(builder, which, 438 ILO_BUILDER_ITEM_KERNEL, offset, size); 439 440 return offset; 441 } 442 443 /** 444 * Reserve a region from the batch buffer. Both the offset, in DWords, and 445 * the pointer to the reserved region are returned. The pointer is only valid 446 * until the next reserve call. 447 * 448 * Note that \p len is in DWords. 449 */ 450 static inline unsigned 451 ilo_builder_batch_pointer(struct ilo_builder *builder, 452 unsigned len, uint32_t **dw) 453 { 454 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 455 /* 456 * We know the batch bo is always aligned. Using 1 here should allow the 457 * compiler to optimize away aligning. 458 */ 459 const unsigned alignment = 1; 460 const unsigned size = len << 2; 461 const unsigned offset = ilo_builder_writer_reserve_bottom(builder, 462 which, alignment, size); 463 struct ilo_builder_writer *writer = &builder->writers[which]; 464 465 assert(offset % 4 == 0); 466 *dw = (uint32_t *) ((char *) writer->ptr + offset); 467 468 writer->used = offset + size; 469 470 return offset >> 2; 471 } 472 473 /** 474 * Write a command to the batch buffer. 475 */ 476 static inline unsigned 477 ilo_builder_batch_write(struct ilo_builder *builder, 478 unsigned len, const uint32_t *dw) 479 { 480 unsigned pos; 481 uint32_t *dst; 482 483 pos = ilo_builder_batch_pointer(builder, len, &dst); 484 memcpy(dst, dw, len << 2); 485 486 return pos; 487 } 488 489 /** 490 * Add a relocation entry for a DWord of a command. 491 */ 492 static inline void 493 ilo_builder_batch_reloc(struct ilo_builder *builder, unsigned pos, 494 struct intel_bo *bo, unsigned bo_offset, 495 unsigned reloc_flags) 496 { 497 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 498 499 ilo_builder_writer_reloc(builder, which, pos << 2, 500 bo, bo_offset, reloc_flags, false); 501 } 502 503 static inline void 504 ilo_builder_batch_reloc64(struct ilo_builder *builder, unsigned pos, 505 struct intel_bo *bo, unsigned bo_offset, 506 unsigned reloc_flags) 507 { 508 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 509 510 ilo_builder_writer_reloc(builder, which, pos << 2, 511 bo, bo_offset, reloc_flags, true); 512 } 513 514 static inline unsigned 515 ilo_builder_batch_used(const struct ilo_builder *builder) 516 { 517 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 518 const struct ilo_builder_writer *writer = &builder->writers[which]; 519 520 return writer->used >> 2; 521 } 522 523 static inline unsigned 524 ilo_builder_batch_space(const struct ilo_builder *builder) 525 { 526 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 527 const struct ilo_builder_writer *writer = &builder->writers[which]; 528 529 return (writer->size - writer->stolen - writer->used) >> 2; 530 } 531 532 static inline void 533 ilo_builder_batch_discard(struct ilo_builder *builder) 534 { 535 ilo_builder_writer_discard(builder, ILO_BUILDER_WRITER_BATCH); 536 } 537 538 static inline void 539 ilo_builder_batch_print_stats(const struct ilo_builder *builder) 540 { 541 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 542 const struct ilo_builder_writer *writer = &builder->writers[which]; 543 544 ilo_printf("%d+%d bytes (%d%% full)\n", 545 writer->used, writer->stolen, 546 (writer->used + writer->stolen) * 100 / writer->size); 547 } 548 549 void 550 ilo_builder_batch_snapshot(const struct ilo_builder *builder, 551 struct ilo_builder_snapshot *snapshot); 552 553 void 554 ilo_builder_batch_restore(struct ilo_builder *builder, 555 const struct ilo_builder_snapshot *snapshot); 556 557 #endif /* ILO_BUILDER_H */ 558