Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
76 changes: 35 additions & 41 deletions impeller/display_list/dl_vertices_geometry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include "impeller/core/device_buffer.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/position_color.vert.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/path_builder.h"
Expand Down Expand Up @@ -160,9 +159,8 @@ GeometryResult DlVerticesGeometry::GetPositionBuffer(
Range{0, total_vtx_bytes}, 0)) {
return {};
}
if (!buffer->CopyHostBuffer(
reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(dl_indices)),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
if (!buffer->CopyHostBuffer(reinterpret_cast<const uint8_t*>(dl_indices),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
return {};
}

Expand All @@ -184,12 +182,10 @@ GeometryResult DlVerticesGeometry::GetPositionBuffer(
};
}

GeometryResult DlVerticesGeometry::GetPositionColorBuffer(
PositionColorBufferResult DlVerticesGeometry::GetPositionColorBuffer(
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) {
using VS = GeometryColorPipeline::VertexShader;

auto index_count = normalized_indices_.size() == 0
? vertices_->index_count()
: normalized_indices_.size();
Expand All @@ -200,56 +196,54 @@ GeometryResult DlVerticesGeometry::GetPositionColorBuffer(
auto* dl_vertices = vertices_->vertices();
auto* dl_colors = vertices_->colors();

std::vector<VS::PerVertexData> vertex_data(vertex_count);
{
for (auto i = 0; i < vertex_count; i++) {
auto dl_color = dl_colors[i];
auto color = Color(dl_color.getRedF(), dl_color.getGreenF(),
dl_color.getBlueF(), dl_color.getAlphaF())
.Premultiply();
auto sk_point = dl_vertices[i];
vertex_data[i] = {
.position = Point(sk_point.x(), sk_point.y()),
.color = color,
};
}
}

size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
size_t total_position_bytes = vertex_count * sizeof(float) * 2;
size_t total_color_bytes = vertex_count * sizeof(float) * 4;
size_t total_vtx_bytes = total_position_bytes + total_color_bytes;
size_t total_idx_bytes = index_count * sizeof(uint16_t);

DeviceBufferDescriptor buffer_desc;
buffer_desc.size = total_vtx_bytes + total_idx_bytes;
buffer_desc.size = total_position_bytes + total_color_bytes + total_idx_bytes;
buffer_desc.storage_mode = StorageMode::kHostVisible;

auto buffer =
renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);

if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
Range{0, total_vtx_bytes}, 0)) {
if (!buffer->CopyHostBuffer(reinterpret_cast<const uint8_t*>(dl_vertices),
Range{0, total_position_bytes}, 0)) {
return {};
}
if (!buffer->CopyHostBuffer(
reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(dl_indices)),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
// This conversion is still necessary because dl_color is backed by a unit32
// instead of 4 floats and is not premupltiplied.
std::vector<Color> colors(vertex_count);
for (auto i = 0; i < vertex_count; i++) {
auto dl_color = dl_colors[i];
colors[i] = Color(dl_color.getRedF(), dl_color.getGreenF(),
dl_color.getBlueF(), dl_color.getAlphaF())
.Premultiply();
}

if (!buffer->CopyHostBuffer(reinterpret_cast<const uint8_t*>(colors.data()),
Range{0, total_color_bytes},
total_position_bytes)) {
return {};
}
if (!buffer->CopyHostBuffer(reinterpret_cast<const uint8_t*>(dl_indices),
Range{0, total_idx_bytes}, total_vtx_bytes)) {
return {};
}

return GeometryResult{
return PositionColorBufferResult{
.index_buffer = {.buffer = buffer,
.range = Range{total_vtx_bytes, total_idx_bytes}},
.position_buffer = {.buffer = buffer,
.range = Range{0, total_position_bytes}},
.color_buffer = {.buffer = buffer,
.range = Range{total_position_bytes, total_color_bytes}},
.type = GetPrimitiveType(vertices_),
.vertex_buffer =
{
.vertex_buffer = {.buffer = buffer,
.range = Range{0, total_vtx_bytes}},
.index_buffer = {.buffer = buffer,
.range =
Range{total_vtx_bytes, total_idx_bytes}},
.vertex_count = index_count,
.index_type = IndexType::k16bit,
},
.vertex_count = index_count,
.index_type = IndexType::k16bit,
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation(),
.prevent_overdraw = false,
};
}

Expand Down
9 changes: 5 additions & 4 deletions impeller/display_list/dl_vertices_geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ class DlVerticesGeometry : public VerticesGeometry {
const flutter::DlVertices* vertices);

// |VerticesGeometry|
GeometryResult GetPositionColorBuffer(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) override;
PositionColorBufferResult GetPositionColorBuffer(
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) override;

// |VerticesGeometry|
// |Geometry|
GeometryResult GetPositionUVBuffer(Rect texture_coverage,
Matrix effect_transform,
const ContentContext& renderer,
Expand Down
2 changes: 1 addition & 1 deletion impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ void ContentContextOptions::ApplyToPipelineDescriptor(
}

desc.SetPrimitiveType(primitive_type);

desc.SetInterleavedVertexData(interleaved_vertex_data);
desc.SetPolygonMode(wireframe ? PolygonMode::kLine : PolygonMode::kFill);
}

Expand Down
13 changes: 7 additions & 6 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,14 @@ struct ContentContextOptions {
std::optional<PixelFormat> color_attachment_pixel_format;
bool has_stencil_attachment = true;
bool wireframe = false;
bool interleaved_vertex_data = true;

struct Hash {
constexpr std::size_t operator()(const ContentContextOptions& o) const {
return fml::HashCombine(o.sample_count, o.blend_mode, o.stencil_compare,
o.stencil_operation, o.primitive_type,
o.color_attachment_pixel_format,
o.has_stencil_attachment, o.wireframe);
return fml::HashCombine(
o.sample_count, o.blend_mode, o.stencil_compare, o.stencil_operation,
o.primitive_type, o.color_attachment_pixel_format,
o.has_stencil_attachment, o.wireframe, o.interleaved_vertex_data);
}
};

Expand All @@ -320,7 +321,8 @@ struct ContentContextOptions {
lhs.color_attachment_pixel_format ==
rhs.color_attachment_pixel_format &&
lhs.has_stencil_attachment == rhs.has_stencil_attachment &&
lhs.wireframe == rhs.wireframe;
lhs.wireframe == rhs.wireframe &&
lhs.interleaved_vertex_data == rhs.interleaved_vertex_data;
}
};

Expand Down Expand Up @@ -815,7 +817,6 @@ class ContentContext {
if (wireframe_) {
opts.wireframe = true;
}

if (auto found = container.find(opts); found != container.end()) {
return found->second->WaitAndGet();
}
Expand Down
7 changes: 6 additions & 1 deletion impeller/entity/contents/vertices_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,15 @@ bool VerticesColorContents::Render(const ContentContext& renderer,
auto geometry_result =
geometry->GetPositionColorBuffer(renderer, entity, pass);
auto opts = OptionsFromPassAndEntity(pass, entity);
opts.interleaved_vertex_data = false;
opts.primitive_type = geometry_result.type;
cmd.pipeline = renderer.GetGeometryColorPipeline(opts);
cmd.stencil_reference = entity.GetStencilDepth();
cmd.BindVertices(geometry_result.vertex_buffer);

cmd.BindVertexBuffers<2>(
{geometry_result.position_buffer, geometry_result.color_buffer});
cmd.BindIndexBuffer(geometry_result.index_type, geometry_result.index_buffer);
cmd.vertex_count = geometry_result.vertex_count;

VS::FrameInfo frame_info;
frame_info.mvp = geometry_result.transform;
Expand Down
76 changes: 76 additions & 0 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "fml/logging.h"
#include "fml/time/time_point.h"
#include "gtest/gtest.h"
#include "impeller/entity/contents/anonymous_contents.h"
#include "impeller/entity/contents/atlas_contents.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/contents/conical_gradient_contents.h"
Expand Down Expand Up @@ -2638,6 +2639,81 @@ TEST_P(EntityTest, PointFieldGeometryDivisions) {
ASSERT_EQ(PointFieldGeometry::ComputeCircleDivisions(20000.0, true), 140u);
}

TEST_P(EntityTest, CanCustomizeVertexLayout) {
auto callback = [&](ContentContext& context, RenderPass& pass) {
using VS = GeometryColorPipeline::VertexShader;
using FS = GeometryColorPipeline::FragmentShader;

auto contents = AnonymousContents::Make(
[](const ContentContext& renderer, const Entity& entity,
RenderPass& pass) {
auto r = Rect::MakeLTRB(0, 0, 400, 400).GetLTRB();

std::vector<Point> position_data = {
{Point(r[0], r[1])}, //
{Point(r[2], r[1])}, //
{Point(r[2], r[3])}, //
{Point(r[0], r[1])}, //
{Point(r[2], r[3])}, //
{Point(r[0], r[3])} //
};
std::vector<Color> color_data = {
Color::Red(), //
Color::Green(), //
Color::Red(), //
Color::Green(), //
Color::Red(), //
Color::Green() //
};

auto& host_buffer = pass.GetTransientsBuffer();
auto position_view = host_buffer.Emplace(
reinterpret_cast<const uint8_t*>(position_data.data()),
position_data.size() * sizeof(Point), alignof(Point));

auto color_view = host_buffer.Emplace(
reinterpret_cast<const uint8_t*>(color_data.data()),
color_data.size() * sizeof(Color), alignof(Color));

Command cmd;
cmd.label = "Per Vertex Colors";
auto options = OptionsFromPass(pass);
options.primitive_type = PrimitiveType::kTriangle;
options.interleaved_vertex_data = false;

cmd.pipeline = renderer.GetGeometryColorPipeline(options);
cmd.BindVertexBuffers<2>({
position_view,
color_view,
});
cmd.BindIndexBuffer(IndexType::kNone, {});
cmd.vertex_count = 6;

VS::FrameInfo frame_info;
frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize());
VS::BindFrameInfo(
cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info));

FS::FragInfo frag_info;
frag_info.alpha = 1.0;
FS::BindFragInfo(
cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info));

return pass.AddCommand(std::move(cmd));
},
[](const Entity& entity) {
return Rect::MakeLTRB(0, 0, 400, 400)
.TransformBounds(entity.GetTransformation());
});

Entity entity;
entity.SetContents(contents);
return entity.Render(context, pass);
};

ASSERT_TRUE(OpenPlaygroundHere(callback));
}

} // namespace testing
} // namespace impeller

