From b5d068366ddc33d144088abdcc0e7a5bbdd56aa4 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 3 Dec 2017 20:23:26 +0100 Subject: [PATCH] [dxvk] Implemented shader resource binding --- src/dxgi/dxgi_presenter.cpp | 72 ++++++++-- src/dxgi/dxgi_presenter.h | 7 + src/dxgi/dxgi_swapchain.cpp | 5 +- src/dxvk/dxvk_binding.h | 61 +++++++++ src/dxvk/dxvk_buffer.cpp | 3 +- src/dxvk/dxvk_buffer.h | 3 - src/dxvk/dxvk_cmdlist.cpp | 45 ++++++ src/dxvk/dxvk_cmdlist.h | 9 ++ src/dxvk/dxvk_compute.cpp | 2 +- src/dxvk/dxvk_compute.h | 24 +--- src/dxvk/dxvk_context.cpp | 203 +++++++++++++++++++++++++--- src/dxvk/dxvk_context.h | 100 +++++++++++--- src/dxvk/dxvk_context_state.h | 6 +- src/dxvk/dxvk_descriptor.h | 13 ++ src/dxvk/dxvk_device.cpp | 10 +- src/dxvk/dxvk_device.h | 14 +- src/dxvk/dxvk_graphics.cpp | 2 +- src/dxvk/dxvk_graphics.h | 22 +-- src/dxvk/dxvk_image.h | 8 ++ src/dxvk/dxvk_limits.h | 11 +- src/dxvk/dxvk_pipeline.cpp | 32 ++--- src/dxvk/dxvk_pipeline.h | 29 ++-- src/dxvk/dxvk_sampler.cpp | 40 ++++++ src/dxvk/dxvk_sampler.h | 82 +++++++++++ src/dxvk/meson.build | 1 + src/spirv/spirv_module.cpp | 80 +++++++++++ src/spirv/spirv_module.h | 32 +++++ tests/d3d11/test_d3d11_triangle.cpp | 2 +- 28 files changed, 778 insertions(+), 140 deletions(-) create mode 100644 src/dxvk/dxvk_binding.h diff --git a/src/dxgi/dxgi_presenter.cpp b/src/dxgi/dxgi_presenter.cpp index a85049af..99cf9147 100644 --- a/src/dxgi/dxgi_presenter.cpp +++ b/src/dxgi/dxgi_presenter.cpp @@ -33,6 +33,26 @@ namespace dxvk { m_acquireSync = m_device->createSemaphore(); m_presentSync = m_device->createSemaphore(); + // Sampler for presentation + DxvkSamplerCreateInfo samplerInfo; + samplerInfo.magFilter = VK_FILTER_NEAREST; + samplerInfo.minFilter = VK_FILTER_NEAREST; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + samplerInfo.mipmapLodBias = 0.0f; + samplerInfo.mipmapLodMin = 0.0f; + samplerInfo.mipmapLodMax = 0.0f; + samplerInfo.useAnisotropy = VK_FALSE; + samplerInfo.maxAnisotropy = 1.0f; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.compareToDepth = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + samplerInfo.usePixelCoord = VK_FALSE; + + m_sampler = m_device->createSampler(samplerInfo); + // Set up context state. The shader bindings and the // constant state objects will never be modified. m_context->bindGraphicsPipeline(createPipeline()); @@ -133,9 +153,12 @@ namespace dxvk { m_context->setViewports(1, &viewport, &scissor); - // TODO bind back buffer as a shader resource -// m_context->bindSampler(0, m_sampler); -// m_context->bindSampledImage(1, view); + m_context->bindResourceSampler( + VK_PIPELINE_BIND_POINT_GRAPHICS, + BindingIds::Sampler, m_sampler); + m_context->bindResourceImage( + VK_PIPELINE_BIND_POINT_GRAPHICS, + BindingIds::Texture, view); m_context->draw(4, 1, 0, 0); m_device->submitCommandList( @@ -279,10 +302,26 @@ namespace dxvk { uint32_t typeVec2 = module.defVectorType(typeF32, 2); uint32_t typeVec4 = module.defVectorType(typeF32, 4); uint32_t typeFn = module.defFunctionType(typeVoid, 0, nullptr); + uint32_t typeSampler = module.defSamplerType(); + uint32_t typeTexture = module.defImageType( + typeF32, spv::Dim2D, 0, 0, 0, 1, spv::ImageFormatUnknown); + uint32_t typeSampledTex = module.defSampledImageType(typeTexture); // Pointer type definitions uint32_t ptrInputVec2 = module.defPointerType(typeVec2, spv::StorageClassInput); uint32_t ptrOutputVec4 = module.defPointerType(typeVec4, spv::StorageClassOutput); + uint32_t ptrSampler = module.defPointerType(typeSampler, spv::StorageClassUniformConstant); + uint32_t ptrTexture = module.defPointerType(typeTexture, spv::StorageClassUniformConstant); + + // Sampler + uint32_t rcSampler = module.newVar(ptrSampler, spv::StorageClassUniformConstant); + module.decorateDescriptorSet(rcSampler, 0); + module.decorateBinding(rcSampler, BindingIds::Sampler); + + // Texture + uint32_t rcTexture = module.newVar(ptrTexture, spv::StorageClassUniformConstant); + module.decorateDescriptorSet(rcTexture, 0); + module.decorateBinding(rcTexture, BindingIds::Texture); // Input variable: Texture coordinates uint32_t inTexCoord = module.newVar( @@ -299,13 +338,14 @@ namespace dxvk { module.opLabel(module.allocateId()); // Load texture coordinates - uint32_t tmpTexCoord = module.opLoad(typeVec2, inTexCoord); - - // Compute final color - uint32_t swizzleIndices[4] = { 0, 1, 2, 3 }; - uint32_t tmpColor = module.opVectorShuffle( - typeVec4, tmpTexCoord, tmpTexCoord, 4, swizzleIndices); - module.opStore(outColor, tmpColor); + module.opStore(outColor, + module.opImageSampleImplicitLod( + typeVec4, + module.opSampledImage( + typeSampledTex, + module.opLoad(typeTexture, rcTexture), + module.opLoad(typeSampler, rcSampler)), + module.opLoad(typeVec2, inTexCoord))); module.opReturn(); module.functionEnd(); @@ -325,12 +365,14 @@ namespace dxvk { Rc DxgiPresenter::createBindingLayout() { - std::array bindings; - bindings.at(0).type = VK_DESCRIPTOR_TYPE_SAMPLER; - bindings.at(0).stages = VK_SHADER_STAGE_FRAGMENT_BIT; + std::array bindings; + bindings.at(BindingIds::Sampler).slot = BindingIds::Sampler; + bindings.at(BindingIds::Sampler).type = VK_DESCRIPTOR_TYPE_SAMPLER; + bindings.at(BindingIds::Sampler).stages = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings.at(1).type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - bindings.at(1).stages = VK_SHADER_STAGE_FRAGMENT_BIT; + bindings.at(BindingIds::Texture).slot = BindingIds::Texture; + bindings.at(BindingIds::Texture).type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + bindings.at(BindingIds::Texture).stages = VK_SHADER_STAGE_FRAGMENT_BIT; return m_device->createBindingLayout( bindings.size(), bindings.data()); diff --git a/src/dxgi/dxgi_presenter.h b/src/dxgi/dxgi_presenter.h index 4ed4dc5f..7db2ed1f 100644 --- a/src/dxgi/dxgi_presenter.h +++ b/src/dxgi/dxgi_presenter.h @@ -43,6 +43,11 @@ namespace dxvk { private: + enum BindingIds : uint32_t { + Sampler = 0, + Texture = 1, + }; + Rc m_device; Rc m_context; @@ -52,6 +57,8 @@ namespace dxvk { Rc m_acquireSync; Rc m_presentSync; + Rc m_sampler; + Rc createVertexShader(); Rc createFragmentShader(); diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index 250fb8d3..bcf200b9 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -45,9 +45,6 @@ namespace dxvk { } // Set initial window mode and fullscreen state - if (FAILED(this->ResizeTarget(&pDesc->BufferDesc))) - throw DxvkError("DxgiSwapChain::DxgiSwapChain: Failed to set initial display mode"); - if (FAILED(this->SetFullscreenState(!pDesc->Windowed, nullptr))) throw DxvkError("DxgiSwapChain::DxgiSwapChain: Failed to set initial fullscreen state"); @@ -319,7 +316,7 @@ namespace dxvk { DxvkImageCreateInfo imageInfo; imageInfo.type = VK_IMAGE_TYPE_2D; - imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + imageInfo.format = VK_FORMAT_R8G8B8A8_SRGB; imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT; imageInfo.extent.width = m_desc.BufferDesc.Width; imageInfo.extent.height = m_desc.BufferDesc.Height; diff --git a/src/dxvk/dxvk_binding.h b/src/dxvk/dxvk_binding.h new file mode 100644 index 00000000..216f01df --- /dev/null +++ b/src/dxvk/dxvk_binding.h @@ -0,0 +1,61 @@ +#pragma once + +#include "dxvk_buffer.h" +#include "dxvk_descriptor.h" +#include "dxvk_image.h" +#include "dxvk_sampler.h" + +namespace dxvk { + + /** + * \brief Bound shader resource + */ + struct DxvkShaderResourceSlot { + Rc sampler; + Rc imageView; + Rc bufferView; + DxvkBufferBinding bufferSlice; + }; + + + /** + * \brief Shader resource slots + */ + class DxvkShaderResourceSlots { + + public: + + DxvkShaderResourceSlots() { } + DxvkShaderResourceSlots(size_t n) { + m_resources .resize(n); + m_descriptors.resize(n); + } + + uint32_t descriptorCount() const { + return m_descriptors.size(); + } + + const DxvkDescriptorInfo* descriptors() const { + return m_descriptors.data(); + } + + const DxvkShaderResourceSlot& getShaderResource(uint32_t slot) const { + return m_resources.at(slot); + } + + void bindShaderResource( + uint32_t slot, + const DxvkShaderResourceSlot& resource, + const DxvkDescriptorInfo& descriptor) { + m_resources .at(slot) = resource; + m_descriptors .at(slot) = descriptor; + } + + private: + + std::vector m_resources; + std::vector m_descriptors; + + }; + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_buffer.cpp b/src/dxvk/dxvk_buffer.cpp index 5d2f546e..7736182f 100644 --- a/src/dxvk/dxvk_buffer.cpp +++ b/src/dxvk/dxvk_buffer.cpp @@ -60,7 +60,8 @@ namespace dxvk { DxvkBufferView::~DxvkBufferView() { - + m_vkd->vkDestroyBufferView( + m_vkd->device(), m_view, nullptr); } } \ No newline at end of file diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index 8e115af6..6a3070b3 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -12,7 +12,6 @@ namespace dxvk { * passed to \ref DxvkDevice::createBuffer */ struct DxvkBufferCreateInfo { - /// Size of the buffer, in bytes VkDeviceSize size; @@ -25,7 +24,6 @@ namespace dxvk { /// Allowed access patterns VkAccessFlags access; - }; @@ -36,7 +34,6 @@ namespace dxvk { * are to \ref DxvkDevice::createBufferView */ struct DxvkBufferViewCreateInfo { - /// Buffer data format, like image data VkFormat format; diff --git a/src/dxvk/dxvk_cmdlist.cpp b/src/dxvk/dxvk_cmdlist.cpp index 28e3fe30..67d7eac6 100644 --- a/src/dxvk/dxvk_cmdlist.cpp +++ b/src/dxvk/dxvk_cmdlist.cpp @@ -91,6 +91,51 @@ namespace dxvk { } + void DxvkCommandList::bindResourceDescriptors( + VkPipelineBindPoint pipeline, + VkPipelineLayout pipelineLayout, + VkDescriptorSetLayout descriptorLayout, + uint32_t descriptorCount, + const DxvkDescriptorSlot* descriptorSlots, + const DxvkDescriptorInfo* descriptorInfos) { + + // Allocate a new descriptor set + VkDescriptorSet dset = m_descAlloc.alloc(descriptorLayout); + + // Write data to the descriptor set + // TODO recycle vector as a class member + std::vector descriptorWrites; + descriptorWrites.resize(descriptorCount); + + for (uint32_t i = 0; i < descriptorCount; i++) { + auto& curr = descriptorWrites.at(i); + auto& binding = descriptorSlots[i]; + + curr.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + curr.pNext = nullptr; + curr.dstSet = dset; + curr.dstBinding = i; + curr.dstArrayElement = 0; + curr.descriptorCount = 1; + curr.descriptorType = binding.type; + curr.pImageInfo = &descriptorInfos[binding.slot].image; + curr.pBufferInfo = &descriptorInfos[binding.slot].buffer; + curr.pTexelBufferView = &descriptorInfos[binding.slot].texelBuffer; + } + + m_vkd->vkUpdateDescriptorSets( + m_vkd->device(), + descriptorWrites.size(), + descriptorWrites.data(), + 0, nullptr); + + // Bind descriptor set to the pipeline + m_vkd->vkCmdBindDescriptorSets(m_buffer, + pipeline, pipelineLayout, 0, 1, + &dset, 0, nullptr); + } + + void DxvkCommandList::cmdBeginRenderPass( const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) { diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 7f875772..205c5ade 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -4,6 +4,7 @@ #include "dxvk_descriptor.h" #include "dxvk_lifetime.h" +#include "dxvk_pipeline.h" namespace dxvk { @@ -76,6 +77,14 @@ namespace dxvk { */ void reset(); + void bindResourceDescriptors( + VkPipelineBindPoint pipeline, + VkPipelineLayout pipelineLayout, + VkDescriptorSetLayout descriptorLayout, + uint32_t descriptorCount, + const DxvkDescriptorSlot* descriptorSlots, + const DxvkDescriptorInfo* descriptorInfos); + void cmdBeginRenderPass( const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); diff --git a/src/dxvk/dxvk_compute.cpp b/src/dxvk/dxvk_compute.cpp index 487d34e3..801ce28c 100644 --- a/src/dxvk/dxvk_compute.cpp +++ b/src/dxvk/dxvk_compute.cpp @@ -14,7 +14,7 @@ namespace dxvk { info.pNext = nullptr; info.flags = 0; info.stage = cs->stageInfo(); - info.layout = this->pipelineLayout(); + info.layout = m_layout->pipelineLayout(); info.basePipelineHandle = VK_NULL_HANDLE; info.basePipelineIndex = 0; diff --git a/src/dxvk/dxvk_compute.h b/src/dxvk/dxvk_compute.h index 3cbef15c..ca658f85 100644 --- a/src/dxvk/dxvk_compute.h +++ b/src/dxvk/dxvk_compute.h @@ -25,25 +25,15 @@ namespace dxvk { ~DxvkComputePipeline(); /** - * \brief Descriptor set layout + * \brief Pipeline layout * - * The descriptor set layout for this pipeline. - * Use this to allocate new descriptor sets. - * \returns The descriptor set layout + * Stores the pipeline layout and the descriptor set + * layout, as well as information on the resource + * slots used by the pipeline. + * \returns Pipeline layout */ - VkDescriptorSetLayout descriptorSetLayout() const { - return m_layout->descriptorSetLayout(); - } - - /** - * \brief Pipeline layout layout - * - * The pipeline layout for this pipeline. - * Use this to bind descriptor sets. - * \returns The descriptor set layout - */ - VkPipelineLayout pipelineLayout() const { - return m_layout->pipelineLayout(); + Rc layout() const { + return m_layout; } /** diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index ac900421..cb57c593 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -53,6 +53,32 @@ namespace dxvk { } + void DxvkContext::bindComputePipeline( + const Rc& pipeline) { + if (m_state.cPipe != pipeline) { + m_state.cPipe = pipeline; + + m_flags.set( + DxvkContextFlag::CpDirtyPipeline, + DxvkContextFlag::CpDirtyResources); + } + } + + + void DxvkContext::bindGraphicsPipeline( + const Rc& pipeline) { + if (m_state.gPipe != pipeline) { + m_state.gPipe = pipeline; + + m_flags.set( + DxvkContextFlag::GpDirtyPipeline, + DxvkContextFlag::GpDirtyResources, + DxvkContextFlag::GpDirtyVertexBuffers, + DxvkContextFlag::GpDirtyIndexBuffer); + } + } + + void DxvkContext::bindIndexBuffer( const DxvkBufferBinding& buffer) { if (m_state.vi.indexBuffer != buffer) { @@ -62,25 +88,93 @@ namespace dxvk { } - void DxvkContext::bindComputePipeline( - const Rc& pipeline) { - m_state.cp = pipeline; + void DxvkContext::bindResourceBuffer( + VkPipelineBindPoint pipe, + uint32_t slot, + const DxvkBufferBinding& buffer) { + auto rc = this->getShaderResourceSlots(pipe); - m_flags.set( - DxvkContextFlag::CpDirtyPipeline, - DxvkContextFlag::CpDirtyResources); + if (rc->getShaderResource(slot).bufferSlice != buffer) { + m_flags.set(this->getResourceDirtyFlag(pipe)); + + DxvkShaderResourceSlot resource; + resource.bufferSlice = buffer; + + DxvkDescriptorInfo descriptor; + + if (buffer.bufferHandle() != VK_NULL_HANDLE) + descriptor.buffer = buffer.descriptorInfo(); + + rc->bindShaderResource(slot, resource, descriptor); + } } - void DxvkContext::bindGraphicsPipeline( - const Rc& pipeline) { - m_state.gp = pipeline; + void DxvkContext::bindResourceTexelBuffer( + VkPipelineBindPoint pipe, + uint32_t slot, + const Rc& bufferView) { + auto rc = this->getShaderResourceSlots(pipe); - m_flags.set( - DxvkContextFlag::GpDirtyPipeline, - DxvkContextFlag::GpDirtyResources, - DxvkContextFlag::GpDirtyVertexBuffers, - DxvkContextFlag::GpDirtyIndexBuffer); + if (rc->getShaderResource(slot).bufferView != bufferView) { + m_flags.set(this->getResourceDirtyFlag(pipe)); + + DxvkShaderResourceSlot resource; + resource.bufferView = bufferView; + + DxvkDescriptorInfo descriptor; + + if (bufferView != nullptr) + descriptor.texelBuffer = bufferView->handle(); + + rc->bindShaderResource(slot, resource, descriptor); + } + } + + + void DxvkContext::bindResourceImage( + VkPipelineBindPoint pipe, + uint32_t slot, + const Rc& image) { + auto rc = this->getShaderResourceSlots(pipe); + + if (rc->getShaderResource(slot).imageView != image) { + m_flags.set(this->getResourceDirtyFlag(pipe)); + + DxvkShaderResourceSlot resource; + resource.imageView = image; + + DxvkDescriptorInfo descriptor; + + if (image != nullptr) { + descriptor.image.imageView = image->handle(); + descriptor.image.imageLayout = image->imageLayout(); + } + + rc->bindShaderResource(slot, resource, descriptor); + } + } + + + void DxvkContext::bindResourceSampler( + VkPipelineBindPoint pipe, + uint32_t slot, + const Rc& sampler) { + auto rc = this->getShaderResourceSlots(pipe); + + if (rc->getShaderResource(slot).sampler != sampler) { + m_flags.set(this->getResourceDirtyFlag(pipe)); + + DxvkShaderResourceSlot resource; + resource.sampler = sampler; + + DxvkDescriptorInfo descriptor; + + if (sampler != nullptr) + descriptor.image.sampler = sampler->handle(); + + rc->bindShaderResource(slot, resource, descriptor); + } } @@ -166,6 +260,8 @@ namespace dxvk { this->commitComputeState(); m_cmd->cmdDispatch(x, y, z); + + this->commitComputeBarriers(); } @@ -335,12 +431,18 @@ namespace dxvk { } - void DxvkContext::bindComputePipeline() { - // TODO implement + void DxvkContext::updateComputePipeline() { + if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) { + m_flags.clr(DxvkContextFlag::CpDirtyPipeline); + + m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, + m_state.cPipe->getPipelineHandle()); + m_cmd->trackResource(m_state.cPipe); + } } - void DxvkContext::bindGraphicsPipeline() { + void DxvkContext::updateGraphicsPipeline() { if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) { m_flags.clr(DxvkContextFlag::GpDirtyPipeline); @@ -355,8 +457,42 @@ namespace dxvk { gpState.viewportCount = m_state.vp.viewportCount; m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, - m_state.gp->getPipelineHandle(gpState)); - m_cmd->trackResource(m_state.gp); + m_state.gPipe->getPipelineHandle(gpState)); + m_cmd->trackResource(m_state.gPipe); + } + } + + + void DxvkContext::updateComputeShaderResources() { + if (m_flags.test(DxvkContextFlag::CpDirtyResources)) { + m_flags.clr(DxvkContextFlag::CpDirtyResources); + + auto layout = m_state.cPipe->layout(); + + m_cmd->bindResourceDescriptors( + VK_PIPELINE_BIND_POINT_COMPUTE, + layout->pipelineLayout(), + layout->descriptorSetLayout(), + layout->bindingCount(), + layout->bindings(), + m_cResources.descriptors()); + } + } + + + void DxvkContext::updateGraphicsShaderResources() { + if (m_flags.test(DxvkContextFlag::GpDirtyResources)) { + m_flags.clr(DxvkContextFlag::GpDirtyResources); + + auto layout = m_state.gPipe->layout(); + + m_cmd->bindResourceDescriptors( + VK_PIPELINE_BIND_POINT_GRAPHICS, + layout->pipelineLayout(), + layout->descriptorSetLayout(), + layout->bindingCount(), + layout->bindings(), + m_gResources.descriptors()); } } @@ -413,16 +549,41 @@ namespace dxvk { void DxvkContext::commitComputeState() { this->renderPassEnd(); - this->bindComputePipeline(); + this->updateComputePipeline(); + this->updateComputeShaderResources(); } void DxvkContext::commitGraphicsState() { this->renderPassBegin(); - this->bindGraphicsPipeline(); + this->updateGraphicsPipeline(); this->updateDynamicState(); this->updateIndexBufferBinding(); this->updateVertexBufferBindings(); + this->updateGraphicsShaderResources(); + } + + + void DxvkContext::commitComputeBarriers() { + // TODO implement + } + + + DxvkShaderResourceSlots* DxvkContext::getShaderResourceSlots(VkPipelineBindPoint pipe) { + switch (pipe) { + case VK_PIPELINE_BIND_POINT_GRAPHICS: return &m_gResources; + case VK_PIPELINE_BIND_POINT_COMPUTE : return &m_cResources; + default: return nullptr; + } + } + + + DxvkContextFlag DxvkContext::getResourceDirtyFlag(VkPipelineBindPoint pipe) const { + switch (pipe) { + default: + case VK_PIPELINE_BIND_POINT_GRAPHICS: return DxvkContextFlag::GpDirtyResources; + case VK_PIPELINE_BIND_POINT_COMPUTE : return DxvkContextFlag::CpDirtyResources; + } } } \ No newline at end of file diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index c1836695..240d031f 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1,6 +1,7 @@ #pragma once #include "dxvk_barrier.h" +#include "dxvk_binding.h" #include "dxvk_cmdlist.h" #include "dxvk_context_state.h" #include "dxvk_data.h" @@ -53,19 +54,8 @@ namespace dxvk { void bindFramebuffer( const Rc& fb); - /** - * \brief Binds index buffer - * \param [in] buffer New index buffer - */ - void bindIndexBuffer( - const DxvkBufferBinding& buffer); - /** * \brief Binds compute pipeline - * - * Note that binding a new pipeline implicitly - * invalidates all resource bindings that are - * used by the pipeline. * \param [in] pipeline The pipeline to bind */ void bindComputePipeline( @@ -73,15 +63,76 @@ namespace dxvk { /** * \brief Binds graphics pipeline - * - * Note that binding a new pipeline implicitly - * invalidates all bindings that are used by - * the pipeline. * \param [in] pipeline The pipeline to bind */ void bindGraphicsPipeline( const Rc& pipeline); + /** + * \brief Binds index buffer + * + * The index buffer will be used when + * issuing \c drawIndexed commands. + * \param [in] buffer New index buffer + */ + void bindIndexBuffer( + const DxvkBufferBinding& buffer); + + /** + * \brief Binds buffer as a shader resource + * + * Can be used for uniform and storage buffers. + * \param [in] pipe Target pipeline + * \param [in] slot Resource binding slot + * \param [in] buffer Buffer to bind + */ + void bindResourceBuffer( + VkPipelineBindPoint pipe, + uint32_t slot, + const DxvkBufferBinding& buffer); + + /** + * \brief Binds texel buffer view + * + * Can be used for both uniform texel + * buffers and storage texel buffers. + * \param [in] pipe Target pipeline + * \param [in] slot Resource binding slot + * \param [in] bufferView Buffer view to bind + */ + void bindResourceTexelBuffer( + VkPipelineBindPoint pipe, + uint32_t slot, + const Rc& bufferView); + + /** + * \brief Binds image view + * + * Can be used for sampled images with a + * dedicated sampler and storage images. + * \param [in] pipe Target pipeline + * \param [in] slot Resource binding slot + * \param [in] imageView Image view to bind + */ + void bindResourceImage( + VkPipelineBindPoint pipe, + uint32_t slot, + const Rc& image); + + /** + * \brief Binds image sampler + * + * Binds a sampler that can be used together with + * an image in order to read from a texture. + * \param [in] pipe Target pipeline + * \param [in] slot Resource binding slot + * \param [in] sampler Sampler view to bind + */ + void bindResourceSampler( + VkPipelineBindPoint pipe, + uint32_t slot, + const Rc& sampler); + /** * \brief Binds vertex buffer * @@ -262,13 +313,17 @@ namespace dxvk { DxvkContextState m_state; DxvkBarrierSet m_barriers; - std::vector m_descriptorSetWrites; + DxvkShaderResourceSlots m_cResources = { 1024 }; + DxvkShaderResourceSlots m_gResources = { 4096 }; void renderPassBegin(); void renderPassEnd(); - void bindComputePipeline(); - void bindGraphicsPipeline(); + void updateComputePipeline(); + void updateGraphicsPipeline(); + + void updateComputeShaderResources(); + void updateGraphicsShaderResources(); void updateDynamicState(); void updateViewports(); @@ -278,6 +333,15 @@ namespace dxvk { void commitComputeState(); void commitGraphicsState(); + + void commitComputeBarriers(); + + DxvkShaderResourceSlots* getShaderResourceSlots( + VkPipelineBindPoint pipe); + + DxvkContextFlag getResourceDirtyFlag( + VkPipelineBindPoint pipe) const; + }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index 8f05b5bc..898289d3 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -7,6 +7,8 @@ #include "dxvk_graphics.h" #include "dxvk_image.h" #include "dxvk_limits.h" +#include "dxvk_pipeline.h" +#include "dxvk_sampler.h" #include "dxvk_shader.h" namespace dxvk { @@ -64,8 +66,8 @@ namespace dxvk { DxvkOutputMergerState om; DxvkConstantStateObjects co; - Rc gp; - Rc cp; + Rc gPipe; + Rc cPipe; }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_descriptor.h b/src/dxvk/dxvk_descriptor.h index 2ccce297..0cf5bde3 100644 --- a/src/dxvk/dxvk_descriptor.h +++ b/src/dxvk/dxvk_descriptor.h @@ -4,6 +4,19 @@ namespace dxvk { + /** + * \brief Descriptor info + * + * Stores information that is required to + * update a single resource descriptor. + */ + struct DxvkDescriptorInfo { + VkDescriptorImageInfo image = { VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED }; + VkDescriptorBufferInfo buffer = { VK_NULL_HANDLE, 0, 0 }; + VkBufferView texelBuffer = VK_NULL_HANDLE; + }; + + /** * \brief Descriptor set allocator * diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index 6a1e03b4..d3732ea0 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -79,6 +79,12 @@ namespace dxvk { } + Rc DxvkDevice::createSampler( + const DxvkSamplerCreateInfo& createInfo) { + return new DxvkSampler(m_vkd, createInfo); + } + + Rc DxvkDevice::createSemaphore() { return new DxvkSemaphore(m_vkd); } @@ -92,8 +98,8 @@ namespace dxvk { Rc DxvkDevice::createBindingLayout( - uint32_t bindingCount, - const DxvkBindingInfo* bindingInfos) { + uint32_t bindingCount, + const DxvkDescriptorSlot* bindingInfos) { return new DxvkBindingLayout(m_vkd, bindingCount, bindingInfos); } diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index 957a29d5..a54ad2f5 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -9,6 +9,7 @@ #include "dxvk_image.h" #include "dxvk_memory.h" #include "dxvk_renderpass.h" +#include "dxvk_sampler.h" #include "dxvk_shader.h" #include "dxvk_swapchain.h" #include "dxvk_sync.h" @@ -141,6 +142,15 @@ namespace dxvk { const Rc& image, const DxvkImageViewCreateInfo& createInfo); + /** + * \brief Creates a sampler object + * + * \param [in] createInfo Sampler parameters + * \returns Newly created sampler object + */ + Rc createSampler( + const DxvkSamplerCreateInfo& createInfo); + /** * \brief Creates a semaphore object * \returns Newly created semaphore @@ -166,8 +176,8 @@ namespace dxvk { * \returns New binding layout */ Rc createBindingLayout( - uint32_t bindingCount, - const DxvkBindingInfo* bindingInfos); + uint32_t bindingCount, + const DxvkDescriptorSlot* bindingInfos); /** * \brief Creates a compute pipeline diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index fde30920..e9dabab7 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -119,7 +119,7 @@ namespace dxvk { info.pDepthStencilState = &state.depthStencilState->info(); info.pColorBlendState = &state.blendState->info(); info.pDynamicState = &dsInfo; - info.layout = this->pipelineLayout(); + info.layout = m_layout->pipelineLayout(); info.renderPass = state.renderPass; info.subpass = 0; info.basePipelineHandle = VK_NULL_HANDLE; diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index 67df245d..06cb0529 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -58,26 +58,16 @@ namespace dxvk { const Rc& fs); ~DxvkGraphicsPipeline(); - /** - * \brief Descriptor set layout - * - * The descriptor set layout for this pipeline. - * Use this to allocate new descriptor sets. - * \returns The descriptor set layout - */ - VkDescriptorSetLayout descriptorSetLayout() const { - return m_layout->descriptorSetLayout(); - } - /** * \brief Pipeline layout * - * The pipeline layout for this pipeline. - * Use this to bind descriptor sets. - * \returns The descriptor set layout + * Stores the pipeline layout and the descriptor set + * layout, as well as information on the resource + * slots used by the pipeline. + * \returns Pipeline layout */ - VkPipelineLayout pipelineLayout() const { - return m_layout->pipelineLayout(); + Rc layout() const { + return m_layout; } /** diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h index 57260a6d..fd92fd64 100644 --- a/src/dxvk/dxvk_image.h +++ b/src/dxvk/dxvk_image.h @@ -178,6 +178,14 @@ namespace dxvk { return m_image; } + /** + * \brief Image layout + * \returns Image layout + */ + VkImageLayout imageLayout() const { + return m_image->info().layout; + } + /** * \brief Subresource range * \returns Subresource range diff --git a/src/dxvk/dxvk_limits.h b/src/dxvk/dxvk_limits.h index b9e3bea5..e1a05fd8 100644 --- a/src/dxvk/dxvk_limits.h +++ b/src/dxvk/dxvk_limits.h @@ -5,11 +5,12 @@ namespace dxvk { enum DxvkLimits : size_t { - MaxNumRenderTargets = 8, - MaxNumVertexAttributes = 32, - MaxNumVertexBindings = 32, - MaxNumOutputStreams = 4, - MaxNumViewports = 16, + MaxNumRenderTargets = 8, + MaxNumVertexAttributes = 32, + MaxNumVertexBindings = 32, + MaxNumOutputStreams = 4, + MaxNumViewports = 16, + MaxNumResourceSlots = 4096, }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_pipeline.cpp b/src/dxvk/dxvk_pipeline.cpp index 7d99a018..1c98aa8b 100644 --- a/src/dxvk/dxvk_pipeline.cpp +++ b/src/dxvk/dxvk_pipeline.cpp @@ -1,29 +1,37 @@ +#include + #include "dxvk_pipeline.h" namespace dxvk { DxvkBindingLayout::DxvkBindingLayout( - const Rc& vkd, - uint32_t bindingCount, - const DxvkBindingInfo* bindingInfos) + const Rc& vkd, + uint32_t bindingCount, + const DxvkDescriptorSlot* bindingInfos) : m_vkd(vkd) { + m_bindingSlots.resize(bindingCount); + std::memcpy(m_bindingSlots.data(), bindingInfos, + bindingCount * sizeof(DxvkDescriptorSlot)); + + std::vector bindings; + for (uint32_t i = 0; i < bindingCount; i++) { VkDescriptorSetLayoutBinding binding; binding.binding = i; binding.descriptorType = bindingInfos[i].type; - binding.descriptorCount = bindingInfos[i].stages == 0 ? 0 : 1; + binding.descriptorCount = 1; binding.stageFlags = bindingInfos[i].stages; binding.pImmutableSamplers = nullptr; - m_bindings.push_back(binding); + bindings.push_back(binding); } VkDescriptorSetLayoutCreateInfo dsetInfo; dsetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; dsetInfo.pNext = nullptr; dsetInfo.flags = 0; - dsetInfo.bindingCount = m_bindings.size(); - dsetInfo.pBindings = m_bindings.data(); + dsetInfo.bindingCount = bindings.size(); + dsetInfo.pBindings = bindings.data(); if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &dsetInfo, nullptr, &m_descriptorSetLayout) != VK_SUCCESS) @@ -59,14 +67,4 @@ namespace dxvk { } } - - DxvkBindingInfo DxvkBindingLayout::binding(uint32_t id) const { - const VkDescriptorSetLayoutBinding& bindingInfo = m_bindings.at(id); - - DxvkBindingInfo result; - result.type = bindingInfo.descriptorType; - result.stages = bindingInfo.stageFlags; - return result; - } - } \ No newline at end of file diff --git a/src/dxvk/dxvk_pipeline.h b/src/dxvk/dxvk_pipeline.h index 1f842f27..664347fa 100644 --- a/src/dxvk/dxvk_pipeline.h +++ b/src/dxvk/dxvk_pipeline.h @@ -11,9 +11,10 @@ namespace dxvk { * Vulkan. DXVK does not use descriptor arrays. * Instead, each binding stores one descriptor. */ - struct DxvkBindingInfo { - VkDescriptorType type; - VkShaderStageFlags stages; + struct DxvkDescriptorSlot { + uint32_t slot; ///< Resource slot index for the context + VkDescriptorType type; ///< Descriptor type (aka resource type) + VkShaderStageFlags stages; ///< Stages that can use the resource }; @@ -28,9 +29,9 @@ namespace dxvk { public: DxvkBindingLayout( - const Rc& vkd, - uint32_t bindingCount, - const DxvkBindingInfo* bindingInfos); + const Rc& vkd, + uint32_t bindingCount, + const DxvkDescriptorSlot* bindingInfos); ~DxvkBindingLayout(); @@ -38,17 +39,17 @@ namespace dxvk { * \brief Number of resource bindings * \returns Resource binding count */ - uint32_t numBindings() const { - return m_bindings.size(); + uint32_t bindingCount() const { + return m_bindingSlots.size(); } /** - * \brief Retrieves binding info - * - * \param [in] binding ID - * \returns Binding info + * \brief Resource binding info + * \returns Resource binding info */ - DxvkBindingInfo binding(uint32_t id) const; + const DxvkDescriptorSlot* bindings() const { + return m_bindingSlots.data(); + } /** * \brief Descriptor set layout handle @@ -73,7 +74,7 @@ namespace dxvk { VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE; VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; - std::vector m_bindings; + std::vector m_bindingSlots; }; diff --git a/src/dxvk/dxvk_sampler.cpp b/src/dxvk/dxvk_sampler.cpp index e69de29b..c7def667 100644 --- a/src/dxvk/dxvk_sampler.cpp +++ b/src/dxvk/dxvk_sampler.cpp @@ -0,0 +1,40 @@ +#include "dxvk_sampler.h" + +namespace dxvk { + + DxvkSampler::DxvkSampler( + const Rc& vkd, + const DxvkSamplerCreateInfo& info) + : m_vkd(vkd), m_info(info) { + VkSamplerCreateInfo samplerInfo; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.pNext = nullptr; + samplerInfo.flags = 0; + samplerInfo.magFilter = info.magFilter; + samplerInfo.minFilter = info.minFilter; + samplerInfo.mipmapMode = info.mipmapMode; + samplerInfo.addressModeU = info.addressModeU; + samplerInfo.addressModeV = info.addressModeV; + samplerInfo.addressModeW = info.addressModeW; + samplerInfo.mipLodBias = info.mipmapLodBias; + samplerInfo.anisotropyEnable = info.useAnisotropy; + samplerInfo.maxAnisotropy = info.maxAnisotropy; + samplerInfo.compareEnable = info.compareToDepth; + samplerInfo.compareOp = info.compareOp; + samplerInfo.minLod = info.mipmapLodMin; + samplerInfo.maxLod = info.mipmapLodMax; + samplerInfo.borderColor = info.borderColor; + samplerInfo.unnormalizedCoordinates = info.usePixelCoord; + + if (m_vkd->vkCreateSampler(m_vkd->device(), + &samplerInfo, nullptr, &m_sampler) != VK_SUCCESS) + throw DxvkError("DxvkSampler::DxvkSampler: Failed to create sampler"); + } + + + DxvkSampler::~DxvkSampler() { + m_vkd->vkDestroySampler( + m_vkd->device(), m_sampler, nullptr); + } + +} diff --git a/src/dxvk/dxvk_sampler.h b/src/dxvk/dxvk_sampler.h index e69de29b..e2ed1ef7 100644 --- a/src/dxvk/dxvk_sampler.h +++ b/src/dxvk/dxvk_sampler.h @@ -0,0 +1,82 @@ +#pragma once + +#include "dxvk_resource.h" + +namespace dxvk { + + /** + * \brief Sampler properties + */ + struct DxvkSamplerCreateInfo { + /// Texture filter propertoes + VkFilter magFilter; + VkFilter minFilter; + + /// Mipmapping properties + VkSamplerMipmapMode mipmapMode; + float mipmapLodBias; + float mipmapLodMin; + float mipmapLodMax; + + /// Anisotropic filtering + VkBool32 useAnisotropy; + float maxAnisotropy; + + /// Address modes + VkSamplerAddressMode addressModeU; + VkSamplerAddressMode addressModeV; + VkSamplerAddressMode addressModeW; + + /// Compare op for shadow textures + VkBool32 compareToDepth; + VkCompareOp compareOp; + + /// Texture border color + VkBorderColor borderColor; + + /// Enables unnormalized coordinates + VkBool32 usePixelCoord; + }; + + + /** + * \brief Sampler + * + * Manages a sampler object that can be bound to + * a pipeline. Sampler objects provide parameters + * for texture lookups within a shader. + */ + class DxvkSampler : public DxvkResource { + + public: + + DxvkSampler( + const Rc& vkd, + const DxvkSamplerCreateInfo& info); + ~DxvkSampler(); + + /** + * \brief Sampler handle + * \returns Sampler handle + */ + VkSampler handle() const { + return m_sampler; + } + + /** + * \brief Sampler parameters + * \returns Sampler parameters + */ + const DxvkSamplerCreateInfo& info() const { + return m_info; + } + + private: + + Rc m_vkd; + DxvkSamplerCreateInfo m_info; + VkSampler m_sampler = VK_NULL_HANDLE; + + }; + +} diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index e7350f28..52a0df48 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -19,6 +19,7 @@ dxvk_src = files([ 'dxvk_pipeline.cpp', 'dxvk_renderpass.cpp', 'dxvk_resource.cpp', + 'dxvk_sampler.cpp', 'dxvk_shader.cpp', 'dxvk_surface.cpp', 'dxvk_swapchain.cpp', diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp index 2feac72f..ce9b7357 100644 --- a/src/spirv/spirv_module.cpp +++ b/src/spirv/spirv_module.cpp @@ -221,6 +221,16 @@ namespace dxvk { } + void SpirvModule::decorateBinding( + uint32_t object, + uint32_t binding) { + m_annotations.putIns (spv::OpDecorate, 4); + m_annotations.putWord (object); + m_annotations.putWord (spv::DecorationBinding); + m_annotations.putInt32(binding); + } + + void SpirvModule::decorateBlock(uint32_t object) { m_annotations.putIns (spv::OpDecorate, 3); m_annotations.putWord (object); @@ -248,6 +258,16 @@ namespace dxvk { } + void SpirvModule::decorateDescriptorSet( + uint32_t object, + uint32_t set) { + m_annotations.putIns (spv::OpDecorate, 4); + m_annotations.putWord (object); + m_annotations.putWord (spv::DecorationDescriptorSet); + m_annotations.putInt32(set); + } + + void SpirvModule::decorateLocation( uint32_t object, uint32_t location) { @@ -378,6 +398,36 @@ namespace dxvk { } + uint32_t SpirvModule::defSamplerType() { + return this->defType(spv::OpTypeSampler, 0, nullptr); + } + + + uint32_t SpirvModule::defImageType( + uint32_t sampledType, + spv::Dim dimensionality, + uint32_t depth, + uint32_t arrayed, + uint32_t multisample, + uint32_t sampled, + spv::ImageFormat format) { + std::array args = { + sampledType, dimensionality, + depth, arrayed, multisample, + sampled, format + }; + + return this->defType(spv::OpTypeImage, + args.size(), args.data()); + } + + + uint32_t SpirvModule::defSampledImageType( + uint32_t imageType) { + return this->defType(spv::OpTypeSampledImage, 1, &imageType); + } + + uint32_t SpirvModule::newVar( uint32_t pointerType, spv::StorageClass storageClass) { @@ -675,6 +725,36 @@ namespace dxvk { } + uint32_t SpirvModule::opSampledImage( + uint32_t resultType, + uint32_t image, + uint32_t sampler) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpSampledImage, 5); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(image); + m_code.putWord(sampler); + return resultId; + } + + + uint32_t SpirvModule::opImageSampleImplicitLod( + uint32_t resultType, + uint32_t sampledImage, + uint32_t coordinates) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpImageSampleImplicitLod, 5); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(sampledImage); + m_code.putWord(coordinates); + return resultId; + } + + void SpirvModule::opReturn() { m_code.putIns (spv::OpReturn, 1); } diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h index a8c8dcf2..d68524e0 100644 --- a/src/spirv/spirv_module.h +++ b/src/spirv/spirv_module.h @@ -81,6 +81,10 @@ namespace dxvk { uint32_t constCount, const uint32_t* constIds); + void decorateBinding( + uint32_t object, + uint32_t binding); + void decorateBlock( uint32_t object); @@ -92,6 +96,10 @@ namespace dxvk { uint32_t object, uint32_t location); + void decorateDescriptorSet( + uint32_t object, + uint32_t set); + void decorateLocation( uint32_t object, uint32_t location); @@ -140,6 +148,20 @@ namespace dxvk { uint32_t variableType, spv::StorageClass storageClass); + uint32_t defSamplerType(); + + uint32_t defImageType( + uint32_t sampledType, + spv::Dim dimensionality, + uint32_t depth, + uint32_t arrayed, + uint32_t multisample, + uint32_t sampled, + spv::ImageFormat format); + + uint32_t defSampledImageType( + uint32_t imageType); + uint32_t newVar( uint32_t pointerType, spv::StorageClass storageClass); @@ -239,6 +261,16 @@ namespace dxvk { uint32_t pointerId, uint32_t valueId); + uint32_t opSampledImage( + uint32_t resultType, + uint32_t image, + uint32_t sampler); + + uint32_t opImageSampleImplicitLod( + uint32_t resultType, + uint32_t sampledImage, + uint32_t coordinates); + void opReturn(); private: diff --git a/tests/d3d11/test_d3d11_triangle.cpp b/tests/d3d11/test_d3d11_triangle.cpp index c927814e..08214a21 100644 --- a/tests/d3d11/test_d3d11_triangle.cpp +++ b/tests/d3d11/test_d3d11_triangle.cpp @@ -63,7 +63,7 @@ public: void run() { - FLOAT color[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + FLOAT color[4] = { 0.8f, 0.2f, 0.2f, 1.0f }; m_context->OMSetRenderTargets(1, &m_bufferView, nullptr); m_context->ClearRenderTargetView(m_bufferView.ptr(), color);