Skip to content

Commit cb4d600

Browse files
committed
Add stroke support to polygonal shape rendering
bug:4419017 bug:7230005 - Adds support for stroke/strokeAndFill for shapes without joins - Fixes path-polygonization threshold calculation - Fixes rendering offset (now only used for points) - Several formatting fixes Change-Id: If72473dc881e45752e2ec212d0dcd1e3f97979ea
1 parent fd3398c commit cb4d600

File tree

7 files changed

+362
-179
lines changed

7 files changed

+362
-179
lines changed

libs/hwui/Caches.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ void Caches::init() {
6868
mCurrentBuffer = meshBuffer;
6969
mCurrentIndicesBuffer = 0;
7070
mCurrentPositionPointer = this;
71+
mCurrentPositionStride = 0;
7172
mCurrentTexCoordsPointer = this;
7273

7374
mTexCoordsArrayEnabled = false;
@@ -340,15 +341,18 @@ bool Caches::unbindIndicesBuffer() {
340341
// Meshes and textures
341342
///////////////////////////////////////////////////////////////////////////////
342343

343-
void Caches::bindPositionVertexPointer(bool force, GLuint slot, GLvoid* vertices, GLsizei stride) {
344-
if (force || vertices != mCurrentPositionPointer) {
344+
void Caches::bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
345+
if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
346+
GLuint slot = currentProgram->position;
345347
glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
346348
mCurrentPositionPointer = vertices;
349+
mCurrentPositionStride = stride;
347350
}
348351
}
349352

350-
void Caches::bindTexCoordsVertexPointer(bool force, GLuint slot, GLvoid* vertices) {
353+
void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices) {
351354
if (force || vertices != mCurrentTexCoordsPointer) {
355+
GLuint slot = currentProgram->texCoords;
352356
glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices);
353357
mCurrentTexCoordsPointer = vertices;
354358
}

libs/hwui/Caches.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,13 @@ class ANDROID_API Caches: public Singleton<Caches> {
173173
* Binds an attrib to the specified float vertex pointer.
174174
* Assumes a stride of gMeshStride and a size of 2.
175175
*/
176-
void bindPositionVertexPointer(bool force, GLuint slot, GLvoid* vertices,
177-
GLsizei stride = gMeshStride);
176+
void bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei stride = gMeshStride);
178177

179178
/**
180179
* Binds an attrib to the specified float vertex pointer.
181180
* Assumes a stride of gMeshStride and a size of 2.
182181
*/
183-
void bindTexCoordsVertexPointer(bool force, GLuint slot, GLvoid* vertices);
182+
void bindTexCoordsVertexPointer(bool force, GLvoid* vertices);
184183

185184
/**
186185
* Resets the vertex pointers.
@@ -295,6 +294,7 @@ class ANDROID_API Caches: public Singleton<Caches> {
295294
GLuint mCurrentBuffer;
296295
GLuint mCurrentIndicesBuffer;
297296
void* mCurrentPositionPointer;
297+
GLuint mCurrentPositionStride;
298298
void* mCurrentTexCoordsPointer;
299299

300300
bool mTexCoordsArrayEnabled;

libs/hwui/FontRenderer.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,9 +374,8 @@ void FontRenderer::issueDrawCommand() {
374374
int offset = 2;
375375

376376
bool force = caches.unbindMeshBuffer();
377-
caches.bindPositionVertexPointer(force, caches.currentProgram->position, buffer);
378-
caches.bindTexCoordsVertexPointer(force, caches.currentProgram->texCoords,
379-
buffer + offset);
377+
caches.bindPositionVertexPointer(force, buffer);
378+
caches.bindTexCoordsVertexPointer(force, buffer + offset);
380379
}
381380

382381
glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);

libs/hwui/OpenGLRenderer.cpp

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,15 @@ bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, fl
12481248
return !clip.intersects(transformed);
12491249
}
12501250

1251+
bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint) {
1252+
if (paint->getStyle() != SkPaint::kFill_Style) {
1253+
float outset = paint->getStrokeWidth() * 0.5f;
1254+
return quickReject(left - outset, top - outset, right + outset, bottom + outset);
1255+
} else {
1256+
return quickReject(left, top, right, bottom);
1257+
}
1258+
}
1259+
12511260
bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
12521261
if (mSnapshot->isIgnored()) {
12531262
return true;
@@ -1490,7 +1499,7 @@ void OpenGLRenderer::setupDrawTextGammaUniforms() {
14901499

14911500
void OpenGLRenderer::setupDrawSimpleMesh() {
14921501
bool force = mCaches.bindMeshBuffer();
1493-
mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, 0);
1502+
mCaches.bindPositionVertexPointer(force, 0);
14941503
mCaches.unbindIndicesBuffer();
14951504
}
14961505

@@ -1523,26 +1532,25 @@ void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint v
15231532
force = mCaches.unbindMeshBuffer();
15241533
}
15251534

1526-
mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
1535+
mCaches.bindPositionVertexPointer(force, vertices);
15271536
if (mCaches.currentProgram->texCoords >= 0) {
1528-
mCaches.bindTexCoordsVertexPointer(force, mCaches.currentProgram->texCoords, texCoords);
1537+
mCaches.bindTexCoordsVertexPointer(force, texCoords);
15291538
}
15301539

15311540
mCaches.unbindIndicesBuffer();
15321541
}
15331542

15341543
void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) {
15351544
bool force = mCaches.unbindMeshBuffer();
1536-
mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
1545+
mCaches.bindPositionVertexPointer(force, vertices);
15371546
if (mCaches.currentProgram->texCoords >= 0) {
1538-
mCaches.bindTexCoordsVertexPointer(force, mCaches.currentProgram->texCoords, texCoords);
1547+
mCaches.bindTexCoordsVertexPointer(force, texCoords);
15391548
}
15401549
}
15411550

15421551
void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
15431552
bool force = mCaches.unbindMeshBuffer();
1544-
mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
1545-
vertices, gVertexStride);
1553+
mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
15461554
mCaches.unbindIndicesBuffer();
15471555
}
15481556

@@ -1560,8 +1568,7 @@ void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
15601568
void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords,
15611569
GLvoid* lengthCoords, float boundaryWidthProportion, int& widthSlot, int& lengthSlot) {
15621570
bool force = mCaches.unbindMeshBuffer();
1563-
mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
1564-
vertices, gAAVertexStride);
1571+
mCaches.bindPositionVertexPointer(force, vertices, gAAVertexStride);
15651572
mCaches.resetTexCoordsVertexPointer();
15661573
mCaches.unbindIndicesBuffer();
15671574

@@ -1919,15 +1926,23 @@ status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const
19191926
}
19201927

19211928
/**
1922-
* This function uses a similar approach to that of AA lines in the drawLines() function.
1923-
* We expand the rectangle by a half pixel in screen space on all sides. However, instead of using
1924-
* a fragment shader to compute the translucency of the color from its position, we simply use a
1925-
* varying parameter to define how far a given pixel is into the region.
1929+
* Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
1930+
* that of AA lines in the drawLines() function. We expand the convex path by a half pixel in
1931+
* screen space in all directions. However, instead of using a fragment shader to compute the
1932+
* translucency of the color from its position, we simply use a varying parameter to define how far
1933+
* a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
1934+
*
1935+
* Doesn't yet support joins, caps, or path effects.
19261936
*/
1927-
void OpenGLRenderer::drawConvexPath(const SkPath& path, int color, SkXfermode::Mode mode, bool isAA) {
1937+
void OpenGLRenderer::drawConvexPath(const SkPath& path, SkPaint* paint) {
1938+
int color = paint->getColor();
1939+
SkPaint::Style style = paint->getStyle();
1940+
SkXfermode::Mode mode = getXfermode(paint->getXfermode());
1941+
bool isAA = paint->isAntiAlias();
1942+
19281943
VertexBuffer vertexBuffer;
19291944
// TODO: try clipping large paths to viewport
1930-
PathRenderer::convexPathFillVertices(path, mSnapshot->transform, vertexBuffer, isAA);
1945+
PathRenderer::convexPathVertices(path, paint, mSnapshot->transform, vertexBuffer);
19311946

19321947
setupDraw();
19331948
setupDrawNoTexture();
@@ -1938,15 +1953,14 @@ void OpenGLRenderer::drawConvexPath(const SkPath& path, int color, SkXfermode::M
19381953
setupDrawShader();
19391954
setupDrawBlending(isAA, mode);
19401955
setupDrawProgram();
1941-
setupDrawModelViewIdentity(true);
1956+
setupDrawModelViewIdentity();
19421957
setupDrawColorUniforms();
19431958
setupDrawColorFilterUniforms();
19441959
setupDrawShaderIdentityUniforms();
19451960

19461961
void* vertices = vertexBuffer.getBuffer();
19471962
bool force = mCaches.unbindMeshBuffer();
1948-
mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
1949-
vertices, isAA ? gAlphaVertexStride : gVertexStride);
1963+
mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
19501964
mCaches.resetTexCoordsVertexPointer();
19511965
mCaches.unbindIndicesBuffer();
19521966

@@ -1960,7 +1974,7 @@ void OpenGLRenderer::drawConvexPath(const SkPath& path, int color, SkXfermode::M
19601974
glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
19611975
}
19621976

1963-
SkRect bounds = path.getBounds();
1977+
SkRect bounds = PathRenderer::computePathBounds(path, paint);
19641978
dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *mSnapshot->transform);
19651979

19661980
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getSize());
@@ -2050,7 +2064,7 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
20502064
setupDrawShader();
20512065
setupDrawBlending(isAA, mode);
20522066
setupDrawProgram();
2053-
setupDrawModelViewIdentity(true);
2067+
setupDrawModelViewIdentity();
20542068
setupDrawColorUniforms();
20552069
setupDrawColorFilterUniforms();
20562070
setupDrawShaderIdentityUniforms();
@@ -2330,11 +2344,11 @@ status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* tex
23302344

23312345
status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
23322346
float rx, float ry, SkPaint* p) {
2333-
if (mSnapshot->isIgnored() || quickReject(left, top, right, bottom)) {
2347+
if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
23342348
return DrawGlInfo::kStatusDone;
23352349
}
23362350

2337-
if (p->getStyle() != SkPaint::kFill_Style) {
2351+
if (p->getPathEffect() != 0) {
23382352
mCaches.activeTexture(0);
23392353
const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
23402354
right - left, bottom - top, rx, ry, p);
@@ -2343,46 +2357,59 @@ status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float
23432357

23442358
SkPath path;
23452359
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2360+
if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2361+
float outset = p->getStrokeWidth() / 2;
2362+
rect.outset(outset, outset);
2363+
rx += outset;
2364+
ry += outset;
2365+
}
23462366
path.addRoundRect(rect, rx, ry);
2347-
drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), p->isAntiAlias());
2367+
drawConvexPath(path, p);
23482368

