diff --git a/src/dxvk/dxvk_adapter.cpp b/src/dxvk/dxvk_adapter.cpp index f1a93db8..fbee13f0 100644 --- a/src/dxvk/dxvk_adapter.cpp +++ b/src/dxvk/dxvk_adapter.cpp @@ -196,7 +196,12 @@ namespace dxvk { if (m_vki->vkCreateDevice(m_handle, &info, nullptr, &device) != VK_SUCCESS) throw DxvkError("DxvkAdapter: Failed to create device"); - return new DxvkDevice(this, new vk::DeviceFn(m_vki->instance(), device), extensions, enabledFeatures); + + Rc result = new DxvkDevice(this, + new vk::DeviceFn(m_vki->instance(), device), + extensions, enabledFeatures); + result->initResources(); + return result; } diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index aa4c79bb..b54361c3 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -304,6 +304,17 @@ namespace dxvk { m_vkd->vkCmdEndRenderPass(m_buffer); } + + void cmdFillBuffer( + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize size, + uint32_t data) { + m_vkd->vkCmdFillBuffer(m_buffer, + dstBuffer, dstOffset, size, data); + } + + void cmdPipelineBarrier( VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 851b064c..73d0b1a5 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -175,6 +175,32 @@ namespace dxvk { } + void DxvkContext::clearBuffer( + const Rc& buffer, + VkDeviceSize offset, + VkDeviceSize length, + uint32_t value) { + this->renderPassEnd(); + + auto slice = buffer->subSlice(offset, length); + + m_cmd->cmdFillBuffer( + slice.handle(), + slice.offset(), + slice.length(), + value); + + m_barriers.accessBuffer(slice, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + buffer->info().stages, + buffer->info().access); + m_barriers.recordCommands(m_cmd); + + m_cmd->trackResource(slice.resource()); + } + + void DxvkContext::clearColorImage( const Rc& image, const VkClearColorValue& value, diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index d5077b3e..67e9757e 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -135,6 +135,23 @@ namespace dxvk { const DxvkBufferSlice& buffer, uint32_t stride); + /** + * \brief Clears a buffer with a fixed value + * + * Note that both \c offset and \c length must + * be multiples of four, and that \c value is + * consumed as a four-byte word. + * \param [in] buffer The buffer to clear + * \param [in] offset Offset of the range to clear + * \param [in] length Bumber of bytes to clear + * \param [in] value Clear value + */ + void clearBuffer( + const Rc& buffer, + VkDeviceSize offset, + VkDeviceSize length, + uint32_t value); + /** * \brief Clears subresources of a color image * diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index 0b0f5aec..a385b0cd 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -192,6 +192,11 @@ namespace dxvk { } + void DxvkDevice::initResources() { + m_unboundResources.clearResources(this); + } + + VkResult DxvkDevice::presentSwapImage( const VkPresentInfoKHR& presentInfo) { m_statCounters.increment(DxvkStat::DevQueuePresents, 1); diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index be70f3c4..17167fa6 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -35,6 +35,7 @@ namespace dxvk { * contexts. Multiple contexts can be created for a device. */ class DxvkDevice : public RcObject { + friend class DxvkContext; friend class DxvkSubmissionQueue; constexpr static VkDeviceSize DefaultStagingBufferSize = 4 * 1024 * 1024; @@ -276,46 +277,13 @@ namespace dxvk { const DxvkSwapchainProperties& properties); /** - * \brief Dummy buffer handle - * \returns Use for unbound vertex buffers. - */ - VkBuffer dummyBufferHandle() const { - return m_unboundResources.bufferHandle(); - } - - /** - * \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 + * \brief Initializes dummy resources * - * \param [in] type Required view type - * \returns Descriptor that points to a dummy image + * Should be called after creating the device in + * case the device initialization was successful + * and the device is usable. */ - VkDescriptorImageInfo dummyImageViewDescriptor(VkImageViewType type) const { - return m_unboundResources.imageViewDescriptor(type); - } + void initResources(); /** * \brief Presents a swap chain image @@ -379,7 +347,6 @@ namespace dxvk { VkQueue m_graphicsQueue = VK_NULL_HANDLE; VkQueue m_presentQueue = VK_NULL_HANDLE; - // TODO fine-tune buffer sizes DxvkRecycler m_recycledCommandLists; DxvkRecycler m_recycledStagingBuffers; @@ -390,6 +357,48 @@ namespace dxvk { void recycleCommandList( const Rc& cmdList); + /** + * \brief Dummy buffer handle + * \returns Use for unbound vertex buffers. + */ + VkBuffer dummyBufferHandle() const { + return m_unboundResources.bufferHandle(); + } + + /** + * \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); + } + }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_unbound.cpp b/src/dxvk/dxvk_unbound.cpp index 818dd7ef..38ae6798 100644 --- a/src/dxvk/dxvk_unbound.cpp +++ b/src/dxvk/dxvk_unbound.cpp @@ -25,6 +25,21 @@ namespace dxvk { } + void DxvkUnboundResources::clearResources(DxvkDevice* dev) { + const Rc ctx = dev->createContext(); + ctx->beginRecording(dev->createCommandList()); + + this->clearBuffer(ctx, m_buffer); + this->clearImage(ctx, m_image1D); + this->clearImage(ctx, m_image2D); + this->clearImage(ctx, m_image3D); + + dev->submitCommandList( + ctx->endRecording(), + nullptr, nullptr); + } + + Rc DxvkUnboundResources::createSampler(DxvkDevice* dev) { DxvkSamplerCreateInfo info; info.minFilter = VK_FILTER_LINEAR; @@ -50,11 +65,13 @@ namespace dxvk { Rc DxvkUnboundResources::createBuffer(DxvkDevice* dev) { DxvkBufferCreateInfo info; info.size = 4; - info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | 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 + info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT + | 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 @@ -93,9 +110,11 @@ namespace dxvk { info.extent = { 1, 1, 1 }; info.numLayers = layers; info.mipLevels = 1; - info.usage = VK_IMAGE_USAGE_SAMPLED_BIT + info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; - info.stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT + info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT + | 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 @@ -147,4 +166,23 @@ namespace dxvk { } } + + void DxvkUnboundResources::clearBuffer( + const Rc& ctx, + const Rc& buffer) { + ctx->clearBuffer(buffer, 0, buffer->info().size, 0); + } + + + void DxvkUnboundResources::clearImage( + const Rc& ctx, + const Rc& image) { + ctx->clearColorImage(image, + VkClearColorValue { }, + VkImageSubresourceRange { + VK_IMAGE_ASPECT_COLOR_BIT, + 0, image->info().mipLevels, + 0, image->info().numLayers }); + } + } \ No newline at end of file diff --git a/src/dxvk/dxvk_unbound.h b/src/dxvk/dxvk_unbound.h index 8981fdad..f13d6882 100644 --- a/src/dxvk/dxvk_unbound.h +++ b/src/dxvk/dxvk_unbound.h @@ -35,8 +35,9 @@ namespace dxvk { /** * \brief Dummy buffer descriptor * - * Points to a small buffer with undefined - * values. Do not access this buffer. + * Points to a small buffer filled with zeroes. + * Do not write to this buffer, and do not use + * it if out-of-bounds read access is possible. * \returns Dummy buffer descriptor */ VkDescriptorBufferInfo bufferDescriptor() const { @@ -95,6 +96,14 @@ namespace dxvk { return result; } + /** + * \brief Clears the resources + * + * Initializes all images and buffers to zero. + * \param [in] dev The DXVK device handle + */ + void clearResources(DxvkDevice* dev); + private: Rc m_sampler; @@ -136,6 +145,14 @@ namespace dxvk { const DxvkImageView* getImageView( VkImageViewType type) const; + void clearBuffer( + const Rc& ctx, + const Rc& buffer); + + void clearImage( + const Rc& ctx, + const Rc& image); + }; } \ No newline at end of file