Set D3D12 IBStripCutValue
Sets IBStripCutValue on the D3D12 render pipeline to the appropriate value when an index buffer is used. Revises primitive restart tests to catch when IBStripCutValue is not set. Bug: dawn:575 Change-Id: I77058d8fe62a52c09641b82d3383a404b7ac6d4a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/34340 Commit-Queue: Brandon Jones <brandon1.jones@intel.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
80baa39ffc
commit
3a915a67f5
|
@ -272,6 +272,24 @@ namespace dawn_native { namespace d3d12 {
|
|||
return mDepthStencilDescriptor;
|
||||
}
|
||||
|
||||
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE ComputeIndexBufferStripCutValue(
|
||||
wgpu::PrimitiveTopology primitiveTopology,
|
||||
wgpu::IndexFormat indexFormat) {
|
||||
if (primitiveTopology != wgpu::PrimitiveTopology::TriangleStrip &&
|
||||
primitiveTopology != wgpu::PrimitiveTopology::LineStrip) {
|
||||
return D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
|
||||
}
|
||||
|
||||
switch (indexFormat) {
|
||||
case wgpu::IndexFormat::Uint16:
|
||||
return D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
|
||||
case wgpu::IndexFormat::Uint32:
|
||||
return D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
|
||||
case wgpu::IndexFormat::Undefined:
|
||||
return D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ResultOrError<RenderPipeline*> RenderPipeline::Create(
|
||||
|
@ -325,6 +343,9 @@ namespace dawn_native { namespace d3d12 {
|
|||
descriptorD3D12.InputLayout = ComputeInputLayout(&inputElementDescriptors);
|
||||
}
|
||||
|
||||
descriptorD3D12.IBStripCutValue = ComputeIndexBufferStripCutValue(
|
||||
GetPrimitiveTopology(), GetVertexStateDescriptor()->indexFormat);
|
||||
|
||||
descriptorD3D12.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
||||
descriptorD3D12.RasterizerState.CullMode = D3D12CullMode(GetCullMode());
|
||||
descriptorD3D12.RasterizerState.FrontCounterClockwise =
|
||||
|
|
|
@ -115,100 +115,6 @@ TEST_P(IndexFormatTest, Uint16) {
|
|||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 100, 300);
|
||||
}
|
||||
|
||||
// Test for primitive restart use vertices like in the drawing and draw the following
|
||||
// indices: 0 1 2 PRIM_RESTART 3 4 2. Then A and B should be written but not C.
|
||||
// |--------------|
|
||||
// | 0 |
|
||||
// | |\ |
|
||||
// | |B \ |
|
||||
// | 2---1 |
|
||||
// | /| C |
|
||||
// | / A| |
|
||||
// | 4---3 |
|
||||
// |--------------|
|
||||
|
||||
// Test use of primitive restart with an Uint32 index format
|
||||
TEST_P(IndexFormatTest, Uint32PrimitiveRestart) {
|
||||
wgpu::RenderPipeline pipeline = MakeTestPipeline(wgpu::IndexFormat::Uint32);
|
||||
|
||||
wgpu::Buffer vertexBuffer = utils::CreateBufferFromData<float>(
|
||||
device, wgpu::BufferUsage::Vertex,
|
||||
{
|
||||
0.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
|
||||
});
|
||||
wgpu::Buffer indexBuffer =
|
||||
utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::Index,
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
0xFFFFFFFFu,
|
||||
3,
|
||||
4,
|
||||
2,
|
||||
});
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetVertexBuffer(0, vertexBuffer);
|
||||
pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32);
|
||||
pass.DrawIndexed(7);
|
||||
pass.EndPass();
|
||||
}
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 190, 190); // A
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 210, 210); // B
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kZero, renderPass.color, 210, 190); // C
|
||||
}
|
||||
|
||||
// Test use of primitive restart with an Uint16 index format
|
||||
TEST_P(IndexFormatTest, Uint16PrimitiveRestart) {
|
||||
wgpu::RenderPipeline pipeline = MakeTestPipeline(wgpu::IndexFormat::Uint16);
|
||||
|
||||
wgpu::Buffer vertexBuffer = utils::CreateBufferFromData<float>(
|
||||
device, wgpu::BufferUsage::Vertex,
|
||||
{
|
||||
0.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
|
||||
});
|
||||
wgpu::Buffer indexBuffer =
|
||||
utils::CreateBufferFromData<uint16_t>(device, wgpu::BufferUsage::Index,
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
0xFFFFu,
|
||||
3,
|
||||
4,
|
||||
2,
|
||||
// This value is for padding.
|
||||
0xFFFFu,
|
||||
});
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetVertexBuffer(0, vertexBuffer);
|
||||
pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16);
|
||||
pass.DrawIndexed(7);
|
||||
pass.EndPass();
|
||||
}
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 190, 190); // A
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 210, 210); // B
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kZero, renderPass.color, 210, 190); // C
|
||||
}
|
||||
|
||||
// Test that the index format used is the format of the last set pipeline. This is to
|
||||
// prevent a case in D3D12 where the index format would be captured from the last
|
||||
// pipeline on SetIndexBuffer.
|
||||
|
@ -272,8 +178,8 @@ TEST_P(IndexFormatTest, SetIndexBufferBeforeSetPipeline) {
|
|||
// Test that index buffers of multiple formats can be used with a pipeline that
|
||||
// doesn't use strip primitive topology.
|
||||
TEST_P(IndexFormatTest, SetIndexBufferDifferentFormats) {
|
||||
wgpu::RenderPipeline pipeline = MakeTestPipeline(wgpu::IndexFormat::Undefined,
|
||||
wgpu::PrimitiveTopology::TriangleList);
|
||||
wgpu::RenderPipeline pipeline =
|
||||
MakeTestPipeline(wgpu::IndexFormat::Undefined, wgpu::PrimitiveTopology::TriangleList);
|
||||
|
||||
wgpu::Buffer vertexBuffer = utils::CreateBufferFromData<float>(
|
||||
device, wgpu::BufferUsage::Vertex,
|
||||
|
@ -314,8 +220,277 @@ TEST_P(IndexFormatTest, SetIndexBufferDifferentFormats) {
|
|||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 100, 300);
|
||||
}
|
||||
|
||||
// Tests for primitive restart use vertices like in the drawing and draw the following
|
||||
// indices: 0 1 2 PRIM_RESTART 3 4 5. Then A and B should be written but not C.
|
||||
// |--------------|
|
||||
// | 0---1 |
|
||||
// | \ B| |
|
||||
// | \| |
|
||||
// | 3 C 2 |
|
||||
// | |\ |
|
||||
// | |A \ |
|
||||
// | 4---5 |
|
||||
// |--------------|
|
||||
|
||||
class TriangleStripPrimitiveRestartTests : public IndexFormatTest {
|
||||
protected:
|
||||
wgpu::Buffer mVertexBuffer;
|
||||
|
||||
void SetUp() override {
|
||||
IndexFormatTest::SetUp();
|
||||
mVertexBuffer = utils::CreateBufferFromData<float>(device, wgpu::BufferUsage::Vertex,
|
||||
{
|
||||
0.0f, 1.0f, 0.0f, 1.0f, // 0
|
||||
1.0f, 1.0f, 0.0f, 1.0f, // 1
|
||||
1.0f, 0.0f, 0.0f, 1.0f, // 2
|
||||
-1.0f, 0.0f, 0.0f, 1.0f, // 3
|
||||
-1.0f, -1.0f, 0.0f, 1.0f, // 4
|
||||
0.0f, -1.0f, 0.0f, 1.0f, // 5
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Test use of primitive restart with an Uint32 index format
|
||||
TEST_P(TriangleStripPrimitiveRestartTests, Uint32PrimitiveRestart) {
|
||||
wgpu::RenderPipeline pipeline = MakeTestPipeline(wgpu::IndexFormat::Uint32);
|
||||
|
||||
wgpu::Buffer indexBuffer =
|
||||
utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::Index,
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
0xFFFFFFFFu,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
});
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetVertexBuffer(0, mVertexBuffer);
|
||||
pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32);
|
||||
pass.DrawIndexed(7);
|
||||
pass.EndPass();
|
||||
}
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 50, 350); // A
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 350, 50); // B
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kZero, renderPass.color, 198, 200); // C
|
||||
}
|
||||
|
||||
// Same as the above test, but uses an OOB index to emulate primitive restart being disabled,
|
||||
// causing point C to be written to.
|
||||
TEST_P(TriangleStripPrimitiveRestartTests, Uint32WithoutPrimitiveRestart) {
|
||||
// TODO: Re-enable for all backends after robust vertex access is implemented.
|
||||
// The behavior of OOB indexes is not strictly defined on non-D3D12 platforms.
|
||||
DAWN_SKIP_TEST_IF(!IsD3D12());
|
||||
// OOB indexes should return a (0,0,0,1) vertex in D3D12, however this does not occur on Intel
|
||||
// GPUs, so we must skip this test on Intel for now.
|
||||
DAWN_SKIP_TEST_IF(IsIntel() && IsD3D12());
|
||||
|
||||
wgpu::RenderPipeline pipeline = MakeTestPipeline(wgpu::IndexFormat::Uint32);
|
||||
wgpu::Buffer indexBuffer =
|
||||
utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::Index,
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
// Not a valid index.
|
||||
0xFFFFFFFEu,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
});
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetVertexBuffer(0, mVertexBuffer);
|
||||
pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32);
|
||||
pass.DrawIndexed(7);
|
||||
pass.EndPass();
|
||||
}
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 50, 350); // A
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 350, 50); // B
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 198, 200); // C
|
||||
}
|
||||
|
||||
// Test use of primitive restart with an Uint16 index format
|
||||
TEST_P(TriangleStripPrimitiveRestartTests, Uint16PrimitiveRestart) {
|
||||
wgpu::RenderPipeline pipeline = MakeTestPipeline(wgpu::IndexFormat::Uint16);
|
||||
|
||||
wgpu::Buffer indexBuffer =
|
||||
utils::CreateBufferFromData<uint16_t>(device, wgpu::BufferUsage::Index,
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
0xFFFFu,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
// This value is for padding.
|
||||
0xFFFFu,
|
||||
});
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetVertexBuffer(0, mVertexBuffer);
|
||||
pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16);
|
||||
pass.DrawIndexed(7);
|
||||
pass.EndPass();
|
||||
}
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 50, 350); // A
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 350, 50); // B
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kZero, renderPass.color, 198, 200); // C
|
||||
}
|
||||
|
||||
// Tests for primitive restart use vertices like in the drawing and draw the following
|
||||
// indices: 0 1 PRIM_RESTART 2 3. Then 1 and 2 should be written but not A.
|
||||
// |--------------|
|
||||
// | 3 0|
|
||||
// | | ||
|
||||
// | | ||
|
||||
// | 2 A 1|
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// |--------------|
|
||||
|
||||
class LineStripPrimitiveRestartTests : public IndexFormatTest {
|
||||
protected:
|
||||
protected:
|
||||
wgpu::Buffer mVertexBuffer;
|
||||
|
||||
void SetUp() override {
|
||||
IndexFormatTest::SetUp();
|
||||
mVertexBuffer = utils::CreateBufferFromData<float>(device, wgpu::BufferUsage::Vertex,
|
||||
{
|
||||
1.0f, 1.0f, 0.0f, 1.0f, // 0
|
||||
1.0f, 0.0f, 0.0f, 1.0f, // 1
|
||||
0.0f, 0.0f, 0.0f, 1.0f, // 2
|
||||
0.0f, 1.0f, 0.0f, 1.0f // 3
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(LineStripPrimitiveRestartTests, Uint32PrimitiveRestart) {
|
||||
wgpu::RenderPipeline pipeline =
|
||||
MakeTestPipeline(wgpu::IndexFormat::Uint32, wgpu::PrimitiveTopology::LineStrip);
|
||||
|
||||
wgpu::Buffer indexBuffer = utils::CreateBufferFromData<uint32_t>(
|
||||
device, wgpu::BufferUsage::Index, {0, 1, 0xFFFFFFFFu, 2, 3});
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetVertexBuffer(0, mVertexBuffer);
|
||||
pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32);
|
||||
pass.DrawIndexed(5);
|
||||
pass.EndPass();
|
||||
}
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 399, 199); // 1
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 199, 199); // 2
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kZero, renderPass.color, 300, 199); // A
|
||||
}
|
||||
|
||||
// Same as the above test, but uses an OOB index to emulate primitive restart being disabled,
|
||||
// causing point A to be written to.
|
||||
TEST_P(LineStripPrimitiveRestartTests, Uint32WithoutPrimitiveRestart) {
|
||||
// TODO: Re-enable for all backends after robust vertex access is implemented.
|
||||
// The behavior of OOB indexes is not strictly defined on non-D3D12 platforms.
|
||||
DAWN_SKIP_TEST_IF(!IsD3D12());
|
||||
// OOB indexes should return a (0,0,0,1) vertex in D3D12, however this does not occur on Intel
|
||||
// GPUs, so we must skip this test on Intel for now.
|
||||
DAWN_SKIP_TEST_IF(IsIntel() && IsD3D12());
|
||||
|
||||
wgpu::RenderPipeline pipeline =
|
||||
MakeTestPipeline(wgpu::IndexFormat::Uint32, wgpu::PrimitiveTopology::LineStrip);
|
||||
|
||||
wgpu::Buffer indexBuffer =
|
||||
utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::Index,
|
||||
{0, 1, // Not a valid index
|
||||
0xFFFFFFFEu, 2, 3});
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetVertexBuffer(0, mVertexBuffer);
|
||||
pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32);
|
||||
pass.DrawIndexed(5);
|
||||
pass.EndPass();
|
||||
}
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 399, 199); // 1
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 199, 199); // 2
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 300, 199); // A
|
||||
}
|
||||
|
||||
TEST_P(LineStripPrimitiveRestartTests, Uint16PrimitiveRestart) {
|
||||
wgpu::RenderPipeline pipeline =
|
||||
MakeTestPipeline(wgpu::IndexFormat::Uint16, wgpu::PrimitiveTopology::LineStrip);
|
||||
|
||||
wgpu::Buffer indexBuffer =
|
||||
utils::CreateBufferFromData<uint16_t>(device, wgpu::BufferUsage::Index,
|
||||
{0, 1, 0xFFFFu, 2, 3, // This value is for padding.
|
||||
0xFFFFu});
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetVertexBuffer(0, mVertexBuffer);
|
||||
pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16);
|
||||
pass.DrawIndexed(5);
|
||||
pass.EndPass();
|
||||
}
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 399, 199); // 1
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 199, 199); // 2
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kZero, renderPass.color, 300, 199); // A
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(IndexFormatTest,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
OpenGLBackend(),
|
||||
VulkanBackend());
|
||||
DAWN_INSTANTIATE_TEST(TriangleStripPrimitiveRestartTests,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
OpenGLBackend(),
|
||||
VulkanBackend());
|
||||
DAWN_INSTANTIATE_TEST(LineStripPrimitiveRestartTests,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
OpenGLBackend(),
|
||||
VulkanBackend());
|
Loading…
Reference in New Issue