Implement rendering with view format reinterpretation

Includes fixes for the backends to create and use a texture view
if reinterpretation is required. Multiple backends used the original
texture and its format instead of the view.

Bug: dawn:1276
Change-Id: Ic31231b2955314e90e011905c9048db6f7899299
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/84704
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Austin Eng 2022-04-07 12:14:55 +00:00 committed by Dawn LUCI CQ
parent 2787a59fcd
commit e1f2dcd3b3
10 changed files with 372 additions and 87 deletions

View File

@ -315,39 +315,38 @@ namespace dawn::native {
AddFormat(internalFormat); AddFormat(internalFormat);
}; };
auto AddMultiAspectFormat = auto AddMultiAspectFormat = [&AddFormat, &table](wgpu::TextureFormat format, Aspect aspects,
[&AddFormat, &table](wgpu::TextureFormat format, Aspect aspects, wgpu::TextureFormat firstFormat,
wgpu::TextureFormat firstFormat, wgpu::TextureFormat secondFormat, wgpu::TextureFormat secondFormat,
bool isRenderable, bool isSupported, bool supportsMultisample, bool isRenderable, bool isSupported,
uint8_t componentCount) { bool supportsMultisample,
Format internalFormat; uint8_t componentCount) {
internalFormat.format = format; Format internalFormat;
internalFormat.baseFormat = format; internalFormat.format = format;
internalFormat.isRenderable = isRenderable; internalFormat.baseFormat = format;
internalFormat.isCompressed = false; internalFormat.isRenderable = isRenderable;
internalFormat.isSupported = isSupported; internalFormat.isCompressed = false;
internalFormat.supportsStorageUsage = false; internalFormat.isSupported = isSupported;
internalFormat.supportsMultisample = supportsMultisample; internalFormat.supportsStorageUsage = false;
internalFormat.supportsResolveTarget = false; internalFormat.supportsMultisample = supportsMultisample;
internalFormat.aspects = aspects; internalFormat.supportsResolveTarget = false;
internalFormat.componentCount = componentCount; internalFormat.aspects = aspects;
internalFormat.componentCount = componentCount;
// Multi aspect formats just copy information about single-aspect formats. This // Multi aspect formats just copy information about single-aspect formats. This
// means that the single-plane formats must have been added before multi-aspect // means that the single-plane formats must have been added before multi-aspect
// ones. (it is ASSERTed below). // ones. (it is ASSERTed below).
const FormatIndex firstFormatIndex = ComputeFormatIndex(firstFormat); const FormatIndex firstFormatIndex = ComputeFormatIndex(firstFormat);
const FormatIndex secondFormatIndex = ComputeFormatIndex(secondFormat); const FormatIndex secondFormatIndex = ComputeFormatIndex(secondFormat);
ASSERT(table[firstFormatIndex].aspectInfo[0].format != ASSERT(table[firstFormatIndex].aspectInfo[0].format != wgpu::TextureFormat::Undefined);
wgpu::TextureFormat::Undefined); ASSERT(table[secondFormatIndex].aspectInfo[0].format != wgpu::TextureFormat::Undefined);
ASSERT(table[secondFormatIndex].aspectInfo[0].format !=
wgpu::TextureFormat::Undefined);
internalFormat.aspectInfo[0] = table[firstFormatIndex].aspectInfo[0]; internalFormat.aspectInfo[0] = table[firstFormatIndex].aspectInfo[0];
internalFormat.aspectInfo[1] = table[secondFormatIndex].aspectInfo[0]; internalFormat.aspectInfo[1] = table[secondFormatIndex].aspectInfo[0];
AddFormat(internalFormat); AddFormat(internalFormat);
}; };
// clang-format off // clang-format off
// 1 byte color formats // 1 byte color formats

View File

