diff --git a/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn index 06339153f1..cecfc1e903 100644 --- a/src/dawn_native/BUILD.gn +++ b/src/dawn_native/BUILD.gn @@ -499,6 +499,8 @@ source_set("dawn_native_sources") { "vulkan/NativeSwapChainImplVk.h", "vulkan/PipelineLayoutVk.cpp", "vulkan/PipelineLayoutVk.h", + "vulkan/QuerySetVk.cpp", + "vulkan/QuerySetVk.h", "vulkan/QueueVk.cpp", "vulkan/QueueVk.h", "vulkan/RenderPassCache.cpp", diff --git a/src/dawn_native/CMakeLists.txt b/src/dawn_native/CMakeLists.txt index c7f08080f3..afac9c5cd9 100644 --- a/src/dawn_native/CMakeLists.txt +++ b/src/dawn_native/CMakeLists.txt @@ -396,6 +396,8 @@ if (DAWN_ENABLE_VULKAN) "vulkan/NativeSwapChainImplVk.h" "vulkan/PipelineLayoutVk.cpp" "vulkan/PipelineLayoutVk.h" + "vulkan/QuerySetVk.cpp" + "vulkan/QuerySetVk.h" "vulkan/QueueVk.cpp" "vulkan/QueueVk.h" "vulkan/RenderPassCache.cpp" diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp index 818af70b1c..01ba55ce46 100644 --- a/src/dawn_native/vulkan/DeviceVk.cpp +++ b/src/dawn_native/vulkan/DeviceVk.cpp @@ -28,6 +28,7 @@ #include "dawn_native/vulkan/ComputePipelineVk.h" #include "dawn_native/vulkan/FencedDeleter.h" #include "dawn_native/vulkan/PipelineLayoutVk.h" +#include "dawn_native/vulkan/QuerySetVk.h" #include "dawn_native/vulkan/QueueVk.h" #include "dawn_native/vulkan/RenderPassCache.h" #include "dawn_native/vulkan/RenderPipelineVk.h" @@ -125,7 +126,7 @@ namespace dawn_native { namespace vulkan { return PipelineLayout::Create(this, descriptor); } ResultOrError Device::CreateQuerySetImpl(const QuerySetDescriptor* descriptor) { - return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation"); + return QuerySet::Create(this, descriptor); } ResultOrError Device::CreateRenderPipelineImpl( const RenderPipelineDescriptor* descriptor) { @@ -318,6 +319,12 @@ namespace dawn_native { namespace vulkan { usedKnobs.features.textureCompressionBC = VK_TRUE; } + if (IsExtensionEnabled(Extension::PipelineStatisticsQuery)) { + ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.pipelineStatisticsQuery == + VK_TRUE); + usedKnobs.features.pipelineStatisticsQuery = VK_TRUE; + } + if (IsExtensionEnabled(Extension::ShaderFloat16)) { const VulkanDeviceInfo& deviceInfo = ToBackend(GetAdapter())->GetDeviceInfo(); ASSERT(deviceInfo.HasExt(DeviceExt::ShaderFloat16Int8) && diff --git a/src/dawn_native/vulkan/FencedDeleter.cpp b/src/dawn_native/vulkan/FencedDeleter.cpp index 388eb93b2e..42a42373e2 100644 --- a/src/dawn_native/vulkan/FencedDeleter.cpp +++ b/src/dawn_native/vulkan/FencedDeleter.cpp @@ -30,6 +30,7 @@ namespace dawn_native { namespace vulkan { ASSERT(mMemoriesToDelete.Empty()); ASSERT(mPipelinesToDelete.Empty()); ASSERT(mPipelineLayoutsToDelete.Empty()); + ASSERT(mQueryPoolsToDelete.Empty()); ASSERT(mRenderPassesToDelete.Empty()); ASSERT(mSamplersToDelete.Empty()); ASSERT(mSemaphoresToDelete.Empty()); @@ -70,6 +71,10 @@ namespace dawn_native { namespace vulkan { mPipelineLayoutsToDelete.Enqueue(layout, mDevice->GetPendingCommandSerial()); } + void FencedDeleter::DeleteWhenUnused(VkQueryPool querypool) { + mQueryPoolsToDelete.Enqueue(querypool, mDevice->GetPendingCommandSerial()); + } + void FencedDeleter::DeleteWhenUnused(VkRenderPass renderPass) { mRenderPassesToDelete.Enqueue(renderPass, mDevice->GetPendingCommandSerial()); } @@ -164,6 +169,11 @@ namespace dawn_native { namespace vulkan { } mDescriptorPoolsToDelete.ClearUpTo(completedSerial); + for (VkQueryPool pool : mQueryPoolsToDelete.IterateUpTo(completedSerial)) { + mDevice->fn.DestroyQueryPool(vkDevice, pool, nullptr); + } + mQueryPoolsToDelete.ClearUpTo(completedSerial); + for (VkSampler sampler : mSamplersToDelete.IterateUpTo(completedSerial)) { mDevice->fn.DestroySampler(vkDevice, sampler, nullptr); } diff --git a/src/dawn_native/vulkan/FencedDeleter.h b/src/dawn_native/vulkan/FencedDeleter.h index 7200eda94d..9e516b1006 100644 --- a/src/dawn_native/vulkan/FencedDeleter.h +++ b/src/dawn_native/vulkan/FencedDeleter.h @@ -36,6 +36,7 @@ namespace dawn_native { namespace vulkan { void DeleteWhenUnused(VkPipelineLayout layout); void DeleteWhenUnused(VkRenderPass renderPass); void DeleteWhenUnused(VkPipeline pipeline); + void DeleteWhenUnused(VkQueryPool querypool); void DeleteWhenUnused(VkSampler sampler); void DeleteWhenUnused(VkSemaphore semaphore); void DeleteWhenUnused(VkShaderModule module); @@ -54,6 +55,7 @@ namespace dawn_native { namespace vulkan { SerialQueue mImageViewsToDelete; SerialQueue mPipelinesToDelete; SerialQueue mPipelineLayoutsToDelete; + SerialQueue mQueryPoolsToDelete; SerialQueue mRenderPassesToDelete; SerialQueue mSamplersToDelete; SerialQueue mSemaphoresToDelete; diff --git a/src/dawn_native/vulkan/QuerySetVk.cpp b/src/dawn_native/vulkan/QuerySetVk.cpp new file mode 100644 index 0000000000..0d740a63ff --- /dev/null +++ b/src/dawn_native/vulkan/QuerySetVk.cpp @@ -0,0 +1,112 @@ +// Copyright 2020 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/vulkan/QuerySetVk.h" + +#include "dawn_native/vulkan/DeviceVk.h" +#include "dawn_native/vulkan/FencedDeleter.h" +#include "dawn_native/vulkan/VulkanError.h" +#include "dawn_platform/DawnPlatform.h" + +namespace dawn_native { namespace vulkan { + + namespace { + VkQueryType VulkanQueryType(wgpu::QueryType type) { + switch (type) { + case wgpu::QueryType::Occlusion: + return VK_QUERY_TYPE_OCCLUSION; + case wgpu::QueryType::PipelineStatistics: + return VK_QUERY_TYPE_PIPELINE_STATISTICS; + case wgpu::QueryType::Timestamp: + return VK_QUERY_TYPE_TIMESTAMP; + default: + UNREACHABLE(); + } + } + + VkQueryPipelineStatisticFlags VulkanQueryPipelineStatisticFlags( + std::vector pipelineStatisticsSet) { + VkQueryPipelineStatisticFlags pipelineStatistics = 0; + for (size_t i = 0; i < pipelineStatisticsSet.size(); ++i) { + switch (pipelineStatisticsSet[i]) { + case wgpu::PipelineStatisticName::ClipperInvocations: + pipelineStatistics |= VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT; + break; + case wgpu::PipelineStatisticName::ClipperPrimitivesOut: + pipelineStatistics |= VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT; + break; + case wgpu::PipelineStatisticName::ComputeShaderInvocations: + pipelineStatistics |= + VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT; + break; + case wgpu::PipelineStatisticName::FragmentShaderInvocations: + pipelineStatistics |= + VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT; + break; + case wgpu::PipelineStatisticName::VertexShaderInvocations: + pipelineStatistics |= + VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT; + break; + default: + UNREACHABLE(); + break; + } + } + + return pipelineStatistics; + } + } // anonymous namespace + + // static + ResultOrError QuerySet::Create(Device* device, + const QuerySetDescriptor* descriptor) { + Ref queryset = AcquireRef(new QuerySet(device, descriptor)); + DAWN_TRY(queryset->Initialize()); + return queryset.Detach(); + } + + MaybeError QuerySet::Initialize() { + VkQueryPoolCreateInfo createInfo; + createInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.queryType = VulkanQueryType(GetQueryType()); + createInfo.queryCount = GetQueryCount(); + if (GetQueryType() == wgpu::QueryType::PipelineStatistics) { + createInfo.pipelineStatistics = + VulkanQueryPipelineStatisticFlags(GetPipelineStatistics()); + } + + Device* device = ToBackend(GetDevice()); + return CheckVkOOMThenSuccess( + device->fn.CreateQueryPool(device->GetVkDevice(), &createInfo, nullptr, &*mHandle), + "vkCreateQueryPool"); + } + + VkQueryPool QuerySet::GetHandle() const { + return mHandle; + } + + QuerySet::~QuerySet() { + DestroyInternal(); + } + + void QuerySet::DestroyImpl() { + if (mHandle != VK_NULL_HANDLE) { + ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(mHandle); + mHandle = VK_NULL_HANDLE; + } + } + +}} // namespace dawn_native::vulkan diff --git a/src/dawn_native/vulkan/QuerySetVk.h b/src/dawn_native/vulkan/QuerySetVk.h new file mode 100644 index 0000000000..18cd001290 --- /dev/null +++ b/src/dawn_native/vulkan/QuerySetVk.h @@ -0,0 +1,45 @@ +// Copyright 2020 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_VULKAN_QUERYSETVK_H_ +#define DAWNNATIVE_VULKAN_QUERYSETVK_H_ + +#include "dawn_native/QuerySet.h" + +#include "common/vulkan_platform.h" + +namespace dawn_native { namespace vulkan { + + class Device; + + class QuerySet final : public QuerySetBase { + public: + static ResultOrError Create(Device* device, + const QuerySetDescriptor* descriptor); + + VkQueryPool GetHandle() const; + + private: + ~QuerySet() override; + using QuerySetBase::QuerySetBase; + MaybeError Initialize(); + + void DestroyImpl() override; + + VkQueryPool mHandle = VK_NULL_HANDLE; + }; + +}} // namespace dawn_native::vulkan + +#endif // DAWNNATIVE_VULKAN_QUERYSETVK_H_ diff --git a/src/tests/end2end/QueryTests.cpp b/src/tests/end2end/QueryTests.cpp index 5436021842..47ccdd06f5 100644 --- a/src/tests/end2end/QueryTests.cpp +++ b/src/tests/end2end/QueryTests.cpp @@ -57,7 +57,7 @@ TEST_P(OcclusionQueryTests, QuerySetDestroy) { querySet.Destroy(); } -DAWN_INSTANTIATE_TEST(OcclusionQueryTests, D3D12Backend()); +DAWN_INSTANTIATE_TEST(OcclusionQueryTests, D3D12Backend(), VulkanBackend()); class PipelineStatisticsQueryTests : public QueryTests { protected: @@ -91,7 +91,7 @@ TEST_P(PipelineStatisticsQueryTests, QuerySetCreation) { device.CreateQuerySet(&descriptor); } -DAWN_INSTANTIATE_TEST(PipelineStatisticsQueryTests, D3D12Backend()); +DAWN_INSTANTIATE_TEST(PipelineStatisticsQueryTests, D3D12Backend(), VulkanBackend()); class TimestampExpectation : public detail::Expectation { public: