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:
parent
2787a59fcd
commit
e1f2dcd3b3
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in New Issue