diff --git a/dawn.json b/dawn.json index a5b0dcc9e0..8304b739e2 100644 --- a/dawn.json +++ b/dawn.json @@ -2519,6 +2519,38 @@ {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"} ] }, + { + "name": "get width", + "returns": "uint32_t" + }, + { + "name": "get height", + "returns": "uint32_t" + }, + { + "name": "get depth or array layers", + "returns": "uint32_t" + }, + { + "name": "get mip level count", + "returns": "uint32_t" + }, + { + "name": "get sample count", + "returns": "uint32_t" + }, + { + "name": "get dimension", + "returns": "texture dimension" + }, + { + "name": "get format", + "returns": "texture format" + }, + { + "name": "get usage", + "returns": "texture usage" + }, { "name": "destroy" } diff --git a/dawn_wire.json b/dawn_wire.json index 8ce3e90bb0..cb0db162d8 100644 --- a/dawn_wire.json +++ b/dawn_wire.json @@ -205,12 +205,21 @@ "ShaderModuleGetCompilationInfo", "QueueOnSubmittedWorkDone", "QueueWriteBuffer", - "QueueWriteTexture" + "QueueWriteTexture", + "TextureGetWidth", + "TextureGetHeight", + "TextureGetDepthOrArrayLayers", + "TextureGetMipLevelCount", + "TextureGetSampleCount", + "TextureGetDimension", + "TextureGetFormat", + "TextureGetUsage" ], "client_handwritten_commands": [ "BufferDestroy", "BufferUnmap", "DeviceCreateErrorBuffer", + "DeviceCreateTexture", "DeviceGetQueue", "DeviceInjectError" ], @@ -220,7 +229,8 @@ "Device", "Instance", "Queue", - "ShaderModule" + "ShaderModule", + "Texture" ], "server_custom_pre_handler_commands": [ "BufferDestroy", diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp index 420230b294..e933b154a4 100644 --- a/src/dawn/native/Device.cpp +++ b/src/dawn/native/Device.cpp @@ -1209,7 +1209,7 @@ TextureBase* DeviceBase::APICreateTexture(const TextureDescriptor* descriptor) { Ref result; if (ConsumedError(CreateTexture(descriptor), &result, "calling %s.CreateTexture(%s).", this, descriptor)) { - return TextureBase::MakeError(this); + return TextureBase::MakeError(this, descriptor); } return result.Detach(); } diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp index 75f8866d93..843b6cfe9d 100644 --- a/src/dawn/native/Texture.cpp +++ b/src/dawn/native/Texture.cpp @@ -529,7 +529,8 @@ TextureBase::TextureBase(DeviceBase* device, mSampleCount(descriptor->sampleCount), mUsage(descriptor->usage), mInternalUsage(mUsage), - mState(state) { + mState(state), + mFormatEnumForReflection(descriptor->format) { uint32_t subresourceCount = mMipLevelCount * GetArrayLayers() * GetAspectCount(mFormat.aspects); mIsSubresourceContentInitializedAtIndex = std::vector(subresourceCount, false); @@ -559,16 +560,25 @@ TextureBase::TextureBase(DeviceBase* device, TextureState state) TrackInDevice(); } -TextureBase::TextureBase(DeviceBase* device, ObjectBase::ErrorTag tag) - : ApiObjectBase(device, tag), mFormat(kUnusedFormat) {} +TextureBase::TextureBase(DeviceBase* device, + const TextureDescriptor* descriptor, + ObjectBase::ErrorTag tag) + : ApiObjectBase(device, tag), + mDimension(descriptor->dimension), + mFormat(kUnusedFormat), + mSize(descriptor->size), + mMipLevelCount(descriptor->mipLevelCount), + mSampleCount(descriptor->sampleCount), + mUsage(descriptor->usage), + mFormatEnumForReflection(descriptor->format) {} void TextureBase::DestroyImpl() { mState = TextureState::Destroyed; } // static -TextureBase* TextureBase::MakeError(DeviceBase* device) { - return new TextureBase(device, ObjectBase::kError); +TextureBase* TextureBase::MakeError(DeviceBase* device, const TextureDescriptor* descriptor) { + return new TextureBase(device, descriptor, ObjectBase::kError); } ObjectType TextureBase::GetType() const { @@ -767,6 +777,37 @@ void TextureBase::APIDestroy() { Destroy(); } +uint32_t TextureBase::APIGetWidth() const { + return mSize.width; +} + +uint32_t TextureBase::APIGetHeight() const { + return mSize.height; +} +uint32_t TextureBase::APIGetDepthOrArrayLayers() const { + return mSize.depthOrArrayLayers; +} + +uint32_t TextureBase::APIGetMipLevelCount() const { + return mMipLevelCount; +} + +uint32_t TextureBase::APIGetSampleCount() const { + return mSampleCount; +} + +wgpu::TextureDimension TextureBase::APIGetDimension() const { + return mDimension; +} + +wgpu::TextureFormat TextureBase::APIGetFormat() const { + return mFormatEnumForReflection; +} + +wgpu::TextureUsage TextureBase::APIGetUsage() const { + return mUsage; +} + MaybeError TextureBase::ValidateDestroy() const { DAWN_TRY(GetDevice()->ValidateObject(this)); return {}; diff --git a/src/dawn/native/Texture.h b/src/dawn/native/Texture.h index dff5dcb0d6..595809442b 100644 --- a/src/dawn/native/Texture.h +++ b/src/dawn/native/Texture.h @@ -47,7 +47,7 @@ class TextureBase : public ApiObjectBase { enum class TextureState { OwnedInternal, OwnedExternal, Destroyed }; enum class ClearValue { Zero, NonZero }; - static TextureBase* MakeError(DeviceBase* device); + static TextureBase* MakeError(DeviceBase* device, const TextureDescriptor* descriptor); ObjectType GetType() const override; @@ -96,6 +96,14 @@ class TextureBase : public ApiObjectBase { // Dawn API TextureViewBase* APICreateView(const TextureViewDescriptor* descriptor = nullptr); void APIDestroy(); + uint32_t APIGetWidth() const; + uint32_t APIGetHeight() const; + uint32_t APIGetDepthOrArrayLayers() const; + uint32_t APIGetMipLevelCount() const; + uint32_t APIGetSampleCount() const; + wgpu::TextureDimension APIGetDimension() const; + wgpu::TextureFormat APIGetFormat() const; + wgpu::TextureUsage APIGetUsage() const; protected: TextureBase(DeviceBase* device, const TextureDescriptor* descriptor, TextureState state); @@ -106,7 +114,7 @@ class TextureBase : public ApiObjectBase { void DestroyImpl() override; private: - TextureBase(DeviceBase* device, ObjectBase::ErrorTag tag); + TextureBase(DeviceBase* device, const TextureDescriptor* descriptor, ObjectBase::ErrorTag tag); MaybeError ValidateDestroy() const; wgpu::TextureDimension mDimension; @@ -118,6 +126,7 @@ class TextureBase : public ApiObjectBase { wgpu::TextureUsage mUsage = wgpu::TextureUsage::None; wgpu::TextureUsage mInternalUsage = wgpu::TextureUsage::None; TextureState mState; + wgpu::TextureFormat mFormatEnumForReflection; // TODO(crbug.com/dawn/845): Use a more optimized data structure to save space std::vector mIsSubresourceContentInitializedAtIndex; diff --git a/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp b/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp index f9a25ab417..03a70d2ced 100644 --- a/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp +++ b/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp @@ -204,6 +204,24 @@ TEST_F(TextureInternalUsageValidationTest, DeprecatedCommandValidation) { } } +// Test that the internal usages aren't reflected with wgpu::Texture::GetUsage. +TEST_F(TextureInternalUsageValidationTest, InternalUsagesAreNotReflected) { + wgpu::DawnTextureInternalUsageDescriptor internalDesc = {}; + internalDesc.internalUsage = wgpu::TextureUsage::StorageBinding; + + wgpu::TextureDescriptor textureDesc = {}; + textureDesc.size = {1, 1}; + textureDesc.usage = wgpu::TextureUsage::CopySrc; + textureDesc.format = wgpu::TextureFormat::RGBA8Unorm; + textureDesc.nextInChain = &internalDesc; + + wgpu::Texture texture = device.CreateTexture(&textureDesc); + ASSERT_EQ(texture.GetUsage(), wgpu::TextureUsage::CopySrc); +} + + +// Test the validation of internal usages against command encoders with and without +// useInternalUsages. TEST_F(TextureInternalUsageValidationTest, CommandValidation) { wgpu::TextureDescriptor textureDesc = {}; textureDesc.size = {1, 1}; diff --git a/src/dawn/tests/unittests/validation/TextureValidationTests.cpp b/src/dawn/tests/unittests/validation/TextureValidationTests.cpp index ffac5ada70..253354b961 100644 --- a/src/dawn/tests/unittests/validation/TextureValidationTests.cpp +++ b/src/dawn/tests/unittests/validation/TextureValidationTests.cpp @@ -906,4 +906,64 @@ TEST_F(CompressedTextureFormatsValidationTests, TextureSize) { } } +static void CheckTextureMatchesDescriptor(const wgpu::Texture& tex, + const wgpu::TextureDescriptor& desc) { + EXPECT_EQ(desc.size.width, tex.GetWidth()); + EXPECT_EQ(desc.size.height, tex.GetHeight()); + EXPECT_EQ(desc.size.depthOrArrayLayers, tex.GetDepthOrArrayLayers()); + EXPECT_EQ(desc.mipLevelCount, tex.GetMipLevelCount()); + EXPECT_EQ(desc.sampleCount, tex.GetSampleCount()); + EXPECT_EQ(desc.dimension, tex.GetDimension()); + EXPECT_EQ(desc.usage, tex.GetUsage()); + EXPECT_EQ(desc.format, tex.GetFormat()); +} + +// Test that the texture creation parameters are correctly reflected for succesfully created +// textures. +TEST_F(TextureValidationTest, CreationParameterReflectionForValidTextures) { + // Test reflection on two succesfully created but different textures. + { + wgpu::TextureDescriptor desc; + desc.size = {3, 2, 1}; + desc.mipLevelCount = 1; + desc.sampleCount = 4; + desc.dimension = wgpu::TextureDimension::e2D; + desc.usage = wgpu::TextureUsage::RenderAttachment; + desc.format = wgpu::TextureFormat::RGBA8Unorm; + wgpu::Texture tex = device.CreateTexture(&desc); + + CheckTextureMatchesDescriptor(tex, desc); + } + { + wgpu::TextureDescriptor desc; + desc.size = {47, 32, 19}; + desc.mipLevelCount = 3; + desc.sampleCount = 1; + desc.dimension = wgpu::TextureDimension::e3D; + desc.usage = wgpu::TextureUsage::TextureBinding; + desc.format = wgpu::TextureFormat::R32Float; + wgpu::Texture tex = device.CreateTexture(&desc); + + CheckTextureMatchesDescriptor(tex, desc); + } +} + +// Test that the texture creation parameters are correctly reflected for error textures. +TEST_F(TextureValidationTest, CreationParameterReflectionForErrorTextures) { + // Fill a descriptor with a bunch of garbage values. + wgpu::TextureDescriptor desc; + desc.size = {0, 0xFFFF'FFFF, 1}; + desc.mipLevelCount = 0; + desc.sampleCount = 42; + desc.dimension = static_cast(0xFFFF'FF00); + desc.usage = static_cast(0xFFFF'FFFF); + desc.format = static_cast(0xFFFF'FFF0); + + // Error! Because the texture width is 0. + wgpu::Texture tex; + ASSERT_DEVICE_ERROR(tex = device.CreateTexture(&desc)); + + CheckTextureMatchesDescriptor(tex, desc); +} + } // namespace diff --git a/src/dawn/wire/BUILD.gn b/src/dawn/wire/BUILD.gn index 4c20cd8473..8ca560b2d6 100644 --- a/src/dawn/wire/BUILD.gn +++ b/src/dawn/wire/BUILD.gn @@ -96,6 +96,8 @@ dawn_component("wire") { "client/RequestTracker.h", "client/ShaderModule.cpp", "client/ShaderModule.h", + "client/Texture.cpp", + "client/Texture.h", "server/ObjectStorage.h", "server/Server.cpp", "server/Server.h", diff --git a/src/dawn/wire/CMakeLists.txt b/src/dawn/wire/CMakeLists.txt index b69eea14da..469868973e 100644 --- a/src/dawn/wire/CMakeLists.txt +++ b/src/dawn/wire/CMakeLists.txt @@ -69,6 +69,8 @@ target_sources(dawn_wire PRIVATE "client/RequestTracker.h" "client/ShaderModule.cpp" "client/ShaderModule.h" + "client/Texture.cpp" + "client/Texture.h" "server/ObjectStorage.h" "server/Server.cpp" "server/Server.h" diff --git a/src/dawn/wire/client/ApiObjects.h b/src/dawn/wire/client/ApiObjects.h index 1998d5493e..14b6b7eb97 100644 --- a/src/dawn/wire/client/ApiObjects.h +++ b/src/dawn/wire/client/ApiObjects.h @@ -23,6 +23,7 @@ #include "dawn/wire/client/Instance.h" #include "dawn/wire/client/Queue.h" #include "dawn/wire/client/ShaderModule.h" +#include "dawn/wire/client/Texture.h" #include "dawn/wire/client/ApiObjects_autogen.h" diff --git a/src/dawn/wire/client/Device.cpp b/src/dawn/wire/client/Device.cpp index f4b24601b9..940764adb0 100644 --- a/src/dawn/wire/client/Device.cpp +++ b/src/dawn/wire/client/Device.cpp @@ -204,6 +204,10 @@ WGPUBuffer Device::CreateErrorBuffer() { return Buffer::CreateError(this, &fakeDescriptor); } +WGPUTexture Device::CreateTexture(const WGPUTextureDescriptor* descriptor) { + return Texture::Create(this, descriptor); +} + WGPUQueue Device::GetQueue() { // The queue is lazily created because if a Device is created by // Reserve/Inject, we cannot send the GetQueue message until diff --git a/src/dawn/wire/client/Device.h b/src/dawn/wire/client/Device.h index f613e6ab52..8a76cb989a 100644 --- a/src/dawn/wire/client/Device.h +++ b/src/dawn/wire/client/Device.h @@ -50,6 +50,7 @@ class Device final : public ObjectBase { void CreateRenderPipelineAsync(WGPURenderPipelineDescriptor const* descriptor, WGPUCreateRenderPipelineAsyncCallback callback, void* userdata); + WGPUTexture CreateTexture(const WGPUTextureDescriptor* descriptor); void HandleError(WGPUErrorType errorType, const char* message); void HandleLogging(WGPULoggingType loggingType, const char* message); diff --git a/src/dawn/wire/client/Texture.cpp b/src/dawn/wire/client/Texture.cpp new file mode 100644 index 0000000000..f4c0b97236 --- /dev/null +++ b/src/dawn/wire/client/Texture.cpp @@ -0,0 +1,82 @@ +// Copyright 2022 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/wire/client/Texture.h" + +#include "dawn/wire/client/Client.h" +#include "dawn/wire/client/Device.h" + +namespace dawn::wire::client { + +// static +WGPUTexture Texture::Create(Device* device, const WGPUTextureDescriptor* descriptor) { + Client* wireClient = device->client; + auto* textureObjectAndSerial = wireClient->TextureAllocator().New(wireClient); + + // Copy over descriptor data for reflection. + Texture* texture = textureObjectAndSerial->object.get(); + texture->mSize = descriptor->size; + texture->mMipLevelCount = descriptor->mipLevelCount; + texture->mSampleCount = descriptor->sampleCount; + texture->mDimension = descriptor->dimension; + texture->mFormat = descriptor->format; + texture->mUsage = static_cast(descriptor->usage); + + // Send the Device::CreateTexture command without modifications. + DeviceCreateTextureCmd cmd; + cmd.self = ToAPI(device); + cmd.selfId = device->id; + cmd.descriptor = descriptor; + cmd.result = ObjectHandle{texture->id, textureObjectAndSerial->generation}; + wireClient->SerializeCommand(cmd); + + return ToAPI(texture); +} + +Texture::Texture(Client* c, uint32_t r, uint32_t i) : ObjectBase(c, r, i) {} +Texture::~Texture() = default; + +uint32_t Texture::GetWidth() const { + return mSize.width; +} + +uint32_t Texture::GetHeight() const { + return mSize.height; +} + +uint32_t Texture::GetDepthOrArrayLayers() const { + return mSize.depthOrArrayLayers; +} + +uint32_t Texture::GetMipLevelCount() const { + return mMipLevelCount; +} + +uint32_t Texture::GetSampleCount() const { + return mSampleCount; +} + +WGPUTextureDimension Texture::GetDimension() const { + return mDimension; +} + +WGPUTextureFormat Texture::GetFormat() const { + return mFormat; +} + +WGPUTextureUsage Texture::GetUsage() const { + return mUsage; +} + +} // namespace dawn::wire::client diff --git a/src/dawn/wire/client/Texture.h b/src/dawn/wire/client/Texture.h new file mode 100644 index 0000000000..0bce2ea66c --- /dev/null +++ b/src/dawn/wire/client/Texture.h @@ -0,0 +1,54 @@ +// Copyright 2022 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 SRC_DAWN_WIRE_CLIENT_TEXTURE_H_ +#define SRC_DAWN_WIRE_CLIENT_TEXTURE_H_ + +#include "dawn/webgpu.h" + +#include "dawn/wire/client/ObjectBase.h" + +namespace dawn::wire::client { + +class Device; + +class Texture final : public ObjectBase { + public: + static WGPUTexture Create(Device* device, const WGPUTextureDescriptor* descriptor); + + Texture(Client* client, uint32_t refcount, uint32_t id); + ~Texture(); + + // Note that these values can be arbitrary since they aren't validated in the wire client. + uint32_t GetWidth() const; + uint32_t GetHeight() const; + uint32_t GetDepthOrArrayLayers() const; + uint32_t GetMipLevelCount() const; + uint32_t GetSampleCount() const; + WGPUTextureDimension GetDimension() const; + WGPUTextureFormat GetFormat() const; + WGPUTextureUsage GetUsage() const; + + private: + WGPUExtent3D mSize; + uint32_t mMipLevelCount; + uint32_t mSampleCount; + WGPUTextureDimension mDimension; + WGPUTextureFormat mFormat; + WGPUTextureUsage mUsage; +}; + +} // namespace dawn::wire::client + +#endif // SRC_DAWN_WIRE_CLIENT_TEXTURE_H_