v3dv: add an 'always flush' mode

In this mode, which can be activated with V3D_DEBUG=always_flush like
in the GL driver, we flush every draw call separately. For now this
is useful for debugging, but we can also set the flag internally on
specific jobs when we identify scenarios where we need the same behavior.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
This commit is contained in:
Iago Toral Quiroga 2020-03-18 10:00:31 +01:00 committed by Marge Bot
parent ebbd326472
commit 761b0c02f8
2 changed files with 66 additions and 10 deletions

View File

@ -71,7 +71,7 @@ v3dv_job_add_extra_bo(struct v3dv_job *job, struct v3dv_bo *bo)
_mesa_set_add(job->extra_bos, bo);
}
static void
static struct v3dv_job *
subpass_start(struct v3dv_cmd_buffer *cmd_buffer, uint32_t subpass_idx);
static void
@ -257,6 +257,12 @@ cmd_buffer_can_merge_subpass(struct v3dv_cmd_buffer *cmd_buffer)
const struct v3dv_physical_device *physical_device =
&cmd_buffer->device->instance->physicalDevice;
if (!cmd_buffer->state.job)
return false;
if (cmd_buffer->state.job->always_flush)
return false;
if (!physical_device->options.merge_jobs)
return false;
@ -515,6 +521,9 @@ v3dv_job_init(struct v3dv_job *job,
*/
if (cmd_buffer && cmd_buffer->state.pass)
job->first_subpass = subpass_idx;
if (V3D_DEBUG & V3D_DEBUG_ALWAYS_FLUSH)
job->always_flush = true;
}
struct v3dv_job *
@ -1491,7 +1500,7 @@ cmd_buffer_emit_render_pass_rcl(struct v3dv_cmd_buffer *cmd_buffer)
cl_emit(rcl, END_OF_RENDERING, end);
}
static void
static struct v3dv_job *
subpass_start(struct v3dv_cmd_buffer *cmd_buffer, uint32_t subpass_idx)
{
struct v3dv_cmd_buffer_state *state = &cmd_buffer->state;
@ -1503,7 +1512,7 @@ subpass_start(struct v3dv_cmd_buffer *cmd_buffer, uint32_t subpass_idx)
*/
struct v3dv_job *job = v3dv_cmd_buffer_start_job(cmd_buffer, subpass_idx);
if (!job)
return;
return NULL;
state->subpass_idx = subpass_idx;
@ -1538,6 +1547,8 @@ subpass_start(struct v3dv_cmd_buffer *cmd_buffer, uint32_t subpass_idx)
cmd_buffer->state.dynamic.viewport.count == 0) {
emit_clip_window(job, &state->render_area);
}
return job;
}
static void
@ -2331,9 +2342,46 @@ cmd_buffer_emit_draw(struct v3dv_cmd_buffer *cmd_buffer,
}
}
static struct v3dv_job *
cmd_buffer_pre_draw_split_job(struct v3dv_cmd_buffer *cmd_buffer)
{
struct v3dv_job *job = cmd_buffer->state.job;
assert(job);
/* If the job has been flagged with 'always_flush' and it has already
* recorded any draw calls then we need to start a new job for it.
*/
if (job->always_flush && job->draw_count > 0) {
assert(cmd_buffer->state.pass);
/* First, flag the current job as not being the last in the
* current subpass
*/
job->is_subpass_finish = false;
/* Now start a new job in the same subpass and flag it as continuing
* the current subpass.
*/
job = subpass_start(cmd_buffer, cmd_buffer->state.subpass_idx);
assert(job->draw_count == 0);
job->is_subpass_continue = true;
/* Inherit the 'always flush' behavior */
job->always_flush = true;
}
assert(job->draw_count == 0 || !job->always_flush);
return job;
}
static void
cmd_buffer_emit_pre_draw(struct v3dv_cmd_buffer *cmd_buffer)
{
/* If the job is configured to flush on every draw call we need to create
* a new job now.
*/
struct v3dv_job *job = cmd_buffer_pre_draw_split_job(cmd_buffer);
job->draw_count++;
/* FIXME: likely to be filtered by really needed states */
uint32_t *dirty = &cmd_buffer->state.dirty;
struct v3dv_dynamic_state *dynamic = &cmd_buffer->state.dynamic;
@ -2383,7 +2431,6 @@ v3dv_CmdDraw(VkCommandBuffer commandBuffer,
{
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
struct v3dv_draw_info info = {};
info.vertex_count = vertexCount;
info.instance_count = instanceCount;
info.first_instance = firstInstance;
@ -2402,11 +2449,11 @@ v3dv_CmdDrawIndexed(VkCommandBuffer commandBuffer,
{
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
cmd_buffer_emit_pre_draw(cmd_buffer);
struct v3dv_job *job = cmd_buffer->state.job;
assert(job);
cmd_buffer_emit_pre_draw(cmd_buffer);
const struct v3dv_pipeline *pipeline = cmd_buffer->state.pipeline;
uint32_t hw_prim_type = v3d_hw_prim_type(pipeline->vs->topology);
uint8_t index_type = ffs(cmd_buffer->state.index_size) - 1;
@ -2453,11 +2500,11 @@ v3dv_CmdDrawIndirect(VkCommandBuffer commandBuffer,
if (drawCount == 0)
return;
cmd_buffer_emit_pre_draw(cmd_buffer);
struct v3dv_job *job = cmd_buffer->state.job;
assert(job);
cmd_buffer_emit_pre_draw(cmd_buffer);
const struct v3dv_pipeline *pipeline = cmd_buffer->state.pipeline;
uint32_t hw_prim_type = v3d_hw_prim_type(pipeline->vs->topology);
@ -2483,11 +2530,11 @@ v3dv_CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer,
if (drawCount == 0)
return;
cmd_buffer_emit_pre_draw(cmd_buffer);
struct v3dv_job *job = cmd_buffer->state.job;
assert(job);
cmd_buffer_emit_pre_draw(cmd_buffer);
const struct v3dv_pipeline *pipeline = cmd_buffer->state.pipeline;
uint32_t hw_prim_type = v3d_hw_prim_type(pipeline->vs->topology);
uint8_t index_type = ffs(cmd_buffer->state.index_size) - 1;

View File

@ -592,6 +592,15 @@ struct v3dv_job {
* submit no-op jobs), then it is our responsibility to do that.
*/
struct v3dv_fence *fence;
/* Number of draw calls recorded into the job */
uint32_t draw_count;
/* A flag indicating whether we want to flush every draw separately. This
* can be used for debugging, or for cases where special circumstances
* require this behavior.
*/
bool always_flush;
};
void v3dv_job_init(struct v3dv_job *job,