Expand Down
18 changes: 15 additions & 3 deletions impeller/entity/geometry/vertices_geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,24 @@

namespace impeller {

struct PositionColorBufferResult {
BufferView index_buffer;
BufferView position_buffer;
BufferView color_buffer;

PrimitiveType type;
size_t vertex_count;
IndexType index_type;
Matrix transform;
};

/// @brief A geometry that is created from a vertices object.
class VerticesGeometry : public Geometry {
public:
virtual GeometryResult GetPositionColorBuffer(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) = 0;
virtual PositionColorBufferResult GetPositionColorBuffer(
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) = 0;

virtual bool HasVertexColors() const = 0;

Expand Down
41 changes: 34 additions & 7 deletions impeller/renderer/backend/gles/buffer_bindings_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,29 @@ bool BufferBindingsGLES::RegisterVertexStageInput(
}
attrib.type = type.value();
attrib.normalized = GL_FALSE;
attrib.offset = offset;
offset += (input.bit_width * input.vec_size) / 8;
auto width = (input.bit_width * input.vec_size) / 8;
if (interleaved_vertex_data_) {
attrib.offset = offset;
offset += width;
} else {
attrib.offset = 0u;
attrib.stride = 0u;
}
vertex_attrib_arrays.emplace_back(attrib);
}
for (auto& array : vertex_attrib_arrays) {
array.stride = offset;
if (interleaved_vertex_data_) {
for (auto& array : vertex_attrib_arrays) {
array.stride = offset;
}
}
vertex_attrib_arrays_ = std::move(vertex_attrib_arrays);
return true;
}

void BufferBindingsGLES::SetInterleavedVertexData(bool value) {
interleaved_vertex_data_ = value;
}

static std::string NormalizeUniformKey(const std::string& key) {
std::string result;
result.reserve(key.length());
Expand Down Expand Up @@ -131,16 +143,31 @@ bool BufferBindingsGLES::ReadUniformsBindings(const ProcTableGLES& gl,
}

bool BufferBindingsGLES::BindVertexAttributes(const ProcTableGLES& gl,
size_t vertex_index,
size_t vertex_offset) const {
for (const auto& array : vertex_attrib_arrays_) {
if (interleaved_vertex_data_) {
for (const auto& array : vertex_attrib_arrays_) {
gl.EnableVertexAttribArray(array.index);
gl.VertexAttribPointer(
array.index, // index
array.size, // size (must be 1, 2, 3, or 4)
array.type, // type
array.normalized, // normalized
array.stride, // stride
reinterpret_cast<const GLvoid*>(
static_cast<GLsizei>(vertex_offset + array.offset)) // pointer
);
}
} else {
auto array = vertex_attrib_arrays_[vertex_index];
gl.EnableVertexAttribArray(array.index);
gl.VertexAttribPointer(array.index, // index
array.size, // size (must be 1, 2, 3, or 4)
array.type, // type
array.normalized, // normalized
array.stride, // stride
reinterpret_cast<const GLvoid*>(static_cast<GLsizei>(
vertex_offset + array.offset)) // pointer
reinterpret_cast<const GLvoid*>(
static_cast<GLsizei>(vertex_offset)) // pointer
);
}

Expand Down
Loading