static void check_texture(skiatest::Reporter* reporter, GrResourceProvider* provider, GrTextureProxy* texProxy, SkBackingFit fit) { GrSurfaceProxy::UniqueID idBefore = texProxy->uniqueID(); bool preinstantiated = texProxy->isInstantiated(); REPORTER_ASSERT(reporter, texProxy->instantiate(provider)); GrTexture* tex = texProxy->peekTexture(); REPORTER_ASSERT(reporter, texProxy->uniqueID() == idBefore); // Deferred resources should always have a different ID from their instantiated texture if (preinstantiated) { REPORTER_ASSERT(reporter, texProxy->uniqueID().asUInt() == tex->uniqueID().asUInt()); } else { REPORTER_ASSERT(reporter, texProxy->uniqueID().asUInt() != tex->uniqueID().asUInt()); } if (SkBackingFit::kExact == fit) { REPORTER_ASSERT(reporter, tex->width() == texProxy->width()); REPORTER_ASSERT(reporter, tex->height() == texProxy->height()); } else { REPORTER_ASSERT(reporter, tex->width() >= texProxy->width()); REPORTER_ASSERT(reporter, tex->height() >= texProxy->height()); } REPORTER_ASSERT(reporter, tex->config() == texProxy->config()); }
GrFragmentProcessor* GrMagnifierEffect::TestCreate(SkRandom* random, GrContext* context, const GrDrawTargetCaps&, GrTexture** textures) { GrTexture* texture = textures[0]; const int kMaxWidth = 200; const int kMaxHeight = 200; const int kMaxInset = 20; uint32_t width = random->nextULessThan(kMaxWidth); uint32_t height = random->nextULessThan(kMaxHeight); uint32_t x = random->nextULessThan(kMaxWidth - width); uint32_t y = random->nextULessThan(kMaxHeight - height); uint32_t inset = random->nextULessThan(kMaxInset); GrFragmentProcessor* effect = GrMagnifierEffect::Create( texture, (float) width / texture->width(), (float) height / texture->height(), texture->width() / (float) x, texture->height() / (float) y, (float) inset / texture->width(), (float) inset / texture->height()); SkASSERT(effect); return effect; }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const GrBitmapTextGeoProc& cte = args.fGP.cast<GrBitmapTextGeoProc>(); GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vsBuilder = pb->getVertexShaderBuilder(); // emit attributes vsBuilder->emitAttributes(cte); // compute numbers to be hardcoded to convert texture coordinates from int to float SkASSERT(cte.numTextures() == 1); GrTexture* atlas = cte.textureAccess(0).getTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); SkScalar recipWidth = 1.0f / atlas->width(); SkScalar recipHeight = 1.0f / atlas->height(); GrGLSLVertToFrag v(kVec2f_GrSLType); pb->addVarying("TextureCoords", &v); vsBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", v.vsOut(), GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipWidth, GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipHeight, cte.inTextureCoords()->fName); // Setup pass through color if (!cte.colorIgnored()) { if (cte.hasVertexColor()) { pb->addPassThroughAttribute(cte.inColor(), args.fOutputColor); } else { this->setupUniformColor(pb, args.fOutputColor, &fColorUniform); } } // Setup position this->setupPosition(pb, gpArgs, cte.inPosition()->fName); // emit transforms this->emitTransforms(args.fPB, gpArgs->fPositionVar, cte.inPosition()->fName, cte.localMatrix(), args.fTransformsIn, args.fTransformsOut); GrGLSLFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder(); if (cte.maskFormat() == kARGB_GrMaskFormat) { fsBuilder->codeAppendf("%s = ", args.fOutputColor); fsBuilder->appendTextureLookupAndModulate(args.fOutputColor, args.fSamplers[0], v.fsIn(), kVec2f_GrSLType); fsBuilder->codeAppend(";"); fsBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage); } else { fsBuilder->codeAppendf("%s = ", args.fOutputCoverage); fsBuilder->appendTextureLookup(args.fSamplers[0], v.fsIn(), kVec2f_GrSLType); fsBuilder->codeAppend(";"); if (cte.maskFormat() == kA565_GrMaskFormat) { // set alpha to be max of rgb coverage fsBuilder->codeAppendf("%s.a = max(max(%s.r, %s.g), %s.b);", args.fOutputCoverage, args.fOutputCoverage, args.fOutputCoverage, args.fOutputCoverage); } } }
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc, FPCoordTransformIter&& transformIter) override { const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>(); if (dfpgp.matrix().hasPerspective() && !fMatrix.cheapEqualTo(dfpgp.matrix())) { fMatrix = dfpgp.matrix(); float matrix[3 * 3]; GrGLSLGetMatrix<3>(matrix, fMatrix); pdman.setMatrix3f(fMatrixUniform, matrix); } SkASSERT(dfpgp.numTextureSamplers() >= 1); GrTexture* atlas = dfpgp.textureSampler(0).peekTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) { fAtlasSize.set(atlas->width(), atlas->height()); pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height()); } if (dfpgp.matrix().hasPerspective()) { this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter); } else { this->setTransformDataHelper(dfpgp.matrix(), pdman, &transformIter); } }
virtual void setData(const GrGLProgramDataManager& pdman, const GrPrimitiveProcessor& proc, const GrBatchTracker& bt) override { SkASSERT(fTextureSizeUni.isValid()); GrTexture* texture = proc.texture(0); if (texture->width() != fTextureSize.width() || texture->height() != fTextureSize.height()) { fTextureSize = SkISize::Make(texture->width(), texture->height()); pdman.set2f(fTextureSizeUni, SkIntToScalar(fTextureSize.width()), SkIntToScalar(fTextureSize.height())); } const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>(); if (!dfpgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfpgp.viewMatrix())) { fViewMatrix = dfpgp.viewMatrix(); GrGLfloat viewMatrix[3 * 3]; GrGLGetMatrix<3>(viewMatrix, fViewMatrix); pdman.setMatrix3f(fViewMatrixUniform, viewMatrix); } if (dfpgp.color() != fColor) { GrGLfloat c[4]; GrColorToRGBAFloat(dfpgp.color(), c); pdman.set4fv(fColorUniform, 1, c); fColor = dfpgp.color(); } }
bool GrDrawTarget::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { if (!GrDrawTarget::onCanCopySurface(dst, src, srcRect, dstPoint)) { return false; } GrRenderTarget* rt = dst->asRenderTarget(); GrTexture* tex = src->asTexture(); GrDrawTarget::AutoStateRestore asr(this, kReset_ASRInit); this->drawState()->setRenderTarget(rt); SkMatrix matrix; matrix.setTranslate(SkIntToScalar(srcRect.fLeft - dstPoint.fX), SkIntToScalar(srcRect.fTop - dstPoint.fY)); matrix.postIDiv(tex->width(), tex->height()); this->drawState()->addColorTextureEffect(tex, matrix); SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, srcRect.width(), srcRect.height()); this->drawSimpleRect(dstRect); return true; }
void writePathVertices(GrDrawBatch::Target* target, GrBatchAtlas* atlas, intptr_t offset, GrColor color, size_t vertexStride, const SkMatrix& viewMatrix, const ShapeData* shapeData) const { GrTexture* texture = atlas->getTexture(); SkScalar dx = shapeData->fBounds.fLeft; SkScalar dy = shapeData->fBounds.fTop; SkScalar width = shapeData->fBounds.width(); SkScalar height = shapeData->fBounds.height(); SkScalar invScale = 1.0f / shapeData->fScale; dx *= invScale; dy *= invScale; width *= invScale; height *= invScale; SkPoint* positions = reinterpret_cast<SkPoint*>(offset); // vertex positions // TODO make the vertex attributes a struct SkRect r = SkRect::MakeXYWH(dx, dy, width, height); positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexStride); // colors for (int i = 0; i < kVerticesPerQuad; i++) { GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertexStride); *colorPtr = color; } const SkScalar tx = SkIntToScalar(shapeData->fAtlasLocation.fX); const SkScalar ty = SkIntToScalar(shapeData->fAtlasLocation.fY); // vertex texture coords SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(GrColor)); textureCoords->setRectFan(tx / texture->width(), ty / texture->height(), (tx + shapeData->fBounds.width()) / texture->width(), (ty + shapeData->fBounds.height()) / texture->height(), vertexStride); }
//////////////////////////////////////////////////////////////////////////////// // return true on success; false on failure bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path, GrPathFill fill, const GrVec* translate, GrDrawTarget* target, GrDrawState::StageMask stageMask, bool antiAlias) { if (NULL == fContext) { return false; } GrAutoScratchTexture ast; GrIRect pathBounds, clipBounds; if (!get_path_and_clip_bounds(target, path, translate, &pathBounds, &clipBounds)) { return true; // path is empty so there is nothing to do } if (sw_draw_path_to_mask_texture(path, pathBounds, fill, fContext, translate, &ast, antiAlias)) { GrTexture* texture = ast.texture(); GrAssert(NULL != texture); GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask); enum { // the SW path renderer shares this stage with glyph // rendering (kGlyphMaskStage in GrBatchedTextContext) kPathMaskStage = GrPaint::kTotalStages, }; GrAssert(NULL == target->drawState()->getTexture(kPathMaskStage)); target->drawState()->setTexture(kPathMaskStage, texture); target->drawState()->sampler(kPathMaskStage)->reset(); GrScalar w = GrIntToScalar(pathBounds.width()); GrScalar h = GrIntToScalar(pathBounds.height()); GrRect maskRect = GrRect::MakeWH(w / texture->width(), h / texture->height()); const GrRect* srcRects[GrDrawState::kNumStages] = {NULL}; srcRects[kPathMaskStage] = &maskRect; stageMask |= 1 << kPathMaskStage; GrRect dstRect = GrRect::MakeLTRB( SK_Scalar1* pathBounds.fLeft, SK_Scalar1* pathBounds.fTop, SK_Scalar1* pathBounds.fRight, SK_Scalar1* pathBounds.fBottom); target->drawRect(dstRect, NULL, stageMask, srcRects, NULL); target->drawState()->setTexture(kPathMaskStage, NULL); if (GrIsFillInverted(fill)) { draw_around_inv_path(target, stageMask, clipBounds, pathBounds); } return true; } return false; }
void GrGLDisplacementMapEffect::setData(const GrGLProgramDataManager& pdman, const GrProcessor& proc) { const GrDisplacementMapEffect& displacementMap = proc.cast<GrDisplacementMapEffect>(); GrTexture* colorTex = displacementMap.texture(1); SkScalar scaleX = SkScalarDiv(displacementMap.scale().fX, SkIntToScalar(colorTex->width())); SkScalar scaleY = SkScalarDiv(displacementMap.scale().fY, SkIntToScalar(colorTex->height())); pdman.set2f(fScaleUni, SkScalarToFloat(scaleX), colorTex->origin() == kTopLeft_GrSurfaceOrigin ? SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY)); fGLDomain.setData(pdman, displacementMap.domain(), colorTex->origin()); }
void GrGLBicubicEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { const GrBicubicEffect& bicubicEffect = processor.cast<GrBicubicEffect>(); GrSurfaceProxy* proxy = processor.textureSampler(0).proxy(); GrTexture* texture = proxy->peekTexture(); float imageIncrement[2]; imageIncrement[0] = 1.0f / texture->width(); imageIncrement[1] = 1.0f / texture->height(); pdman.set2fv(fImageIncrementUni, 1, imageIncrement); fDomain.setData(pdman, bicubicEffect.domain(), proxy); }
const GrFragmentProcessor* GrMagnifierEffect::TestCreate(GrProcessorTestData* d) { GrTexture* texture = d->fTextures[0]; const int kMaxWidth = 200; const int kMaxHeight = 200; const int kMaxInset = 20; uint32_t width = d->fRandom->nextULessThan(kMaxWidth); uint32_t height = d->fRandom->nextULessThan(kMaxHeight); uint32_t x = d->fRandom->nextULessThan(kMaxWidth - width); uint32_t y = d->fRandom->nextULessThan(kMaxHeight - height); uint32_t inset = d->fRandom->nextULessThan(kMaxInset); GrFragmentProcessor* effect = GrMagnifierEffect::Create( texture, SkRect::MakeWH(SkIntToScalar(kMaxWidth), SkIntToScalar(kMaxHeight)), (float) width / texture->width(), (float) height / texture->height(), texture->width() / (float) x, texture->height() / (float) y, (float) inset / texture->width(), (float) inset / texture->height()); SkASSERT(effect); return effect; }
void GrGLBicubicEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { const GrBicubicEffect& bicubicEffect = processor.cast<GrBicubicEffect>(); GrTexture* texture = processor.textureSampler(0).peekTexture(); float imageIncrement[2]; imageIncrement[0] = 1.0f / texture->width(); imageIncrement[1] = 1.0f / texture->height(); pdman.set2fv(fImageIncrementUni, 1, imageIncrement); fDomain.setData(pdman, bicubicEffect.domain(), texture); if (SkToBool(bicubicEffect.colorSpaceXform())) { fColorSpaceHelper.setData(pdman, bicubicEffect.colorSpaceXform()); } }
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc, FPCoordTransformIter&& transformIter) override { SkASSERT(fTextureSizeUni.isValid()); GrTexture* texture = proc.texture(0); if (texture->width() != fTextureSize.width() || texture->height() != fTextureSize.height()) { fTextureSize = SkISize::Make(texture->width(), texture->height()); pdman.set2f(fTextureSizeUni, SkIntToScalar(fTextureSize.width()), SkIntToScalar(fTextureSize.height())); } const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>(); if (!dfpgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfpgp.viewMatrix())) { fViewMatrix = dfpgp.viewMatrix(); float viewMatrix[3 * 3]; GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix); pdman.setMatrix3f(fViewMatrixUniform, viewMatrix); } this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter); }
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc, FPCoordTransformIter&& transformIter) override { const GrDistanceFieldA8TextGeoProc& dfa8gp = proc.cast<GrDistanceFieldA8TextGeoProc>(); #ifdef SK_GAMMA_APPLY_TO_A8 float distanceAdjust = dfa8gp.getDistanceAdjust(); if (distanceAdjust != fDistanceAdjust) { fDistanceAdjust = distanceAdjust; pdman.set1f(fDistanceAdjustUni, distanceAdjust); } #endif SkASSERT(dfa8gp.numTextureSamplers() >= 1); GrTexture* atlas = dfa8gp.textureSampler(0).peekTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) { fAtlasSize.set(atlas->width(), atlas->height()); pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height()); } this->setTransformDataHelper(dfa8gp.localMatrix(), pdman, &transformIter); }
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& processor, FPCoordTransformIter&& transformIter) override { SkASSERT(fDistanceAdjustUni.isValid()); const GrDistanceFieldLCDTextGeoProc& dflcd = processor.cast<GrDistanceFieldLCDTextGeoProc>(); GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dflcd.getDistanceAdjust(); if (wa != fDistanceAdjust) { pdman.set3f(fDistanceAdjustUni, wa.fR, wa.fG, wa.fB); fDistanceAdjust = wa; } SkASSERT(dflcd.numTextureSamplers() >= 1); GrTexture* atlas = dflcd.textureSampler(0).peekTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) { fAtlasSize.set(atlas->width(), atlas->height()); pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height()); } this->setTransformDataHelper(dflcd.localMatrix(), pdman, &transformIter); }
virtual void setData(const GrGLProgramDataManager& pdman, const GrPrimitiveProcessor& proc, const GrBatchTracker& bt) override { SkASSERT(fTextureSizeUni.isValid()); GrTexture* texture = proc.texture(0); if (texture->width() != fTextureSize.width() || texture->height() != fTextureSize.height()) { fTextureSize = SkISize::Make(texture->width(), texture->height()); pdman.set2f(fTextureSizeUni, SkIntToScalar(fTextureSize.width()), SkIntToScalar(fTextureSize.height())); } this->setUniformViewMatrix(pdman, proc.viewMatrix()); const DistanceFieldNoGammaBatchTracker& local = bt.cast<DistanceFieldNoGammaBatchTracker>(); if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) { GrGLfloat c[4]; GrColorToRGBAFloat(local.fColor, c); pdman.set4fv(fColorUniform, 1, c); fColor = local.fColor; } }
static inline void GenKey(const GrGeometryProcessor& gp, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>(); uint32_t key = dfTexEffect.getFlags(); key |= dfTexEffect.colorIgnored() << 16; key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25; b->add32(key); // Currently we hardcode numbers to convert atlas coordinates to normalized floating point SkASSERT(gp.numTextures() == 1); GrTexture* atlas = gp.textureAccess(0).getTexture(); SkASSERT(atlas); b->add32(atlas->width()); b->add32(atlas->height()); }
static inline void GenKey(const GrGeometryProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { const GrBitmapTextGeoProc& gp = proc.cast<GrBitmapTextGeoProc>(); uint32_t key = 0; key |= gp.usesLocalCoords() && gp.localMatrix().hasPerspective() ? 0x1 : 0x0; key |= gp.colorIgnored() ? 0x2 : 0x0; key |= gp.maskFormat() << 3; b->add32(key); // Currently we hardcode numbers to convert atlas coordinates to normalized floating point SkASSERT(gp.numTextures() == 1); GrTexture* atlas = gp.textureAccess(0).getTexture(); SkASSERT(atlas); b->add32(atlas->width()); b->add32(atlas->height()); }
bool GrDrawTarget::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { SkASSERT(dst); SkASSERT(src); SkIRect clippedSrcRect; SkIPoint clippedDstPoint; // If the rect is outside the src or dst then we've already succeeded. if (!clip_srcrect_and_dstpoint(dst, src, srcRect, dstPoint, &clippedSrcRect, &clippedDstPoint)) { return true; } if (this->onCopySurface(dst, src, clippedSrcRect, clippedDstPoint)) { return true; } GrRenderTarget* rt = dst->asRenderTarget(); GrTexture* tex = src->asTexture(); if ((dst == src) || !rt || !tex) { return false; } GrPipelineBuilder pipelineBuilder; pipelineBuilder.setRenderTarget(rt); SkMatrix matrix; matrix.setTranslate(SkIntToScalar(clippedSrcRect.fLeft - clippedDstPoint.fX), SkIntToScalar(clippedSrcRect.fTop - clippedDstPoint.fY)); matrix.postIDiv(tex->width(), tex->height()); pipelineBuilder.addColorTextureProcessor(tex, matrix); SkIRect dstRect = SkIRect::MakeXYWH(clippedDstPoint.fX, clippedDstPoint.fY, clippedSrcRect.width(), clippedSrcRect.height()); this->drawSimpleRect(&pipelineBuilder, GrColor_WHITE, SkMatrix::I(), dstRect); return true; }
void GrGLMatrixConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { const GrMatrixConvolutionEffect& conv = processor.cast<GrMatrixConvolutionEffect>(); GrSurfaceProxy* proxy = conv.textureSampler(0).proxy(); GrTexture* texture = proxy->priv().peekTexture(); float imageIncrement[2]; float ySign = proxy->origin() == kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; imageIncrement[0] = 1.0f / texture->width(); imageIncrement[1] = ySign / texture->height(); pdman.set2fv(fImageIncrementUni, 1, imageIncrement); pdman.set2fv(fKernelOffsetUni, 1, conv.kernelOffset()); int kernelCount = conv.kernelSize().width() * conv.kernelSize().height(); int arrayCount = (kernelCount + 3) / 4; SkASSERT(4 * arrayCount >= kernelCount); pdman.set4fv(fKernelUni, arrayCount, conv.kernel()); pdman.set1f(fGainUni, conv.gain()); pdman.set1f(fBiasUni, conv.bias()); fDomain.setData(pdman, conv.domain(), proxy); }
bool GrDrawTarget::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { SkASSERT(dst); SkASSERT(src); SkIRect clippedSrcRect; SkIPoint clippedDstPoint; // If the rect is outside the src or dst then we've already succeeded. if (!clip_srcrect_and_dstpoint(dst, src, srcRect, dstPoint, &clippedSrcRect, &clippedDstPoint)) { SkASSERT(GrDrawTarget::canCopySurface(dst, src, srcRect, dstPoint)); return true; } if (!GrDrawTarget::canCopySurface(dst, src, clippedSrcRect, clippedDstPoint)) { return false; } GrRenderTarget* rt = dst->asRenderTarget(); GrTexture* tex = src->asTexture(); GrDrawTarget::AutoStateRestore asr(this, kReset_ASRInit); this->drawState()->setRenderTarget(rt); SkMatrix matrix; matrix.setTranslate(SkIntToScalar(clippedSrcRect.fLeft - clippedDstPoint.fX), SkIntToScalar(clippedSrcRect.fTop - clippedDstPoint.fY)); matrix.postIDiv(tex->width(), tex->height()); this->drawState()->addColorTextureProcessor(tex, matrix); SkIRect dstRect = SkIRect::MakeXYWH(clippedDstPoint.fX, clippedDstPoint.fY, clippedSrcRect.width(), clippedSrcRect.height()); this->drawSimpleRect(dstRect); return true; }
std::unique_ptr<SkCrossContextImageData> SkCrossContextImageData::MakeFromEncoded( GrContext* context, sk_sp<SkData> encoded, SkColorSpace* dstColorSpace) { sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded)); if (!codecImage) { return nullptr; } // Some backends or drivers don't support (safely) moving resources between contexts if (!context->caps()->crossContextTextureSupport()) { return std::unique_ptr<SkCrossContextImageData>( new SkCrossContextImageData(std::move(codecImage))); } sk_sp<SkImage> textureImage = codecImage->makeTextureImage(context, dstColorSpace); if (!textureImage) { // TODO: Force decode to raster here? Do mip-mapping, like getDeferredTextureImageData? return std::unique_ptr<SkCrossContextImageData>( new SkCrossContextImageData(std::move(codecImage))); } // Crack open the gpu image, extract the backend data, stick it in the SkCCID GrTexture* texture = as_IB(textureImage)->peekTexture(); SkASSERT(texture); GrBackendTextureDesc desc; desc.fFlags = kNone_GrBackendTextureFlag; desc.fOrigin = texture->origin(); desc.fWidth = texture->width(); desc.fHeight = texture->height(); desc.fConfig = texture->config(); desc.fSampleCnt = 0; context->contextPriv().prepareSurfaceForExternalIO(as_IB(textureImage)->peekProxy()); auto textureData = texture->texturePriv().detachBackendTexture(); SkASSERT(textureData); SkImageInfo info = as_IB(textureImage)->onImageInfo(); return std::unique_ptr<SkCrossContextImageData>(new SkCrossContextImageData( desc, std::move(textureData), info.alphaType(), info.refColorSpace())); }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldLCDTextGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldLCDTextGeoProc>(); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(dfTexEffect); GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; // setup pass through color if (!dfTexEffect.colorIgnored()) { varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); } // Setup position this->setupPosition(vertBuilder, uniformHandler, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(), &fViewMatrixUniform); // emit transforms this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, args.fTransformsIn, args.fTransformsOut); // set up varyings bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) == kUniformScale_DistanceFieldEffectMask; bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag); GrGLSLVertToFrag recipScale(kFloat_GrSLType); GrGLSLVertToFrag uv(kVec2f_GrSLType); varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName); // compute numbers to be hardcoded to convert texture coordinates from float to int SkASSERT(dfTexEffect.numTextures() == 1); GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); GrGLSLVertToFrag st(kVec2f_GrSLType); varyingHandler->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); vertBuilder->codeAppendf("%s = vec2(%d, %d) * %s;", st.vsOut(), atlas->width(), atlas->height(), dfTexEffect.inTextureCoords()->fName); // add frag shader code SkAssertResult(fragBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); // create LCD offset adjusted by inverse of transform // Use highp to work around aliasing issues fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, kHigh_GrSLPrecision)); fragBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, kHigh_GrSLPrecision)); SkScalar lcdDelta = 1.0f / (3.0f * atlas->width()); if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) { fragBuilder->codeAppendf("float delta = -%.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta); } else { fragBuilder->codeAppendf("float delta = %.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta); } if (isUniformScale) { fragBuilder->codeAppendf("float st_grad_len = abs(dFdy(%s.y));", st.fsIn()); fragBuilder->codeAppend("vec2 offset = vec2(st_grad_len*delta, 0.0);"); } else if (isSimilarity) { // For a similarity matrix with rotation, the gradient will not be aligned // with the texel coordinate axes, so we need to calculate it. // We use dFdy because of a Mali 400 bug, and rotate -90 degrees to // get the gradient in the x direction. fragBuilder->codeAppendf("vec2 st_grad = dFdy(%s);", st.fsIn()); fragBuilder->codeAppend("float st_grad_len = length(st_grad);"); fragBuilder->codeAppend("vec2 offset = delta*vec2(st_grad.y, -st_grad.x);"); } else { fragBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn()); fragBuilder->codeAppend("vec2 Jdx = dFdx(st);"); fragBuilder->codeAppend("vec2 Jdy = dFdy(st);"); fragBuilder->codeAppend("vec2 offset = delta*Jdx;"); } // green is distance to uv center fragBuilder->codeAppend("\tvec4 texColor = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType); fragBuilder->codeAppend(";\n"); fragBuilder->codeAppend("\tvec3 distance;\n"); fragBuilder->codeAppend("\tdistance.y = texColor.r;\n"); // red is distance to left offset fragBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n"); fragBuilder->codeAppend("\ttexColor = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType); fragBuilder->codeAppend(";\n"); fragBuilder->codeAppend("\tdistance.x = texColor.r;\n"); // blue is distance to right offset fragBuilder->codeAppend("\tuv_adjusted = uv + offset;\n"); fragBuilder->codeAppend("\ttexColor = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType); fragBuilder->codeAppend(";\n"); fragBuilder->codeAppend("\tdistance.z = texColor.r;\n"); fragBuilder->codeAppend("\tdistance = " "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));"); // adjust width based on gamma const char* distanceAdjustUniName = nullptr; fDistanceAdjustUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec3f_GrSLType, kDefault_GrSLPrecision, "DistanceAdjust", &distanceAdjustUniName); fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); // To be strictly correct, we should compute the anti-aliasing factor separately // for each color component. However, this is only important when using perspective // transformations, and even then using a single factor seems like a reasonable // trade-off between quality and speed. fragBuilder->codeAppend("float afwidth;"); if (isSimilarity) { // For similarity transform (uniform scale-only is a subset of this), we adjust for the // effect of the transformation on the distance by using the length of the gradient of // the texture coordinates. We use st coordinates to ensure we're mapping 1:1 from texel // space to pixel space. // this gives us a smooth step across approximately one fragment fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*st_grad_len;"); } else { // For general transforms, to determine the amount of correction we multiply a unit // vector pointing along the SDF gradient direction by the Jacobian of the st coords // (which is the inverse transform for this fragment) and take the length of the result. fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));"); // the length of the gradient may be 0, so we need to check for this // this also compensates for the Adreno, which likes to drop tiles on division by 0 fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); fragBuilder->codeAppend("if (dg_len2 < 0.0001) {"); fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); fragBuilder->codeAppend("} else {"); fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);"); fragBuilder->codeAppend("}"); fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); // this gives us a smooth step across approximately one fragment fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); } fragBuilder->codeAppend( "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);"); // set alpha to be max of rgb coverage fragBuilder->codeAppend("val.a = max(max(val.r, val.g), val.b);"); fragBuilder->codeAppendf("%s = val;", args.fOutputCoverage); }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldA8TextGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldA8TextGeoProc>(); GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; SkAssertResult(fragBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(dfTexEffect); #ifdef SK_GAMMA_APPLY_TO_A8 // adjust based on gamma const char* distanceAdjustUniName = nullptr; // width, height, 1/(3*width) fDistanceAdjustUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "DistanceAdjust", &distanceAdjustUniName); #endif // Setup pass through color if (!dfTexEffect.colorIgnored()) { varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); } // Setup position this->setupPosition(vertBuilder, uniformHandler, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(), &fViewMatrixUniform); // emit transforms this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, args.fTransformsIn, args.fTransformsOut); // add varyings GrGLSLVertToFrag recipScale(kFloat_GrSLType); GrGLSLVertToFrag uv(kVec2f_GrSLType); bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) == kUniformScale_DistanceFieldEffectMask; bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag); varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName); // compute numbers to be hardcoded to convert texture coordinates from float to int SkASSERT(dfTexEffect.numTextures() == 1); GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); GrGLSLVertToFrag st(kVec2f_GrSLType); varyingHandler->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); vertBuilder->codeAppendf("%s = vec2(%d, %d) * %s;", st.vsOut(), atlas->width(), atlas->height(), dfTexEffect.inTextureCoords()->fName); // Use highp to work around aliasing issues fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, kHigh_GrSLPrecision)); fragBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); fragBuilder->codeAppend("\tfloat texColor = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType); fragBuilder->codeAppend(".r;\n"); fragBuilder->codeAppend("\tfloat distance = " SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");"); #ifdef SK_GAMMA_APPLY_TO_A8 // adjust width based on gamma fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); #endif fragBuilder->codeAppend("float afwidth;"); if (isUniformScale) { // For uniform scale, we adjust for the effect of the transformation on the distance // by using the length of the gradient of the t coordinate in the y direction. // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space. // We use the y gradient because there is a bug in the Mali 400 in the x direction. // this gives us a smooth step across approximately one fragment fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(%s.y));", st.fsIn()); } else if (isSimilarity) { // For similarity transform, we adjust the effect of the transformation on the distance // by using the length of the gradient of the texture coordinates. We use st coordinates // to ensure we're mapping 1:1 from texel space to pixel space. // We use the y gradient because there is a bug in the Mali 400 in the x direction. // this gives us a smooth step across approximately one fragment fragBuilder->codeAppendf("float st_grad_len = length(dFdy(%s));", st.fsIn()); fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);"); } else { // For general transforms, to determine the amount of correction we multiply a unit // vector pointing along the SDF gradient direction by the Jacobian of the st coords // (which is the inverse transform for this fragment) and take the length of the result. fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));"); // the length of the gradient may be 0, so we need to check for this // this also compensates for the Adreno, which likes to drop tiles on division by 0 fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); fragBuilder->codeAppend("if (dg_len2 < 0.0001) {"); fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); fragBuilder->codeAppend("} else {"); fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);"); fragBuilder->codeAppend("}"); fragBuilder->codeAppendf("vec2 Jdx = dFdx(%s);", st.fsIn()); fragBuilder->codeAppendf("vec2 Jdy = dFdy(%s);", st.fsIn()); fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); // this gives us a smooth step across approximately one fragment fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); } fragBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);"); fragBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage); }
bool SkXfermodeImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { GrContext* context = nullptr; SkBitmap background = src; SkIPoint backgroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &background, &backgroundOffset)) { background.reset(); } GrTexture* backgroundTex = background.getTexture(); if (backgroundTex) { context = backgroundTex->getContext(); } SkBitmap foreground = src; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPUDeprecated(1, proxy, src, ctx, &foreground, &foregroundOffset)) { foreground.reset(); } GrTexture* foregroundTex = foreground.getTexture(); if (foregroundTex) { context = foregroundTex->getContext(); } if (!context) { return false; } SkIRect bounds = background.bounds().makeOffset(backgroundOffset.x(), backgroundOffset.y()); bounds.join(foreground.bounds().makeOffset(foregroundOffset.x(), foregroundOffset.y())); if (bounds.isEmpty()) { return false; } GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } GrPaint paint; SkAutoTUnref<const GrFragmentProcessor> bgFP; if (backgroundTex) { SkMatrix backgroundMatrix; backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), SkIntToScalar(-backgroundOffset.fY)); bgFP.reset(GrTextureDomainEffect::Create( backgroundTex, backgroundMatrix, GrTextureDomain::MakeTexelDomain(backgroundTex, background.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode)); } else { bgFP.reset(GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, GrConstColorProcessor::kIgnore_InputMode)); } if (foregroundTex) { SkMatrix foregroundMatrix; foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), SkIntToScalar(-foregroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> foregroundFP; foregroundFP.reset(GrTextureDomainEffect::Create( foregroundTex, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode)); paint.addColorFragmentProcessor(foregroundFP.get()); // A null fMode is interpreted to mean kSrcOver_Mode (to match raster). SkAutoTUnref<SkXfermode> mode(SkSafeRef(fMode.get())); if (!mode) { // It would be awesome to use SkXfermode::Create here but it knows better // than us and won't return a kSrcOver_Mode SkXfermode. That means we // have to get one the hard way. struct ProcCoeff rec; rec.fProc = SkXfermode::GetProc(SkXfermode::kSrcOver_Mode); SkXfermode::ModeAsCoeff(SkXfermode::kSrcOver_Mode, &rec.fSC, &rec.fDC); mode.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode)); } SkAutoTUnref<const GrFragmentProcessor> xferFP(mode->getFragmentProcessorForImageFilter(bgFP)); // A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed if (xferFP) { paint.addColorFragmentProcessor(xferFP); } } else { paint.addColorFragmentProcessor(bgFP); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return false; } SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(bounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; }
bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap background = src; SkIPoint backgroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(0, proxy, src, ctx, &background, &backgroundOffset)) { return false; } GrTexture* backgroundTex = background.getTexture(); if (nullptr == backgroundTex) { SkASSERT(false); return false; } SkBitmap foreground = src; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(1, proxy, src, ctx, &foreground, &foregroundOffset)) { return false; } GrTexture* foregroundTex = foreground.getTexture(); GrContext* context = foregroundTex->getContext(); SkIRect bounds = background.bounds().makeOffset(backgroundOffset.x(), backgroundOffset.y()); bounds.join(foreground.bounds().makeOffset(foregroundOffset.x(), foregroundOffset.y())); if (bounds.isEmpty()) { return false; } const GrFragmentProcessor* xferFP = nullptr; GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } GrPaint paint; SkMatrix backgroundMatrix; backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), SkIntToScalar(-backgroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> bgFP(GrTextureDomainEffect::Create( backgroundTex, backgroundMatrix, GrTextureDomain::MakeTexelDomain(backgroundTex, background.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode) ); if (!fMode || !fMode->asFragmentProcessor(&xferFP, bgFP)) { // canFilterImageGPU() should've taken care of this SkASSERT(false); return false; } SkMatrix foregroundMatrix; foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), SkIntToScalar(-foregroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> foregroundFP(GrTextureDomainEffect::Create( foregroundTex, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode) ); paint.addColorFragmentProcessor(foregroundFP.get()); if (xferFP) { paint.addColorFragmentProcessor(xferFP)->unref(); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return false; } SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(bounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldLCDTextGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldLCDTextGeoProc>(); GrGLGPBuilder* pb = args.fPB; GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); // emit attributes vsBuilder->emitAttributes(dfTexEffect); // setup pass through color if (!dfTexEffect.colorIgnored()) { this->setupUniformColor(pb, args.fOutputColor, &fColorUniform); } // Setup position this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(), &fViewMatrixUniform); // emit transforms this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, args.fTransformsIn, args.fTransformsOut); // set up varyings bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask); GrGLVertToFrag recipScale(kFloat_GrSLType); GrGLVertToFrag st(kVec2f_GrSLType); args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName); // compute numbers to be hardcoded to convert texture coordinates from int to float SkASSERT(dfTexEffect.numTextures() == 1); GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); SkScalar recipWidth = 1.0f / atlas->width(); SkScalar recipHeight = 1.0f / atlas->height(); GrGLVertToFrag uv(kVec2f_GrSLType); args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", uv.vsOut(), GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipWidth, GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipHeight, dfTexEffect.inTextureCoords()->fName); // add frag shader code GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); SkAssertResult(fsBuilder->enableFeature( GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); // create LCD offset adjusted by inverse of transform // Use highp to work around aliasing issues fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision, pb->ctxInfo().standard())); fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision, pb->ctxInfo().standard())); SkScalar lcdDelta = 1.0f / (3.0f * atlas->width()); if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) { fsBuilder->codeAppendf("float delta = -%.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta); } else { fsBuilder->codeAppendf("float delta = %.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta); } if (isUniformScale) { fsBuilder->codeAppendf("float dy = abs(dFdy(%s.y));", st.fsIn()); fsBuilder->codeAppend("vec2 offset = vec2(dy*delta, 0.0);"); } else { fsBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn()); fsBuilder->codeAppend("vec2 Jdx = dFdx(st);"); fsBuilder->codeAppend("vec2 Jdy = dFdy(st);"); fsBuilder->codeAppend("vec2 offset = delta*Jdx;"); } // green is distance to uv center fsBuilder->codeAppend("\tvec4 texColor = "); fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType); fsBuilder->codeAppend(";\n"); fsBuilder->codeAppend("\tvec3 distance;\n"); fsBuilder->codeAppend("\tdistance.y = texColor.r;\n"); // red is distance to left offset fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n"); fsBuilder->codeAppend("\ttexColor = "); fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType); fsBuilder->codeAppend(";\n"); fsBuilder->codeAppend("\tdistance.x = texColor.r;\n"); // blue is distance to right offset fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n"); fsBuilder->codeAppend("\ttexColor = "); fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType); fsBuilder->codeAppend(";\n"); fsBuilder->codeAppend("\tdistance.z = texColor.r;\n"); fsBuilder->codeAppend("\tdistance = " "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));"); // adjust width based on gamma const char* distanceAdjustUniName = NULL; fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType, kDefault_GrSLPrecision, "DistanceAdjust", &distanceAdjustUniName); fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); // To be strictly correct, we should compute the anti-aliasing factor separately // for each color component. However, this is only important when using perspective // transformations, and even then using a single factor seems like a reasonable // trade-off between quality and speed. fsBuilder->codeAppend("float afwidth;"); if (isUniformScale) { // For uniform scale, we adjust for the effect of the transformation on the distance // by using the length of the gradient of the texture coordinates. We use st coordinates // to ensure we're mapping 1:1 from texel space to pixel space. // this gives us a smooth step across approximately one fragment fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*dy;"); } else { // For general transforms, to determine the amount of correction we multiply a unit // vector pointing along the SDF gradient direction by the Jacobian of the st coords // (which is the inverse transform for this fragment) and take the length of the result. fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));"); // the length of the gradient may be 0, so we need to check for this // this also compensates for the Adreno, which likes to drop tiles on division by 0 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); fsBuilder->codeAppend("if (dg_len2 < 0.0001) {"); fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); fsBuilder->codeAppend("} else {"); fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);"); fsBuilder->codeAppend("}"); fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); // this gives us a smooth step across approximately one fragment fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); } fsBuilder->codeAppend( "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);"); fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage); }