Add entry point of creating texture view by TextureViewDescriptor

This patch adds the entry point creating texture view with a
TextureViewDescriptor and all the validations on the parameters
according to https://github.com/gpuweb/gpuweb/issues/79.

BUG=dawn:16
TEST=dawn_unittests

Change-Id: Ibc04a0f7b9f334c57da191606313ab156e18af1f
Reviewed-on: https://dawn-review.googlesource.com/c/1800
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Jiawei Shao 2018-10-12 08:32:58 +00:00 committed by Commit Bot service account
parent c35be1a4dd
commit 6329e5ad47
18 changed files with 367 additions and 6 deletions

View File

@ -780,6 +780,7 @@ test("dawn_unittests") {
"src/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp",
"src/tests/unittests/validation/RenderPipelineValidationTests.cpp",
"src/tests/unittests/validation/ShaderModuleValidationTests.cpp",
"src/tests/unittests/validation/TextureViewValidationTests.cpp",
"src/tests/unittests/validation/ValidationTest.cpp",
"src/tests/unittests/validation/ValidationTest.h",
"src/tests/unittests/validation/VertexBufferValidationTests.cpp",

View File

@ -1031,6 +1031,13 @@
{
"name": "create default texture view",
"returns": "texture view"
},
{
"name": "create texture view",
"returns": "texture view",
"args": [
{"name": "descriptor", "type": "texture view descriptor", "annotation": "const*"}
]
}
]
},
@ -1041,9 +1048,9 @@
{"name": "usage", "type": "texture usage bit"},
{"name": "dimension", "type": "texture dimension"},
{"name": "size", "type": "extent 3D"},
{"name": "arrayLayer", "type": "uint32_t"},
{"name": "array layer", "type": "uint32_t"},
{"name": "format", "type": "texture format"},
{"name": "mipLevel", "type": "uint32_t"}
{"name": "mip level", "type": "uint32_t"}
]
},
"texture dimension": {
@ -1077,9 +1084,34 @@
{"value": 32, "name": "present"}
]
},
"texture view descriptor": {
"category": "structure",
"extensible": true,
"members": [
{"name": "format", "type": "texture format"},
{"name": "dimension", "type": "texture view dimension"},
{"name": "base mip level", "type": "uint32_t"},
{"name": "level count", "type": "uint32_t"},
{"name": "base array layer", "type": "uint32_t"},
{"name": "layer count", "type": "uint32_t"}
],
"TODO": [
"jiawei.shao@intel.com: Allow choosing the aspect (depth vs. stencil)"
]
},
"texture view": {
"category": "object"
},
"texture view dimension": {
"category": "enum",
"values": [
{"value": 0, "name": "2D"},
{"value": 1, "name": "2D array"}
],
"TODO": [
"jiawei.shao@intel.com: support 1D, 3D, cube and cube array texture views"
]
},
"vertex format": {
"category": "enum",
"values": [

View File

@ -192,6 +192,15 @@ namespace dawn_native {
}
return result;
}
TextureViewBase* DeviceBase::CreateTextureView(TextureBase* texture,
const TextureViewDescriptor* descriptor) {
TextureViewBase* result = nullptr;
if (ConsumedError(CreateTextureViewInternal(&result, texture, descriptor))) {
return nullptr;
}
return result;
}
// Other Device API methods
@ -271,6 +280,14 @@ namespace dawn_native {
return {};
}
MaybeError DeviceBase::CreateTextureViewInternal(TextureViewBase** result,
TextureBase* texture,
const TextureViewDescriptor* descriptor) {
DAWN_TRY(ValidateTextureViewDescriptor(this, texture, descriptor));
DAWN_TRY_ASSIGN(*result, CreateTextureViewImpl(texture, descriptor));
return {};
}
// Other implementation details
void DeviceBase::ConsumeError(ErrorData* error) {

View File

@ -96,6 +96,8 @@ namespace dawn_native {
ShaderModuleBase* CreateShaderModule(const ShaderModuleDescriptor* descriptor);
SwapChainBuilder* CreateSwapChainBuilder();
TextureBase* CreateTexture(const TextureDescriptor* descriptor);
TextureViewBase* CreateTextureView(TextureBase* texture,
const TextureViewDescriptor* descriptor);
void Tick();
void SetErrorCallback(dawn::DeviceErrorCallback callback, dawn::CallbackUserdata userdata);
@ -123,6 +125,9 @@ namespace dawn_native {
const ShaderModuleDescriptor* descriptor) = 0;
virtual ResultOrError<TextureBase*> CreateTextureImpl(
const TextureDescriptor* descriptor) = 0;
virtual ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) = 0;
MaybeError CreateBindGroupLayoutInternal(BindGroupLayoutBase** result,
const BindGroupLayoutDescriptor* descriptor);
@ -136,6 +141,9 @@ namespace dawn_native {
MaybeError CreateShaderModuleInternal(ShaderModuleBase** result,
const ShaderModuleDescriptor* descriptor);
MaybeError CreateTextureInternal(TextureBase** result, const TextureDescriptor* descriptor);
MaybeError CreateTextureViewInternal(TextureViewBase** result,
TextureBase* texture,
const TextureViewDescriptor* descriptor);
void ConsumeError(ErrorData* error);

View File

@ -23,10 +23,7 @@ namespace dawn_native {
// file to avoid having all files including headers like <string> and <vector>
class ErrorData;
enum class ErrorType : uint32_t {
Validation,
ContextLost,
};
enum class ErrorType : uint32_t { Validation, ContextLost, Unimplemented };
// MaybeError and ResultOrError are meant to be used as return value for function that are not
// expected to, but might fail. The handling of error is potentially much slower than successes.
@ -47,6 +44,7 @@ namespace dawn_native {
#define DAWN_MAKE_ERROR(TYPE, MESSAGE) MakeError(TYPE, MESSAGE, __FILE__, __func__, __LINE__)
#define DAWN_VALIDATION_ERROR(MESSAGE) DAWN_MAKE_ERROR(ErrorType::Validation, MESSAGE)
#define DAWN_CONTEXT_LOST_ERROR(MESSAGE) DAWN_MAKE_ERROR(ErrorType::ContextLost, MESSAGE)
#define DAWN_UNIMPLEMENTED_ERROR(MESSAGE) DAWN_MAKE_ERROR(ErrorType::Unimplemented, MESSAGE)
#define DAWN_CONCAT1(x, y) x##y
#define DAWN_CONCAT2(x, y) DAWN_CONCAT1(x, y)

View File

@ -19,6 +19,68 @@
#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:
return textureDimension == dawn::TextureDimension::e2D;
case dawn::TextureViewDimension::e2DArray:
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;
default:
UNREACHABLE();
return false;
}
}
MaybeError ValidateTextureViewDimensionCompatibility(
const TextureBase* texture,
const TextureViewDescriptor* descriptor) {
if (!IsArrayLayerValidForTextureViewDimension(descriptor->dimension,
descriptor->layerCount)) {
return DAWN_VALIDATION_ERROR(
"The dimension of the texture view is not compatible to the layer count");
}
if (!IsTextureViewDimensionCompatibleWithTextureDimension(descriptor->dimension,
texture->GetDimension())) {
return DAWN_VALIDATION_ERROR(
"The dimension of texture view is not compatible to the original texture");
}
return {};
}
} // anonymous namespace
MaybeError ValidateTextureDescriptor(DeviceBase*, const TextureDescriptor* descriptor) {
if (descriptor->nextInChain != nullptr) {
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
@ -38,6 +100,37 @@ namespace dawn_native {
return {};
}
MaybeError ValidateTextureViewDescriptor(const DeviceBase*,
const TextureBase* texture,
const TextureViewDescriptor* descriptor) {
if (descriptor->nextInChain != nullptr) {
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
}
DAWN_TRY(ValidateTextureViewDimension(descriptor->dimension));
DAWN_TRY(ValidateTextureFormat(descriptor->format));
// TODO(jiawei.shao@intel.com): check stuff based on resource limits
if (descriptor->layerCount == 0 || descriptor->levelCount == 0) {
return DAWN_VALIDATION_ERROR("Cannot create an empty texture view");
}
if (uint64_t(descriptor->baseArrayLayer) + uint64_t(descriptor->layerCount) >
uint64_t(texture->GetArrayLayers())) {
return DAWN_VALIDATION_ERROR("Texture view array-layer out of range");
}
if (uint64_t(descriptor->baseMipLevel) + uint64_t(descriptor->levelCount) >
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:
@ -120,9 +213,16 @@ namespace dawn_native {
}
TextureViewBase* TextureBase::CreateDefaultTextureView() {
// TODO(jiawei.shao@intel.com): remove Device->CreateDefaultTextureView in all back-ends
// and implement this function by creating a TextureViewDescriptor based on the texture
// and calling CreateTextureView(&descriptor) instead.
return mDevice->CreateDefaultTextureView(this);
}
TextureViewBase* TextureBase::CreateTextureView(const TextureViewDescriptor* descriptor) {
return mDevice->CreateTextureView(this, descriptor);
}
// TextureViewBase
TextureViewBase::TextureViewBase(TextureBase* texture) : mTexture(texture) {

View File

@ -24,6 +24,9 @@
namespace dawn_native {
MaybeError ValidateTextureDescriptor(DeviceBase* device, const TextureDescriptor* descriptor);
MaybeError ValidateTextureViewDescriptor(const DeviceBase* device,
const TextureBase* texture,
const TextureViewDescriptor* descriptor);
uint32_t TextureFormatPixelSize(dawn::TextureFormat format);
bool TextureFormatHasDepth(dawn::TextureFormat format);
@ -52,6 +55,7 @@ namespace dawn_native {
// Dawn API
TextureViewBase* CreateDefaultTextureView();
TextureViewBase* CreateTextureView(const TextureViewDescriptor* descriptor);
private:
DeviceBase* mDevice;

View File

@ -337,6 +337,12 @@ namespace dawn_native { namespace d3d12 {
TextureViewBase* Device::CreateDefaultTextureView(TextureBase* texture) {
return new TextureView(texture);
}
// TODO(jiawei.shao@intel.com): implement creating texture view with TextureViewDescriptor
ResultOrError<TextureViewBase*> Device::CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) {
return DAWN_UNIMPLEMENTED_ERROR("Creating texture view with descriptor is unimplemented.");
}
void Device::CollectPCIInfo() {
memset(&mPCIInfo, 0, sizeof(mPCIInfo));

View File

@ -91,6 +91,9 @@ namespace dawn_native { namespace d3d12 {
ResultOrError<ShaderModuleBase*> CreateShaderModuleImpl(
const ShaderModuleDescriptor* descriptor) override;
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) override;
void CollectPCIInfo();
// Keep mFunctions as the first member so that in the destructor it is freed. Otherwise the

View File

@ -75,6 +75,9 @@ namespace dawn_native { namespace metal {
ResultOrError<ShaderModuleBase*> CreateShaderModuleImpl(
const ShaderModuleDescriptor* descriptor) override;
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) override;
void CollectPCIInfo();
void OnCompletedHandler();

View File

@ -135,6 +135,12 @@ namespace dawn_native { namespace metal {
TextureViewBase* Device::CreateDefaultTextureView(TextureBase* texture) {
return new TextureView(texture);
}
// TODO(jiawei.shao@intel.com): implement creating texture view with TextureViewDescriptor
ResultOrError<TextureViewBase*> Device::CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) {
return DAWN_UNIMPLEMENTED_ERROR("Creating texture view with descriptor is unimplemented.");
}
void Device::TickImpl() {
mResourceUploader->Tick(mFinishedCommandSerial);

View File

@ -98,6 +98,12 @@ namespace dawn_native { namespace null {
TextureViewBase* Device::CreateDefaultTextureView(TextureBase* texture) {
return new TextureView(texture);
}
// TODO(jiawei.shao@intel.com): implement creating texture view by TextureViewDescriptor
ResultOrError<TextureViewBase*> Device::CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) {
return new TextureView(texture);
}
void Device::InitFakePCIInfo() {
mPCIInfo.name = "Null backend";

View File

@ -127,6 +127,9 @@ namespace dawn_native { namespace null {
ResultOrError<ShaderModuleBase*> CreateShaderModuleImpl(
const ShaderModuleDescriptor* descriptor) override;
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) override;
void InitFakePCIInfo();
std::vector<std::unique_ptr<PendingOperation>> mPendingOperations;

View File

@ -109,6 +109,12 @@ namespace dawn_native { namespace opengl {
TextureViewBase* Device::CreateDefaultTextureView(TextureBase* texture) {
return new TextureView(texture);
}
// TODO(jiawei.shao@intel.com): implement creating texture view with TextureViewDescriptor
ResultOrError<TextureViewBase*> Device::CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) {
return DAWN_UNIMPLEMENTED_ERROR("Creating texture view with descriptor is unimplemented.");
}
void Device::TickImpl() {
}

View File

@ -62,6 +62,9 @@ namespace dawn_native { namespace opengl {
ResultOrError<ShaderModuleBase*> CreateShaderModuleImpl(
const ShaderModuleDescriptor* descriptor) override;
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) override;
void CollectPCIInfo();
dawn_native::PCIInfo mPCIInfo;

View File

@ -274,6 +274,13 @@ namespace dawn_native { namespace vulkan {
return new TextureView(texture);
}
// TODO(jiawei.shao@intel.com): implement creating texture view with TextureViewDescriptor
ResultOrError<TextureViewBase*> Device::CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) {
return DAWN_UNIMPLEMENTED_ERROR("Creating texture view with descriptor is unimplemented.");
}
void Device::TickImpl() {
CheckPassedFences();
RecycleCompletedCommands();

View File

@ -93,6 +93,9 @@ namespace dawn_native { namespace vulkan {
ResultOrError<ShaderModuleBase*> CreateShaderModuleImpl(
const ShaderModuleDescriptor* descriptor) override;
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture,
const TextureViewDescriptor* descriptor) override;
bool CreateInstance(VulkanGlobalKnobs* usedKnobs,
const std::vector<const char*>& requiredExtensions);

View File

@ -0,0 +1,155 @@
// Copyright 2018 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"
namespace {
class TextureViewValidationTest : public ValidationTest {
};
constexpr uint32_t kWidth = 32u;
constexpr uint32_t kHeight = 32u;
constexpr uint32_t kDefaultMipLevels = 6u;
constexpr dawn::TextureFormat kDefaultTextureFormat = dawn::TextureFormat::R8G8B8A8Unorm;
dawn::Texture Create2DArrayTexture(dawn::Device& device,
uint32_t arrayLayers,
dawn::TextureFormat format = kDefaultTextureFormat) {
dawn::TextureDescriptor descriptor;
descriptor.dimension = dawn::TextureDimension::e2D;
descriptor.size.width = kWidth;
descriptor.size.height = kHeight;
descriptor.size.depth = 1;
descriptor.arrayLayer = arrayLayers;
descriptor.format = format;
descriptor.mipLevel = kDefaultMipLevels;
descriptor.usage = dawn::TextureUsageBit::Sampled;
return device.CreateTexture(&descriptor);
}
dawn::TextureViewDescriptor CreateDefaultTextureViewDescriptor(dawn::TextureViewDimension dimension) {
dawn::TextureViewDescriptor descriptor;
descriptor.format = kDefaultTextureFormat;
descriptor.dimension = dimension;
descriptor.baseMipLevel = 0;
descriptor.levelCount = kDefaultMipLevels;
descriptor.baseArrayLayer = 0;
descriptor.layerCount = 1;
return descriptor;
}
// Test creating texture view on a 2D non-array texture
TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture2D) {
dawn::Texture texture = Create2DArrayTexture(device, 1);
dawn::TextureViewDescriptor base2DTextureViewDescriptor =
CreateDefaultTextureViewDescriptor(dawn::TextureViewDimension::e2D);
// It is OK to create a 2D texture view on a 2D texture.
{
dawn::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.layerCount = 1;
texture.CreateTextureView(&descriptor);
}
// It is an error to specify the layer count of the texture view > 1 when texture view dimension
// is 2D.
{
dawn::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.layerCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateTextureView(&descriptor));
}
// It is OK to create a 1-layer 2D array texture view on a 2D texture.
{
dawn::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.dimension = dawn::TextureViewDimension::e2DArray;
descriptor.layerCount = 1;
texture.CreateTextureView(&descriptor);
}
// It is an error to specify levelCount == 0.
{
dawn::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.levelCount = 0;
ASSERT_DEVICE_ERROR(texture.CreateTextureView(&descriptor));
}
// It is an error to make the mip level out of range.
{
dawn::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.baseMipLevel = kDefaultMipLevels - 1;
descriptor.levelCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateTextureView(&descriptor));
}
}
// Test creating texture view on a 2D array texture
TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture2DArray) {
constexpr uint32_t kDefaultArrayLayers = 6;
dawn::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
dawn::TextureViewDescriptor base2DArrayTextureViewDescriptor =
CreateDefaultTextureViewDescriptor(dawn::TextureViewDimension::e2DArray);
// It is OK to create a 2D texture view on a 2D array texture.
{
dawn::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = dawn::TextureViewDimension::e2D;
descriptor.layerCount = 1;
texture.CreateTextureView(&descriptor);
}
// It is OK to create a 2D array texture view on a 2D array texture.
{
dawn::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.layerCount = kDefaultArrayLayers;
texture.CreateTextureView(&descriptor);
}
// It is an error to specify layerCount == 0.
{
dawn::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.layerCount = 0;
ASSERT_DEVICE_ERROR(texture.CreateTextureView(&descriptor));
}
// It is an error to make the array layer out of range.
{
dawn::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.layerCount = kDefaultArrayLayers + 1;
ASSERT_DEVICE_ERROR(texture.CreateTextureView(&descriptor));
}
}
// Test the format compatibility rules when creating a texture view.
// TODO(jiawei.shao@intel.com): add more tests when the rules are fully implemented.
TEST_F(TextureViewValidationTest, TextureViewFormatCompatibility) {
dawn::Texture texture = Create2DArrayTexture(device, 1);
dawn::TextureViewDescriptor base2DTextureViewDescriptor =
CreateDefaultTextureViewDescriptor(dawn::TextureViewDimension::e2D);
// It is an error to create a texture view in depth-stencil format on a RGBA texture.
{
dawn::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.format = dawn::TextureFormat::D32FloatS8Uint;
ASSERT_DEVICE_ERROR(texture.CreateTextureView(&descriptor));
}
}
}