Change render passes from multi to single pass.

This as an API change to get closer to the direction in which WebGPU is
headed. The API change in next.json caused a ton of files to be changed
in the same commit to keep things compiling.

API: the Framebuffer and RenderPass objects are now merged in a single
RenderPassInfo that contains the attachments, loadOps and clear values
for a BeginRenderPass command. The concept of subpass is removed.
The RenderPass creation argument to RenderPipelines is replaced by
explicitly setting the format of attachments for RenderPipeline.

Validation: SetPipeline checks are changed to check that the attachments
info set on a RenderPipeline matches the attachments of the render pass.

Backends: Most changes are simplifications of the backends that no
longer require and indirection to query the current subpass out of the
render pass in BeginSubpass, and don't need to get the attachment info
from a RenderPass when creating RenderPipelines. In the Vulkan backend,
a VkRenderPass cache is added to reuse VkRenderPasses between
RenderPassInfos and RenderPipelines.

Tests and examples: they are updated with the simplified API. Tests
specific to the Framebuffer and RenderPass objects were removed and
validation tests for RenderPassInfo were added.

Tested by running CppHelloTriangle on all backends, end2end tests on all
platforms and all examples on the GL backend.
This commit is contained in:
Corentin Wallez
2018-05-02 18:10:13 -04:00
committed by Corentin Wallez
parent 87ec361cc2
commit 6f7749cce9
92 changed files with 1869 additions and 3168 deletions

View File

@@ -23,43 +23,15 @@ TEST_F(CommandBufferValidationTest, Empty) {
.GetResult();
}
// Tests for null arguments to the command buffer builder
TEST_F(CommandBufferValidationTest, NullArguments) {
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(0)
.GetResult();
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetDimensions(100, 100)
.GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, nullptr)
.EndRenderPass()
.GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(nullptr, framebuffer)
.EndRenderPass()
.GetResult();
}
// Tests for basic render pass usage
TEST_F(CommandBufferValidationTest, RenderPass) {
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetAttachmentCount(0)
.SetSubpassCount(1)
.GetResult();
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetDimensions(100, 100)
.GetResult();
auto renderpass = CreateSimpleRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer)
.BeginRenderPass(renderpass)
.EndRenderPass()
.GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer)
.BeginRenderPass(renderpass)
.GetResult();
}

View File

