blob: 3f20dab9de56dc129cdf76c9f6b1894f5b94d3a3 [file] [log] [blame]
// 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/Features.h"
#include "dawn/native/ObjectType_autogen.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) {
DAWN_INVALID_IF(descriptor->nextInChain != nullptr, "nextInChain must be nullptr");
DAWN_TRY(ValidateQueryType(descriptor->type));
DAWN_INVALID_IF(descriptor->count > kMaxQueryCount,
"Query count (%u) exceeds the maximum query count (%u).", descriptor->count,
kMaxQueryCount);
switch (descriptor->type) {
case wgpu::QueryType::Occlusion:
DAWN_INVALID_IF(descriptor->pipelineStatisticsCount != 0,
"Pipeline statistics specified for a query of type %s.",
descriptor->type);
break;
case wgpu::QueryType::PipelineStatistics: {
// TODO(crbug.com/1177506): Pipeline statistics query is not fully implemented.
// Disallow it as unsafe until the implementaion is completed.
DAWN_INVALID_IF(device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs),
"Pipeline statistics queries are disallowed because they are not "
"fully implemented");
DAWN_INVALID_IF(
!device->IsFeatureEnabled(Feature::PipelineStatisticsQuery),
"Pipeline statistics query set created without the feature being enabled.");
DAWN_INVALID_IF(descriptor->pipelineStatisticsCount == 0,
"Pipeline statistics query set created with 0 statistics.");
std::set<wgpu::PipelineStatisticName> pipelineStatisticsSet;
for (uint32_t i = 0; i < descriptor->pipelineStatisticsCount; i++) {
DAWN_TRY(ValidatePipelineStatisticName(descriptor->pipelineStatistics[i]));
auto [_, inserted] =
pipelineStatisticsSet.insert((descriptor->pipelineStatistics[i]));
DAWN_INVALID_IF(!inserted, "Statistic %s is specified more than once.",
descriptor->pipelineStatistics[i]);
}
} break;
case wgpu::QueryType::Timestamp:
DAWN_INVALID_IF(device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs),
"Timestamp queries are disallowed because they may expose precise "
"timing information.");
DAWN_INVALID_IF(!device->IsFeatureEnabled(Feature::TimestampQuery),
"Timestamp query set created without the feature being enabled.");
DAWN_INVALID_IF(descriptor->pipelineStatisticsCount != 0,
"Pipeline statistics specified for a query of type %s.",
descriptor->type);
break;
default:
break;
}
return {};
}
QuerySetBase::QuerySetBase(DeviceBase* device, const QuerySetDescriptor* descriptor)
: ApiObjectBase(device, descriptor->label),
mQueryType(descriptor->type),
mQueryCount(descriptor->count),
mState(QuerySetState::Available) {
for (uint32_t i = 0; i < descriptor->pipelineStatisticsCount; i++) {
mPipelineStatistics.push_back(descriptor->pipelineStatistics[i]);
}
mQueryAvailability.resize(descriptor->count);
TrackInDevice();
}
QuerySetBase::QuerySetBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) {
TrackInDevice();
}
QuerySetBase::QuerySetBase(DeviceBase* device, ObjectBase::ErrorTag tag)
: ApiObjectBase(device, tag) {
}
QuerySetBase::~QuerySetBase() {
// Uninitialized or already destroyed
ASSERT(mState == QuerySetState::Unavailable || mState == QuerySetState::Destroyed);
}
void QuerySetBase::DestroyImpl() {
mState = QuerySetState::Destroyed;
}
// static
QuerySetBase* QuerySetBase::MakeError(DeviceBase* device) {
return new ErrorQuerySet(device);
}
ObjectType QuerySetBase::GetType() const {
return ObjectType::QuerySet;
}
wgpu::QueryType QuerySetBase::GetQueryType() const {
return mQueryType;
}
uint32_t QuerySetBase::GetQueryCount() const {
return mQueryCount;
}
const std::vector<wgpu::PipelineStatisticName>& QuerySetBase::GetPipelineStatistics() const {
return mPipelineStatistics;
}
const std::vector<bool>& QuerySetBase::GetQueryAvailability() const {
return mQueryAvailability;
}
void QuerySetBase::SetQueryAvailability(uint32_t index, bool available) {
mQueryAvailability[index] = available;
}
MaybeError QuerySetBase::ValidateCanUseInSubmitNow() const {
ASSERT(!IsError());
DAWN_INVALID_IF(mState == QuerySetState::Destroyed, "%s used while destroyed.", this);
return {};
}
void QuerySetBase::APIDestroy() {
if (GetDevice()->ConsumedError(ValidateDestroy())) {
return;
}
Destroy();
}
MaybeError QuerySetBase::ValidateDestroy() const {
DAWN_TRY(GetDevice()->ValidateObject(this));
return {};
}
} // namespace dawn::native