void GrGLNormalPathProcessor::emitTransforms(GrGLGPBuilder* pb, const TransformsIn& tin, TransformsOut* tout) { tout->push_back_n(tin.count()); fInstalledTransforms.push_back_n(tin.count()); for (int i = 0; i < tin.count(); i++) { const ProcCoords& coordTransforms = tin[i]; fInstalledTransforms[i].push_back_n(coordTransforms.count()); for (int t = 0; t < coordTransforms.count(); t++) { GrSLType varyingType = coordTransforms[t]->getMatrix().hasPerspective() ? kVec3f_GrSLType : kVec2f_GrSLType; SkString strVaryingName("MatrixCoord"); strVaryingName.appendf("_%i_%i", i, t); GrGLVertToFrag v(varyingType); pb->addVarying(strVaryingName.c_str(), &v); SeparableVaryingInfo& varyingInfo = fSeparableVaryingInfos.push_back(); varyingInfo.fVariable = pb->getFragmentShaderBuilder()->fInputs.back(); varyingInfo.fLocation = fSeparableVaryingInfos.count() - 1; varyingInfo.fType = varyingType; fInstalledTransforms[i][t].fHandle = ShaderVarHandle(varyingInfo.fLocation); fInstalledTransforms[i][t].fType = varyingType; SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords, (SkString(v.fsIn()), varyingType)); } } }
void emitTransforms(GrGLSLVaryingHandler* varyingHandler, const TransformsIn& tin, TransformsOut* tout) { tout->push_back_n(tin.count()); fInstalledTransforms.push_back_n(tin.count()); for (int i = 0; i < tin.count(); i++) { const ProcCoords& coordTransforms = tin[i]; fInstalledTransforms[i].push_back_n(coordTransforms.count()); for (int t = 0; t < coordTransforms.count(); t++) { GrSLType varyingType = coordTransforms[t]->getMatrix().hasPerspective() ? kVec3f_GrSLType : kVec2f_GrSLType; SkString strVaryingName("MatrixCoord"); strVaryingName.appendf("_%i_%i", i, t); GrGLSLVertToFrag v(varyingType); GrGLVaryingHandler* glVaryingHandler = (GrGLVaryingHandler*) varyingHandler; fInstalledTransforms[i][t].fHandle = glVaryingHandler->addPathProcessingVarying(strVaryingName.c_str(), &v).toIndex(); fInstalledTransforms[i][t].fType = varyingType; SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLSLTransformedCoords, (SkString(v.fsIn()), varyingType)); } } }
void GrGLPathTexGenProgramEffects::setupPathTexGen(GrGLFragmentOnlyShaderBuilder* builder, const GrDrawEffect& drawEffect, TransformedCoordsArray* outCoords) { int numTransforms = drawEffect.effect()->numTransforms(); uint32_t totalKey = GenTransformKey(drawEffect); int texCoordIndex = builder->addTexCoordSets(numTransforms); SkNEW_APPEND_TO_TARRAY(&fTransforms, Transforms, (totalKey, texCoordIndex)); SkString name; for (int t = 0; t < numTransforms; ++t) { GrSLType type = kGeneral_MatrixType == get_matrix_type(totalKey, t) ? kVec3f_GrSLType : kVec2f_GrSLType; name.printf("%s(gl_TexCoord[%i])", GrGLSLTypeString(type), texCoordIndex++); SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords, (name, type)); } }
void GrGLVertexProgramEffects::emitTransforms(GrGLFullShaderBuilder* builder, const GrDrawEffect& drawEffect, TransformedCoordsArray* outCoords) { SkTArray<Transform, true>& transforms = fTransforms.push_back(); uint32_t totalKey = GenTransformKey(drawEffect); int numTransforms = drawEffect.effect()->numTransforms(); transforms.push_back_n(numTransforms); for (int t = 0; t < numTransforms; t++) { GrSLType varyingType = kVoid_GrSLType; const char* uniName; switch (get_matrix_type(totalKey, t)) { case kNoPersp_MatrixType: uniName = "StageMatrix"; varyingType = kVec2f_GrSLType; break; case kGeneral_MatrixType: uniName = "StageMatrix"; varyingType = kVec3f_GrSLType; break; default: SkFAIL("Unexpected key."); } SkString suffixedUniName; if (0 != t) { suffixedUniName.append(uniName); suffixedUniName.appendf("_%i", t); uniName = suffixedUniName.c_str(); } transforms[t].fHandle = builder->addUniform(GrGLShaderBuilder::kVertex_Visibility, kMat33f_GrSLType, uniName, &uniName); const char* varyingName = "MatrixCoord"; SkString suffixedVaryingName; if (0 != t) { suffixedVaryingName.append(varyingName); suffixedVaryingName.appendf("_%i", t); varyingName = suffixedVaryingName.c_str(); } const char* vsVaryingName; const char* fsVaryingName; builder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName); const GrGLShaderVar& coords = kPosition_GrCoordSet == get_source_coords(totalKey, t) ? builder->positionAttribute() : builder->localCoordsAttribute(); // varying = matrix * coords (logically) SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType); if (kVec2f_GrSLType == varyingType) { builder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n", vsVaryingName, uniName, coords.c_str()); } else { builder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n", vsVaryingName, uniName, coords.c_str()); } SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords, (SkString(fsVaryingName), varyingType)); } }
void GrGLNvprProgramBuilder::emitTransforms(const GrFragmentStage& processorStage, GrGLProcessor::TransformedCoordsArray* outCoords, GrGLInstalledFragProc* ifp) { const GrFragmentProcessor* effect = processorStage.getProcessor(); int numTransforms = effect->numTransforms(); ifp->fTransforms.push_back_n(numTransforms); for (int t = 0; t < numTransforms; t++) { GrSLType varyingType = processorStage.isPerspectiveCoordTransform(t, false) ? kVec3f_GrSLType : kVec2f_GrSLType; const char* varyingName = "MatrixCoord"; SkString suffixedVaryingName; if (0 != t) { suffixedVaryingName.append(varyingName); suffixedVaryingName.appendf("_%i", t); varyingName = suffixedVaryingName.c_str(); } GrGLVertToFrag v(varyingType); ifp->fTransforms[t].fHandle = this->addSeparableVarying(varyingName, &v); ifp->fTransforms[t].fType = varyingType; SkNEW_APPEND_TO_TARRAY(outCoords, GrGLProcessor::TransformedCoords, (SkString(v.fsIn()), varyingType)); } }
void GrGLPathTexGenProgramEffects::setupPathTexGen(GrGLFragmentOnlyShaderBuilder* builder, const GrEffectRef& effect, EffectKey effectKey, TransformedCoordsArray* outCoords) { int numTransforms = effect->numTransforms(); EffectKey totalKey = GrBackendEffectFactory::GetTransformKey(effectKey); int texCoordIndex = builder->addTexCoordSets(numTransforms); SkNEW_APPEND_TO_TARRAY(&fTransforms, Transforms, (totalKey, texCoordIndex)); SkString name; for (int t = 0; t < numTransforms; ++t) { GrSLType type = kGeneral_MatrixType == get_matrix_type(totalKey, t) ? kVec3f_GrSLType : kVec2f_GrSLType; name.printf("%s(gl_TexCoord[%i])", GrGLSLTypeString(type), texCoordIndex++); SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords, (name, type)); } }
void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor, GrGLProcessor::TextureSamplerArray* outSamplers, GrGLInstalledProc<Proc>* ip) { int numTextures = processor.numTextures(); ip->fSamplers.push_back_n(numTextures); SkString name; for (int t = 0; t < numTextures; ++t) { name.printf("Sampler%d", t); ip->fSamplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility, kSampler2D_GrSLType, kDefault_GrSLPrecision, name.c_str()); SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler, (ip->fSamplers[t].fUniform, processor.textureAccess(t))); } }
void GrGLProgramEffects::emitSamplers(GrGLShaderBuilder* builder, const GrEffect* effect, TextureSamplerArray* outSamplers) { SkTArray<Sampler, true>& samplers = fSamplers.push_back(); int numTextures = effect->numTextures(); samplers.push_back_n(numTextures); SkString name; for (int t = 0; t < numTextures; ++t) { name.printf("Sampler%d", t); samplers[t].fUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kSampler2D_GrSLType, name.c_str()); SkNEW_APPEND_TO_TARRAY(outSamplers, TextureSampler, (samplers[t].fUniform, effect->textureAccess(t))); } }
void GrGLLegacyPathProcessor::emitTransforms(GrGLGPBuilder*, const TransformsIn& tin, TransformsOut* tout) { tout->push_back_n(tin.count()); fInstalledTransforms.push_back_n(tin.count()); for (int i = 0; i < tin.count(); i++) { const ProcCoords& coordTransforms = tin[i]; int texCoordIndex = this->addTexCoordSets(coordTransforms.count()); // Use the first uniform location as the texcoord index. fInstalledTransforms[i].push_back_n(1); fInstalledTransforms[i][0].fHandle = ShaderVarHandle(texCoordIndex); SkString name; for (int t = 0; t < coordTransforms.count(); ++t) { GrSLType type = coordTransforms[t]->getMatrix().hasPerspective() ? kVec3f_GrSLType : kVec2f_GrSLType; name.printf("%s(gl_TexCoord[%i])", GrGLSLTypeString(type), texCoordIndex++); SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords, (name, type)); } } }
void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor, GrGLSLTextureSampler::TextureSamplerArray* outSamplers) { int numTextures = processor.numTextures(); UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures); SkString name; for (int t = 0; t < numTextures; ++t) { name.printf("Sampler%d", t); GrSLType samplerType = get_sampler_type(processor.textureAccess(t)); localSamplerUniforms[t] = fUniformHandler.addUniform(GrGLSLUniformHandler::kFragment_Visibility, samplerType, kDefault_GrSLPrecision, name.c_str()); SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLSLTextureSampler, (localSamplerUniforms[t], processor.textureAccess(t))); if (kSamplerExternal_GrSLType == samplerType) { const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString(); // We shouldn't ever create a GrGLTexture that requires external sampler type SkASSERT(externalFeatureString); fFS.addFeature(1 << GrGLSLFragmentShaderBuilder::kExternalTexture_GLSLPrivateFeature, externalFeatureString); } } }
void GrGLGeometryProcessor::emitTransforms(GrGLGPBuilder* pb, const GrShaderVar& posVar, const char* localCoords, const SkMatrix& localMatrix, const TransformsIn& tin, TransformsOut* tout) { GrGLVertexBuilder* vb = pb->getVertexShaderBuilder(); tout->push_back_n(tin.count()); fInstalledTransforms.push_back_n(tin.count()); for (int i = 0; i < tin.count(); i++) { const ProcCoords& coordTransforms = tin[i]; fInstalledTransforms[i].push_back_n(coordTransforms.count()); for (int t = 0; t < coordTransforms.count(); t++) { SkString strUniName("StageMatrix"); strUniName.appendf("_%i_%i", i, t); GrSLType varyingType; GrCoordSet coordType = coordTransforms[t]->sourceCoords(); uint32_t type = coordTransforms[t]->getMatrix().getType(); if (kLocal_GrCoordSet == coordType) { type |= localMatrix.getType(); } varyingType = SkToBool(SkMatrix::kPerspective_Mask & type) ? kVec3f_GrSLType : kVec2f_GrSLType; GrSLPrecision precision = coordTransforms[t]->precision(); const char* uniName; fInstalledTransforms[i][t].fHandle = pb->addUniform(GrGLProgramBuilder::kVertex_Visibility, kMat33f_GrSLType, precision, strUniName.c_str(), &uniName).toShaderBuilderIndex(); SkString strVaryingName("MatrixCoord"); strVaryingName.appendf("_%i_%i", i, t); GrGLVertToFrag v(varyingType); pb->addVarying(strVaryingName.c_str(), &v, precision); SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType); SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords, (SkString(v.fsIn()), varyingType)); // varying = matrix * coords (logically) if (kDevice_GrCoordSet == coordType) { if (kVec2f_GrSLType == varyingType) { if (kVec2f_GrSLType == posVar.getType()) { vb->codeAppendf("%s = (%s * vec3(%s, 1)).xy;", v.vsOut(), uniName, posVar.c_str()); } else { // The brackets here are just to scope the temp variable vb->codeAppendf("{ vec3 temp = %s * %s;", uniName, posVar.c_str()); vb->codeAppendf("%s = vec2(temp.x/temp.z, temp.y/temp.z); }", v.vsOut()); } } else { if (kVec2f_GrSLType == posVar.getType()) { vb->codeAppendf("%s = %s * vec3(%s, 1);", v.vsOut(), uniName, posVar.c_str()); } else { vb->codeAppendf("%s = %s * %s;", v.vsOut(), uniName, posVar.c_str()); } } } else { if (kVec2f_GrSLType == varyingType) { vb->codeAppendf("%s = (%s * vec3(%s, 1)).xy;", v.vsOut(), uniName, localCoords); } else { vb->codeAppendf("%s = %s * vec3(%s, 1);", v.vsOut(), uniName, localCoords); } } } } }
// This test hammers the GPU textblobcache and font atlas static void text_blob_cache_inner(skiatest::Reporter* reporter, GrContext* context, int maxTotalText, int maxGlyphID, int maxFamilies, bool normal, bool stressTest) { // setup surface uint32_t flags = 0; SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType); // configure our context for maximum stressing of cache and atlas if (stressTest) { GrTest::SetupAlwaysEvictAtlas(context); context->setTextBlobCacheLimit_ForTesting(0); } SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kN32_SkColorType, kPremul_SkAlphaType); SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0, &props)); REPORTER_ASSERT(reporter, surface); if (!surface) { return; } SkCanvas* canvas = surface->getCanvas(); SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault()); int count = SkMin32(fm->countFamilies(), maxFamilies); // make a ton of text SkAutoTArray<uint16_t> text(maxTotalText); for (int i = 0; i < maxTotalText; i++) { text[i] = i % maxGlyphID; } // generate textblobs SkTArray<TextBlobWrapper> blobs; for (int i = 0; i < count; i++) { SkPaint paint; paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setTextSize(48); // draw big glyphs to really stress the atlas SkString familyName; fm->getFamilyName(i, &familyName); SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i)); for (int j = 0; j < set->count(); ++j) { SkFontStyle fs; set->getStyle(j, &fs, nullptr); // We use a typeface which randomy returns unexpected mask formats to fuzz SkAutoTUnref<SkTypeface> orig(set->createTypeface(j)); if (normal) { paint.setTypeface(orig); } else { SkAutoTUnref<SkTypeface> typeface(new SkRandomTypeface(orig, paint, true)); paint.setTypeface(typeface); } SkTextBlobBuilder builder; for (int aa = 0; aa < 2; aa++) { for (int subpixel = 0; subpixel < 2; subpixel++) { for (int lcd = 0; lcd < 2; lcd++) { paint.setAntiAlias(SkToBool(aa)); paint.setSubpixelText(SkToBool(subpixel)); paint.setLCDRenderText(SkToBool(lcd)); if (!SkToBool(lcd)) { paint.setTextSize(160); } const SkTextBlobBuilder::RunBuffer& run = builder.allocRun(paint, maxTotalText, 0, 0, nullptr); memcpy(run.glyphs, text.get(), maxTotalText * sizeof(uint16_t)); } } } SkNEW_APPEND_TO_TARRAY(&blobs, TextBlobWrapper, (builder.build())); } } // create surface where LCD is impossible info = SkImageInfo::MakeN32Premul(kWidth, kHeight); SkSurfaceProps propsNoLCD(0, kUnknown_SkPixelGeometry); SkAutoTUnref<SkSurface> surfaceNoLCD(canvas->newSurface(info, &propsNoLCD)); REPORTER_ASSERT(reporter, surface); if (!surface) { return; } SkCanvas* canvasNoLCD = surfaceNoLCD->getCanvas(); // test redraw draw(canvas, 2, blobs); draw(canvasNoLCD, 2, blobs); // test draw after free context->freeGpuResources(); draw(canvas, 1, blobs); context->freeGpuResources(); draw(canvasNoLCD, 1, blobs); // test draw after abandon context->abandonContext(); draw(canvas, 1, blobs); }
GrPipeline::GrPipeline(const GrPipelineBuilder& pipelineBuilder, const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, const GrDrawTargetCaps& caps, const GrScissorState& scissorState, const GrDeviceCoordTexture* dstCopy) { // Create XferProcessor from DS's XPFactory SkAutoTUnref<GrXferProcessor> xferProcessor( pipelineBuilder.getXPFactory()->createXferProcessor(colorPOI, coveragePOI, dstCopy, caps)); GrColor overrideColor = GrColor_ILLEGAL; if (colorPOI.firstEffectiveStageIndex() != 0) { overrideColor = colorPOI.inputColorToEffectiveStage(); } GrXferProcessor::OptFlags optFlags; if (xferProcessor) { fXferProcessor.reset(xferProcessor.get()); optFlags = xferProcessor->getOptimizations(colorPOI, coveragePOI, pipelineBuilder.getStencil().doesWrite(), &overrideColor, caps); } // When path rendering the stencil settings are not always set on the GrPipelineBuilder // so we must check the draw type. In cases where we will skip drawing we simply return a // null GrPipeline. if (!xferProcessor || (GrXferProcessor::kSkipDraw_OptFlag & optFlags)) { // Set the fields that don't default init and return. The lack of a render target will // indicate that this can be skipped. fFlags = 0; fDrawFace = GrPipelineBuilder::kInvalid_DrawFace; return; } fRenderTarget.reset(pipelineBuilder.fRenderTarget.get()); SkASSERT(fRenderTarget); fScissorState = scissorState; fStencilSettings = pipelineBuilder.getStencil(); fDrawFace = pipelineBuilder.getDrawFace(); fFlags = 0; if (pipelineBuilder.isHWAntialias()) { fFlags |= kHWAA_Flag; } if (pipelineBuilder.isDither()) { fFlags |= kDither_Flag; } if (pipelineBuilder.snapVerticesToPixelCenters()) { fFlags |= kSnapVertices_Flag; } int firstColorStageIdx = colorPOI.firstEffectiveStageIndex(); // TODO: Once we can handle single or four channel input into coverage stages then we can use // GrPipelineBuilder's coverageProcInfo (like color above) to set this initial information. int firstCoverageStageIdx = 0; this->adjustProgramFromOptimizations(pipelineBuilder, optFlags, colorPOI, coveragePOI, &firstColorStageIdx, &firstCoverageStageIdx); bool usesLocalCoords = false; // Copy Stages from PipelineBuilder to Pipeline for (int i = firstColorStageIdx; i < pipelineBuilder.numColorFragmentStages(); ++i) { SkNEW_APPEND_TO_TARRAY(&fFragmentStages, GrPendingFragmentStage, (pipelineBuilder.fColorStages[i])); usesLocalCoords = usesLocalCoords || pipelineBuilder.fColorStages[i].processor()->usesLocalCoords(); } fNumColorStages = fFragmentStages.count(); for (int i = firstCoverageStageIdx; i < pipelineBuilder.numCoverageFragmentStages(); ++i) { SkNEW_APPEND_TO_TARRAY(&fFragmentStages, GrPendingFragmentStage, (pipelineBuilder.fCoverageStages[i])); usesLocalCoords = usesLocalCoords || pipelineBuilder.fCoverageStages[i].processor()->usesLocalCoords(); } // let the GP init the batch tracker fInitBT.fColorIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreColor_OptFlag); fInitBT.fOverrideColor = fInitBT.fColorIgnored ? GrColor_ILLEGAL : overrideColor; fInitBT.fCoverageIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreCoverage_OptFlag); fInitBT.fUsesLocalCoords = usesLocalCoords; fInitBT.fCanTweakAlphaForCoverage = SkToBool(optFlags & GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag); }