diff options
author | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-25 11:59:40 +0000 |
---|---|---|
committer | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-25 11:59:40 +0000 |
commit | 9b62aa156bcf1db6f11af9302bf8bb8ef2567142 (patch) | |
tree | dae7097b678bfcd382993b53ba9808ae9438aa57 /src/gpu/gl/GrGpuGL.cpp | |
parent | 5c260f41af0af0d6bbfa9268664ac361a5ddc1e0 (diff) |
Make it possible to draw multiple paths at once to a draw target
Add interface to draw multiple paths in a single "command" to a draw
target. Implement this interface in GrGpuGL with NVPR "instanced"
calls.
The instanced calls accept list of paths and list of transformations as
their parameters. The transformations are at this moment expected to be
2d affine transformations, as the functions are called only for text
rendering.
This will be used when drawing fonts. Later it can be maybe be used in
GrInOrderDrawBuffer to aggregate many draw calls into one instanced draw
call, similar to drawing rects.
R=jvanverth@google.com, bsalomon@google.com
Author: kkinnunen@nvidia.com
Review URL: https://codereview.chromium.org/209413006
git-svn-id: http://skia.googlecode.com/svn/trunk@13930 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu/gl/GrGpuGL.cpp')
-rw-r--r-- | src/gpu/gl/GrGpuGL.cpp | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp index 5fb268863b..0aa072cd84 100644 --- a/src/gpu/gl/GrGpuGL.cpp +++ b/src/gpu/gl/GrGpuGL.cpp @@ -1695,6 +1695,99 @@ void GrGpuGL::onGpuDrawPath(const GrPath* path, SkPath::FillType fill) { } } +void GrGpuGL::onGpuDrawPaths(size_t pathCount, const GrPath** paths, + const SkMatrix* transforms, + SkPath::FillType fill, + SkStrokeRec::Style stroke) { + SkASSERT(this->caps()->pathRenderingSupport()); + SkASSERT(NULL != this->drawState()->getRenderTarget()); + SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer()); + SkASSERT(!fCurrentProgram->hasVertexShader()); + SkASSERT(stroke != SkStrokeRec::kHairline_Style); + + SkAutoMalloc pathData(pathCount * sizeof(GrGLuint)); + SkAutoMalloc transformData(pathCount * sizeof(GrGLfloat) * 6); + GrGLfloat* transformValues = + reinterpret_cast<GrGLfloat*>(transformData.get()); + GrGLuint* pathIDs = reinterpret_cast<GrGLuint*>(pathData.get()); + + for (size_t i = 0; i < pathCount; ++i) { + SkASSERT(transforms[i].asAffine(NULL)); + const SkMatrix& m = transforms[i]; + transformValues[i * 6] = m.getScaleX(); + transformValues[i * 6 + 1] = m.getSkewY(); + transformValues[i * 6 + 2] = m.getSkewX(); + transformValues[i * 6 + 3] = m.getScaleY(); + transformValues[i * 6 + 4] = m.getTranslateX(); + transformValues[i * 6 + 5] = m.getTranslateY(); + pathIDs[i] = static_cast<const GrGLPath*>(paths[i])->pathID(); + } + + flushPathStencilSettings(fill); + + SkPath::FillType nonInvertedFill = + SkPath::ConvertToNonInverseFillType(fill); + + SkASSERT(!fHWPathStencilSettings.isTwoSided()); + GrGLenum fillMode = + gr_stencil_op_to_gl_path_rendering_fill_mode( + fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face)); + GrGLint writeMask = + fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face); + + bool doFill = stroke == SkStrokeRec::kFill_Style + || stroke == SkStrokeRec::kStrokeAndFill_Style; + bool doStroke = stroke == SkStrokeRec::kStroke_Style + || stroke == SkStrokeRec::kStrokeAndFill_Style; + + if (doFill) { + GL_CALL(StencilFillPathInstanced(pathCount, GR_GL_UNSIGNED_INT, + pathIDs, 0, + fillMode, writeMask, + GR_GL_AFFINE_2D, transformValues)); + } + if (doStroke) { + GL_CALL(StencilStrokePathInstanced(pathCount, GR_GL_UNSIGNED_INT, + pathIDs, 0, + 0xffff, writeMask, + GR_GL_AFFINE_2D, transformValues)); + } + + if (nonInvertedFill == fill) { + if (doStroke) { + GL_CALL(CoverStrokePathInstanced( + pathCount, GR_GL_UNSIGNED_INT, pathIDs, 0, + GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES, + GR_GL_AFFINE_2D, transformValues)); + } else { + GL_CALL(CoverFillPathInstanced( + pathCount, GR_GL_UNSIGNED_INT, pathIDs, 0, + GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES, + GR_GL_AFFINE_2D, transformValues)); + + } + } else { + GrDrawState* drawState = this->drawState(); + GrDrawState::AutoViewMatrixRestore avmr; + SkRect bounds = SkRect::MakeLTRB(0, 0, + SkIntToScalar(drawState->getRenderTarget()->width()), + SkIntToScalar(drawState->getRenderTarget()->height())); + SkMatrix vmi; + // mapRect through persp matrix may not be correct + if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) { + vmi.mapRect(&bounds); + // theoretically could set bloat = 0, instead leave it because of matrix inversion + // precision. + SkScalar bloat = drawState->getViewMatrix().getMaxStretch() * SK_ScalarHalf; + bounds.outset(bloat, bloat); + } else { + avmr.setIdentity(drawState); + } + + this->drawSimpleRect(bounds, NULL); + } +} + void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) { GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target); if (rt->needsResolve()) { |