[dxvk] Implemented proper image memory barriers

This commit is contained in:
Philip Rebohle 2017-12-05 13:00:06 +01:00
parent 7c1064e3eb
commit e0df25a7c5
9 changed files with 223 additions and 119 deletions

View File

@ -120,9 +120,16 @@ namespace dxvk {
void DxgiPresenter::initBackBuffer(const Rc<DxvkImage>& image) {
VkImageSubresourceRange sr;
sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
sr.baseMipLevel = 0;
sr.levelCount = image->info().mipLevels;
sr.baseArrayLayer = 0;
sr.layerCount = image->info().numLayers;
m_context->beginRecording(
m_device->createCommandList());
m_context->initImage(image, nullptr);
m_context->initImage(image, sr);
m_device->submitCommandList(
m_context->endRecording(),
nullptr, nullptr);
@ -133,8 +140,9 @@ namespace dxvk {
m_context->beginRecording(
m_device->createCommandList());
auto framebuffer = m_swapchain->getFramebuffer(m_acquireSync);
auto framebuffer = m_swapchain->getFramebuffer(m_acquireSync);
auto framebufferSize = framebuffer->size();
m_context->bindFramebuffer(framebuffer);
VkViewport viewport;

View File

@ -9,20 +9,22 @@ namespace dxvk {
const Rc<DxvkBuffer>& buffer,
VkDeviceSize offset,
VkDeviceSize size,
VkPipelineStageFlags stages,
VkAccessFlags access) {
VkPipelineStageFlags srcStages,
VkAccessFlags srcAccess,
VkPipelineStageFlags dstStages,
VkAccessFlags dstAccess) {
const DxvkResourceAccessTypes accessTypes
= this->getAccessTypes(access);
= this->getAccessTypes(srcAccess);
m_srcStages |= stages;
m_dstStages |= buffer->info().stages;
m_srcStages |= srcStages;
m_dstStages |= dstStages;
if (accessTypes.test(DxvkResourceAccessType::Write)) {
VkBufferMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = access;
barrier.dstAccessMask = buffer->info().access;
barrier.srcAccessMask = srcAccess;
barrier.dstAccessMask = dstAccess;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.buffer = buffer->handle();
@ -33,26 +35,35 @@ namespace dxvk {
}
void DxvkBarrierSet::initImage(
void DxvkBarrierSet::accessImage(
const Rc<DxvkImage>& image,
const VkImageSubresourceRange& subresources,
VkImageLayout srcLayout,
VkPipelineStageFlags srcStages,
VkAccessFlags srcAccess,
VkImageLayout dstLayout,
VkPipelineStageFlags dstStages,
VkAccessFlags dstAccess) {
const DxvkResourceAccessTypes accessTypes
= this->getAccessTypes(srcAccess);
m_srcStages |= srcStages;
m_dstStages |= dstStages;
VkImageMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = dstAccess;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = dstLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image->handle();
barrier.subresourceRange = subresources;
m_imgBarriers.push_back(barrier);
if ((srcLayout != dstLayout) || accessTypes.test(DxvkResourceAccessType::Write)) {
VkImageMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = srcAccess;
barrier.dstAccessMask = dstAccess;
barrier.oldLayout = srcLayout;
barrier.newLayout = dstLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image->handle();
barrier.subresourceRange = subresources;
m_imgBarriers.push_back(barrier);
}
}

View File

@ -24,12 +24,17 @@ namespace dxvk {
const Rc<DxvkBuffer>& buffer,
VkDeviceSize offset,
VkDeviceSize size,
VkPipelineStageFlags stages,
VkAccessFlags access);
VkPipelineStageFlags srcStages,
VkAccessFlags srcAccess,
VkPipelineStageFlags dstStages,
VkAccessFlags dstAccess);
void initImage(
void accessImage(
const Rc<DxvkImage>& image,
const VkImageSubresourceRange& subresources,
VkImageLayout srcLayout,
VkPipelineStageFlags srcStages,
VkAccessFlags srcAccess,
VkImageLayout dstLayout,
VkPipelineStageFlags dstStages,
VkAccessFlags dstAccess);

View File

@ -148,7 +148,7 @@ namespace dxvk {
if (image != nullptr) {
descriptor.image.imageView = image->handle();
descriptor.image.imageLayout = image->imageLayout();
descriptor.image.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
}
rc->bindShaderResource(slot, resource, descriptor);
@ -194,12 +194,27 @@ namespace dxvk {
const VkImageSubresourceRange& subresources) {
this->renderPassEnd();
m_cmd->cmdClearColorImage(
image->handle(),
VK_IMAGE_LAYOUT_GENERAL,
if (image->info().layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
m_barriers.accessImage(image, subresources,
VK_IMAGE_LAYOUT_UNDEFINED, 0, 0,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
m_barriers.recordCommands(m_cmd);
}
m_cmd->cmdClearColorImage(image->handle(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
&value, 1, &subresources);
// TODO memory barrier
m_barriers.accessImage(image, subresources,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
image->info().layout,
image->info().stages,
image->info().access);
m_barriers.recordCommands(m_cmd);
m_cmd->trackResource(image);
}
@ -215,6 +230,8 @@ namespace dxvk {
m_cmd->cmdClearAttachments(
1, &attachment, 1, &clearArea);
// FIXME add barriers if required
}
@ -238,12 +255,16 @@ namespace dxvk {
m_barriers.accessBuffer(
srcBuffer, srcOffset, numBytes,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT);
VK_ACCESS_TRANSFER_READ_BIT,
srcBuffer->info().stages,
srcBuffer->info().access);
m_barriers.accessBuffer(
dstBuffer, dstOffset, numBytes,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
VK_ACCESS_TRANSFER_WRITE_BIT,
dstBuffer->info().stages,
dstBuffer->info().access);
m_barriers.recordCommands(m_cmd);
@ -293,32 +314,15 @@ namespace dxvk {
}
void DxvkContext::initBuffer(
const Rc<DxvkBuffer>& buffer,
const Rc<DxvkDataBuffer>& data) {
// TODO implement
}
void DxvkContext::initImage(
const Rc<DxvkImage>& image,
const Rc<DxvkDataBuffer>& data) {
const DxvkImageCreateInfo& info = image->info();
VkImageSubresourceRange sr;
sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
sr.baseMipLevel = 0;
sr.levelCount = info.mipLevels;
sr.baseArrayLayer = 0;
sr.layerCount = info.numLayers;
m_barriers.initImage(image, sr,
VK_IMAGE_LAYOUT_GENERAL,
info.stages,
info.access);
const Rc<DxvkImage>& image,
const VkImageSubresourceRange& subresources) {
m_barriers.accessImage(image, subresources,
VK_IMAGE_LAYOUT_UNDEFINED, 0, 0,
image->info().layout,
image->info().stages,
image->info().access);
m_barriers.recordCommands(m_cmd);
// TODO implement data upload
}
@ -399,6 +403,9 @@ namespace dxvk {
&& (m_state.om.framebuffer != nullptr)) {
m_flags.set(DxvkContextFlag::GpRenderPassBound);
this->transformLayoutsRenderPassBegin(
m_state.om.framebuffer->renderTargets());
const DxvkFramebufferSize fbSize
= m_state.om.framebuffer->size();
@ -427,6 +434,9 @@ namespace dxvk {
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
m_cmd->cmdEndRenderPass();
this->transformLayoutsRenderPassEnd(
m_state.om.framebuffer->renderTargets());
}
}
@ -569,6 +579,99 @@ namespace dxvk {
}
void DxvkContext::transformLayoutsRenderPassBegin(
const DxvkRenderTargets& renderTargets) {
// Ensure that all color attachments are in the optimal layout.
// Any image that is used as a present source requires special
// care as we cannot use it for reading.
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
const Rc<DxvkImageView> target = renderTargets.getColorTarget(i);
if ((target != nullptr)
&& (target->imageInfo().layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)) {
VkImageLayout srcLayout = target->imageInfo().layout;
if (srcLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
srcLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_barriers.accessImage(
target->image(),
target->subresources(),
srcLayout,
target->imageInfo().stages,
target->imageInfo().access,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
}
}
// Transform the depth-stencil view to the optimal layout
const Rc<DxvkImageView> dsTarget = renderTargets.getDepthTarget();
if ((dsTarget != nullptr)
&& (dsTarget->imageInfo().layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)) {
m_barriers.accessImage(
dsTarget->image(),
dsTarget->subresources(),
dsTarget->imageInfo().layout,
dsTarget->imageInfo().stages,
dsTarget->imageInfo().access,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
}
m_barriers.recordCommands(m_cmd);
}
void DxvkContext::transformLayoutsRenderPassEnd(
const DxvkRenderTargets& renderTargets) {
// Transform color attachments back to their original layouts and
// make sure that they can be used for subsequent draw or compute
// operations. Swap chain images are treated like any other image.
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
const Rc<DxvkImageView> target = renderTargets.getColorTarget(i);
if (target != nullptr) {
m_barriers.accessImage(
target->image(),
target->subresources(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
target->imageInfo().layout,
target->imageInfo().stages,
target->imageInfo().access);
}
}
// Transform the depth-stencil attachment back to its original layout.
const Rc<DxvkImageView> dsTarget = renderTargets.getDepthTarget();
if (dsTarget != nullptr) {
m_barriers.accessImage(
dsTarget->image(),
dsTarget->subresources(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
dsTarget->imageInfo().layout,
dsTarget->imageInfo().stages,
dsTarget->imageInfo().access);
}
m_barriers.recordCommands(m_cmd);
}
DxvkShaderResourceSlots* DxvkContext::getShaderResourceSlots(VkPipelineBindPoint pipe) {
switch (pipe) {
case VK_PIPELINE_BIND_POINT_GRAPHICS: return &m_gResources;

View File

@ -144,7 +144,7 @@ namespace dxvk {
const DxvkBufferBinding& buffer);
/**
* \brief Clears subresources of an image
* \brief Clears subresources of a color image
*
* \param [in] image The image to clear
* \param [in] value Clear value
@ -224,31 +224,16 @@ namespace dxvk {
uint32_t firstInstance);
/**
* \brief Initializes a buffer
*
* Uploads initial data to the buffer so that it
* can be used for read-only operations. Unlike
* \ref initImage, calling this is optional.
* \param [in] buffer The buffer to initialize
* \param [in] data Initial data buffer
*/
void initBuffer(
const Rc<DxvkBuffer>& buffer,
const Rc<DxvkDataBuffer>& data);
/**
* \brief Initializes an image
* \brief Initializes or invalidates an image
*
* Sets up the image layout for future operations
* and uploads data to the image. Note that this
* method \e must be executed on the GPU before
* the image can be used for any other operations.
* while discarding any previous contents.
* \param [in] image The image to initialize
* \param [in] data Initial data. Can be omitted.
* \param [in] subresources Image subresources
*/
void initImage(
const Rc<DxvkImage>& image,
const Rc<DxvkDataBuffer>& data);
const Rc<DxvkImage>& image,
const VkImageSubresourceRange& subresources);
/**
* \brief Sets viewports
@ -336,6 +321,12 @@ namespace dxvk {
void commitComputeBarriers();
void transformLayoutsRenderPassBegin(
const DxvkRenderTargets& renderTargets);
void transformLayoutsRenderPassEnd(
const DxvkRenderTargets& renderTargets);
DxvkShaderResourceSlots* getShaderResourceSlots(
VkPipelineBindPoint pipe);

View File

@ -170,6 +170,14 @@ namespace dxvk {
return m_info;
}
/**
* \brief Image properties
* \returns Image properties
*/
const DxvkImageCreateInfo& imageInfo() const {
return m_image->info();
}
/**
* \brief Image
* \returns Image
@ -178,14 +186,6 @@ namespace dxvk {
return m_image;
}
/**
* \brief Image layout
* \returns Image layout
*/
VkImageLayout imageLayout() const {
return m_image->info().layout;
}
/**
* \brief Subresource range
* \returns Subresource range

View File

@ -40,9 +40,7 @@ namespace dxvk {
DxvkRenderPass::DxvkRenderPass(
const Rc<vk::DeviceFn>& vkd,
const DxvkRenderPassFormat& fmt,
VkImageLayout initialLayout,
VkImageLayout finalLayout)
const DxvkRenderPassFormat& fmt)
: m_vkd(vkd), m_format(fmt) {
std::vector<VkAttachmentDescription> attachments;
@ -51,23 +49,17 @@ namespace dxvk {
// Render passes may not require the previous
// contents of the attachments to be preserved.
VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
VkAttachmentStoreOp storeOp = VK_ATTACHMENT_STORE_OP_STORE;
if (initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
if (fmt.getDepthFormat() != VK_FORMAT_UNDEFINED) {
VkAttachmentDescription desc;
desc.flags = 0;
desc.format = fmt.getDepthFormat();
desc.samples = fmt.getSampleCount();
desc.loadOp = loadOp;
desc.storeOp = storeOp;
desc.stencilLoadOp = loadOp;
desc.stencilStoreOp = storeOp;
desc.initialLayout = initialLayout;
desc.finalLayout = finalLayout;
desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
desc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
desc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthRef.attachment = attachments.size();
depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
@ -81,15 +73,15 @@ namespace dxvk {
if (fmt.getColorFormat(i) != VK_FORMAT_UNDEFINED) {
VkAttachmentDescription desc;
desc.flags = 0;
desc.format = fmt.getColorFormat(i);
desc.samples = fmt.getSampleCount();
desc.loadOp = loadOp;
desc.storeOp = storeOp;
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc.initialLayout = initialLayout;
desc.finalLayout = finalLayout;
desc.flags = 0;
desc.format = fmt.getColorFormat(i);
desc.samples = fmt.getSampleCount();
desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
desc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorRef.at(i).attachment = attachments.size();
colorRef.at(i).layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@ -160,9 +152,7 @@ namespace dxvk {
Rc<DxvkRenderPass> DxvkRenderPassPool::createRenderPass(
const DxvkRenderPassFormat& fmt) {
return new DxvkRenderPass(m_vkd, fmt,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_GENERAL);
return new DxvkRenderPass(m_vkd, fmt);
}
}

View File

@ -110,9 +110,7 @@ namespace dxvk {
DxvkRenderPass(
const Rc<vk::DeviceFn>& vkd,
const DxvkRenderPassFormat& fmt,
VkImageLayout initialLayout,
VkImageLayout finalLayout);
const DxvkRenderPassFormat& fmt);
~DxvkRenderPass();
/**

View File

@ -129,9 +129,7 @@ namespace dxvk {
renderTargetFormat.setColorFormat(0, fmt.format);
m_renderPass = new DxvkRenderPass(
m_vkd, renderTargetFormat,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
m_vkd, renderTargetFormat);
// Retrieve swap images
auto swapImages = this->retrieveSwapImages();
@ -152,7 +150,7 @@ namespace dxvk {
imageInfo.access = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
| VK_ACCESS_MEMORY_READ_BIT;
imageInfo.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
DxvkImageViewCreateInfo viewInfo;
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;