mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-10 15:15:58 +00:00
Add AlignTo method to make a Blob's contents aligned
After loading a Blob from the cache, Dawn may need it to match a particular alignment. For example, SPIRV must be 4-byte aligned, or Dawn may need to cast a Blob to a struct layout. Bug: dawn:549 Change-Id: Iad4857d1ad2d9b41e61e9f177aa7083b1f078be5 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94532 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Loko Kung <lokokung@google.com> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
d69c5d2d1c
commit
245e91d42e
@ -15,14 +15,24 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "dawn/common/Assert.h"
|
#include "dawn/common/Assert.h"
|
||||||
|
#include "dawn/common/Math.h"
|
||||||
#include "dawn/native/Blob.h"
|
#include "dawn/native/Blob.h"
|
||||||
|
|
||||||
namespace dawn::native {
|
namespace dawn::native {
|
||||||
|
|
||||||
Blob CreateBlob(size_t size) {
|
Blob CreateBlob(size_t size, size_t alignment) {
|
||||||
|
ASSERT(IsPowerOfTwo(alignment));
|
||||||
|
ASSERT(alignment != 0);
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
uint8_t* data = new uint8_t[size];
|
// Allocate extra space so that there will be sufficient space for |size| even after
|
||||||
return Blob::UnsafeCreateWithDeleter(data, size, [=]() { delete[] data; });
|
// the |data| pointer is aligned.
|
||||||
|
// TODO(crbug.com/dawn/824): Use aligned_alloc when possible. It should be available
|
||||||
|
// with C++17 but on macOS it also requires macOS 10.15 to work.
|
||||||
|
size_t allocatedSize = size + alignment - 1;
|
||||||
|
uint8_t* data = new uint8_t[allocatedSize];
|
||||||
|
uint8_t* ptr = AlignPtr(data, alignment);
|
||||||
|
ASSERT(ptr + size <= data + allocatedSize);
|
||||||
|
return Blob::UnsafeCreateWithDeleter(ptr, size, [=]() { delete[] data; });
|
||||||
} else {
|
} else {
|
||||||
return Blob();
|
return Blob();
|
||||||
}
|
}
|
||||||
@ -77,4 +87,14 @@ size_t Blob::Size() const {
|
|||||||
return mSize;
|
return mSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Blob::AlignTo(size_t alignment) {
|
||||||
|
if (IsPtrAligned(mData, alignment)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Blob blob = CreateBlob(mSize, alignment);
|
||||||
|
memcpy(blob.Data(), mData, mSize);
|
||||||
|
*this = std::move(blob);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dawn::native
|
} // namespace dawn::native
|
||||||
|
@ -43,6 +43,10 @@ class Blob {
|
|||||||
uint8_t* Data();
|
uint8_t* Data();
|
||||||
size_t Size() const;
|
size_t Size() const;
|
||||||
|
|
||||||
|
// If the blob data is not aligned to |alignment|, copy it into a new backing store which
|
||||||
|
// is aligned.
|
||||||
|
void AlignTo(size_t alignment);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The constructor should be responsible to take ownership of |data| and releases ownership by
|
// The constructor should be responsible to take ownership of |data| and releases ownership by
|
||||||
// calling |deleter|. The deleter function is called at ~Blob() and during std::move.
|
// calling |deleter|. The deleter function is called at ~Blob() and during std::move.
|
||||||
@ -53,7 +57,7 @@ class Blob {
|
|||||||
std::function<void()> mDeleter;
|
std::function<void()> mDeleter;
|
||||||
};
|
};
|
||||||
|
|
||||||
Blob CreateBlob(size_t size);
|
Blob CreateBlob(size_t size, size_t alignment = 1);
|
||||||
|
|
||||||
} // namespace dawn::native
|
} // namespace dawn::native
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "dawn/common/Math.h"
|
||||||
#include "dawn/native/Blob.h"
|
#include "dawn/native/Blob.h"
|
||||||
#include "gmock/gmock.h"
|
#include "gmock/gmock.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
@ -163,6 +164,61 @@ TEST(BlobTests, MoveAssignOver) {
|
|||||||
EXPECT_EQ(memcmp(b2.Data(), data, sizeof(data)), 0);
|
EXPECT_EQ(memcmp(b2.Data(), data, sizeof(data)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that an empty blob can be requested to have a particular alignment.
|
||||||
|
TEST(BlobTests, EmptyAlignTo) {
|
||||||
|
for (size_t alignment : {1, 2, 4, 8, 16, 32}) {
|
||||||
|
Blob b;
|
||||||
|
EXPECT_TRUE(b.Empty());
|
||||||
|
EXPECT_EQ(b.Size(), 0u);
|
||||||
|
EXPECT_EQ(b.Data(), nullptr);
|
||||||
|
b.AlignTo(alignment);
|
||||||
|
// After aligning, it is still empty.
|
||||||
|
EXPECT_TRUE(b.Empty());
|
||||||
|
EXPECT_EQ(b.Size(), 0u);
|
||||||
|
EXPECT_EQ(b.Data(), nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that AlignTo makes a blob have a particular alignment.
|
||||||
|
TEST(BlobTests, AlignTo) {
|
||||||
|
uint8_t data[64];
|
||||||
|
for (uint8_t i = 0; i < sizeof(data); ++i) {
|
||||||
|
data[i] = i;
|
||||||
|
}
|
||||||
|
// Test multiple alignments.
|
||||||
|
for (size_t alignment : {1, 2, 4, 8, 16, 32}) {
|
||||||
|
for (size_t offset = 0; offset < alignment; ++offset) {
|
||||||
|
// Make a blob pointing to |data| starting at |offset|.
|
||||||
|
size_t size = sizeof(data) - offset;
|
||||||
|
testing::StrictMock<testing::MockFunction<void()>> mockDeleter;
|
||||||
|
Blob b =
|
||||||
|
Blob::UnsafeCreateWithDeleter(&data[offset], size, [&]() { mockDeleter.Call(); });
|
||||||
|
bool alreadyAligned = IsPtrAligned(&data[offset], alignment);
|
||||||
|
|
||||||
|
// The backing store should be deleted at the end of the scope, or because it was
|
||||||
|
// replaced.
|
||||||
|
EXPECT_CALL(mockDeleter, Call());
|
||||||
|
|
||||||
|
b.AlignTo(alignment);
|
||||||
|
if (!alreadyAligned) {
|
||||||
|
// If the Blob is not aligned, its data will be deleted and replaced by AlignTo.
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&mockDeleter);
|
||||||
|
}
|
||||||
|
// The blob should not have changed in size.
|
||||||
|
EXPECT_EQ(b.Size(), size) << "alignment = " << alignment << " offset = " << offset;
|
||||||
|
// The data should be aligned.
|
||||||
|
EXPECT_TRUE(IsPtrAligned(b.Data(), alignment))
|
||||||
|
<< "alignment = " << alignment << " offset = " << offset;
|
||||||
|
// The contents should be the same.
|
||||||
|
EXPECT_EQ(memcmp(b.Data(), &data[offset], size), 0)
|
||||||
|
<< "alignment = " << alignment << " offset = " << offset;
|
||||||
|
// If the data was already aligned, the blob should point to the same memory.
|
||||||
|
EXPECT_EQ(alreadyAligned, b.Data() == &data[offset])
|
||||||
|
<< "alignment = " << alignment << " offset = " << offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
} // namespace dawn::native
|
} // namespace dawn::native
|
||||||
|
Loading…
x
Reference in New Issue
Block a user