mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 19:54:19 +01:00
[dxvk,d3d11] Refactor uploadImage to consume a staging buffer
And also handle format differences.
This commit is contained in:
parent
34e0f6952b
commit
725a04b954
@ -130,6 +130,7 @@ namespace dxvk {
|
||||
const D3D11_SUBRESOURCE_DATA* pInitialData) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
// Image migt be null if this is a staging resource
|
||||
Rc<DxvkImage> image = pTexture->GetImage();
|
||||
|
||||
auto mapMode = pTexture->GetMapMode();
|
||||
@ -139,52 +140,54 @@ namespace dxvk {
|
||||
auto formatInfo = lookupFormatInfo(packedFormat);
|
||||
|
||||
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
|
||||
// pInitialData is an array that stores an entry for
|
||||
// every single subresource. Since we will define all
|
||||
// subresources, this counts as initialization.
|
||||
for (uint32_t layer = 0; layer < desc->ArraySize; layer++) {
|
||||
for (uint32_t level = 0; level < desc->MipLevels; level++) {
|
||||
const uint32_t id = D3D11CalcSubresource(
|
||||
level, layer, desc->MipLevels);
|
||||
// Compute data size for all subresources and allocate staging buffer memory
|
||||
DxvkBufferSlice stagingSlice;
|
||||
|
||||
VkOffset3D mipLevelOffset = { 0, 0, 0 };
|
||||
VkExtent3D mipLevelExtent = pTexture->MipLevelExtent(level);
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
|
||||
VkDeviceSize dataSize = 0u;
|
||||
|
||||
for (uint32_t mip = 0; mip < image->info().mipLevels; mip++) {
|
||||
dataSize += image->info().numLayers * util::computeImageDataSize(
|
||||
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask);
|
||||
}
|
||||
|
||||
stagingSlice = m_stagingBuffer.alloc(dataSize);
|
||||
}
|
||||
|
||||
// Copy initial data for each subresource into the staging buffer,
|
||||
// as well as the mapped per-subresource buffers if available.
|
||||
VkDeviceSize dataOffset = 0u;
|
||||
|
||||
for (uint32_t mip = 0; mip < desc->MipLevels; mip++) {
|
||||
for (uint32_t layer = 0; layer < desc->ArraySize; layer++) {
|
||||
uint32_t index = D3D11CalcSubresource(mip, layer, desc->MipLevels);
|
||||
VkExtent3D mipLevelExtent = pTexture->MipLevelExtent(mip);
|
||||
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
|
||||
VkDeviceSize mipSizePerLayer = util::computeImageDataSize(
|
||||
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask);
|
||||
|
||||
m_transferCommands += 1;
|
||||
m_transferMemory += pTexture->GetSubresourceLayout(formatInfo->aspectMask, id).Size;
|
||||
|
||||
VkImageSubresourceLayers subresourceLayers;
|
||||
subresourceLayers.aspectMask = formatInfo->aspectMask;
|
||||
subresourceLayers.mipLevel = level;
|
||||
subresourceLayers.baseArrayLayer = layer;
|
||||
subresourceLayers.layerCount = 1;
|
||||
|
||||
if (formatInfo->aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
m_context->uploadImage(
|
||||
image, subresourceLayers,
|
||||
pInitialData[id].pSysMem,
|
||||
pInitialData[id].SysMemPitch,
|
||||
pInitialData[id].SysMemSlicePitch);
|
||||
} else {
|
||||
m_context->updateDepthStencilImage(
|
||||
image, subresourceLayers,
|
||||
VkOffset2D { mipLevelOffset.x, mipLevelOffset.y },
|
||||
VkExtent2D { mipLevelExtent.width, mipLevelExtent.height },
|
||||
pInitialData[id].pSysMem,
|
||||
pInitialData[id].SysMemPitch,
|
||||
pInitialData[id].SysMemSlicePitch,
|
||||
packedFormat);
|
||||
}
|
||||
m_transferMemory += mipSizePerLayer;
|
||||
|
||||
util::packImageData(stagingSlice.mapPtr(dataOffset),
|
||||
pInitialData[index].pSysMem, pInitialData[index].SysMemPitch, pInitialData[index].SysMemSlicePitch,
|
||||
0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask);
|
||||
|
||||
dataOffset += mipSizePerLayer;
|
||||
}
|
||||
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
|
||||
util::packImageData(pTexture->GetMappedBuffer(id)->mapPtr(0),
|
||||
pInitialData[id].pSysMem, pInitialData[id].SysMemPitch, pInitialData[id].SysMemSlicePitch,
|
||||
util::packImageData(pTexture->GetMappedBuffer(index)->mapPtr(0),
|
||||
pInitialData[index].pSysMem, pInitialData[index].SysMemPitch, pInitialData[index].SysMemSlicePitch,
|
||||
0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Upload all subresources of the image in one go
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING)
|
||||
m_context->uploadImage(image, stagingSlice.buffer(), stagingSlice.offset(), packedFormat);
|
||||
} else {
|
||||
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
|
||||
m_transferCommands += 1;
|
||||
|
@ -973,7 +973,14 @@ namespace dxvk {
|
||||
m_vkd->vkCmdSetStencilReference(m_cmd.execBuffer,
|
||||
faceMask, reference);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void cmdSetStencilWriteMask(
|
||||
VkStencilFaceFlags faceMask,
|
||||
uint32_t writeMask) {
|
||||
m_vkd->vkCmdSetStencilWriteMask(m_cmd.execBuffer, faceMask, writeMask);
|
||||
}
|
||||
|
||||
|
||||
void cmdSetViewport(
|
||||
uint32_t viewportCount,
|
||||
|
@ -2496,45 +2496,6 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::updateDepthStencilImage(
|
||||
const Rc<DxvkImage>& image,
|
||||
const VkImageSubresourceLayers& subresources,
|
||||
VkOffset2D imageOffset,
|
||||
VkExtent2D imageExtent,
|
||||
const void* data,
|
||||
VkDeviceSize pitchPerRow,
|
||||
VkDeviceSize pitchPerLayer,
|
||||
VkFormat format) {
|
||||
auto formatInfo = lookupFormatInfo(format);
|
||||
|
||||
VkExtent3D extent3D;
|
||||
extent3D.width = imageExtent.width;
|
||||
extent3D.height = imageExtent.height;
|
||||
extent3D.depth = subresources.layerCount;
|
||||
|
||||
VkDeviceSize pixelCount = extent3D.width * extent3D.height * extent3D.depth;
|
||||
|
||||
DxvkBufferCreateInfo tmpBufferInfo;
|
||||
tmpBufferInfo.size = pixelCount * formatInfo->elementSize;
|
||||
tmpBufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
tmpBufferInfo.stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
tmpBufferInfo.access = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
auto tmpBuffer = m_device->createBuffer(tmpBufferInfo,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
util::packImageData(tmpBuffer->mapPtr(0), data,
|
||||
extent3D, formatInfo->elementSize,
|
||||
pitchPerRow, pitchPerLayer);
|
||||
|
||||
copyPackedBufferToDepthStencilImage(
|
||||
image, subresources, imageOffset, imageExtent,
|
||||
tmpBuffer, 0, VkOffset2D { 0, 0 }, imageExtent,
|
||||
format);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::uploadBuffer(
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
const Rc<DxvkBuffer>& source,
|
||||
@ -2579,60 +2540,19 @@ namespace dxvk {
|
||||
|
||||
void DxvkContext::uploadImage(
|
||||
const Rc<DxvkImage>& image,
|
||||
const VkImageSubresourceLayers& subresources,
|
||||
const void* data,
|
||||
VkDeviceSize pitchPerRow,
|
||||
VkDeviceSize pitchPerLayer) {
|
||||
VkOffset3D imageOffset = { 0, 0, 0 };
|
||||
VkExtent3D imageExtent = image->mipLevelExtent(subresources.mipLevel);
|
||||
const Rc<DxvkBuffer>& source,
|
||||
VkDeviceSize sourceOffset,
|
||||
VkFormat format) {
|
||||
// Always use framebuffer path for depth-stencil images since we know
|
||||
// they are writeable and can't use Vulkan transfer queues. Stencil
|
||||
// data is interleaved and needs to be decoded manually anyway.
|
||||
bool useFb = (format && format != image->info().format) ||
|
||||
(image->formatInfo()->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT));
|
||||
|
||||
DxvkCmdBuffer cmdBuffer = DxvkCmdBuffer::SdmaBuffer;
|
||||
DxvkBarrierSet* barriers = &m_sdmaAcquires;
|
||||
|
||||
if (subresources.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
cmdBuffer = DxvkCmdBuffer::InitBuffer;
|
||||
barriers = &m_initBarriers;
|
||||
}
|
||||
|
||||
// Discard previous subresource contents
|
||||
barriers->accessImage(image,
|
||||
vk::makeSubresourceRange(subresources),
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0,
|
||||
image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
|
||||
barriers->recordCommands(m_cmd);
|
||||
|
||||
this->copyImageHostData(cmdBuffer,
|
||||
image, subresources, imageOffset, imageExtent,
|
||||
data, pitchPerRow, pitchPerLayer);
|
||||
|
||||
// Transfer ownership to graphics queue
|
||||
if (cmdBuffer == DxvkCmdBuffer::SdmaBuffer) {
|
||||
m_sdmaBarriers.releaseImage(m_initBarriers,
|
||||
image, vk::makeSubresourceRange(subresources),
|
||||
m_device->queues().transfer.queueFamily,
|
||||
image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
m_device->queues().graphics.queueFamily,
|
||||
image->info().layout,
|
||||
image->info().stages,
|
||||
image->info().access);
|
||||
} else {
|
||||
barriers->accessImage(image,
|
||||
vk::makeSubresourceRange(subresources),
|
||||
image->pickLayout(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_cmd->trackResource<DxvkAccess::Write>(image);
|
||||
if (useFb)
|
||||
uploadImageFb(image, source, sourceOffset, format);
|
||||
else
|
||||
uploadImageHw(image, source, sourceOffset);
|
||||
}
|
||||
|
||||
|
||||
@ -3447,54 +3367,244 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::copyImageHostData(
|
||||
DxvkCmdBuffer cmd,
|
||||
void DxvkContext::copyBufferToImageFb(
|
||||
const Rc<DxvkImage>& image,
|
||||
const VkImageSubresourceLayers& imageSubresource,
|
||||
VkOffset3D imageOffset,
|
||||
VkExtent3D imageExtent,
|
||||
const void* hostData,
|
||||
VkDeviceSize rowPitch,
|
||||
VkDeviceSize slicePitch) {
|
||||
auto formatInfo = image->formatInfo();
|
||||
auto srcData = reinterpret_cast<const char*>(hostData);
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
VkDeviceSize bufferOffset,
|
||||
VkDeviceSize bufferRowAlignment,
|
||||
VkDeviceSize bufferSliceAlignment,
|
||||
VkFormat bufferFormat) {
|
||||
this->spillRenderPass(true);
|
||||
this->invalidateState();
|
||||
|
||||
for (uint32_t i = 0; i < imageSubresource.layerCount; i++) {
|
||||
auto layerData = srcData + i * slicePitch;
|
||||
this->prepareImage(image, vk::makeSubresourceRange(imageSubresource));
|
||||
|
||||
for (auto aspects = imageSubresource.aspectMask; aspects; ) {
|
||||
auto aspect = vk::getNextAspect(aspects);
|
||||
auto extent = imageExtent;
|
||||
if (m_execBarriers.isImageDirty(image, vk::makeSubresourceRange(imageSubresource), DxvkAccess::Write))
|
||||
m_execBarriers.recordCommands(m_cmd);
|
||||
|
||||
VkDeviceSize elementSize = formatInfo->elementSize;
|
||||
auto formatInfo = lookupFormatInfo(bufferFormat);
|
||||
|
||||
if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
|
||||
auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
|
||||
extent.width /= plane->blockSize.width;
|
||||
extent.height /= plane->blockSize.height;
|
||||
elementSize = plane->elementSize;
|
||||
}
|
||||
if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
|
||||
Logger::err(str::format("DxvkContext: Planar formats not supported for shader-based buffer to image copies"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto blockCount = util::computeBlockCount(extent, formatInfo->blockSize);
|
||||
auto stagingSlice = m_staging.alloc(elementSize * util::flattenImageExtent(blockCount));
|
||||
auto stagingHandle = stagingSlice.getSliceHandle();
|
||||
VkDeviceSize rowPitch = imageExtent.width * formatInfo->elementSize;
|
||||
|
||||
util::packImageData(stagingHandle.mapPtr, layerData,
|
||||
blockCount, elementSize, rowPitch, slicePitch);
|
||||
if (bufferRowAlignment > formatInfo->elementSize)
|
||||
rowPitch = bufferRowAlignment >= rowPitch ? bufferRowAlignment : align(rowPitch, bufferRowAlignment);
|
||||
|
||||
auto subresource = imageSubresource;
|
||||
subresource.aspectMask = aspect;
|
||||
VkDeviceSize slicePitch = imageExtent.height * rowPitch;
|
||||
|
||||
this->copyImageBufferData<true>(cmd,
|
||||
image, subresource, imageOffset, imageExtent,
|
||||
image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
|
||||
stagingHandle, 0, 0);
|
||||
if (bufferSliceAlignment > formatInfo->elementSize)
|
||||
slicePitch = bufferSliceAlignment >= slicePitch ? bufferSliceAlignment : align(slicePitch, bufferSliceAlignment);
|
||||
|
||||
layerData += blockCount.height * rowPitch;
|
||||
if ((rowPitch % formatInfo->elementSize) || (slicePitch % formatInfo->elementSize)) {
|
||||
Logger::err(str::format("DxvkContext: Pitches ", rowPitch, ",", slicePitch, " not a multiple of element size ", formatInfo->elementSize, " for format ", bufferFormat));
|
||||
return;
|
||||
}
|
||||
|
||||
m_cmd->trackResource<DxvkAccess::Read>(stagingSlice.buffer());
|
||||
// Create texel buffer view to read from
|
||||
DxvkBufferViewKey bufferViewInfo = { };
|
||||
bufferViewInfo.format = sanitizeTexelBufferFormat(bufferFormat);
|
||||
bufferViewInfo.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
|
||||
bufferViewInfo.offset = bufferOffset;
|
||||
bufferViewInfo.size = slicePitch * imageExtent.depth * imageSubresource.layerCount;
|
||||
|
||||
Rc<DxvkBufferView> bufferView = buffer->createView(bufferViewInfo);
|
||||
VkBufferView bufferViewHandle = bufferView->handle();
|
||||
|
||||
// Create image view to render to
|
||||
bool discard = image->isFullSubresource(imageSubresource, imageExtent);
|
||||
bool isDepthStencil = imageSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
|
||||
DxvkImageViewKey imageViewInfo = { };
|
||||
imageViewInfo.viewType = image->info().type == VK_IMAGE_TYPE_1D
|
||||
? VK_IMAGE_VIEW_TYPE_1D_ARRAY
|
||||
: VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
imageViewInfo.format = image->info().format;
|
||||
imageViewInfo.usage = isDepthStencil
|
||||
? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
: VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
imageViewInfo.aspects = image->formatInfo()->aspectMask;
|
||||
imageViewInfo.mipIndex = imageSubresource.mipLevel;
|
||||
imageViewInfo.mipCount = 1u;
|
||||
imageViewInfo.layerIndex = imageSubresource.baseArrayLayer;
|
||||
imageViewInfo.layerCount = imageSubresource.layerCount;
|
||||
|
||||
if (image->info().type == VK_IMAGE_TYPE_3D) {
|
||||
imageViewInfo.layerIndex = imageOffset.z;
|
||||
imageViewInfo.layerCount = imageExtent.depth;
|
||||
}
|
||||
|
||||
Rc<DxvkImageView> imageView = image->createView(imageViewInfo);
|
||||
|
||||
// Transition image to required layout and discard if possible
|
||||
VkImageLayout imageLayout = isDepthStencil
|
||||
? image->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
|
||||
: image->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
VkPipelineStageFlags stages = isDepthStencil
|
||||
? VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
|
||||
: VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
|
||||
VkAccessFlags access = isDepthStencil
|
||||
? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
|
||||
: VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
m_execAcquires.accessImage(image, vk::makeSubresourceRange(imageSubresource),
|
||||
discard ? VK_IMAGE_LAYOUT_UNDEFINED : image->info().layout,
|
||||
image->info().stages, image->info().access,
|
||||
imageLayout, stages, access);
|
||||
|
||||
m_execAcquires.recordCommands(m_cmd);
|
||||
|
||||
// Bind image for rendering
|
||||
VkRenderingAttachmentInfo attachment = { VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO };
|
||||
attachment.imageView = imageView->handle();
|
||||
attachment.imageLayout = imageLayout;
|
||||
attachment.loadOp = discard
|
||||
? VK_ATTACHMENT_LOAD_OP_DONT_CARE
|
||||
: VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
VkExtent3D mipExtent = imageView->mipLevelExtent(0u);
|
||||
|
||||
VkRenderingInfo renderingInfo = { VK_STRUCTURE_TYPE_RENDERING_INFO };
|
||||
renderingInfo.renderArea.extent = { mipExtent.width, mipExtent.height };
|
||||
renderingInfo.layerCount = imageViewInfo.layerCount;
|
||||
|
||||
if (image->formatInfo()->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
renderingInfo.colorAttachmentCount = 1;
|
||||
renderingInfo.pColorAttachments = &attachment;
|
||||
}
|
||||
|
||||
if (image->formatInfo()->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
|
||||
renderingInfo.pDepthAttachment = &attachment;
|
||||
|
||||
if (image->formatInfo()->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
|
||||
renderingInfo.pStencilAttachment = &attachment;
|
||||
|
||||
DxvkBufferSliceHandle bufferSlice = buffer->getSliceHandle(
|
||||
bufferOffset, slicePitch * renderingInfo.layerCount);
|
||||
|
||||
if (m_execBarriers.isBufferDirty(bufferSlice, DxvkAccess::Read))
|
||||
m_execBarriers.recordCommands(m_cmd);
|
||||
|
||||
m_cmd->cmdBeginRendering(&renderingInfo);
|
||||
|
||||
// Set up viewport and scissor state
|
||||
VkViewport viewport = { };
|
||||
viewport.x = imageOffset.x;
|
||||
viewport.y = imageOffset.y;
|
||||
viewport.width = imageExtent.width;
|
||||
viewport.height = imageExtent.height;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
m_cmd->cmdSetViewport(1, &viewport);
|
||||
|
||||
VkRect2D scissor = { };
|
||||
scissor.offset = { imageOffset.x, imageOffset.y };
|
||||
scissor.extent = { imageExtent.width, imageExtent.height };
|
||||
|
||||
m_cmd->cmdSetScissor(1, &scissor);
|
||||
|
||||
// Get pipeline and descriptor set layout. All pipelines
|
||||
// will be using the same pipeline layout here.
|
||||
bool needsBitwiseStencilCopy = !m_device->features().extShaderStencilExport
|
||||
&& (imageSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
|
||||
// If we have a depth aspect, this will give us either the depth-only
|
||||
// pipeline or one that can write all the given aspects
|
||||
DxvkMetaCopyPipeline pipeline = m_common->metaCopy().getCopyBufferToImagePipeline(
|
||||
image->info().format, bufferFormat, imageSubresource.aspectMask);
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
|
||||
descriptorWrite.dstSet = m_descriptorPool->alloc(pipeline.dsetLayout);
|
||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
|
||||
descriptorWrite.descriptorCount = 1;
|
||||
descriptorWrite.pTexelBufferView = &bufferViewHandle;
|
||||
|
||||
m_cmd->updateDescriptorSets(1, &descriptorWrite);
|
||||
|
||||
DxvkBufferImageCopyArgs pushConst = { };
|
||||
pushConst.imageOffset = imageOffset;
|
||||
pushConst.bufferOffset = 0u;
|
||||
pushConst.imageExtent = imageExtent;
|
||||
pushConst.bufferImageWidth = rowPitch / formatInfo->elementSize;
|
||||
pushConst.bufferImageHeight = slicePitch / rowPitch;
|
||||
|
||||
if (imageSubresource.aspectMask != VK_IMAGE_ASPECT_STENCIL_BIT || !needsBitwiseStencilCopy) {
|
||||
m_cmd->cmdBindPipeline(DxvkCmdBuffer::ExecBuffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeHandle);
|
||||
|
||||
m_cmd->cmdBindDescriptorSet(DxvkCmdBuffer::ExecBuffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeLayout,
|
||||
descriptorWrite.dstSet, 0, nullptr);
|
||||
|
||||
m_cmd->cmdPushConstants(DxvkCmdBuffer::ExecBuffer,
|
||||
pipeline.pipeLayout, VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
0, sizeof(pushConst), &pushConst);
|
||||
|
||||
m_cmd->cmdDraw(3, renderingInfo.layerCount, 0, 0);
|
||||
}
|
||||
|
||||
if (needsBitwiseStencilCopy) {
|
||||
// On systems that do not support stencil export, we need to clear
|
||||
// stencil to 0 and then "write" each individual bit by discarding
|
||||
// fragments where that bit is not set.
|
||||
pipeline = m_common->metaCopy().getCopyBufferToImagePipeline(
|
||||
image->info().format, bufferFormat, VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
|
||||
if (imageSubresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
|
||||
VkClearAttachment clear = { };
|
||||
clear.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
VkClearRect clearRect = { };
|
||||
clearRect.rect = scissor;
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = renderingInfo.layerCount;
|
||||
|
||||
m_cmd->cmdClearAttachments(1, &clear, 1, &clearRect);
|
||||
}
|
||||
|
||||
m_cmd->cmdBindPipeline(DxvkCmdBuffer::ExecBuffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeHandle);
|
||||
|
||||
m_cmd->cmdBindDescriptorSet(DxvkCmdBuffer::ExecBuffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeLayout,
|
||||
descriptorWrite.dstSet, 0, nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < 8; i++) {
|
||||
pushConst.stencilBitIndex = i;
|
||||
|
||||
m_cmd->cmdPushConstants(DxvkCmdBuffer::ExecBuffer,
|
||||
pipeline.pipeLayout, VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
0, sizeof(pushConst), &pushConst);
|
||||
|
||||
m_cmd->cmdSetStencilWriteMask(VK_STENCIL_FACE_FRONT_AND_BACK, 1u << i);
|
||||
m_cmd->cmdDraw(3, renderingInfo.layerCount, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
m_cmd->cmdEndRendering();
|
||||
|
||||
m_execBarriers.accessImage(image,
|
||||
vk::makeSubresourceRange(imageSubresource),
|
||||
imageLayout, stages, access,
|
||||
image->info().layout, image->info().stages, image->info().access);
|
||||
|
||||
m_execBarriers.accessBuffer(bufferSlice,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
buffer->info().stages,
|
||||
buffer->info().access);
|
||||
|
||||
m_cmd->trackResource<DxvkAccess::Write>(image);
|
||||
m_cmd->trackResource<DxvkAccess::Read>(buffer);
|
||||
}
|
||||
|
||||
|
||||
@ -4668,6 +4778,77 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::uploadImageFb(
|
||||
const Rc<DxvkImage>& image,
|
||||
const Rc<DxvkBuffer>& source,
|
||||
VkDeviceSize sourceOffset,
|
||||
VkFormat format) {
|
||||
if (!format)
|
||||
format = image->info().format;
|
||||
|
||||
for (uint32_t i = 0; i < image->info().mipLevels; i++) {
|
||||
VkExtent3D mipExtent = image->mipLevelExtent(i);
|
||||
|
||||
copyBufferToImageFb(image,
|
||||
vk::pickSubresourceLayers(image->getAvailableSubresources(), i),
|
||||
VkOffset3D { 0, 0, 0 }, mipExtent,
|
||||
source, sourceOffset, 0, 0, format);
|
||||
|
||||
sourceOffset += image->info().numLayers * util::computeImageDataSize(
|
||||
format, mipExtent, image->formatInfo()->aspectMask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::uploadImageHw(
|
||||
const Rc<DxvkImage>& image,
|
||||
const Rc<DxvkBuffer>& source,
|
||||
VkDeviceSize sourceOffset) {
|
||||
// Initialize all subresources of the image at once
|
||||
VkImageLayout transferLayout = image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
m_sdmaAcquires.accessImage(image,
|
||||
image->getAvailableSubresources(),
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, 0, 0,
|
||||
transferLayout,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
|
||||
m_sdmaAcquires.recordCommands(m_cmd);
|
||||
|
||||
// Copy image data, one mip at a time
|
||||
VkDeviceSize dataOffset = sourceOffset;
|
||||
|
||||
for (uint32_t i = 0; i < image->info().mipLevels; i++) {
|
||||
VkExtent3D mipExtent = image->mipLevelExtent(i);
|
||||
|
||||
VkDeviceSize mipSize = image->info().numLayers * util::computeImageDataSize(
|
||||
image->info().format, mipExtent, image->formatInfo()->aspectMask);
|
||||
|
||||
copyImageBufferData<true>(DxvkCmdBuffer::SdmaBuffer,
|
||||
image, vk::pickSubresourceLayers(image->getAvailableSubresources(), i),
|
||||
VkOffset3D { 0, 0, 0 }, mipExtent, transferLayout,
|
||||
source->getSliceHandle(dataOffset, mipSize), 0, 0);
|
||||
|
||||
dataOffset += mipSize;
|
||||
}
|
||||
|
||||
m_sdmaBarriers.releaseImage(m_initBarriers,
|
||||
image, image->getAvailableSubresources(),
|
||||
m_device->queues().transfer.queueFamily,
|
||||
transferLayout,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
m_device->queues().graphics.queueFamily,
|
||||
image->info().layout,
|
||||
image->info().stages,
|
||||
image->info().access);
|
||||
|
||||
m_cmd->trackResource<DxvkAccess::Read>(source);
|
||||
m_cmd->trackResource<DxvkAccess::Write>(image);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::startRenderPass() {
|
||||
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
||||
this->applyRenderTargetLoadLayouts();
|
||||
@ -6873,4 +7054,30 @@ namespace dxvk {
|
||||
this->beginCurrentCommands();
|
||||
}
|
||||
|
||||
|
||||
VkFormat DxvkContext::sanitizeTexelBufferFormat(
|
||||
VkFormat srcFormat) {
|
||||
switch (srcFormat) {
|
||||
case VK_FORMAT_S8_UINT:
|
||||
return VK_FORMAT_R8_UINT;
|
||||
|
||||
case VK_FORMAT_D16_UNORM:
|
||||
return VK_FORMAT_R16_UINT;
|
||||
|
||||
case VK_FORMAT_D16_UNORM_S8_UINT:
|
||||
return VK_FORMAT_R16G16_UINT;
|
||||
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
return VK_FORMAT_R32_UINT;
|
||||
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
return VK_FORMAT_R32G32_UINT;
|
||||
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1127,28 +1127,6 @@ namespace dxvk {
|
||||
VkDeviceSize size,
|
||||
const void* data);
|
||||
|
||||
/**
|
||||
* \brief Updates an depth-stencil image
|
||||
*
|
||||
* \param [in] image Destination image
|
||||
* \param [in] subsresources Image subresources to update
|
||||
* \param [in] imageOffset Offset of the image area to update
|
||||
* \param [in] imageExtent Size of the image area to update
|
||||
* \param [in] data Source data
|
||||
* \param [in] pitchPerRow Row pitch of the source data
|
||||
* \param [in] pitchPerLayer Layer pitch of the source data
|
||||
* \param [in] format Packed depth-stencil format
|
||||
*/
|
||||
void updateDepthStencilImage(
|
||||
const Rc<DxvkImage>& image,
|
||||
const VkImageSubresourceLayers& subresources,
|
||||
VkOffset2D imageOffset,
|
||||
VkExtent2D imageExtent,
|
||||
const void* data,
|
||||
VkDeviceSize pitchPerRow,
|
||||
VkDeviceSize pitchPerLayer,
|
||||
VkFormat format);
|
||||
|
||||
/**
|
||||
* \brief Uses transfer queue to initialize buffer
|
||||
*
|
||||
@ -1166,20 +1144,22 @@ namespace dxvk {
|
||||
/**
|
||||
* \brief Uses transfer queue to initialize image
|
||||
*
|
||||
* Only safe to use if the image is not in use by the GPU.
|
||||
* Only safe to use if the image is not in use by the GPU. Data is
|
||||
* assumed to be tightly packed, with all layers of the top-level mip
|
||||
* stored first, then the next mip etc. If the given format does not
|
||||
* match the image format and is not \c VK_FORMAT_UNDEFINED, the data
|
||||
* will be converted to the image format before performing the upload.
|
||||
* \param [in] image The image to initialize
|
||||
* \param [in] subresources Subresources to initialize
|
||||
* \param [in] data Source data
|
||||
* \param [in] pitchPerRow Row pitch of the source data
|
||||
* \param [in] pitchPerLayer Layer pitch of the source data
|
||||
* \param [in] source Staging buffer containing data
|
||||
* \param [in] sourceOffset Offset into staging buffer
|
||||
* \param [in] format Actual data format
|
||||
*/
|
||||
void uploadImage(
|
||||
const Rc<DxvkImage>& image,
|
||||
const VkImageSubresourceLayers& subresources,
|
||||
const void* data,
|
||||
VkDeviceSize pitchPerRow,
|
||||
VkDeviceSize pitchPerLayer);
|
||||
|
||||
const Rc<DxvkBuffer>& source,
|
||||
VkDeviceSize sourceOffset,
|
||||
VkFormat format);
|
||||
|
||||
/**
|
||||
* \brief Sets viewports
|
||||
*
|
||||
@ -1529,15 +1509,16 @@ namespace dxvk {
|
||||
VkDeviceSize bufferRowAlignment,
|
||||
VkDeviceSize bufferSliceAlignment);
|
||||
|
||||
void copyImageHostData(
|
||||
DxvkCmdBuffer cmd,
|
||||
void copyBufferToImageFb(
|
||||
const Rc<DxvkImage>& image,
|
||||
const VkImageSubresourceLayers& imageSubresource,
|
||||
VkOffset3D imageOffset,
|
||||
VkExtent3D imageExtent,
|
||||
const void* hostData,
|
||||
VkDeviceSize rowPitch,
|
||||
VkDeviceSize slicePitch);
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
VkDeviceSize bufferOffset,
|
||||
VkDeviceSize bufferRowAlignment,
|
||||
VkDeviceSize bufferSliceAlignment,
|
||||
VkFormat bufferFormat);
|
||||
|
||||
void clearImageViewFb(
|
||||
const Rc<DxvkImageView>& imageView,
|
||||
@ -1621,7 +1602,18 @@ namespace dxvk {
|
||||
VkFormat format,
|
||||
VkResolveModeFlagBits depthMode,
|
||||
VkResolveModeFlagBits stencilMode);
|
||||
|
||||
|
||||
void uploadImageFb(
|
||||
const Rc<DxvkImage>& image,
|
||||
const Rc<DxvkBuffer>& source,
|
||||
VkDeviceSize sourceOffset,
|
||||
VkFormat format);
|
||||
|
||||
void uploadImageHw(
|
||||
const Rc<DxvkImage>& image,
|
||||
const Rc<DxvkBuffer>& source,
|
||||
VkDeviceSize sourceOffset);
|
||||
|
||||
void performClear(
|
||||
const Rc<DxvkImageView>& imageView,
|
||||
int32_t attachmentIndex,
|
||||
@ -1768,7 +1760,7 @@ namespace dxvk {
|
||||
VkAccessFlags srcAccess,
|
||||
VkPipelineStageFlags dstStages,
|
||||
VkAccessFlags dstAccess);
|
||||
|
||||
|
||||
void trackDrawBuffer();
|
||||
|
||||
bool tryInvalidateDeviceLocalBuffer(
|
||||
@ -1806,6 +1798,9 @@ namespace dxvk {
|
||||
|
||||
void splitCommands();
|
||||
|
||||
static VkFormat sanitizeTexelBufferFormat(
|
||||
VkFormat srcFormat);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -175,14 +175,12 @@ namespace dxvk {
|
||||
|
||||
|
||||
DxvkMetaCopyPipeline DxvkMetaCopyObjects::getCopyBufferToImagePipeline(
|
||||
VkImageViewType viewType,
|
||||
VkFormat dstFormat,
|
||||
VkFormat srcFormat,
|
||||
VkImageAspectFlags aspects) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
DxvkMetaBufferImageCopyPipelineKey key;
|
||||
key.imageViewType = viewType;
|
||||
key.imageFormat = dstFormat;
|
||||
key.bufferFormat = srcFormat;
|
||||
key.imageAspects = aspects;
|
||||
|
@ -169,13 +169,11 @@ namespace dxvk {
|
||||
*
|
||||
* Note that setting both depth and stencil aspects
|
||||
* requires device support for depth-stencil export.
|
||||
* \param [in] viewType Image view type
|
||||
* \param [in] dstFormat Destionation image format
|
||||
* \param [in] srcFormat Source buffer data format
|
||||
* \param [in] aspects Aspect mask to copy
|
||||
*/
|
||||
DxvkMetaCopyPipeline getCopyBufferToImagePipeline(
|
||||
VkImageViewType viewType,
|
||||
VkFormat dstFormat,
|
||||
VkFormat srcFormat,
|
||||
VkImageAspectFlags aspects);
|
||||
|
Loading…
x
Reference in New Issue
Block a user