mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-16 04:11:25 +00:00
ValidateTextureViewDescriptor was running into use of uninitialized value. Fixing this by moving the texture state check below the texture object check. This should validate the texture object before trying to validate it's texture state. Bug: chromium:947150 Change-Id: I9b41791bfb960fbe4873ba5fcadf046bd32e5853 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/6180 Reviewed-by: Kai Ninomiya <kainino@chromium.org> Commit-Queue: Natasha Lee <natlee@microsoft.com>
472 lines
17 KiB
C++
472 lines
17 KiB
C++
// Copyright 2017 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/Texture.h"
|
|
|
|
#include "common/Assert.h"
|
|
#include "dawn_native/Device.h"
|
|
#include "dawn_native/ValidationUtils_autogen.h"
|
|
|
|
namespace dawn_native {
|
|
namespace {
|
|
// TODO(jiawei.shao@intel.com): implement texture view format compatibility rule
|
|
MaybeError ValidateTextureViewFormatCompatibility(const TextureBase* texture,
|
|
const TextureViewDescriptor* descriptor) {
|
|
if (texture->GetFormat() != descriptor->format) {
|
|
return DAWN_VALIDATION_ERROR(
|
|
"The format of texture view is not compatible to the original texture");
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
// TODO(jiawei.shao@intel.com): support validation on all texture view dimensions
|
|
bool IsTextureViewDimensionCompatibleWithTextureDimension(
|
|
dawn::TextureViewDimension textureViewDimension,
|
|
dawn::TextureDimension textureDimension) {
|
|
switch (textureViewDimension) {
|
|
case dawn::TextureViewDimension::e2D:
|
|
case dawn::TextureViewDimension::e2DArray:
|
|
case dawn::TextureViewDimension::Cube:
|
|
case dawn::TextureViewDimension::CubeArray:
|
|
return textureDimension == dawn::TextureDimension::e2D;
|
|
default:
|
|
UNREACHABLE();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// TODO(jiawei.shao@intel.com): support validation on all texture view dimensions
|
|
bool IsArrayLayerValidForTextureViewDimension(
|
|
dawn::TextureViewDimension textureViewDimension,
|
|
uint32_t textureViewArrayLayer) {
|
|
switch (textureViewDimension) {
|
|
case dawn::TextureViewDimension::e2D:
|
|
return textureViewArrayLayer == 1u;
|
|
case dawn::TextureViewDimension::e2DArray:
|
|
return true;
|
|
case dawn::TextureViewDimension::Cube:
|
|
return textureViewArrayLayer == 6u;
|
|
case dawn::TextureViewDimension::CubeArray:
|
|
return textureViewArrayLayer % 6 == 0;
|
|
default:
|
|
UNREACHABLE();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool IsTextureSizeValidForTextureViewDimension(
|
|
dawn::TextureViewDimension textureViewDimension,
|
|
const Extent3D& textureSize) {
|
|
switch (textureViewDimension) {
|
|
case dawn::TextureViewDimension::Cube:
|
|
case dawn::TextureViewDimension::CubeArray:
|
|
return textureSize.width == textureSize.height;
|
|
case dawn::TextureViewDimension::e2D:
|
|
case dawn::TextureViewDimension::e2DArray:
|
|
return true;
|
|
default:
|
|
UNREACHABLE();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// TODO(jiawei.shao@intel.com): support more sample count.
|
|
MaybeError ValidateSampleCount(const TextureDescriptor* descriptor) {
|
|
if (!IsValidSampleCount(descriptor->sampleCount)) {
|
|
return DAWN_VALIDATION_ERROR("The sample count of the texture is not supported.");
|
|
}
|
|
|
|
if (descriptor->sampleCount > 1) {
|
|
if (descriptor->mipLevelCount > 1) {
|
|
return DAWN_VALIDATION_ERROR(
|
|
"The mipmap level count of a multisampled texture must be 1.");
|
|
}
|
|
|
|
// Multisampled 2D array texture is not supported because on Metal it requires the
|
|
// version of macOS be greater than 10.14.
|
|
if (descriptor->arrayLayerCount > 1) {
|
|
return DAWN_VALIDATION_ERROR("Multisampled 2D array texture is not supported.");
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
MaybeError ValidateTextureViewDimensionCompatibility(
|
|
const TextureBase* texture,
|
|
const TextureViewDescriptor* descriptor) {
|
|
if (!IsArrayLayerValidForTextureViewDimension(descriptor->dimension,
|
|
descriptor->arrayLayerCount)) {
|
|
return DAWN_VALIDATION_ERROR(
|
|
"The dimension of the texture view is not compatible with the layer count");
|
|
}
|
|
|
|
if (!IsTextureViewDimensionCompatibleWithTextureDimension(descriptor->dimension,
|
|
texture->GetDimension())) {
|
|
return DAWN_VALIDATION_ERROR(
|
|
"The dimension of the texture view is not compatible with the dimension of the"
|
|
"original texture");
|
|
}
|
|
|
|
if (!IsTextureSizeValidForTextureViewDimension(descriptor->dimension,
|
|
texture->GetSize())) {
|
|
return DAWN_VALIDATION_ERROR(
|
|
"The dimension of the texture view is not compatible with the size of the"
|
|
"original texture");
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
TextureViewDescriptor MakeDefaultTextureViewDescriptor(const TextureBase* texture) {
|
|
TextureViewDescriptor descriptor;
|
|
descriptor.format = texture->GetFormat();
|
|
descriptor.baseArrayLayer = 0;
|
|
descriptor.arrayLayerCount = texture->GetArrayLayers();
|
|
descriptor.baseMipLevel = 0;
|
|
descriptor.mipLevelCount = texture->GetNumMipLevels();
|
|
|
|
// TODO(jiawei.shao@intel.com): support all texture dimensions.
|
|
switch (texture->GetDimension()) {
|
|
case dawn::TextureDimension::e2D:
|
|
if (texture->GetArrayLayers() == 1u) {
|
|
descriptor.dimension = dawn::TextureViewDimension::e2D;
|
|
} else {
|
|
descriptor.dimension = dawn::TextureViewDimension::e2DArray;
|
|
}
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
|
|
return descriptor;
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
MaybeError ValidateTextureDescriptor(DeviceBase*, const TextureDescriptor* descriptor) {
|
|
if (descriptor->nextInChain != nullptr) {
|
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
|
}
|
|
|
|
DAWN_TRY(ValidateTextureUsageBit(descriptor->usage));
|
|
DAWN_TRY(ValidateTextureDimension(descriptor->dimension));
|
|
DAWN_TRY(ValidateTextureFormat(descriptor->format));
|
|
DAWN_TRY(ValidateSampleCount(descriptor));
|
|
|
|
// TODO(jiawei.shao@intel.com): check stuff based on the dimension
|
|
if (descriptor->size.width == 0 || descriptor->size.height == 0 ||
|
|
descriptor->size.depth == 0 || descriptor->arrayLayerCount == 0 ||
|
|
descriptor->mipLevelCount == 0) {
|
|
return DAWN_VALIDATION_ERROR("Cannot create an empty texture");
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
MaybeError ValidateTextureViewDescriptor(const DeviceBase* device,
|
|
const TextureBase* texture,
|
|
const TextureViewDescriptor* descriptor) {
|
|
if (descriptor->nextInChain != nullptr) {
|
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
|
}
|
|
|
|
DAWN_TRY(device->ValidateObject(texture));
|
|
if (texture->GetTextureState() == TextureBase::TextureState::Destroyed) {
|
|
return DAWN_VALIDATION_ERROR("Destroyed texture used to create texture view");
|
|
}
|
|
|
|
DAWN_TRY(ValidateTextureViewDimension(descriptor->dimension));
|
|
DAWN_TRY(ValidateTextureFormat(descriptor->format));
|
|
|
|
// TODO(jiawei.shao@intel.com): check stuff based on resource limits
|
|
if (descriptor->arrayLayerCount == 0 || descriptor->mipLevelCount == 0) {
|
|
return DAWN_VALIDATION_ERROR("Cannot create an empty texture view");
|
|
}
|
|
|
|
if (uint64_t(descriptor->baseArrayLayer) + uint64_t(descriptor->arrayLayerCount) >
|
|
uint64_t(texture->GetArrayLayers())) {
|
|
return DAWN_VALIDATION_ERROR("Texture view array-layer out of range");
|
|
}
|
|
|
|
if (uint64_t(descriptor->baseMipLevel) + uint64_t(descriptor->mipLevelCount) >
|
|
uint64_t(texture->GetNumMipLevels())) {
|
|
return DAWN_VALIDATION_ERROR("Texture view mip-level out of range");
|
|
}
|
|
|
|
DAWN_TRY(ValidateTextureViewFormatCompatibility(texture, descriptor));
|
|
DAWN_TRY(ValidateTextureViewDimensionCompatibility(texture, descriptor));
|
|
|
|
return {};
|
|
}
|
|
|
|
uint32_t TextureFormatPixelSize(dawn::TextureFormat format) {
|
|
switch (format) {
|
|
case dawn::TextureFormat::R8Unorm:
|
|
case dawn::TextureFormat::R8Uint:
|
|
return 1;
|
|
case dawn::TextureFormat::R8G8Unorm:
|
|
case dawn::TextureFormat::R8G8Uint:
|
|
return 2;
|
|
case dawn::TextureFormat::R8G8B8A8Unorm:
|
|
case dawn::TextureFormat::R8G8B8A8Uint:
|
|
case dawn::TextureFormat::B8G8R8A8Unorm:
|
|
return 4;
|
|
case dawn::TextureFormat::D32FloatS8Uint:
|
|
return 8;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
bool TextureFormatHasDepth(dawn::TextureFormat format) {
|
|
switch (format) {
|
|
case dawn::TextureFormat::D32FloatS8Uint:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool TextureFormatHasStencil(dawn::TextureFormat format) {
|
|
switch (format) {
|
|
case dawn::TextureFormat::D32FloatS8Uint:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool TextureFormatHasDepthOrStencil(dawn::TextureFormat format) {
|
|
switch (format) {
|
|
case dawn::TextureFormat::D32FloatS8Uint:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool IsColorRenderableTextureFormat(dawn::TextureFormat format) {
|
|
switch (format) {
|
|
case dawn::TextureFormat::B8G8R8A8Unorm:
|
|
case dawn::TextureFormat::R8G8B8A8Uint:
|
|
case dawn::TextureFormat::R8G8B8A8Unorm:
|
|
case dawn::TextureFormat::R8G8Uint:
|
|
case dawn::TextureFormat::R8G8Unorm:
|
|
case dawn::TextureFormat::R8Uint:
|
|
case dawn::TextureFormat::R8Unorm:
|
|
return true;
|
|
|
|
case dawn::TextureFormat::D32FloatS8Uint:
|
|
return false;
|
|
|
|
default:
|
|
UNREACHABLE();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool IsDepthStencilRenderableTextureFormat(dawn::TextureFormat format) {
|
|
switch (format) {
|
|
case dawn::TextureFormat::D32FloatS8Uint:
|
|
return true;
|
|
|
|
case dawn::TextureFormat::B8G8R8A8Unorm:
|
|
case dawn::TextureFormat::R8G8B8A8Uint:
|
|
case dawn::TextureFormat::R8G8B8A8Unorm:
|
|
case dawn::TextureFormat::R8G8Uint:
|
|
case dawn::TextureFormat::R8G8Unorm:
|
|
case dawn::TextureFormat::R8Uint:
|
|
case dawn::TextureFormat::R8Unorm:
|
|
return false;
|
|
|
|
default:
|
|
UNREACHABLE();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool IsValidSampleCount(uint32_t sampleCount) {
|
|
switch (sampleCount) {
|
|
case 1:
|
|
case 4:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// TextureBase
|
|
|
|
TextureBase::TextureBase(DeviceBase* device,
|
|
const TextureDescriptor* descriptor,
|
|
TextureState state)
|
|
: ObjectBase(device),
|
|
mDimension(descriptor->dimension),
|
|
mFormat(descriptor->format),
|
|
mSize(descriptor->size),
|
|
mArrayLayerCount(descriptor->arrayLayerCount),
|
|
mMipLevelCount(descriptor->mipLevelCount),
|
|
mSampleCount(descriptor->sampleCount),
|
|
mUsage(descriptor->usage),
|
|
mState(state) {
|
|
}
|
|
|
|
TextureBase::TextureBase(DeviceBase* device, ObjectBase::ErrorTag tag)
|
|
: ObjectBase(device, tag) {
|
|
}
|
|
|
|
// static
|
|
TextureBase* TextureBase::MakeError(DeviceBase* device) {
|
|
return new TextureBase(device, ObjectBase::kError);
|
|
}
|
|
|
|
dawn::TextureDimension TextureBase::GetDimension() const {
|
|
ASSERT(!IsError());
|
|
return mDimension;
|
|
}
|
|
dawn::TextureFormat TextureBase::GetFormat() const {
|
|
ASSERT(!IsError());
|
|
return mFormat;
|
|
}
|
|
const Extent3D& TextureBase::GetSize() const {
|
|
ASSERT(!IsError());
|
|
return mSize;
|
|
}
|
|
uint32_t TextureBase::GetArrayLayers() const {
|
|
ASSERT(!IsError());
|
|
return mArrayLayerCount;
|
|
}
|
|
uint32_t TextureBase::GetNumMipLevels() const {
|
|
ASSERT(!IsError());
|
|
return mMipLevelCount;
|
|
}
|
|
uint32_t TextureBase::GetSampleCount() const {
|
|
ASSERT(!IsError());
|
|
return mSampleCount;
|
|
}
|
|
dawn::TextureUsageBit TextureBase::GetUsage() const {
|
|
ASSERT(!IsError());
|
|
return mUsage;
|
|
}
|
|
|
|
TextureBase::TextureState TextureBase::GetTextureState() const {
|
|
ASSERT(!IsError());
|
|
return mState;
|
|
}
|
|
|
|
MaybeError TextureBase::ValidateCanUseInSubmitNow() const {
|
|
ASSERT(!IsError());
|
|
if (mState == TextureState::Destroyed) {
|
|
return DAWN_VALIDATION_ERROR("Destroyed texture used in a submit");
|
|
}
|
|
return {};
|
|
}
|
|
|
|
MaybeError TextureBase::ValidateCanCreateTextureViewNow() const {
|
|
ASSERT(!IsError());
|
|
if (mState == TextureState::Destroyed) {
|
|
return DAWN_VALIDATION_ERROR("Destroyed texture used to create texture view");
|
|
}
|
|
return {};
|
|
}
|
|
|
|
bool TextureBase::IsMultisampledTexture() const {
|
|
ASSERT(!IsError());
|
|
return mSampleCount > 1;
|
|
}
|
|
|
|
TextureViewBase* TextureBase::CreateDefaultTextureView() {
|
|
TextureViewDescriptor descriptor = {};
|
|
|
|
if (!IsError()) {
|
|
descriptor = MakeDefaultTextureViewDescriptor(this);
|
|
}
|
|
|
|
return GetDevice()->CreateTextureView(this, &descriptor);
|
|
}
|
|
|
|
TextureViewBase* TextureBase::CreateTextureView(const TextureViewDescriptor* descriptor) {
|
|
return GetDevice()->CreateTextureView(this, descriptor);
|
|
}
|
|
|
|
void TextureBase::Destroy() {
|
|
if (mState == TextureState::OwnedInternal) {
|
|
DestroyImpl();
|
|
}
|
|
mState = TextureState::Destroyed;
|
|
}
|
|
|
|
void TextureBase::DestroyImpl() {
|
|
}
|
|
|
|
// TextureViewBase
|
|
|
|
TextureViewBase::TextureViewBase(TextureBase* texture, const TextureViewDescriptor* descriptor)
|
|
: ObjectBase(texture->GetDevice()),
|
|
mTexture(texture),
|
|
mFormat(descriptor->format),
|
|
mBaseMipLevel(descriptor->baseMipLevel),
|
|
mMipLevelCount(descriptor->mipLevelCount),
|
|
mBaseArrayLayer(descriptor->baseArrayLayer),
|
|
mArrayLayerCount(descriptor->arrayLayerCount) {
|
|
}
|
|
|
|
TextureViewBase::TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag)
|
|
: ObjectBase(device, tag) {
|
|
}
|
|
|
|
// static
|
|
TextureViewBase* TextureViewBase::MakeError(DeviceBase* device) {
|
|
return new TextureViewBase(device, ObjectBase::kError);
|
|
}
|
|
|
|
const TextureBase* TextureViewBase::GetTexture() const {
|
|
ASSERT(!IsError());
|
|
return mTexture.Get();
|
|
}
|
|
|
|
TextureBase* TextureViewBase::GetTexture() {
|
|
ASSERT(!IsError());
|
|
return mTexture.Get();
|
|
}
|
|
|
|
dawn::TextureFormat TextureViewBase::GetFormat() const {
|
|
ASSERT(!IsError());
|
|
return mFormat;
|
|
}
|
|
|
|
uint32_t TextureViewBase::GetBaseMipLevel() const {
|
|
ASSERT(!IsError());
|
|
return mBaseMipLevel;
|
|
}
|
|
|
|
uint32_t TextureViewBase::GetLevelCount() const {
|
|
ASSERT(!IsError());
|
|
return mMipLevelCount;
|
|
}
|
|
|
|
uint32_t TextureViewBase::GetBaseArrayLayer() const {
|
|
ASSERT(!IsError());
|
|
return mBaseArrayLayer;
|
|
}
|
|
|
|
uint32_t TextureViewBase::GetLayerCount() const {
|
|
ASSERT(!IsError());
|
|
return mArrayLayerCount;
|
|
}
|
|
} // namespace dawn_native
|