mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Wire up texture creation from buffers.
This commit is contained in:
parent
ffe1fc656e
commit
ec3d9f6060
@ -27,8 +27,8 @@ executable("impeller_unittests") {
|
||||
"compositor:compositor_unittests",
|
||||
"entity:entity_unittests",
|
||||
"fixtures",
|
||||
"geometry:geometry_unittests",
|
||||
"playground",
|
||||
"primitives:primitives_unittests",
|
||||
"//flutter/testing",
|
||||
]
|
||||
}
|
||||
|
||||
@ -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",
|
||||
]
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -31,3 +31,12 @@ impeller_component("geometry") {
|
||||
"vector.h",
|
||||
]
|
||||
}
|
||||
|
||||
impeller_component("geometry_unittests") {
|
||||
testonly = true
|
||||
sources = [ "geometry_unittests.cc" ]
|
||||
deps = [
|
||||
":geometry",
|
||||
"//flutter/testing",
|
||||
]
|
||||
}
|
||||
|
||||
23
engine/src/flutter/impeller/geometry/geometry_unittests.cc
Normal file
23
engine/src/flutter/impeller/geometry/geometry_unittests.cc
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -65,7 +65,7 @@ TEST_F(PrimitivesTest, CanCreateBoxPrimitive) {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
OpenPlaygroundHere(callback);
|
||||
// OpenPlaygroundHere(callback);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user