1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-13 19:29:14 +01:00

[dxvk] Implement transform feedback

Begins transform feedback when rendering with an xfb-enabled
pipeline bound, and ends transform feedback as needed, while
writing back the counters supplied by the app. This does not
yet support transform feedback queries or the draw command.
This commit is contained in:
Philip Rebohle 2018-07-24 18:20:45 +02:00
parent a27e440272
commit 93b1b9bc00
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
5 changed files with 123 additions and 5 deletions

View File

@ -273,7 +273,9 @@ namespace dxvk {
* \returns The physical buffer slice
*/
DxvkPhysicalBufferSlice physicalSlice() const {
return m_buffer->subSlice(m_offset, m_length);
return m_buffer != nullptr
? m_buffer->subSlice(m_offset, m_length)
: DxvkPhysicalBufferSlice();
}
/**
@ -301,7 +303,9 @@ namespace dxvk {
* \returns Pointer into mapped buffer memory
*/
void* mapPtr(VkDeviceSize offset) const {
return m_buffer->mapPtr(m_offset + offset);
return m_buffer != nullptr
? m_buffer->mapPtr(m_offset + offset)
: nullptr;
}
/**

View File

@ -134,7 +134,9 @@ namespace dxvk {
* \returns Buffer handle
*/
VkBuffer handle() const {
return m_buffer->handle();
return m_buffer != nullptr
? m_buffer->handle()
: VK_NULL_HANDLE;
}
/**

View File

@ -36,6 +36,7 @@ namespace dxvk {
// before any draw or dispatch command is recorded.
m_flags.clr(
DxvkContextFlag::GpRenderPassBound,
DxvkContextFlag::GpXfbActive,
DxvkContextFlag::GpClearRenderTargets);
m_flags.set(
@ -44,6 +45,7 @@ namespace dxvk {
DxvkContextFlag::GpDirtyResources,
DxvkContextFlag::GpDirtyVertexBuffers,
DxvkContextFlag::GpDirtyIndexBuffer,
DxvkContextFlag::GpDirtyXfbBuffers,
DxvkContextFlag::CpDirtyPipeline,
DxvkContextFlag::CpDirtyPipelineState,
DxvkContextFlag::CpDirtyResources,
@ -222,6 +224,8 @@ namespace dxvk {
uint32_t binding,
const DxvkBufferSlice& buffer,
const DxvkBufferSlice& counter) {
this->spillRenderPass();
m_state.xfb.buffers [binding] = buffer;
m_state.xfb.counters[binding] = counter;
@ -1151,6 +1155,9 @@ namespace dxvk {
if (usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
m_flags.set(DxvkContextFlag::GpDirtyVertexBuffers);
if (usage & VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT)
m_flags.set(DxvkContextFlag::GpDirtyXfbBuffers);
if (usage & (VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT
| VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) {
m_flags.set(DxvkContextFlag::GpDirtyResources,
@ -2163,6 +2170,8 @@ namespace dxvk {
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
this->pauseTransformFeedback();
m_queries.endQueries(m_cmd, VK_QUERY_TYPE_OCCLUSION);
m_queries.endQueries(m_cmd, VK_QUERY_TYPE_PIPELINE_STATISTICS);
@ -2243,6 +2252,52 @@ namespace dxvk {
}
void DxvkContext::startTransformFeedback() {
if (!m_flags.test(DxvkContextFlag::GpXfbActive)) {
m_flags.set(DxvkContextFlag::GpXfbActive);
VkBuffer ctrBuffers[MaxNumXfbBuffers];
VkDeviceSize ctrOffsets[MaxNumXfbBuffers];
for (uint32_t i = 0; i < MaxNumXfbBuffers; i++) {
auto physSlice = m_state.xfb.counters[i].physicalSlice();
ctrBuffers[i] = physSlice.handle();
ctrOffsets[i] = physSlice.offset();
if (physSlice.handle() != VK_NULL_HANDLE)
m_cmd->trackResource(physSlice.resource());
}
m_cmd->cmdBeginTransformFeedback(
0, MaxNumXfbBuffers, ctrBuffers, ctrOffsets);
}
}
void DxvkContext::pauseTransformFeedback() {
if (m_flags.test(DxvkContextFlag::GpXfbActive)) {
m_flags.clr(DxvkContextFlag::GpXfbActive);
VkBuffer ctrBuffers[MaxNumXfbBuffers];
VkDeviceSize ctrOffsets[MaxNumXfbBuffers];
for (uint32_t i = 0; i < MaxNumXfbBuffers; i++) {
auto physSlice = m_state.xfb.counters[i].physicalSlice();
ctrBuffers[i] = physSlice.handle();
ctrOffsets[i] = physSlice.offset();
if (physSlice.handle() != VK_NULL_HANDLE)
m_cmd->trackResource(physSlice.resource());
}
m_cmd->cmdEndTransformFeedback(
0, MaxNumXfbBuffers, ctrBuffers, ctrOffsets);
}
}
void DxvkContext::unbindComputePipeline() {
m_flags.set(
DxvkContextFlag::CpDirtyPipeline,
@ -2289,7 +2344,8 @@ namespace dxvk {
DxvkContextFlag::GpDirtyPipelineState,
DxvkContextFlag::GpDirtyResources,
DxvkContextFlag::GpDirtyVertexBuffers,
DxvkContextFlag::GpDirtyIndexBuffer);
DxvkContextFlag::GpDirtyIndexBuffer,
DxvkContextFlag::GpDirtyXfbBuffers);
m_gpActivePipeline = VK_NULL_HANDLE;
}
@ -2315,6 +2371,8 @@ namespace dxvk {
if (m_flags.test(DxvkContextFlag::GpDirtyPipelineState)) {
m_flags.clr(DxvkContextFlag::GpDirtyPipelineState);
this->pauseTransformFeedback();
for (uint32_t i = 0; i < m_state.gp.state.ilBindingCount; i++) {
const uint32_t binding = m_state.gp.state.ilBindings[i].binding;
@ -2677,6 +2735,50 @@ namespace dxvk {
}
}
}
void DxvkContext::updateTransformFeedbackBuffers() {
VkBuffer xfbBuffers[MaxNumXfbBuffers];
VkDeviceSize xfbOffsets[MaxNumXfbBuffers];
VkDeviceSize xfbLengths[MaxNumXfbBuffers];
for (size_t i = 0; i < MaxNumXfbBuffers; i++) {
auto physSlice = m_state.xfb.buffers[i].physicalSlice();
xfbBuffers[i] = physSlice.handle();
xfbOffsets[i] = physSlice.offset();
xfbLengths[i] = physSlice.length();
if (physSlice.handle() == VK_NULL_HANDLE)
xfbBuffers[i] = m_device->dummyBufferHandle();
if (physSlice.handle() != VK_NULL_HANDLE)
m_cmd->trackResource(physSlice.resource());
}
m_cmd->cmdBindTransformFeedbackBuffers(
0, MaxNumXfbBuffers,
xfbBuffers, xfbOffsets, xfbLengths);
}
void DxvkContext::updateTransformFeedbackState() {
bool hasTransformFeedback =
m_state.gp.pipeline != nullptr
&& m_state.gp.pipeline->flags().test(DxvkGraphicsPipelineFlag::HasTransformFeedback);
if (!hasTransformFeedback)
return;
if (m_flags.test(DxvkContextFlag::GpDirtyXfbBuffers)) {
m_flags.clr(DxvkContextFlag::GpDirtyXfbBuffers);
this->pauseTransformFeedback();
this->updateTransformFeedbackBuffers();
}
this->startTransformFeedback();
}
void DxvkContext::updateDynamicState() {
@ -2743,6 +2845,7 @@ namespace dxvk {
this->updateVertexBufferBindings();
this->updateGraphicsShaderResources();
this->updateGraphicsPipelineState();
this->updateTransformFeedbackState();
this->updateGraphicsShaderDescriptors();
this->updateDynamicState();
}

View File

@ -788,6 +788,9 @@ namespace dxvk {
const DxvkRenderTargets& renderTargets,
DxvkRenderPassOps& renderPassOps);
void startTransformFeedback();
void pauseTransformFeedback();
void unbindComputePipeline();
void updateComputePipeline();
void updateComputePipelineState();
@ -820,6 +823,9 @@ namespace dxvk {
void updateIndexBufferBinding();
void updateVertexBufferBindings();
void updateTransformFeedbackBuffers();
void updateTransformFeedbackState();
void updateDynamicState();

View File

@ -135,6 +135,8 @@ namespace dxvk {
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT |
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT |
VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
@ -144,7 +146,8 @@ namespace dxvk {
VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_TRANSFER_READ_BIT |
VK_ACCESS_UNIFORM_READ_BIT |
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, 0 },
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT, 0 },
}};
VkRenderPassCreateInfo info;