Reland "Destroy backend implementation for Buffers"

This reverts commit 9bf529ec94.

Reason for revert:
Fixed test failure by submitting basic render pass to clear out texture
before running the tests.

The test was failing previously because the texture pixel color was not
cleared before running the tests, causing unexpected
pixel colors to be compared. Creating a basic render pass clears
the texture, but since the first test fails on submit expectedly,
the pixel is never cleared.

Bug: dawn:46
Change-Id: Ic190c2d8d6af3f9d8def3370b92c6974a82a0096
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/5500
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Natasha Lee <natlee@microsoft.com>
This commit is contained in:
Natasha Lee 2019-03-11 17:05:22 +00:00 committed by Commit Bot service account
parent 45f9730855
commit 718e1dbb89
14 changed files with 184 additions and 11 deletions

View File

@ -645,6 +645,7 @@ test("dawn_end2end_tests") {
"src/tests/end2end/CopyTests.cpp", "src/tests/end2end/CopyTests.cpp",
"src/tests/end2end/DebugMarkerTests.cpp", "src/tests/end2end/DebugMarkerTests.cpp",
"src/tests/end2end/DepthStencilStateTests.cpp", "src/tests/end2end/DepthStencilStateTests.cpp",
"src/tests/end2end/DestroyBufferTests.cpp",
"src/tests/end2end/DrawIndexedTests.cpp", "src/tests/end2end/DrawIndexedTests.cpp",
"src/tests/end2end/DrawTests.cpp", "src/tests/end2end/DrawTests.cpp",
"src/tests/end2end/FenceTests.cpp", "src/tests/end2end/FenceTests.cpp",

View File

@ -47,6 +47,9 @@ namespace dawn_native {
void UnmapImpl() override { void UnmapImpl() override {
UNREACHABLE(); UNREACHABLE();
} }
void DestroyImpl() override {
UNREACHABLE();
}
}; };
} // anonymous namespace } // anonymous namespace
@ -232,6 +235,7 @@ namespace dawn_native {
if (mState == BufferState::Mapped) { if (mState == BufferState::Mapped) {
Unmap(); Unmap();
} }
DestroyImpl();
mState = BufferState::Destroyed; mState = BufferState::Destroyed;
} }

View File

