diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 0b58406516e30..924fbd659824c 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -51,6 +51,9 @@ #include "include/gpu/GrDirectContext.h" #include "pipeline/skia/AnimatedDrawables.h" #include "pipeline/skia/FunctorDrawable.h" +#ifdef __ANDROID__ +#include "renderthread/CanvasContext.h" +#endif namespace android { namespace uirenderer { @@ -489,7 +492,19 @@ struct DrawPoints final : Op { size_t count; SkPaint paint; void draw(SkCanvas* c, const SkMatrix&) const { - c->drawPoints(mode, count, pod(this), paint); + if (paint.isAntiAlias()) { + c->drawPoints(mode, count, pod(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(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 940d6bfdb83c9..f0461bef170c5 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -53,6 +53,14 @@ public: 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 6f1b99b95bbdc..f22652f92c158 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -215,6 +215,10 @@ void SkiaVulkanPipeline::onContextDestroyed() { } } +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 0713e93bccdec..01a93c7218d96 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -55,6 +55,7 @@ public: bool isContextReady() override; bool supportsExtendedRangeHdr() const override { return true; } void setTargetSdrHdrRatio(float ratio) override; + const SkM44& getPixelSnapMatrix() const override; static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); static sk_sp allocateHardwareBitmap(renderthread::RenderThread& thread, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 6b2c99534a4cb..1b9d41a73f469 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -871,6 +871,10 @@ SkISize CanvasContext::getNextFrameSize() const { 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 3f2533959c201..d7215de923759 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -200,6 +200,9 @@ public: 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 c68fcdfc76f2d..9ebad81c5c817 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -97,6 +97,7 @@ public: virtual bool supportsExtendedRangeHdr() const { return false; } virtual void setTargetSdrHdrRatio(float ratio) = 0; + virtual const SkM44& getPixelSnapMatrix() const = 0; virtual ~IRenderPipeline() {} }; diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp index ae4f0572576ea..2b7fa0420cef8 100644 --- a/libs/hwui/renderthread/VulkanSurface.cpp +++ b/libs/hwui/renderthread/VulkanSurface.cpp @@ -63,6 +63,18 @@ static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) { 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 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode 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) { @@ -413,6 +427,7 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { } 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 3b69b73bcab33..d3266af814374 100644 --- a/libs/hwui/renderthread/VulkanSurface.h +++ b/libs/hwui/renderthread/VulkanSurface.h @@ -47,6 +47,7 @@ public: const SkMatrix& getCurrentPreTransform() { return mWindowInfo.preTransform; } void setColorSpace(sk_sp colorSpace); + const SkM44& getPixelSnapMatrix() const { return mWindowInfo.pixelSnapMatrix; } bool isBeyond8Bit() const; @@ -107,6 +108,7 @@ private: 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);