Implement the stencil8 format.

Rolled in changes made by cwallez@ as part of
https://dawn-review.googlesource.com/c/dawn/+/75983, which was
originally based on this change.

Bug: dawn:666

Change-Id: I5d6ad592294ee8302f3b18f7f31bbfd982297251
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/68280
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Brandon Jones <bajones@chromium.org>
This commit is contained in:
Corentin Wallez 2022-03-24 17:54:56 +00:00 committed by Dawn LUCI CQ
parent cbdde604b8
commit 0bf63577d2
24 changed files with 174 additions and 122 deletions

View File

@ -369,15 +369,19 @@ namespace dawn::native {
}
} else {
DAWN_TRY(ValidateLoadOp(depthStencilAttachment->stencilLoadOp));
DAWN_INVALID_IF(depthStencilAttachment->stencilLoadOp == wgpu::LoadOp::Undefined,
"stencilLoadOp must be set if the attachment (%s) has a stencil "
"aspect and stencilReadOnly (%u) is false.",
attachment, depthStencilAttachment->stencilReadOnly);
DAWN_INVALID_IF(
depthStencilAttachment->stencilLoadOp == wgpu::LoadOp::Undefined,
"stencilLoadOp (%s) must be set if the attachment (%s) has a stencil "
"aspect and stencilReadOnly (%u) is false.",
depthStencilAttachment->stencilLoadOp, attachment,
depthStencilAttachment->stencilReadOnly);
DAWN_TRY(ValidateStoreOp(depthStencilAttachment->stencilStoreOp));
DAWN_INVALID_IF(depthStencilAttachment->depthStoreOp == wgpu::StoreOp::Undefined,
"stencilStoreOp must be set if the attachment (%s) has a stencil "
"aspect and stencilReadOnly (%u) is false.",
attachment, depthStencilAttachment->stencilReadOnly);
DAWN_INVALID_IF(
depthStencilAttachment->stencilStoreOp == wgpu::StoreOp::Undefined,
"stencilStoreOp (%s) must be set if the attachment (%s) has a stencil "
"aspect and stencilReadOnly (%u) is false.",
depthStencilAttachment->stencilStoreOp, attachment,
depthStencilAttachment->stencilReadOnly);
}
if (!std::isnan(depthStencilAttachment->clearDepth)) {

View File

@ -264,13 +264,22 @@ namespace dawn::native {
internalFormat.baseFormat = baseFormat;
}
AspectInfo* firstAspect = internalFormat.aspectInfo.data();
firstAspect->block.byteSize = 1;
firstAspect->block.width = 1;
firstAspect->block.height = 1;
firstAspect->baseType = wgpu::TextureComponentType::Uint;
firstAspect->supportedSampleTypes = SampleTypeBit::Uint;
firstAspect->format = format;
// Duplicate the data for the stencil aspect in both the first and second aspect info.
// - aspectInfo[0] is used by AddMultiAspectFormat to copy the info for the whole
// stencil8 aspect of depth-stencil8 formats.
// - aspectInfo[1] is the actual info used in the rest of Dawn since
// GetAspectIndex(Aspect::Stencil) is 1.
ASSERT(GetAspectIndex(Aspect::Stencil) == 1);
internalFormat.aspectInfo[0].block.byteSize = 1;
internalFormat.aspectInfo[0].block.width = 1;
internalFormat.aspectInfo[0].block.height = 1;
internalFormat.aspectInfo[0].baseType = wgpu::TextureComponentType::Uint;
internalFormat.aspectInfo[0].supportedSampleTypes = SampleTypeBit::Uint;
internalFormat.aspectInfo[0].format = format;
internalFormat.aspectInfo[1] = internalFormat.aspectInfo[0];
AddFormat(internalFormat);
};
@ -330,9 +339,17 @@ namespace dawn::native {
internalFormat.baseFormat = baseFormat;
}
// Multi aspect formats just copy information about single-aspect formats. This
// means that the single-plane formats must have been added before multi-aspect
// ones. (it is ASSERTed below).
const size_t firstFormatIndex = ComputeFormatIndex(firstFormat);
const size_t secondFormatIndex = ComputeFormatIndex(secondFormat);
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];
@ -388,8 +405,7 @@ namespace dawn::native {
AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, false, false, 16, SampleTypeBit::UnfilterableFloat, 4);
// Depth-stencil formats
// TODO(dawn:666): Implement the stencil8 format
AddStencilFormat(wgpu::TextureFormat::Stencil8, false);
AddStencilFormat(wgpu::TextureFormat::Stencil8, true);
AddDepthFormat(wgpu::TextureFormat::Depth16Unorm, 2, true);
// TODO(crbug.com/dawn/843): This is 4 because we read this to perform zero initialization,
// and textures are always use depth32float. We should improve this to be more robust. Perhaps,

