From 93b1b9bc0099e7e8c33834577cdb7fdfe3f34cf2 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 24 Jul 2018 18:20:45 +0200 Subject: [PATCH] [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. --- src/dxvk/dxvk_buffer.h | 8 ++- src/dxvk/dxvk_buffer_res.h | 4 +- src/dxvk/dxvk_context.cpp | 105 ++++++++++++++++++++++++++++++++++- src/dxvk/dxvk_context.h | 6 ++ src/dxvk/dxvk_renderpass.cpp | 5 +- 5 files changed, 123 insertions(+), 5 deletions(-) diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index ee8e1dd7..e0a3ff77 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -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; } /** diff --git a/src/dxvk/dxvk_buffer_res.h b/src/dxvk/dxvk_buffer_res.h index ca69ef6f..d69eccd9 100644 --- a/src/dxvk/dxvk_buffer_res.h +++ b/src/dxvk/dxvk_buffer_res.h @@ -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; } /** diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index f550b7fb..425efed6 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -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(); } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index b186bf6a..388f12c7 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -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(); diff --git a/src/dxvk/dxvk_renderpass.cpp b/src/dxvk/dxvk_renderpass.cpp index 9bb6517c..58422dd7 100644 --- a/src/dxvk/dxvk_renderpass.cpp +++ b/src/dxvk/dxvk_renderpass.cpp @@ -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;