Wire up texture creation from buffers.

This commit is contained in:
Chinmay Garde 2021-07-05 14:37:11 -07:00 committed by Dan Field
parent ffe1fc656e
commit ec3d9f6060
11 changed files with 164 additions and 19 deletions

View File

@ -27,8 +27,8 @@ executable("impeller_unittests") {
"compositor:compositor_unittests",
"entity:entity_unittests",
"fixtures",
"geometry:geometry_unittests",
"playground",
"primitives:primitives_unittests",
"//flutter/testing",
]
}

View File

@ -76,10 +76,14 @@ impeller_component("compositor") {
source_set("compositor_unittests") {
testonly = true
sources = [ "host_buffer_unittests.mm" ]
sources = [
"device_buffer_unittests.mm",
"host_buffer_unittests.mm",
]
deps = [
":compositor",
"../playground",
"//flutter/testing:testing_lib",
]
}

View File

@ -14,6 +14,7 @@
#include "impeller/compositor/buffer.h"
#include "impeller/compositor/buffer_view.h"
#include "impeller/compositor/range.h"
#include "impeller/compositor/texture.h"
namespace impeller {
@ -26,6 +27,9 @@ class DeviceBuffer final : public Buffer,
Range source_range,
size_t offset = 0u);
std::shared_ptr<Texture> MakeTexture(TextureDescriptor desc,
size_t offset = 0u) const;
id<MTLBuffer> GetMTLBuffer() const;
bool SetLabel(const std::string& label);

View File

@ -4,7 +4,8 @@
#include "impeller/compositor/device_buffer.h"
#include <Foundation/Foundation.h>
#include "flutter/fml/logging.h"
#include "impeller/compositor/formats_metal.h"
namespace impeller {
@ -17,6 +18,34 @@ id<MTLBuffer> DeviceBuffer::GetMTLBuffer() const {
return buffer_;
}
std::shared_ptr<Texture> DeviceBuffer::MakeTexture(TextureDescriptor desc,
size_t offset) const {
if (!desc.IsValid() || !buffer_) {
return nullptr;
}
// Avoid overruns.
if (offset + desc.GetSizeOfBaseMipLevel() > size_) {
FML_DLOG(ERROR) << "Avoiding buffer overrun when creating texture.";
return nullptr;
}
auto mtl_desc = [[MTLTextureDescriptor alloc] init];
mtl_desc.pixelFormat = ToMTLPixelFormat(desc.format);
mtl_desc.width = desc.size.width;
mtl_desc.height = desc.size.height;
mtl_desc.mipmapLevelCount = desc.mip_count;
auto texture = [buffer_ newTextureWithDescriptor:mtl_desc
offset:offset
bytesPerRow:desc.GetBytesPerRow()];
if (!texture) {
return nullptr;
}
return std::make_shared<Texture>(texture);
}
[[nodiscard]] bool DeviceBuffer::CopyHostBuffer(const uint8_t* source,
Range source_range,
size_t offset) {

View File

@ -0,0 +1,15 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/testing/testing.h"
#include "impeller/compositor/device_buffer.h"
#include "impeller/playground/playground.h"
namespace impeller {
namespace testing {
using DeviceBufferTest = Playground;
} // namespace testing
} // namespace impeller

View File

@ -93,6 +93,23 @@ enum class ColorWriteMask : uint64_t {
kAll = kRed | kGreen | kBlue,
};
constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format) {
switch (format) {
case PixelFormat::kUnknown:
return 0u;
case PixelFormat::kPixelFormat_B8G8R8A8_UNormInt:
return 4u;
case PixelFormat::kPixelFormat_B8G8R8A8_UNormInt_SRGB:
return 4u;
case PixelFormat::kPixelFormat_D32_Float_S8_UNormInt:
// This is an esoteric format and implementations may use 64 bits.
// Impeller doesn't work with these natively and this return is only here
// for completeness. The 40 bits is as documented.
return 5u;
}
return 0u;
}
struct ColorAttachmentDescriptor {
PixelFormat format = PixelFormat::kUnknown;
bool blending_enabled = false;

View File

@ -7,10 +7,38 @@
#include <Metal/Metal.h>
#include "flutter/fml/macros.h"
#include "impeller/compositor/formats.h"
#include "impeller/geometry/size.h"
namespace impeller {
struct TextureDescriptor {
PixelFormat format = PixelFormat::kUnknown;
ISize size;
size_t mip_count = 1u; // Size::MipCount is usually appropriate.
constexpr size_t GetSizeOfBaseMipLevel() const {
if (!IsValid()) {
return 0u;
}
return size.Area() * BytesPerPixelForPixelFormat(format);
}
constexpr size_t GetBytesPerRow() const {
if (!IsValid()) {
return 0u;
}
return size.width * BytesPerPixelForPixelFormat(format);
}
bool IsValid() const {
return format != PixelFormat::kUnknown && //
size.IsPositive() && //
mip_count >= 1u //
;
}
};
class Texture {
public:
Texture(id<MTLTexture> texture);

View File

@ -31,3 +31,12 @@ impeller_component("geometry") {
"vector.h",
]
}
impeller_component("geometry_unittests") {
testonly = true
sources = [ "geometry_unittests.cc" ]
deps = [
":geometry",
"//flutter/testing",
]
}

View File

@ -0,0 +1,23 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/testing/testing.h"
#include "impeller/geometry/size.h"
namespace impeller {
namespace testing {
TEST(GeometryTest, CanGenerateMipCounts) {
ASSERT_EQ((Size{128, 128}.MipCount()), 7u);
ASSERT_EQ((Size{128, 256}.MipCount()), 8u);
ASSERT_EQ((Size{128, 130}.MipCount()), 8u);
ASSERT_EQ((Size{128, 257}.MipCount()), 9u);
ASSERT_EQ((Size{257, 128}.MipCount()), 9u);
ASSERT_EQ((Size{128, 0}.MipCount()), 1u);
ASSERT_EQ((Size{128, -25}.MipCount()), 1u);
ASSERT_EQ((Size{-128, 25}.MipCount()), 1u);
}
} // namespace testing
} // namespace impeller

View File

@ -4,6 +4,7 @@
#pragma once
#include <cmath>
#include <limits>
#include <string>
@ -11,60 +12,75 @@
namespace impeller {
struct Size {
Scalar width = 0.0;
Scalar height = 0.0;
template <class T>
struct TSize {
using Type = T;
constexpr Size() {}
Type width = {};
Type height = {};
constexpr Size(Scalar width, Scalar height) : width(width), height(height) {}
constexpr TSize() {}
static constexpr Size Infinite() {
return Size{std::numeric_limits<Scalar>::max(),
std::numeric_limits<Scalar>::max()};
constexpr TSize(Type width, Type height) : width(width), height(height) {}
static constexpr TSize Infinite() {
return TSize{std::numeric_limits<Type>::max(),
std::numeric_limits<Type>::max()};
}
constexpr Size operator*(Scalar scale) const {
constexpr TSize operator*(Type scale) const {
return {width * scale, height * scale};
}
constexpr bool operator==(const Size& s) const {
constexpr bool operator==(const TSize& s) const {
return s.width == width && s.height == height;
}
constexpr bool operator!=(const Size& s) const {
constexpr bool operator!=(const TSize& s) const {
return s.width != width || s.height != height;
}
constexpr Size operator+(const Size& s) const {
constexpr TSize operator+(const TSize& s) const {
return {width + s.width, height + s.height};
}
constexpr Size operator-(const Size& s) const {
constexpr TSize operator-(const TSize& s) const {
return {width - s.width, height - s.height};
}
constexpr Size Union(const Size& o) const {
constexpr TSize Union(const TSize& o) const {
return {
std::max(width, o.width),
std::max(height, o.height),
};
}
constexpr Size Intersection(const Size& o) const {
constexpr TSize Intersection(const TSize& o) const {
return {
std::min(width, o.width),
std::min(height, o.height),
};
}
constexpr Type Area() const { return width * height; }
constexpr bool IsZero() const { return width * height == 0.0; }
constexpr bool IsPositive() const { return width * height > 0.0; }
constexpr bool IsEmpty() { return !IsPositive(); }
constexpr size_t MipCount() const {
if (!IsPositive()) {
return 1u;
}
return std::max(ceil(log2(width)), ceil(log2(height)));
}
};
using Size = TSize<Scalar>;
using ISize = TSize<int64_t>;
static_assert(sizeof(Size) == 2 * sizeof(Scalar));
} // namespace impeller

View File

@ -65,7 +65,7 @@ TEST_F(PrimitivesTest, CanCreateBoxPrimitive) {
}
return true;
};
OpenPlaygroundHere(callback);
// OpenPlaygroundHere(callback);
}
} // namespace testing