@@ -17,23 +17,13 @@
class SetScissorRectTest : public ValidationTest {
};
// Test to check that SetScissor can only be used inside render subpasses
TEST_F(SetScissorRectTest, AllowedOnlyInRenderSubpass) {
// Test to check that SetScissor can only be used inside render passes
TEST_F(SetScissorRectTest, AllowedOnlyInRenderPass) {
DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.BeginRenderSubpass()
.BeginRenderPass(renderPass.renderPass)
.SetScissorRect(0, 0, 1, 1)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.SetScissorRect(0, 0, 1, 1)
.BeginRenderSubpass()
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
@@ -53,10 +43,8 @@ TEST_F(SetScissorRectTest, EmptyScissor) {
DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.BeginRenderSubpass()
.BeginRenderPass(renderPass.renderPass)
.SetScissorRect(0, 0, 0, 0)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
}
@@ -68,10 +56,8 @@ TEST_F(SetScissorRectTest, ScissorLargerThanFramebuffer) {
DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.BeginRenderSubpass()
.BeginRenderPass(renderPass.renderPass)
.SetScissorRect(0, 0, renderPass.width + 1, renderPass.height + 1)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
}
@@ -79,23 +65,13 @@ TEST_F(SetScissorRectTest, ScissorLargerThanFramebuffer) {
class SetBlendColorTest : public ValidationTest {
};
// Test to check that SetBlendColor can only be used inside render subpasses
TEST_F(SetBlendColorTest, AllowedOnlyInRenderSubpass) {
// Test to check that SetBlendColor can only be used inside render passes
TEST_F(SetBlendColorTest, AllowedOnlyInRenderPass) {
DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.BeginRenderSubpass()
.BeginRenderPass(renderPass.renderPass)
.SetBlendColor(0.0f, 0.0f, 0.0f, 0.0f)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.SetBlendColor(0.0f, 0.0f, 0.0f, 0.0f)
.BeginRenderSubpass()
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
@@ -115,10 +91,8 @@ TEST_F(SetBlendColorTest, AnyValueAllowed) {
DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.BeginRenderSubpass()
.BeginRenderPass(renderPass.renderPass)
.SetBlendColor(-1.0f, 42.0f, -0.0f, 0.0f)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
}
@@ -126,23 +100,13 @@ TEST_F(SetBlendColorTest, AnyValueAllowed) {
class SetStencilReferenceTest : public ValidationTest {
};
// Test to check that SetStencilReference can only be used inside render subpasses
TEST_F(SetStencilReferenceTest, AllowedOnlyInRenderSubpass) {
// Test to check that SetStencilReference can only be used inside render passes
TEST_F(SetStencilReferenceTest, AllowedOnlyInRenderPass) {
DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.BeginRenderSubpass()
.BeginRenderPass(renderPass.renderPass)
.SetStencilReference(0)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.SetStencilReference(0)
.BeginRenderSubpass()
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
@@ -162,10 +126,8 @@ TEST_F(SetStencilReferenceTest, AllBitsAllowed) {
DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.BeginRenderSubpass()
.BeginRenderPass(renderPass.renderPass)
.SetStencilReference(0xFFFFFFFF)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
}

View File

@@ -1,227 +0,0 @@
// Copyright 2017 The NXT Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "tests/unittests/validation/ValidationTest.h"
class FramebufferValidationTest : public ValidationTest {
protected:
nxt::TextureView Create2DAttachment(uint32_t width, uint32_t height, nxt::TextureFormat format) {
nxt::Texture attachment = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D)
.SetExtent(width, height, 1)
.SetFormat(format)
.SetMipLevels(1)
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
.SetInitialUsage(nxt::TextureUsageBit::OutputAttachment)
.GetResult();
return attachment.CreateTextureViewBuilder()
.GetResult();
}
nxt::Framebuffer CreateFramebufferWithAttachment(uint32_t width, uint32_t height, nxt::TextureFormat format) {
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetAttachmentCount(1)
.AttachmentSetFormat(0, format)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
nxt::TextureView attachment = Create2DAttachment(width, height, format);
return AssertWillBeSuccess(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetAttachment(0, attachment)
.SetDimensions(100, 100)
.GetResult();
}
};
// Test for an empty framebuffer builder
TEST_F(FramebufferValidationTest, Empty) {
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
.GetResult();
}
// Tests for null arguments to a framebuffer builder
TEST_F(FramebufferValidationTest, NullArguments) {
AssertWillBeError(device.CreateFramebufferBuilder())
.SetRenderPass(nullptr)
.GetResult();
}
// Tests for passing error-valued arguments to a framebuffer builder
TEST_F(FramebufferValidationTest, ErrorValues) {
auto renderpass = AssertWillBeError(device.CreateRenderPassBuilder())
.GetResult();
AssertWillBeError(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.GetResult();
}
// Tests for basic framebuffer construction
TEST_F(FramebufferValidationTest, Basic) {
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(0)
.GetResult();
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetDimensions(100, 100)
.GetResult();
}
// Tests for framebuffer construction with an (empty) attachment
TEST_F(FramebufferValidationTest, BasicWithEmptyAttachment) {
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
AssertWillBeError(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetDimensions(100, 100)
.GetResult();
}
// Test for a basic framebuffer with one attachment
TEST_F(FramebufferValidationTest, BasicWithOneAttachment) {
CreateFramebufferWithAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
}
// Tests for setting clear values
TEST_F(FramebufferValidationTest, ClearValues) {
auto framebuffer = CreateFramebufferWithAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
// Set clear color value for attachment 0
framebuffer.AttachmentSetClearColor(0, 0.0f, 0.0f, 0.0f, 0.0f);
// Set clear depth/stencil values for attachment 0 - ok, but ignored, since it's a color attachment
framebuffer.AttachmentSetClearDepthStencil(0, 0.0f, 0);
// Set clear color value for attachment 1 - should fail
ASSERT_DEVICE_ERROR(framebuffer.AttachmentSetClearColor(1, 0.0f, 0.0f, 0.0f, 0.0f));
}
// Check validation that the attachment size must be the same as the framebuffer size.
// TODO(cwallez@chromium.org): Investigate this constraint more, for example Vulkan requires
// that the attachment sizes are *at least* the framebuffer size.
TEST_F(FramebufferValidationTest, AttachmentSizeMatchFramebufferSize) {
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
nxt::TextureView attachment = Create2DAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
// Control case: two attachments of the same size
{
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetAttachment(0, attachment)
.SetDimensions(100, 100)
.GetResult();
}
// Error: case, size mismatch (framebuffer bigger than attachments)
{
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetAttachment(0, attachment)
.SetDimensions(200, 200)
.GetResult();
}
// Error: case, size mismatch (framebuffer smaller than attachments)
{
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetAttachment(0, attachment)
.SetDimensions(50, 50)
.GetResult();
}
// TODO(cwallez@chromium.org): also test with a mismatches depth / stencil
}
TEST_F(FramebufferValidationTest, AttachmentFormatMatchTextureFormat) {
// Control case: attach color attachment to color slot
{
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
nxt::TextureView attachment = Create2DAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetAttachment(0, attachment)
.SetDimensions(100, 100)
.GetResult();
}
// Error: attach color attachment to depth slot, setting the attachment format first
{
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetAttachmentCount(1)
.SetSubpassCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::D32FloatS8Uint)
.SubpassSetDepthStencilAttachment(0, 0)
.GetResult();
nxt::TextureView attachment = Create2DAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetAttachment(0, attachment)
.SetDimensions(100, 100)
.GetResult();
}
// Error: attach color attachment to depth slot, but setting the attachment format last
{
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.SubpassSetDepthStencilAttachment(0, 0)
.AttachmentSetFormat(0, nxt::TextureFormat::D32FloatS8Uint)
.GetResult();
nxt::TextureView attachment = Create2DAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetAttachment(0, attachment)
.SetDimensions(100, 100)
.GetResult();
}
// Error: attach depth texture to color slot
{
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
nxt::TextureView attachment = Create2DAttachment(100, 100, nxt::TextureFormat::D32FloatS8Uint);
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetAttachment(0, attachment)
.SetDimensions(100, 100)
.GetResult();
}
// TODO(kainino@chromium.org): also check attachment samples, etc.
}

View File

@@ -46,7 +46,7 @@ class InputStateTest : public ValidationTest {
builder = AssertWillBeError(device.CreateRenderPipelineBuilder());
}
return builder.SetSubpass(renderpassData.renderPass, 0)
return builder.SetColorAttachmentFormat(0, renderpassData.attachmentFormat)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetInputState(inputState)

View File

@@ -54,11 +54,9 @@ TEST_F(PushConstantTest, Success) {
.SetPushConstants(nxt::ShaderStageBit::Compute, 0, 1, constants)
.EndComputePass()
// PushConstants in a render subpass
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
.BeginRenderSubpass()
// PushConstants in a render pass
.BeginRenderPass(renderpassData.renderPass)
.SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, constants)
.EndRenderSubpass()
.EndRenderPass()
// Setting all constants
@@ -120,36 +118,9 @@ TEST_F(PushConstantTest, NotInPass) {
.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, constants)
.GetResult();
}
// Setting in renderpass but outside subpass is invalid
{
// Control to check the error is caused by the SetPushConstants
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
.BeginRenderSubpass()
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, constants)
.BeginRenderSubpass()
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
.BeginRenderSubpass()
.EndRenderSubpass()
.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, constants)
.EndRenderPass()
.GetResult();
}
}
// Test valid stages for subpass
// Test valid stages for compute pass
TEST_F(PushConstantTest, StageForComputePass) {
// Control case: setting to the compute stage in compute passes
{
@@ -179,17 +150,15 @@ TEST_F(PushConstantTest, StageForComputePass) {
}
}
// Test valid stages for compute passes
TEST_F(PushConstantTest, StageForSubpass) {
// Test valid stages for render passes
TEST_F(PushConstantTest, StageForRenderPass) {
DummyRenderPass renderpassData = CreateDummyRenderPass();
// Control case: setting to vertex and fragment in subpass
// Control case: setting to vertex and fragment in render pass
{
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
.BeginRenderSubpass()
.BeginRenderPass(renderpassData.renderPass)
.SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, constants)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
}
@@ -197,10 +166,8 @@ TEST_F(PushConstantTest, StageForSubpass) {
// Compute stage is disallowed
{
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
.BeginRenderSubpass()
.BeginRenderPass(renderpassData.renderPass)
.SetPushConstants(nxt::ShaderStageBit::Compute, 0, 1, constants)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
}
@@ -208,10 +175,8 @@ TEST_F(PushConstantTest, StageForSubpass) {
// A None shader stage mask is valid.
{
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
.BeginRenderSubpass()
.BeginRenderPass(renderpassData.renderPass)
.SetPushConstants(nxt::ShaderStageBit::None, 0, 1, constants)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
}

View File

@@ -0,0 +1,181 @@
// Copyright 2018 The NXT Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "tests/unittests/validation/ValidationTest.h"
#include "common/Constants.h"
namespace {
class RenderPassInfoValidationTest : public ValidationTest {
};
nxt::TextureView Create2DAttachment(nxt::Device& device, uint32_t width, uint32_t height, nxt::TextureFormat format) {
nxt::Texture attachment = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D)
.SetExtent(width, height, 1)
.SetFormat(format)
.SetMipLevels(1)
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
.SetInitialUsage(nxt::TextureUsageBit::OutputAttachment)
.GetResult();
return attachment.CreateTextureViewBuilder()
.GetResult();
}
// A render pass with no attachments isn't valid
TEST_F(RenderPassInfoValidationTest, Empty) {
AssertWillBeError(device.CreateRenderPassInfoBuilder())
.GetResult();
}
// A render pass with only one color or one depth attachment is ok
TEST_F(RenderPassInfoValidationTest, OneAttachment) {
// One color attachment
{
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(0, color, nxt::LoadOp::Clear)
.GetResult();
}
// One depth-stencil attachment
{
nxt::TextureView depthStencil = Create2DAttachment(device, 1, 1, nxt::TextureFormat::D32FloatS8Uint);
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
.SetDepthStencilAttachment(depthStencil, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
.GetResult();
}
}
// Test OOB color attachment indices are handled
TEST_F(RenderPassInfoValidationTest, ColorAttachmentOutOfBounds) {
// For setting the color attachment, control case
{
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(kMaxColorAttachments - 1, color, nxt::LoadOp::Clear)
.GetResult();
}
// For setting the color attachment, OOB
{
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
AssertWillBeError(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(kMaxColorAttachments, color, nxt::LoadOp::Clear)
.GetResult();
}
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
// For setting the clear color, control case
{
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(0, color, nxt::LoadOp::Clear)
.SetColorAttachmentClearColor(kMaxColorAttachments - 1, 0.0f, 0.0f, 0.0f, 0.0f)
.GetResult();
}
// For setting the clear color, OOB
{
AssertWillBeError(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(0, color, nxt::LoadOp::Clear)
.SetColorAttachmentClearColor(kMaxColorAttachments, 0.0f, 0.0f, 0.0f, 0.0f)
.GetResult();
}
}
// Test setting a clear value without an attachment and vice-versa is ok.
TEST_F(RenderPassInfoValidationTest, ClearAndAttachmentMismatchIsOk) {
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
// For cleared attachment 0 doesn't get a color, clear color for 1 is unused
{
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(0, color, nxt::LoadOp::Clear)
.SetColorAttachmentClearColor(1, 0.0f, 0.0f, 0.0f, 0.0f)
.GetResult();
}
// Clear depth stencil doesn't get values
{
nxt::TextureView depthStencil = Create2DAttachment(device, 1, 1, nxt::TextureFormat::D32FloatS8Uint);
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
.SetDepthStencilAttachment(depthStencil, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
.GetResult();
}
// Clear values for depth-stencil when it isn't used
{
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(0, color, nxt::LoadOp::Clear)
.SetDepthStencilAttachmentClearValue(0.0f, 0)
.GetResult();
}
}
// Attachments must have the same size
TEST_F(RenderPassInfoValidationTest, SizeMustMatch) {
nxt::TextureView color1x1A = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
nxt::TextureView color1x1B = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
nxt::TextureView color2x2 = Create2DAttachment(device, 2, 2, nxt::TextureFormat::R8G8B8A8Unorm);
nxt::TextureView depthStencil1x1 = Create2DAttachment(device, 1, 1, nxt::TextureFormat::D32FloatS8Uint);
nxt::TextureView depthStencil2x2 = Create2DAttachment(device, 2, 2, nxt::TextureFormat::D32FloatS8Uint);
// Control case: all the same size (1x1)
{
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(0, color1x1A, nxt::LoadOp::Clear)
.SetColorAttachment(1, color1x1B, nxt::LoadOp::Clear)
.SetDepthStencilAttachment(depthStencil1x1, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
.GetResult();
}
// One of the color attachments has a different size
{
AssertWillBeError(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(0, color1x1A, nxt::LoadOp::Clear)
.SetColorAttachment(1, color2x2, nxt::LoadOp::Clear)
.SetDepthStencilAttachment(depthStencil1x1, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
.GetResult();
}
// The depth stencil attachment has a different size
{
AssertWillBeError(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(0, color1x1A, nxt::LoadOp::Clear)
.SetColorAttachment(1, color1x1B, nxt::LoadOp::Clear)
.SetDepthStencilAttachment(depthStencil2x2, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
.GetResult();
}
}
// Attachments formats must match whether they are used for color or depth-stencil
TEST_F(RenderPassInfoValidationTest, FormatMismatch) {
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
nxt::TextureView depthStencil = Create2DAttachment(device, 1, 1, nxt::TextureFormat::D32FloatS8Uint);
// Using depth-stencil for color
{
AssertWillBeError(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(0, depthStencil, nxt::LoadOp::Clear)
.GetResult();
}
// Using color for depth-stencil
{
AssertWillBeError(device.CreateRenderPassInfoBuilder())
.SetDepthStencilAttachment(color, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
.GetResult();
}
}
// TODO(cwallez@chromium.org): Constraints on attachment aliasing?
} // anonymous namespace

View File

@@ -1,159 +0,0 @@
// Copyright 2017 The NXT Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "tests/unittests/validation/ValidationTest.h"
class RenderPassValidationTest : public ValidationTest {
};
// Test for an empty render pass builder
TEST_F(RenderPassValidationTest, Empty) {
AssertWillBeError(device.CreateRenderPassBuilder())
.GetResult();
}
// Test for a render pass with one subpass and no attachments
TEST_F(RenderPassValidationTest, OneSubpass) {
AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(0)
.GetResult();
}
// Test for a render pass with one subpass and one attachment
TEST_F(RenderPassValidationTest, OneSubpassOneAttachment) {
AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
// without a load op
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
}
// Tests for setting attachment load ops
TEST_F(RenderPassValidationTest, AttachmentLoadOps) {
AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
// with a load op
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
// with a load op of the wrong type - this is okay, just ignored
.AttachmentSetDepthStencilLoadOps(0, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
}
// Test for attachment slot arguments out of bounds
TEST_F(RenderPassValidationTest, AttachmentOutOfBounds) {
// Control case
AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.GetResult();
AssertWillBeError(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
// Test AttachmentSetFormat slot out of bounds
.AttachmentSetFormat(1, nxt::TextureFormat::R8G8B8A8Unorm)
.GetResult();
AssertWillBeError(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
// Test AttachmentSetColorLoadOp slot out of bounds
.AttachmentSetColorLoadOp(1, nxt::LoadOp::Clear)
.GetResult();
AssertWillBeError(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
// Test AttachmentSetDepthStencilLoadOps slot out of bounds
.AttachmentSetDepthStencilLoadOps(1, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
.GetResult();
AssertWillBeError(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
// Test SubpassSetColorAttachment attachment slot out of bounds
.SubpassSetColorAttachment(0, 0, 1)
.GetResult();
AssertWillBeError(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
// Test SubpassSetDepthStencilAttachment attachment slot out of bounds
.SubpassSetDepthStencilAttachment(0, 1)
.GetResult();
}
// Test for subpass arguments out of bounds
TEST_F(RenderPassValidationTest, SubpassOutOfBounds) {
// Control case
AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
AssertWillBeError(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SubpassSetColorAttachment(0, 0, 0)
// Test SubpassSetColorAttachment subpass out of bounds
.SubpassSetColorAttachment(1, 0, 0)
.GetResult();
AssertWillBeError(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::D32FloatS8Uint)
// Test SubpassSetDepthStencilAttachment subpass out of bounds
.SubpassSetDepthStencilAttachment(1, 0)
.GetResult();
}
// Test attaching depth/stencil textures to color attachments and vice versa
TEST_F(RenderPassValidationTest, SubpassAttachmentWrongAspect) {
AssertWillBeError(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SubpassSetDepthStencilAttachment(0, 0)
.GetResult();
AssertWillBeError(device.CreateRenderPassBuilder())
.SetSubpassCount(1)
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::D32FloatS8Uint)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
}

View File

@@ -14,6 +14,7 @@
#include "tests/unittests/validation/ValidationTest.h"
#include "common/Constants.h"
#include "utils/NXTHelpers.h"
class RenderPipelineValidationTest : public ValidationTest {
@@ -21,7 +22,7 @@ class RenderPipelineValidationTest : public ValidationTest {
void SetUp() override {
ValidationTest::SetUp();
CreateSimpleRenderPassAndFramebuffer(device, &renderpass, &framebuffer);
renderpass = CreateSimpleRenderPass();
pipelineLayout = device.CreatePipelineLayoutBuilder().GetResult();
@@ -45,7 +46,7 @@ class RenderPipelineValidationTest : public ValidationTest {
}
nxt::RenderPipelineBuilder& AddDefaultStates(nxt::RenderPipelineBuilder&& builder) {
builder.SetSubpass(renderpass, 0)
builder.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@@ -53,8 +54,7 @@ class RenderPipelineValidationTest : public ValidationTest {
return builder;
}
nxt::RenderPass renderpass;
nxt::Framebuffer framebuffer;
nxt::RenderPassInfo renderpass;
nxt::ShaderModule vsModule;
nxt::ShaderModule fsModule;
nxt::InputState inputState;
@@ -81,7 +81,7 @@ TEST_F(RenderPipelineValidationTest, CreationMissingProperty) {
// Vertex stage not set
{
AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0)
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList)
@@ -91,14 +91,14 @@ TEST_F(RenderPipelineValidationTest, CreationMissingProperty) {
// Fragment stage not set
{
AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0)
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList)
.GetResult();
}
// Subpass not set
// No attachment set
{
AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetLayout(pipelineLayout)
@@ -112,47 +112,9 @@ TEST_F(RenderPipelineValidationTest, CreationMissingProperty) {
TEST_F(RenderPipelineValidationTest, BlendState) {
// Fails because blend state is set on a nonexistent color attachment
{
auto texture1 = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D)
.SetExtent(640, 480, 1)
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
.SetMipLevels(1)
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
.GetResult();
texture1.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
auto textureView1 = texture1.CreateTextureViewBuilder()
.GetResult();
auto texture2 = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D)
.SetExtent(640, 480, 1)
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
.SetMipLevels(1)
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
.GetResult();
texture2.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
auto textureView2 = texture2.CreateTextureViewBuilder()
.GetResult();
auto renderpass = device.CreateRenderPassBuilder()
.SetAttachmentCount(2)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.AttachmentSetFormat(1, nxt::TextureFormat::R8G8B8A8Unorm)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
auto framebuffer = device.CreateFramebufferBuilder()
.SetRenderPass(renderpass)
.SetDimensions(640, 480)
.SetAttachment(0, textureView1)
.SetAttachment(1, textureView2)
.GetResult();
// This one succeeds because attachment 0 is the subpass's color attachment
// This one succeeds because attachment 0 is the color attachment
AssertWillBeSuccess(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0)
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@@ -160,9 +122,9 @@ TEST_F(RenderPipelineValidationTest, BlendState) {
.SetColorAttachmentBlendState(0, blendState)
.GetResult();
// This fails because attachment 1 is not one of the subpass's color attachments
// This fails because attachment 1 is not one of the color attachments
AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0)
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@@ -174,7 +136,7 @@ TEST_F(RenderPipelineValidationTest, BlendState) {
// Fails because color attachment is out of bounds
{
AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder()))
.SetColorAttachmentBlendState(1, blendState)
.SetColorAttachmentBlendState(kMaxColorAttachments, blendState)
.GetResult();
}
@@ -192,7 +154,7 @@ TEST_F(RenderPipelineValidationTest, DISABLED_TodoCreationMissingProperty) {
// Fails because pipeline layout is not set
{
AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0)
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList)
@@ -202,7 +164,7 @@ TEST_F(RenderPipelineValidationTest, DISABLED_TodoCreationMissingProperty) {
// Fails because primitive topology is not set
{
AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0)
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@@ -240,13 +202,6 @@ TEST_F(RenderPipelineValidationTest, DISABLED_CreationDuplicates) {
.GetResult();
}
// Fails because subpass is set twice
{
AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder()))
.SetSubpass(renderpass, 0)
.GetResult();
}
// Fails because the layout is set twice
{
AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder()))

View File

@@ -69,7 +69,7 @@ bool ValidationTest::EndExpectDeviceError() {
return mError;
}
void ValidationTest::CreateSimpleRenderPassAndFramebuffer(const nxt::Device& device, nxt::RenderPass* renderpass, nxt::Framebuffer* framebuffer) {
nxt::RenderPassInfo ValidationTest::CreateSimpleRenderPass() {
auto colorBuffer = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D)
.SetExtent(640, 480, 1)
@@ -81,17 +81,8 @@ void ValidationTest::CreateSimpleRenderPassAndFramebuffer(const nxt::Device& dev
auto colorView = colorBuffer.CreateTextureViewBuilder()
.GetResult();
*renderpass = device.CreateRenderPassBuilder()
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
*framebuffer = device.CreateFramebufferBuilder()
.SetRenderPass(*renderpass)
.SetDimensions(640, 480)
.SetAttachment(0, colorView)
return device.CreateRenderPassInfoBuilder()
.SetColorAttachment(0, colorView, nxt::LoadOp::Clear)
.GetResult();
}
@@ -128,13 +119,6 @@ ValidationTest::DummyRenderPass ValidationTest::CreateDummyRenderPass() {
dummy.height = 400;
dummy.attachmentFormat = nxt::TextureFormat::R8G8B8A8Unorm;
dummy.renderPass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
.SetAttachmentCount(1)
.AttachmentSetFormat(0, dummy.attachmentFormat)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
dummy.attachment = AssertWillBeSuccess(device.CreateTextureBuilder())
.SetDimension(nxt::TextureDimension::e2D)
.SetExtent(dummy.width, dummy.height, 1)
@@ -146,10 +130,8 @@ ValidationTest::DummyRenderPass ValidationTest::CreateDummyRenderPass() {
nxt::TextureView view = AssertWillBeSuccess(dummy.attachment.CreateTextureViewBuilder()).GetResult();
dummy.framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
.SetRenderPass(dummy.renderPass)
.SetAttachment(0, view)
.SetDimensions(dummy.width, dummy.height)
dummy.renderPass = AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
.SetColorAttachment(0, view, nxt::LoadOp::Clear)
.GetResult();
return dummy;

View File

@@ -48,13 +48,12 @@ class ValidationTest : public testing::Test {
void StartExpectDeviceError();
bool EndExpectDeviceError();
void CreateSimpleRenderPassAndFramebuffer(const nxt::Device& device, nxt::RenderPass* renderpass, nxt::Framebuffer* framebuffer);
nxt::RenderPassInfo CreateSimpleRenderPass();
// Helper functions to create objects to test validation.
struct DummyRenderPass {
nxt::RenderPass renderPass;
nxt::Framebuffer framebuffer;
nxt::RenderPassInfo renderPass;
nxt::Texture attachment;
nxt::TextureFormat attachmentFormat;
uint32_t width;

View File

@@ -23,6 +23,8 @@ class VertexBufferValidationTest : public ValidationTest {
void SetUp() override {
ValidationTest::SetUp();
renderpass = CreateSimpleRenderPass();
fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
#version 450
layout(location = 0) out vec4 fragColor;
@@ -31,36 +33,6 @@ class VertexBufferValidationTest : public ValidationTest {
})");
}
void MakeRenderPassAndFrameBuffer(uint32_t subpassCount) {
auto colorBuffer = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D)
.SetExtent(640, 480, 1)
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
.SetMipLevels(1)
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
.GetResult();
colorBuffer.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
auto colorView = colorBuffer.CreateTextureViewBuilder()
.GetResult();
auto renderpassBuilder = device.CreateRenderPassBuilder();
renderpassBuilder.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetSubpassCount(subpassCount);
for (uint32_t i = 0; i < subpassCount; ++i) {
renderpassBuilder.SubpassSetColorAttachment(i, 0, 0);
}
renderpass = renderpassBuilder.GetResult();
framebuffer = device.CreateFramebufferBuilder()
.SetRenderPass(renderpass)
.SetDimensions(640, 480)
.SetAttachment(0, colorView)
.GetResult();
}
template <unsigned int N>
std::array<nxt::Buffer, N> MakeVertexBuffers() {
std::array<nxt::Buffer, N> buffers;
@@ -105,102 +77,89 @@ class VertexBufferValidationTest : public ValidationTest {
return builder.GetResult();
}
nxt::RenderPipeline MakeRenderPipeline(uint32_t subpass, const nxt::ShaderModule& vsModule, const nxt::InputState& inputState) {
nxt::RenderPipeline MakeRenderPipeline(const nxt::ShaderModule& vsModule, const nxt::InputState& inputState) {
return device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, subpass)
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetInputState(inputState)
.GetResult();
}
nxt::RenderPass renderpass;
nxt::Framebuffer framebuffer;
nxt::RenderPassInfo renderpass;
nxt::ShaderModule fsModule;
};
TEST_F(VertexBufferValidationTest, VertexInputsInheritedBetweenPipelines) {
MakeRenderPassAndFrameBuffer(1);
auto vsModule2 = MakeVertexShader(2);
auto vsModule1 = MakeVertexShader(1);
auto inputState2 = MakeInputState(2);
auto inputState1 = MakeInputState(1);
auto pipeline2 = MakeRenderPipeline(0, vsModule2, inputState2);
auto pipeline1 = MakeRenderPipeline(0, vsModule1, inputState1);
auto pipeline2 = MakeRenderPipeline(vsModule2, inputState2);
auto pipeline1 = MakeRenderPipeline(vsModule1, inputState1);
auto vertexBuffers = MakeVertexBuffers<2>();
uint32_t offsets[] = { 0, 0 };
// Check failure when vertex buffer is not set
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline1)
.DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.BeginRenderPass(renderpass)
.SetRenderPipeline(pipeline1)
.DrawArrays(3, 1, 0, 0)
.EndRenderPass()
.GetResult();
// Check success when vertex buffer is inherited from previous pipeline
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline2)
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0)
.SetRenderPipeline(pipeline1)
.DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.BeginRenderPass(renderpass)
.SetRenderPipeline(pipeline2)
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0)
.SetRenderPipeline(pipeline1)
.DrawArrays(3, 1, 0, 0)
.EndRenderPass()
.GetResult();
}
TEST_F(VertexBufferValidationTest, VertexInputsNotInheritedBetweenSubpasses) {
MakeRenderPassAndFrameBuffer(2);
TEST_F(VertexBufferValidationTest, VertexInputsNotInheritedBetweenRendePasses) {
auto vsModule2 = MakeVertexShader(2);
auto vsModule1 = MakeVertexShader(1);
auto inputState2 = MakeInputState(2);
auto inputState1 = MakeInputState(1);
auto pipeline2 = MakeRenderPipeline(0, vsModule2, inputState2);
auto pipeline1 = MakeRenderPipeline(1, vsModule1, inputState1);
auto pipeline2 = MakeRenderPipeline(vsModule2, inputState2);
auto pipeline1 = MakeRenderPipeline(vsModule1, inputState1);
auto vertexBuffers = MakeVertexBuffers<2>();
uint32_t offsets[] = { 0, 0 };
// Check success when vertex buffer is set for each subpass
// Check success when vertex buffer is set for each render pass
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline2)
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.BeginRenderSubpass()
.SetRenderPipeline(pipeline1)
.SetVertexBuffers(0, 1, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.BeginRenderPass(renderpass)
.SetRenderPipeline(pipeline2)
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0)
.EndRenderPass()
.BeginRenderPass(renderpass)
.SetRenderPipeline(pipeline1)
.SetVertexBuffers(0, 1, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0)
.EndRenderPass()
.GetResult();
// Check failure because vertex buffer is not inherited in second subpass
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline2)
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.BeginRenderSubpass()
.SetRenderPipeline(pipeline1)
.DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.BeginRenderPass(renderpass)
.SetRenderPipeline(pipeline2)
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0)
.EndRenderPass()
.BeginRenderPass(renderpass)
.SetRenderPipeline(pipeline1)
.DrawArrays(3, 1, 0, 0)
.EndRenderPass()
.GetResult();
}