2 * Copyright © 2011 Intel Corporation
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:
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
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
26 * Code to initialize the binding table entries used by transform feedback.
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"
38 gen6_update_sol_surfaces(struct brw_context
*brw
)
40 struct gl_context
*ctx
= &brw
->ctx
;
41 /* BRW_NEW_TRANSFORM_FEEDBACK */
42 struct gl_transform_feedback_object
*xfb_obj
=
43 ctx
->TransformFeedback
.CurrentObject
;
44 const struct gl_shader_program
*shaderprog
;
45 const struct gl_transform_feedback_info
*linked_xfb_info
;
48 if (brw
->geometry_program
) {
49 /* BRW_NEW_GEOMETRY_PROGRAM */
51 ctx
->_Shader
->CurrentProgram
[MESA_SHADER_GEOMETRY
];
53 /* BRW_NEW_VERTEX_PROGRAM */
55 ctx
->_Shader
->CurrentProgram
[MESA_SHADER_VERTEX
];
57 linked_xfb_info
= &shaderprog
->LinkedTransformFeedback
;
59 for (i
= 0; i
< BRW_MAX_SOL_BINDINGS
; ++i
) {
60 const int surf_index
= SURF_INDEX_GEN6_SOL_BINDING(i
);
61 if (_mesa_is_xfb_active_and_unpaused(ctx
) &&
62 i
< linked_xfb_info
->NumOutputs
) {
63 unsigned buffer
= linked_xfb_info
->Outputs
[i
].OutputBuffer
;
64 unsigned buffer_offset
=
65 xfb_obj
->Offset
[buffer
] / 4 +
66 linked_xfb_info
->Outputs
[i
].DstOffset
;
67 if (brw
->geometry_program
) {
68 brw_update_sol_surface(
69 brw
, xfb_obj
->Buffers
[buffer
],
70 &brw
->gs
.base
.surf_offset
[surf_index
],
71 linked_xfb_info
->Outputs
[i
].NumComponents
,
72 linked_xfb_info
->BufferStride
[buffer
], buffer_offset
);
74 brw_update_sol_surface(
75 brw
, xfb_obj
->Buffers
[buffer
],
76 &brw
->ff_gs
.surf_offset
[surf_index
],
77 linked_xfb_info
->Outputs
[i
].NumComponents
,
78 linked_xfb_info
->BufferStride
[buffer
], buffer_offset
);
81 if (!brw
->geometry_program
)
82 brw
->ff_gs
.surf_offset
[surf_index
] = 0;
84 brw
->gs
.base
.surf_offset
[surf_index
] = 0;
88 brw
->state
.dirty
.brw
|= BRW_NEW_SURFACES
;
91 const struct brw_tracked_state gen6_sol_surface
= {
94 .brw
= (BRW_NEW_BATCH
|
95 BRW_NEW_VERTEX_PROGRAM
|
96 BRW_NEW_GEOMETRY_PROGRAM
|
97 BRW_NEW_TRANSFORM_FEEDBACK
),
100 .emit
= gen6_update_sol_surfaces
,
104 * Constructs the binding table for the WM surface state, which maps unit
105 * numbers to surface state objects.
108 brw_gs_upload_binding_table(struct brw_context
*brw
)
112 if (!brw
->geometry_program
) {
113 struct gl_context
*ctx
= &brw
->ctx
;
114 /* BRW_NEW_VERTEX_PROGRAM */
115 const struct gl_shader_program
*shaderprog
=
116 ctx
->_Shader
->CurrentProgram
[MESA_SHADER_VERTEX
];
117 bool has_surfaces
= false;
120 const struct gl_transform_feedback_info
*linked_xfb_info
=
121 &shaderprog
->LinkedTransformFeedback
;
122 /* Currently we only ever upload surfaces for SOL. */
123 has_surfaces
= linked_xfb_info
->NumOutputs
!= 0;
125 /* Skip making a binding table if we don't have anything to put in it. */
127 if (brw
->ff_gs
.bind_bo_offset
!= 0) {
128 brw
->state
.dirty
.brw
|= BRW_NEW_GS_BINDING_TABLE
;
129 brw
->ff_gs
.bind_bo_offset
= 0;
136 /* Might want to calculate nr_surfaces first, to avoid taking up so much
137 * space for the binding table.
139 if (brw
->geometry_program
) {
140 bind
= brw_state_batch(brw
, AUB_TRACE_BINDING_TABLE
,
141 sizeof(uint32_t) * BRW_MAX_GEN6_GS_SURFACES
,
142 32, &brw
->gs
.base
.bind_bo_offset
);
144 /* BRW_NEW_SURFACES */
145 memcpy(bind
, brw
->gs
.base
.surf_offset
, BRW_MAX_GEN6_GS_SURFACES
* sizeof(uint32_t));
147 bind
= brw_state_batch(brw
, AUB_TRACE_BINDING_TABLE
,
148 sizeof(uint32_t) * BRW_MAX_GEN6_GS_SURFACES
,
149 32, &brw
->ff_gs
.bind_bo_offset
);
151 /* BRW_NEW_SURFACES */
152 memcpy(bind
, brw
->ff_gs
.surf_offset
, BRW_MAX_GEN6_GS_SURFACES
* sizeof(uint32_t));
155 brw
->state
.dirty
.brw
|= BRW_NEW_GS_BINDING_TABLE
;
158 const struct brw_tracked_state gen6_gs_binding_table
= {
161 .brw
= (BRW_NEW_BATCH
|
162 BRW_NEW_VERTEX_PROGRAM
|
163 BRW_NEW_GEOMETRY_PROGRAM
|
167 .emit
= brw_gs_upload_binding_table
,
170 struct gl_transform_feedback_object
*
171 brw_new_transform_feedback(struct gl_context
*ctx
, GLuint name
)
173 struct brw_context
*brw
= brw_context(ctx
);
174 struct brw_transform_feedback_object
*brw_obj
=
175 CALLOC_STRUCT(brw_transform_feedback_object
);
179 _mesa_init_transform_feedback_object(&brw_obj
->base
, name
);
182 drm_intel_bo_alloc(brw
->bufmgr
, "transform feedback offsets", 16, 64);
183 brw_obj
->prim_count_bo
=
184 drm_intel_bo_alloc(brw
->bufmgr
, "xfb primitive counts", 4096, 64);
186 return &brw_obj
->base
;
190 brw_delete_transform_feedback(struct gl_context
*ctx
,
191 struct gl_transform_feedback_object
*obj
)
193 struct brw_transform_feedback_object
*brw_obj
=
194 (struct brw_transform_feedback_object
*) obj
;
196 for (unsigned i
= 0; i
< Elements(obj
->Buffers
); i
++) {
197 _mesa_reference_buffer_object(ctx
, &obj
->Buffers
[i
], NULL
);
200 drm_intel_bo_unreference(brw_obj
->offset_bo
);
201 drm_intel_bo_unreference(brw_obj
->prim_count_bo
);
207 brw_begin_transform_feedback(struct gl_context
*ctx
, GLenum mode
,
208 struct gl_transform_feedback_object
*obj
)
210 struct brw_context
*brw
= brw_context(ctx
);
211 const struct gl_shader_program
*shaderprog
;
212 const struct gl_transform_feedback_info
*linked_xfb_info
;
213 struct gl_transform_feedback_object
*xfb_obj
=
214 ctx
->TransformFeedback
.CurrentObject
;
216 assert(brw
->gen
== 6);
218 if (brw
->geometry_program
) {
219 /* BRW_NEW_GEOMETRY_PROGRAM */
221 ctx
->_Shader
->CurrentProgram
[MESA_SHADER_GEOMETRY
];
223 /* BRW_NEW_VERTEX_PROGRAM */
225 ctx
->_Shader
->CurrentProgram
[MESA_SHADER_VERTEX
];
227 linked_xfb_info
= &shaderprog
->LinkedTransformFeedback
;
229 /* Compute the maximum number of vertices that we can write without
230 * overflowing any of the buffers currently being used for feedback.
233 = _mesa_compute_max_transform_feedback_vertices(xfb_obj
,
236 /* 3DSTATE_GS_SVB_INDEX is non-pipelined. */
237 intel_emit_post_sync_nonzero_flush(brw
);
239 /* Initialize the SVBI 0 register to zero and set the maximum index. */
241 OUT_BATCH(_3DSTATE_GS_SVB_INDEX
<< 16 | (4 - 2));
242 OUT_BATCH(0); /* SVBI 0 */
243 OUT_BATCH(0); /* starting index */
244 OUT_BATCH(max_index
);
247 /* Initialize the rest of the unused streams to sane values. Otherwise,
248 * they may indicate that there is no room to write data and prevent
249 * anything from happening at all.
251 for (int i
= 1; i
< 4; i
++) {
253 OUT_BATCH(_3DSTATE_GS_SVB_INDEX
<< 16 | (4 - 2));
254 OUT_BATCH(i
<< SVB_INDEX_SHIFT
);
255 OUT_BATCH(0); /* starting index */
256 OUT_BATCH(0xffffffff);
262 brw_end_transform_feedback(struct gl_context
*ctx
,
263 struct gl_transform_feedback_object
*obj
)
265 /* After EndTransformFeedback, it's likely that the client program will try
266 * to draw using the contents of the transform feedback buffer as vertex
267 * input. In order for this to work, we need to flush the data through at
268 * least the GS stage of the pipeline, and flush out the render cache. For
269 * simplicity, just do a full flush.
271 struct brw_context
*brw
= brw_context(ctx
);
272 intel_batchbuffer_emit_mi_flush(brw
);