summaryrefslogtreecommitdiff
path: root/libs/hwui
diff options
context:
space:
mode:
author Alex Strelnikov <strel@google.com> 2024-03-07 20:38:10 +0000
committer Alex Strelnikov <strel@google.com> 2024-03-10 03:07:27 +0000
commitb58afe6dab72f08f19111448633354bb69c4d14b (patch)
treead29a901ce0c96ac268fc0b29986f05a0c819654 /libs/hwui
parentd2a2fae7eb0a46d6ed2d7afbd7127f00dcf0da54 (diff)
Fix Mesh UAF, uniform handling, and performance bug.
Prior to this change, the render thread would only receive a non-owning pointer or reference to a Mesh. Also because the Mesh itself was passed by pointer, the refcount in its uniform sk_sp<SkData> would not be incremented until an SkMesh was updated on the render thread, causing uniform setting calls on the UI thread to impact prior draw calls with the same mesh. The dirty flag used for the uniforms was also signaling a reupload of vertex and index data to the GPU. This fix adds a MeshBufferData class to handle keeping Skia buffers up-to-date, and a Mesh::Snapshot class that carries shared ownership of all pieces needed to construct an SkMesh. The snapshot is stored on the render thread by value and increments the refcount of the uniform sk_sp<SkData>. Because the current Android Mesh API does not support partial buffer updates, there is no need for a dirty flag, as comparing the DirectContextID and checking if the buffers have been created is sufficient. Creating an SkMesh is performed lazily inside the SkMesh getter of the snapshot. BUG: 328507000 Test: atest CtsUiRenderingTestCases:MeshTest Change-Id: Iabe83dca462d4526c118047621b131009032d35b
Diffstat (limited to 'libs/hwui')
-rw-r--r--libs/hwui/Mesh.cpp48
-rw-r--r--libs/hwui/Mesh.h225
-rw-r--r--libs/hwui/RecordingCanvas.cpp13
-rw-r--r--libs/hwui/RecordingCanvas.h17
-rw-r--r--libs/hwui/SkiaCanvas.cpp4
-rw-r--r--libs/hwui/hwui/Canvas.h2
-rw-r--r--libs/hwui/jni/android_graphics_Mesh.cpp14
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.cpp6
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.h3
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp2
10 files changed, 191 insertions, 143 deletions
diff --git a/libs/hwui/Mesh.cpp b/libs/hwui/Mesh.cpp
index 37a7d74330e9..5ef7acdaf0fa 100644
--- a/libs/hwui/Mesh.cpp
+++ b/libs/hwui/Mesh.cpp
@@ -21,6 +21,8 @@
#include "SafeMath.h"
+namespace android {
+
static size_t min_vcount_for_mode(SkMesh::Mode mode) {
switch (mode) {
case SkMesh::Mode::kTriangles:
@@ -28,6 +30,7 @@ static size_t min_vcount_for_mode(SkMesh::Mode mode) {
case SkMesh::Mode::kTriangleStrip:
return 3;
}
+ return 1;
}
// Re-implementation of SkMesh::validate to validate user side that their mesh is valid.
@@ -36,29 +39,30 @@ std::tuple<bool, SkString> Mesh::validate() {
if (!mMeshSpec) {
FAIL_MESH_VALIDATE("MeshSpecification is required.");
}
- if (mVertexBufferData.empty()) {
+ if (mBufferData->vertexData().empty()) {
FAIL_MESH_VALIDATE("VertexBuffer is required.");
}
- auto meshStride = mMeshSpec->stride();
- auto meshMode = SkMesh::Mode(mMode);
+ size_t vertexStride = mMeshSpec->stride();
+ size_t vertexCount = mBufferData->vertexCount();
+ size_t vertexOffset = mBufferData->vertexOffset();
SafeMath sm;
- size_t vsize = sm.mul(meshStride, mVertexCount);
- if (sm.add(vsize, mVertexOffset) > mVertexBufferData.size()) {
+ size_t vertexSize = sm.mul(vertexStride, vertexCount);
+ if (sm.add(vertexSize, vertexOffset) > mBufferData->vertexData().size()) {
FAIL_MESH_VALIDATE(
"The vertex buffer offset and vertex count reads beyond the end of the"
" vertex buffer.");
}
- if (mVertexOffset % meshStride != 0) {
+ if (vertexOffset % vertexStride != 0) {
FAIL_MESH_VALIDATE("The vertex offset (%zu) must be a multiple of the vertex stride (%zu).",
- mVertexOffset, meshStride);
+ vertexOffset, vertexStride);
}
if (size_t uniformSize = mMeshSpec->uniformSize()) {
- if (!mBuilder->fUniforms || mBuilder->fUniforms->size() < uniformSize) {
+ if (!mUniformBuilder.fUniforms || mUniformBuilder.fUniforms->size() < uniformSize) {
FAIL_MESH_VALIDATE("The uniform data is %zu bytes but must be at least %zu.",
- mBuilder->fUniforms->size(), uniformSize);
+ mUniformBuilder.fUniforms->size(), uniformSize);
}
}
@@ -69,29 +73,33 @@ std::tuple<bool, SkString> Mesh::validate() {
case SkMesh::Mode::kTriangleStrip:
return "triangle-strip";
}
+ return "unknown";
};
- if (!mIndexBufferData.empty()) {
- if (mIndexCount < min_vcount_for_mode(meshMode)) {
+
+ size_t indexCount = mBufferData->indexCount();
+ size_t indexOffset = mBufferData->indexOffset();
+ if (!mBufferData->indexData().empty()) {
+ if (indexCount < min_vcount_for_mode(mMode)) {
FAIL_MESH_VALIDATE("%s mode requires at least %zu indices but index count is %zu.",
- modeToStr(meshMode), min_vcount_for_mode(meshMode), mIndexCount);
+ modeToStr(mMode), min_vcount_for_mode(mMode), indexCount);
}
- size_t isize = sm.mul(sizeof(uint16_t), mIndexCount);
- if (sm.add(isize, mIndexOffset) > mIndexBufferData.size()) {
+ size_t isize = sm.mul(sizeof(uint16_t), indexCount);
+ if (sm.add(isize, indexOffset) > mBufferData->indexData().size()) {
FAIL_MESH_VALIDATE(
"The index buffer offset and index count reads beyond the end of the"
" index buffer.");
}
// If we allow 32 bit indices then this should enforce 4 byte alignment in that case.
- if (!SkIsAlign2(mIndexOffset)) {
+ if (!SkIsAlign2(indexOffset)) {
FAIL_MESH_VALIDATE("The index offset must be a multiple of 2.");
}
} else {
- if (mVertexCount < min_vcount_for_mode(meshMode)) {
+ if (vertexCount < min_vcount_for_mode(mMode)) {
FAIL_MESH_VALIDATE("%s mode requires at least %zu vertices but vertex count is %zu.",
- modeToStr(meshMode), min_vcount_for_mode(meshMode), mVertexCount);
+ modeToStr(mMode), min_vcount_for_mode(mMode), vertexCount);
}
- LOG_ALWAYS_FATAL_IF(mIndexCount != 0);
- LOG_ALWAYS_FATAL_IF(mIndexOffset != 0);
+ LOG_ALWAYS_FATAL_IF(indexCount != 0);
+ LOG_ALWAYS_FATAL_IF(indexOffset != 0);
}
if (!sm.ok()) {
@@ -100,3 +108,5 @@ std::tuple<bool, SkString> Mesh::validate() {
#undef FAIL_MESH_VALIDATE
return {true, {}};
}
+
+} // namespace android
diff --git a/libs/hwui/Mesh.h b/libs/hwui/Mesh.h
index 69fda34afc78..8c6ca9758479 100644
--- a/libs/hwui/Mesh.h
+++ b/libs/hwui/Mesh.h
@@ -25,6 +25,8 @@
#include <utility>
+namespace android {
+
class MeshUniformBuilder {
public:
struct MeshUniform {
@@ -103,111 +105,170 @@ private:
sk_sp<SkMeshSpecification> fMeshSpec;
};
-class Mesh {
+// Storage for CPU and GPU copies of the vertex and index data of a mesh.
+class MeshBufferData {
public:
- Mesh(const sk_sp<SkMeshSpecification>& meshSpec, int mode,
- std::vector<uint8_t>&& vertexBufferData, jint vertexCount, jint vertexOffset,
- std::unique_ptr<MeshUniformBuilder> builder, const SkRect& bounds)
- : mMeshSpec(meshSpec)
- , mMode(mode)
- , mVertexBufferData(std::move(vertexBufferData))
- , mVertexCount(vertexCount)
- , mVertexOffset(vertexOffset)
- , mBuilder(std::move(builder))
- , mBounds(bounds) {}
-
- Mesh(const sk_sp<SkMeshSpecification>& meshSpec, int mode,
- std::vector<uint8_t>&& vertexBufferData, jint vertexCount, jint vertexOffset,
- std::vector<uint8_t>&& indexBuffer, jint indexCount, jint indexOffset,
- std::unique_ptr<MeshUniformBuilder> builder, const SkRect& bounds)
- : mMeshSpec(meshSpec)
- , mMode(mode)
- , mVertexBufferData(std::move(vertexBufferData))
- , mVertexCount(vertexCount)
+ MeshBufferData(std::vector<uint8_t> vertexData, int32_t vertexCount, int32_t vertexOffset,
+ std::vector<uint8_t> indexData, int32_t indexCount, int32_t indexOffset)
+ : mVertexCount(vertexCount)
, mVertexOffset(vertexOffset)
- , mIndexBufferData(std::move(indexBuffer))
, mIndexCount(indexCount)
, mIndexOffset(indexOffset)
- , mBuilder(std::move(builder))
- , mBounds(bounds) {}
-
- Mesh(Mesh&&) = default;
+ , mVertexData(std::move(vertexData))
+ , mIndexData(std::move(indexData)) {}
- Mesh& operator=(Mesh&&) = default;
-
- [[nodiscard]] std::tuple<bool, SkString> validate();
-
- void updateSkMesh(GrDirectContext* context) const {
- GrDirectContext::DirectContextID genId = GrDirectContext::DirectContextID();
- if (context) {
- genId = context->directContextID();
+ void updateBuffers(GrDirectContext* context) const {
+ GrDirectContext::DirectContextID currentId = context == nullptr
+ ? GrDirectContext::DirectContextID()
+ : context->directContextID();
+ if (currentId == mSkiaBuffers.fGenerationId && mSkiaBuffers.fVertexBuffer != nullptr) {
+ // Nothing to update since the Android API does not support partial updates yet.
+ return;
}
- if (mIsDirty || genId != mGenerationId) {
- auto vertexData = reinterpret_cast<const void*>(mVertexBufferData.data());
+ mSkiaBuffers.fVertexBuffer =
#ifdef __ANDROID__
- auto vb = SkMeshes::MakeVertexBuffer(context,
- vertexData,
- mVertexBufferData.size());
+ SkMeshes::MakeVertexBuffer(context, mVertexData.data(), mVertexData.size());
#else
- auto vb = SkMeshes::MakeVertexBuffer(vertexData,
- mVertexBufferData.size());
+ SkMeshes::MakeVertexBuffer(mVertexData.data(), mVertexData.size());
#endif
- auto meshMode = SkMesh::Mode(mMode);
- if (!mIndexBufferData.empty()) {
- auto indexData = reinterpret_cast<const void*>(mIndexBufferData.data());
+ if (mIndexCount != 0) {
+ mSkiaBuffers.fIndexBuffer =
#ifdef __ANDROID__
- auto ib = SkMeshes::MakeIndexBuffer(context,
- indexData,
- mIndexBufferData.size());
+ SkMeshes::MakeIndexBuffer(context, mIndexData.data(), mIndexData.size());
#else
- auto ib = SkMeshes::MakeIndexBuffer(indexData,
- mIndexBufferData.size());
+ SkMeshes::MakeIndexBuffer(mIndexData.data(), mIndexData.size());
#endif
- mMesh = SkMesh::MakeIndexed(mMeshSpec, meshMode, vb, mVertexCount, mVertexOffset,
- ib, mIndexCount, mIndexOffset, mBuilder->fUniforms,
- SkSpan<SkRuntimeEffect::ChildPtr>(), mBounds)
- .mesh;
- } else {
- mMesh = SkMesh::Make(mMeshSpec, meshMode, vb, mVertexCount, mVertexOffset,
- mBuilder->fUniforms, SkSpan<SkRuntimeEffect::ChildPtr>(),
- mBounds)
- .mesh;
- }
- mIsDirty = false;
- mGenerationId = genId;
}
+ mSkiaBuffers.fGenerationId = currentId;
}
- SkMesh& getSkMesh() const {
- LOG_FATAL_IF(mIsDirty,
- "Attempt to obtain SkMesh when Mesh is dirty, did you "
- "forget to call updateSkMesh with a GrDirectContext? "
- "Defensively creating a CPU mesh");
- return mMesh;
- }
+ SkMesh::VertexBuffer* vertexBuffer() const { return mSkiaBuffers.fVertexBuffer.get(); }
+
+ sk_sp<SkMesh::VertexBuffer> refVertexBuffer() const { return mSkiaBuffers.fVertexBuffer; }
+ int32_t vertexCount() const { return mVertexCount; }
+ int32_t vertexOffset() const { return mVertexOffset; }
- void markDirty() { mIsDirty = true; }
+ sk_sp<SkMesh::IndexBuffer> refIndexBuffer() const { return mSkiaBuffers.fIndexBuffer; }
+ int32_t indexCount() const { return mIndexCount; }
+ int32_t indexOffset() const { return mIndexOffset; }
- MeshUniformBuilder* uniformBuilder() { return mBuilder.get(); }
+ const std::vector<uint8_t>& vertexData() const { return mVertexData; }
+ const std::vector<uint8_t>& indexData() const { return mIndexData; }
private:
- sk_sp<SkMeshSpecification> mMeshSpec;
- int mMode = 0;
+ struct CachedSkiaBuffers {
+ sk_sp<SkMesh::VertexBuffer> fVertexBuffer;
+ sk_sp<SkMesh::IndexBuffer> fIndexBuffer;
+ GrDirectContext::DirectContextID fGenerationId = GrDirectContext::DirectContextID();
+ };
+
+ mutable CachedSkiaBuffers mSkiaBuffers;
+ int32_t mVertexCount = 0;
+ int32_t mVertexOffset = 0;
+ int32_t mIndexCount = 0;
+ int32_t mIndexOffset = 0;
+ std::vector<uint8_t> mVertexData;
+ std::vector<uint8_t> mIndexData;
+};
- std::vector<uint8_t> mVertexBufferData;
- size_t mVertexCount = 0;
- size_t mVertexOffset = 0;
+class Mesh {
+public:
+ // A snapshot of the mesh for use by the render thread.
+ //
+ // After a snapshot is taken, future uniform changes to the original Mesh will not modify the
+ // uniforms returned by makeSkMesh.
+ class Snapshot {
+ public:
+ Snapshot() = delete;
+ Snapshot(const Snapshot&) = default;
+ Snapshot(Snapshot&&) = default;
+ Snapshot& operator=(const Snapshot&) = default;
+ Snapshot& operator=(Snapshot&&) = default;
+ ~Snapshot() = default;
- std::vector<uint8_t> mIndexBufferData;
- size_t mIndexCount = 0;
- size_t mIndexOffset = 0;
+ const SkMesh& getSkMesh() const {
+ SkMesh::VertexBuffer* vertexBuffer = mBufferData->vertexBuffer();
+ LOG_FATAL_IF(vertexBuffer == nullptr,
+ "Attempt to obtain SkMesh when vertexBuffer has not been created, did you "
+ "forget to call MeshBufferData::updateBuffers with a GrDirectContext?");
+ if (vertexBuffer != mMesh.vertexBuffer()) mMesh = makeSkMesh();
+ return mMesh;
+ }
- std::unique_ptr<MeshUniformBuilder> mBuilder;
- SkRect mBounds{};
+ private:
+ friend class Mesh;
- mutable SkMesh mMesh{};
- mutable bool mIsDirty = true;
- mutable GrDirectContext::DirectContextID mGenerationId = GrDirectContext::DirectContextID();
+ Snapshot(sk_sp<SkMeshSpecification> meshSpec, SkMesh::Mode mode,
+ std::shared_ptr<const MeshBufferData> bufferData, sk_sp<const SkData> uniforms,
+ const SkRect& bounds)
+ : mMeshSpec(std::move(meshSpec))
+ , mMode(mode)
+ , mBufferData(std::move(bufferData))
+ , mUniforms(std::move(uniforms))
+ , mBounds(bounds) {}
+
+ SkMesh makeSkMesh() const {
+ const MeshBufferData& d = *mBufferData;
+ if (d.indexCount() != 0) {
+ return SkMesh::MakeIndexed(mMeshSpec, mMode, d.refVertexBuffer(), d.vertexCount(),
+ d.vertexOffset(), d.refIndexBuffer(), d.indexCount(),
+ d.indexOffset(), mUniforms,
+ SkSpan<SkRuntimeEffect::ChildPtr>(), mBounds)
+ .mesh;
+ }
+ return SkMesh::Make(mMeshSpec, mMode, d.refVertexBuffer(), d.vertexCount(),
+ d.vertexOffset(), mUniforms, SkSpan<SkRuntimeEffect::ChildPtr>(),
+ mBounds)
+ .mesh;
+ }
+
+ mutable SkMesh mMesh;
+ sk_sp<SkMeshSpecification> mMeshSpec;
+ SkMesh::Mode mMode;
+ std::shared_ptr<const MeshBufferData> mBufferData;
+ sk_sp<const SkData> mUniforms;
+ SkRect mBounds;
+ };
+
+ Mesh(sk_sp<SkMeshSpecification> meshSpec, SkMesh::Mode mode, std::vector<uint8_t> vertexData,
+ int32_t vertexCount, int32_t vertexOffset, const SkRect& bounds)
+ : Mesh(std::move(meshSpec), mode, std::move(vertexData), vertexCount, vertexOffset,
+ /* indexData = */ {}, /* indexCount = */ 0, /* indexOffset = */ 0, bounds) {}
+
+ Mesh(sk_sp<SkMeshSpecification> meshSpec, SkMesh::Mode mode, std::vector<uint8_t> vertexData,
+ int32_t vertexCount, int32_t vertexOffset, std::vector<uint8_t> indexData,
+ int32_t indexCount, int32_t indexOffset, const SkRect& bounds)
+ : mMeshSpec(std::move(meshSpec))
+ , mMode(mode)
+ , mBufferData(std::make_shared<MeshBufferData>(std::move(vertexData), vertexCount,
+ vertexOffset, std::move(indexData),
+ indexCount, indexOffset))
+ , mUniformBuilder(mMeshSpec)
+ , mBounds(bounds) {}
+
+ Mesh(Mesh&&) = default;
+
+ Mesh& operator=(Mesh&&) = default;
+
+ [[nodiscard]] std::tuple<bool, SkString> validate();
+
+ std::shared_ptr<const MeshBufferData> refBufferData() const { return mBufferData; }
+
+ Snapshot takeSnapshot() const {
+ return Snapshot(mMeshSpec, mMode, mBufferData, mUniformBuilder.fUniforms, mBounds);
+ }
+
+ MeshUniformBuilder* uniformBuilder() { return &mUniformBuilder; }
+
+private:
+ sk_sp<SkMeshSpecification> mMeshSpec;
+ SkMesh::Mode mMode;
+ std::shared_ptr<MeshBufferData> mBufferData;
+ MeshUniformBuilder mUniformBuilder;
+ SkRect mBounds;
};
+
+} // namespace android
+
#endif // MESH_H_
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 54aef55f8b90..d0263798d2c2 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -573,9 +573,9 @@ struct DrawSkMesh final : Op {
struct DrawMesh final : Op {
static const auto kType = Type::DrawMesh;
DrawMesh(const Mesh& mesh, sk_sp<SkBlender> blender, const SkPaint& paint)
- : mesh(mesh), blender(std::move(blender)), paint(paint) {}
+ : mesh(mesh.takeSnapshot()), blender(std::move(blender)), paint(paint) {}
- const Mesh& mesh;
+ Mesh::Snapshot mesh;
sk_sp<SkBlender> blender;
SkPaint paint;
@@ -1296,14 +1296,5 @@ void RecordingCanvas::drawWebView(skiapipeline::FunctorDrawable* drawable) {
fDL->drawWebView(drawable);
}
-[[nodiscard]] const SkMesh& DrawMeshPayload::getSkMesh() const {
- LOG_FATAL_IF(!meshWrapper && !mesh, "One of Mesh or Mesh must be non-null");
- if (meshWrapper) {
- return meshWrapper->getSkMesh();
- } else {
- return *mesh;
- }
-}
-
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 965264f31119..f86785274224 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -41,11 +41,12 @@
enum class SkBlendMode;
class SkRRect;
-class Mesh;
namespace android {
-namespace uirenderer {
+class Mesh;
+
+namespace uirenderer {
namespace skiapipeline {
class FunctorDrawable;
}
@@ -68,18 +69,6 @@ struct DisplayListOp {
static_assert(sizeof(DisplayListOp) == 4);
-class DrawMeshPayload {
-public:
- explicit DrawMeshPayload(const SkMesh* mesh) : mesh(mesh) {}
- explicit DrawMeshPayload(const Mesh* meshWrapper) : meshWrapper(meshWrapper) {}
-
- [[nodiscard]] const SkMesh& getSkMesh() const;
-
-private:
- const SkMesh* mesh = nullptr;
- const Mesh* meshWrapper = nullptr;
-};
-
struct DrawImagePayload {
explicit DrawImagePayload(Bitmap& bitmap)
: image(bitmap.makeImage()), palette(bitmap.palette()) {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 0b739c361d64..72e83afbd96f 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -596,8 +596,8 @@ void SkiaCanvas::drawMesh(const Mesh& mesh, sk_sp<SkBlender> blender, const Pain
if (recordingContext) {
context = recordingContext->asDirectContext();
}
- mesh.updateSkMesh(context);
- mCanvas->drawMesh(mesh.getSkMesh(), blender, paint);
+ mesh.refBufferData()->updateBuffers(context);
+ mCanvas->drawMesh(mesh.takeSnapshot().getSkMesh(), blender, paint);
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 14b4f584f0f3..4eb6918d7e9a 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -34,7 +34,6 @@ class SkCanvasState;
class SkRRect;
class SkRuntimeShaderBuilder;
class SkVertices;
-class Mesh;
namespace minikin {
class Font;
@@ -61,6 +60,7 @@ typedef std::function<void(uint16_t* text, float* positions)> ReadGlyphFunc;
class AnimatedImageDrawable;
class Bitmap;
+class Mesh;
class Paint;
struct Typeface;
diff --git a/libs/hwui/jni/android_graphics_Mesh.cpp b/libs/hwui/jni/android_graphics_Mesh.cpp
index 5cb43e54e499..3109de5055ca 100644
--- a/libs/hwui/jni/android_graphics_Mesh.cpp
+++ b/libs/hwui/jni/android_graphics_Mesh.cpp
@@ -38,8 +38,8 @@ static jlong make(JNIEnv* env, jobject, jlong meshSpec, jint mode, jobject verte
return 0;
}
auto skRect = SkRect::MakeLTRB(left, top, right, bottom);
- auto meshPtr = new Mesh(skMeshSpec, mode, std::move(buffer), vertexCount, vertexOffset,
- std::make_unique<MeshUniformBuilder>(skMeshSpec), skRect);
+ auto meshPtr = new Mesh(skMeshSpec, static_cast<SkMesh::Mode>(mode), std::move(buffer),
+ vertexCount, vertexOffset, skRect);
auto [valid, msg] = meshPtr->validate();
if (!valid) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", msg.c_str());
@@ -63,9 +63,9 @@ static jlong makeIndexed(JNIEnv* env, jobject, jlong meshSpec, jint mode, jobjec
return 0;
}
auto skRect = SkRect::MakeLTRB(left, top, right, bottom);
- auto meshPtr = new Mesh(skMeshSpec, mode, std::move(vBuf), vertexCount, vertexOffset,
- std::move(iBuf), indexCount, indexOffset,
- std::make_unique<MeshUniformBuilder>(skMeshSpec), skRect);
+ auto meshPtr =
+ new Mesh(skMeshSpec, static_cast<SkMesh::Mode>(mode), std::move(vBuf), vertexCount,
+ vertexOffset, std::move(iBuf), indexCount, indexOffset, skRect);
auto [valid, msg] = meshPtr->validate();
if (!valid) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", msg.c_str());
@@ -133,7 +133,6 @@ static void updateFloatUniforms(JNIEnv* env, jobject, jlong meshWrapper, jstring
ScopedUtfChars name(env, uniformName);
const float values[4] = {value1, value2, value3, value4};
nativeUpdateFloatUniforms(env, wrapper->uniformBuilder(), name.c_str(), values, count, false);
- wrapper->markDirty();
}
static void updateFloatArrayUniforms(JNIEnv* env, jobject, jlong meshWrapper, jstring jUniformName,
@@ -143,7 +142,6 @@ static void updateFloatArrayUniforms(JNIEnv* env, jobject, jlong meshWrapper, js
AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
nativeUpdateFloatUniforms(env, wrapper->uniformBuilder(), name.c_str(), autoValues.ptr(),
autoValues.length(), isColor);
- wrapper->markDirty();
}
static void nativeUpdateIntUniforms(JNIEnv* env, MeshUniformBuilder* builder,
@@ -166,7 +164,6 @@ static void updateIntUniforms(JNIEnv* env, jobject, jlong meshWrapper, jstring u
ScopedUtfChars name(env, uniformName);
const int values[4] = {value1, value2, value3, value4};
nativeUpdateIntUniforms(env, wrapper->uniformBuilder(), name.c_str(), values, count);
- wrapper->markDirty();
}
static void updateIntArrayUniforms(JNIEnv* env, jobject, jlong meshWrapper, jstring uniformName,
@@ -176,7 +173,6 @@ static void updateIntArrayUniforms(JNIEnv* env, jobject, jlong meshWrapper, jstr
AutoJavaIntArray autoValues(env, values, 0);
nativeUpdateIntUniforms(env, wrapper->uniformBuilder(), name.c_str(), autoValues.ptr(),
autoValues.length());
- wrapper->markDirty();
}
static void MeshWrapper_destroy(Mesh* wrapper) {
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 5c8285a8e1e9..e0216b680064 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -111,8 +111,8 @@ bool SkiaDisplayList::prepareListAndChildren(
}
auto grContext = info.canvasContext.getGrContext();
- for (auto mesh : mMeshes) {
- mesh->updateSkMesh(grContext);
+ for (const auto& bufferData : mMeshBufferData) {
+ bufferData->updateBuffers(grContext);
}
#endif
@@ -181,7 +181,7 @@ void SkiaDisplayList::reset() {
mDisplayList.reset();
- mMeshes.clear();
+ mMeshBufferData.clear();
mMutableImages.clear();
mVectorDrawables.clear();
mAnimatedImages.clear();
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index b9dc1c49f09e..071a4e8caaff 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -17,6 +17,7 @@
#pragma once
#include <deque>
+#include <memory>
#include "Mesh.h"
#include "RecordingCanvas.h"
@@ -172,7 +173,7 @@ public:
std::deque<RenderNodeDrawable> mChildNodes;
std::deque<FunctorDrawable*> mChildFunctors;
std::vector<SkImage*> mMutableImages;
- std::vector<const Mesh*> mMeshes;
+ std::vector<std::shared_ptr<const MeshBufferData>> mMeshBufferData;
private:
std::vector<Pair<VectorDrawableRoot*, SkMatrix>> mVectorDrawables;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index e917f9a66917..45bfe1c4957f 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -342,7 +342,7 @@ double SkiaRecordingCanvas::drawAnimatedImage(AnimatedImageDrawable* animatedIma
}
void SkiaRecordingCanvas::drawMesh(const Mesh& mesh, sk_sp<SkBlender> blender, const Paint& paint) {
- mDisplayList->mMeshes.push_back(&mesh);
+ mDisplayList->mMeshBufferData.push_back(mesh.refBufferData());
mRecorder.drawMesh(mesh, blender, paint);
}