mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-09-17 08:39:56 +00:00
Fix a DrawElements bug in the Metal backend.
The indexOffset of the draw was not being used. It must be included in the indexBufferOffset. Renamed indexBufferOffset -> indexBufferBaseOffset. Add a DrawElements test which exercises zero and non-zero index offsets.
This commit is contained in:
parent
a5aacc9cad
commit
8c231b6990
@ -167,7 +167,7 @@ namespace backend { namespace metal {
|
||||
ComputePipeline* lastComputePipeline = nullptr;
|
||||
RenderPipeline* lastRenderPipeline = nullptr;
|
||||
id<MTLBuffer> indexBuffer = nil;
|
||||
uint32_t indexBufferOffset = 0;
|
||||
uint32_t indexBufferBaseOffset = 0;
|
||||
|
||||
CurrentEncoders encoders;
|
||||
encoders.device = mDevice;
|
||||
@ -304,6 +304,7 @@ namespace backend { namespace metal {
|
||||
|
||||
case Command::DrawElements: {
|
||||
DrawElementsCmd* draw = mCommands.NextCommand<DrawElementsCmd>();
|
||||
size_t formatSize = IndexFormatSize(lastRenderPipeline->GetIndexFormat());
|
||||
|
||||
ASSERT(encoders.render);
|
||||
[encoders.render
|
||||
@ -311,7 +312,7 @@ namespace backend { namespace metal {
|
||||
indexCount:draw->indexCount
|
||||
indexType:lastRenderPipeline->GetMTLIndexType()
|
||||
indexBuffer:indexBuffer
|
||||
indexBufferOffset:indexBufferOffset
|
||||
indexBufferOffset:indexBufferBaseOffset + draw->firstIndex * formatSize
|
||||
instanceCount:draw->instanceCount
|
||||
baseVertex:0
|
||||
baseInstance:draw->firstInstance];
|
||||
@ -526,7 +527,7 @@ namespace backend { namespace metal {
|
||||
SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>();
|
||||
auto b = ToBackend(cmd->buffer.Get());
|
||||
indexBuffer = b->GetMTLBuffer();
|
||||
indexBufferOffset = cmd->offset;
|
||||
indexBufferBaseOffset = cmd->offset;
|
||||
} break;
|
||||
|
||||
case Command::SetVertexBuffers: {
|
||||
|
@ -243,7 +243,7 @@ namespace backend { namespace opengl {
|
||||
PipelineBase* lastPipeline = nullptr;
|
||||
PipelineGL* lastGLPipeline = nullptr;
|
||||
RenderPipeline* lastRenderPipeline = nullptr;
|
||||
uint32_t indexBufferOffset = 0;
|
||||
uint32_t indexBufferBaseOffset = 0;
|
||||
|
||||
PersistentPipelineState persistentPipelineState;
|
||||
persistentPipelineState.SetDefaultState();
|
||||
@ -505,7 +505,7 @@ namespace backend { namespace opengl {
|
||||
lastRenderPipeline->GetGLPrimitiveTopology(), draw->indexCount,
|
||||
formatType,
|
||||
reinterpret_cast<void*>(draw->firstIndex * formatSize +
|
||||
indexBufferOffset),
|
||||
indexBufferBaseOffset),
|
||||
draw->instanceCount, draw->firstInstance);
|
||||
} else {
|
||||
// This branch is only needed on OpenGL < 4.2
|
||||
@ -513,7 +513,7 @@ namespace backend { namespace opengl {
|
||||
lastRenderPipeline->GetGLPrimitiveTopology(), draw->indexCount,
|
||||
formatType,
|
||||
reinterpret_cast<void*>(draw->firstIndex * formatSize +
|
||||
indexBufferOffset),
|
||||
indexBufferBaseOffset),
|
||||
draw->instanceCount);
|
||||
}
|
||||
} break;
|
||||
@ -635,7 +635,7 @@ namespace backend { namespace opengl {
|
||||
|
||||
case Command::SetIndexBuffer: {
|
||||
SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>();
|
||||
indexBufferOffset = cmd->offset;
|
||||
indexBufferBaseOffset = cmd->offset;
|
||||
inputBuffers.OnSetIndexBuffer(cmd->buffer.Get());
|
||||
} break;
|
||||
|
||||
|
@ -75,6 +75,7 @@ add_executable(nxt_end2end_tests
|
||||
${END2END_TESTS_DIR}/BufferTests.cpp
|
||||
${END2END_TESTS_DIR}/BlendStateTests.cpp
|
||||
${END2END_TESTS_DIR}/CopyTests.cpp
|
||||
${END2END_TESTS_DIR}/DrawElementsTests.cpp
|
||||
${END2END_TESTS_DIR}/DepthStencilStateTests.cpp
|
||||
${END2END_TESTS_DIR}/IndexFormatTests.cpp
|
||||
${END2END_TESTS_DIR}/InputStateTests.cpp
|
||||
|
137
src/tests/end2end/DrawElementsTests.cpp
Normal file
137
src/tests/end2end/DrawElementsTests.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
// 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/NXTTest.h"
|
||||
|
||||
#include "utils/NXTHelpers.h"
|
||||
|
||||
constexpr uint32_t kRTSize = 4;
|
||||
|
||||
class DrawElementsTest : public NXTTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
NXTTest::SetUp();
|
||||
|
||||
renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
renderTarget = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(kRTSize, kRTSize, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment | nxt::TextureUsageBit::TransferSrc)
|
||||
.SetInitialUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
|
||||
renderTargetView = renderTarget.CreateTextureViewBuilder().GetResult();
|
||||
|
||||
framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.SetDimensions(kRTSize, kRTSize)
|
||||
.GetResult();
|
||||
|
||||
nxt::InputState inputState = device.CreateInputStateBuilder()
|
||||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||
.SetAttribute(0, 0, nxt::VertexFormat::FloatR32G32B32A32, 0)
|
||||
.GetResult();
|
||||
|
||||
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
layout(location = 0) in vec4 pos;
|
||||
void main() {
|
||||
gl_Position = pos;
|
||||
})"
|
||||
);
|
||||
|
||||
nxt::ShaderModule fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
|
||||
#version 450
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
})"
|
||||
);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleStrip)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetIndexFormat(nxt::IndexFormat::Uint32)
|
||||
.SetInputState(inputState)
|
||||
.GetResult();
|
||||
|
||||
vertexBuffer = utils::CreateFrozenBufferFromData<float>(device, nxt::BufferUsageBit::Vertex, {
|
||||
-1.0f, -1.0f, 0.0f, 1.0f,
|
||||
1.0f, 1.0f, 0.0f, 1.0f,
|
||||
-1.0f, 1.0f, 0.0f, 1.0f,
|
||||
1.0f, -1.0f, 0.0f, 1.0f
|
||||
});
|
||||
indexBuffer = utils::CreateFrozenBufferFromData<uint32_t>(device, nxt::BufferUsageBit::Index, {
|
||||
0, 1, 2, 0, 3, 1
|
||||
});
|
||||
}
|
||||
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Texture renderTarget;
|
||||
nxt::TextureView renderTargetView;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::Buffer vertexBuffer;
|
||||
nxt::Buffer indexBuffer;
|
||||
|
||||
void Test(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex,
|
||||
uint32_t firstInstance, RGBA8 bottomLeftExpected, RGBA8 topRightExpected) {
|
||||
uint32_t zeroOffset = 0;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
|
||||
.SetIndexBuffer(indexBuffer, 0)
|
||||
.DrawElements(indexCount, instanceCount, firstIndex, firstInstance)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(bottomLeftExpected, renderTarget, 1, 3);
|
||||
EXPECT_PIXEL_RGBA8_EQ(topRightExpected, renderTarget, 3, 1);
|
||||
}
|
||||
};
|
||||
|
||||
// The most basic DrawElements triangle draw.
|
||||
TEST_P(DrawElementsTest, Uint32) {
|
||||
|
||||
RGBA8 filled(0, 255, 0, 255);
|
||||
RGBA8 notFilled(0, 0, 0, 0);
|
||||
|
||||
// Test a draw with no indices.
|
||||
Test(0, 0, 0, 0, notFilled, notFilled);
|
||||
// Test a draw with only the first 3 indices (bottom left triangle)
|
||||
Test(3, 1, 0, 0, filled, notFilled);
|
||||
// Test a draw with only the last 3 indices (top right triangle)
|
||||
Test(3, 1, 3, 0, notFilled, filled);
|
||||
// Test a draw with all 6 indices (both triangles).
|
||||
Test(6, 1, 0, 0, filled, filled);
|
||||
}
|
||||
|
||||
NXT_INSTANTIATE_TEST(DrawElementsTest, MetalBackend, OpenGLBackend, D3D12Backend, VulkanBackend)
|
Loading…
x
Reference in New Issue
Block a user