1
0
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:
Philip Rebohle 2024-10-05 10:07:03 +02:00 committed by Philip Rebohle
parent 34e0f6952b
commit 725a04b954
6 changed files with 411 additions and 203 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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;
}
}
}

View File

@ -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);
};
}

View File

@ -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;

View File

@ -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);