Query API: QuerySet
- Add QuerySet w/o backends implementation.
- Add validation tests
Bug: dawn:434
Change-Id: Id9fed4e42fac464b1254cd2e9cf5337a1d803089
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/22440
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Hao Li <hao.x.li@intel.com>
diff --git a/dawn.json b/dawn.json
index a9f278b..aa26700 100644
--- a/dawn.json
+++ b/dawn.json
@@ -636,6 +636,13 @@
{"name": "callback", "type": "error callback"},
{"name": "userdata", "type": "void", "annotation": "*"}
]
+ },
+ {
+ "name": "create query set",
+ "returns": "query set",
+ "args": [
+ {"name": "descriptor", "type": "query set descriptor", "annotation": "const*"}
+ ]
}
]
},
@@ -854,6 +861,16 @@
{"name": "bind group layouts", "type": "bind group layout", "annotation": "const*", "length": "bind group layout count"}
]
},
+ "pipeline statistics name": {
+ "category": "enum",
+ "values": [
+ {"value": 0, "name": "vertex shader invocations"},
+ {"value": 1, "name": "clipper invocations"},
+ {"value": 2, "name": "clipper primitives out"},
+ {"value": 3, "name": "fragment shader invocations"},
+ {"value": 4, "name": "compute shader invocations"}
+ ]
+ },
"present mode": {
"category": "enum",
"values": [
@@ -880,6 +897,33 @@
{"value": 4, "name": "triangle strip"}
]
},
+ "query set": {
+ "category": "object",
+ "methods": [
+ {
+ "name": "destroy"
+ }
+ ]
+ },
+ "query set descriptor": {
+ "category": "structure",
+ "extensible": true,
+ "members": [
+ {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+ {"name": "type", "type": "query type"},
+ {"name": "count", "type": "uint32_t"},
+ {"name": "pipeline statistics count", "type": "uint32_t", "default": "0"},
+ {"name": "pipeline statistics", "type": "pipeline statistics name", "annotation": "const*", "length": "pipeline statistics count"}
+ ]
+ },
+ "query type": {
+ "category": "enum",
+ "values": [
+ {"value": 0, "name": "occlusion"},
+ {"value": 1, "name": "pipeline statistics"},
+ {"value": 2, "name": "timestamp"}
+ ]
+ },
"queue": {
"category": "object",
"methods": [
diff --git a/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn
index 25f02f9..3f24ba3 100644
--- a/src/dawn_native/BUILD.gn
+++ b/src/dawn_native/BUILD.gn
@@ -230,6 +230,8 @@
"PipelineLayout.h",
"ProgrammablePassEncoder.cpp",
"ProgrammablePassEncoder.h",
+ "QuerySet.cpp",
+ "QuerySet.h",
"Queue.cpp",
"Queue.h",
"RenderBundle.cpp",
@@ -442,6 +444,8 @@
"opengl/PipelineGL.h",
"opengl/PipelineLayoutGL.cpp",
"opengl/PipelineLayoutGL.h",
+ "opengl/QuerySetGL.cpp",
+ "opengl/QuerySetGL.h",
"opengl/QueueGL.cpp",
"opengl/QueueGL.h",
"opengl/RenderPipelineGL.cpp",
diff --git a/src/dawn_native/CMakeLists.txt b/src/dawn_native/CMakeLists.txt
index c51ae82..7cee0d0 100644
--- a/src/dawn_native/CMakeLists.txt
+++ b/src/dawn_native/CMakeLists.txt
@@ -102,6 +102,8 @@
"PipelineLayout.h"
"ProgrammablePassEncoder.cpp"
"ProgrammablePassEncoder.h"
+ "QuerySet.cpp"
+ "QuerySet.h"
"Queue.cpp"
"Queue.h"
"RenderBundle.cpp"
@@ -333,6 +335,8 @@
"opengl/PipelineGL.h"
"opengl/PipelineLayoutGL.cpp"
"opengl/PipelineLayoutGL.h"
+ "opengl/QuerySetGL.cpp"
+ "opengl/QuerySetGL.h"
"opengl/QueueGL.cpp"
"opengl/QueueGL.h"
"opengl/RenderPipelineGL.cpp"
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 01fc874..73bbcf9 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -32,6 +32,7 @@
#include "dawn_native/Instance.h"
#include "dawn_native/MapRequestTracker.h"
#include "dawn_native/PipelineLayout.h"
+#include "dawn_native/QuerySet.h"
#include "dawn_native/Queue.h"
#include "dawn_native/RenderBundleEncoder.h"
#include "dawn_native/RenderPipeline.h"
@@ -647,6 +648,15 @@
return result;
}
+ QuerySetBase* DeviceBase::CreateQuerySet(const QuerySetDescriptor* descriptor) {
+ QuerySetBase* result = nullptr;
+
+ if (ConsumedError(CreateQuerySetInternal(&result, descriptor))) {
+ return QuerySetBase::MakeError(this);
+ }
+
+ return result;
+ }
QueueBase* DeviceBase::CreateQueue() {
// TODO(dawn:22): Remove this once users use GetDefaultQueue
EmitDeprecationWarning(
@@ -884,6 +894,16 @@
return {};
}
+ MaybeError DeviceBase::CreateQuerySetInternal(QuerySetBase** result,
+ const QuerySetDescriptor* descriptor) {
+ DAWN_TRY(ValidateIsAlive());
+ if (IsValidationEnabled()) {
+ DAWN_TRY(ValidateQuerySetDescriptor(this, descriptor));
+ }
+ DAWN_TRY_ASSIGN(*result, CreateQuerySetImpl(descriptor));
+ return {};
+ }
+
MaybeError DeviceBase::CreateRenderBundleEncoderInternal(
RenderBundleEncoder** result,
const RenderBundleEncoderDescriptor* descriptor) {
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 9e336ac..b94f762 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -146,6 +146,7 @@
CommandEncoder* CreateCommandEncoder(const CommandEncoderDescriptor* descriptor);
ComputePipelineBase* CreateComputePipeline(const ComputePipelineDescriptor* descriptor);
PipelineLayoutBase* CreatePipelineLayout(const PipelineLayoutDescriptor* descriptor);
+ QuerySetBase* CreateQuerySet(const QuerySetDescriptor* descriptor);
QueueBase* CreateQueue();
RenderBundleEncoder* CreateRenderBundleEncoder(
const RenderBundleEncoderDescriptor* descriptor);
@@ -239,6 +240,8 @@
const ComputePipelineDescriptor* descriptor) = 0;
virtual ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const PipelineLayoutDescriptor* descriptor) = 0;
+ virtual ResultOrError<QuerySetBase*> CreateQuerySetImpl(
+ const QuerySetDescriptor* descriptor) = 0;
virtual ResultOrError<RenderPipelineBase*> CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) = 0;
virtual ResultOrError<SamplerBase*> CreateSamplerImpl(
@@ -267,6 +270,8 @@
const ComputePipelineDescriptor* descriptor);
MaybeError CreatePipelineLayoutInternal(PipelineLayoutBase** result,
const PipelineLayoutDescriptor* descriptor);
+ MaybeError CreateQuerySetInternal(QuerySetBase** result,
+ const QuerySetDescriptor* descriptor);
MaybeError CreateRenderBundleEncoderInternal(
RenderBundleEncoder** result,
const RenderBundleEncoderDescriptor* descriptor);
diff --git a/src/dawn_native/Forward.h b/src/dawn_native/Forward.h
index be7c98f..66e07e4 100644
--- a/src/dawn_native/Forward.h
+++ b/src/dawn_native/Forward.h
@@ -34,6 +34,7 @@
class InstanceBase;
class PipelineBase;
class PipelineLayoutBase;
+ class QuerySetBase;
class QueueBase;
class RenderBundleBase;
class RenderBundleEncoder;
diff --git a/src/dawn_native/QuerySet.cpp b/src/dawn_native/QuerySet.cpp
new file mode 100644
index 0000000..513658d
--- /dev/null
+++ b/src/dawn_native/QuerySet.cpp
@@ -0,0 +1,153 @@
+// 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/QuerySet.h"
+
+#include "dawn_native/Device.h"
+#include "dawn_native/Extensions.h"
+#include "dawn_native/ValidationUtils_autogen.h"
+
+#include <set>
+
+namespace dawn_native {
+
+ namespace {
+
+ class ErrorQuerySet final : public QuerySetBase {
+ public:
+ ErrorQuerySet(DeviceBase* device) : QuerySetBase(device, ObjectBase::kError) {
+ }
+
+ private:
+ void DestroyImpl() override {
+ UNREACHABLE();
+ }
+ };
+
+ } // anonymous namespace
+
+ MaybeError ValidateQuerySetDescriptor(DeviceBase* device,
+ const QuerySetDescriptor* descriptor) {
+ if (descriptor->nextInChain != nullptr) {
+ return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
+ }
+
+ DAWN_TRY(ValidateQueryType(descriptor->type));
+
+ switch (descriptor->type) {
+ case wgpu::QueryType::Occlusion:
+ if (descriptor->pipelineStatisticsCount != 0) {
+ return DAWN_VALIDATION_ERROR(
+ "The pipeline statistics should not be set if query type is Occlusion");
+ }
+ break;
+
+ case wgpu::QueryType::PipelineStatistics: {
+ if (!device->IsExtensionEnabled(Extension::PipelineStatisticsQuery)) {
+ return DAWN_VALIDATION_ERROR(
+ "The pipeline statistics query feature is not supported");
+ }
+
+ if (descriptor->pipelineStatisticsCount == 0) {
+ return DAWN_VALIDATION_ERROR(
+ "At least one pipeline statistics is set if query type is "
+ "PipelineStatistics");
+ }
+
+ std::set<wgpu::PipelineStatisticsName> pipelineStatisticsSet;
+ for (uint32_t i = 0; i < descriptor->pipelineStatisticsCount; i++) {
+ DAWN_TRY(ValidatePipelineStatisticsName(descriptor->pipelineStatistics[i]));
+
+ std::pair<std::set<wgpu::PipelineStatisticsName>::iterator, bool> res =
+ pipelineStatisticsSet.insert((descriptor->pipelineStatistics[i]));
+ if (!res.second) {
+ return DAWN_VALIDATION_ERROR("Duplicate pipeline statistics found");
+ }
+ }
+ } break;
+
+ case wgpu::QueryType::Timestamp:
+ if (!device->IsExtensionEnabled(Extension::TimestampQuery)) {
+ return DAWN_VALIDATION_ERROR("The timestamp query feature is not supported");
+ }
+
+ if (descriptor->pipelineStatisticsCount != 0) {
+ return DAWN_VALIDATION_ERROR(
+ "The pipeline statistics should not be set if query type is Timestamp");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return {};
+ }
+
+ QuerySetBase::QuerySetBase(DeviceBase* device, const QuerySetDescriptor* descriptor)
+ : ObjectBase(device),
+ mQueryType(descriptor->type),
+ mQueryCount(descriptor->count),
+ mState(QuerySetState::Available) {
+ for (uint32_t i = 0; i < descriptor->pipelineStatisticsCount; i++) {
+ mPipelineStatistics.push_back(descriptor->pipelineStatistics[i]);
+ }
+ }
+
+ QuerySetBase::QuerySetBase(DeviceBase* device, ObjectBase::ErrorTag tag)
+ : ObjectBase(device, tag) {
+ }
+
+ QuerySetBase::~QuerySetBase() {
+ // Uninitialized or already destroyed
+ ASSERT(mState == QuerySetState::Unavailable || mState == QuerySetState::Destroyed);
+ }
+
+ // static
+ QuerySetBase* QuerySetBase::MakeError(DeviceBase* device) {
+ return new ErrorQuerySet(device);
+ }
+
+ wgpu::QueryType QuerySetBase::GetQueryType() const {
+ return mQueryType;
+ }
+
+ uint32_t QuerySetBase::GetQueryCount() const {
+ return mQueryCount;
+ }
+
+ const std::vector<wgpu::PipelineStatisticsName>& QuerySetBase::GetPipelineStatistics() const {
+ return mPipelineStatistics;
+ }
+
+ void QuerySetBase::Destroy() {
+ if (GetDevice()->ConsumedError(ValidateDestroy())) {
+ return;
+ }
+ DestroyInternal();
+ }
+
+ MaybeError QuerySetBase::ValidateDestroy() const {
+ DAWN_TRY(GetDevice()->ValidateObject(this));
+ return {};
+ }
+
+ void QuerySetBase::DestroyInternal() {
+ if (mState != QuerySetState::Destroyed) {
+ DestroyImpl();
+ }
+ mState = QuerySetState::Destroyed;
+ }
+
+} // namespace dawn_native
diff --git a/src/dawn_native/QuerySet.h b/src/dawn_native/QuerySet.h
new file mode 100644
index 0000000..7883678
--- /dev/null
+++ b/src/dawn_native/QuerySet.h
@@ -0,0 +1,61 @@
+// 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_QUERYSET_H_
+#define DAWNNATIVE_QUERYSET_H_
+
+#include "dawn_native/Error.h"
+#include "dawn_native/Forward.h"
+#include "dawn_native/ObjectBase.h"
+
+#include "dawn_native/dawn_platform.h"
+
+namespace dawn_native {
+
+ MaybeError ValidateQuerySetDescriptor(DeviceBase* device, const QuerySetDescriptor* descriptor);
+
+ class QuerySetBase : public ObjectBase {
+ public:
+ QuerySetBase(DeviceBase* device, const QuerySetDescriptor* descriptor);
+
+ static QuerySetBase* MakeError(DeviceBase* device);
+
+ wgpu::QueryType GetQueryType() const;
+ uint32_t GetQueryCount() const;
+ const std::vector<wgpu::PipelineStatisticsName>& GetPipelineStatistics() const;
+
+ void Destroy();
+
+ protected:
+ QuerySetBase(DeviceBase* device, ObjectBase::ErrorTag tag);
+ ~QuerySetBase() override;
+
+ void DestroyInternal();
+
+ private:
+ virtual void DestroyImpl() = 0;
+
+ MaybeError ValidateDestroy() const;
+
+ wgpu::QueryType mQueryType;
+ uint32_t mQueryCount;
+ std::vector<wgpu::PipelineStatisticsName> mPipelineStatistics;
+
+ enum class QuerySetState { Unavailable, Available, Destroyed };
+ QuerySetState mState = QuerySetState::Unavailable;
+ };
+
+} // namespace dawn_native
+
+#endif // DAWNNATIVE_QUERYSET_H_
diff --git a/src/dawn_native/ToBackend.h b/src/dawn_native/ToBackend.h
index b9940ab..3cc0715 100644
--- a/src/dawn_native/ToBackend.h
+++ b/src/dawn_native/ToBackend.h
@@ -64,6 +64,11 @@
};
template <typename BackendTraits>
+ struct ToBackendTraits<QuerySetBase, BackendTraits> {
+ using BackendType = typename BackendTraits::QuerySetType;
+ };
+
+ template <typename BackendTraits>
struct ToBackendTraits<QueueBase, BackendTraits> {
using BackendType = typename BackendTraits::QueueType;
};
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index a32b77c..dcb0227 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -285,6 +285,9 @@
const PipelineLayoutDescriptor* descriptor) {
return PipelineLayout::Create(this, descriptor);
}
+ ResultOrError<QuerySetBase*> Device::CreateQuerySetImpl(const QuerySetDescriptor* descriptor) {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation");
+ }
ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) {
return RenderPipeline::Create(this, descriptor);
diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h
index 7ce3a95..1ee4092 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -136,6 +136,8 @@
const ComputePipelineDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const PipelineLayoutDescriptor* descriptor) override;
+ ResultOrError<QuerySetBase*> CreateQuerySetImpl(
+ const QuerySetDescriptor* descriptor) override;
ResultOrError<RenderPipelineBase*> CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) override;
ResultOrError<SamplerBase*> CreateSamplerImpl(const SamplerDescriptor* descriptor) override;
diff --git a/src/dawn_native/d3d12/Forward.h b/src/dawn_native/d3d12/Forward.h
index 1143a4a..4e5368b 100644
--- a/src/dawn_native/d3d12/Forward.h
+++ b/src/dawn_native/d3d12/Forward.h
@@ -28,6 +28,7 @@
class Device;
class Heap;
class PipelineLayout;
+ class QuerySet;
class Queue;
class RenderPipeline;
class Sampler;
@@ -46,6 +47,7 @@
using ComputePipelineType = ComputePipeline;
using DeviceType = Device;
using PipelineLayoutType = PipelineLayout;
+ using QuerySetType = QuerySet;
using QueueType = Queue;
using RenderPipelineType = RenderPipeline;
using ResourceHeapType = Heap;
diff --git a/src/dawn_native/metal/DeviceMTL.h b/src/dawn_native/metal/DeviceMTL.h
index 33ce4b6..76e4151 100644
--- a/src/dawn_native/metal/DeviceMTL.h
+++ b/src/dawn_native/metal/DeviceMTL.h
@@ -76,6 +76,8 @@
const ComputePipelineDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const PipelineLayoutDescriptor* descriptor) override;
+ ResultOrError<QuerySetBase*> CreateQuerySetImpl(
+ const QuerySetDescriptor* descriptor) override;
ResultOrError<RenderPipelineBase*> CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) override;
ResultOrError<SamplerBase*> CreateSamplerImpl(const SamplerDescriptor* descriptor) override;
diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm
index 34b66fc..d53e2e1 100644
--- a/src/dawn_native/metal/DeviceMTL.mm
+++ b/src/dawn_native/metal/DeviceMTL.mm
@@ -123,6 +123,9 @@
const PipelineLayoutDescriptor* descriptor) {
return new PipelineLayout(this, descriptor);
}
+ ResultOrError<QuerySetBase*> Device::CreateQuerySetImpl(const QuerySetDescriptor* descriptor) {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation");
+ }
ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) {
return RenderPipeline::Create(this, descriptor);
diff --git a/src/dawn_native/metal/Forward.h b/src/dawn_native/metal/Forward.h
index a773a18..9481348 100644
--- a/src/dawn_native/metal/Forward.h
+++ b/src/dawn_native/metal/Forward.h
@@ -28,6 +28,7 @@
class Device;
class Framebuffer;
class PipelineLayout;
+ class QuerySet;
class Queue;
class RenderPipeline;
class Sampler;
@@ -46,6 +47,7 @@
using ComputePipelineType = ComputePipeline;
using DeviceType = Device;
using PipelineLayoutType = PipelineLayout;
+ using QuerySetType = QuerySet;
using QueueType = Queue;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
diff --git a/src/dawn_native/null/DeviceNull.cpp b/src/dawn_native/null/DeviceNull.cpp
index fb11d59..c19670e 100644
--- a/src/dawn_native/null/DeviceNull.cpp
+++ b/src/dawn_native/null/DeviceNull.cpp
@@ -116,6 +116,9 @@
const PipelineLayoutDescriptor* descriptor) {
return new PipelineLayout(this, descriptor);
}
+ ResultOrError<QuerySetBase*> Device::CreateQuerySetImpl(const QuerySetDescriptor* descriptor) {
+ return new QuerySet(this, descriptor);
+ }
ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) {
return new RenderPipeline(this, descriptor);
@@ -351,6 +354,19 @@
FreeCommands(&mCommands);
}
+ // QuerySet
+
+ QuerySet::QuerySet(Device* device, const QuerySetDescriptor* descriptor)
+ : QuerySetBase(device, descriptor) {
+ }
+
+ QuerySet::~QuerySet() {
+ DestroyInternal();
+ }
+
+ void QuerySet::DestroyImpl() {
+ }
+
// Queue
Queue::Queue(Device* device) : QueueBase(device) {
diff --git a/src/dawn_native/null/DeviceNull.h b/src/dawn_native/null/DeviceNull.h
index 7a93822..42fce4d 100644
--- a/src/dawn_native/null/DeviceNull.h
+++ b/src/dawn_native/null/DeviceNull.h
@@ -24,6 +24,7 @@
#include "dawn_native/ComputePipeline.h"
#include "dawn_native/Device.h"
#include "dawn_native/PipelineLayout.h"
+#include "dawn_native/QuerySet.h"
#include "dawn_native/Queue.h"
#include "dawn_native/RenderPipeline.h"
#include "dawn_native/RingBufferAllocator.h"
@@ -45,6 +46,7 @@
using ComputePipeline = ComputePipelineBase;
class Device;
using PipelineLayout = PipelineLayoutBase;
+ class QuerySet;
class Queue;
using RenderPipeline = RenderPipelineBase;
using Sampler = SamplerBase;
@@ -62,6 +64,7 @@
using ComputePipelineType = ComputePipeline;
using DeviceType = Device;
using PipelineLayoutType = PipelineLayout;
+ using QuerySetType = QuerySet;
using QueueType = Queue;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
@@ -118,6 +121,8 @@
const ComputePipelineDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const PipelineLayoutDescriptor* descriptor) override;
+ ResultOrError<QuerySetBase*> CreateQuerySetImpl(
+ const QuerySetDescriptor* descriptor) override;
ResultOrError<RenderPipelineBase*> CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) override;
ResultOrError<SamplerBase*> CreateSamplerImpl(const SamplerDescriptor* descriptor) override;
@@ -216,6 +221,16 @@
CommandIterator mCommands;
};
+ class QuerySet final : public QuerySetBase {
+ public:
+ QuerySet(Device* device, const QuerySetDescriptor* descriptor);
+
+ private:
+ ~QuerySet() override;
+
+ void DestroyImpl() override;
+ };
+
class Queue final : public QueueBase {
public:
Queue(Device* device);
diff --git a/src/dawn_native/opengl/DeviceGL.cpp b/src/dawn_native/opengl/DeviceGL.cpp
index 6550b48..f47474f 100644
--- a/src/dawn_native/opengl/DeviceGL.cpp
+++ b/src/dawn_native/opengl/DeviceGL.cpp
@@ -24,6 +24,7 @@
#include "dawn_native/opengl/CommandBufferGL.h"
#include "dawn_native/opengl/ComputePipelineGL.h"
#include "dawn_native/opengl/PipelineLayoutGL.h"
+#include "dawn_native/opengl/QuerySetGL.h"
#include "dawn_native/opengl/QueueGL.h"
#include "dawn_native/opengl/RenderPipelineGL.h"
#include "dawn_native/opengl/SamplerGL.h"
@@ -116,6 +117,9 @@
const PipelineLayoutDescriptor* descriptor) {
return new PipelineLayout(this, descriptor);
}
+ ResultOrError<QuerySetBase*> Device::CreateQuerySetImpl(const QuerySetDescriptor* descriptor) {
+ return new QuerySet(this, descriptor);
+ }
ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) {
return new RenderPipeline(this, descriptor);
diff --git a/src/dawn_native/opengl/DeviceGL.h b/src/dawn_native/opengl/DeviceGL.h
index c38fcf6..4a03f4a 100644
--- a/src/dawn_native/opengl/DeviceGL.h
+++ b/src/dawn_native/opengl/DeviceGL.h
@@ -19,6 +19,7 @@
#include "common/Platform.h"
#include "dawn_native/Device.h"
+#include "dawn_native/QuerySet.h"
#include "dawn_native/opengl/Forward.h"
#include "dawn_native/opengl/GLFormat.h"
#include "dawn_native/opengl/OpenGLFunctions.h"
@@ -75,6 +76,8 @@
const ComputePipelineDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const PipelineLayoutDescriptor* descriptor) override;
+ ResultOrError<QuerySetBase*> CreateQuerySetImpl(
+ const QuerySetDescriptor* descriptor) override;
ResultOrError<RenderPipelineBase*> CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) override;
ResultOrError<SamplerBase*> CreateSamplerImpl(const SamplerDescriptor* descriptor) override;
diff --git a/src/dawn_native/opengl/Forward.h b/src/dawn_native/opengl/Forward.h
index bd2cc76..82d0766 100644
--- a/src/dawn_native/opengl/Forward.h
+++ b/src/dawn_native/opengl/Forward.h
@@ -28,6 +28,7 @@
class Device;
class PersistentPipelineState;
class PipelineLayout;
+ class QuerySet;
class Queue;
class RenderPipeline;
class Sampler;
@@ -45,6 +46,7 @@
using ComputePipelineType = ComputePipeline;
using DeviceType = Device;
using PipelineLayoutType = PipelineLayout;
+ using QuerySetType = QuerySet;
using QueueType = Queue;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
diff --git a/src/dawn_native/opengl/QuerySetGL.cpp b/src/dawn_native/opengl/QuerySetGL.cpp
new file mode 100644
index 0000000..6ff5d20
--- /dev/null
+++ b/src/dawn_native/opengl/QuerySetGL.cpp
@@ -0,0 +1,32 @@
+// 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/opengl/QuerySetGL.h"
+
+#include "dawn_native/opengl/DeviceGL.h"
+
+namespace dawn_native { namespace opengl {
+
+ QuerySet::QuerySet(Device* device, const QuerySetDescriptor* descriptor)
+ : QuerySetBase(device, descriptor) {
+ }
+
+ QuerySet::~QuerySet() {
+ DestroyInternal();
+ }
+
+ void QuerySet::DestroyImpl() {
+ }
+
+}} // namespace dawn_native::opengl
diff --git a/src/dawn_native/opengl/QuerySetGL.h b/src/dawn_native/opengl/QuerySetGL.h
new file mode 100644
index 0000000..2a83bdd
--- /dev/null
+++ b/src/dawn_native/opengl/QuerySetGL.h
@@ -0,0 +1,36 @@
+// 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_OPENGL_QUERYSETGL_H_
+#define DAWNNATIVE_OPENGL_QUERYSETGL_H_
+
+#include "dawn_native/QuerySet.h"
+
+namespace dawn_native { namespace opengl {
+
+ class Device;
+
+ class QuerySet final : public QuerySetBase {
+ public:
+ QuerySet(Device* device, const QuerySetDescriptor* descriptor);
+
+ private:
+ ~QuerySet() override;
+
+ void DestroyImpl() override;
+ };
+
+}} // namespace dawn_native::opengl
+
+#endif // DAWNNATIVE_OPENGL_QUERYSETGL_H_
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index bd3ba34..fb116a1 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -124,6 +124,9 @@
const PipelineLayoutDescriptor* descriptor) {
return PipelineLayout::Create(this, descriptor);
}
+ ResultOrError<QuerySetBase*> Device::CreateQuerySetImpl(const QuerySetDescriptor* descriptor) {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation");
+ }
ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) {
return RenderPipeline::Create(this, descriptor);
diff --git a/src/dawn_native/vulkan/DeviceVk.h b/src/dawn_native/vulkan/DeviceVk.h
index 799f7f2..b38eb77 100644
--- a/src/dawn_native/vulkan/DeviceVk.h
+++ b/src/dawn_native/vulkan/DeviceVk.h
@@ -108,6 +108,8 @@
const ComputePipelineDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const PipelineLayoutDescriptor* descriptor) override;
+ ResultOrError<QuerySetBase*> CreateQuerySetImpl(
+ const QuerySetDescriptor* descriptor) override;
ResultOrError<RenderPipelineBase*> CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) override;
ResultOrError<SamplerBase*> CreateSamplerImpl(const SamplerDescriptor* descriptor) override;
diff --git a/src/dawn_native/vulkan/Forward.h b/src/dawn_native/vulkan/Forward.h
index 9b5a7a1..e11a74f 100644
--- a/src/dawn_native/vulkan/Forward.h
+++ b/src/dawn_native/vulkan/Forward.h
@@ -27,6 +27,7 @@
class ComputePipeline;
class Device;
class PipelineLayout;
+ class QuerySet;
class Queue;
class RenderPipeline;
class ResourceHeap;
@@ -46,6 +47,7 @@
using ComputePipelineType = ComputePipeline;
using DeviceType = Device;
using PipelineLayoutType = PipelineLayout;
+ using QuerySetType = QuerySet;
using QueueType = Queue;
using RenderPipelineType = RenderPipeline;
using ResourceHeapType = ResourceHeap;
diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn
index b9ae2fe..e602269 100644
--- a/src/tests/BUILD.gn
+++ b/src/tests/BUILD.gn
@@ -185,6 +185,7 @@
"unittests/validation/FenceValidationTests.cpp",
"unittests/validation/GetBindGroupLayoutValidationTests.cpp",
"unittests/validation/IndexBufferValidationTests.cpp",
+ "unittests/validation/QuerySetValidationTests.cpp",
"unittests/validation/QueueSubmitValidationTests.cpp",
"unittests/validation/RenderBundleValidationTests.cpp",
"unittests/validation/RenderPassDescriptorValidationTests.cpp",
diff --git a/src/tests/unittests/validation/QuerySetValidationTests.cpp b/src/tests/unittests/validation/QuerySetValidationTests.cpp
new file mode 100644
index 0000000..311bc66
--- /dev/null
+++ b/src/tests/unittests/validation/QuerySetValidationTests.cpp
@@ -0,0 +1,150 @@
+// 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 "tests/unittests/validation/ValidationTest.h"
+
+#include "utils/WGPUHelpers.h"
+
+class QuerySetValidationTest : public ValidationTest {
+ protected:
+ void SetUp() override {
+ ValidationTest::SetUp();
+
+ // Initialize the device with required extensions
+ deviceWithPipelineStatistics =
+ CreateDeviceFromAdapter(adapter, {"pipeline_statistics_query"});
+ deviceWithTimestamp = CreateDeviceFromAdapter(adapter, {"timestamp_query"});
+ }
+
+ void CreateQuerySet(wgpu::Device cDevice,
+ wgpu::QueryType queryType,
+ uint32_t queryCount,
+ std::vector<wgpu::PipelineStatisticsName> pipelineStatistics = {}) {
+ wgpu::QuerySetDescriptor descriptor;
+ descriptor.type = queryType;
+ descriptor.count = queryCount;
+
+ if (pipelineStatistics.size() > 0) {
+ descriptor.pipelineStatistics = pipelineStatistics.data();
+ descriptor.pipelineStatisticsCount = pipelineStatistics.size();
+ }
+
+ cDevice.CreateQuerySet(&descriptor);
+ }
+
+ wgpu::Device deviceWithPipelineStatistics;
+ wgpu::Device deviceWithTimestamp;
+};
+
+// Test creating query set with/without extensions
+TEST_F(QuerySetValidationTest, Creation) {
+ // Create query set for Occlusion query
+ {
+ // Success on default device without any extension enabled
+ // Occlusion query does not require any extension.
+ CreateQuerySet(device, wgpu::QueryType::Occlusion, 1);
+
+ // Success on the device with extension enabled.
+ CreateQuerySet(deviceWithPipelineStatistics, wgpu::QueryType::Occlusion, 1);
+ CreateQuerySet(deviceWithTimestamp, wgpu::QueryType::Occlusion, 1);
+ }
+
+ // Create query set for PipelineStatistics query
+ {
+ // Fail on default device without any extension enabled
+ ASSERT_DEVICE_ERROR(
+ CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
+ {wgpu::PipelineStatisticsName::VertexShaderInvocations}));
+
+ // Success on the device if the extension is enabled.
+ CreateQuerySet(deviceWithPipelineStatistics, wgpu::QueryType::PipelineStatistics, 1,
+ {wgpu::PipelineStatisticsName::VertexShaderInvocations});
+ }
+
+ // Create query set for Timestamp query
+ {
+ // Fail on default device without any extension enabled
+ ASSERT_DEVICE_ERROR(CreateQuerySet(device, wgpu::QueryType::Timestamp, 1));
+
+ // Success on the device if the extension is enabled.
+ CreateQuerySet(deviceWithTimestamp, wgpu::QueryType::Timestamp, 1);
+ }
+}
+
+// Test creating query set with invalid type
+TEST_F(QuerySetValidationTest, InvalidQueryType) {
+ ASSERT_DEVICE_ERROR(CreateQuerySet(device, static_cast<wgpu::QueryType>(0xFFFFFFFF), 1));
+}
+
+// Test creating query set with unnecessary pipeline statistics
+TEST_F(QuerySetValidationTest, UnnecessaryPipelineStatistics) {
+ // Fail to create with pipeline statistics for Occlusion query
+ {
+ ASSERT_DEVICE_ERROR(
+ CreateQuerySet(device, wgpu::QueryType::Occlusion, 1,
+ {wgpu::PipelineStatisticsName::VertexShaderInvocations}));
+ }
+
+ // Fail to create with pipeline statistics for Timestamp query
+ {
+ ASSERT_DEVICE_ERROR(
+ CreateQuerySet(deviceWithTimestamp, wgpu::QueryType::Timestamp, 1,
+ {wgpu::PipelineStatisticsName::VertexShaderInvocations}));
+ }
+}
+
+// Test creating query set with invalid pipeline statistics
+TEST_F(QuerySetValidationTest, InvalidPipelineStatistics) {
+ // Success to create with all pipeline statistics names which are not in the same order as
+ // defined in webgpu header file
+ {
+ CreateQuerySet(deviceWithPipelineStatistics, wgpu::QueryType::PipelineStatistics, 1,
+ {wgpu::PipelineStatisticsName::ClipperInvocations,
+ wgpu::PipelineStatisticsName::ClipperPrimitivesOut,
+ wgpu::PipelineStatisticsName::ComputeShaderInvocations,
+ wgpu::PipelineStatisticsName::FragmentShaderInvocations,
+ wgpu::PipelineStatisticsName::VertexShaderInvocations});
+ }
+
+ // Fail to create with empty pipeline statistics
+ {
+ ASSERT_DEVICE_ERROR(CreateQuerySet(deviceWithPipelineStatistics,
+ wgpu::QueryType::PipelineStatistics, 1, {}));
+ }
+
+ // Fail to create with invalid pipeline statistics
+ {
+ ASSERT_DEVICE_ERROR(
+ CreateQuerySet(deviceWithPipelineStatistics, wgpu::QueryType::PipelineStatistics, 1,
+ {static_cast<wgpu::PipelineStatisticsName>(0xFFFFFFFF)}));
+ }
+
+ // Fail to create with duplicate pipeline statistics
+ {
+ ASSERT_DEVICE_ERROR(
+ CreateQuerySet(deviceWithPipelineStatistics, wgpu::QueryType::PipelineStatistics, 1,
+ {wgpu::PipelineStatisticsName::VertexShaderInvocations,
+ wgpu::PipelineStatisticsName::VertexShaderInvocations}));
+ }
+}
+
+// Test destroying a destroyed query set
+TEST_F(QuerySetValidationTest, DestroyDestroyedQuerySet) {
+ wgpu::QuerySetDescriptor descriptor;
+ descriptor.type = wgpu::QueryType::Occlusion;
+ descriptor.count = 1;
+ wgpu::QuerySet querySet = device.CreateQuerySet(&descriptor);
+ querySet.Destroy();
+ querySet.Destroy();
+}