diff --git a/core/src/test/java/icyllis/modernui/test/TestJ2D.java b/core/src/test/java/icyllis/modernui/test/TestJ2D.java index 64dfeb4a..a592579a 100644 --- a/core/src/test/java/icyllis/modernui/test/TestJ2D.java +++ b/core/src/test/java/icyllis/modernui/test/TestJ2D.java @@ -223,7 +223,7 @@ public static Matrix4 getOldMatrix(float pivotX, float pivotY, float translation matrix.setTranslate(pivotX + translationX, pivotY + translationY, 0); matrix.preScale(scaleX, scaleY); matrix.preTranslate(-pivotX, -pivotY); - Matrix4 matrix2 = Matrix4.identity(); + Matrix4 matrix2 = new Matrix4(); matrix2.m34 = 1 / 1920f; matrix2.preRotate(Math.toRadians(-rotationX), Math.toRadians(-rotationY), @@ -236,11 +236,11 @@ public static Matrix4 getOldMatrix(float pivotX, float pivotY, float translation public static Matrix4 getNewMatrix(float pivotX, float pivotY, float translationX, float translationY, float scaleX, float scaleY, float rotationX, float rotationY, float rotationZ) { - Matrix4 matrix = Matrix4.identity(); + Matrix4 matrix = new Matrix4(); matrix.preTranslate(pivotX, pivotY); matrix.preScale(scaleX, scaleY); matrix.preTranslate(-pivotX, -pivotY); - Matrix4 matrix2 = Matrix4.identity(); + Matrix4 matrix2 = new Matrix4(); matrix2.m34 = 1 / 1920f; matrix2.preRotate(Math.toRadians(-rotationX), Math.toRadians(-rotationY), @@ -253,7 +253,7 @@ public static Matrix4 getNewMatrix(float pivotX, float pivotY, float translation public static Matrix4 getNewMatrix2(float pivotX, float pivotY, float translationX, float translationY, float scaleX, float scaleY, float rotationX, float rotationY, float rotationZ) { - Matrix4 matrix = Matrix4.identity(); + Matrix4 matrix = new Matrix4(); matrix.m34 = 1 / 1920f; matrix.preRotate(Math.toRadians(-rotationX), Math.toRadians(-rotationY), diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/core/Device.java b/external/Arc3D/src/main/java/icyllis/arc3d/core/Device.java index b7c3954e..40e630e5 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/core/Device.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/core/Device.java @@ -38,12 +38,12 @@ public abstract class Device extends RefCnt { private final ImageInfo mInfo; private final Rect2i mBounds = new Rect2i(); - final Matrix4 mLocalToDevice = Matrix4.identity(); + final Matrix4 mLocalToDevice = new Matrix4(); final Matrix mLocalToDevice33 = new Matrix(); // mDeviceToGlobal and mGlobalToDevice are inverses of each other - final Matrix4 mDeviceToGlobal = Matrix4.identity(); - final Matrix4 mGlobalToDevice = Matrix4.identity(); + final Matrix4 mDeviceToGlobal = new Matrix4(); + final Matrix4 mGlobalToDevice = new Matrix4(); public Device(ImageInfo info) { mInfo = info; diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrix.java b/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrix.java index f5987522..7c7b55a8 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrix.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrix.java @@ -2218,21 +2218,7 @@ private static float computeMaxScale(double m11, double m21, double m12, double return (float) Math.sqrt(0.5 * (s1 + s2)); } - /** - * Returns the minimum scaling factor of this matrix by decomposing the scaling and - * shearing elements. When this matrix has perspective, the scaling factor is specific - * to the given point p.
- * Returns -1 if scale factor overflows. - * - * @param px the x-coord of point - * @param py the y-coord of point - * @return minimum scale factor - */ - public float getMinScale(float px, float py) { - if (!hasPerspective()) { - return getMinScale(); - } - + private float computeMinScale(double px, double py) { double x = m11 * px + m21 * py + m41; double y = m12 * px + m22 * py + m42; double w = m14 * px + m24 * py + m44; @@ -2254,6 +2240,23 @@ public float getMinScale(float px, float py) { return computeMinScale(dfdu, dfdv, dgdu, dgdv); } + /** + * Returns the minimum scaling factor of this matrix by decomposing the scaling and + * shearing elements. When this matrix has perspective, the scaling factor is specific + * to the given point p.
+ * Returns -1 if scale factor overflows. + * + * @param px the x-coord of point + * @param py the y-coord of point + * @return minimum scale factor + */ + public float getMinScale(float px, float py) { + if (!hasPerspective()) { + return getMinScale(); + } + return computeMinScale(px, py); + } + /** * Returns the maximum scaling factor of this matrix by decomposing the scaling and * shearing elements. When this matrix has perspective, the scaling factor is specific @@ -2347,6 +2350,53 @@ public float differentialAreaScale(float px, float py) { return (float) (Math.abs(detJ * denom)); } + /** + * Return the minimum distance needed to move in local (pre-transform) space to ensure that the + * transformed coordinates are at least 1px away from the original mapped point. This minimum + * distance is specific to the given local 'bounds' since the scale factors change with + * perspective. + *

+ * If the bounds will be clipped by the w=0 plane or otherwise is ill-conditioned, this will + * return positive infinity. + */ + public float localAARadius(Rect2fc bounds) { + return localAARadius(bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); + } + + /** + * Return the minimum distance needed to move in local (pre-transform) space to ensure that the + * transformed coordinates are at least 1px away from the original mapped point. This minimum + * distance is specific to the given local 'bounds' since the scale factors change with + * perspective. + *

+ * If the bounds will be clipped by the w=0 plane or otherwise is ill-conditioned, this will + * return positive infinity. + */ + public float localAARadius(float left, float top, float right, float bottom) { + float min; + if ((getType() & kPerspective_Mask) == 0) { + min = getMinScale(); + } else { + // Calculate the minimum scale factor over the 4 corners of the bounding box + float tl = computeMinScale(left, top); + float tr = computeMinScale(right, top); + float br = computeMinScale(right, bottom); + float bl = computeMinScale(left, bottom); + min = MathUtil.min(tl, tr, br, bl); + } + + // Moving 1 from 'p' before transforming will move at least 'min' and at most 'max' from + // the transformed point. Thus moving between [1/max, 1/min] pre-transformation means post + // transformation moves between [1,max/min] so using 1/min as the local AA radius ensures that + // the post-transformed point is at least 1px away from the original. + float aaRadius = 1.0f / min; + if (Float.isFinite(aaRadius)) { // check Inf and NaN + return aaRadius; + } else { + return Float.POSITIVE_INFINITY; + } + } + /** * Sets matrix to scale and translate src rect to dst rect. Returns false if * src is empty, and sets matrix to identity. Returns true if dst is empty, diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrix4.java b/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrix4.java index 2e9aef92..ef834b25 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrix4.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrix4.java @@ -48,6 +48,8 @@ @SuppressWarnings("unused") public non-sealed class Matrix4 implements Matrix4c, Cloneable { + private static final Matrix4 IDENTITY = new Matrix4(); + // sequential matrix elements, m(ij) (row, column) // directly using primitives will be faster than array in Java (before Vector API) // [m11 m12 m13 m14] @@ -72,11 +74,10 @@ public non-sealed class Matrix4 implements Matrix4c, Cloneable { public float m44; /** - * Create a zero matrix. - * - * @see #identity() + * Create a new identity matrix. */ public Matrix4() { + m11 = m22 = m33 = m44 = 1.0f; } /** @@ -106,20 +107,18 @@ public Matrix4(@Nonnull float... a) { * @return a copy of the matrix */ @Nonnull - public static Matrix4 copy(@Nullable Matrix4 m) { - return m == null ? identity() : m.clone(); + public static Matrix4 copy(@Nullable Matrix4c m) { + return m == null ? new Matrix4() : m.clone(); } /** - * Create a new identity matrix. + * Returns a read-only identity matrix. * * @return an identity matrix */ @Nonnull - public static Matrix4 identity() { - final Matrix4 m = new Matrix4(); - m.m11 = m.m22 = m.m33 = m.m44 = 1.0f; - return m; + public static Matrix4c identity() { + return IDENTITY; } /** diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrixc.java b/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrixc.java index 55114fa6..43e6e1a7 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrixc.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/core/Matrixc.java @@ -540,6 +540,28 @@ default void mapPoints(float[] src, float[] dst, int count) { */ float differentialAreaScale(float px, float py); + /** + * Return the minimum distance needed to move in local (pre-transform) space to ensure that the + * transformed coordinates are at least 1px away from the original mapped point. This minimum + * distance is specific to the given local 'bounds' since the scale factors change with + * perspective. + *

+ * If the bounds will be clipped by the w=0 plane or otherwise is ill-conditioned, this will + * return positive infinity. + */ + float localAARadius(Rect2fc bounds); + + /** + * Return the minimum distance needed to move in local (pre-transform) space to ensure that the + * transformed coordinates are at least 1px away from the original mapped point. This minimum + * distance is specific to the given local 'bounds' since the scale factors change with + * perspective. + *

+ * If the bounds will be clipped by the w=0 plane or otherwise is ill-conditioned, this will + * return positive infinity. + */ + float localAARadius(float left, float top, float right, float bottom); + /** * Returns true if all elements of the matrix are finite. Returns false if any * element is infinity, or NaN. @@ -556,4 +578,7 @@ default void mapPoints(float[] src, float[] dst, int count) { @Override String toString(); + + @Nonnull + Matrix clone(); } diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/core/Quaternion.java b/external/Arc3D/src/main/java/icyllis/arc3d/core/Quaternion.java index 51a91feb..a75451a6 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/core/Quaternion.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/core/Quaternion.java @@ -730,7 +730,7 @@ public Matrix3 toMatrix3() { public Matrix4 toMatrix4() { final float sq = lengthSq(); if (sq < 1.0e-6f) { - return Matrix4.identity(); + return new Matrix4(); } final float is; if (MathUtil.isApproxEqual(sq, 1.0f)) { diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/ClipStack.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/ClipStack.java index 15d12a81..fdf2831d 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/ClipStack.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/ClipStack.java @@ -97,7 +97,7 @@ public Collection elements() { private final ClipElement mTmpElement = new ClipElement(); - public void clipRect(@Nullable Matrix4c viewMatrix, + public void clipRect(@Nullable Matrixc viewMatrix, @Nonnull Rect2fc localRect, int clipOp) { clip(mTmpElement.init( @@ -317,7 +317,7 @@ public boolean prepareForDraw(Draw draw, assert elementsForMask.isEmpty(); mTmpDraw.init( - shapeInDeviceSpace ? Matrix4.identity() : draw.mTransform, + shapeInDeviceSpace ? Matrix.identity() : draw.mTransform, shapeBounds, drawBounds ); @@ -419,7 +419,7 @@ public interface ClipGeometry { Rect2fc shape(); - Matrix4c viewMatrix(); + Matrixc viewMatrix(); Rect2fc outerBounds(); @@ -568,17 +568,17 @@ public static class Element { // owned memory final Rect2f mShape; - final Matrix4 mViewMatrix; + final Matrix mViewMatrix; int mClipOp; Element() { mShape = new Rect2f(); - mViewMatrix = new Matrix4(); + mViewMatrix = new Matrix(); } - Element(Rect2fc shape, Matrix4c viewMatrix, int clipOp) { + Element(Rect2fc shape, Matrixc viewMatrix, int clipOp) { mShape = new Rect2f(shape); - mViewMatrix = new Matrix4(viewMatrix); + mViewMatrix = new Matrix(viewMatrix); mClipOp = clipOp; } @@ -590,7 +590,7 @@ public Rect2fc shape() { // local to device // do not modify - public Matrix4c viewMatrix() { + public Matrixc viewMatrix() { return mViewMatrix; } @@ -614,7 +614,7 @@ static final class ClipElement extends Element implements ClipGeometry { boolean mInverseFill; // cached inverse of fLocalToDevice for contains() optimization - final Matrix4 mInverseViewMatrix = new Matrix4(); + final Matrix mInverseViewMatrix = new Matrix(); // Device space bounds. These bounds are not snapped to pixels with the assumption that if // a relation (intersects, contains, etc.) is true for the bounds it will be true for the @@ -668,7 +668,7 @@ public void set(ClipElement e) { public ClipElement init(Rect2ic deviceBounds, Rect2fc shape, boolean inverseFill, - Matrix4c viewMatrix, + Matrixc viewMatrix, int clipOp) { mShape.set(shape); mViewMatrix.set(viewMatrix); @@ -1108,8 +1108,8 @@ public Rect2fc shape() { } @Override - public Matrix4c viewMatrix() { - return Matrix4.identity(); + public Matrixc viewMatrix() { + return Matrix.identity(); } public Rect2fc outerBounds() { @@ -1438,11 +1438,11 @@ public Rect2ic scissor(Rect2ic deviceBounds, Rect2fc drawBounds) { static final class ClipDraw implements ClipGeometry { - final Matrix4 mViewMatrix = new Matrix4(); + final Matrix mViewMatrix = new Matrix(); final Rect2f mShape = new Rect2f(); final Rect2f mDrawBounds = new Rect2f(); - public ClipDraw init(Matrix4c viewMatrix, + public ClipDraw init(Matrixc viewMatrix, Rect2fc shape, Rect2fc drawBounds) { mViewMatrix.set(viewMatrix); @@ -1462,7 +1462,7 @@ public Rect2fc shape() { } @Override - public Matrix4 viewMatrix() { + public Matrixc viewMatrix() { return mViewMatrix; } diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/Draw.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/Draw.java index 6ce7aaf6..86ee9d3b 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/Draw.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/Draw.java @@ -38,7 +38,7 @@ public final class Draw implements AutoCloseable { /** * This matrix transforms geometry's local space to device space. */ - public Matrix4c mTransform; + public Matrixc mTransform; public Object mGeometry; /** * Clip params (immutable), set by {@link ClipStack}. diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/DrawPass.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/DrawPass.java index ecdfabc8..340c0a60 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/DrawPass.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/DrawPass.java @@ -161,13 +161,6 @@ public static DrawPass make(RecordingContext context, textureDataGatherer.reset(); - // collect geometry data - uniformDataGatherer.reset(); - // first add the 2D orthographic projection - uniformDataGatherer.write4f(projX, projY, projZ, projW); - step.writeUniformsAndTextures(context, draw, uniformDataGatherer, textureDataGatherer); - var geometryUniforms = uniformDataCache.insert(uniformDataGatherer.finish()); - // collect fragment data and pipeline key uniformDataGatherer.reset(); if (step.performsShading() && draw.mPaintParams != null) { @@ -187,14 +180,22 @@ public static DrawPass make(RecordingContext context, } var fragmentUniforms = uniformDataCache.insert(uniformDataGatherer.finish()); - // geometry texture samplers and then fragment texture samplers - // we build shader code and set binding points in this order as well - var textures = textureDataGatherer.finish(); - int pipelineIndex = pipelineToIndex.computeIfAbsent( lookupDesc.set(step, paintParamsKeyBuilder, finalBlendMode, useFastSolidColor), pipelineAccumulator); + // collect geometry data + uniformDataGatherer.reset(); + // first add the 2D orthographic projection + uniformDataGatherer.write4f(projX, projY, projZ, projW); + step.writeUniformsAndTextures(context, draw, uniformDataGatherer, textureDataGatherer, + lookupDesc.mayRequireLocalCoords()); + var geometryUniforms = uniformDataCache.insert(uniformDataGatherer.finish()); + + // geometry texture samplers and then fragment texture samplers + // we build shader code and set binding points in this order as well + var textures = textureDataGatherer.finish(); + var geometryUniformIndex = geometryUniformTracker.trackUniforms( pipelineIndex, geometryUniforms @@ -230,7 +231,7 @@ public static DrawPass make(RecordingContext context, Rect2ic lastScissor = new Rect2i(0, 0, deviceInfo.width(), deviceInfo.height()); int lastPipelineIndex = INVALID_INDEX; - float[] cachedSolidColor = new float[4]; + float[] tmpSolidColor = new float[4]; commandList.setScissor(lastScissor, surfaceHeight, surfaceOrigin); @@ -295,14 +296,16 @@ public static DrawPass make(RecordingContext context, } float[] solidColor = null; - if (step.performsShading() && draw.mPaintParams != null) { - if (step.handlesSolidColor() && - draw.mPaintParams.getSolidColor(deviceInfo, cachedSolidColor)) { - solidColor = cachedSolidColor; - } + var pipelineDesc = indexToPipeline.get(pipelineIndex); + if (pipelineDesc.usesFastSolidColor()) { + assert draw.mPaintParams != null; + boolean res = draw.mPaintParams.getSolidColor(deviceInfo, tmpSolidColor); + assert res; + solidColor = tmpSolidColor; } - step.writeMesh(drawWriter, draw, solidColor); + step.writeMesh(drawWriter, draw, solidColor, + pipelineDesc.mayRequireLocalCoords()); if (bufferManager.hasMappingFailed()) { return null; diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/GeometryStep.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/GeometryStep.java index f48bc5bd..cad22367 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/GeometryStep.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/GeometryStep.java @@ -117,7 +117,7 @@ protected static VertexInputLayout.Attribute makeColorAttribute(String name, boo * any uniform values. *

* See {@link #emitFragmentColorCode(Formatter, String)} and - * {@link #writeMesh(MeshDrawWriter, Draw, float[])}. + * {@link #writeMesh(MeshDrawWriter, Draw, float[], boolean)}. *

* Not compatible with {@link #FLAG_EMIT_PRIMITIVE_COLOR}. */ @@ -430,10 +430,12 @@ public final void appendAttributesToKey(@Nonnull KeyBuilder b) { @Nonnull public abstract ProgramImpl makeProgramImpl(ShaderCaps caps); - public void emitVaryings(VaryingHandler varyingHandler) { + public void emitVaryings(VaryingHandler varyingHandler, + boolean usesFastSolidColor) { } - public void emitUniforms(UniformHandler uniformHandler) { + public void emitUniforms(UniformHandler uniformHandler, + boolean mayRequireLocalCoords) { } public void emitSamplers(UniformHandler uniformHandler) { @@ -447,7 +449,8 @@ public void emitSamplers(UniformHandler uniformHandler) { */ public void emitVertexGeomCode(Formatter vs, @Nonnull String worldPosVar, - @Nullable String localPosVar) { + @Nullable String localPosVar, + boolean usesFastSolidColor) { } /** @@ -469,12 +472,15 @@ public void emitFragmentColorCode(Formatter fs, String outputColor) { public void emitFragmentCoverageCode(Formatter fs, String outputCoverage) { } - public void writeMesh(MeshDrawWriter writer, Draw draw, @Nullable float[] solidColor) { + public void writeMesh(MeshDrawWriter writer, Draw draw, + @Nullable float[] solidColor, + boolean mayRequireLocalCoords) { } public void writeUniformsAndTextures(RecordingContext context, Draw draw, UniformDataGatherer uniformDataGatherer, - TextureDataGatherer textureDataGatherer) { + TextureDataGatherer textureDataGatherer, + boolean mayRequireLocalCoords) { } /** diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/GraniteDevice.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/GraniteDevice.java index 8f9fbc0e..2a0bad25 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/GraniteDevice.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/GraniteDevice.java @@ -238,7 +238,7 @@ public ClipStack getClipStack() { @Override public void clipRect(Rect2fc rect, int clipOp, boolean doAA) { - mClipStack.clipRect(getLocalToDevice(), rect, clipOp); + mClipStack.clipRect(getLocalToDevice33(), rect, clipOp); } @Override @@ -321,19 +321,19 @@ public void drawLine(float x0, float y0, float x1, float y1, @Paint.Cap int cap, float width, Paint paint) { var shape = new SimpleShape(); shape.setLine(x0, y0, x1, y1, cap, width); - drawGeometry(getLocalToDevice(), shape, SimpleShape::getBounds, paint, + drawGeometry(getLocalToDevice33(), shape, SimpleShape::getBounds, paint, mRC.getRendererProvider().getSimpleBox(paint.isAntiAlias()), null); } @Override public void drawRect(Rect2fc r, Paint paint) { - drawGeometry(getLocalToDevice(), new SimpleShape(r), SimpleShape::getBounds, paint, + drawGeometry(getLocalToDevice33(), new SimpleShape(r), SimpleShape::getBounds, paint, mRC.getRendererProvider().getSimpleBox(paint.isAntiAlias()), null); } @Override public void drawRoundRect(RoundRect rr, Paint paint) { - drawGeometry(getLocalToDevice(), new SimpleShape(rr), SimpleShape::getBounds, paint, + drawGeometry(getLocalToDevice33(), new SimpleShape(rr), SimpleShape::getBounds, paint, mRC.getRendererProvider().getSimpleBox(paint.isAntiAlias()), null); } @@ -341,7 +341,7 @@ public void drawRoundRect(RoundRect rr, Paint paint) { public void drawCircle(float cx, float cy, float radius, Paint paint) { var shape = new SimpleShape(); shape.setEllipseXY(cx, cy, radius, radius); - drawGeometry(getLocalToDevice(), shape, SimpleShape::getBounds, paint, + drawGeometry(getLocalToDevice33(), shape, SimpleShape::getBounds, paint, mRC.getRendererProvider().getSimpleBox(paint.isAntiAlias()), null); } @@ -355,7 +355,7 @@ public void drawArc(float cx, float cy, float radius, float startAngle, case Paint.CAP_SQUARE -> ArcShape.kArcSquare_Type; default -> throw new AssertionError(); }; - drawGeometry(getLocalToDevice(), shape, ArcShape::getBounds, paint, + drawGeometry(getLocalToDevice33(), shape, ArcShape::getBounds, paint, mRC.getRendererProvider().getArc(shape.mType), null); } @@ -364,7 +364,7 @@ public void drawPie(float cx, float cy, float radius, float startAngle, float sweepAngle, Paint paint) { var shape = new ArcShape(cx, cy, radius, startAngle, sweepAngle, 0); shape.mType = ArcShape.kPie_Type; - drawGeometry(getLocalToDevice(), shape, ArcShape::getBounds, paint, + drawGeometry(getLocalToDevice33(), shape, ArcShape::getBounds, paint, mRC.getRendererProvider().getArc(shape.mType), null); } @@ -373,7 +373,7 @@ public void drawChord(float cx, float cy, float radius, float startAngle, float sweepAngle, Paint paint) { var shape = new ArcShape(cx, cy, radius, startAngle, sweepAngle, 0); shape.mType = ArcShape.kChord_Type; - drawGeometry(getLocalToDevice(), shape, ArcShape::getBounds, paint, + drawGeometry(getLocalToDevice33(), shape, ArcShape::getBounds, paint, mRC.getRendererProvider().getArc(shape.mType), null); } @@ -428,7 +428,7 @@ protected void onDrawGlyphRunList(Canvas canvas, @Override public void drawVertices(Vertices vertices, @SharedPtr Blender blender, Paint paint) { - drawGeometry(getLocalToDevice(), vertices, Vertices::getBounds, paint, + drawGeometry(getLocalToDevice33(), vertices, Vertices::getBounds, paint, mRC.getRendererProvider().getVertices( vertices.getVertexMode(), vertices.hasColors(), vertices.hasTexCoords()), blender); // move @@ -455,13 +455,18 @@ public void drawAtlasSubRun(SubRunContainer.AtlasSubRun subRun, break; } if (glyphsPrepared > 0) { - SubRunData subRunData = new SubRunData(subRun, - getLocalToDevice(), originX, originY, - subRunCursor, glyphsPrepared); // subRunToDevice is our "localToDevice", // as sub run's coordinates are returned in sub run's space - Matrix4 subRunToDevice = new Matrix4(getLocalToDevice()); - subRunToDevice.preConcat2D(subRunData.getSubRunToLocal()); + Matrix subRunToLocal = new Matrix(); + Matrix subRunToDevice = new Matrix(); + int filter = subRun.getMatrixAndFilter( + getLocalToDevice33(), + originX, originY, + subRunToLocal, + subRunToDevice); + SubRunData subRunData = new SubRunData(subRun, + subRunToLocal, filter, + subRunCursor, glyphsPrepared); subRunPaint.set(paint); if (subRun.getMaskFormat() == Engine.MASK_FORMAT_ARGB) { @@ -531,7 +536,7 @@ private static boolean paint_depends_on_dst(PaintParams paintParams) { paintParams.getPrimitiveBlender()); } - public void drawGeometry(Matrix4c localToDevice, + public void drawGeometry(Matrixc localToDevice, GEO geometry, BiConsumer boundsFn, Paint paint, diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/GraphicsPipelineDesc.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/GraphicsPipelineDesc.java index bff467d0..965b6e72 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/GraphicsPipelineDesc.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/GraphicsPipelineDesc.java @@ -78,6 +78,12 @@ public boolean usesFastSolidColor() { return mUseFastSolidColor; } + public boolean mayRequireLocalCoords() { + return !mUseFastSolidColor && + (mPaintParamsKey.size() != 1 || + mPaintParamsKey.get(0) != FragmentStage.kSolidColorShader_BuiltinStageID); + } + private FragmentNode createNode(ShaderCodeSource codeSource, StringBuilder label, int[] currentStageIndex) { diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/PipelineBuilder.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/PipelineBuilder.java index bfbe0c46..3d9d8e48 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/PipelineBuilder.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/PipelineBuilder.java @@ -101,7 +101,7 @@ private void getNodeUniforms(FragmentNode node) { public PipelineDesc.GraphicsPipelineInfo build() { - mDesc.geomStep().emitVaryings(mVaryings); + mDesc.geomStep().emitVaryings(mVaryings, mDesc.usesFastSolidColor()); if (needsLocalCoords()) { mVaryings.addVarying(LOCAL_COORDS_VARYING_NAME, SLDataType.kFloat2); } @@ -113,7 +113,7 @@ public PipelineDesc.GraphicsPipelineInfo build() { SLDataType.kFloat4, UniformHandler.PROJECTION_NAME, -1); - mDesc.geomStep().emitUniforms(mGeometryUniforms); + mDesc.geomStep().emitUniforms(mGeometryUniforms, mDesc.mayRequireLocalCoords()); mDesc.geomStep().emitSamplers(mFragmentUniforms); for (var root : mRootNodes) { @@ -215,7 +215,8 @@ public void buildVertexShader() { // shader will define the world pos local variable mDesc.geomStep().emitVertexGeomCode(vs, WORLD_POS_VAR_NAME, - needsLocalCoords() ? LOCAL_COORDS_VARYING_NAME : null); + needsLocalCoords() ? LOCAL_COORDS_VARYING_NAME : null, + mDesc.usesFastSolidColor()); // map into clip space // remember to preserve the painter's depth in depth buffer, it must be first multiplied by w, diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/SubRunContainer.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/SubRunContainer.java index c6341292..612985f1 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/SubRunContainer.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/SubRunContainer.java @@ -145,19 +145,51 @@ public void fillInstanceData(MeshDrawWriter writer, writer.endAppender(); } + /** + * @see icyllis.arc3d.granite.geom.RasterTextStep + */ + public void fillInstanceData(MeshDrawWriter writer, + int offset, int count, + float offsetX, float offsetY, + float depth) { + writer.beginInstances(null, null, 4); + long instanceData = writer.append(count); + + var glyphs = mGlyphs.getGlyphs(); + var positions = mPositions; + for (int i = offset, j = offset << 1, e = offset + count; i < e; i += 1, j += 2) { + var glyph = glyphs[i]; + // xy pos + MemoryUtil.memPutFloat(instanceData, positions[j] + offsetX); + MemoryUtil.memPutFloat(instanceData + 4, positions[j | 1] + offsetY); + // uv pos + MemoryUtil.memPutShort(instanceData + 8, glyph.u1); + MemoryUtil.memPutShort(instanceData + 10, glyph.v1); + // size + MemoryUtil.memPutShort(instanceData + 12, glyph.width()); + MemoryUtil.memPutShort(instanceData + 14, glyph.height()); + // painter's depth + MemoryUtil.memPutFloat(instanceData + 16, depth); + instanceData += 20; + } + + writer.endAppender(); + } + public Rect2fc getBounds() { return mCreationBounds; } /** - * Compute sub-run-to-local matrix with the given origin and store - * in outSubRunToLocal. Compute filter based on - * local-to-device matrix and origin, and return it. + * Compute sub-run-to-local matrix and sub-run-to-device with the + * given origin. Compute filter based on local-to-device matrix and + * origin, and return it. */ @SuppressWarnings("AssertWithSideEffects") - public int getSubRunToLocalAndFilter(Matrix4c localToDevice, - float originX, float originY, - Matrix outSubRunToLocal) { + public int getMatrixAndFilter(Matrixc localToDevice, + float originX, float originY, + Matrix outSubRunToLocal, + Matrix outSubRunToDevice) { // the creation matrix has no perspective if (mCreationMatrix.invert(outSubRunToLocal)) { outSubRunToLocal.postTranslate(originX, originY); @@ -165,27 +197,30 @@ public int getSubRunToLocalAndFilter(Matrix4c localToDevice, } else { outSubRunToLocal.setIdentity(); } - if (mCanDrawDirect) { - boolean compatible = !localToDevice.hasPerspective() && - localToDevice.m11() == mCreationMatrix.m11() && - localToDevice.m12() == mCreationMatrix.m12() && - localToDevice.m21() == mCreationMatrix.m21() && - localToDevice.m22() == mCreationMatrix.m22(); - if (compatible) { - // compatible means only the difference is translation - float mappedOriginX = localToDevice.m11() * originX + - localToDevice.m21() * originY + localToDevice.m41(); - float mappedOriginY = localToDevice.m12() * originX + - localToDevice.m22() * originY + localToDevice.m42(); - // creation matrix has no perspective, so translate vector is its origin - float offsetX = mappedOriginX - mCreationMatrix.getTranslateX(); - float offsetY = mappedOriginY - mCreationMatrix.getTranslateY(); - if (offsetX == (float) Math.floor(offsetX) && - offsetY == (float) Math.floor(offsetY)) { - // integer translate - return SamplerDesc.FILTER_NEAREST; - } + boolean compatible = !localToDevice.hasPerspective() && + localToDevice.m11() == mCreationMatrix.m11() && + localToDevice.m12() == mCreationMatrix.m12() && + localToDevice.m21() == mCreationMatrix.m21() && + localToDevice.m22() == mCreationMatrix.m22(); + if (compatible) { + // compatible means only the difference is translation + float mappedOriginX = localToDevice.m11() * originX + + localToDevice.m21() * originY + localToDevice.m41(); + float mappedOriginY = localToDevice.m12() * originX + + localToDevice.m22() * originY + localToDevice.m42(); + // creation matrix has no perspective, so translate vector is its origin + float offsetX = mappedOriginX - mCreationMatrix.getTranslateX(); + float offsetY = mappedOriginY - mCreationMatrix.getTranslateY(); + outSubRunToDevice.setTranslate(offsetX, offsetY); + if (mCanDrawDirect && + offsetX == (float) Math.floor(offsetX) && + offsetY == (float) Math.floor(offsetY)) { + // integer translate in device space + return SamplerDesc.FILTER_NEAREST; } + } else { + outSubRunToDevice.set(localToDevice); + outSubRunToDevice.preConcat(outSubRunToLocal); } return SamplerDesc.FILTER_LINEAR; } diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/SubRunData.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/SubRunData.java index e00b6a33..0d572b6d 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/SubRunData.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/SubRunData.java @@ -29,17 +29,13 @@ public class SubRunData { private final int mStartGlyphIndex; private final int mGlyphCount; + // subRunToLocal is affine, no copy public SubRunData(SubRunContainer.AtlasSubRun subRun, - Matrix4c localToDevice, - float originX, float originY, + Matrix subRunToLocal, int filter, int startGlyphIndex, int glyphCount) { mSubRun = subRun; - var subRunToLocal = new Matrix(); - mFilter = subRun.getSubRunToLocalAndFilter( - localToDevice, - originX, originY, - subRunToLocal); mSubRunToLocal = subRunToLocal; + mFilter = filter; mStartGlyphIndex = startGlyphIndex; mGlyphCount = glyphCount; } @@ -48,10 +44,14 @@ public SubRunContainer.AtlasSubRun getSubRun() { return mSubRun; } + // affine matrix public Matrixc getSubRunToLocal() { return mSubRunToLocal; } + /** + * @see icyllis.arc3d.engine.SamplerDesc + */ public int getFilter() { return mFilter; } diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/SurfaceDrawContext.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/SurfaceDrawContext.java index cb13fc53..d3abaeeb 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/SurfaceDrawContext.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/SurfaceDrawContext.java @@ -40,7 +40,7 @@ public final class SurfaceDrawContext implements AutoCloseable { private TaskList mDrawTaskList; - private Matrix4 mLastTransform; // for deduplication + private Matrix mLastTransform; // for deduplication private final ObjectArrayList mPendingDraws = new ObjectArrayList<>(); private int mNumSteps; @@ -297,8 +297,8 @@ public DrawTask snapDrawTask(RecordingContext context) { return task; } - private Matrix4c getStableTransform(Matrix4c transform) { - Matrix4 last = mLastTransform; + private Matrixc getStableTransform(Matrixc transform) { + Matrix last = mLastTransform; if (!transform.equals(last)) { var copy = transform.clone(); mLastTransform = copy; diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/UniformDataGatherer.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/UniformDataGatherer.java index cdfc0967..60b57d6b 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/UniformDataGatherer.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/UniformDataGatherer.java @@ -198,11 +198,6 @@ public void writeMatrix3f(int offset, float[] value) { memPutInt(dst + 44, 0); } - public void writeMatrix4fAs2D(Matrix4c matrix) { - long dst = append(16, 48); - matrix.storeAs2DAligned(dst); - } - public void writeMatrix4f(Matrix4c matrix) { long dst = append(16, 64); matrix.store(dst); diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/AnalyticArcStep.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/AnalyticArcStep.java index 63280446..4be7d7fe 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/AnalyticArcStep.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/AnalyticArcStep.java @@ -113,7 +113,7 @@ public ProgramImpl makeProgramImpl(ShaderCaps caps) { } @Override - public void emitVaryings(VaryingHandler varyingHandler) { + public void emitVaryings(VaryingHandler varyingHandler, boolean usesFastSolidColor) { // the local coords, center point is (0,0) varyingHandler.addVarying("f_ArcEdge", SLDataType.kFloat2); // cos(sweepAngle), sin(sweepAngle) @@ -128,15 +128,18 @@ public void emitVaryings(VaryingHandler varyingHandler) { varyingHandler.addVarying("f_Radii", SLDataType.kFloat3, VaryingHandler.kCanBeFlat_Interpolation); } - // solid color - varyingHandler.addVarying("f_Color", SLDataType.kFloat4, - VaryingHandler.kCanBeFlat_Interpolation); + if (usesFastSolidColor) { + // solid color + varyingHandler.addVarying("f_Color", SLDataType.kFloat4, + VaryingHandler.kCanBeFlat_Interpolation); + } } @Override public void emitVertexGeomCode(Formatter vs, @Nonnull String worldPosVar, - @Nullable String localPosVar) { + @Nullable String localPosVar, + boolean usesFastSolidColor) { // {(-1,-1), (-1,1), (1,-1), (1,1)} // corner selector, CCW vs.format("vec2 position = vec2(gl_VertexID >> 1, gl_VertexID & 1) * 2.0 - 1.0;\n"); @@ -181,8 +184,10 @@ public void emitVertexGeomCode(Formatter vs, """, RADII.name(), FLAGS_AND_DEPTH.name(), "f_ArcEdge", "f_Span", "f_Radii"); } - // setup pass through color - vs.format("%s = %s;\n", "f_Color", SOLID_COLOR.name()); + if (usesFastSolidColor) { + // setup pass through color + vs.format("%s = %s;\n", "f_Color", SOLID_COLOR.name()); + } // setup position vs.format(""" @@ -277,7 +282,9 @@ public void emitFragmentCoverageCode(Formatter fs, String outputCoverage) { } @Override - public void writeMesh(MeshDrawWriter writer, Draw draw, @Nullable float[] solidColor) { + public void writeMesh(MeshDrawWriter writer, Draw draw, + @Nullable float[] solidColor, + boolean mayRequireLocalCoords) { writer.beginInstances(null, null, 4); long instanceData = writer.append(1); if (solidColor != null) { @@ -320,7 +327,7 @@ public void writeMesh(MeshDrawWriter writer, Draw draw, @Nullable float[] solidC int join = (mType == ArcShape.kArc_Type || mType == ArcShape.kArcSquare_Type) && draw.mJoinLimit >= MathUtil.SQRT2 ? 16 : 0; MemoryUtil.memPutInt(instanceData + 44, (draw.getDepth() << 16) | (join | dir)); - draw.mTransform.storeAs2D(instanceData + 48); + draw.mTransform.store(instanceData + 48); writer.endAppender(); } } diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/AnalyticSimpleBoxStep.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/AnalyticSimpleBoxStep.java index 452b0845..6820680b 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/AnalyticSimpleBoxStep.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/AnalyticSimpleBoxStep.java @@ -111,7 +111,7 @@ public ProgramImpl makeProgramImpl(ShaderCaps caps) { } @Override - public void emitVaryings(VaryingHandler varyingHandler) { + public void emitVaryings(VaryingHandler varyingHandler, boolean usesFastSolidColor) { // the local coords, center point is (0,0) varyingHandler.addVarying("f_RectEdge", SLDataType.kFloat2); // half width, half height @@ -120,19 +120,21 @@ public void emitVaryings(VaryingHandler varyingHandler) { // corner radius, stroke radius, stroke offset varyingHandler.addVarying("f_Radii", SLDataType.kFloat3, VaryingHandler.kCanBeFlat_Interpolation); - // solid color - varyingHandler.addVarying("f_Color", SLDataType.kFloat4, - VaryingHandler.kCanBeFlat_Interpolation); + if (usesFastSolidColor) { + // solid color + varyingHandler.addVarying("f_Color", SLDataType.kFloat4, + VaryingHandler.kCanBeFlat_Interpolation); + } } @Override - public void emitUniforms(UniformHandler uniformHandler) { + public void emitUniforms(UniformHandler uniformHandler, boolean mayRequireLocalCoords) { } @Override public void emitVertexGeomCode(Formatter vs, @Nonnull String worldPosVar, - @Nullable String localPosVar) { + @Nullable String localPosVar, boolean usesFastSolidColor) { // {(-1,-1), (-1,1), (1,-1), (1,1)} // corner selector, CCW vs.format("vec2 position = vec2(gl_VertexID >> 1, gl_VertexID & 1) * 2.0 - 1.0;\n"); @@ -177,8 +179,10 @@ public void emitVertexGeomCode(Formatter vs, } """, RADII.name(), FLAGS_AND_DEPTH.name(), "f_RectEdge", "f_Size", "f_Radii"); - // setup pass through color - vs.format("%s = %s;\n", "f_Color", SOLID_COLOR.name()); + if (usesFastSolidColor) { + // setup pass through color + vs.format("%s = %s;\n", "f_Color", SOLID_COLOR.name()); + } // setup position vs.format(""" @@ -242,7 +246,9 @@ public void emitFragmentCoverageCode(Formatter fs, String outputCoverage) { } @Override - public void writeMesh(MeshDrawWriter writer, Draw draw, @Nullable float[] solidColor) { + public void writeMesh(MeshDrawWriter writer, Draw draw, + @Nullable float[] solidColor, + boolean mayRequireLocalCoords) { writer.beginInstances(null, null, 4); long instanceData = writer.append(1); if (solidColor != null) { @@ -278,7 +284,7 @@ public void writeMesh(MeshDrawWriter writer, Draw draw, @Nullable float[] solidC // only butt/square line and rect can have miter join int join = (type == 2 || shape.isRect()) && draw.mJoinLimit >= MathUtil.SQRT2 ? 16 : 0; MemoryUtil.memPutInt(instanceData + 44, (draw.getDepth() << 16) | (join | dir | type)); - draw.mTransform.storeAs2D(instanceData + 48); + draw.mTransform.store(instanceData + 48); writer.endAppender(); } } diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/RasterTextStep.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/RasterTextStep.java index 724609b4..c9c61272 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/RasterTextStep.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/RasterTextStep.java @@ -91,18 +91,21 @@ public ProgramImpl makeProgramImpl(ShaderCaps caps) { } @Override - public void emitVaryings(VaryingHandler varyingHandler) { + public void emitVaryings(VaryingHandler varyingHandler, boolean usesFastSolidColor) { + assert !usesFastSolidColor; varyingHandler.addVarying("f_TexCoords", SLDataType.kFloat2); } @Override - public void emitUniforms(UniformHandler uniformHandler) { + public void emitUniforms(UniformHandler uniformHandler, boolean mayRequireLocalCoords) { // may have perspective uniformHandler.addUniform(Engine.ShaderFlags.kVertex, SLDataType.kFloat3x3, "u_SubRunToDevice", -1); - // no perspective - uniformHandler.addUniform(Engine.ShaderFlags.kVertex, - SLDataType.kFloat3x3, "u_SubRunToLocal", -1); + if (mayRequireLocalCoords) { + // no perspective + uniformHandler.addUniform(Engine.ShaderFlags.kVertex, + SLDataType.kFloat3x3, "u_SubRunToLocal", -1); + } uniformHandler.addUniform(Engine.ShaderFlags.kVertex, SLDataType.kFloat2, "u_InvAtlasSize", -1); } @@ -116,7 +119,9 @@ public void emitSamplers(UniformHandler uniformHandler) { @Override public void emitVertexGeomCode(Formatter vs, @Nonnull String worldPosVar, - @Nullable String localPosVar) { + @Nullable String localPosVar, + boolean usesFastSolidColor) { + assert !usesFastSolidColor; // {(0,0), (0,1), (1,0), (1,1)} // corner selector, CCW vs.format("vec2 position = vec2(gl_VertexID >> 1, gl_VertexID & 1) * vec2(%s);\n", @@ -159,7 +164,7 @@ public void emitFragmentColorCode(Formatter fs, String outputColor) { public void emitFragmentCoverageCode(Formatter fs, String outputCoverage) { // A8 and LCD only if (mMaskFormat == Engine.MASK_FORMAT_A8) { - // A8 is always backed by R8 texture + // A8 is always backed by R8 texture, colors are premultiplied fs.format("%s = texture(%s, %s).rrrr;\n", outputCoverage, "u_GlyphAtlas", "f_TexCoords"); } else { fs.format("%s = texture(%s, %s);\n", outputCoverage, "u_GlyphAtlas", "f_TexCoords"); @@ -167,21 +172,38 @@ public void emitFragmentCoverageCode(Formatter fs, String outputCoverage) { } @Override - public void writeMesh(MeshDrawWriter writer, Draw draw, @Nullable float[] solidColor) { + public void writeMesh(MeshDrawWriter writer, Draw draw, + @Nullable float[] solidColor, + boolean mayRequireLocalCoords) { assert solidColor == null; var subRunData = (SubRunData) draw.mGeometry; - subRunData.getSubRun().fillInstanceData( - writer, - subRunData.getStartGlyphIndex(), - subRunData.getGlyphCount(), - draw.getDepthAsFloat() - ); + // SubRunToDevice + if (!mayRequireLocalCoords && draw.mTransform.isTranslate()) { + // if local coordinates are not required and SubRunToDevice is translation only, + // we can extract translation to XY and reduce uniform binding changes + subRunData.getSubRun().fillInstanceData( + writer, + subRunData.getStartGlyphIndex(), + subRunData.getGlyphCount(), + draw.mTransform.getTranslateX(), + draw.mTransform.getTranslateY(), + draw.getDepthAsFloat() + ); + } else { + subRunData.getSubRun().fillInstanceData( + writer, + subRunData.getStartGlyphIndex(), + subRunData.getGlyphCount(), + draw.getDepthAsFloat() + ); + } } @Override public void writeUniformsAndTextures(RecordingContext context, Draw draw, UniformDataGatherer uniformDataGatherer, - TextureDataGatherer textureDataGatherer) { + TextureDataGatherer textureDataGatherer, + boolean mayRequireLocalCoords) { var subRunData = (SubRunData) draw.mGeometry; @RawPtr var texture = context.getAtlasProvider().getGlyphAtlasManager().getCurrentTexture( @@ -189,8 +211,17 @@ public void writeUniformsAndTextures(RecordingContext context, Draw draw, ); assert texture != null; - uniformDataGatherer.writeMatrix4fAs2D(draw.mTransform); // SubRunToDevice - uniformDataGatherer.writeMatrix3f(subRunData.getSubRunToLocal()); + // SubRunToDevice + if (!mayRequireLocalCoords && draw.mTransform.isTranslate()) { + // if local coordinates are not required and SubRunToDevice is translation only, + // we can extract translation to XY and reduce uniform binding changes + uniformDataGatherer.writeMatrix3f(Matrix.identity()); + } else { + uniformDataGatherer.writeMatrix3f(draw.mTransform); + } + if (mayRequireLocalCoords) { + uniformDataGatherer.writeMatrix3f(subRunData.getSubRunToLocal()); + } uniformDataGatherer.write2f( 1.f / texture.getWidth(), 1.f / texture.getHeight() diff --git a/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/VerticesStep.java b/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/VerticesStep.java index c534ca7a..8b8544f7 100644 --- a/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/VerticesStep.java +++ b/external/Arc3D/src/main/java/icyllis/arc3d/granite/geom/VerticesStep.java @@ -108,7 +108,9 @@ public ProgramImpl makeProgramImpl(ShaderCaps caps) { } @Override - public void emitVaryings(VaryingHandler varyingHandler) { + public void emitVaryings(VaryingHandler varyingHandler, + boolean usesFastSolidColor) { + assert !usesFastSolidColor; // vertex color if (mHasColor) { varyingHandler.addVarying("f_Color", SLDataType.kFloat4); @@ -116,7 +118,8 @@ public void emitVaryings(VaryingHandler varyingHandler) { } @Override - public void emitUniforms(UniformHandler uniformHandler) { + public void emitUniforms(UniformHandler uniformHandler, + boolean mayRequireLocalCoords) { uniformHandler.addUniform(Engine.ShaderFlags.kVertex, SLDataType.kFloat3x3, "u_LocalToDevice", -1); uniformHandler.addUniform(Engine.ShaderFlags.kVertex, @@ -126,7 +129,9 @@ public void emitUniforms(UniformHandler uniformHandler) { @Override public void emitVertexGeomCode(Formatter vs, @Nonnull String worldPosVar, - @Nullable String localPosVar) { + @Nullable String localPosVar, + boolean usesFastSolidColor) { + assert !usesFastSolidColor; if (mHasColor) { vs.format(""" %1$s = vec4(%2$s.rgb * %2$s.a, %2$s.a); @@ -148,7 +153,9 @@ public void emitFragmentColorCode(Formatter fs, String outputColor) { } @Override - public void writeMesh(MeshDrawWriter writer, Draw draw, @Nullable float[] solidColor) { + public void writeMesh(MeshDrawWriter writer, Draw draw, + @Nullable float[] solidColor, + boolean mayRequireLocalCoords) { assert solidColor == null; Vertices vertices = (Vertices) draw.mGeometry; int vertexCount = vertices.getVertexCount(); @@ -209,8 +216,9 @@ public void writeMesh(MeshDrawWriter writer, Draw draw, @Nullable float[] solidC @Override public void writeUniformsAndTextures(RecordingContext context, Draw draw, UniformDataGatherer uniformDataGatherer, - TextureDataGatherer textureDataGatherer) { - uniformDataGatherer.writeMatrix4fAs2D(draw.mTransform); + TextureDataGatherer textureDataGatherer, + boolean mayRequireLocalCoords) { + uniformDataGatherer.writeMatrix3f(draw.mTransform); // LocalToDevice uniformDataGatherer.write1f(draw.getDepthAsFloat()); } } diff --git a/external/Arc3D/src/test/java/icyllis/arc3d/test/Camera.java b/external/Arc3D/src/test/java/icyllis/arc3d/test/Camera.java index 5164c733..d0f68268 100644 --- a/external/Arc3D/src/test/java/icyllis/arc3d/test/Camera.java +++ b/external/Arc3D/src/test/java/icyllis/arc3d/test/Camera.java @@ -31,7 +31,7 @@ public class Camera { public static void main(String[] args) { PrintWriter pw = new PrintWriter(System.out, true, StandardCharsets.UTF_8); - Matrix4 mat = Matrix4.identity(); + Matrix4 mat = new Matrix4(); mat.m34 = 1 / 576f; //mat.preTranslateZ(-20f); mat.preRotateY(MathUtil.PI_O_3); @@ -51,7 +51,7 @@ public static void main(String[] args) { Camera3D camera3D = new Camera3D(); - Matrix4 transformMat = Matrix4.identity(); + Matrix4 transformMat = new Matrix4(); transformMat.preRotateY(MathUtil.PI_O_3); Matrix3 outMatrix = new Matrix3(); camera3D.getMatrix(transformMat, outMatrix, pw); diff --git a/external/Arc3D/src/test/java/icyllis/arc3d/test/TestBenchmark.java b/external/Arc3D/src/test/java/icyllis/arc3d/test/TestBenchmark.java index 82b14844..744c8118 100644 --- a/external/Arc3D/src/test/java/icyllis/arc3d/test/TestBenchmark.java +++ b/external/Arc3D/src/test/java/icyllis/arc3d/test/TestBenchmark.java @@ -43,7 +43,7 @@ public static void main(String[] args) throws RunnerException { .run(); } - private final Matrix4 mMatrix = Matrix4.identity(); + private final Matrix4 mMatrix = new Matrix4(); { mMatrix.preRotate(MathUtil.PI_O_3, MathUtil.PI_O_6, MathUtil.PI_O_4); } diff --git a/external/Arc3D/src/test/java/icyllis/arc3d/test/TestDrawPass.java b/external/Arc3D/src/test/java/icyllis/arc3d/test/TestDrawPass.java index e245ef7c..cf5e1670 100644 --- a/external/Arc3D/src/test/java/icyllis/arc3d/test/TestDrawPass.java +++ b/external/Arc3D/src/test/java/icyllis/arc3d/test/TestDrawPass.java @@ -124,20 +124,20 @@ public static void main(String[] args) { rad, rad ); draw.mGeometry = rrect; - var transform = Matrix4.identity(); + var transform = new Matrix4(); float cx = rrect.centerX(); float cy = rrect.centerY(); transform.preTranslate(cx, cy); transform.preRotateZ(i); transform.preTranslate(-cx, -cy); - draw.mTransform = transform; + draw.mTransform = transform.toMatrix(); int stroke = (int) (Math.random() * 50); draw.mHalfWidth = stroke < 25 ? -1 : stroke - 20; float[] col = {(float) Math.random(), (float) Math.random(), (float) Math.random(), 1.0f}; for (int j = 0; j < 4; j++) { col[j] *= 0.5f; // premultiplied color } - step.writeMesh(drawWriter, draw, col); + step.writeMesh(drawWriter, draw, col, true); } drawWriter.flush(); diff --git a/external/Arc3D/src/test/java/icyllis/arc3d/test/TestGraniteRenderer.java b/external/Arc3D/src/test/java/icyllis/arc3d/test/TestGraniteRenderer.java index e34e36c0..4c047311 100644 --- a/external/Arc3D/src/test/java/icyllis/arc3d/test/TestGraniteRenderer.java +++ b/external/Arc3D/src/test/java/icyllis/arc3d/test/TestGraniteRenderer.java @@ -667,7 +667,7 @@ private void drawScene(Canvas canvas) { paint.setShader(RefCnt.create(mTestShader1)); paint.setStyle(Paint.FILL); paint.setAlphaF(0.7f); - var mat = Matrix4.identity(); + var mat = new Matrix4(); mat.setTranslate(1000, 100, 0); canvas.setMatrix(mat); rrect.setRectXY(200, 100, 600, 500, 20, 20); @@ -716,6 +716,12 @@ private void drawScene(Canvas canvas) { paint.setShader(RefCnt.create(mTestShader3)); canvas.translate(wid, 0); canvas.drawRect(rect, paint); + } else if (TEST_SCENE == 3) { + paint.setStyle(Paint.STROKE); + paint.setStrokeJoin(Paint.JOIN_MITER); + paint.setStrokeWidth(2); + canvas.drawTextBlob(mTextBlob1 != null ? mTextBlob1 : mTextBlob2, 400, 400, paint); + canvas.drawTextBlob(mTextBlob1 != null ? mTextBlob1 : mTextBlob2, 800, 620, paint); } paint.close(); canvas.restore(); diff --git a/external/Arc3D/src/test/java/icyllis/arc3d/test/TestManagedResource.java b/external/Arc3D/src/test/java/icyllis/arc3d/test/TestManagedResource.java index 4fc0103e..29fbef3a 100644 --- a/external/Arc3D/src/test/java/icyllis/arc3d/test/TestManagedResource.java +++ b/external/Arc3D/src/test/java/icyllis/arc3d/test/TestManagedResource.java @@ -483,11 +483,11 @@ public static void testRenderTarget(ImmediateContext dContext) { } public static void testRightHandedRotation(PrintWriter pw) { - Matrix4 mat = Matrix4.identity(); + Matrix4 mat = new Matrix4(); mat.preRotateZ(MathUtil.PI_O_3); pw.println("preRotateX " + mat); - Matrix4 mat2 = Matrix4.identity(); + Matrix4 mat2 = new Matrix4(); mat2.setPerspective(Math.toRadians(75), 16 / 9., 0, 2000, false); pw.println("preRotateAxisAngle " + mat2); @@ -506,13 +506,13 @@ public static void testKeyBuilder(PrintWriter pw) { } public static void testSimilarity(PrintWriter pw) { - Matrix4 transform = Matrix4.identity(); + Matrix4 transform = new Matrix4(); transform.m34 = 1 / 4096f; transform.preRotateX(MathUtil.PI_O_3); Matrix matrix3 = transform.toMatrix(); pw.println(matrix3); - Matrix4 mat = Matrix4.identity(); + Matrix4 mat = new Matrix4(); mat.preRotateZ(MathUtil.PI_O_2 * 29); Matrix m3 = mat.toMatrix(); pw.println(m3); diff --git a/external/Arc3D/src/test/java/icyllis/arc3d/test/TestMatrixAAOutset.java b/external/Arc3D/src/test/java/icyllis/arc3d/test/TestMatrixAAOutset.java index d4fd5718..460e5032 100644 --- a/external/Arc3D/src/test/java/icyllis/arc3d/test/TestMatrixAAOutset.java +++ b/external/Arc3D/src/test/java/icyllis/arc3d/test/TestMatrixAAOutset.java @@ -24,7 +24,7 @@ public class TestMatrixAAOutset { public static void main(String[] args) { - Matrix4 matrix = Matrix4.identity(); + Matrix4 matrix = new Matrix4(); matrix.m34 = 1 / 576f; matrix.preRotateX(Math.PI / 6); Rect2f rect = new Rect2f(-10, -50, 10, 50);