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,10 +315,11 @@ namespace dawn::native {
|
|||
AddFormat(internalFormat);
|
||||
};
|
||||
|
||||
auto AddMultiAspectFormat =
|
||||
[&AddFormat, &table](wgpu::TextureFormat format, Aspect aspects,
|
||||
wgpu::TextureFormat firstFormat, wgpu::TextureFormat secondFormat,
|
||||
bool isRenderable, bool isSupported, bool supportsMultisample,
|
||||
auto AddMultiAspectFormat = [&AddFormat, &table](wgpu::TextureFormat format, Aspect aspects,
|
||||
wgpu::TextureFormat firstFormat,
|
||||
wgpu::TextureFormat secondFormat,
|
||||
bool isRenderable, bool isSupported,
|
||||
bool supportsMultisample,
|
||||
uint8_t componentCount) {
|
||||
Format internalFormat;
|
||||
internalFormat.format = format;
|
||||
|
@ -338,10 +339,8 @@ namespace dawn::native {
|
|||
const FormatIndex firstFormatIndex = ComputeFormatIndex(firstFormat);
|
||||
const FormatIndex secondFormatIndex = ComputeFormatIndex(secondFormat);
|
||||
|
||||
ASSERT(table[firstFormatIndex].aspectInfo[0].format !=
|
||||
wgpu::TextureFormat::Undefined);
|
||||
ASSERT(table[secondFormatIndex].aspectInfo[0].format !=
|
||||
wgpu::TextureFormat::Undefined);
|
||||
ASSERT(table[firstFormatIndex].aspectInfo[0].format != wgpu::TextureFormat::Undefined);
|
||||
ASSERT(table[secondFormatIndex].aspectInfo[0].format != wgpu::TextureFormat::Undefined);
|
||||
|
||||
internalFormat.aspectInfo[0] = table[firstFormatIndex].aspectInfo[0];
|
||||
internalFormat.aspectInfo[1] = table[secondFormatIndex].aspectInfo[0];
|
||||
|
|
|
@ -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 sliceCount) const {
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
|
||||
rtvDesc.Format = GetD3D12Format();
|
||||
rtvDesc.Format = D3D12TextureFormat(format.format);
|
||||
if (IsMultisampledTexture()) {
|
||||
ASSERT(GetDimension() == wgpu::TextureDimension::e2D);
|
||||
ASSERT(GetNumMipLevels() == 1);
|
||||
|
@ -1070,7 +1071,7 @@ namespace dawn::native::d3d12 {
|
|||
sliceCount = std::max(GetDepth() >> level, 1u);
|
||||
}
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc =
|
||||
GetRTVDescriptor(level, baseSlice, sliceCount);
|
||||
GetRTVDescriptor(GetFormat(), level, baseSlice, sliceCount);
|
||||
device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(), &rtvDesc,
|
||||
rtvHandle);
|
||||
commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr);
|
||||
|
@ -1340,7 +1341,8 @@ namespace dawn::native::d3d12 {
|
|||
|
||||
D3D12_RENDER_TARGET_VIEW_DESC TextureView::GetRTVDescriptor() const {
|
||||
return ToBackend(GetTexture())
|
||||
->GetRTVDescriptor(GetBaseMipLevel(), GetBaseArrayLayer(), GetLayerCount());
|
||||
->GetRTVDescriptor(GetFormat(), GetBaseMipLevel(), GetBaseArrayLayer(),
|
||||
GetLayerCount());
|
||||
}
|
||||
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor(bool depthReadOnly,
|
||||
|
|
|
@ -55,7 +55,8 @@ namespace dawn::native::d3d12 {
|
|||
ID3D12Resource* GetD3D12Resource() 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 sliceCount) const;
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor(uint32_t mipLevel,
|
||||
|
|
|
@ -87,19 +87,18 @@ namespace dawn::native::metal {
|
|||
break;
|
||||
}
|
||||
|
||||
descriptor.colorAttachments[i].texture =
|
||||
ToBackend(attachmentInfo.view->GetTexture())->GetMTLTexture();
|
||||
descriptor.colorAttachments[i].level = attachmentInfo.view->GetBaseMipLevel();
|
||||
descriptor.colorAttachments[i].slice = attachmentInfo.view->GetBaseArrayLayer();
|
||||
auto colorAttachment = ToBackend(attachmentInfo.view)->GetAttachmentInfo();
|
||||
descriptor.colorAttachments[i].texture = colorAttachment.texture.Get();
|
||||
descriptor.colorAttachments[i].level = colorAttachment.baseMipLevel;
|
||||
descriptor.colorAttachments[i].slice = colorAttachment.baseArrayLayer;
|
||||
|
||||
bool hasResolveTarget = attachmentInfo.resolveTarget != nullptr;
|
||||
if (hasResolveTarget) {
|
||||
descriptor.colorAttachments[i].resolveTexture =
|
||||
ToBackend(attachmentInfo.resolveTarget->GetTexture())->GetMTLTexture();
|
||||
descriptor.colorAttachments[i].resolveLevel =
|
||||
attachmentInfo.resolveTarget->GetBaseMipLevel();
|
||||
descriptor.colorAttachments[i].resolveSlice =
|
||||
attachmentInfo.resolveTarget->GetBaseArrayLayer();
|
||||
auto resolveAttachment =
|
||||
ToBackend(attachmentInfo.resolveTarget)->GetAttachmentInfo();
|
||||
descriptor.colorAttachments[i].resolveTexture = resolveAttachment.texture.Get();
|
||||
descriptor.colorAttachments[i].resolveLevel = resolveAttachment.baseMipLevel;
|
||||
descriptor.colorAttachments[i].resolveSlice = resolveAttachment.baseArrayLayer;
|
||||
|
||||
switch (attachmentInfo.storeOp) {
|
||||
case wgpu::StoreOp::Store:
|
||||
|
@ -132,14 +131,13 @@ namespace dawn::native::metal {
|
|||
if (renderPass->attachmentState->HasDepthStencilAttachment()) {
|
||||
auto& attachmentInfo = renderPass->depthStencilAttachment;
|
||||
|
||||
id<MTLTexture> texture =
|
||||
ToBackend(attachmentInfo.view->GetTexture())->GetMTLTexture();
|
||||
const Format& format = attachmentInfo.view->GetTexture()->GetFormat();
|
||||
auto depthStencilAttachment = ToBackend(attachmentInfo.view)->GetAttachmentInfo();
|
||||
const Format& format = attachmentInfo.view->GetFormat();
|
||||
|
||||
if (format.HasDepth()) {
|
||||
descriptor.depthAttachment.texture = texture;
|
||||
descriptor.depthAttachment.level = attachmentInfo.view->GetBaseMipLevel();
|
||||
descriptor.depthAttachment.slice = attachmentInfo.view->GetBaseArrayLayer();
|
||||
descriptor.depthAttachment.texture = depthStencilAttachment.texture.Get();
|
||||
descriptor.depthAttachment.level = depthStencilAttachment.baseMipLevel;
|
||||
descriptor.depthAttachment.slice = depthStencilAttachment.baseArrayLayer;
|
||||
|
||||
switch (attachmentInfo.depthStoreOp) {
|
||||
case wgpu::StoreOp::Store:
|
||||
|
@ -172,9 +170,9 @@ namespace dawn::native::metal {
|
|||
}
|
||||
|
||||
if (format.HasStencil()) {
|
||||
descriptor.stencilAttachment.texture = texture;
|
||||
descriptor.stencilAttachment.level = attachmentInfo.view->GetBaseMipLevel();
|
||||
descriptor.stencilAttachment.slice = attachmentInfo.view->GetBaseArrayLayer();
|
||||
descriptor.stencilAttachment.texture = depthStencilAttachment.texture.Get();
|
||||
descriptor.stencilAttachment.level = depthStencilAttachment.baseMipLevel;
|
||||
descriptor.stencilAttachment.slice = depthStencilAttachment.baseArrayLayer;
|
||||
|
||||
switch (attachmentInfo.stencilStoreOp) {
|
||||
case wgpu::StoreOp::Store:
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace dawn::native::metal {
|
|||
const TextureDescriptor* descriptor,
|
||||
NSPRef<id<MTLTexture>> wrapped);
|
||||
|
||||
id<MTLTexture> GetMTLTexture();
|
||||
id<MTLTexture> GetMTLTexture() const;
|
||||
IOSurfaceRef GetIOSurface();
|
||||
NSPRef<id<MTLTexture>> CreateFormatView(wgpu::TextureFormat format);
|
||||
|
||||
|
@ -83,12 +83,20 @@ namespace dawn::native::metal {
|
|||
static ResultOrError<Ref<TextureView>> Create(TextureBase* texture,
|
||||
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:
|
||||
using TextureViewBase::TextureViewBase;
|
||||
MaybeError Initialize(const TextureViewDescriptor* descriptor);
|
||||
|
||||
// TODO(crbug.com/dawn/1355): Clear this reference on texture destroy.
|
||||
NSPRef<id<MTLTexture>> mMtlTextureView;
|
||||
};
|
||||
|
||||
|
|
|
@ -28,11 +28,6 @@
|
|||
namespace dawn::native::metal {
|
||||
|
||||
namespace {
|
||||
bool UsageNeedsTextureView(wgpu::TextureUsage usage) {
|
||||
constexpr wgpu::TextureUsage kUsageNeedsTextureView =
|
||||
wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::TextureBinding;
|
||||
return usage & kUsageNeedsTextureView;
|
||||
}
|
||||
|
||||
MTLTextureUsage MetalTextureUsage(const Format& format,
|
||||
wgpu::TextureUsage usage,
|
||||
|
@ -46,8 +41,10 @@ namespace dawn::native::metal {
|
|||
if (usage & (wgpu::TextureUsage::TextureBinding)) {
|
||||
result |= MTLTextureUsageShaderRead;
|
||||
|
||||
// For sampling stencil aspect of combined depth/stencil. See TextureView
|
||||
// constructor.
|
||||
// For sampling stencil aspect of combined depth/stencil.
|
||||
// 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 (IsSubset(Aspect::Depth | Aspect::Stencil, format.aspects)) {
|
||||
result |= MTLTextureUsagePixelFormatView;
|
||||
|
@ -86,13 +83,28 @@ namespace dawn::native::metal {
|
|||
|
||||
bool RequiresCreatingNewTextureView(const TextureBase* texture,
|
||||
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 &&
|
||||
!texture->GetFormat().HasDepthOrStencil()) {
|
||||
// Color format reinterpretation required. Note: Depth/stencil formats don't support
|
||||
// reinterpretation.
|
||||
// Color format reinterpretation required.
|
||||
// Note: Depth/stencil formats don't support reinterpretation.
|
||||
// See also TextureView::GetAttachmentInfo when modifying this condition.
|
||||
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 ||
|
||||
(texture->GetArrayLayers() == 1 &&
|
||||
texture->GetDimension() == wgpu::TextureDimension::e2D &&
|
||||
|
@ -107,8 +119,11 @@ namespace dawn::native::metal {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (IsSubset(Aspect::Depth | Aspect::Stencil, texture->GetFormat().aspects) &&
|
||||
textureViewDescriptor->aspect == wgpu::TextureAspect::StencilOnly) {
|
||||
// If the texture is created with MTLTextureUsagePixelFormatView, we need
|
||||
// a new view to perform format reinterpretation.
|
||||
if ((MetalTextureUsage(texture->GetFormat(), texture->GetInternalUsage(),
|
||||
texture->GetSampleCount()) &
|
||||
MTLTextureUsagePixelFormatView) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -776,7 +791,7 @@ namespace dawn::native::metal {
|
|||
mIOSurface = nullptr;
|
||||
}
|
||||
|
||||
id<MTLTexture> Texture::GetMTLTexture() {
|
||||
id<MTLTexture> Texture::GetMTLTexture() const {
|
||||
return mMtlTexture.Get();
|
||||
}
|
||||
|
||||
|
@ -1026,9 +1041,7 @@ namespace dawn::native::metal {
|
|||
|
||||
id<MTLTexture> mtlTexture = texture->GetMTLTexture();
|
||||
|
||||
if (!UsageNeedsTextureView(texture->GetInternalUsage())) {
|
||||
mMtlTextureView = nullptr;
|
||||
} else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
|
||||
if (!RequiresCreatingNewTextureView(texture, descriptor)) {
|
||||
mMtlTextureView = mtlTexture;
|
||||
} else if (texture->GetFormat().IsMultiPlanar()) {
|
||||
NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
|
||||
|
@ -1112,8 +1125,30 @@ namespace dawn::native::metal {
|
|||
return {};
|
||||
}
|
||||
|
||||
id<MTLTexture> TextureView::GetMTLTexture() {
|
||||
id<MTLTexture> TextureView::GetMTLTexture() const {
|
||||
ASSERT(mMtlTextureView != nullptr);
|
||||
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
|
||||
|
|
|
@ -87,14 +87,16 @@ namespace dawn::native::opengl {
|
|||
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,
|
||||
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 &&
|
||||
!texture->GetFormat().HasDepthOrStencil()) {
|
||||
// Color format reinterpretation required. Note: Depth/stencil formats don't support
|
||||
|
@ -102,6 +104,12 @@ namespace dawn::native::opengl {
|
|||
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 ||
|
||||
(texture->GetArrayLayers() == 1 &&
|
||||
texture->GetDimension() == wgpu::TextureDimension::e2D &&
|
||||
|
@ -554,9 +562,7 @@ namespace dawn::native::opengl {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!UsageNeedsTextureView(texture->GetUsage())) {
|
||||
mHandle = 0;
|
||||
} else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
|
||||
if (!RequiresCreatingNewTextureView(texture, descriptor)) {
|
||||
mHandle = ToBackend(texture)->GetHandle();
|
||||
} else {
|
||||
// glTextureView() is supported on OpenGL version >= 4.3
|
||||
|
@ -601,13 +607,26 @@ namespace dawn::native::opengl {
|
|||
void TextureView::BindToFramebuffer(GLenum target, GLenum attachment) {
|
||||
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 = ToBackend(GetTexture())->GetHandle();
|
||||
GLuint textarget = ToBackend(GetTexture())->GetGLTarget();
|
||||
GLuint mipLevel = GetBaseMipLevel();
|
||||
GLuint handle, textarget, mipLevel, arrayLayer;
|
||||
if (mOwnsHandle) {
|
||||
// Use our own texture handle and target which points to a subset of the texture's
|
||||
// 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) {
|
||||
gl.FramebufferTextureLayer(target, attachment, handle, mipLevel, GetBaseArrayLayer());
|
||||
gl.FramebufferTextureLayer(target, attachment, handle, mipLevel, arrayLayer);
|
||||
} else {
|
||||
gl.FramebufferTexture2D(target, attachment, textarget, handle, mipLevel);
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ namespace dawn::native::opengl {
|
|||
~TextureView() override;
|
||||
void DestroyImpl() override;
|
||||
|
||||
// TODO(crbug.com/dawn/1355): Delete this handle on texture destroy.
|
||||
GLuint mHandle;
|
||||
GLenum mTarget;
|
||||
bool mOwnsHandle;
|
||||
|
|
|
@ -438,7 +438,7 @@ TEST_P(TextureViewSamplingTest, Texture2DArrayViewOnOneLevelOf2DArrayTexture) {
|
|||
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.
|
||||
TEST_P(TextureViewSamplingTest, SRGBReinterpretation) {
|
||||
// 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,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
|
@ -781,7 +1001,9 @@ DAWN_INSTANTIATE_TEST(TextureViewSamplingTest,
|
|||
|
||||
DAWN_INSTANTIATE_TEST(TextureViewRenderingTest,
|
||||
D3D12Backend(),
|
||||
D3D12Backend({}, {"use_d3d12_render_pass"}),
|
||||
MetalBackend(),
|
||||
MetalBackend({"emulate_store_and_msaa_resolve"}),
|
||||
OpenGLBackend(),
|
||||
OpenGLESBackend(),
|
||||
VulkanBackend());
|
||||
|
|
Loading…
Reference in New Issue