23492369
return DrawGlInfo::kStatusDrew;
23502370
}
23512371

23522372
status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* p) {
2353-
if (mSnapshot->isIgnored() || quickReject(x - radius, y - radius, x + radius, y + radius)) {
2373+
if (mSnapshot->isIgnored() || quickRejectPreStroke(x - radius, y - radius,
2374+
x + radius, y + radius, p)) {
23542375
return DrawGlInfo::kStatusDone;
23552376
}
2356-
2357-
if (p->getStyle() != SkPaint::kFill_Style) {
2377+
if (p->getPathEffect() != 0) {
23582378
mCaches.activeTexture(0);
23592379
const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, p);
23602380
return drawShape(x - radius, y - radius, texture, p);
23612381
}
23622382

23632383
SkPath path;
2364-
path.addCircle(x, y, radius);
2365-
drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), p->isAntiAlias());
2384+
if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2385+
path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
2386+
} else {
2387+
path.addCircle(x, y, radius);
2388+
}
2389+
drawConvexPath(path, p);
23662390

23672391
return DrawGlInfo::kStatusDrew;
23682392
}
23692393

23702394
status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
23712395
SkPaint* p) {
2372-
if (mSnapshot->isIgnored() || quickReject(left, top, right, bottom)) {
2396+
if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
23732397
return DrawGlInfo::kStatusDone;
23742398
}
23752399

2376-
if (p->getStyle() != SkPaint::kFill_Style) {
2400+
if (p->getPathEffect() != 0) {
23772401
mCaches.activeTexture(0);
23782402
const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, p);
23792403
return drawShape(left, top, texture, p);
23802404
}
23812405

23822406
SkPath path;
23832407
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2408+
if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2409+
rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2410+
}
23842411
path.addOval(rect);
2385-
drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), p->isAntiAlias());
2412+
drawConvexPath(path, p);
23862413