@ -76,6 +76,7 @@ namespace dawn_native {
virtual void MapReadAsyncImpl(uint32_t serial) = 0; virtual void MapReadAsyncImpl(uint32_t serial) = 0;
virtual void MapWriteAsyncImpl(uint32_t serial) = 0; virtual void MapWriteAsyncImpl(uint32_t serial) = 0;
virtual void UnmapImpl() = 0; virtual void UnmapImpl() = 0;
virtual void DestroyImpl() = 0;
MaybeError ValidateSetSubData(uint32_t start, uint32_t count) const; MaybeError ValidateSetSubData(uint32_t start, uint32_t count) const;
MaybeError ValidateMap(dawn::BufferUsageBit requiredUsage) const; MaybeError ValidateMap(dawn::BufferUsageBit requiredUsage) const;

View File

@ -105,7 +105,7 @@ namespace dawn_native { namespace d3d12 {
} }
Buffer::~Buffer() { Buffer::~Buffer() {
ToBackend(GetDevice())->GetResourceAllocator()->Release(mResource); DestroyImpl();
} }
uint32_t Buffer::GetD3D12Size() const { uint32_t Buffer::GetD3D12Size() const {
@ -189,6 +189,11 @@ namespace dawn_native { namespace d3d12 {
mWrittenMappedRange = {}; mWrittenMappedRange = {};
} }
void Buffer::DestroyImpl() {
ToBackend(GetDevice())->GetResourceAllocator()->Release(mResource);
mResource = nullptr;
}
MapRequestTracker::MapRequestTracker(Device* device) : mDevice(device) { MapRequestTracker::MapRequestTracker(Device* device) : mDevice(device) {
} }

View File

@ -42,6 +42,7 @@ namespace dawn_native { namespace d3d12 {
void MapReadAsyncImpl(uint32_t serial) override; void MapReadAsyncImpl(uint32_t serial) override;
void MapWriteAsyncImpl(uint32_t serial) override; void MapWriteAsyncImpl(uint32_t serial) override;
void UnmapImpl() override; void UnmapImpl() override;
void DestroyImpl() override;
ComPtr<ID3D12Resource> mResource; ComPtr<ID3D12Resource> mResource;
bool mFixedResourceState = false; bool mFixedResourceState = false;

View File

@ -37,6 +37,7 @@ namespace dawn_native { namespace metal {
void MapReadAsyncImpl(uint32_t serial) override; void MapReadAsyncImpl(uint32_t serial) override;
void MapWriteAsyncImpl(uint32_t serial) override; void MapWriteAsyncImpl(uint32_t serial) override;
void UnmapImpl() override; void UnmapImpl() override;
void DestroyImpl() override;
id<MTLBuffer> mMtlBuffer = nil; id<MTLBuffer> mMtlBuffer = nil;
}; };

View File

@ -31,8 +31,7 @@ namespace dawn_native { namespace metal {
} }
Buffer::~Buffer() { Buffer::~Buffer() {
[mMtlBuffer release]; DestroyImpl();
mMtlBuffer = nil;
} }
id<MTLBuffer> Buffer::GetMTLBuffer() { id<MTLBuffer> Buffer::GetMTLBuffer() {
@ -62,6 +61,11 @@ namespace dawn_native { namespace metal {
// Nothing to do, Metal StorageModeShared buffers are always mapped. // Nothing to do, Metal StorageModeShared buffers are always mapped.
} }
void Buffer::DestroyImpl() {
[mMtlBuffer release];
mMtlBuffer = nil;
}
MapRequestTracker::MapRequestTracker(Device* device) : mDevice(device) { MapRequestTracker::MapRequestTracker(Device* device) : mDevice(device) {
} }

View File

@ -226,6 +226,9 @@ namespace dawn_native { namespace null {
void Buffer::UnmapImpl() { void Buffer::UnmapImpl() {
} }
void Buffer::DestroyImpl() {
}
// CommandBuffer // CommandBuffer
CommandBuffer::CommandBuffer(Device* device, CommandEncoderBase* encoder) CommandBuffer::CommandBuffer(Device* device, CommandEncoderBase* encoder)

View File

@ -146,6 +146,7 @@ namespace dawn_native { namespace null {
void MapReadAsyncImpl(uint32_t serial) override; void MapReadAsyncImpl(uint32_t serial) override;
void MapWriteAsyncImpl(uint32_t serial) override; void MapWriteAsyncImpl(uint32_t serial) override;
void UnmapImpl() override; void UnmapImpl() override;
void DestroyImpl() override;
void MapAsyncImplCommon(uint32_t serial, bool isWrite); void MapAsyncImplCommon(uint32_t serial, bool isWrite);

View File

@ -27,6 +27,10 @@ namespace dawn_native { namespace opengl {
glBufferData(GL_ARRAY_BUFFER, GetSize(), nullptr, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, GetSize(), nullptr, GL_STATIC_DRAW);
} }
Buffer::~Buffer() {
DestroyImpl();
}
GLuint Buffer::GetHandle() const { GLuint Buffer::GetHandle() const {
return mBuffer; return mBuffer;
} }
@ -58,4 +62,9 @@ namespace dawn_native { namespace opengl {
glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ARRAY_BUFFER);
} }
void Buffer::DestroyImpl() {
glDeleteBuffers(1, &mBuffer);
mBuffer = 0;
}
}} // namespace dawn_native::opengl }} // namespace dawn_native::opengl

View File

@ -26,6 +26,7 @@ namespace dawn_native { namespace opengl {
class Buffer : public BufferBase { class Buffer : public BufferBase {
public: public:
Buffer(Device* device, const BufferDescriptor* descriptor); Buffer(Device* device, const BufferDescriptor* descriptor);
~Buffer();
GLuint GetHandle() const; GLuint GetHandle() const;
@ -34,6 +35,7 @@ namespace dawn_native { namespace opengl {
void MapReadAsyncImpl(uint32_t serial) override; void MapReadAsyncImpl(uint32_t serial) override;
void MapWriteAsyncImpl(uint32_t serial) override; void MapWriteAsyncImpl(uint32_t serial) override;
void UnmapImpl() override; void UnmapImpl() override;
void DestroyImpl() override;
GLuint mBuffer = 0; GLuint mBuffer = 0;
}; };

View File

@ -137,14 +137,7 @@ namespace dawn_native { namespace vulkan {
} }
Buffer::~Buffer() { Buffer::~Buffer() {
Device* device = ToBackend(GetDevice()); DestroyImpl();
device->GetMemoryAllocator()->Free(&mMemoryAllocation);
if (mHandle != VK_NULL_HANDLE) {
device->GetFencedDeleter()->DeleteWhenUnused(mHandle);
mHandle = VK_NULL_HANDLE;
}
} }
void Buffer::OnMapReadCommandSerialFinished(uint32_t mapSerial, const void* data) { void Buffer::OnMapReadCommandSerialFinished(uint32_t mapSerial, const void* data) {
@ -225,6 +218,15 @@ namespace dawn_native { namespace vulkan {
// No need to do anything, we keep CPU-visible memory mapped at all time. // No need to do anything, we keep CPU-visible memory mapped at all time.
} }
void Buffer::DestroyImpl() {
ToBackend(GetDevice())->GetMemoryAllocator()->Free(&mMemoryAllocation);
if (mHandle != VK_NULL_HANDLE) {
ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(mHandle);
mHandle = VK_NULL_HANDLE;
}
}
// MapRequestTracker // MapRequestTracker
MapRequestTracker::MapRequestTracker(Device* device) : mDevice(device) { MapRequestTracker::MapRequestTracker(Device* device) : mDevice(device) {

View File

@ -44,6 +44,7 @@ namespace dawn_native { namespace vulkan {
void MapReadAsyncImpl(uint32_t serial) override; void MapReadAsyncImpl(uint32_t serial) override;
void MapWriteAsyncImpl(uint32_t serial) override; void MapWriteAsyncImpl(uint32_t serial) override;
void UnmapImpl() override; void UnmapImpl() override;
void DestroyImpl() override;
VkBuffer mHandle = VK_NULL_HANDLE; VkBuffer mHandle = VK_NULL_HANDLE;
DeviceMemoryAllocation mMemoryAllocation; DeviceMemoryAllocation mMemoryAllocation;

View File

@ -0,0 +1,138 @@
// Copyright 2019 The Dawn 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/DawnTest.h"
#include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/DawnHelpers.h"
constexpr uint32_t kRTSize = 4;
class DestroyBufferTest : public DawnTest {
protected:
void SetUp() override {
DawnTest::SetUp();
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
dawn::VertexInputDescriptor input;
input.inputSlot = 0;
input.stride = 4 * sizeof(float);
input.stepMode = dawn::InputStepMode::Vertex;
dawn::VertexAttributeDescriptor attribute;
attribute.shaderLocation = 0;
attribute.inputSlot = 0;
attribute.offset = 0;
attribute.format = dawn::VertexFormat::FloatR32G32B32A32;
dawn::InputState inputState =
device.CreateInputStateBuilder().SetInput(&input).SetAttribute(&attribute).GetResult();
dawn::ShaderModule vsModule =
utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
#version 450
layout(location = 0) in vec4 pos;
void main() {
gl_Position = pos;
})");
dawn::ShaderModule fsModule =
utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
#version 450
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
})");
utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.cVertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule;
descriptor.primitiveTopology = dawn::PrimitiveTopology::TriangleStrip;
descriptor.indexFormat = dawn::IndexFormat::Uint32;
descriptor.inputState = inputState;
descriptor.cColorStates[0]->format = renderPass.colorFormat;
pipeline = device.CreateRenderPipeline(&descriptor);
vertexBuffer = utils::CreateBufferFromData<float>(
device, dawn::BufferUsageBit::Vertex,
{// The bottom left triangle
-1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f});
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.BeginRenderPass(&renderPass.renderPassInfo).EndPass();
dawn::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
}
utils::BasicRenderPass renderPass;
dawn::RenderPipeline pipeline;
dawn::Buffer vertexBuffer;
dawn::CommandBuffer CreateTriangleCommandBuffer() {
uint32_t zeroOffset = 0;
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
{
dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
pass.SetPipeline(pipeline);
pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
pass.Draw(3, 1, 0, 0);
pass.EndPass();
}
dawn::CommandBuffer commands = encoder.Finish();
return commands;
}
};
// Destroy before submit will result in error, and nothing drawn
TEST_P(DestroyBufferTest, DestroyBeforeSubmit) {
RGBA8 notFilled(0, 0, 0, 0);
dawn::CommandBuffer commands = CreateTriangleCommandBuffer();
vertexBuffer.Destroy();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, 1, 3);
}
// Destroy after submit will draw successfully
TEST_P(DestroyBufferTest, DestroyAfterSubmit) {
RGBA8 filled(0, 255, 0, 255);
dawn::CommandBuffer commands = CreateTriangleCommandBuffer();
queue.Submit(1, &commands);
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, 1, 3);
vertexBuffer.Destroy();
}
// First submit succeeds, draws triangle, second submit fails
// after destroy is called on the buffer, pixel does not change
TEST_P(DestroyBufferTest, SubmitDestroySubmit) {
RGBA8 filled(0, 255, 0, 255);
dawn::CommandBuffer commands = CreateTriangleCommandBuffer();
queue.Submit(1, &commands);
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, 1, 3);
vertexBuffer.Destroy();
// Submit fails because vertex buffer was destroyed
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
// Pixel stays the same
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, 1, 3);
}
DAWN_INSTANTIATE_TEST(DestroyBufferTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend);