• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /** \file gen6_sol.c
25  *
26  * Code to initialize the binding table entries used by transform feedback.
27  */
28 
29 #include "main/bufferobj.h"
30 #include "main/macros.h"
31 #include "brw_context.h"
32 #include "intel_batchbuffer.h"
33 #include "brw_defines.h"
34 #include "brw_state.h"
35 #include "main/transformfeedback.h"
36 
37 static void
gen6_update_sol_surfaces(struct brw_context * brw)38 gen6_update_sol_surfaces(struct brw_context *brw)
39 {
40    struct gl_context *ctx = &brw->ctx;
41    bool xfb_active = _mesa_is_xfb_active_and_unpaused(ctx);
42    struct gl_transform_feedback_object *xfb_obj;
43    const struct gl_transform_feedback_info *linked_xfb_info = NULL;
44 
45    if (xfb_active) {
46       /* BRW_NEW_TRANSFORM_FEEDBACK */
47       xfb_obj = ctx->TransformFeedback.CurrentObject;
48       linked_xfb_info = xfb_obj->program->sh.LinkedTransformFeedback;
49    }
50 
51    for (int i = 0; i < BRW_MAX_SOL_BINDINGS; ++i) {
52       const int surf_index = SURF_INDEX_GEN6_SOL_BINDING(i);
53       if (xfb_active && i < linked_xfb_info->NumOutputs) {
54          unsigned buffer = linked_xfb_info->Outputs[i].OutputBuffer;
55          unsigned buffer_offset =
56             xfb_obj->Offset[buffer] / 4 +
57             linked_xfb_info->Outputs[i].DstOffset;
58          if (brw->geometry_program) {
59             brw_update_sol_surface(
60                brw, xfb_obj->Buffers[buffer],
61                &brw->gs.base.surf_offset[surf_index],
62                linked_xfb_info->Outputs[i].NumComponents,
63                linked_xfb_info->Buffers[buffer].Stride, buffer_offset);
64          } else {
65             brw_update_sol_surface(
66                brw, xfb_obj->Buffers[buffer],
67                &brw->ff_gs.surf_offset[surf_index],
68                linked_xfb_info->Outputs[i].NumComponents,
69                linked_xfb_info->Buffers[buffer].Stride, buffer_offset);
70          }
71       } else {
72          if (!brw->geometry_program)
73             brw->ff_gs.surf_offset[surf_index] = 0;
74          else
75             brw->gs.base.surf_offset[surf_index] = 0;
76       }
77    }
78 
79    brw->ctx.NewDriverState |= BRW_NEW_SURFACES;
80 }
81 
82 const struct brw_tracked_state gen6_sol_surface = {
83    .dirty = {
84       .mesa = 0,
85       .brw = BRW_NEW_BATCH |
86              BRW_NEW_BLORP |
87              BRW_NEW_TRANSFORM_FEEDBACK,
88    },
89    .emit = gen6_update_sol_surfaces,
90 };
91 
92 /**
93  * Constructs the binding table for the WM surface state, which maps unit
94  * numbers to surface state objects.
95  */
96 static void
brw_gs_upload_binding_table(struct brw_context * brw)97 brw_gs_upload_binding_table(struct brw_context *brw)
98 {
99    uint32_t *bind;
100    struct gl_context *ctx = &brw->ctx;
101    const struct gl_shader_program *shaderprog;
102    bool need_binding_table = false;
103 
104    /* We have two scenarios here:
105     * 1) We are using a geometry shader only to implement transform feedback
106     *    for a vertex shader (brw->geometry_program == NULL). In this case, we
107     *    only need surfaces for transform feedback in the GS stage.
108     * 2) We have a user-provided geometry shader. In this case we may need
109     *    surfaces for transform feedback and/or other stuff, like textures,
110     *    in the GS stage.
111     */
112 
113    if (!brw->geometry_program) {
114       /* BRW_NEW_VERTEX_PROGRAM */
115       shaderprog = ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
116       if (shaderprog) {
117          /* Skip making a binding table if we don't have anything to put in it */
118          const struct gl_transform_feedback_info *linked_xfb_info =
119             shaderprog->xfb_program->sh.LinkedTransformFeedback;
120          need_binding_table = linked_xfb_info->NumOutputs > 0;
121       }
122       if (!need_binding_table) {
123          if (brw->ff_gs.bind_bo_offset != 0) {
124             brw->ctx.NewDriverState |= BRW_NEW_BINDING_TABLE_POINTERS;
125             brw->ff_gs.bind_bo_offset = 0;
126          }
127          return;
128       }
129 
130       /* Might want to calculate nr_surfaces first, to avoid taking up so much
131        * space for the binding table. Anyway, in this case we know that we only
132        * use BRW_MAX_SOL_BINDINGS surfaces at most.
133        */
134       bind = brw_state_batch(brw, AUB_TRACE_BINDING_TABLE,
135                              sizeof(uint32_t) * BRW_MAX_SOL_BINDINGS,
136                              32, &brw->ff_gs.bind_bo_offset);
137 
138       /* BRW_NEW_SURFACES */
139       memcpy(bind, brw->ff_gs.surf_offset,
140              BRW_MAX_SOL_BINDINGS * sizeof(uint32_t));
141    } else {
142       /* BRW_NEW_GEOMETRY_PROGRAM */
143       shaderprog = ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY];
144       if (shaderprog) {
145          /* Skip making a binding table if we don't have anything to put in it */
146          struct brw_stage_prog_data *prog_data = brw->gs.base.prog_data;
147          const struct gl_transform_feedback_info *linked_xfb_info =
148             shaderprog->xfb_program->sh.LinkedTransformFeedback;
149          need_binding_table = linked_xfb_info->NumOutputs > 0 ||
150                               prog_data->binding_table.size_bytes > 0;
151       }
152       if (!need_binding_table) {
153          if (brw->gs.base.bind_bo_offset != 0) {
154             brw->gs.base.bind_bo_offset = 0;
155             brw->ctx.NewDriverState |= BRW_NEW_BINDING_TABLE_POINTERS;
156          }
157          return;
158       }
159 
160       /* Might want to calculate nr_surfaces first, to avoid taking up so much
161        * space for the binding table.
162        */
163       bind = brw_state_batch(brw, AUB_TRACE_BINDING_TABLE,
164                              sizeof(uint32_t) * BRW_MAX_SURFACES,
165                              32, &brw->gs.base.bind_bo_offset);
166 
167       /* BRW_NEW_SURFACES */
168       memcpy(bind, brw->gs.base.surf_offset,
169              BRW_MAX_SURFACES * sizeof(uint32_t));
170    }
171 
172    brw->ctx.NewDriverState |= BRW_NEW_BINDING_TABLE_POINTERS;
173 }
174 
175 const struct brw_tracked_state gen6_gs_binding_table = {
176    .dirty = {
177       .mesa = 0,
178       .brw = BRW_NEW_BATCH |
179              BRW_NEW_BLORP |
180              BRW_NEW_GEOMETRY_PROGRAM |
181              BRW_NEW_VERTEX_PROGRAM |
182              BRW_NEW_SURFACES,
183    },
184    .emit = brw_gs_upload_binding_table,
185 };
186 
187 struct gl_transform_feedback_object *
brw_new_transform_feedback(struct gl_context * ctx,GLuint name)188 brw_new_transform_feedback(struct gl_context *ctx, GLuint name)
189 {
190    struct brw_context *brw = brw_context(ctx);
191    struct brw_transform_feedback_object *brw_obj =
192       CALLOC_STRUCT(brw_transform_feedback_object);
193    if (!brw_obj)
194       return NULL;
195 
196    _mesa_init_transform_feedback_object(&brw_obj->base, name);
197 
198    brw_obj->offset_bo =
199       drm_intel_bo_alloc(brw->bufmgr, "transform feedback offsets", 16, 64);
200    brw_obj->prim_count_bo =
201       drm_intel_bo_alloc(brw->bufmgr, "xfb primitive counts", 4096, 64);
202 
203    return &brw_obj->base;
204 }
205 
206 void
brw_delete_transform_feedback(struct gl_context * ctx,struct gl_transform_feedback_object * obj)207 brw_delete_transform_feedback(struct gl_context *ctx,
208                               struct gl_transform_feedback_object *obj)
209 {
210    struct brw_transform_feedback_object *brw_obj =
211       (struct brw_transform_feedback_object *) obj;
212 
213    for (unsigned i = 0; i < ARRAY_SIZE(obj->Buffers); i++) {
214       _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
215    }
216 
217    drm_intel_bo_unreference(brw_obj->offset_bo);
218    drm_intel_bo_unreference(brw_obj->prim_count_bo);
219 
220    free(brw_obj);
221 }
222 
223 void
brw_begin_transform_feedback(struct gl_context * ctx,GLenum mode,struct gl_transform_feedback_object * obj)224 brw_begin_transform_feedback(struct gl_context *ctx, GLenum mode,
225 			     struct gl_transform_feedback_object *obj)
226 {
227    struct brw_context *brw = brw_context(ctx);
228    const struct gl_shader_program *shaderprog;
229    const struct gl_transform_feedback_info *linked_xfb_info;
230    struct gl_transform_feedback_object *xfb_obj =
231       ctx->TransformFeedback.CurrentObject;
232 
233    assert(brw->gen == 6);
234 
235    if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
236       /* BRW_NEW_GEOMETRY_PROGRAM */
237       shaderprog =
238          ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY];
239    } else {
240       /* BRW_NEW_VERTEX_PROGRAM */
241       shaderprog =
242          ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
243    }
244    linked_xfb_info = shaderprog->xfb_program->sh.LinkedTransformFeedback;
245 
246    /* Compute the maximum number of vertices that we can write without
247     * overflowing any of the buffers currently being used for feedback.
248     */
249    unsigned max_index
250       = _mesa_compute_max_transform_feedback_vertices(ctx, xfb_obj,
251                                                       linked_xfb_info);
252 
253    /* Initialize the SVBI 0 register to zero and set the maximum index. */
254    BEGIN_BATCH(4);
255    OUT_BATCH(_3DSTATE_GS_SVB_INDEX << 16 | (4 - 2));
256    OUT_BATCH(0); /* SVBI 0 */
257    OUT_BATCH(0); /* starting index */
258    OUT_BATCH(max_index);
259    ADVANCE_BATCH();
260 
261    /* Initialize the rest of the unused streams to sane values.  Otherwise,
262     * they may indicate that there is no room to write data and prevent
263     * anything from happening at all.
264     */
265    for (int i = 1; i < 4; i++) {
266       BEGIN_BATCH(4);
267       OUT_BATCH(_3DSTATE_GS_SVB_INDEX << 16 | (4 - 2));
268       OUT_BATCH(i << SVB_INDEX_SHIFT);
269       OUT_BATCH(0); /* starting index */
270       OUT_BATCH(0xffffffff);
271       ADVANCE_BATCH();
272    }
273 }
274 
275 void
brw_end_transform_feedback(struct gl_context * ctx,struct gl_transform_feedback_object * obj)276 brw_end_transform_feedback(struct gl_context *ctx,
277                            struct gl_transform_feedback_object *obj)
278 {
279    /* After EndTransformFeedback, it's likely that the client program will try
280     * to draw using the contents of the transform feedback buffer as vertex
281     * input.  In order for this to work, we need to flush the data through at
282     * least the GS stage of the pipeline, and flush out the render cache.  For
283     * simplicity, just do a full flush.
284     */
285    struct brw_context *brw = brw_context(ctx);
286    brw_emit_mi_flush(brw);
287 }
288