23872414
return DrawGlInfo::kStatusDrew;
23882415
}
@@ -2402,10 +2429,11 @@ status_t OpenGLRenderer::drawArc(float left, float top, float right, float botto
24022429
}
24032430

24042431
status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
2405-
if (mSnapshot->isIgnored() || quickReject(left, top, right, bottom)) {
2432+
if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
24062433
return DrawGlInfo::kStatusDone;
24072434
}
24082435

2436+
// only fill style is supported by drawConvexPath, since others have to handle joins
24092437
if (p->getStyle() != SkPaint::kFill_Style) {
24102438
mCaches.activeTexture(0);
24112439
const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, p);
@@ -2415,7 +2443,7 @@ status_t OpenGLRenderer::drawRect(float left, float top, float right, float bott
24152443
if (p->isAntiAlias() && !mSnapshot->transform->isSimple()) {
24162444
SkPath path;
24172445
path.addRect(left, top, right, bottom);
2418-
drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), true);
2446+
drawConvexPath(path, p);
24192447
} else {
24202448
drawColorRect(left, top, right, bottom, p->getColor(), getXfermode(p->getXfermode()));
24212449
}

libs/hwui/OpenGLRenderer.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,11 @@ class OpenGLRenderer {
406406
bool quickRejectNoScissor(float left, float top, float right, float bottom,
407407
Rect& transformed, Rect& clip);
408408

409+
/**
410+
* Performs a quick reject but adjust the bounds to account for stroke width if necessary
411+
*/
412+
bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);
413+
409414
/**
410415
* Creates a new layer stored in the specified snapshot.
411416
*
@@ -513,11 +518,9 @@ class OpenGLRenderer {
513518
* Renders the convex hull defined by the specified path as a strip of polygons.
514519
*
515520
* @param path The hull of the path to draw
516-
* @param color The color of the rect
517-
* @param mode The blending mode to draw the path
518-
* @param isAA True if the drawing should be anti-aliased
521+
* @param paint The paint to render with
519522
*/
520-
void drawConvexPath(const SkPath& path, int color, SkXfermode::Mode mode, bool isAA);
523+
void drawConvexPath(const SkPath& path, SkPaint* paint);
521524

522525
/**
523526
* Draws a textured rectangle with the specified texture. The specified coordinates

0 commit comments

Comments
 (0)