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 #include "util/u_memory.h" 29 30 #include "ilo_builder.h" 31 #include "ilo_builder_render.h" /* for ilo_builder_batch_patch_sba() */ 32 33 enum ilo_builder_writer_flags { 34 /* 35 * When this bit is set, ilo_builder_begin() will not realllocate. New 36 * data will be appended instead. 37 */ 38 WRITER_FLAG_APPEND = 1 << 0, 39 40 /* 41 * When this bit is set, the writer grows when full. When not, callers 42 * must make sure the writer never needs to grow. 43 */ 44 WRITER_FLAG_GROW = 1 << 1, 45 46 /* 47 * The writer will be mapped directly. 48 */ 49 WRITER_FLAG_MAP = 1 << 2, 50 }; 51 52 /** 53 * Set the initial size and flags of a writer. 54 */ 55 static void 56 ilo_builder_writer_init(struct ilo_builder *builder, 57 enum ilo_builder_writer_type which) 58 { 59 struct ilo_builder_writer *writer = &builder->writers[which]; 60 61 switch (which) { 62 case ILO_BUILDER_WRITER_BATCH: 63 writer->size = sizeof(uint32_t) * 8192; 64 break; 65 case ILO_BUILDER_WRITER_INSTRUCTION: 66 /* 67 * The EUs pretch some instructions. But since the kernel invalidates 68 * the instruction cache between batch buffers, we can set 69 * WRITER_FLAG_APPEND without worrying the EUs would see invalid 70 * instructions prefetched. 71 */ 72 writer->flags = WRITER_FLAG_APPEND | WRITER_FLAG_GROW; 73 writer->size = 8192; 74 break; 75 default: 76 assert(!"unknown builder writer"); 77 return; 78 break; 79 } 80 81 if (builder->dev->has_llc) 82 writer->flags |= WRITER_FLAG_MAP; 83 } 84 85 /** 86 * Free all resources used by a writer. Note that the initial size is not 87 * reset. 88 */ 89 static void 90 ilo_builder_writer_reset(struct ilo_builder *builder, 91 enum ilo_builder_writer_type which) 92 { 93 struct ilo_builder_writer *writer = &builder->writers[which]; 94 95 if (writer->ptr) { 96 if (writer->flags & WRITER_FLAG_MAP) 97 intel_bo_unmap(writer->bo); 98 else 99 FREE(writer->ptr); 100 101 writer->ptr = NULL; 102 } 103 104 intel_bo_unref(writer->bo); 105 writer->bo = NULL; 106 107 writer->used = 0; 108 writer->stolen = 0; 109 110 if (writer->items) { 111 FREE(writer->items); 112 writer->item_alloc = 0; 113 writer->item_used = 0; 114 } 115 } 116 117 /** 118 * Discard everything written so far. 119 */ 120 void 121 ilo_builder_writer_discard(struct ilo_builder *builder, 122 enum ilo_builder_writer_type which) 123 { 124 struct ilo_builder_writer *writer = &builder->writers[which]; 125 126 intel_bo_truncate_relocs(writer->bo, 0); 127 writer->used = 0; 128 writer->stolen = 0; 129 writer->item_used = 0; 130 } 131 132 static struct intel_bo * 133 alloc_writer_bo(struct intel_winsys *winsys, 134 enum ilo_builder_writer_type which, 135 unsigned size) 136 { 137 static const char *writer_names[ILO_BUILDER_WRITER_COUNT] = { 138 [ILO_BUILDER_WRITER_BATCH] = "batch", 139 [ILO_BUILDER_WRITER_INSTRUCTION] = "instruction", 140 }; 141 142 return intel_winsys_alloc_bo(winsys, writer_names[which], size, true); 143 } 144 145 static void * 146 map_writer_bo(struct intel_bo *bo, unsigned flags) 147 { 148 assert(flags & WRITER_FLAG_MAP); 149 150 if (flags & WRITER_FLAG_APPEND) 151 return intel_bo_map_gtt_async(bo); 152 else 153 return intel_bo_map(bo, true); 154 } 155 156 /** 157 * Allocate and map the buffer for writing. 158 */ 159 static bool 160 ilo_builder_writer_alloc_and_map(struct ilo_builder *builder, 161 enum ilo_builder_writer_type which) 162 { 163 struct ilo_builder_writer *writer = &builder->writers[which]; 164 165 /* allocate a new bo when not appending */ 166 if (!(writer->flags & WRITER_FLAG_APPEND) || !writer->bo) { 167 struct intel_bo *bo; 168 169 bo = alloc_writer_bo(builder->winsys, which, writer->size); 170 if (bo) { 171 intel_bo_unref(writer->bo); 172 writer->bo = bo; 173 } else if (writer->bo) { 174 /* reuse the old bo */ 175 ilo_builder_writer_discard(builder, which); 176 } else { 177 return false; 178 } 179 180 writer->used = 0; 181 writer->stolen = 0; 182 writer->item_used = 0; 183 } 184 185 /* map the bo or allocate the staging system memory */ 186 if (writer->flags & WRITER_FLAG_MAP) 187 writer->ptr = map_writer_bo(writer->bo, writer->flags); 188 else if (!writer->ptr) 189 writer->ptr = MALLOC(writer->size); 190 191 return (writer->ptr != NULL); 192 } 193 194 /** 195 * Unmap the buffer for submission. 196 */ 197 static bool 198 ilo_builder_writer_unmap(struct ilo_builder *builder, 199 enum ilo_builder_writer_type which) 200 { 201 struct ilo_builder_writer *writer = &builder->writers[which]; 202 unsigned offset; 203 int err = 0; 204 205 if (writer->flags & WRITER_FLAG_MAP) { 206 intel_bo_unmap(writer->bo); 207 writer->ptr = NULL; 208 return true; 209 } 210 211 offset = builder->begin_used[which]; 212 if (writer->used > offset) { 213 err = intel_bo_pwrite(writer->bo, offset, writer->used - offset, 214 (char *) writer->ptr + offset); 215 } 216 217 if (writer->stolen && !err) { 218 const unsigned offset = writer->size - writer->stolen; 219 err = intel_bo_pwrite(writer->bo, offset, writer->stolen, 220 (const char *) writer->ptr + offset); 221 } 222 223 /* keep writer->ptr */ 224 225 return !err; 226 } 227 228 /** 229 * Grow a mapped writer to at least \p new_size. 230 */ 231 bool 232 ilo_builder_writer_grow(struct ilo_builder *builder, 233 enum ilo_builder_writer_type which, 234 unsigned new_size, bool preserve) 235 { 236 struct ilo_builder_writer *writer = &builder->writers[which]; 237 struct intel_bo *new_bo; 238 void *new_ptr; 239 240 if (!(writer->flags & WRITER_FLAG_GROW)) 241 return false; 242 243 /* stolen data may already be referenced and cannot be moved */ 244 if (writer->stolen) 245 return false; 246 247 if (new_size < writer->size << 1) 248 new_size = writer->size << 1; 249 /* STATE_BASE_ADDRESS requires page-aligned buffers */ 250 new_size = align(new_size, 4096); 251 252 new_bo = alloc_writer_bo(builder->winsys, which, new_size); 253 if (!new_bo) 254 return false; 255 256 /* map and copy the data over */ 257 if (writer->flags & WRITER_FLAG_MAP) { 258 new_ptr = map_writer_bo(new_bo, writer->flags); 259 260 /* 261 * When WRITER_FLAG_APPEND and WRITER_FLAG_GROW are both set, we may end 262 * up copying between two GTT-mapped BOs. That is slow. The issue 263 * could be solved by adding intel_bo_map_async(), or callers may choose 264 * to manually grow the writer without preserving the data. 265 */ 266 if (new_ptr && preserve) 267 memcpy(new_ptr, writer->ptr, writer->used); 268 } else if (preserve) { 269 new_ptr = REALLOC(writer->ptr, writer->size, new_size); 270 } else { 271 new_ptr = MALLOC(new_size); 272 } 273 274 if (!new_ptr) { 275 intel_bo_unref(new_bo); 276 return false; 277 } 278 279 if (writer->flags & WRITER_FLAG_MAP) 280 intel_bo_unmap(writer->bo); 281 else if (!preserve) 282 FREE(writer->ptr); 283 284 intel_bo_unref(writer->bo); 285 286 writer->size = new_size; 287 writer->bo = new_bo; 288 writer->ptr = new_ptr; 289 290 return true; 291 } 292 293 /** 294 * Record an item for later decoding. 295 */ 296 bool 297 ilo_builder_writer_record(struct ilo_builder *builder, 298 enum ilo_builder_writer_type which, 299 enum ilo_builder_item_type type, 300 unsigned offset, unsigned size) 301 { 302 struct ilo_builder_writer *writer = &builder->writers[which]; 303 struct ilo_builder_item *item; 304 305 if (writer->item_used == writer->item_alloc) { 306 const unsigned new_alloc = (writer->item_alloc) ? 307 writer->item_alloc << 1 : 256; 308 struct ilo_builder_item *items; 309 310 items = REALLOC(writer->items, 311 sizeof(writer->items[0]) * writer->item_alloc, 312 sizeof(writer->items[0]) * new_alloc); 313 if (!items) 314 return false; 315 316 writer->items = items; 317 writer->item_alloc = new_alloc; 318 } 319 320 item = &writer->items[writer->item_used++]; 321 item->type = type; 322 item->offset = offset; 323 item->size = size; 324 325 return true; 326 } 327 328 /** 329 * Initialize the builder. 330 */ 331 void 332 ilo_builder_init(struct ilo_builder *builder, 333 const struct ilo_dev *dev, 334 struct intel_winsys *winsys) 335 { 336 unsigned i; 337 338 assert(ilo_is_zeroed(builder, sizeof(*builder))); 339 340 builder->dev = dev; 341 builder->winsys = winsys; 342 343 /* gen6_SURFACE_STATE() may override this */ 344 switch (ilo_dev_gen(dev)) { 345 case ILO_GEN(8): 346 builder->mocs = GEN8_MOCS_MT_WB | GEN8_MOCS_CT_L3; 347 break; 348 case ILO_GEN(7.5): 349 case ILO_GEN(7): 350 builder->mocs = GEN7_MOCS_L3_WB; 351 break; 352 default: 353 builder->mocs = 0; 354 break; 355 } 356 357 for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) 358 ilo_builder_writer_init(builder, i); 359 } 360 361 /** 362 * Reset the builder and free all resources used. After resetting, the 363 * builder behaves as if it is newly initialized, except for potentially 364 * larger initial bo sizes. 365 */ 366 void 367 ilo_builder_reset(struct ilo_builder *builder) 368 { 369 unsigned i; 370 371 for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) 372 ilo_builder_writer_reset(builder, i); 373 } 374 375 /** 376 * Allocate and map the BOs. It may re-allocate or reuse existing BOs if 377 * there is any. 378 * 379 * Most builder functions can only be called after ilo_builder_begin() and 380 * before ilo_builder_end(). 381 */ 382 bool 383 ilo_builder_begin(struct ilo_builder *builder) 384 { 385 unsigned i; 386 387 for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) { 388 if (!ilo_builder_writer_alloc_and_map(builder, i)) { 389 ilo_builder_reset(builder); 390 return false; 391 } 392 393 builder->begin_used[i] = builder->writers[i].used; 394 } 395 396 builder->unrecoverable_error = false; 397 builder->sba_instruction_pos = 0; 398 399 return true; 400 } 401 402 /** 403 * Unmap BOs and make sure the written data landed the BOs. The batch buffer 404 * ready for submission is returned. 405 */ 406 struct intel_bo * 407 ilo_builder_end(struct ilo_builder *builder, unsigned *used) 408 { 409 struct ilo_builder_writer *bat; 410 unsigned i; 411 412 ilo_builder_batch_patch_sba(builder); 413 414 assert(ilo_builder_validate(builder, 0, NULL)); 415 416 for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) { 417 if (!ilo_builder_writer_unmap(builder, i)) 418 builder->unrecoverable_error = true; 419 } 420 421 if (builder->unrecoverable_error) 422 return NULL; 423 424 bat = &builder->writers[ILO_BUILDER_WRITER_BATCH]; 425 426 *used = bat->used; 427 428 return bat->bo; 429 } 430 431 /** 432 * Return true if the builder is in a valid state, after accounting for the 433 * additional BOs specified. The additional BOs can be listed to avoid 434 * snapshotting and restoring when they are known ahead of time. 435 * 436 * The number of additional BOs should not be more than a few. Like two, for 437 * copying between two BOs. 438 * 439 * Callers must make sure the builder is in a valid state when 440 * ilo_builder_end() is called. 441 */ 442 bool 443 ilo_builder_validate(struct ilo_builder *builder, 444 unsigned bo_count, struct intel_bo **bos) 445 { 446 const unsigned max_bo_count = 2; 447 struct intel_bo *bos_to_submit[ILO_BUILDER_WRITER_COUNT + max_bo_count]; 448 int i; 449 450 for (i = 0; i < ILO_BUILDER_WRITER_COUNT; i++) 451 bos_to_submit[i] = builder->writers[i].bo; 452 453 if (bo_count) { 454 assert(bo_count <= max_bo_count); 455 if (bo_count > max_bo_count) 456 return false; 457 458 memcpy(&bos_to_submit[ILO_BUILDER_WRITER_COUNT], 459 bos, sizeof(*bos) * bo_count); 460 i += bo_count; 461 } 462 463 return intel_winsys_can_submit_bo(builder->winsys, bos_to_submit, i); 464 } 465 466 /** 467 * Take a snapshot of the writer state. 468 */ 469 void 470 ilo_builder_batch_snapshot(const struct ilo_builder *builder, 471 struct ilo_builder_snapshot *snapshot) 472 { 473 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 474 const struct ilo_builder_writer *writer = &builder->writers[which]; 475 476 snapshot->reloc_count = intel_bo_get_reloc_count(writer->bo); 477 snapshot->used = writer->used; 478 snapshot->stolen = writer->stolen; 479 snapshot->item_used = writer->item_used; 480 } 481 482 /** 483 * Restore the writer state to when the snapshot was taken, except that it 484 * does not (unnecessarily) shrink BOs or the item array. 485 */ 486 void 487 ilo_builder_batch_restore(struct ilo_builder *builder, 488 const struct ilo_builder_snapshot *snapshot) 489 { 490 const enum ilo_builder_writer_type which = ILO_BUILDER_WRITER_BATCH; 491 struct ilo_builder_writer *writer = &builder->writers[which]; 492 493 intel_bo_truncate_relocs(writer->bo, snapshot->reloc_count); 494 writer->used = snapshot->used; 495 writer->stolen = snapshot->stolen; 496 writer->item_used = snapshot->item_used; 497 } 498