RESTRICT AUTOMERGE pixel-snap on HWUI side
Bug: 254771190
Test: android.uirendering.cts.testclasses.ExactCanvasTests#testDrawLine
Change-Id: Idfb5027fe3230f2c2b0cad224f2c7640e147ce4a
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index a285462..d101a1b 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -39,6 +39,9 @@
#include "VectorDrawable.h"
#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/FunctorDrawable.h"
+#ifdef __ANDROID__
+#include "renderthread/CanvasContext.h"
+#endif
namespace android {
namespace uirenderer {
@@ -434,7 +437,19 @@
size_t count;
SkPaint paint;
void draw(SkCanvas* c, const SkMatrix&) const {
- c->drawPoints(mode, count, pod<SkPoint>(this), paint);
+ if (paint.isAntiAlias()) {
+ c->drawPoints(mode, count, pod<SkPoint>(this), paint);
+ } else {
+ c->save();
+#ifdef __ANDROID__
+ auto pixelSnap = renderthread::CanvasContext::getActiveContext()->getPixelSnapMatrix();
+ auto transform = c->getLocalToDevice();
+ transform.postConcat(pixelSnap);
+ c->setMatrix(transform);
+#endif
+ c->drawPoints(mode, count, pod<SkPoint>(this), paint);
+ c->restore();
+ }
}
};
struct DrawVertices final : Op {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index a80c613..fe41420 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -53,6 +53,14 @@
bool isSurfaceReady() override;
bool isContextReady() override;
+ const SkM44& getPixelSnapMatrix() const override {
+ // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the
+ // desired fragment
+ static const SkScalar kOffset = 0.063f;
+ static const SkM44 sSnapMatrix = SkM44::Translate(kOffset, kOffset);
+ return sSnapMatrix;
+ }
+
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
protected:
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index cc2565d..18e0b91 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -180,6 +180,10 @@
}
}
+const SkM44& SkiaVulkanPipeline::getPixelSnapMatrix() const {
+ return mVkSurface->getPixelSnapMatrix();
+}
+
} /* namespace skiapipeline */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index a6e685d..7c8f65b 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -49,6 +49,7 @@
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
+ const SkM44& getPixelSnapMatrix() const override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 602554a..f56d19b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -793,6 +793,10 @@
return size;
}
+const SkM44& CanvasContext::getPixelSnapMatrix() const {
+ return mRenderPipeline->getPixelSnapMatrix();
+}
+
void CanvasContext::prepareAndDraw(RenderNode* node) {
ATRACE_CALL();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 951ee21..d85e579 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -195,6 +195,9 @@
SkISize getNextFrameSize() const;
+ // Returns the matrix to use to nudge non-AA'd points/lines towards the fragment center
+ const SkM44& getPixelSnapMatrix() const;
+
// Called when SurfaceStats are available.
static void onSurfaceStatsAvailable(void* context, int32_t surfaceControlId,
ASurfaceControlStats* stats);
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index ef58bc5..54adec2 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -88,6 +88,8 @@
virtual void setPictureCapturedCallback(
const std::function<void(sk_sp<SkPicture>&&)>& callback) = 0;
+ virtual const SkM44& getPixelSnapMatrix() const = 0;
+
virtual ~IRenderPipeline() {}
};
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 7dd3561..666f329 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -63,6 +63,18 @@
return SkMatrix::I();
}
+static SkM44 GetPixelSnapMatrix(SkISize windowSize, int transform) {
+ // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the
+ // desired fragment
+ static const SkScalar kOffset = 0.063f;
+ SkMatrix preRotation = GetPreTransformMatrix(windowSize, transform);
+ SkMatrix invert;
+ LOG_ALWAYS_FATAL_IF(!preRotation.invert(&invert));
+ return SkM44::Translate(kOffset, kOffset)
+ .postConcat(SkM44(preRotation))
+ .preConcat(SkM44(invert));
+}
+
static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
ATRACE_CALL();
@@ -178,6 +190,8 @@
outWindowInfo->preTransform =
GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
+ outWindowInfo->pixelSnapMatrix =
+ GetPixelSnapMatrix(outWindowInfo->size, outWindowInfo->transform);
err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
if (err != 0 || query_value < 0) {
@@ -406,6 +420,7 @@
}
mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
+ mWindowInfo.pixelSnapMatrix = GetPixelSnapMatrix(mWindowInfo.size, mWindowInfo.transform);
}
uint32_t idx;
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index beb71b72..b8ccf78 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -45,6 +45,8 @@
}
const SkMatrix& getCurrentPreTransform() { return mWindowInfo.preTransform; }
+ const SkM44& getPixelSnapMatrix() const { return mWindowInfo.pixelSnapMatrix; }
+
private:
/*
* All structs/methods in this private section are specifically for use by the VulkanManager
@@ -101,6 +103,7 @@
SkISize actualSize;
// transform to be applied to the SkSurface to map the coordinates to the provided transform
SkMatrix preTransform;
+ SkM44 pixelSnapMatrix;
};
VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, GrDirectContext* grContext);