View File

@ -72,7 +72,7 @@ namespace dawn::native {
// an internal Dawn enum.
wgpu::TextureComponentType baseType;
SampleTypeBit supportedSampleTypes;
wgpu::TextureFormat format;
wgpu::TextureFormat format = wgpu::TextureFormat::Undefined;
};
// The number of formats Dawn knows about. Asserts in BuildFormatTable ensure that this is the

View File

@ -87,6 +87,10 @@ namespace dawn::native {
return 1;
} else if (aspects == (Aspect::Plane0 | Aspect::Plane1)) {
return 2;
} else if (aspects == Aspect::Stencil) {
// Fake a the existence of a depth aspect so that the stencil data stays at index 1.
ASSERT(GetAspectIndex(Aspect::Stencil) == 1);
return 2;
} else {
ASSERT(aspects == (Aspect::Depth | Aspect::Stencil));
return 2;

View File

@ -99,6 +99,12 @@ namespace dawn::native {
"backend will use D32S8 (toggle to on) but setting the toggle to off will make it "
"use the D24S8 format when possible.",
"https://crbug.com/dawn/286"}},
{Toggle::VulkanUseS8,
{"vulkan_use_s8",
"Vulkan has a pure stencil8 format but it is not universally available. When this "
"toggle is on, the backend will use S8 for the stencil8 format, otherwise it will "
"fallback to D32S8 or D24S8.",
"https://crbug.com/dawn/666"}},
{Toggle::MetalDisableSamplerCompare,
{"metal_disable_sampler_compare",
"Disables the use of sampler compare on Metal. This is unsupported before A9 "

View File

@ -35,6 +35,7 @@ namespace dawn::native {
UseD3D12ResidencyManagement,
SkipValidation,
VulkanUseD32S8,
VulkanUseS8,
MetalDisableSamplerCompare,
MetalUseSharedModeForCounterSampleBuffer,
DisableBaseVertex,

View File

@ -1327,7 +1327,7 @@ namespace dawn::native::d3d12 {
}
}
if (renderPassBuilder->HasDepth()) {
if (renderPassBuilder->HasDepthOrStencil()) {
D3D12_CLEAR_FLAGS clearFlags = {};
float depthClear = 0.0f;
uint8_t stencilClear = 0u;
@ -1359,7 +1359,7 @@ namespace dawn::native::d3d12 {
commandList->OMSetRenderTargets(
static_cast<uint8_t>(renderPassBuilder->GetHighestColorAttachmentIndexPlusOne()),
renderPassBuilder->GetRenderTargetViews(), FALSE,
renderPassBuilder->HasDepth()
renderPassBuilder->HasDepthOrStencil()
? &renderPassBuilder->GetRenderPassDepthStencilDescriptor()->cpuDescriptor
: nullptr);
}
@ -1384,7 +1384,7 @@ namespace dawn::native::d3d12 {
commandContext->GetCommandList4()->BeginRenderPass(
static_cast<uint8_t>(renderPassBuilder.GetHighestColorAttachmentIndexPlusOne()),
renderPassBuilder.GetRenderPassRenderTargetDescriptors().data(),
renderPassBuilder.HasDepth()
renderPassBuilder.HasDepthOrStencil()
? renderPassBuilder.GetRenderPassDepthStencilDescriptor()
: nullptr,
renderPassBuilder.GetRenderPassFlags());

View File

@ -136,8 +136,8 @@ namespace dawn::native::d3d12 {
return mHighestColorAttachmentIndexPlusOne;
}
bool RenderPassBuilder::HasDepth() const {
return mHasDepth;
bool RenderPassBuilder::HasDepthOrStencil() const {
return mHasDepthOrStencil;
}
ityp::span<ColorAttachmentIndex, const D3D12_RENDER_PASS_RENDER_TARGET_DESC>
@ -204,7 +204,7 @@ namespace dawn::native::d3d12 {
wgpu::StoreOp storeOp,
float clearDepth,
DXGI_FORMAT format) {
mHasDepth = true;
mHasDepthOrStencil = true;
mRenderPassDepthStencilDesc.DepthBeginningAccess.Type = D3D12BeginningAccessType(loadOp);
if (loadOp == wgpu::LoadOp::Clear) {
mRenderPassDepthStencilDesc.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth =
@ -218,6 +218,7 @@ namespace dawn::native::d3d12 {
wgpu::StoreOp storeOp,
uint8_t clearStencil,
DXGI_FORMAT format) {
mHasDepthOrStencil = true;
mRenderPassDepthStencilDesc.StencilBeginningAccess.Type = D3D12BeginningAccessType(loadOp);
if (loadOp == wgpu::LoadOp::Clear) {
mRenderPassDepthStencilDesc.StencilBeginningAccess.Clear.ClearValue.DepthStencil

View File

@ -52,7 +52,7 @@ namespace dawn::native::d3d12 {
// Returns attachment RTVs to use with OMSetRenderTargets.
const D3D12_CPU_DESCRIPTOR_HANDLE* GetRenderTargetViews() const;
bool HasDepth() const;
bool HasDepthOrStencil() const;
// Functions that set the appropriate values in the render pass descriptors.
void SetDepthAccess(wgpu::LoadOp loadOp,
@ -83,7 +83,7 @@ namespace dawn::native::d3d12 {
private:
ColorAttachmentIndex mHighestColorAttachmentIndexPlusOne{uint8_t(0)};
bool mHasDepth = false;
bool mHasDepthOrStencil = false;
D3D12_RENDER_PASS_FLAGS mRenderPassFlags = D3D12_RENDER_PASS_FLAG_NONE;
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC mRenderPassDepthStencilDesc;
ityp::

View File

@ -279,7 +279,11 @@ namespace dawn::native::d3d12 {
D3D12_DEPTH_STENCIL_DESC ComputeDepthStencilDesc(const DepthStencilState* descriptor) {
D3D12_DEPTH_STENCIL_DESC mDepthStencilDescriptor;
mDepthStencilDescriptor.DepthEnable = TRUE;
mDepthStencilDescriptor.DepthEnable =
(descriptor->depthCompare == wgpu::CompareFunction::Always &&
!descriptor->depthWriteEnabled)
? FALSE
: TRUE;
mDepthStencilDescriptor.DepthWriteMask = descriptor->depthWriteEnabled
? D3D12_DEPTH_WRITE_MASK_ALL
: D3D12_DEPTH_WRITE_MASK_ZERO;

View File

@ -299,7 +299,8 @@ namespace dawn::native::d3d12 {
// incorrectly allocate a mismatched size.
if (resourceInfo.SizeInBytes == 0 ||
resourceInfo.SizeInBytes == std::numeric_limits<uint64_t>::max()) {
return DAWN_OUT_OF_MEMORY_ERROR("Resource allocation size was invalid.");
return DAWN_OUT_OF_MEMORY_ERROR(absl::StrFormat(
"Resource allocation size (%u) was invalid.", resourceInfo.SizeInBytes));
}
BuddyMemoryAllocator* allocator =

View File

@ -178,6 +178,8 @@ namespace dawn::native::d3d12 {
case wgpu::TextureFormat::Depth24Plus:
return DXGI_FORMAT_R32_TYPELESS;
// Depth24UnormStencil8 is the smallest format supported on D3D12 that has stencil.
case wgpu::TextureFormat::Stencil8:
case wgpu::TextureFormat::Depth24UnormStencil8:
return DXGI_FORMAT_R24G8_TYPELESS;
case wgpu::TextureFormat::Depth24PlusStencil8:
@ -253,8 +255,6 @@ namespace dawn::native::d3d12 {
case wgpu::TextureFormat::ASTC12x12UnormSrgb:
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
// TODO(dawn:666): implement stencil8
case wgpu::TextureFormat::Stencil8:
case wgpu::TextureFormat::Undefined:
UNREACHABLE();
}
@ -346,6 +346,8 @@ namespace dawn::native::d3d12 {
case wgpu::TextureFormat::Depth32Float:
case wgpu::TextureFormat::Depth24Plus:
return DXGI_FORMAT_D32_FLOAT;
// Depth24UnormStencil8 is the smallest format supported on D3D12 that has stencil.
case wgpu::TextureFormat::Stencil8:
case wgpu::TextureFormat::Depth24UnormStencil8:
return DXGI_FORMAT_D24_UNORM_S8_UINT;
case wgpu::TextureFormat::Depth24PlusStencil8:
@ -424,8 +426,6 @@ namespace dawn::native::d3d12 {
case wgpu::TextureFormat::ASTC12x12Unorm:
case wgpu::TextureFormat::ASTC12x12UnormSrgb:
// TODO(dawn:666): implement stencil8
case wgpu::TextureFormat::Stencil8:
case wgpu::TextureFormat::Undefined:
UNREACHABLE();
}
@ -684,6 +684,7 @@ namespace dawn::native::d3d12 {
case wgpu::TextureFormat::Depth24UnormStencil8:
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
case wgpu::TextureFormat::Stencil8:
switch (aspect) {
case Aspect::Depth:
return DXGI_FORMAT_R32_FLOAT;
@ -1179,6 +1180,7 @@ namespace dawn::native::d3d12 {
case wgpu::TextureFormat::Depth16Unorm:
mSrvDesc.Format = DXGI_FORMAT_R16_UNORM;
break;
case wgpu::TextureFormat::Stencil8:
case wgpu::TextureFormat::Depth24UnormStencil8:
switch (descriptor->aspect) {
case wgpu::TextureAspect::DepthOnly:

View File

@ -43,7 +43,7 @@ namespace dawn::native::metal {
newComputePipelineStateWithFunction:computeData.function.Get()
error:&error]);
if (error != nullptr) {
return DAWN_INTERNAL_ERROR("Error creating pipeline state" +
return DAWN_INTERNAL_ERROR("Error creating pipeline state " +
std::string([error.localizedDescription UTF8String]));
}
ASSERT(mMtlComputePipelineState != nil);

View File

@ -391,7 +391,7 @@ namespace dawn::native::metal {
AcquireNSPRef([mtlDevice newRenderPipelineStateWithDescriptor:descriptorMTL
error:&error]);
if (error != nullptr) {
return DAWN_INTERNAL_ERROR(std::string("Error creating pipeline state") +
return DAWN_INTERNAL_ERROR(std::string("Error creating pipeline state ") +
[error.localizedDescription UTF8String]);
}
ASSERT(mMtlRenderPipelineState != nil);

View File

@ -289,6 +289,8 @@ namespace dawn::native::metal {
// TODO (dawn:1181): Allow non-conformant implementation on macOS 10.11
UNREACHABLE();
}
case wgpu::TextureFormat::Stencil8:
return MTLPixelFormatStencil8;
#if defined(DAWN_PLATFORM_MACOS)
case wgpu::TextureFormat::Depth24UnormStencil8:
@ -383,8 +385,6 @@ namespace dawn::native::metal {
case wgpu::TextureFormat::ASTC12x12Unorm:
case wgpu::TextureFormat::ASTC12x12UnormSrgb:
// TODO(dawn:666): implement stencil8
case wgpu::TextureFormat::Stencil8:
case wgpu::TextureFormat::Undefined:
UNREACHABLE();
}

View File

@ -95,6 +95,7 @@ namespace dawn::native::opengl {
AddFormat(wgpu::TextureFormat::Depth24Plus, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, Type::DepthStencil);
AddFormat(wgpu::TextureFormat::Depth24PlusStencil8, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, Type::DepthStencil);
AddFormat(wgpu::TextureFormat::Depth16Unorm, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, Type::DepthStencil);
AddFormat(wgpu::TextureFormat::Stencil8, GL_STENCIL_INDEX8, GL_STENCIL, GL_UNSIGNED_BYTE, Type::DepthStencil);
// Block compressed formats
AddFormat(wgpu::TextureFormat::BC1RGBAUnorm, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, Type::Float);

View File

@ -46,6 +46,9 @@ namespace dawn::native::opengl {
GLint GetStencilMaskFromStencilFormat(wgpu::TextureFormat depthStencilFormat) {
switch (depthStencilFormat) {
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth24UnormStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
case wgpu::TextureFormat::Stencil8:
return 0xFF;
default:

View File

@ -44,7 +44,7 @@ namespace dawn::native::vulkan {
bool Adapter::IsDepthStencilFormatSupported(VkFormat format) {
ASSERT(format == VK_FORMAT_D16_UNORM_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT ||
format == VK_FORMAT_D32_SFLOAT_S8_UINT);
format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_S8_UINT);
VkFormatProperties properties;
mVulkanInstance->GetFunctions().GetPhysicalDeviceFormatProperties(mPhysicalDevice, format,

View File

@ -93,9 +93,9 @@ namespace dawn::native::vulkan {
DAWN_TRY(PrepareRecordingContext());
// The environment can request to use D32S8 or D24S8 when it's not available. Override
// the decision if it is not applicable.
ApplyDepth24PlusS8Toggle();
// The environment can request to various options for depth-stencil formats that could be
// unavailable. Override the decision if it is not applicable.
ApplyDepthStencilFormatToggles();
// The environment can only request to use VK_KHR_zero_initialize_workgroup_memory when the
// extension is available. Override the decision if it is no applicable.
@ -518,13 +518,17 @@ namespace dawn::native::vulkan {
// By default try to initialize workgroup memory with OpConstantNull according to the Vulkan
// extension VK_KHR_zero_initialize_workgroup_memory.
SetToggle(Toggle::VulkanUseZeroInitializeWorkgroupMemoryExtension, true);
// By default try to use S8 if available.
SetToggle(Toggle::VulkanUseS8, true);
}
void Device::ApplyDepth24PlusS8Toggle() {
void Device::ApplyDepthStencilFormatToggles() {
bool supportsD32s8 =
ToBackend(GetAdapter())->IsDepthStencilFormatSupported(VK_FORMAT_D32_SFLOAT_S8_UINT);
bool supportsD24s8 =
ToBackend(GetAdapter())->IsDepthStencilFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT);
bool supportsS8 = ToBackend(GetAdapter())->IsDepthStencilFormatSupported(VK_FORMAT_S8_UINT);
ASSERT(supportsD32s8 || supportsD24s8);
@ -534,6 +538,9 @@ namespace dawn::native::vulkan {
if (!supportsD32s8) {
ForceSetToggle(Toggle::VulkanUseD32S8, false);
}
if (!supportsS8) {
ForceSetToggle(Toggle::VulkanUseS8, false);
}
}
void Device::ApplyUseZeroInitializeWorkgroupMemoryExtensionToggle() {

View File

@ -151,7 +151,7 @@ namespace dawn::native::vulkan {
uint32_t FindComputeSubgroupSize() const;
void InitTogglesFromDriver();
void ApplyDepth24PlusS8Toggle();
void ApplyDepthStencilFormatToggles();
void ApplyUseZeroInitializeWorkgroupMemoryExtensionToggle();
void DestroyImpl() override;

View File

@ -318,6 +318,14 @@ namespace dawn::native::vulkan {
return VK_FORMAT_D24_UNORM_S8_UINT;
case wgpu::TextureFormat::Depth32FloatStencil8:
return VK_FORMAT_D32_SFLOAT_S8_UINT;
case wgpu::TextureFormat::Stencil8:
// Try to use the stencil8 format if possible, otherwise use whatever format we can
// use that contains a stencil8 component.
if (device->IsToggleEnabled(Toggle::VulkanUseS8)) {
return VK_FORMAT_S8_UINT;
} else {
return VulkanImageFormat(device, wgpu::TextureFormat::Depth24PlusStencil8);
}
case wgpu::TextureFormat::BC1RGBAUnorm:
return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
@ -429,8 +437,6 @@ namespace dawn::native::vulkan {
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
// TODO(dawn:666): implement stencil8
case wgpu::TextureFormat::Stencil8:
case wgpu::TextureFormat::Undefined:
break;
}
@ -982,6 +988,12 @@ namespace dawn::native::vulkan {
// single plane in a new SubresourceStorage<TextureUsage>. The barriers will be produced
// for DEPTH | STENCIL since the SubresourceRange uses Aspect::CombinedDepthStencil.
bool Texture::ShouldCombineDepthStencilBarriers() const {
// If the Stencil8 format is being emulated then memory barriers also need to include
// the depth aspect. (See: crbug.com/dawn/1331)
if (GetFormat().format == wgpu::TextureFormat::Stencil8 &&
!GetDevice()->IsToggleEnabled(Toggle::VulkanUseS8)) {
return true;
}
return GetFormat().aspects == (Aspect::Depth | Aspect::Stencil);
}

View File

@ -126,53 +126,6 @@ class DepthStencilCopyTests : public DawnTestWithParams<DepthStencilCopyTestPara
return device.CreateTexture(&texDescriptor);
}
void PopulatePipelineDescriptorWriteDepth(utils::ComboRenderPipelineDescriptor* desc,
wgpu::TextureFormat format,
float regionDepth) {
desc->vertex.module = mVertexModule;
std::string fsSource = R"(
@stage(fragment) fn main() -> @builtin(frag_depth) f32 {
return )" + std::to_string(regionDepth) +
";\n}";
desc->cFragment.module = utils::CreateShaderModule(device, fsSource.c_str());
wgpu::DepthStencilState* depthStencil = desc->EnableDepthStencil(format);
depthStencil->depthWriteEnabled = true;
desc->cFragment.targetCount = 0;
}
// Initialize the depth/stencil values for the texture using a render pass.
// The texture will be cleared to the "clear" value, and then bottom left corner will
// be written with the "region" value.
void InitializeDepthTextureRegion(wgpu::Texture texture,
wgpu::TextureFormat depthFormat,
float clearDepth,
float regionDepth,
uint32_t mipLevel = 0) {
wgpu::TextureViewDescriptor viewDesc = {};
viewDesc.baseMipLevel = mipLevel;
viewDesc.mipLevelCount = 1;
utils::ComboRenderPassDescriptor renderPassDesc({}, texture.CreateView(&viewDesc));
renderPassDesc.UnsetDepthStencilLoadStoreOpsForFormat(depthFormat);
renderPassDesc.cDepthStencilAttachmentInfo.depthClearValue = clearDepth;
utils::ComboRenderPipelineDescriptor renderPipelineDesc;
PopulatePipelineDescriptorWriteDepth(&renderPipelineDesc, GetParam().mTextureFormat,
regionDepth);
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPassDesc);
pass.SetPipeline(pipeline);
pass.Draw(6);
pass.End();
wgpu::CommandBuffer commands = commandEncoder.Finish();
queue.Submit(1, &commands);
}
// Initialize the depth/stencil values for the texture using a render pass.
// The texture will be cleared to the "clear" values, and then bottom left corner will
// be written with the "region" values.
@ -182,21 +135,43 @@ class DepthStencilCopyTests : public DawnTestWithParams<DepthStencilCopyTestPara
uint8_t clearStencil,
uint8_t regionStencil,
uint32_t mipLevel = 0) {
wgpu::TextureFormat format = GetParam().mTextureFormat;
// Create the render pass used for the initialization.
utils::ComboRenderPipelineDescriptor renderPipelineDesc;
renderPipelineDesc.vertex.module = mVertexModule;
renderPipelineDesc.cFragment.targetCount = 0;
wgpu::DepthStencilState* depthStencil = renderPipelineDesc.EnableDepthStencil(format);
if (utils::IsStencilOnlyFormat(format)) {
depthStencil->depthCompare = wgpu::CompareFunction::Always;
renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
@stage(fragment) fn main() {}
)");
} else {
depthStencil->depthWriteEnabled = true;
renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, std::string(R"(
@stage(fragment) fn main() -> @builtin(frag_depth) f32 {
return )" + std::to_string(regionDepth) + R"(;
})")
.c_str());
}
if (!utils::IsDepthOnlyFormat(format)) {
depthStencil->stencilFront.passOp = wgpu::StencilOperation::Replace;
}
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
// Build the render pass used for initialization.
wgpu::TextureViewDescriptor viewDesc = {};
viewDesc.baseMipLevel = mipLevel;
viewDesc.mipLevelCount = 1;
utils::ComboRenderPassDescriptor renderPassDesc({}, texture.CreateView(&viewDesc));
renderPassDesc.UnsetDepthStencilLoadStoreOpsForFormat(format);
renderPassDesc.cDepthStencilAttachmentInfo.depthClearValue = clearDepth;
renderPassDesc.cDepthStencilAttachmentInfo.stencilClearValue = clearStencil;
utils::ComboRenderPipelineDescriptor renderPipelineDesc;
PopulatePipelineDescriptorWriteDepth(&renderPipelineDesc, GetParam().mTextureFormat,
regionDepth);
renderPipelineDesc.cDepthStencil.stencilFront.passOp = wgpu::StencilOperation::Replace;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
// Draw the quad (two triangles)
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPassDesc);
@ -471,7 +446,7 @@ TEST_P(DepthCopyTests, FromDepthAspect) {
kWidth, kHeight, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
constexpr float kInitDepth = 0.2f;
InitializeDepthTextureRegion(texture, GetParam().mTextureFormat, 0.f, kInitDepth);
InitializeDepthStencilTextureRegion(texture, 0.f, kInitDepth, 0, 0);
// This expectation is the test as it performs the CopyTextureToBuffer.
if (GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm) {
@ -511,7 +486,7 @@ TEST_P(DepthCopyTests, FromNonZeroMipDepthAspect) {
9, 9, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, 2);
constexpr float kInitDepth = 0.4f;
InitializeDepthTextureRegion(depthTexture, GetParam().mTextureFormat, 0.f, kInitDepth, 1);
InitializeDepthStencilTextureRegion(depthTexture, 0.f, kInitDepth, 0, 0, /*mipLevel*/ 1);
// This expectation is the test as it performs the CopyTextureToBuffer.
if (GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm) {
@ -670,17 +645,19 @@ TEST_P(StencilCopyTests, ToStencilAspect) {
// Create a stencil texture
constexpr uint32_t kWidth = 4;
constexpr uint32_t kHeight = 4;
const bool hasDepth = !utils::IsStencilOnlyFormat(GetParam().mTextureFormat);
wgpu::Texture depthStencilTexture =
CreateDepthStencilTexture(kWidth, kHeight,
wgpu::TextureUsage::RenderAttachment |
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst);
{
if (hasDepth) {
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
// Clear depth to 0.7, so we can check that the stencil copy doesn't mutate the depth.
utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
passDescriptor.UnsetDepthStencilLoadStoreOpsForFormat(GetParam().mTextureFormat);
passDescriptor.cDepthStencilAttachmentInfo.depthClearValue = 0.7;
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
@ -727,10 +704,14 @@ TEST_P(StencilCopyTests, ToStencilAspect) {
renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
@stage(fragment) fn main() {
})");
renderPipelineDesc.cFragment.targetCount = 0;
wgpu::DepthStencilState* depthStencil =
renderPipelineDesc.EnableDepthStencil(GetParam().mTextureFormat);
depthStencil->stencilFront.passOp = wgpu::StencilOperation::DecrementClamp;
renderPipelineDesc.cFragment.targetCount = 0;
if (!hasDepth) {
depthStencil->depthWriteEnabled = false;
depthStencil->depthCompare = wgpu::CompareFunction::Always;
}
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
@ -739,6 +720,7 @@ TEST_P(StencilCopyTests, ToStencilAspect) {
utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
passDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
passDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
passDescriptor.UnsetDepthStencilLoadStoreOpsForFormat(GetParam().mTextureFormat);
// Draw the quad in the bottom left (two triangles).
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
@ -754,19 +736,23 @@ TEST_P(StencilCopyTests, ToStencilAspect) {
EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0}, {kWidth, kHeight}, 0,
wgpu::TextureAspect::StencilOnly);
ExpectAttachmentDepthTestData(depthStencilTexture, GetParam().mTextureFormat, kWidth, kHeight,
0, 0,
{
0.7, 0.7, 0.7, 0.7, //
0.7, 0.7, 0.7, 0.7, //
0.7, 0.7, 0.7, 0.7, //
0.7, 0.7, 0.7, 0.7, //
});
if (hasDepth) {
ExpectAttachmentDepthTestData(depthStencilTexture, GetParam().mTextureFormat, kWidth,
kHeight, 0, 0,
{
0.7, 0.7, 0.7, 0.7, //
0.7, 0.7, 0.7, 0.7, //
0.7, 0.7, 0.7, 0.7, //
0.7, 0.7, 0.7, 0.7, //
});
}
}
DAWN_INSTANTIATE_TEST_P(DepthStencilCopyTests,
{D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(),
VulkanBackend()},
// Test with the vulkan_use_s8 toggle forced on and off.
VulkanBackend({"vulkan_use_s8"}, {}),
VulkanBackend({}, {"vulkan_use_s8"})},
std::vector<wgpu::TextureFormat>(utils::kDepthAndStencilFormats.begin(),
utils::kDepthAndStencilFormats.end()));
@ -784,6 +770,8 @@ DAWN_INSTANTIATE_TEST_P(DepthCopyFromBufferTests,
DAWN_INSTANTIATE_TEST_P(StencilCopyTests,
{D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(),
VulkanBackend()},
// Test with the vulkan_use_s8 toggle forced on and off.
VulkanBackend({"vulkan_use_s8"}, {}),
VulkanBackend({}, {"vulkan_use_s8"})},
std::vector<wgpu::TextureFormat>(utils::kStencilFormats.begin(),
utils::kStencilFormats.end()));

View File

@ -215,12 +215,17 @@ namespace utils {
}
}
bool IsStencilOnlyFormat(wgpu::TextureFormat textureFormat) {
return textureFormat == wgpu::TextureFormat::Stencil8;
}
uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat) {
switch (textureFormat) {
case wgpu::TextureFormat::R8Unorm:
case wgpu::TextureFormat::R8Snorm:
case wgpu::TextureFormat::R8Uint:
case wgpu::TextureFormat::R8Sint:
case wgpu::TextureFormat::Stencil8:
return 1u;
case wgpu::TextureFormat::R16Uint:
@ -339,8 +344,6 @@ namespace utils {
// Block size of a multi-planar format depends on aspect.
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
// TODO(dawn:666): implement stencil8
case wgpu::TextureFormat::Stencil8:
case wgpu::TextureFormat::Undefined:
break;
}
@ -391,6 +394,7 @@ namespace utils {
case wgpu::TextureFormat::Depth16Unorm:
case wgpu::TextureFormat::Depth24UnormStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
case wgpu::TextureFormat::Stencil8:
return 1u;
case wgpu::TextureFormat::BC1RGBAUnorm:
@ -457,8 +461,6 @@ namespace utils {
// Block size of a multi-planar format depends on aspect.
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
// TODO(dawn:666): implement stencil8
case wgpu::TextureFormat::Stencil8:
case wgpu::TextureFormat::Undefined:
break;
}
@ -509,6 +511,7 @@ namespace utils {
case wgpu::TextureFormat::Depth16Unorm:
case wgpu::TextureFormat::Depth24UnormStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
case wgpu::TextureFormat::Stencil8:
return 1u;
case wgpu::TextureFormat::BC1RGBAUnorm:
@ -575,8 +578,6 @@ namespace utils {
// Block size of a multi-planar format depends on aspect.
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
// TODO(dawn:666): implement stencil8
case wgpu::TextureFormat::Stencil8:
case wgpu::TextureFormat::Undefined:
break;
}

View File

@ -22,8 +22,7 @@
#include "dawn/common/Assert.h"
namespace utils {
// TODO(dawn:666): Add Stencil8 format when it's implemented.
static constexpr std::array<wgpu::TextureFormat, 94> kAllTextureFormats = {
static constexpr std::array<wgpu::TextureFormat, 95> kAllTextureFormats = {
wgpu::TextureFormat::R8Unorm,
wgpu::TextureFormat::R8Snorm,
wgpu::TextureFormat::R8Uint,
@ -66,6 +65,7 @@ namespace utils {
wgpu::TextureFormat::Depth24PlusStencil8,
wgpu::TextureFormat::Depth24UnormStencil8,
wgpu::TextureFormat::Depth32FloatStencil8,
wgpu::TextureFormat::Stencil8,
wgpu::TextureFormat::BC1RGBAUnorm,
wgpu::TextureFormat::BC1RGBAUnormSrgb,
wgpu::TextureFormat::BC2RGBAUnorm,
@ -206,16 +206,16 @@ namespace utils {
kBCFormats.size() + kETC2Formats.size() + kASTCFormats.size(),
"Number of compressed format must equal number of BC, ETC2, and ASTC formats.");
// TODO(dawn:666): Add Stencil8 format when it's implemented.
static constexpr std::array<wgpu::TextureFormat, 6> kDepthFormats = {
wgpu::TextureFormat::Depth16Unorm, wgpu::TextureFormat::Depth32Float,
wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Depth24PlusStencil8,
wgpu::TextureFormat::Depth24UnormStencil8, wgpu::TextureFormat::Depth32FloatStencil8,
};
static constexpr std::array<wgpu::TextureFormat, 3> kStencilFormats = {
static constexpr std::array<wgpu::TextureFormat, 4> kStencilFormats = {
wgpu::TextureFormat::Depth24PlusStencil8,
wgpu::TextureFormat::Depth24UnormStencil8,
wgpu::TextureFormat::Depth32FloatStencil8,
wgpu::TextureFormat::Stencil8,
};
static constexpr std::array<wgpu::TextureFormat, 3> kDepthAndStencilFormats = {
wgpu::TextureFormat::Depth24PlusStencil8,
@ -230,6 +230,7 @@ namespace utils {
bool IsASTCTextureFormat(wgpu::TextureFormat textureFormat);
bool IsDepthOnlyFormat(wgpu::TextureFormat textureFormat);
bool IsStencilOnlyFormat(wgpu::TextureFormat textureFormat);
bool TextureFormatSupportsMultisampling(wgpu::TextureFormat textureFormat);
bool TextureFormatSupportsResolveTarget(wgpu::TextureFormat textureFormat);