@ -909,11 +909,12 @@ namespace dawn::native::d3d12 {
}); });
} }
D3D12_RENDER_TARGET_VIEW_DESC Texture::GetRTVDescriptor(uint32_t mipLevel, D3D12_RENDER_TARGET_VIEW_DESC Texture::GetRTVDescriptor(const Format& format,
uint32_t mipLevel,
uint32_t baseSlice, uint32_t baseSlice,
uint32_t sliceCount) const { uint32_t sliceCount) const {
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
rtvDesc.Format = GetD3D12Format(); rtvDesc.Format = D3D12TextureFormat(format.format);
if (IsMultisampledTexture()) { if (IsMultisampledTexture()) {
ASSERT(GetDimension() == wgpu::TextureDimension::e2D); ASSERT(GetDimension() == wgpu::TextureDimension::e2D);
ASSERT(GetNumMipLevels() == 1); ASSERT(GetNumMipLevels() == 1);
@ -1070,7 +1071,7 @@ namespace dawn::native::d3d12 {
sliceCount = std::max(GetDepth() >> level, 1u); sliceCount = std::max(GetDepth() >> level, 1u);
} }
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = D3D12_RENDER_TARGET_VIEW_DESC rtvDesc =
GetRTVDescriptor(level, baseSlice, sliceCount); GetRTVDescriptor(GetFormat(), level, baseSlice, sliceCount);
device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(), &rtvDesc, device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(), &rtvDesc,
rtvHandle); rtvHandle);
commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr); commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr);
@ -1340,7 +1341,8 @@ namespace dawn::native::d3d12 {
D3D12_RENDER_TARGET_VIEW_DESC TextureView::GetRTVDescriptor() const { D3D12_RENDER_TARGET_VIEW_DESC TextureView::GetRTVDescriptor() const {
return ToBackend(GetTexture()) return ToBackend(GetTexture())
->GetRTVDescriptor(GetBaseMipLevel(), GetBaseArrayLayer(), GetLayerCount()); ->GetRTVDescriptor(GetFormat(), GetBaseMipLevel(), GetBaseArrayLayer(),
GetLayerCount());
} }
D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor(bool depthReadOnly, D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor(bool depthReadOnly,

View File

@ -55,7 +55,8 @@ namespace dawn::native::d3d12 {
ID3D12Resource* GetD3D12Resource() const; ID3D12Resource* GetD3D12Resource() const;
DXGI_FORMAT GetD3D12CopyableSubresourceFormat(Aspect aspect) const; DXGI_FORMAT GetD3D12CopyableSubresourceFormat(Aspect aspect) const;
D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(uint32_t mipLevel, D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(const Format& format,
uint32_t mipLevel,
uint32_t baseSlice, uint32_t baseSlice,
uint32_t sliceCount) const; uint32_t sliceCount) const;
D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor(uint32_t mipLevel, D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor(uint32_t mipLevel,

View File

@ -87,19 +87,18 @@ namespace dawn::native::metal {
break; break;
} }
descriptor.colorAttachments[i].texture = auto colorAttachment = ToBackend(attachmentInfo.view)->GetAttachmentInfo();
ToBackend(attachmentInfo.view->GetTexture())->GetMTLTexture(); descriptor.colorAttachments[i].texture = colorAttachment.texture.Get();
descriptor.colorAttachments[i].level = attachmentInfo.view->GetBaseMipLevel(); descriptor.colorAttachments[i].level = colorAttachment.baseMipLevel;
descriptor.colorAttachments[i].slice = attachmentInfo.view->GetBaseArrayLayer(); descriptor.colorAttachments[i].slice = colorAttachment.baseArrayLayer;
bool hasResolveTarget = attachmentInfo.resolveTarget != nullptr; bool hasResolveTarget = attachmentInfo.resolveTarget != nullptr;
if (hasResolveTarget) { if (hasResolveTarget) {
descriptor.colorAttachments[i].resolveTexture = auto resolveAttachment =
ToBackend(attachmentInfo.resolveTarget->GetTexture())->GetMTLTexture(); ToBackend(attachmentInfo.resolveTarget)->GetAttachmentInfo();
descriptor.colorAttachments[i].resolveLevel = descriptor.colorAttachments[i].resolveTexture = resolveAttachment.texture.Get();
attachmentInfo.resolveTarget->GetBaseMipLevel(); descriptor.colorAttachments[i].resolveLevel = resolveAttachment.baseMipLevel;
descriptor.colorAttachments[i].resolveSlice = descriptor.colorAttachments[i].resolveSlice = resolveAttachment.baseArrayLayer;
attachmentInfo.resolveTarget->GetBaseArrayLayer();
switch (attachmentInfo.storeOp) { switch (attachmentInfo.storeOp) {
case wgpu::StoreOp::Store: case wgpu::StoreOp::Store:
@ -132,14 +131,13 @@ namespace dawn::native::metal {
if (renderPass->attachmentState->HasDepthStencilAttachment()) { if (renderPass->attachmentState->HasDepthStencilAttachment()) {
auto& attachmentInfo = renderPass->depthStencilAttachment; auto& attachmentInfo = renderPass->depthStencilAttachment;
id<MTLTexture> texture = auto depthStencilAttachment = ToBackend(attachmentInfo.view)->GetAttachmentInfo();
ToBackend(attachmentInfo.view->GetTexture())->GetMTLTexture(); const Format& format = attachmentInfo.view->GetFormat();
const Format& format = attachmentInfo.view->GetTexture()->GetFormat();
if (format.HasDepth()) { if (format.HasDepth()) {
descriptor.depthAttachment.texture = texture; descriptor.depthAttachment.texture = depthStencilAttachment.texture.Get();
descriptor.depthAttachment.level = attachmentInfo.view->GetBaseMipLevel(); descriptor.depthAttachment.level = depthStencilAttachment.baseMipLevel;
descriptor.depthAttachment.slice = attachmentInfo.view->GetBaseArrayLayer(); descriptor.depthAttachment.slice = depthStencilAttachment.baseArrayLayer;
switch (attachmentInfo.depthStoreOp) { switch (attachmentInfo.depthStoreOp) {
case wgpu::StoreOp::Store: case wgpu::StoreOp::Store:
@ -172,9 +170,9 @@ namespace dawn::native::metal {
} }
if (format.HasStencil()) { if (format.HasStencil()) {
descriptor.stencilAttachment.texture = texture; descriptor.stencilAttachment.texture = depthStencilAttachment.texture.Get();
descriptor.stencilAttachment.level = attachmentInfo.view->GetBaseMipLevel(); descriptor.stencilAttachment.level = depthStencilAttachment.baseMipLevel;
descriptor.stencilAttachment.slice = attachmentInfo.view->GetBaseArrayLayer(); descriptor.stencilAttachment.slice = depthStencilAttachment.baseArrayLayer;
switch (attachmentInfo.stencilStoreOp) { switch (attachmentInfo.stencilStoreOp) {
case wgpu::StoreOp::Store: case wgpu::StoreOp::Store:

View File

@ -46,7 +46,7 @@ namespace dawn::native::metal {
const TextureDescriptor* descriptor, const TextureDescriptor* descriptor,
NSPRef<id<MTLTexture>> wrapped); NSPRef<id<MTLTexture>> wrapped);
id<MTLTexture> GetMTLTexture(); id<MTLTexture> GetMTLTexture() const;
IOSurfaceRef GetIOSurface(); IOSurfaceRef GetIOSurface();
NSPRef<id<MTLTexture>> CreateFormatView(wgpu::TextureFormat format); NSPRef<id<MTLTexture>> CreateFormatView(wgpu::TextureFormat format);
@ -83,12 +83,20 @@ namespace dawn::native::metal {
static ResultOrError<Ref<TextureView>> Create(TextureBase* texture, static ResultOrError<Ref<TextureView>> Create(TextureBase* texture,
const TextureViewDescriptor* descriptor); const TextureViewDescriptor* descriptor);
id<MTLTexture> GetMTLTexture(); id<MTLTexture> GetMTLTexture() const;
struct AttachmentInfo {
NSPRef<id<MTLTexture>> texture;
uint32_t baseMipLevel;
uint32_t baseArrayLayer;
};
AttachmentInfo GetAttachmentInfo() const;
private: private:
using TextureViewBase::TextureViewBase; using TextureViewBase::TextureViewBase;
MaybeError Initialize(const TextureViewDescriptor* descriptor); MaybeError Initialize(const TextureViewDescriptor* descriptor);
// TODO(crbug.com/dawn/1355): Clear this reference on texture destroy.
NSPRef<id<MTLTexture>> mMtlTextureView; NSPRef<id<MTLTexture>> mMtlTextureView;
}; };

View File

@ -28,11 +28,6 @@
namespace dawn::native::metal { namespace dawn::native::metal {
namespace { namespace {
bool UsageNeedsTextureView(wgpu::TextureUsage usage) {
constexpr wgpu::TextureUsage kUsageNeedsTextureView =
wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::TextureBinding;
return usage & kUsageNeedsTextureView;
}
MTLTextureUsage MetalTextureUsage(const Format& format, MTLTextureUsage MetalTextureUsage(const Format& format,
wgpu::TextureUsage usage, wgpu::TextureUsage usage,
@ -46,8 +41,10 @@ namespace dawn::native::metal {
if (usage & (wgpu::TextureUsage::TextureBinding)) { if (usage & (wgpu::TextureUsage::TextureBinding)) {
result |= MTLTextureUsageShaderRead; result |= MTLTextureUsageShaderRead;
// For sampling stencil aspect of combined depth/stencil. See TextureView // For sampling stencil aspect of combined depth/stencil.
// constructor. // See TextureView::Initialize.
// Depth views for depth/stencil textures in Metal simply use the original
// texture's format, but stencil views require format reinterpretation.
if (@available(macOS 10.12, iOS 10.0, *)) { if (@available(macOS 10.12, iOS 10.0, *)) {
if (IsSubset(Aspect::Depth | Aspect::Stencil, format.aspects)) { if (IsSubset(Aspect::Depth | Aspect::Stencil, format.aspects)) {
result |= MTLTextureUsagePixelFormatView; result |= MTLTextureUsagePixelFormatView;
@ -86,13 +83,28 @@ namespace dawn::native::metal {
bool RequiresCreatingNewTextureView(const TextureBase* texture, bool RequiresCreatingNewTextureView(const TextureBase* texture,
const TextureViewDescriptor* textureViewDescriptor) { const TextureViewDescriptor* textureViewDescriptor) {
constexpr wgpu::TextureUsage kShaderUsageNeedsView =
wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::TextureBinding;
constexpr wgpu::TextureUsage kUsageNeedsView =
kShaderUsageNeedsView | wgpu::TextureUsage::RenderAttachment;
if ((texture->GetInternalUsage() & kUsageNeedsView) == 0) {
return false;
}
if (texture->GetFormat().format != textureViewDescriptor->format && if (texture->GetFormat().format != textureViewDescriptor->format &&
!texture->GetFormat().HasDepthOrStencil()) { !texture->GetFormat().HasDepthOrStencil()) {
// Color format reinterpretation required. Note: Depth/stencil formats don't support // Color format reinterpretation required.
// reinterpretation. // Note: Depth/stencil formats don't support reinterpretation.
// See also TextureView::GetAttachmentInfo when modifying this condition.
return true; return true;
} }
// Reinterpretation not required. Now, we only need a new view if the view dimension or
// set of subresources for the shader is different from the base texture.
if ((texture->GetInternalUsage() & kShaderUsageNeedsView) == 0) {
return false;
}
if (texture->GetArrayLayers() != textureViewDescriptor->arrayLayerCount || if (texture->GetArrayLayers() != textureViewDescriptor->arrayLayerCount ||
(texture->GetArrayLayers() == 1 && (texture->GetArrayLayers() == 1 &&
texture->GetDimension() == wgpu::TextureDimension::e2D && texture->GetDimension() == wgpu::TextureDimension::e2D &&
@ -107,8 +119,11 @@ namespace dawn::native::metal {
return true; return true;
} }
if (IsSubset(Aspect::Depth | Aspect::Stencil, texture->GetFormat().aspects) && // If the texture is created with MTLTextureUsagePixelFormatView, we need
textureViewDescriptor->aspect == wgpu::TextureAspect::StencilOnly) { // a new view to perform format reinterpretation.
if ((MetalTextureUsage(texture->GetFormat(), texture->GetInternalUsage(),
texture->GetSampleCount()) &
MTLTextureUsagePixelFormatView) != 0) {
return true; return true;
} }
@ -776,7 +791,7 @@ namespace dawn::native::metal {
mIOSurface = nullptr; mIOSurface = nullptr;
} }
id<MTLTexture> Texture::GetMTLTexture() { id<MTLTexture> Texture::GetMTLTexture() const {
return mMtlTexture.Get(); return mMtlTexture.Get();
} }
@ -1026,9 +1041,7 @@ namespace dawn::native::metal {
id<MTLTexture> mtlTexture = texture->GetMTLTexture(); id<MTLTexture> mtlTexture = texture->GetMTLTexture();
if (!UsageNeedsTextureView(texture->GetInternalUsage())) { if (!RequiresCreatingNewTextureView(texture, descriptor)) {
mMtlTextureView = nullptr;
} else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
mMtlTextureView = mtlTexture; mMtlTextureView = mtlTexture;
} else if (texture->GetFormat().IsMultiPlanar()) { } else if (texture->GetFormat().IsMultiPlanar()) {
NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]); NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
@ -1112,8 +1125,30 @@ namespace dawn::native::metal {
return {}; return {};
} }
id<MTLTexture> TextureView::GetMTLTexture() { id<MTLTexture> TextureView::GetMTLTexture() const {
ASSERT(mMtlTextureView != nullptr); ASSERT(mMtlTextureView != nullptr);
return mMtlTextureView.Get(); return mMtlTextureView.Get();
} }
TextureView::AttachmentInfo TextureView::GetAttachmentInfo() const {
ASSERT(GetTexture()->GetInternalUsage() & wgpu::TextureUsage::RenderAttachment);
// Use our own view if the formats do not match.
// If the formats do not match, format reinterpretation will be required.
// Note: Depth/stencil formats don't support reinterpretation.
// Also, we compute |useOwnView| here instead of relying on whether or not
// a view was created in Initialize, because rendering to a depth/stencil
// texture on Metal only works when using the original texture, not a view.
bool useOwnView = GetFormat().format != GetTexture()->GetFormat().format &&
!GetTexture()->GetFormat().HasDepthOrStencil();
if (useOwnView) {
ASSERT(mMtlTextureView.Get());
return {mMtlTextureView, 0, 0};
}
AttachmentInfo info;
info.texture = ToBackend(GetTexture())->GetMTLTexture();
info.baseMipLevel = GetBaseMipLevel();
info.baseArrayLayer = GetBaseArrayLayer();
return info;
}
} // namespace dawn::native::metal } // namespace dawn::native::metal

View File

@ -87,14 +87,16 @@ namespace dawn::native::opengl {
return handle; return handle;
} }
bool UsageNeedsTextureView(wgpu::TextureUsage usage) {
constexpr wgpu::TextureUsage kUsageNeedingTextureView =
wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::TextureBinding;
return usage & kUsageNeedingTextureView;
}
bool RequiresCreatingNewTextureView(const TextureBase* texture, bool RequiresCreatingNewTextureView(const TextureBase* texture,
const TextureViewDescriptor* textureViewDescriptor) { const TextureViewDescriptor* textureViewDescriptor) {
constexpr wgpu::TextureUsage kShaderUsageNeedsView =
wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::TextureBinding;
constexpr wgpu::TextureUsage kUsageNeedsView =
kShaderUsageNeedsView | wgpu::TextureUsage::RenderAttachment;
if ((texture->GetInternalUsage() & kUsageNeedsView) == 0) {
return false;
}
if (texture->GetFormat().format != textureViewDescriptor->format && if (texture->GetFormat().format != textureViewDescriptor->format &&
!texture->GetFormat().HasDepthOrStencil()) { !texture->GetFormat().HasDepthOrStencil()) {
// Color format reinterpretation required. Note: Depth/stencil formats don't support // Color format reinterpretation required. Note: Depth/stencil formats don't support
@ -102,6 +104,12 @@ namespace dawn::native::opengl {
return true; return true;
} }
// Reinterpretation not required. Now, we only need a new view if the view dimension or
// set of subresources for the shader is different from the base texture.
if ((texture->GetInternalUsage() & kShaderUsageNeedsView) == 0) {
return false;
}
if (texture->GetArrayLayers() != textureViewDescriptor->arrayLayerCount || if (texture->GetArrayLayers() != textureViewDescriptor->arrayLayerCount ||
(texture->GetArrayLayers() == 1 && (texture->GetArrayLayers() == 1 &&
texture->GetDimension() == wgpu::TextureDimension::e2D && texture->GetDimension() == wgpu::TextureDimension::e2D &&
@ -554,9 +562,7 @@ namespace dawn::native::opengl {
return; return;
} }
if (!UsageNeedsTextureView(texture->GetUsage())) { if (!RequiresCreatingNewTextureView(texture, descriptor)) {
mHandle = 0;
} else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
mHandle = ToBackend(texture)->GetHandle(); mHandle = ToBackend(texture)->GetHandle();
} else { } else {
// glTextureView() is supported on OpenGL version >= 4.3 // glTextureView() is supported on OpenGL version >= 4.3
@ -601,13 +607,26 @@ namespace dawn::native::opengl {
void TextureView::BindToFramebuffer(GLenum target, GLenum attachment) { void TextureView::BindToFramebuffer(GLenum target, GLenum attachment) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
// Use the texture's handle and target, and the view's base mip level and base array layer GLuint handle, textarget, mipLevel, arrayLayer;
GLuint handle = ToBackend(GetTexture())->GetHandle(); if (mOwnsHandle) {
GLuint textarget = ToBackend(GetTexture())->GetGLTarget(); // Use our own texture handle and target which points to a subset of the texture's
GLuint mipLevel = GetBaseMipLevel(); // subresources.
handle = GetHandle();
textarget = GetGLTarget();
mipLevel = 0;
arrayLayer = 0;
} else {
// Use the texture's handle and target, with the view's base mip level and base array
// layer.
handle = ToBackend(GetTexture())->GetHandle();
textarget = ToBackend(GetTexture())->GetGLTarget();
mipLevel = GetBaseMipLevel();
arrayLayer = GetBaseArrayLayer();
}
ASSERT(handle != 0);
if (textarget == GL_TEXTURE_2D_ARRAY || textarget == GL_TEXTURE_3D) { if (textarget == GL_TEXTURE_2D_ARRAY || textarget == GL_TEXTURE_3D) {
gl.FramebufferTextureLayer(target, attachment, handle, mipLevel, GetBaseArrayLayer()); gl.FramebufferTextureLayer(target, attachment, handle, mipLevel, arrayLayer);
} else { } else {
gl.FramebufferTexture2D(target, attachment, textarget, handle, mipLevel); gl.FramebufferTexture2D(target, attachment, textarget, handle, mipLevel);
} }

View File

@ -60,6 +60,7 @@ namespace dawn::native::opengl {
~TextureView() override; ~TextureView() override;
void DestroyImpl() override; void DestroyImpl() override;
// TODO(crbug.com/dawn/1355): Delete this handle on texture destroy.
GLuint mHandle; GLuint mHandle;
GLenum mTarget; GLenum mTarget;
bool mOwnsHandle; bool mOwnsHandle;

View File

@ -433,7 +433,7 @@ namespace dawn::native::vulkan {
config.alphaMode = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; config.alphaMode = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
#if !defined(DAWN_PLATFORM_ANDROID) #if !defined(DAWN_PLATFORM_ANDROID)
DAWN_INVALID_IF((surfaceInfo.capabilities.supportedCompositeAlpha & DAWN_INVALID_IF((surfaceInfo.capabilities.supportedCompositeAlpha &
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) == 0, VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) == 0,
"Vulkan SwapChain must support opaque alpha."); "Vulkan SwapChain must support opaque alpha.");
#else #else
// TODO(dawn:286): investigate composite alpha for WebGPU native // TODO(dawn:286): investigate composite alpha for WebGPU native

View File

@ -438,7 +438,7 @@ TEST_P(TextureViewSamplingTest, Texture2DArrayViewOnOneLevelOf2DArrayTexture) {
Texture2DArrayViewTest(6, 6, 2, 4); Texture2DArrayViewTest(6, 6, 2, 4);
} }
// Test that an RGBA8 texture may be interpreted as RGBA8UnormSrgb // Test that an RGBA8 texture may be interpreted as RGBA8UnormSrgb and sampled from.
// More extensive color value checks and format tests are left for the CTS. // More extensive color value checks and format tests are left for the CTS.
TEST_P(TextureViewSamplingTest, SRGBReinterpretation) { TEST_P(TextureViewSamplingTest, SRGBReinterpretation) {
// TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES. // TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
@ -772,6 +772,226 @@ TEST_P(TextureViewRenderingTest, Texture2DArrayViewOnALayerOf2DArrayTextureAsCol
} }
} }
// Test that an RGBA8 texture may be interpreted as RGBA8UnormSrgb and rendered to.
// More extensive color value checks and format tests are left for the CTS.
TEST_P(TextureViewRenderingTest, SRGBReinterpretationRenderAttachment) {
// TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
// Test will render into an SRGB view
wgpu::TextureViewDescriptor viewDesc = {};
viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb;
// Make an RGBA8Unorm texture to back the SRGB view.
wgpu::TextureDescriptor textureDesc = {};
textureDesc.size = {2, 2, 1};
textureDesc.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment;
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
textureDesc.viewFormats = &viewDesc.format;
textureDesc.viewFormatCount = 1;
wgpu::Texture texture = device.CreateTexture(&textureDesc);
// Make an RGBA8Unorm sampled texture as the source.
textureDesc.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding;
wgpu::Texture sampledTexture = device.CreateTexture(&textureDesc);
// Initial non-SRGB data to upload to |sampledTexture|.
std::array<RGBA8, 4> rgbaTextureData = {
RGBA8(117, 0, 0, 255),
RGBA8(0, 23, 0, 127),
RGBA8(0, 0, 12, 100),
RGBA8(13, 117, 24, 90),
};
wgpu::ImageCopyTexture dst = {};
wgpu::TextureDataLayout dataLayout = {};
// Upload |rgbaTextureData| into |sampledTexture|.
dst.texture = sampledTexture;
dataLayout.bytesPerRow = textureDesc.size.width * sizeof(RGBA8);
queue.WriteTexture(&dst, rgbaTextureData.data(), rgbaTextureData.size() * sizeof(RGBA8),
&dataLayout, &textureDesc.size);
// View both the attachment as SRGB.
wgpu::TextureView textureView = texture.CreateView(&viewDesc);
// Create a render pipeline to blit |sampledTexture| into |textureView|.
utils::ComboRenderPipelineDescriptor pipelineDesc;
pipelineDesc.vertex.module = utils::CreateShaderModule(device, R"(
@stage(vertex)
fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> {
var pos = array<vec2<f32>, 6>(
vec2<f32>(-1.0, -1.0),
vec2<f32>(-1.0, 1.0),
vec2<f32>( 1.0, -1.0),
vec2<f32>(-1.0, 1.0),
vec2<f32>( 1.0, -1.0),
vec2<f32>( 1.0, 1.0));
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
}
)");
pipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
@group(0) @binding(0) var texture : texture_2d<f32>;
@stage(fragment)
fn main(@builtin(position) coord: vec4<f32>) -> @location(0) vec4<f32> {
return textureLoad(texture, vec2<i32>(coord.xy), 0);
}
)");
pipelineDesc.cTargets[0].format = viewDesc.format;
// Submit a render pass to perform the blit from |sampledTexture| to |textureView|.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{{0, sampledTexture.CreateView()}});
utils::ComboRenderPassDescriptor renderPassInfo{textureView};
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassInfo);
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(6);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
// Check the results. This is the sRGB encoding for the same non-SRGB colors
// represented by |initialData|.
EXPECT_PIXEL_RGBA8_BETWEEN( //
RGBA8(180, 0, 0, 255), //
RGBA8(181, 0, 0, 255), texture, 0, 0);
EXPECT_PIXEL_RGBA8_BETWEEN( //
RGBA8(0, 85, 0, 127), //
RGBA8(0, 86, 0, 127), texture, 1, 0);
EXPECT_PIXEL_RGBA8_BETWEEN( //
RGBA8(0, 0, 61, 100), //
RGBA8(0, 0, 62, 100), texture, 0, 1);
EXPECT_PIXEL_RGBA8_BETWEEN( //
RGBA8(64, 180, 86, 90), //
RGBA8(15, 181, 87, 90), texture, 1, 1);
}
// Test that an RGBA8 texture may be interpreted as RGBA8UnormSrgb and resolved to.
// More extensive color value checks and format tests are left for the CTS.
// This test samples the RGBA8Unorm texture into an RGBA8Unorm multisample texture viewed as SRGB,
// and resolves it into an RGBA8Unorm texture, viewed as SRGB.
TEST_P(TextureViewRenderingTest, SRGBReinterpretionResolveAttachment) {
// TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
// Test will resolve into an SRGB view
wgpu::TextureViewDescriptor viewDesc = {};
viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb;
// Make an RGBA8Unorm texture to back the SRGB view.
wgpu::TextureDescriptor textureDesc = {};
textureDesc.size = {2, 2, 1};
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
textureDesc.viewFormats = &viewDesc.format;
textureDesc.viewFormatCount = 1;
textureDesc.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment;
wgpu::Texture resolveTexture = device.CreateTexture(&textureDesc);
// Make an RGBA8Unorm multisampled texture for the color attachment.
textureDesc.sampleCount = 4;
textureDesc.usage = wgpu::TextureUsage::RenderAttachment;
wgpu::Texture multisampledTexture = device.CreateTexture(&textureDesc);
// Make an RGBA8Unorm sampled texture as the source.
textureDesc.sampleCount = 1;
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
textureDesc.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding;
wgpu::Texture sampledTexture = device.CreateTexture(&textureDesc);
// Initial non-SRGB data to upload to |sampledTexture|.
std::array<RGBA8, 4> rgbaTextureData = {
RGBA8(117, 0, 0, 255),
RGBA8(0, 23, 0, 127),
RGBA8(0, 0, 12, 100),
RGBA8(13, 117, 24, 90),
};
wgpu::ImageCopyTexture dst = {};
wgpu::TextureDataLayout dataLayout = {};
// Upload |rgbaTextureData| into |sampledTexture|.
dst.texture = sampledTexture;
dataLayout.bytesPerRow = textureDesc.size.width * sizeof(RGBA8);
queue.WriteTexture(&dst, rgbaTextureData.data(), rgbaTextureData.size() * sizeof(RGBA8),
&dataLayout, &textureDesc.size);
// View both the multisampled texture and the resolve texture as SRGB.
wgpu::TextureView resolveView = resolveTexture.CreateView(&viewDesc);
wgpu::TextureView multisampledTextureView = multisampledTexture.CreateView(&viewDesc);
// Create a render pipeline to blit |sampledTexture| into |multisampledTextureView|.
utils::ComboRenderPipelineDescriptor pipelineDesc;
pipelineDesc.vertex.module = utils::CreateShaderModule(device, R"(
@stage(vertex)
fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> {
var pos = array<vec2<f32>, 6>(
vec2<f32>(-1.0, -1.0),
vec2<f32>(-1.0, 1.0),
vec2<f32>( 1.0, -1.0),
vec2<f32>(-1.0, 1.0),
vec2<f32>( 1.0, -1.0),
vec2<f32>( 1.0, 1.0));
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
}
)");
pipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
@group(0) @binding(0) var texture : texture_2d<f32>;
@stage(fragment)
fn main(@builtin(position) coord: vec4<f32>) -> @location(0) vec4<f32> {
return textureLoad(texture, vec2<i32>(coord.xy), 0);
}
)");
pipelineDesc.cTargets[0].format = viewDesc.format;
pipelineDesc.multisample.count = 4;
// Submit a render pass to perform the blit from |sampledTexture| to |multisampledTextureView|.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{{0, sampledTexture.CreateView()}});
utils::ComboRenderPassDescriptor renderPassInfo{multisampledTextureView};
renderPassInfo.cColorAttachments[0].resolveTarget = resolveView;
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassInfo);
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(6);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
// Check the results. This is the sRGB encoding for the same non-SRGB colors
// represented by |initialData|.
EXPECT_PIXEL_RGBA8_BETWEEN( //
RGBA8(180, 0, 0, 255), //
RGBA8(181, 0, 0, 255), resolveTexture, 0, 0);
EXPECT_PIXEL_RGBA8_BETWEEN( //
RGBA8(0, 85, 0, 127), //
RGBA8(0, 86, 0, 127), resolveTexture, 1, 0);
EXPECT_PIXEL_RGBA8_BETWEEN( //
RGBA8(0, 0, 61, 100), //
RGBA8(0, 0, 62, 100), resolveTexture, 0, 1);
EXPECT_PIXEL_RGBA8_BETWEEN( //
RGBA8(64, 180, 86, 90), //
RGBA8(15, 181, 87, 90), resolveTexture, 1, 1);
}
DAWN_INSTANTIATE_TEST(TextureViewSamplingTest, DAWN_INSTANTIATE_TEST(TextureViewSamplingTest,
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),
@ -781,7 +1001,9 @@ DAWN_INSTANTIATE_TEST(TextureViewSamplingTest,
DAWN_INSTANTIATE_TEST(TextureViewRenderingTest, DAWN_INSTANTIATE_TEST(TextureViewRenderingTest,
D3D12Backend(), D3D12Backend(),
D3D12Backend({}, {"use_d3d12_render_pass"}),
MetalBackend(), MetalBackend(),
MetalBackend({"emulate_store_and_msaa_resolve"}),
OpenGLBackend(), OpenGLBackend(),
OpenGLESBackend(), OpenGLESBackend(),
VulkanBackend()); VulkanBackend());