Add check on the sample count between render pipeline and render pass
This patch adds the support of multisampling in the render pipeline and the validations that the sample count of the render pipeline must be equal to the ones in render pass color and depth stencil attachments. BUG=dawn:56 TEST=dawn_unittests Change-Id: I823c565bf9466ac6029f2797b31368bbdd6b8280 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/5622 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
parent
fef613365a
commit
54e4d47db4
|
@ -340,8 +340,13 @@ namespace dawn_native {
|
|||
|
||||
// *sampleCount == 0 must only happen when there is no color attachment. In that case we
|
||||
// do not need to validate the sample count of the depth stencil attachment.
|
||||
if (*sampleCount != 0 && (attachment->GetTexture()->GetSampleCount() != *sampleCount)) {
|
||||
return DAWN_VALIDATION_ERROR("Depth stencil attachment sample counts mismatch");
|
||||
const uint32_t depthStencilSampleCount = attachment->GetTexture()->GetSampleCount();
|
||||
if (*sampleCount != 0) {
|
||||
if (depthStencilSampleCount != *sampleCount) {
|
||||
return DAWN_VALIDATION_ERROR("Depth stencil attachment sample counts mismatch");
|
||||
}
|
||||
} else {
|
||||
*sampleCount = depthStencilSampleCount;
|
||||
}
|
||||
|
||||
DAWN_TRY(ValidateAttachmentArrayLayersAndLevelCount(attachment));
|
||||
|
@ -350,23 +355,23 @@ namespace dawn_native {
|
|||
return {};
|
||||
}
|
||||
|
||||
MaybeError ValidateRenderPassDescriptorAndSetSize(const DeviceBase* device,
|
||||
const RenderPassDescriptor* renderPass,
|
||||
uint32_t* width,
|
||||
uint32_t* height) {
|
||||
MaybeError ValidateRenderPassDescriptor(const DeviceBase* device,
|
||||
const RenderPassDescriptor* renderPass,
|
||||
uint32_t* width,
|
||||
uint32_t* height,
|
||||
uint32_t* sampleCount) {
|
||||
if (renderPass->colorAttachmentCount > kMaxColorAttachments) {
|
||||
return DAWN_VALIDATION_ERROR("Setting color attachments out of bounds");
|
||||
}
|
||||
|
||||
uint32_t sampleCount = 0;
|
||||
for (uint32_t i = 0; i < renderPass->colorAttachmentCount; ++i) {
|
||||
DAWN_TRY(ValidateRenderPassColorAttachment(device, renderPass->colorAttachments[i],
|
||||
width, height, &sampleCount));
|
||||
width, height, sampleCount));
|
||||
}
|
||||
|
||||
if (renderPass->depthStencilAttachment != nullptr) {
|
||||
DAWN_TRY(ValidateRenderPassDepthStencilAttachment(
|
||||
device, renderPass->depthStencilAttachment, width, height, &sampleCount));
|
||||
device, renderPass->depthStencilAttachment, width, height, sampleCount));
|
||||
}
|
||||
|
||||
if (renderPass->colorAttachmentCount == 0 &&
|
||||
|
@ -584,10 +589,14 @@ namespace dawn_native {
|
|||
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
if (ConsumedError(ValidateRenderPassDescriptorAndSetSize(device, info, &width, &height))) {
|
||||
uint32_t sampleCount = 0;
|
||||
if (ConsumedError(
|
||||
ValidateRenderPassDescriptor(device, info, &width, &height, &sampleCount))) {
|
||||
return RenderPassEncoderBase::MakeError(device, this);
|
||||
}
|
||||
|
||||
ASSERT(width > 0 && height > 0 && sampleCount > 0);
|
||||
|
||||
mEncodingState = EncodingState::RenderPass;
|
||||
|
||||
BeginRenderPassCmd* cmd = mAllocator.Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
|
||||
|
@ -619,6 +628,7 @@ namespace dawn_native {
|
|||
|
||||
cmd->width = width;
|
||||
cmd->height = height;
|
||||
cmd->sampleCount = sampleCount;
|
||||
|
||||
return new RenderPassEncoderBase(device, this, &mAllocator);
|
||||
}
|
||||
|
|
|
@ -81,9 +81,10 @@ namespace dawn_native {
|
|||
bool hasDepthStencilAttachment;
|
||||
RenderPassDepthStencilAttachmentInfo depthStencilAttachment;
|
||||
|
||||
// Cache the width and height of all attachments for convenience
|
||||
// Cache the width, height and sample count of all attachments for convenience
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t sampleCount;
|
||||
};
|
||||
|
||||
struct BufferCopy {
|
||||
|
|
|
@ -117,8 +117,8 @@ namespace dawn_native {
|
|||
"Pipeline vertex stage uses inputs not in the input state");
|
||||
}
|
||||
|
||||
if (descriptor->sampleCount != 1) {
|
||||
return DAWN_VALIDATION_ERROR("Sample count must be one");
|
||||
if (!IsValidSampleCount(descriptor->sampleCount)) {
|
||||
return DAWN_VALIDATION_ERROR("Sample count is not supported");
|
||||
}
|
||||
|
||||
if (descriptor->colorStateCount > kMaxColorAttachments) {
|
||||
|
@ -170,7 +170,8 @@ namespace dawn_native {
|
|||
mIndexFormat(descriptor->indexFormat),
|
||||
mInputState(descriptor->inputState),
|
||||
mPrimitiveTopology(descriptor->primitiveTopology),
|
||||
mHasDepthStencilAttachment(descriptor->depthStencilState != nullptr) {
|
||||
mHasDepthStencilAttachment(descriptor->depthStencilState != nullptr),
|
||||
mSampleCount(descriptor->sampleCount) {
|
||||
if (mHasDepthStencilAttachment) {
|
||||
mDepthStencilState = *descriptor->depthStencilState;
|
||||
} else {
|
||||
|
@ -285,6 +286,10 @@ namespace dawn_native {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (renderPass->sampleCount != mSampleCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,8 @@ namespace dawn_native {
|
|||
|
||||
std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
|
||||
bool mHasDepthStencilAttachment = false;
|
||||
|
||||
uint32_t mSampleCount;
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -100,18 +100,13 @@ namespace dawn_native {
|
|||
|
||||
// TODO(jiawei.shao@intel.com): support more sample count.
|
||||
MaybeError ValidateSampleCount(const TextureDescriptor* descriptor) {
|
||||
switch (descriptor->sampleCount) {
|
||||
case 1:
|
||||
break;
|
||||
case 4:
|
||||
if (descriptor->mipLevelCount > 1) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"The mipmap level count of a multisampled texture must be 1.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"The sample count of the texture is not supported.");
|
||||
if (!IsValidSampleCount(descriptor->sampleCount)) {
|
||||
return DAWN_VALIDATION_ERROR("The sample count of the texture is not supported.");
|
||||
}
|
||||
|
||||
if (descriptor->sampleCount > 1 && descriptor->mipLevelCount > 1) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"The mipmap level count of a multisampled texture must be 1.");
|
||||
}
|
||||
|
||||
return {};
|
||||
|
@ -314,6 +309,17 @@ namespace dawn_native {
|
|||
}
|
||||
}
|
||||
|
||||
bool IsValidSampleCount(uint32_t sampleCount) {
|
||||
switch (sampleCount) {
|
||||
case 1:
|
||||
case 4:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TextureBase
|
||||
|
||||
TextureBase::TextureBase(DeviceBase* device, const TextureDescriptor* descriptor)
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace dawn_native {
|
|||
bool TextureFormatHasDepthOrStencil(dawn::TextureFormat format);
|
||||
bool IsColorRenderableTextureFormat(dawn::TextureFormat format);
|
||||
bool IsDepthStencilRenderableTextureFormat(dawn::TextureFormat format);
|
||||
bool IsValidSampleCount(uint32_t sampleCount);
|
||||
|
||||
static constexpr dawn::TextureUsageBit kReadOnlyTextureUsages =
|
||||
dawn::TextureUsageBit::TransferSrc | dawn::TextureUsageBit::Sampled |
|
||||
|
|
|
@ -71,3 +71,176 @@ TEST_F(RenderPipelineValidationTest, ColorState) {
|
|||
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests that the sample count of the render pipeline must be valid.
|
||||
TEST_F(RenderPipelineValidationTest, SampleCount) {
|
||||
{
|
||||
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||
descriptor.cVertexStage.module = vsModule;
|
||||
descriptor.cFragmentStage.module = fsModule;
|
||||
descriptor.sampleCount = 4;
|
||||
|
||||
device.CreateRenderPipeline(&descriptor);
|
||||
}
|
||||
|
||||
{
|
||||
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||
descriptor.cVertexStage.module = vsModule;
|
||||
descriptor.cFragmentStage.module = fsModule;
|
||||
descriptor.sampleCount = 3;
|
||||
|
||||
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the sample count of the render pipeline must be equal to the one of every attachments
|
||||
// in the render pass.
|
||||
TEST_F(RenderPipelineValidationTest, SampleCountCompatibilityWithRenderPass) {
|
||||
constexpr uint32_t kMultisampledCount = 4;
|
||||
constexpr dawn::TextureFormat kColorFormat = dawn::TextureFormat::R8G8B8A8Unorm;
|
||||
constexpr dawn::TextureFormat kDepthStencilFormat = dawn::TextureFormat::D32FloatS8Uint;
|
||||
|
||||
dawn::TextureDescriptor baseTextureDescriptor;
|
||||
baseTextureDescriptor.size.width = 4;
|
||||
baseTextureDescriptor.size.height = 4;
|
||||
baseTextureDescriptor.size.depth = 1;
|
||||
baseTextureDescriptor.arrayLayerCount = 1;
|
||||
baseTextureDescriptor.mipLevelCount = 1;
|
||||
baseTextureDescriptor.dimension = dawn::TextureDimension::e2D;
|
||||
baseTextureDescriptor.usage = dawn::TextureUsageBit::OutputAttachment;
|
||||
|
||||
utils::ComboRenderPipelineDescriptor nonMultisampledPipelineDescriptor(device);
|
||||
nonMultisampledPipelineDescriptor.sampleCount = 1;
|
||||
nonMultisampledPipelineDescriptor.cVertexStage.module = vsModule;
|
||||
nonMultisampledPipelineDescriptor.cFragmentStage.module = fsModule;
|
||||
dawn::RenderPipeline nonMultisampledPipeline =
|
||||
device.CreateRenderPipeline(&nonMultisampledPipelineDescriptor);
|
||||
|
||||
nonMultisampledPipelineDescriptor.colorStateCount = 0;
|
||||
nonMultisampledPipelineDescriptor.depthStencilState =
|
||||
&nonMultisampledPipelineDescriptor.cDepthStencilState;
|
||||
dawn::RenderPipeline nonMultisampledPipelineWithDepthStencilOnly =
|
||||
device.CreateRenderPipeline(&nonMultisampledPipelineDescriptor);
|
||||
|
||||
utils::ComboRenderPipelineDescriptor multisampledPipelineDescriptor(device);
|
||||
multisampledPipelineDescriptor.sampleCount = kMultisampledCount;
|
||||
multisampledPipelineDescriptor.cVertexStage.module = vsModule;
|
||||
multisampledPipelineDescriptor.cFragmentStage.module = fsModule;
|
||||
dawn::RenderPipeline multisampledPipeline =
|
||||
device.CreateRenderPipeline(&multisampledPipelineDescriptor);
|
||||
|
||||
multisampledPipelineDescriptor.colorStateCount = 0;
|
||||
multisampledPipelineDescriptor.depthStencilState =
|
||||
&multisampledPipelineDescriptor.cDepthStencilState;
|
||||
dawn::RenderPipeline multisampledPipelineWithDepthStencilOnly =
|
||||
device.CreateRenderPipeline(&multisampledPipelineDescriptor);
|
||||
|
||||
// It is not allowed to use multisampled render pass and non-multisampled render pipeline.
|
||||
{
|
||||
{
|
||||
dawn::TextureDescriptor textureDescriptor = baseTextureDescriptor;
|
||||
textureDescriptor.format = kColorFormat;
|
||||
textureDescriptor.sampleCount = kMultisampledCount;
|
||||
dawn::Texture multisampledColorTexture = device.CreateTexture(&textureDescriptor);
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor(
|
||||
{multisampledColorTexture.CreateDefaultTextureView()});
|
||||
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
renderPass.SetPipeline(nonMultisampledPipeline);
|
||||
renderPass.EndPass();
|
||||
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
}
|
||||
|
||||
{
|
||||
dawn::TextureDescriptor textureDescriptor = baseTextureDescriptor;
|
||||
textureDescriptor.sampleCount = kMultisampledCount;
|
||||
textureDescriptor.format = kDepthStencilFormat;
|
||||
dawn::Texture multisampledDepthStencilTexture =
|
||||
device.CreateTexture(&textureDescriptor);
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor(
|
||||
{}, multisampledDepthStencilTexture.CreateDefaultTextureView());
|
||||
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
renderPass.SetPipeline(nonMultisampledPipelineWithDepthStencilOnly);
|
||||
renderPass.EndPass();
|
||||
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
}
|
||||
}
|
||||
|
||||
// It is allowed to use multisampled render pass and multisampled render pipeline.
|
||||
{
|
||||
{
|
||||
dawn::TextureDescriptor textureDescriptor = baseTextureDescriptor;
|
||||
textureDescriptor.format = kColorFormat;
|
||||
textureDescriptor.sampleCount = kMultisampledCount;
|
||||
dawn::Texture multisampledColorTexture = device.CreateTexture(&textureDescriptor);
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor(
|
||||
{multisampledColorTexture.CreateDefaultTextureView()});
|
||||
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
renderPass.SetPipeline(multisampledPipeline);
|
||||
renderPass.EndPass();
|
||||
|
||||
encoder.Finish();
|
||||
}
|
||||
|
||||
{
|
||||
dawn::TextureDescriptor textureDescriptor = baseTextureDescriptor;
|
||||
textureDescriptor.sampleCount = kMultisampledCount;
|
||||
textureDescriptor.format = kDepthStencilFormat;
|
||||
dawn::Texture multisampledDepthStencilTexture =
|
||||
device.CreateTexture(&textureDescriptor);
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor(
|
||||
{}, multisampledDepthStencilTexture.CreateDefaultTextureView());
|
||||
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
renderPass.SetPipeline(multisampledPipelineWithDepthStencilOnly);
|
||||
renderPass.EndPass();
|
||||
|
||||
encoder.Finish();
|
||||
}
|
||||
}
|
||||
|
||||
// It is not allowed to use non-multisampled render pass and multisampled render pipeline.
|
||||
{
|
||||
{
|
||||
dawn::TextureDescriptor textureDescriptor = baseTextureDescriptor;
|
||||
textureDescriptor.format = kColorFormat;
|
||||
textureDescriptor.sampleCount = 1;
|
||||
dawn::Texture nonMultisampledColorTexture = device.CreateTexture(&textureDescriptor);
|
||||
utils::ComboRenderPassDescriptor nonMultisampledRenderPassDescriptor(
|
||||
{ nonMultisampledColorTexture.CreateDefaultTextureView() });
|
||||
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder renderPass =
|
||||
encoder.BeginRenderPass(&nonMultisampledRenderPassDescriptor);
|
||||
renderPass.SetPipeline(multisampledPipeline);
|
||||
renderPass.EndPass();
|
||||
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
}
|
||||
|
||||
{
|
||||
dawn::TextureDescriptor textureDescriptor = baseTextureDescriptor;
|
||||
textureDescriptor.sampleCount = 1;
|
||||
textureDescriptor.format = kDepthStencilFormat;
|
||||
dawn::Texture multisampledDepthStencilTexture =
|
||||
device.CreateTexture(&textureDescriptor);
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor(
|
||||
{}, multisampledDepthStencilTexture.CreateDefaultTextureView());
|
||||
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
renderPass.SetPipeline(multisampledPipelineWithDepthStencilOnly);
|
||||
renderPass.EndPass();
|
||||
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue