From e59aee131b6d51236613bc374cfa2d5f3b54efe1 Mon Sep 17 00:00:00 2001 From: Yong He Date: Wed, 17 Feb 2021 15:09:09 -0800 Subject: Add `SampleGrad` overload for lod clamp. (#1711) * Add `SampleGrad` overload for lod clamp. * Fix gfx to run the test on vulkan. * Whitespace change to trigger CI build * remove presentFrame call in render-test Co-authored-by: Yong He Co-authored-by: Tim Foley --- source/slang/core.meta.slang | 10 ++ source/slang/slang-reflection-api.cpp | 4 + .../compute/texture-sample-grad-offset-clamp.slang | 85 ++++++++++++++ ...ure-sample-grad-offset-clamp.slang.expected.txt | 1 + tools/gfx/render.h | 2 - tools/gfx/vulkan/render-vk.cpp | 129 +++++++++++++++++---- tools/render-test/render-test-main.cpp | 1 + 7 files changed, 208 insertions(+), 24 deletions(-) create mode 100644 tests/compute/texture-sample-grad-offset-clamp.slang create mode 100644 tests/compute/texture-sample-grad-offset-clamp.slang.expected.txt diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 970ed1fa8..d63311985 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -1358,6 +1358,16 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradY, "; sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; + + sb << "__glsl_extension(GL_ARB_sparse_texture_clamp)"; + sb << "__target_intrinsic(glsl, \"$ctextureGradOffsetClampARB($p, $2, $3, $4, $5, $6)$z\")\n"; + sb << "T SampleGrad(SamplerState s, "; + sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; + sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, "; + sb << "float" << kBaseTextureTypes[tt].coordCount << " gradY, "; + sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset, "; + sb << "float lodClamp);\n"; + } // `SampleLevel` diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp index 1cfb8fecc..cd141a622 100644 --- a/source/slang/slang-reflection-api.cpp +++ b/source/slang/slang-reflection-api.cpp @@ -1148,6 +1148,10 @@ namespace Slang { return SLANG_BINDING_TYPE_CONSTANT_BUFFER; } + else if( as(type) ) + { + return SLANG_BINDING_TYPE_SAMPLER; + } else { return SLANG_BINDING_TYPE_UNKNOWN; diff --git a/tests/compute/texture-sample-grad-offset-clamp.slang b/tests/compute/texture-sample-grad-offset-clamp.slang new file mode 100644 index 000000000..2a7d4d79a --- /dev/null +++ b/tests/compute/texture-sample-grad-offset-clamp.slang @@ -0,0 +1,85 @@ +//TEST(compute, vulkan):COMPARE_RENDER_COMPUTE:-vk -shaderobj +//TEST(compute):COMPARE_RENDER_COMPUTE:-shaderobj + +//TEST_INPUT: Texture2D(size=4, content = one):name=t2D +//TEST_INPUT: Sampler:name=samplerState +//TEST_INPUT: ubuffer(data=[0], stride=4):out,name=outputBuffer + +Texture2D t2D; +SamplerState samplerState; +RWStructuredBuffer outputBuffer; + +cbuffer Uniforms +{ + float4x4 modelViewProjection; +} + +struct AssembledVertex +{ + float3 position; + float3 color; + float2 uv; +}; + +struct CoarseVertex +{ + float3 color; + float2 uv; +}; + +struct Fragment +{ + float4 color; +}; + + +// Vertex Shader + +struct VertexStageInput +{ + AssembledVertex assembledVertex : A; +}; + +struct VertexStageOutput +{ + CoarseVertex coarseVertex : CoarseVertex; + float4 sv_position : SV_Position; +}; + +VertexStageOutput vertexMain(VertexStageInput input) +{ + VertexStageOutput output; + + float3 position = input.assembledVertex.position; + float3 color = input.assembledVertex.color; + + output.coarseVertex.color = color; + output.sv_position = mul(modelViewProjection, float4(position, 1.0)); + output.coarseVertex.uv = input.assembledVertex.uv; + return output; +} + +// Fragment Shader + +struct FragmentStageInput +{ + CoarseVertex coarseVertex : CoarseVertex; +}; + +struct FragmentStageOutput +{ + Fragment fragment : SV_Target; +}; + +FragmentStageOutput fragmentMain(FragmentStageInput input) +{ + FragmentStageOutput output; + + float3 color = input.coarseVertex.color; + float2 uv = input.coarseVertex.uv; + output.fragment.color = float4(color, 1.0); + + float4 val = t2D.SampleGrad(samplerState, uv, float2(0,0), float2(0,0), 0, 0.5f); + outputBuffer[0] = val.x; + return output; +} diff --git a/tests/compute/texture-sample-grad-offset-clamp.slang.expected.txt b/tests/compute/texture-sample-grad-offset-clamp.slang.expected.txt new file mode 100644 index 000000000..47b9ba0c8 --- /dev/null +++ b/tests/compute/texture-sample-grad-offset-clamp.slang.expected.txt @@ -0,0 +1 @@ +3F800000 \ No newline at end of file diff --git a/tools/gfx/render.h b/tools/gfx/render.h index e783273ee..053f9e1e2 100644 --- a/tools/gfx/render.h +++ b/tools/gfx/render.h @@ -1039,8 +1039,6 @@ struct GraphicsPipelineStateDesc IPipelineLayout* pipelineLayout = nullptr; IInputLayout* inputLayout; - UInt framebufferWidth; - UInt framebufferHeight; UInt renderTargetCount = 0; // Only used if `pipelineLayout` is non-null DepthStencilDesc depthStencil; RasterizerDesc rasterizer; diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp index f58a81b8d..6bfd58dda 100644 --- a/tools/gfx/vulkan/render-vk.cpp +++ b/tools/gfx/vulkan/render-vk.cpp @@ -249,6 +249,14 @@ public: } public: VkSampler m_sampler; + const VulkanApi* m_api; + SamplerStateImpl(const VulkanApi* api) + : m_api(api) + {} + ~SamplerStateImpl() + { + m_api->vkDestroySampler(m_api->m_device, m_sampler, nullptr); + } }; class ResourceViewImpl : public IResourceView, public RefObject @@ -268,17 +276,26 @@ public: TexelBuffer, PlainBuffer, }; + public: + ResourceViewImpl(ViewType viewType, const VulkanApi* api) + : m_type(viewType), m_api(api) + { + } ViewType m_type; + const VulkanApi* m_api; }; class TextureResourceViewImpl : public ResourceViewImpl { public: - TextureResourceViewImpl() + TextureResourceViewImpl(const VulkanApi* api) + : ResourceViewImpl(ViewType::Texture, api) { - m_type = ViewType::Texture; } - + ~TextureResourceViewImpl() + { + m_api->vkDestroyImageView(m_api->m_device, m_view, nullptr); + } RefPtr m_texture; VkImageView m_view; VkImageLayout m_layout; @@ -287,11 +304,14 @@ public: class TexelBufferResourceViewImpl : public ResourceViewImpl { public: - TexelBufferResourceViewImpl() + TexelBufferResourceViewImpl(const VulkanApi* api) + : ResourceViewImpl(ViewType::TexelBuffer, api) { - m_type = ViewType::TexelBuffer; } - + ~TexelBufferResourceViewImpl() + { + m_api->vkDestroyBufferView(m_api->m_device, m_view, nullptr); + } RefPtr m_buffer; VkBufferView m_view; }; @@ -299,11 +319,10 @@ public: class PlainBufferResourceViewImpl : public ResourceViewImpl { public: - PlainBufferResourceViewImpl() + PlainBufferResourceViewImpl(const VulkanApi* api) + : ResourceViewImpl(ViewType::PlainBuffer, api) { - m_type = ViewType::PlainBuffer; } - RefPtr m_buffer; VkDeviceSize offset; VkDeviceSize size; @@ -1989,7 +2008,7 @@ Result VKRenderer::createSamplerState(ISamplerState::Desc const& desc, ISamplerS VkSampler sampler; SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateSampler(m_device, &samplerInfo, nullptr, &sampler)); - RefPtr samplerImpl = new SamplerStateImpl(); + RefPtr samplerImpl = new SamplerStateImpl(&m_api); samplerImpl->m_sampler = sampler; *outSampler = samplerImpl.detach(); return SLANG_OK; @@ -1997,8 +2016,60 @@ Result VKRenderer::createSamplerState(ISamplerState::Desc const& desc, ISamplerS Result VKRenderer::createTextureView(ITextureResource* texture, IResourceView::Desc const& desc, IResourceView** outView) { - assert(!"unimplemented"); - return SLANG_FAIL; + auto resourceImpl = static_cast(texture); + RefPtr view = new TextureResourceViewImpl(&m_api); + view->m_texture = resourceImpl; + VkImageViewCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.flags = 0; + createInfo.format = VulkanUtil::getVkFormat(desc.format); + createInfo.image = resourceImpl->m_image; + createInfo.components = VkComponentMapping{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,VK_COMPONENT_SWIZZLE_B,VK_COMPONENT_SWIZZLE_A }; + switch (resourceImpl->getType()) + { + case IResource::Type::Texture1D: + createInfo.viewType = VK_IMAGE_VIEW_TYPE_1D; + break; + case IResource::Type::Texture2D: + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + break; + case IResource::Type::Texture3D: + createInfo.viewType = VK_IMAGE_VIEW_TYPE_3D; + break; + case IResource::Type::TextureCube: + createInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; + break; + default: + SLANG_UNIMPLEMENTED_X("Unknown Texture type."); + break; + } + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + createInfo.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + switch (desc.type) + { + case IResourceView::Type::DepthStencil: + view->m_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + break; + case IResourceView::Type::RenderTarget: + view->m_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + break; + case IResourceView::Type::ShaderResource: + view->m_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + break; + case IResourceView::Type::UnorderedAccess: + view->m_layout = VK_IMAGE_LAYOUT_GENERAL; + break; + default: + SLANG_UNIMPLEMENTED_X("Unknown TextureViewDesc type."); + break; + } + m_api.vkCreateImageView(m_device, &createInfo, nullptr, &view->m_view); + *outView = view.detach(); + return SLANG_OK; } Result VKRenderer::createBufferView(IBufferResource* buffer, IResourceView::Desc const& desc, IResourceView** outView) @@ -2041,7 +2112,7 @@ Result VKRenderer::createBufferView(IBufferResource* buffer, IResourceView::Desc { // Buffer usage that doesn't involve formatting doesn't // require a view in Vulkan. - RefPtr viewImpl = new PlainBufferResourceViewImpl(); + RefPtr viewImpl = new PlainBufferResourceViewImpl(&m_api); viewImpl->m_buffer = resourceImpl; viewImpl->offset = 0; viewImpl->size = size; @@ -2065,7 +2136,7 @@ Result VKRenderer::createBufferView(IBufferResource* buffer, IResourceView::Desc VkBufferView view; SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateBufferView(m_device, &info, nullptr, &view)); - RefPtr viewImpl = new TexelBufferResourceViewImpl(); + RefPtr viewImpl = new TexelBufferResourceViewImpl(&m_api); viewImpl->m_buffer = resourceImpl; viewImpl->m_view = view; *outView = viewImpl.detach(); @@ -2698,7 +2769,6 @@ void VKRenderer::DescriptorSetImpl::setResource(UInt range, UInt index, IResourc VkDescriptorImageInfo imageInfo = {}; imageInfo.imageView = textureViewImpl->m_view; imageInfo.imageLayout = textureViewImpl->m_layout; - // imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; writeInfo.dstSet = m_descriptorSet; @@ -2762,7 +2832,16 @@ void VKRenderer::DescriptorSetImpl::setSampler(UInt range, UInt index, ISamplerS auto boundObjectIndex = rangeInfo.arrayIndex + index; auto descriptorType = rangeInfo.vkDescriptorType; - // TODO: Actually bind it! + VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + writeInfo.dstSet = m_descriptorSet; + writeInfo.dstBinding = uint32_t(bindingIndex); + writeInfo.dstArrayElement = uint32_t(index); + writeInfo.descriptorCount = 1; + writeInfo.descriptorType = descriptorType; + VkDescriptorImageInfo imageInfo = {}; + imageInfo.sampler = static_cast(sampler)->m_sampler; + writeInfo.pImageInfo = &imageInfo; + m_renderer->m_api.vkUpdateDescriptorSets(m_renderer->m_device, 1, &writeInfo, 0, nullptr); m_boundObjects[boundObjectIndex] = dynamic_cast(sampler); } @@ -2885,9 +2964,6 @@ Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout; auto inputLayoutImpl = (InputLayoutImpl*) desc.inputLayout; - const int width = int(desc.framebufferWidth); - const int height = int(desc.framebufferHeight); - // Shader Stages // // Currently only handles vertex/fragment. @@ -2932,14 +3008,16 @@ Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& VkViewport viewport = {}; viewport.x = 0.0f; viewport.y = 0.0f; - viewport.width = (float)width; - viewport.height = (float)height; + // We are using dynamic viewport and scissor state. + // Here we specify an arbitrary size, actual viewport will be set at `beginRenderPass` time. + viewport.width = 16.0f; + viewport.height = 16.0f; viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; VkRect2D scissor = {}; scissor.offset = { 0, 0 }; - scissor.extent = { uint32_t(width), uint32_t(height) }; + scissor.extent = { uint32_t(16), uint32_t(16) }; VkPipelineViewportStateCreateInfo viewportState = {}; viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; @@ -2978,6 +3056,12 @@ Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; + VkPipelineDynamicStateCreateInfo dynamicStateInfo = {}; + dynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicStateInfo.dynamicStateCount = 2; + VkDynamicState dynamicStates[] = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR}; + dynamicStateInfo.pDynamicStates = dynamicStates; + VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -2993,6 +3077,7 @@ Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& pipelineInfo.renderPass = m_renderPass; pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + pipelineInfo.pDynamicState = &dynamicStateInfo; VkPipeline pipeline = VK_NULL_HANDLE; SLANG_VK_CHECK(m_api.vkCreateGraphicsPipelines(m_device, pipelineCache, 1, &pipelineInfo, nullptr, &pipeline)); diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp index 77708461c..e57e3917e 100644 --- a/tools/render-test/render-test-main.cpp +++ b/tools/render-test/render-test-main.cpp @@ -357,6 +357,7 @@ SlangResult _assignVarsFromLayout( IResourceView::Desc viewDesc; viewDesc.type = IResourceView::Type::ShaderResource; + viewDesc.format = texture->getDesc()->format; auto textureView = renderer->createTextureView( texture, viewDesc); -- cgit v1.2.3