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);