From d1f76b96af7f96facbcc630aa5b7a1ecd235e787 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 27 Jan 2018 19:25:41 +0100 Subject: [PATCH] [dxvk] Added dummy resources for descriptors This should finally shut up validation layers and also allows the branches in texture sample operations to be removed. --- src/dxvk/dxvk_context.cpp | 35 ++++----- src/dxvk/dxvk_device.cpp | 1 + src/dxvk/dxvk_device.h | 36 +++++++++ src/dxvk/dxvk_unbound.cpp | 149 ++++++++++++++++++++++++++++++++++++++ src/dxvk/dxvk_unbound.h | 129 +++++++++++++++++++++++++++++++++ src/dxvk/meson.build | 1 + 6 files changed, 334 insertions(+), 17 deletions(-) create mode 100644 src/dxvk/dxvk_unbound.cpp create mode 100644 src/dxvk/dxvk_unbound.h diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index c962c6e8..accc9a00 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1288,6 +1288,7 @@ namespace dxvk { m_cmd->trackResource(res.sampler); } else { updatePipelineState |= bs.setUnbound(i); + m_descriptors[i].image = m_device->dummySamplerDescriptor(); } break; case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: @@ -1303,6 +1304,7 @@ namespace dxvk { m_cmd->trackResource(res.imageView->image()); } else { updatePipelineState |= bs.setUnbound(i); + m_descriptors[i].image = m_device->dummyImageViewDescriptor(binding.view); } break; case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: @@ -1316,6 +1318,7 @@ namespace dxvk { m_cmd->trackResource(res.bufferView->resource()); } else { updatePipelineState |= bs.setUnbound(i); + m_descriptors[i].texelBuffer = m_device->dummyBufferViewDescriptor(); } break; case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: @@ -1331,6 +1334,7 @@ namespace dxvk { m_cmd->trackResource(physicalSlice.resource()); } else { updatePipelineState |= bs.setUnbound(i); + m_descriptors[i].buffer = m_device->dummyBufferDescriptor(); } break; default: @@ -1355,26 +1359,23 @@ namespace dxvk { const VkDescriptorSet dset = m_cmd->allocateDescriptorSet( layout->descriptorSetLayout()); - - size_t writeId = 0; - for (uint32_t i = 0; i < layout->bindingCount(); i++) { - if (bindingState.isBound(i)) { - writes[writeId].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writes[writeId].pNext = nullptr; - writes[writeId].dstSet = dset; - writes[writeId].dstBinding = i; - writes[writeId].dstArrayElement = 0; - writes[writeId].descriptorCount = 1; - writes[writeId].descriptorType = layout->binding(i).type; - writes[writeId].pImageInfo = &m_descriptors[i].image; - writes[writeId].pBufferInfo = &m_descriptors[i].buffer; - writes[writeId].pTexelBufferView = &m_descriptors[i].texelBuffer; - writeId++; - } + const uint32_t bindingCount = layout->bindingCount(); + + for (uint32_t i = 0; i < bindingCount; i++) { + writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes[i].pNext = nullptr; + writes[i].dstSet = dset; + writes[i].dstBinding = i; + writes[i].dstArrayElement = 0; + writes[i].descriptorCount = 1; + writes[i].descriptorType = layout->binding(i).type; + writes[i].pImageInfo = &m_descriptors[i].image; + writes[i].pBufferInfo = &m_descriptors[i].buffer; + writes[i].pTexelBufferView = &m_descriptors[i].texelBuffer; } - m_cmd->updateDescriptorSet(writeId, writes.data()); + m_cmd->updateDescriptorSet(bindingCount, writes.data()); m_cmd->cmdBindDescriptorSet(bindPoint, layout->pipelineLayout(), dset); } diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index 404f8020..b9098f19 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -16,6 +16,7 @@ namespace dxvk { m_renderPassPool (new DxvkRenderPassPool (vkd)), m_pipelineCache (new DxvkPipelineCache (vkd)), m_pipelineManager (new DxvkPipelineManager(this)), + m_unboundResources(this), m_submissionQueue (this) { m_options.adjustAppOptions(env::getExeName()); m_options.adjustDeviceOptions(m_adapter); diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index d81f93be..955998ef 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -20,6 +20,7 @@ #include "dxvk_stats.h" #include "dxvk_swapchain.h" #include "dxvk_sync.h" +#include "dxvk_unbound.h" namespace dxvk { @@ -276,6 +277,40 @@ namespace dxvk { const Rc& surface, const DxvkSwapchainProperties& properties); + /** + * \brief Dummy buffer descriptor + * \returns Descriptor that points to a dummy buffer + */ + VkDescriptorBufferInfo dummyBufferDescriptor() const { + return m_unboundResources.bufferDescriptor(); + } + + /** + * \brief Dummy buffer view descriptor + * \returns Dummy buffer view handle + */ + VkBufferView dummyBufferViewDescriptor() const { + return m_unboundResources.bufferViewDescriptor(); + } + + /** + * \brief Dummy sampler descriptor + * \returns Descriptor that points to a dummy sampler + */ + VkDescriptorImageInfo dummySamplerDescriptor() const { + return m_unboundResources.samplerDescriptor(); + } + + /** + * \brief Dummy image view descriptor + * + * \param [in] type Required view type + * \returns Descriptor that points to a dummy image + */ + VkDescriptorImageInfo dummyImageViewDescriptor(VkImageViewType type) const { + return m_unboundResources.imageViewDescriptor(type); + } + /** * \brief Presents a swap chain image * @@ -331,6 +366,7 @@ namespace dxvk { Rc m_pipelineCache; Rc m_pipelineManager; + DxvkUnboundResources m_unboundResources; DxvkOptions m_options; std::mutex m_submissionLock; diff --git a/src/dxvk/dxvk_unbound.cpp b/src/dxvk/dxvk_unbound.cpp new file mode 100644 index 00000000..5baa1dd3 --- /dev/null +++ b/src/dxvk/dxvk_unbound.cpp @@ -0,0 +1,149 @@ +#include "dxvk_device.h" + +namespace dxvk { + + DxvkUnboundResources::DxvkUnboundResources(DxvkDevice* dev) + : m_buffer (createBuffer(dev)), + m_bufferView (createBufferView(dev, m_buffer)), + m_image1D (createImage(dev, VK_IMAGE_TYPE_1D, 1)), + m_image2D (createImage(dev, VK_IMAGE_TYPE_2D, 6)), + m_image3D (createImage(dev, VK_IMAGE_TYPE_3D, 1)), + m_view1D (createImageView(dev, m_image1D, VK_IMAGE_VIEW_TYPE_1D, 1)), + m_view1DArr (createImageView(dev, m_image1D, VK_IMAGE_VIEW_TYPE_1D_ARRAY, 1)), + m_view2D (createImageView(dev, m_image2D, VK_IMAGE_VIEW_TYPE_2D, 1)), + m_view2DArr (createImageView(dev, m_image2D, VK_IMAGE_VIEW_TYPE_2D_ARRAY, 1)), + m_viewCube (createImageView(dev, m_image2D, VK_IMAGE_VIEW_TYPE_CUBE, 6)), + m_viewCubeArr (createImageView(dev, m_image2D, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, 6)), + m_view3D (createImageView(dev, m_image3D, VK_IMAGE_VIEW_TYPE_3D, 1)) { + + } + + + DxvkUnboundResources::~DxvkUnboundResources() { + + } + + + Rc DxvkUnboundResources::createSampler(DxvkDevice* dev) { + DxvkSamplerCreateInfo info; + info.minFilter = VK_FILTER_LINEAR; + info.magFilter = VK_FILTER_LINEAR; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + info.mipmapLodBias = 0.0f; + info.mipmapLodMin = -256.0f; + info.mipmapLodMax = 256.0f; + info.useAnisotropy = VK_FALSE; + info.maxAnisotropy = 1.0f; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.compareToDepth = VK_FALSE; + info.compareOp = VK_COMPARE_OP_NEVER; + info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + info.usePixelCoord = VK_FALSE; + + return dev->createSampler(info); + } + + + Rc DxvkUnboundResources::createBuffer(DxvkDevice* dev) { + DxvkBufferCreateInfo info; + info.size = 4; + info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT + | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT + | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; + info.stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT + | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT + | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT + | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT + | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT + | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + info.access = VK_ACCESS_UNIFORM_READ_BIT + | VK_ACCESS_SHADER_READ_BIT + | VK_ACCESS_SHADER_WRITE_BIT; + + return dev->createBuffer(info, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + } + + + Rc DxvkUnboundResources::createBufferView( + DxvkDevice* dev, + const Rc& buffer) { + DxvkBufferViewCreateInfo info; + info.format = VK_FORMAT_R32_UINT; + info.rangeOffset = 0; + info.rangeLength = buffer->info().size; + + return dev->createBufferView(buffer, info); + } + + + Rc DxvkUnboundResources::createImage( + DxvkDevice* dev, + VkImageType type, + uint32_t layers) { + DxvkImageCreateInfo info; + info.type = type; + info.format = VK_FORMAT_R32_UINT; + info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + info.sampleCount = VK_SAMPLE_COUNT_1_BIT; + info.extent = { 1, 1, 1 }; + info.numLayers = layers; + info.mipLevels = 1; + info.usage = VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT; + info.stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT + | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT + | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT + | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT + | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT + | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + info.access = VK_ACCESS_SHADER_READ_BIT; + info.layout = VK_IMAGE_LAYOUT_GENERAL; + info.tiling = VK_IMAGE_TILING_OPTIMAL; + + if (type == VK_IMAGE_TYPE_2D) + info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + + return dev->createImage(info, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + } + + + Rc DxvkUnboundResources::createImageView( + DxvkDevice* dev, + const Rc& image, + VkImageViewType type, + uint32_t layers) { + DxvkImageViewCreateInfo info; + info.type = type; + info.format = image->info().format; + info.aspect = VK_IMAGE_ASPECT_COLOR_BIT; + info.minLevel = 0; + info.numLevels = 1; + info.minLayer = 0; + info.numLayers = layers; + info.swizzle = VkComponentMapping { + VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, + VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO }; + + return dev->createImageView(image, info); + } + + + const DxvkImageView* DxvkUnboundResources::getImageView(VkImageViewType type) const { + switch (type) { + case VK_IMAGE_VIEW_TYPE_1D: return m_view1D.ptr(); + case VK_IMAGE_VIEW_TYPE_1D_ARRAY: return m_view1DArr.ptr(); + case VK_IMAGE_VIEW_TYPE_2D: return m_view2D.ptr(); + case VK_IMAGE_VIEW_TYPE_2D_ARRAY: return m_view2DArr.ptr(); + case VK_IMAGE_VIEW_TYPE_CUBE: return m_viewCube.ptr(); + case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: return m_viewCubeArr.ptr(); + case VK_IMAGE_VIEW_TYPE_3D: return m_view3D.ptr(); + default: return nullptr; + } + } + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_unbound.h b/src/dxvk/dxvk_unbound.h new file mode 100644 index 00000000..37d87d0d --- /dev/null +++ b/src/dxvk/dxvk_unbound.h @@ -0,0 +1,129 @@ +#pragma once + +#include "dxvk_buffer.h" +#include "dxvk_image.h" +#include "dxvk_sampler.h" + +namespace dxvk { + + /** + * \brief Unbound resources + * + * Creates dummy resources that will be used + * for descriptor sets when the client API did + * not bind a compatible resource to a slot. + */ + class DxvkUnboundResources { + + public: + + DxvkUnboundResources(DxvkDevice* dev); + ~DxvkUnboundResources(); + + /** + * \brief Dummy buffer descriptor + * + * Points to a tiny buffer with undefined + * values. Do not access this buffer. + * \returns Dummy buffer descriptor + */ + VkDescriptorBufferInfo bufferDescriptor() const { + auto slice = m_buffer->slice(); + + VkDescriptorBufferInfo result; + result.buffer = slice.handle(); + result.offset = slice.offset(); + result.range = slice.length(); + return result; + } + + /** + * \brief Dummy buffer view + * + * Returns an \c R32_UINT view into the + * dummy buffer, which will contain one + * element with undefined value. + * \returns Dummy buffer view + */ + VkBufferView bufferViewDescriptor() const { + return m_bufferView->handle(); + } + + /** + * \brief Dummy sampler descriptor + * + * Points to a sampler which was created with + * reasonable default values. Client APIs may + * still require different behaviour. + * \returns Dummy sampler descriptor + */ + VkDescriptorImageInfo samplerDescriptor() const { + VkDescriptorImageInfo result; + result.sampler = m_sampler->handle(); + result.imageView = VK_NULL_HANDLE; + result.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + return result; + } + + /** + * \brief Dummy image view descriptor + * + * Points to an image view which, instead of + * reading image data, will return zeroes for + * all components unconditionally. + * \returns Dummy image view descriptor + */ + VkDescriptorImageInfo imageViewDescriptor(VkImageViewType type) const { + auto view = getImageView(type); + + VkDescriptorImageInfo result; + result.sampler = VK_NULL_HANDLE; + result.imageView = view->handle(); + result.imageLayout = view->imageInfo().layout; + return result; + } + + private: + + Rc m_sampler; + + Rc m_buffer; + Rc m_bufferView; + + Rc m_image1D; + Rc m_image2D; + Rc m_image3D; + + Rc m_view1D; + Rc m_view1DArr; + Rc m_view2D; + Rc m_view2DArr; + Rc m_viewCube; + Rc m_viewCubeArr; + Rc m_view3D; + + Rc createSampler(DxvkDevice* dev); + + Rc createBuffer(DxvkDevice* dev); + + Rc createBufferView( + DxvkDevice* dev, + const Rc& buffer); + + Rc createImage( + DxvkDevice* dev, + VkImageType type, + uint32_t layers); + + Rc createImageView( + DxvkDevice* dev, + const Rc& image, + VkImageViewType type, + uint32_t layers); + + const DxvkImageView* getImageView( + VkImageViewType type) const; + + }; + +} \ No newline at end of file diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 6747d999..ed476a40 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -38,6 +38,7 @@ dxvk_src = files([ 'dxvk_surface.cpp', 'dxvk_swapchain.cpp', 'dxvk_sync.cpp', + 'dxvk_unbound.cpp', 'dxvk_util.cpp', 'hud/dxvk_hud.cpp',