diff --git a/src/d3d9/d3d9_common_texture.cpp b/src/d3d9/d3d9_common_texture.cpp index d415dac0e..8bb5f99ab 100644 --- a/src/d3d9/d3d9_common_texture.cpp +++ b/src/d3d9/d3d9_common_texture.cpp @@ -331,6 +331,7 @@ namespace dxvk { if (m_mapping.ConversionFormatInfo.FormatType != D3D9ConversionFormat_None) { imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT; imageInfo.stages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + imageInfo.shared = true; } DecodeMultiSampleType(m_device->GetDXVKDevice(), m_desc.MultiSample, m_desc.MultisampleQuality, &imageInfo.sampleCount); diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index cdbe8055d..17dcc7c3a 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -5055,13 +5055,17 @@ namespace dxvk { slice.mapPtr, mapPtr, srcBlockCount, formatElementSize, pitch, std::min(pSrcTexture->GetPlaneCount(), 2u) * pitch * srcBlockCount.height); - Flush(); - SynchronizeCsThread(DxvkCsThread::SynchronizeAll); + EmitCs([this, + cConvertFormat = convertFormat, + cDstImage = std::move(image), + cDstLayers = convertedDstLayers, + cSrcSlice = std::move(slice.slice) + ] (DxvkContext* ctx) { + auto contextObjects = ctx->beginExternalRendering(); - m_converter->ConvertFormat( - convertFormat, - image, convertedDstLayers, - slice.slice); + m_converter->ConvertFormat(contextObjects, + cConvertFormat, cDstImage, cDstLayers, cSrcSlice); + }); } UnmapTextures(); ConsiderFlush(GpuFlushType::ImplicitWeakHint); @@ -5848,8 +5852,6 @@ namespace dxvk { if constexpr (Synchronize9On12) m_submitStatus.result = VK_NOT_READY; - m_converter->Flush(); - // Update signaled staging buffer counter and signal the fence m_stagingMemorySignaled = m_stagingBuffer.getStatistics().allocatedTotal; diff --git a/src/d3d9/d3d9_format_helpers.cpp b/src/d3d9/d3d9_format_helpers.cpp index 6f3a69521..765e48a23 100644 --- a/src/d3d9/d3d9_format_helpers.cpp +++ b/src/d3d9/d3d9_format_helpers.cpp @@ -11,21 +11,23 @@ namespace dxvk { D3D9FormatHelper::D3D9FormatHelper(const Rc& device) - : m_device(device), m_context(m_device->createContext(DxvkContextType::Supplementary)) { - m_context->beginRecording( - m_device->createCommandList()); - - InitShaders(); + : m_device (device) + , m_setLayout (CreateSetLayout()) + , m_pipelineLayout (CreatePipelineLayout()) { + InitPipelines(); } - void D3D9FormatHelper::Flush() { - if (m_transferCommands != 0) - FlushInternal(); + D3D9FormatHelper::~D3D9FormatHelper() { + auto vk = m_device->vkd(); + + for (auto& p : m_pipelines) + vk->vkDestroyPipeline(vk->device(), p, nullptr); } void D3D9FormatHelper::ConvertFormat( + const DxvkContextObjects& ctx, D3D9_CONVERSION_FORMAT_INFO conversionFormat, const Rc& dstImage, VkImageSubresourceLayers dstSubresource, @@ -33,33 +35,32 @@ namespace dxvk { switch (conversionFormat.FormatType) { case D3D9ConversionFormat_YUY2: case D3D9ConversionFormat_UYVY: { - uint32_t specConstant = conversionFormat.FormatType == D3D9ConversionFormat_UYVY ? 1 : 0; - ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, specConstant, { 2u, 1u }); + ConvertGenericFormat(ctx, conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, { 2u, 1u }); break; } case D3D9ConversionFormat_NV12: - ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R16_UINT, 0, { 2u, 1u }); + ConvertGenericFormat(ctx, conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R16_UINT, { 2u, 1u }); break; case D3D9ConversionFormat_YV12: - ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R8_UINT, 0, { 1u, 1u }); + ConvertGenericFormat(ctx, conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R8_UINT, { 1u, 1u }); break; case D3D9ConversionFormat_L6V5U5: - ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R16_UINT, 0, { 1u, 1u }); + ConvertGenericFormat(ctx, conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R16_UINT, { 1u, 1u }); break; case D3D9ConversionFormat_X8L8V8U8: - ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, 0, { 1u, 1u }); + ConvertGenericFormat(ctx, conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, { 1u, 1u }); break; case D3D9ConversionFormat_A2W10V10U10: - ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, 0, { 1u, 1u }); + ConvertGenericFormat(ctx, conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, { 1u, 1u }); break; case D3D9ConversionFormat_W11V11U10: - ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, 0, { 1u, 1u }); + ConvertGenericFormat(ctx, conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, { 1u, 1u }); break; default: @@ -69,12 +70,12 @@ namespace dxvk { void D3D9FormatHelper::ConvertGenericFormat( + const DxvkContextObjects& ctx, D3D9_CONVERSION_FORMAT_INFO videoFormat, const Rc& dstImage, VkImageSubresourceLayers dstSubresource, const DxvkBufferSlice& srcSlice, VkFormat bufferFormat, - uint32_t specConstantValue, VkExtent2D macroPixelRun) { DxvkImageViewKey imageViewInfo; imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; @@ -99,53 +100,156 @@ namespace dxvk { bufferViewInfo.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; auto tmpBufferView = srcSlice.buffer()->createView(bufferViewInfo); - m_context->setSpecConstant(VK_PIPELINE_BIND_POINT_COMPUTE, 0, specConstantValue); - m_context->bindResourceImageView(VK_SHADER_STAGE_COMPUTE_BIT, BindingIds::Image, std::move(tmpImageView)); - m_context->bindResourceBufferView(VK_SHADER_STAGE_COMPUTE_BIT, BindingIds::Buffer, std::move(tmpBufferView)); - m_context->bindShader(Rc(m_shaders[videoFormat.FormatType])); - m_context->pushConstants(0, sizeof(VkExtent2D), &imageExtent); - m_context->dispatch( - (imageExtent.width / 8) + (imageExtent.width % 8), - (imageExtent.height / 8) + (imageExtent.height % 8), - 1); + VkDescriptorSet set = ctx.descriptorPool->alloc(m_setLayout); - m_transferCommands += 1; + VkDescriptorImageInfo imageDescriptor = { }; + imageDescriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageDescriptor.imageView = tmpImageView->handle(); + + VkBufferView bufferViewHandle = tmpBufferView->handle(); + + std::array descriptorWrites = {{ + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, + set, 0, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageDescriptor }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, + set, 1, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, nullptr, nullptr, &bufferViewHandle }, + }}; + + ctx.cmd->updateDescriptorSets( + descriptorWrites.size(), + descriptorWrites.data()); + + ctx.cmd->cmdBindPipeline(DxvkCmdBuffer::ExecBuffer, + VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelines[videoFormat.FormatType]); + ctx.cmd->cmdBindDescriptorSet(DxvkCmdBuffer::ExecBuffer, + VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, set, 0, nullptr); + ctx.cmd->cmdPushConstants(DxvkCmdBuffer::ExecBuffer, m_pipelineLayout, + VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(VkExtent2D), &imageExtent); + ctx.cmd->cmdDispatch(DxvkCmdBuffer::ExecBuffer, + ((imageExtent.width + 7u) / 8u), + ((imageExtent.height + 7u) / 8u), + 1u); + + // We can reasonably assume that the image is in GENERAL layout anyway + VkMemoryBarrier2 memoryBarrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 }; + memoryBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + memoryBarrier.srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT; + memoryBarrier.dstStageMask = dstImage->info().stages | srcSlice.buffer()->info().stages; + memoryBarrier.dstAccessMask = dstImage->info().access | srcSlice.buffer()->info().access; + + VkDependencyInfo depInfo = { VK_STRUCTURE_TYPE_DEPENDENCY_INFO }; + depInfo.memoryBarrierCount = 1u; + depInfo.pMemoryBarriers = &memoryBarrier; + + ctx.cmd->cmdPipelineBarrier(DxvkCmdBuffer::ExecBuffer, &depInfo); + + ctx.cmd->track(tmpImageView->image(), DxvkAccess::Write); + ctx.cmd->track(tmpBufferView->buffer(), DxvkAccess::Read); } - void D3D9FormatHelper::InitShaders() { - m_shaders[D3D9ConversionFormat_YUY2] = InitShader(d3d9_convert_yuy2_uyvy); - m_shaders[D3D9ConversionFormat_UYVY] = m_shaders[D3D9ConversionFormat_YUY2]; - m_shaders[D3D9ConversionFormat_L6V5U5] = InitShader(d3d9_convert_l6v5u5); - m_shaders[D3D9ConversionFormat_X8L8V8U8] = InitShader(d3d9_convert_x8l8v8u8); - m_shaders[D3D9ConversionFormat_A2W10V10U10] = InitShader(d3d9_convert_a2w10v10u10); - m_shaders[D3D9ConversionFormat_W11V11U10] = InitShader(d3d9_convert_w11v11u10); - m_shaders[D3D9ConversionFormat_NV12] = InitShader(d3d9_convert_nv12); - m_shaders[D3D9ConversionFormat_YV12] = InitShader(d3d9_convert_yv12); + void D3D9FormatHelper::InitPipelines() { + m_pipelines[D3D9ConversionFormat_YUY2] = CreatePipeline(sizeof(d3d9_convert_yuy2_uyvy), d3d9_convert_yuy2_uyvy, 0); + m_pipelines[D3D9ConversionFormat_UYVY] = CreatePipeline(sizeof(d3d9_convert_yuy2_uyvy), d3d9_convert_yuy2_uyvy, 1); + m_pipelines[D3D9ConversionFormat_L6V5U5] = CreatePipeline(sizeof(d3d9_convert_l6v5u5), d3d9_convert_l6v5u5, 0); + m_pipelines[D3D9ConversionFormat_X8L8V8U8] = CreatePipeline(sizeof(d3d9_convert_x8l8v8u8), d3d9_convert_x8l8v8u8, 0); + m_pipelines[D3D9ConversionFormat_A2W10V10U10] = CreatePipeline(sizeof(d3d9_convert_a2w10v10u10), d3d9_convert_a2w10v10u10, 0); + m_pipelines[D3D9ConversionFormat_W11V11U10] = CreatePipeline(sizeof(d3d9_convert_w11v11u10), d3d9_convert_w11v11u10, 0); + m_pipelines[D3D9ConversionFormat_NV12] = CreatePipeline(sizeof(d3d9_convert_nv12), d3d9_convert_nv12, 0); + m_pipelines[D3D9ConversionFormat_YV12] = CreatePipeline(sizeof(d3d9_convert_yv12), d3d9_convert_yv12, 0); } - Rc D3D9FormatHelper::InitShader(SpirvCodeBuffer code) { - const std::array bindings = { { - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, BindingIds::Image, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_COMPUTE_BIT, VK_ACCESS_SHADER_WRITE_BIT }, - { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, BindingIds::Buffer, VK_IMAGE_VIEW_TYPE_1D, VK_SHADER_STAGE_COMPUTE_BIT, VK_ACCESS_SHADER_READ_BIT }, - } }; + VkDescriptorSetLayout D3D9FormatHelper::CreateSetLayout() { + auto vk = m_device->vkd(); - DxvkShaderCreateInfo info; - info.stage = VK_SHADER_STAGE_COMPUTE_BIT; + static const std::array bindings = {{ + { 0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT }, + { 1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT }, + }}; + + VkDescriptorSetLayoutCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; info.bindingCount = bindings.size(); - info.bindings = bindings.data(); - info.pushConstStages = VK_SHADER_STAGE_COMPUTE_BIT; - info.pushConstSize = sizeof(VkExtent2D); + info.pBindings = bindings.data(); - return new DxvkShader(info, std::move(code)); + VkDescriptorSetLayout layout = VK_NULL_HANDLE; + VkResult vr = vk->vkCreateDescriptorSetLayout(vk->device(), &info, nullptr, &layout); + + if (vr != VK_SUCCESS) + throw DxvkError(str::format("Failed to create format conversion descriptor set layout: ", vr)); + + return layout; } - void D3D9FormatHelper::FlushInternal() { - m_context->flushCommandList(nullptr); - - m_transferCommands = 0; + VkPipelineLayout D3D9FormatHelper::CreatePipelineLayout() { + auto vk = m_device->vkd(); + + VkPushConstantRange pushConstants = { }; + pushConstants.size = sizeof(VkExtent2D); + pushConstants.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + + VkPipelineLayoutCreateInfo info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + info.setLayoutCount = 1u; + info.pSetLayouts = &m_setLayout; + info.pushConstantRangeCount = 1u; + info.pPushConstantRanges = &pushConstants; + + VkPipelineLayout layout = VK_NULL_HANDLE; + VkResult vr = vk->vkCreatePipelineLayout(vk->device(), &info, nullptr, &layout); + + if (vr != VK_SUCCESS) + throw DxvkError(str::format("Failed to create format conversion pipeline layout: ", vr)); + + return layout; + } + + + VkPipeline D3D9FormatHelper::CreatePipeline(size_t size, const uint32_t* code, uint32_t specConstant) { + auto vk = m_device->vkd(); + + VkSpecializationMapEntry specEntry = { }; + specEntry.size = sizeof(specConstant); + + VkSpecializationInfo specInfo = { }; + specInfo.mapEntryCount = 1; + specInfo.pMapEntries = &specEntry; + specInfo.dataSize = sizeof(specConstant); + specInfo.pData = &specConstant; + + VkComputePipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; + pipelineInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + pipelineInfo.stage.pName = "main"; + pipelineInfo.stage.pSpecializationInfo = &specInfo; + pipelineInfo.layout = m_pipelineLayout; + pipelineInfo.basePipelineIndex = -1; + + VkShaderModuleCreateInfo moduleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; + moduleInfo.codeSize = size; + moduleInfo.pCode = code; + + if (m_device->features().khrMaintenance5.maintenance5 + || m_device->features().extGraphicsPipelineLibrary.graphicsPipelineLibrary) { + pipelineInfo.stage.pNext = &moduleInfo; + } else { + VkResult vr = vk->vkCreateShaderModule(vk->device(), + &moduleInfo, nullptr, &pipelineInfo.stage.module); + + if (vr != VK_SUCCESS) + throw DxvkError(str::format("Failed to create format conversion shader module: ", vr)); + } + + VkPipeline pipeline = VK_NULL_HANDLE; + VkResult vr = vk->vkCreateComputePipelines(vk->device(), + VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline); + + vk->vkDestroyShaderModule(vk->device(), pipelineInfo.stage.module, nullptr); + + if (vr != VK_SUCCESS) + throw DxvkError(str::format("Failed to create format conversion pipeline: ", vr)); + + return pipeline; } } \ No newline at end of file diff --git a/src/d3d9/d3d9_format_helpers.h b/src/d3d9/d3d9_format_helpers.h index 16348eda2..5c3f70624 100644 --- a/src/d3d9/d3d9_format_helpers.h +++ b/src/d3d9/d3d9_format_helpers.h @@ -13,9 +13,12 @@ namespace dxvk { D3D9FormatHelper(const Rc& device); + ~D3D9FormatHelper(); + void Flush(); void ConvertFormat( + const DxvkContextObjects& ctx, D3D9_CONVERSION_FORMAT_INFO conversionFormat, const Rc& dstImage, VkImageSubresourceLayers dstSubresource, @@ -24,12 +27,12 @@ namespace dxvk { private: void ConvertGenericFormat( + const DxvkContextObjects& ctx, D3D9_CONVERSION_FORMAT_INFO videoFormat, const Rc& dstImage, VkImageSubresourceLayers dstSubresource, const DxvkBufferSlice& srcSlice, VkFormat bufferFormat, - uint32_t specConstantValue, VkExtent2D macroPixelRun); enum BindingIds : uint32_t { @@ -37,18 +40,20 @@ namespace dxvk { Buffer = 1, }; - void InitShaders(); + void InitPipelines(); - Rc InitShader(SpirvCodeBuffer code); + VkDescriptorSetLayout CreateSetLayout(); - void FlushInternal(); + VkPipelineLayout CreatePipelineLayout(); - Rc m_device; - Rc m_context; + VkPipeline CreatePipeline(size_t size, const uint32_t* code, uint32_t specConstant); - size_t m_transferCommands = 0; + Rc m_device; - std::array, D3D9ConversionFormat_Count> m_shaders; + VkDescriptorSetLayout m_setLayout = VK_NULL_HANDLE; + VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; + + std::array m_pipelines = { }; };