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
gen7_begin_transform_feedback(struct gl_context * ctx,GLenum mode,struct gl_transform_feedback_object * obj)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
gen7_end_transform_feedback(struct gl_context * ctx,struct gl_transform_feedback_object * obj)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
gen7_pause_transform_feedback(struct gl_context * ctx,struct gl_transform_feedback_object * obj)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
gen7_resume_transform_feedback(struct gl_context * ctx,struct gl_transform_feedback_object * obj)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