1 /* 2 * Copyright 2011 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24 /** 25 * @file gen7_sol_state.c 26 * 27 * Controls the stream output logic (SOL) stage of the gen7 hardware, which is 28 * used to implement GL_EXT_transform_feedback. 29 */ 30 31 #include "brw_context.h" 32 #include "brw_state.h" 33 #include "brw_defines.h" 34 #include "intel_batchbuffer.h" 35 #include "intel_buffer_objects.h" 36 #include "main/transformfeedback.h" 37 38 void 39 gen7_begin_transform_feedback(struct gl_context *ctx, GLenum mode, 40 struct gl_transform_feedback_object *obj) 41 { 42 struct brw_context *brw = brw_context(ctx); 43 struct brw_transform_feedback_object *brw_obj = 44 (struct brw_transform_feedback_object *) obj; 45 46 assert(brw->screen->devinfo.gen == 7); 47 48 /* Store the starting value of the SO_NUM_PRIMS_WRITTEN counters. */ 49 brw_save_primitives_written_counters(brw, brw_obj); 50 51 /* Reset the SO buffer offsets to 0. */ 52 if (!can_do_pipelined_register_writes(brw->screen)) { 53 intel_batchbuffer_flush(brw); 54 brw->batch.needs_sol_reset = true; 55 } else { 56 for (int i = 0; i < 4; i++) { 57 brw_load_register_imm32(brw, GEN7_SO_WRITE_OFFSET(i), 0); 58 } 59 } 60 61 brw_obj->primitive_mode = mode; 62 } 63 64 void 65 gen7_end_transform_feedback(struct gl_context *ctx, 66 struct gl_transform_feedback_object *obj) 67 { 68 /* After EndTransformFeedback, it's likely that the client program will try 69 * to draw using the contents of the transform feedback buffer as vertex 70 * input. In order for this to work, we need to flush the data through at 71 * least the GS stage of the pipeline, and flush out the render cache. For 72 * simplicity, just do a full flush. 73 */ 74 struct brw_context *brw = brw_context(ctx); 75 struct brw_transform_feedback_object *brw_obj = 76 (struct brw_transform_feedback_object *) obj; 77 78 /* Store the ending value of the SO_NUM_PRIMS_WRITTEN counters. */ 79 if (!obj->Paused) 80 brw_save_primitives_written_counters(brw, brw_obj); 81 82 /* We've reached the end of a transform feedback begin/end block. This 83 * means that future DrawTransformFeedback() calls will need to pick up the 84 * results of the current counter, and that it's time to roll back the 85 * current primitive counter to zero. 86 */ 87 brw_obj->previous_counter = brw_obj->counter; 88 brw_reset_transform_feedback_counter(&brw_obj->counter); 89 90 /* EndTransformFeedback() means that we need to update the number of 91 * vertices written. Since it's only necessary if DrawTransformFeedback() 92 * is called and it means mapping a buffer object, we delay computing it 93 * until it's absolutely necessary to try and avoid stalls. 94 */ 95 brw_obj->vertices_written_valid = false; 96 } 97 98 void 99 gen7_pause_transform_feedback(struct gl_context *ctx, 100 struct gl_transform_feedback_object *obj) 101 { 102 struct brw_context *brw = brw_context(ctx); 103 struct brw_transform_feedback_object *brw_obj = 104 (struct brw_transform_feedback_object *) obj; 105 106 /* Flush any drawing so that the counters have the right values. */ 107 brw_emit_mi_flush(brw); 108 109 assert(brw->screen->devinfo.gen == 7); 110 111 /* Save the SOL buffer offset register values. */ 112 for (int i = 0; i < 4; i++) { 113 BEGIN_BATCH(3); 114 OUT_BATCH(MI_STORE_REGISTER_MEM | (3 - 2)); 115 OUT_BATCH(GEN7_SO_WRITE_OFFSET(i)); 116 OUT_RELOC(brw_obj->offset_bo, RELOC_WRITE, i * sizeof(uint32_t)); 117 ADVANCE_BATCH(); 118 } 119 120 /* Store the temporary ending value of the SO_NUM_PRIMS_WRITTEN counters. 121 * While this operation is paused, other transform feedback actions may 122 * occur, which will contribute to the counters. We need to exclude that 123 * from our counts. 124 */ 125 brw_save_primitives_written_counters(brw, brw_obj); 126 } 127 128 void 129 gen7_resume_transform_feedback(struct gl_context *ctx, 130 struct gl_transform_feedback_object *obj) 131 { 132 struct brw_context *brw = brw_context(ctx); 133 struct brw_transform_feedback_object *brw_obj = 134 (struct brw_transform_feedback_object *) obj; 135 136 assert(brw->screen->devinfo.gen == 7); 137 138 /* Reload the SOL buffer offset registers. */ 139 for (int i = 0; i < 4; i++) { 140 BEGIN_BATCH(3); 141 OUT_BATCH(GEN7_MI_LOAD_REGISTER_MEM | (3 - 2)); 142 OUT_BATCH(GEN7_SO_WRITE_OFFSET(i)); 143 OUT_RELOC(brw_obj->offset_bo, RELOC_WRITE, i * sizeof(uint32_t)); 144 ADVANCE_BATCH(); 145 } 146 147 /* Store the new starting value of the SO_NUM_PRIMS_WRITTEN counters. */ 148 brw_save_primitives_written_counters(brw, brw_obj); 149 } 150