static bool render_page(const SkString& outputDir, const SkString& inputFilename, const SkPdfRenderer& renderer, int page) { SkRect rect = renderer.MediaBox(page < 0 ? 0 :page); // Exercise all pdf codepaths as in normal rendering, but no actual bits are changed. if (!FLAGS_config.isEmpty() && strcmp(FLAGS_config[0], "nul") == 0) { SkBitmap bitmap; SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap))); SkNulCanvas canvas(device); renderer.renderPage(page < 0 ? 0 : page, &canvas, rect); } else { // 8888 SkRect rect = renderer.MediaBox(page < 0 ? 0 :page); SkBitmap bitmap; SkScalar width = SkScalarMul(rect.width(), SkDoubleToScalar(FLAGS_DPI / 72.0)); SkScalar height = SkScalarMul(rect.height(), SkDoubleToScalar(FLAGS_DPI / 72.0)); rect = SkRect::MakeWH(width, height); SkColor background = FLAGS_transparentBackground ? SK_ColorTRANSPARENT : SK_ColorWHITE; #ifdef PDF_DEBUG_3X setup_bitmap(&bitmap, 3 * (int)SkScalarToDouble(width), 3 * (int)SkScalarToDouble(height), background); #else setup_bitmap(&bitmap, (int)SkScalarToDouble(width), (int)SkScalarToDouble(height), background); #endif SkAutoTUnref<SkBaseDevice> device; if (strcmp(FLAGS_config[0], "8888") == 0) { device.reset(SkNEW_ARGS(SkBitmapDevice, (bitmap))); } #if SK_SUPPORT_GPU else if (strcmp(FLAGS_config[0], "gpu") == 0) { SkAutoTUnref<GrSurface> target; GrContext* gr = gContextFactory.get(GrContextFactory::kNative_GLContextType); if (gr) { // create a render target to back the device GrTextureDesc desc; desc.fConfig = kSkia8888_GrPixelConfig; desc.fFlags = kRenderTarget_GrTextureFlagBit; desc.fWidth = SkScalarCeilToInt(width); desc.fHeight = SkScalarCeilToInt(height); desc.fSampleCnt = 0; target.reset(gr->createUncachedTexture(desc, NULL, 0)); } if (NULL == target.get()) { SkASSERT(0); return false; } device.reset(SkGpuDevice::Create(target)); } #endif else { SkDebugf("unknown --config: %s\n", FLAGS_config[0]); return false; } SkCanvas canvas(device); #ifdef PDF_TRACE_DIFF_IN_PNG gDumpBitmap = &bitmap; gDumpCanvas = &canvas; #endif renderer.renderPage(page < 0 ? 0 : page, &canvas, rect); SkString outputPath; if (!make_output_filepath(&outputPath, outputDir, inputFilename, page)) { return false; } SkImageEncoder::EncodeFile(outputPath.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100); if (FLAGS_showMemoryUsage) { SkDebugf("Memory usage after page %i rendered: %u\n", page < 0 ? 0 : page, (unsigned int)renderer.bytesUsed()); } } return true; }
SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) { printf("Started\n"); v8::V8::SetFlagsFromCommandLine(&argc, argv, true); SkCommandLineFlags::Parse(argc, argv); v8::V8::InitializeICU(); v8::Platform* platform = v8::platform::CreateDefaultPlatform(); v8::V8::InitializePlatform(platform); v8::V8::Initialize(); v8::Isolate* isolate = v8::Isolate::New(); v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); isolate->Enter(); global = new Global(isolate); // Set up things to look like a browser by creating // a console object that invokes our print function. const char* startupScript = "function Console() {}; \n" "Console.prototype.log = function() { \n" " var args = Array.prototype.slice.call(arguments).join(' '); \n" " print(args); \n" "}; \n" "console = new Console(); \n"; if (!global->parseScript(startupScript)) { printf("Failed to parse startup script: %s.\n", FLAGS_infile[0]); exit(1); } const char* script = "function onDraw(canvas) { \n" " canvas.fillStyle = '#00FF00'; \n" " canvas.fillRect(20, 20, 100, 100); \n" " canvas.inval(); \n" "} \n"; SkAutoTUnref<SkData> data; if (FLAGS_infile.count()) { data.reset(SkData::NewFromFileName(FLAGS_infile[0])); script = static_cast<const char*>(data->data()); } if (NULL == script) { printf("Could not load file: %s.\n", FLAGS_infile[0]); exit(1); } Path2DBuilder::AddToGlobal(global); Path2D::AddToGlobal(global); if (!global->parseScript(script)) { printf("Failed to parse file: %s.\n", FLAGS_infile[0]); exit(1); } JsContext* jsContext = new JsContext(global); if (!jsContext->initialize()) { printf("Failed to initialize.\n"); exit(1); } SkV8ExampleWindow* win = new SkV8ExampleWindow(hwnd, jsContext); global->setWindow(win); return win; }
const GrGLInterface* GrGLCreateNullInterface() { // The gl functions are not context-specific so we create one global // interface static SkAutoTUnref<GrGLInterface> glInterface; if (!glInterface.get()) { GrGLInterface* interface = SkNEW(GrGLInterface); glInterface.reset(interface); interface->fBindingsExported = kDesktop_GrGLBinding; interface->fActiveTexture = nullGLActiveTexture; interface->fAttachShader = nullGLAttachShader; interface->fBeginQuery = nullGLBeginQuery; interface->fBindAttribLocation = nullGLBindAttribLocation; interface->fBindBuffer = nullGLBindBuffer; interface->fBindFragDataLocation = nullGLBindFragDataLocation; interface->fBindTexture = nullGLBindTexture; interface->fBlendColor = nullGLBlendColor; interface->fBlendFunc = nullGLBlendFunc; interface->fBufferData = nullGLBufferData; interface->fBufferSubData = nullGLBufferSubData; interface->fClear = nullGLClear; interface->fClearColor = nullGLClearColor; interface->fClearStencil = nullGLClearStencil; interface->fColorMask = nullGLColorMask; interface->fCompileShader = nullGLCompileShader; interface->fCompressedTexImage2D = nullGLCompressedTexImage2D; interface->fCreateProgram = nullGLCreateProgram; interface->fCreateShader = nullGLCreateShader; interface->fCullFace = nullGLCullFace; interface->fDeleteBuffers = nullGLDeleteBuffers; interface->fDeleteProgram = nullGLDelete; interface->fDeleteQueries = nullGLDeleteIds; interface->fDeleteShader = nullGLDelete; interface->fDeleteTextures = nullGLDeleteIds; interface->fDepthMask = nullGLDepthMask; interface->fDisable = nullGLDisable; interface->fDisableVertexAttribArray = nullGLDisableVertexAttribArray; interface->fDrawArrays = nullGLDrawArrays; interface->fDrawBuffer = nullGLDrawBuffer; interface->fDrawBuffers = nullGLDrawBuffers; interface->fDrawElements = nullGLDrawElements; interface->fEnable = nullGLEnable; interface->fEnableVertexAttribArray = nullGLEnableVertexAttribArray; interface->fEndQuery = nullGLEndQuery; interface->fFinish = nullGLFinish; interface->fFlush = nullGLFlush; interface->fFrontFace = nullGLFrontFace; interface->fGenBuffers = nullGLGenIds; interface->fGenQueries = nullGLGenIds; interface->fGenTextures = nullGLGenIds; interface->fGetBufferParameteriv = nullGLGetBufferParameteriv; interface->fGetError = nullGLGetError; interface->fGetIntegerv = nullGLGetIntegerv; interface->fGetQueryObjecti64v = nullGLGetQueryObjecti64v; interface->fGetQueryObjectiv = nullGLGetQueryObjectiv; interface->fGetQueryObjectui64v = nullGLGetQueryObjectui64v; interface->fGetQueryObjectuiv = nullGLGetQueryObjectuiv; interface->fGetQueryiv = nullGLGetQueryiv; interface->fGetProgramInfoLog = nullGLGetInfoLog; interface->fGetProgramiv = nullGLGetShaderOrProgramiv; interface->fGetShaderInfoLog = nullGLGetInfoLog; interface->fGetShaderiv = nullGLGetShaderOrProgramiv; interface->fGetString = nullGLGetString; interface->fGetTexLevelParameteriv = nullGLGetTexLevelParameteriv; interface->fGetUniformLocation = nullGLGetUniformLocation; interface->fLineWidth = nullGLLineWidth; interface->fLinkProgram = nullGLLinkProgram; interface->fPixelStorei = nullGLPixelStorei; interface->fQueryCounter = nullGLQueryCounter; interface->fReadBuffer = nullGLReadBuffer; interface->fReadPixels = nullGLReadPixels; interface->fScissor = nullGLScissor; interface->fShaderSource = nullGLShaderSource; interface->fStencilFunc = nullGLStencilFunc; interface->fStencilFuncSeparate = nullGLStencilFuncSeparate; interface->fStencilMask = nullGLStencilMask; interface->fStencilMaskSeparate = nullGLStencilMaskSeparate; interface->fStencilOp = nullGLStencilOp; interface->fStencilOpSeparate = nullGLStencilOpSeparate; interface->fTexImage2D = nullGLTexImage2D; interface->fTexParameteri = nullGLTexParameteri; interface->fTexParameteriv = nullGLTexParameteriv; interface->fTexSubImage2D = nullGLTexSubImage2D; interface->fTexStorage2D = nullGLTexStorage2D; interface->fUniform1f = nullGLUniform1f; interface->fUniform1i = nullGLUniform1i; interface->fUniform1fv = nullGLUniform1fv; interface->fUniform1iv = nullGLUniform1iv; interface->fUniform2f = nullGLUniform2f; interface->fUniform2i = nullGLUniform2i; interface->fUniform2fv = nullGLUniform2fv; interface->fUniform2iv = nullGLUniform2iv; interface->fUniform3f = nullGLUniform3f; interface->fUniform3i = nullGLUniform3i; interface->fUniform3fv = nullGLUniform3fv; interface->fUniform3iv = nullGLUniform3iv; interface->fUniform4f = nullGLUniform4f; interface->fUniform4i = nullGLUniform4i; interface->fUniform4fv = nullGLUniform4fv; interface->fUniform4iv = nullGLUniform4iv; interface->fUniformMatrix2fv = nullGLUniformMatrix2fv; interface->fUniformMatrix3fv = nullGLUniformMatrix3fv; interface->fUniformMatrix4fv = nullGLUniformMatrix4fv; interface->fUseProgram = nullGLUseProgram; interface->fVertexAttrib4fv = nullGLVertexAttrib4fv; interface->fVertexAttribPointer = nullGLVertexAttribPointer; interface->fViewport = nullGLViewport; interface->fBindFramebuffer = nullGLBindFramebuffer; interface->fBindRenderbuffer = nullGLBindRenderbuffer; interface->fCheckFramebufferStatus = nullGLCheckFramebufferStatus; interface->fDeleteFramebuffers = nullGLDeleteFramebuffers; interface->fDeleteRenderbuffers = nullGLDeleteRenderbuffers; interface->fFramebufferRenderbuffer = nullGLFramebufferRenderbuffer; interface->fFramebufferTexture2D = nullGLFramebufferTexture2D; interface->fGenFramebuffers = nullGLGenIds; interface->fGenRenderbuffers = nullGLGenIds; interface->fGetFramebufferAttachmentParameteriv = nullGLGetFramebufferAttachmentParameteriv; interface->fGetRenderbufferParameteriv = nullGLGetRenderbufferParameteriv; interface->fRenderbufferStorage = nullGLRenderbufferStorage; interface->fRenderbufferStorageMultisample = nullGLRenderbufferStorageMultisample; interface->fBlitFramebuffer = nullGLBlitFramebuffer; interface->fResolveMultisampleFramebuffer = nullGLResolveMultisampleFramebuffer; interface->fMapBuffer = nullGLMapBuffer; interface->fUnmapBuffer = nullGLUnmapBuffer; interface->fBindFragDataLocationIndexed = nullGLBindFragDataLocationIndexed; } glInterface.get()->ref(); return glInterface.get(); }
GrTexture* GaussianBlur(GrContext* context, GrTexture* srcTexture, bool canClobberSrc, const SkRect& dstBounds, const SkRect* srcBounds, float sigmaX, float sigmaY, GrTextureProvider::SizeConstraint constraint) { SkASSERT(context); SkIRect clearRect; int scaleFactorX, radiusX; int scaleFactorY, radiusY; int maxTextureSize = context->caps()->maxTextureSize(); sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX); sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY); SkPoint srcOffset = SkPoint::Make(-dstBounds.x(), -dstBounds.y()); SkRect localDstBounds = SkRect::MakeWH(dstBounds.width(), dstBounds.height()); SkRect localSrcBounds; SkRect srcRect; if (srcBounds) { srcRect = localSrcBounds = *srcBounds; srcRect.offset(srcOffset); srcBounds = &localSrcBounds; } else { srcRect = localDstBounds; } scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); srcRect.roundOut(&srcRect); scale_rect(&srcRect, static_cast<float>(scaleFactorX), static_cast<float>(scaleFactorY)); // setup new clip GrClip clip(localDstBounds); SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() || kRGBA_8888_GrPixelConfig == srcTexture->config() || kAlpha_8_GrPixelConfig == srcTexture->config()); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = SkScalarFloorToInt(dstBounds.width()); desc.fHeight = SkScalarFloorToInt(dstBounds.height()); desc.fConfig = srcTexture->config(); GrTexture* dstTexture; GrTexture* tempTexture; SkAutoTUnref<GrTexture> temp1, temp2; temp1.reset(context->textureProvider()->createTexture(desc, constraint)); dstTexture = temp1.get(); if (canClobberSrc) { tempTexture = srcTexture; } else { temp2.reset(context->textureProvider()->createTexture(desc, constraint)); tempTexture = temp2.get(); } if (nullptr == dstTexture || nullptr == tempTexture) { return nullptr; } SkAutoTUnref<GrDrawContext> srcDrawContext; for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { GrPaint paint; SkMatrix matrix; matrix.setIDiv(srcTexture->width(), srcTexture->height()); SkRect dstRect(srcRect); if (srcBounds && i == 1) { SkRect domain; matrix.mapRect(&domain, *srcBounds); domain.inset((i < scaleFactorX) ? SK_ScalarHalf / srcTexture->width() : 0.0f, (i < scaleFactorY) ? SK_ScalarHalf / srcTexture->height() : 0.0f); SkAutoTUnref<const GrFragmentProcessor> fp(GrTextureDomainEffect::Create( srcTexture, matrix, domain, GrTextureDomain::kDecal_Mode, GrTextureParams::kBilerp_FilterMode)); paint.addColorFragmentProcessor(fp); srcRect.offset(-srcOffset); srcOffset.set(0, 0); } else { GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); paint.addColorTextureProcessor(srcTexture, matrix, params); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, i < scaleFactorY ? 0.5f : 1.0f); SkAutoTUnref<GrDrawContext> dstDrawContext( context->drawContext(dstTexture->asRenderTarget())); if (!dstDrawContext) { return nullptr; } dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); srcDrawContext.swap(dstDrawContext); srcRect = dstRect; srcTexture = dstTexture; SkTSwap(dstTexture, tempTexture); localSrcBounds = srcRect; } // For really small blurs (certainly no wider than 5x5 on desktop gpus) it is faster to just // launch a single non separable kernel vs two launches srcRect = localDstBounds; if (sigmaX > 0.0f && sigmaY > 0.0f && (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) { // We shouldn't be scaling because this is a small size blur SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY)); SkAutoTUnref<GrDrawContext> dstDrawContext( context->drawContext(dstTexture->asRenderTarget())); if (!dstDrawContext) { return nullptr; } convolve_gaussian_2d(dstDrawContext, clip, srcRect, srcOffset, srcTexture, radiusX, radiusY, sigmaX, sigmaY, srcBounds); srcDrawContext.swap(dstDrawContext); srcRect.offsetTo(0, 0); srcTexture = dstTexture; SkTSwap(dstTexture, tempTexture); } else { scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); srcRect.roundOut(&srcRect); const SkIRect srcIRect = srcRect.roundOut(); if (sigmaX > 0.0f) { if (scaleFactorX > 1) { // TODO: if we pass in the source draw context we don't need this here if (!srcDrawContext) { srcDrawContext.reset(context->drawContext(srcTexture->asRenderTarget())); if (!srcDrawContext) { return nullptr; } } // Clear out a radius to the right of the srcRect to prevent the // X convolution from reading garbage. clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, radiusX, srcIRect.height()); srcDrawContext->clear(&clearRect, 0x0, false); } SkAutoTUnref<GrDrawContext> dstDrawContext( context->drawContext(dstTexture->asRenderTarget())); if (!dstDrawContext) { return nullptr; } convolve_gaussian(dstDrawContext, clip, srcRect, srcTexture, Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, srcBounds, srcOffset); srcDrawContext.swap(dstDrawContext); srcTexture = dstTexture; srcRect.offsetTo(0, 0); SkTSwap(dstTexture, tempTexture); localSrcBounds = srcRect; srcOffset.set(0, 0); } if (sigmaY > 0.0f) { if (scaleFactorY > 1 || sigmaX > 0.0f) { // TODO: if we pass in the source draw context we don't need this here if (!srcDrawContext) { srcDrawContext.reset(context->drawContext(srcTexture->asRenderTarget())); if (!srcDrawContext) { return nullptr; } } // Clear out a radius below the srcRect to prevent the Y // convolution from reading garbage. clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, srcIRect.width(), radiusY); srcDrawContext->clear(&clearRect, 0x0, false); } SkAutoTUnref<GrDrawContext> dstDrawContext( context->drawContext(dstTexture->asRenderTarget())); if (!dstDrawContext) { return nullptr; } convolve_gaussian(dstDrawContext, clip, srcRect, srcTexture, Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, srcBounds, srcOffset); srcDrawContext.swap(dstDrawContext); srcTexture = dstTexture; srcRect.offsetTo(0, 0); SkTSwap(dstTexture, tempTexture); } } const SkIRect srcIRect = srcRect.roundOut(); if (scaleFactorX > 1 || scaleFactorY > 1) { SkASSERT(srcDrawContext); // Clear one pixel to the right and below, to accommodate bilinear // upsampling. clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, srcIRect.width() + 1, 1); srcDrawContext->clear(&clearRect, 0x0, false); clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, 1, srcIRect.height()); srcDrawContext->clear(&clearRect, 0x0, false); SkMatrix matrix; matrix.setIDiv(srcTexture->width(), srcTexture->height()); GrPaint paint; // FIXME: this should be mitchell, not bilinear. GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); paint.addColorTextureProcessor(srcTexture, matrix, params); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkRect dstRect(srcRect); scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY); SkAutoTUnref<GrDrawContext> dstDrawContext( context->drawContext(dstTexture->asRenderTarget())); if (!dstDrawContext) { return nullptr; } dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); srcDrawContext.swap(dstDrawContext); srcRect = dstRect; srcTexture = dstTexture; SkTSwap(dstTexture, tempTexture); } return SkRef(srcTexture); }
void onDraw(SkCanvas* canvas) override{ SkPaint blackFill; //----------- // Normal paints (no source) SkTArray<SkPaint> paints; create_paints(nullptr, &paints); //----------- // Paints with a PictureImageFilter as a source SkAutoTUnref<SkPicture> pic; { SkPictureRecorder rec; SkCanvas* c = rec.beginRecording(10, 10); c->drawRect(SkRect::MakeWH(10, 10), blackFill); pic.reset(rec.endRecording()); } SkAutoTUnref<SkPictureImageFilter> pif(SkPictureImageFilter::Create(pic)); SkTArray<SkPaint> pifPaints; create_paints(pif, &pifPaints); //----------- // Paints with a SkImageSource as a source SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(10, 10)); { SkPaint p; SkCanvas* temp = surface->getCanvas(); temp->clear(SK_ColorYELLOW); p.setColor(SK_ColorBLUE); temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p); p.setColor(SK_ColorGREEN); temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p); } SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); SkAutoTUnref<SkImageFilter> imageSource(SkImageSource::Create(image)); SkTArray<SkPaint> bmsPaints; create_paints(imageSource, &bmsPaints); //----------- SkASSERT(paints.count() == kNumVertTiles); SkASSERT(paints.count() == pifPaints.count()); SkASSERT(paints.count() == bmsPaints.count()); // horizontal separators for (int i = 1; i < paints.count(); ++i) { canvas->drawLine(0, i*SkIntToScalar(kTileHeight), SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth), i*SkIntToScalar(kTileHeight), blackFill); } // vertical separators for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) { canvas->drawLine(SkIntToScalar(i * kTileWidth), 0, SkIntToScalar(i * kTileWidth), SkIntToScalar(paints.count() * kTileWidth), blackFill); } // A column of saveLayers with PictureImageFilters for (int i = 0; i < pifPaints.count(); ++i) { draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight), canvas, pifPaints[i]); } // A column of saveLayers with BitmapSources for (int i = 0; i < pifPaints.count(); ++i) { draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight), canvas, bmsPaints[i]); } // Multiple columns with different geometry for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) { for (int j = 0; j < paints.count(); ++j) { draw_geom_with_paint(*gDrawMthds[i], SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight), canvas, paints[j]); } } }
GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args, GrXPOverridesForBatch* overrides) { const GrPipelineBuilder& builder = *args.fPipelineBuilder; GrPipeline* pipeline = new (memory) GrPipeline; pipeline->fRenderTarget.reset(builder.fRenderTarget.get()); SkASSERT(pipeline->fRenderTarget); pipeline->fScissorState = *args.fScissor; if (builder.hasUserStencilSettings() || args.fHasStencilClip) { const GrRenderTargetPriv& rtPriv = builder.getRenderTarget()->renderTargetPriv(); pipeline->fStencilSettings.reset(*builder.getUserStencil(), args.fHasStencilClip, rtPriv.numStencilBits()); SkASSERT(!pipeline->fStencilSettings.usesWrapOp() || args.fCaps->stencilWrapOpsSupport()); } pipeline->fDrawFace = builder.getDrawFace(); pipeline->fFlags = 0; if (builder.isHWAntialias()) { pipeline->fFlags |= kHWAA_Flag; } if (builder.snapVerticesToPixelCenters()) { pipeline->fFlags |= kSnapVertices_Flag; } if (builder.getDisableOutputConversionToSRGB()) { pipeline->fFlags |= kDisableOutputConversionToSRGB_Flag; } if (builder.getAllowSRGBInputs()) { pipeline->fFlags |= kAllowSRGBInputs_Flag; } if (args.fHasStencilClip) { pipeline->fFlags |= kHasStencilClip_Flag; } // Create XferProcessor from DS's XPFactory bool hasMixedSamples = builder.getRenderTarget()->hasMixedSamples() && (builder.isHWAntialias() || !pipeline->fStencilSettings.isDisabled()); const GrXPFactory* xpFactory = builder.getXPFactory(); SkAutoTUnref<GrXferProcessor> xferProcessor; if (xpFactory) { xferProcessor.reset(xpFactory->createXferProcessor(args.fOpts, hasMixedSamples, &args.fDstTexture, *args.fCaps)); if (!xferProcessor) { pipeline->~GrPipeline(); return nullptr; } } else { // This may return nullptr in the common case of src-over implemented using hw blending. xferProcessor.reset(GrPorterDuffXPFactory::CreateSrcOverXferProcessor( *args.fCaps, args.fOpts, hasMixedSamples, &args.fDstTexture)); } GrColor overrideColor = GrColor_ILLEGAL; if (args.fOpts.fColorPOI.firstEffectiveProcessorIndex() != 0) { overrideColor = args.fOpts.fColorPOI.inputColorToFirstEffectiveProccesor(); } GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags; const GrXferProcessor* xpForOpts = xferProcessor ? xferProcessor.get() : &GrPorterDuffXPFactory::SimpleSrcOverXP(); optFlags = xpForOpts->getOptimizations(args.fOpts, pipeline->fStencilSettings.doesWrite(), &overrideColor, *args.fCaps); // 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 (GrXferProcessor::kSkipDraw_OptFlag & optFlags) { pipeline->~GrPipeline(); return nullptr; } // No need to have an override color if it isn't even going to be used. if (SkToBool(GrXferProcessor::kIgnoreColor_OptFlag & optFlags)) { overrideColor = GrColor_ILLEGAL; } pipeline->fXferProcessor.reset(xferProcessor); int firstColorProcessorIdx = args.fOpts.fColorPOI.firstEffectiveProcessorIndex(); // TODO: Once we can handle single or four channel input into coverage GrFragmentProcessors // then we can use GrPipelineBuilder's coverageProcInfo (like color above) to set this initial // information. int firstCoverageProcessorIdx = 0; pipeline->adjustProgramFromOptimizations(builder, optFlags, args.fOpts.fColorPOI, args.fOpts.fCoveragePOI, &firstColorProcessorIdx, &firstCoverageProcessorIdx); bool usesLocalCoords = false; // Copy GrFragmentProcessors from GrPipelineBuilder to Pipeline pipeline->fNumColorProcessors = builder.numColorFragmentProcessors() - firstColorProcessorIdx; int numTotalProcessors = pipeline->fNumColorProcessors + builder.numCoverageFragmentProcessors() - firstCoverageProcessorIdx; pipeline->fFragmentProcessors.reset(numTotalProcessors); int currFPIdx = 0; for (int i = firstColorProcessorIdx; i < builder.numColorFragmentProcessors(); ++i, ++currFPIdx) { const GrFragmentProcessor* fp = builder.getColorFragmentProcessor(i); pipeline->fFragmentProcessors[currFPIdx].reset(fp); usesLocalCoords = usesLocalCoords || fp->usesLocalCoords(); } for (int i = firstCoverageProcessorIdx; i < builder.numCoverageFragmentProcessors(); ++i, ++currFPIdx) { const GrFragmentProcessor* fp = builder.getCoverageFragmentProcessor(i); pipeline->fFragmentProcessors[currFPIdx].reset(fp); usesLocalCoords = usesLocalCoords || fp->usesLocalCoords(); } // Setup info we need to pass to GrPrimitiveProcessors that are used with this GrPipeline. overrides->fFlags = 0; if (!SkToBool(optFlags & GrXferProcessor::kIgnoreColor_OptFlag)) { overrides->fFlags |= GrXPOverridesForBatch::kReadsColor_Flag; } if (GrColor_ILLEGAL != overrideColor) { overrides->fFlags |= GrXPOverridesForBatch::kUseOverrideColor_Flag; overrides->fOverrideColor = overrideColor; } if (!SkToBool(optFlags & GrXferProcessor::kIgnoreCoverage_OptFlag)) { overrides->fFlags |= GrXPOverridesForBatch::kReadsCoverage_Flag; } if (usesLocalCoords) { overrides->fFlags |= GrXPOverridesForBatch::kReadsLocalCoords_Flag; } if (SkToBool(optFlags & GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag)) { overrides->fFlags |= GrXPOverridesForBatch::kCanTweakAlphaForCoverage_Flag; } GrXPFactory::InvariantBlendedColor blendedColor; if (xpFactory) { xpFactory->getInvariantBlendedColor(args.fOpts.fColorPOI, &blendedColor); } else { GrPorterDuffXPFactory::SrcOverInvariantBlendedColor(args.fOpts.fColorPOI.color(), args.fOpts.fColorPOI.validFlags(), args.fOpts.fColorPOI.isOpaque(), &blendedColor); } if (blendedColor.fWillBlendWithDst) { overrides->fFlags |= GrXPOverridesForBatch::kWillColorBlendWithDst_Flag; } return pipeline; }
static GrTexture* load_yuv_texture(GrContext* ctx, const GrUniqueKey& optionalKey, const SkBitmap& bm, const GrSurfaceDesc& desc) { // Subsets are not supported, the whole pixelRef is loaded when using YUV decoding SkPixelRef* pixelRef = bm.pixelRef(); if ((nullptr == pixelRef) || (pixelRef->info().width() != bm.info().width()) || (pixelRef->info().height() != bm.info().height())) { return nullptr; } const bool useCache = optionalKey.isValid(); SkYUVPlanesCache::Info yuvInfo; SkAutoTUnref<SkCachedData> cachedData; SkAutoMalloc storage; if (useCache) { cachedData.reset(SkYUVPlanesCache::FindAndRef(pixelRef->getGenerationID(), &yuvInfo)); } void* planes[3]; if (cachedData.get()) { planes[0] = (void*)cachedData->data(); planes[1] = (uint8_t*)planes[0] + yuvInfo.fSizeInMemory[0]; planes[2] = (uint8_t*)planes[1] + yuvInfo.fSizeInMemory[1]; } else { // Fetch yuv plane sizes for memory allocation. Here, width and height can be // rounded up to JPEG block size and be larger than the image's width and height. if (!pixelRef->getYUV8Planes(yuvInfo.fSize, nullptr, nullptr, nullptr)) { return nullptr; } // Allocate the memory for YUV size_t totalSize(0); for (int i = 0; i < 3; ++i) { yuvInfo.fRowBytes[i] = yuvInfo.fSize[i].fWidth; yuvInfo.fSizeInMemory[i] = yuvInfo.fRowBytes[i] * yuvInfo.fSize[i].fHeight; totalSize += yuvInfo.fSizeInMemory[i]; } if (useCache) { cachedData.reset(SkResourceCache::NewCachedData(totalSize)); planes[0] = cachedData->writable_data(); } else { storage.reset(totalSize); planes[0] = storage.get(); } planes[1] = (uint8_t*)planes[0] + yuvInfo.fSizeInMemory[0]; planes[2] = (uint8_t*)planes[1] + yuvInfo.fSizeInMemory[1]; // Get the YUV planes and update plane sizes to actual image size if (!pixelRef->getYUV8Planes(yuvInfo.fSize, planes, yuvInfo.fRowBytes, &yuvInfo.fColorSpace)) { return nullptr; } if (useCache) { // Decoding is done, cache the resulting YUV planes SkYUVPlanesCache::Add(pixelRef->getGenerationID(), cachedData, &yuvInfo); } } GrSurfaceDesc yuvDesc; yuvDesc.fConfig = kAlpha_8_GrPixelConfig; SkAutoTUnref<GrTexture> yuvTextures[3]; for (int i = 0; i < 3; ++i) { yuvDesc.fWidth = yuvInfo.fSize[i].fWidth; yuvDesc.fHeight = yuvInfo.fSize[i].fHeight; bool needsExactTexture = (yuvDesc.fWidth != yuvInfo.fSize[0].fWidth) || (yuvDesc.fHeight != yuvInfo.fSize[0].fHeight); if (needsExactTexture) { yuvTextures[i].reset(ctx->textureProvider()->createTexture(yuvDesc, true)); } else { yuvTextures[i].reset(ctx->textureProvider()->createApproxTexture(yuvDesc)); } if (!yuvTextures[i] || !yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight, yuvDesc.fConfig, planes[i], yuvInfo.fRowBytes[i])) { return nullptr; } } GrSurfaceDesc rtDesc = desc; rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag; GrTexture* result = create_texture_for_bmp(ctx, optionalKey, rtDesc, pixelRef, nullptr, 0); if (!result) { return nullptr; } GrRenderTarget* renderTarget = result->asRenderTarget(); SkASSERT(renderTarget); GrPaint paint; SkAutoTUnref<GrFragmentProcessor> yuvToRgbProcessor(GrYUVtoRGBEffect::Create(paint.getProcessorDataManager(), yuvTextures[0], yuvTextures[1], yuvTextures[2], yuvInfo.fSize, yuvInfo.fColorSpace)); paint.addColorFragmentProcessor(yuvToRgbProcessor); SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth), SkIntToScalar(yuvInfo.fSize[0].fHeight)); GrDrawContext* drawContext = ctx->drawContext(); if (!drawContext) { return nullptr; } drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, SkMatrix::I(), r); return result; }
static int filter_picture(const SkString& inFile, const SkString& outFile) { SkAutoTUnref<SkPicture> inPicture; SkFILEStream inStream(inFile.c_str()); if (inStream.isValid()) { inPicture.reset(SkPicture::CreateFromStream(&inStream)); } if (nullptr == inPicture.get()) { SkDebugf("Could not read file %s\n", inFile.c_str()); return -1; } int localCount[SK_ARRAY_COUNT(gOptTable)]; memset(localCount, 0, sizeof(localCount)); SkDebugCanvas debugCanvas(SkScalarCeilToInt(inPicture->cullRect().width()), SkScalarCeilToInt(inPicture->cullRect().height())); inPicture->playback(&debugCanvas); // delete the initial save and restore since replaying the commands will // re-add them if (debugCanvas.getSize() > 1) { debugCanvas.deleteDrawCommandAt(0); debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1); } bool changed = true; int numBefore = debugCanvas.getSize(); while (changed) { changed = false; for (int i = 0; i < debugCanvas.getSize(); ++i) { for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) { (*gOptTable[opt].fApply)(&debugCanvas, i); ++gOptTable[opt].fNumTimesApplied; ++localCount[opt]; if (debugCanvas.getSize() == i) { // the optimization removed all the remaining operations break; } opt = 0; // try all the opts all over again changed = true; } } } } int numAfter = debugCanvas.getSize(); if (!outFile.isEmpty()) { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(inPicture->cullRect().width(), inPicture->cullRect().height(), nullptr, 0); debugCanvas.draw(canvas); SkAutoTUnref<SkPicture> outPicture(recorder.endRecording()); SkFILEWStream outStream(outFile.c_str()); outPicture->serialize(&outStream); } bool someOptFired = false; for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) { if (0 != localCount[opt]) { SkDebugf("%d: %d ", opt, localCount[opt]); someOptFired = true; } } if (!someOptFired) { SkDebugf("No opts fired\n"); } else { SkDebugf("\t before: %d after: %d delta: %d\n", numBefore, numAfter, numBefore-numAfter); } return 0; }
GrContext* GrContextFactory::get(GLContextType type, GrGLStandard forcedGpuAPI) { for (int i = 0; i < fContexts.count(); ++i) { if (forcedGpuAPI != kNone_GrGLStandard && forcedGpuAPI != fContexts[i].fGLContext->gl()->fStandard) continue; if (fContexts[i].fType == type) { fContexts[i].fGLContext->makeCurrent(); return fContexts[i].fGrContext; } } SkAutoTUnref<SkGLContext> glCtx; SkAutoTUnref<GrContext> grCtx; switch (type) { case kNVPR_GLContextType: // fallthru case kNative_GLContextType: glCtx.reset(SkCreatePlatformGLContext(forcedGpuAPI)); break; #ifdef SK_ANGLE case kANGLE_GLContextType: glCtx.reset(SkANGLEGLContext::Create(forcedGpuAPI)); break; #endif #ifdef SK_MESA case kMESA_GLContextType: glCtx.reset(SkMesaGLContext::Create(forcedGpuAPI)); break; #endif case kNull_GLContextType: glCtx.reset(SkNullGLContext::Create(forcedGpuAPI)); break; case kDebug_GLContextType: glCtx.reset(SkDebugGLContext::Create(forcedGpuAPI)); break; } if (NULL == glCtx.get()) { return NULL; } SkASSERT(glCtx->isValid()); // Block NVPR from non-NVPR types. SkAutoTUnref<const GrGLInterface> glInterface(SkRef(glCtx->gl())); if (kNVPR_GLContextType != type) { glInterface.reset(GrGLInterfaceRemoveNVPR(glInterface)); if (!glInterface) { return NULL; } } else { if (!glInterface->hasExtension("GL_NV_path_rendering")) { return NULL; } } glCtx->makeCurrent(); GrBackendContext p3dctx = reinterpret_cast<GrBackendContext>(glInterface.get()); grCtx.reset(GrContext::Create(kOpenGL_GrBackend, p3dctx, fGlobalOptions)); if (!grCtx.get()) { return NULL; } // Warn if path rendering support is not available for the NVPR type. if (kNVPR_GLContextType == type) { if (!grCtx->caps()->shaderCaps()->pathRenderingSupport()) { GrGLGpu* gpu = static_cast<GrGLGpu*>(grCtx->getGpu()); const GrGLubyte* verUByte; GR_GL_CALL_RET(gpu->glInterface(), verUByte, GetString(GR_GL_VERSION)); const char* ver = reinterpret_cast<const char*>(verUByte); SkDebugf("\nWARNING: nvprmsaa config requested, but driver path rendering support not" " available. Maybe update the driver? Your driver version string: \"%s\"\n", ver); } } GPUContext& ctx = fContexts.push_back(); ctx.fGLContext = glCtx.get(); ctx.fGLContext->ref(); ctx.fGrContext = grCtx.get(); ctx.fGrContext->ref(); ctx.fType = type; return ctx.fGrContext; }
DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) { SkRecord record; SkRecorder recorder(&record, W, H); SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200)); SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60)); SkPaint alphaOnlyLayerPaint; alphaOnlyLayerPaint.setColor(0x03000000); // Only alpha. SkPaint translucentLayerPaint; translucentLayerPaint.setColor(0x03040506); // Not only alpha. SkPaint xfermodePaint; xfermodePaint.setXfermodeMode(SkXfermode::kDstIn_Mode); SkPaint colorFilterPaint; colorFilterPaint.setColorFilter( SkColorFilter::CreateModeFilter(SK_ColorLTGRAY, SkXfermode::kSrcIn_Mode))->unref(); SkPaint opaqueFilterLayerPaint; opaqueFilterLayerPaint.setColor(0xFF020202); // Opaque. SkPaint translucentFilterLayerPaint; translucentFilterLayerPaint.setColor(0x0F020202); // Not opaque. SkAutoTUnref<SkPicture> shape; { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100)); SkPaint shapePaint; shapePaint.setColor(SK_ColorWHITE); canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint); shape.reset(recorder.endRecordingAsPicture()); } translucentFilterLayerPaint.setImageFilter(SkPictureImageFilter::Create(shape))->unref(); int index = 0; { // Any combination of these should cause the pattern to be optimized. SkRect* firstBounds[] = { NULL, &bounds }; SkPaint* firstPaints[] = { NULL, &alphaOnlyLayerPaint }; SkRect* secondBounds[] = { NULL, &bounds }; SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint }; for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) { for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) { for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) { for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) { recorder.saveLayer(firstBounds[i], firstPaints[j]); recorder.save(); recorder.clipRect(clip); recorder.saveLayer(secondBounds[k], secondPaints[m]); recorder.restore(); recorder.restore(); recorder.restore(); assert_merge_svg_opacity_and_filter_layers(r, &record, index, true); index += 7; } } } } } // These should cause the pattern to stay unoptimized: struct { SkPaint* firstPaint; SkPaint* secondPaint; } noChangeTests[] = { // No change: NULL filter layer paint not implemented. { &alphaOnlyLayerPaint, NULL }, // No change: layer paint is not alpha-only. { &translucentLayerPaint, &opaqueFilterLayerPaint }, // No change: layer paint has an xfereffect. { &xfermodePaint, &opaqueFilterLayerPaint }, // No change: filter layer paint has an xfereffect. { &alphaOnlyLayerPaint, &xfermodePaint }, // No change: layer paint has a color filter. { &colorFilterPaint, &opaqueFilterLayerPaint }, // No change: filter layer paint has a color filter (until the optimization accounts for // constant color draws that can filter the color). { &alphaOnlyLayerPaint, &colorFilterPaint } }; for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) { recorder.saveLayer(NULL, noChangeTests[i].firstPaint); recorder.save(); recorder.clipRect(clip); recorder.saveLayer(NULL, noChangeTests[i].secondPaint); recorder.restore(); recorder.restore(); recorder.restore(); assert_merge_svg_opacity_and_filter_layers(r, &record, index, false); index += 7; } // Test the folded alpha value. recorder.saveLayer(NULL, &alphaOnlyLayerPaint); recorder.save(); recorder.clipRect(clip); recorder.saveLayer(NULL, &opaqueFilterLayerPaint); recorder.restore(); recorder.restore(); recorder.restore(); assert_merge_svg_opacity_and_filter_layers(r, &record, index, true); const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3); REPORTER_ASSERT(r, saveLayer != NULL); REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202); index += 7; // Test that currently we do not fold alphas for patterns without the clip. This is just not // implemented. recorder.saveLayer(NULL, &alphaOnlyLayerPaint); recorder.saveLayer(NULL, &opaqueFilterLayerPaint); recorder.restore(); recorder.restore(); SkRecordMergeSvgOpacityAndFilterLayers(&record); assert_type<SkRecords::SaveLayer>(r, record, index); assert_type<SkRecords::SaveLayer>(r, record, index + 1); assert_type<SkRecords::Restore>(r, record, index + 2); assert_type<SkRecords::Restore>(r, record, index + 3); index += 4; }
GrContextFactory::ContextInfo* GrContextFactory::getContextInfo(GLContextType type, GLContextOptions options) { for (int i = 0; i < fContexts.count(); ++i) { if (fContexts[i]->fType == type && fContexts[i]->fOptions == options) { fContexts[i]->fGLContext->makeCurrent(); return fContexts[i]; } } SkAutoTUnref<SkGLContext> glCtx; SkAutoTUnref<GrContext> grCtx; switch (type) { case kNative_GLContextType: glCtx.reset(SkCreatePlatformGLContext(kNone_GrGLStandard)); break; case kGL_GLContextType: glCtx.reset(SkCreatePlatformGLContext(kGL_GrGLStandard)); break; case kGLES_GLContextType: glCtx.reset(SkCreatePlatformGLContext(kGLES_GrGLStandard)); break; #if SK_ANGLE #ifdef SK_BUILD_FOR_WIN case kANGLE_GLContextType: glCtx.reset(SkANGLEGLContext::CreateDirectX()); break; #endif case kANGLE_GL_GLContextType: glCtx.reset(SkANGLEGLContext::CreateOpenGL()); break; #endif #if SK_COMMAND_BUFFER case kCommandBuffer_GLContextType: glCtx.reset(SkCommandBufferGLContext::Create()); break; #endif #if SK_MESA case kMESA_GLContextType: glCtx.reset(SkMesaGLContext::Create()); break; #endif case kNull_GLContextType: glCtx.reset(SkNullGLContext::Create()); break; case kDebug_GLContextType: glCtx.reset(SkDebugGLContext::Create()); break; } if (nullptr == glCtx.get()) { return nullptr; } SkASSERT(glCtx->isValid()); // Block NVPR from non-NVPR types. SkAutoTUnref<const GrGLInterface> glInterface(SkRef(glCtx->gl())); if (!(kEnableNVPR_GLContextOptions & options)) { glInterface.reset(GrGLInterfaceRemoveNVPR(glInterface)); if (!glInterface) { return nullptr; } } glCtx->makeCurrent(); GrBackendContext p3dctx = reinterpret_cast<GrBackendContext>(glInterface.get()); #ifdef SK_VULKAN grCtx.reset(GrContext::Create(kVulkan_GrBackend, p3dctx, fGlobalOptions)); #else grCtx.reset(GrContext::Create(kOpenGL_GrBackend, p3dctx, fGlobalOptions)); #endif if (!grCtx.get()) { return nullptr; } if (kEnableNVPR_GLContextOptions & options) { if (!grCtx->caps()->shaderCaps()->pathRenderingSupport()) { return nullptr; } } ContextInfo* ctx = fContexts.emplace_back(new ContextInfo); ctx->fGLContext = SkRef(glCtx.get()); ctx->fGrContext = SkRef(grCtx.get()); ctx->fType = type; ctx->fOptions = options; return ctx; }
void onPrepareDraws(Target* target) override { SkAutoTUnref<const GrGeometryProcessor> gp; { using namespace GrDefaultGeoProcFactory; Color color(this->color()); Coverage coverage(this->coverage()); if (this->coverageIgnored()) { coverage.fType = Coverage::kNone_Type; } LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type); gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords, this->viewMatrix())); } size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(SkPoint)); target->initDraw(gp, this->pipeline()); int instanceCount = fGeoData.count(); // compute number of vertices int maxVertices = 0; // We will use index buffers if we have multiple paths or one path with multiple contours bool isIndexed = instanceCount > 1; for (int i = 0; i < instanceCount; i++) { Geometry& args = fGeoData[i]; int contourCount; maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount, args.fTolerance); isIndexed = isIndexed || contourCount > 1; } if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) { SkDebugf("Cannot render path (%d)\n", maxVertices); return; } // determine primitiveType int maxIndices = 0; GrPrimitiveType primitiveType; if (this->isHairline()) { if (isIndexed) { maxIndices = 2 * maxVertices; primitiveType = kLines_GrPrimitiveType; } else { primitiveType = kLineStrip_GrPrimitiveType; } } else { if (isIndexed) { maxIndices = 3 * maxVertices; primitiveType = kTriangles_GrPrimitiveType; } else { primitiveType = kTriangleFan_GrPrimitiveType; } } // allocate vertex / index buffers const GrVertexBuffer* vertexBuffer; int firstVertex; void* verts = target->makeVertexSpace(vertexStride, maxVertices, &vertexBuffer, &firstVertex); if (!verts) { SkDebugf("Could not allocate vertices\n"); return; } const GrIndexBuffer* indexBuffer = nullptr; int firstIndex = 0; void* indices = nullptr; if (isIndexed) { indices = target->makeIndexSpace(maxIndices, &indexBuffer, &firstIndex); if (!indices) { SkDebugf("Could not allocate indices\n"); return; } } // fill buffers int vertexOffset = 0; int indexOffset = 0; for (int i = 0; i < instanceCount; i++) { Geometry& args = fGeoData[i]; int vertexCnt = 0; int indexCnt = 0; if (!this->createGeom(verts, vertexOffset, indices, indexOffset, &vertexCnt, &indexCnt, args.fPath, args.fTolerance, isIndexed)) { return; } vertexOffset += vertexCnt; indexOffset += indexCnt; SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices); } GrVertices vertices; if (isIndexed) { vertices.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex, vertexOffset, indexOffset); } else { vertices.init(primitiveType, vertexBuffer, firstVertex, vertexOffset); } target->draw(vertices); // put back reserves target->putBackIndices((size_t)(maxIndices - indexOffset)); target->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride); }
static inline bool skpaint_to_grpaint_impl(GrContext* context, const SkPaint& skPaint, const SkMatrix& viewM, const GrFragmentProcessor** shaderProcessor, SkXfermode::Mode* primColorMode, bool primitiveIsSrc, GrPaint* grPaint) { grPaint->setAntiAlias(skPaint.isAntiAlias()); // Setup the initial color considering the shader, the SkPaint color, and the presence or not // of per-vertex colors. SkAutoTUnref<const GrFragmentProcessor> aufp; const GrFragmentProcessor* shaderFP = nullptr; if (!primColorMode || blend_requires_shader(*primColorMode, primitiveIsSrc)) { if (shaderProcessor) { shaderFP = *shaderProcessor; } else if (const SkShader* shader = skPaint.getShader()) { aufp.reset(shader->asFragmentProcessor(context, viewM, nullptr, skPaint.getFilterQuality())); shaderFP = aufp; if (!shaderFP) { return false; } } } // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is // a known constant value. In that case we can simply apply a color filter during this // conversion without converting the color filter to a GrFragmentProcessor. bool applyColorFilterToPaintColor = false; if (shaderFP) { if (primColorMode) { // There is a blend between the primitive color and the shader color. The shader sees // the opaque paint color. The shader's output is blended using the provided mode by // the primitive color. The blended color is then modulated by the paint's alpha. // The geometry processor will insert the primitive color to start the color chain, so // the GrPaint color will be ignored. GrColor shaderInput = SkColorToOpaqueGrColor(skPaint.getColor()); shaderFP = GrFragmentProcessor::OverrideInput(shaderFP, shaderInput); aufp.reset(shaderFP); if (primitiveIsSrc) { shaderFP = GrXfermodeFragmentProcessor::CreateFromDstProcessor(shaderFP, *primColorMode); } else { shaderFP = GrXfermodeFragmentProcessor::CreateFromSrcProcessor(shaderFP, *primColorMode); } aufp.reset(shaderFP); // The above may return null if compose results in a pass through of the prim color. if (shaderFP) { grPaint->addColorFragmentProcessor(shaderFP); } GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != paintAlpha) { grPaint->addColorFragmentProcessor(GrConstColorProcessor::Create( paintAlpha, GrConstColorProcessor::kModulateRGBA_InputMode))->unref(); } } else { // The shader's FP sees the paint unpremul color grPaint->setColor(SkColorToUnpremulGrColor(skPaint.getColor())); grPaint->addColorFragmentProcessor(shaderFP); } } else { if (primColorMode) { // There is a blend between the primitive color and the paint color. The blend considers // the opaque paint color. The paint's alpha is applied to the post-blended color. SkAutoTUnref<const GrFragmentProcessor> processor( GrConstColorProcessor::Create(SkColorToOpaqueGrColor(skPaint.getColor()), GrConstColorProcessor::kIgnore_InputMode)); if (primitiveIsSrc) { processor.reset(GrXfermodeFragmentProcessor::CreateFromDstProcessor(processor, *primColorMode)); } else { processor.reset(GrXfermodeFragmentProcessor::CreateFromSrcProcessor(processor, *primColorMode)); } if (processor) { grPaint->addColorFragmentProcessor(processor); } grPaint->setColor(SkColorToOpaqueGrColor(skPaint.getColor())); GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != paintAlpha) { grPaint->addColorFragmentProcessor(GrConstColorProcessor::Create( paintAlpha, GrConstColorProcessor::kModulateRGBA_InputMode))->unref(); } } else { // No shader, no primitive color. grPaint->setColor(SkColorToPremulGrColor(skPaint.getColor())); applyColorFilterToPaintColor = true; } } SkColorFilter* colorFilter = skPaint.getColorFilter(); if (colorFilter) { if (applyColorFilterToPaintColor) { grPaint->setColor(SkColorToPremulGrColor(colorFilter->filterColor(skPaint.getColor()))); } else { SkAutoTUnref<const GrFragmentProcessor> cfFP( colorFilter->asFragmentProcessor(context)); if (cfFP) { grPaint->addColorFragmentProcessor(cfFP); } else { return false; } } } // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on // the GrPaint to also be null (also kSrcOver). SkASSERT(!grPaint->getXPFactory()); SkXfermode* xfermode = skPaint.getXfermode(); if (xfermode) { // SafeUnref in case a new xfermode is added that returns null. // In such cases we will fall back to kSrcOver_Mode. SkSafeUnref(grPaint->setXPFactory(xfermode->asXPFactory())); } #ifndef SK_IGNORE_GPU_DITHER if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0) { grPaint->addColorFragmentProcessor(GrDitherEffect::Create())->unref(); } #endif return true; }
void SkPicturePlayback::handleOp(SkReader32* reader, DrawType op, uint32_t size, SkCanvas* canvas, const SkMatrix& initialMatrix) { switch (op) { case NOOP: { SkASSERT(size >= 4); reader->skip(size - 4); } break; case CLIP_PATH: { const SkPath& path = fPictureData->getPath(reader); uint32_t packed = reader->readInt(); SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed); bool doAA = ClipParams_unpackDoAA(packed); size_t offsetToRestore = reader->readInt(); SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset()); canvas->clipPath(path, regionOp, doAA); if (canvas->isClipEmpty() && offsetToRestore) { reader->setOffset(offsetToRestore); } } break; case CLIP_REGION: { SkRegion region; reader->readRegion(®ion); uint32_t packed = reader->readInt(); SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed); size_t offsetToRestore = reader->readInt(); SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset()); canvas->clipRegion(region, regionOp); if (canvas->isClipEmpty() && offsetToRestore) { reader->setOffset(offsetToRestore); } } break; case CLIP_RECT: { const SkRect& rect = reader->skipT<SkRect>(); uint32_t packed = reader->readInt(); SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed); bool doAA = ClipParams_unpackDoAA(packed); size_t offsetToRestore = reader->readInt(); SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset()); canvas->clipRect(rect, regionOp, doAA); if (canvas->isClipEmpty() && offsetToRestore) { reader->setOffset(offsetToRestore); } } break; case CLIP_RRECT: { SkRRect rrect; reader->readRRect(&rrect); uint32_t packed = reader->readInt(); SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed); bool doAA = ClipParams_unpackDoAA(packed); size_t offsetToRestore = reader->readInt(); SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset()); canvas->clipRRect(rrect, regionOp, doAA); if (canvas->isClipEmpty() && offsetToRestore) { reader->setOffset(offsetToRestore); } } break; case PUSH_CULL: break; // Deprecated, safe to ignore both push and pop. case POP_CULL: break; case CONCAT: { SkMatrix matrix; reader->readMatrix(&matrix); canvas->concat(matrix); break; } case DRAW_ATLAS: { const SkPaint* paint = fPictureData->getPaint(reader); const SkImage* atlas = fPictureData->getImage(reader); const uint32_t flags = reader->readU32(); const int count = reader->readU32(); const SkRSXform* xform = (const SkRSXform*)reader->skip(count * sizeof(SkRSXform)); const SkRect* tex = (const SkRect*)reader->skip(count * sizeof(SkRect)); const SkColor* colors = NULL; SkXfermode::Mode mode = SkXfermode::kDst_Mode; if (flags & DRAW_ATLAS_HAS_COLORS) { colors = (const SkColor*)reader->skip(count * sizeof(SkColor)); mode = (SkXfermode::Mode)reader->readU32(); } const SkRect* cull = NULL; if (flags & DRAW_ATLAS_HAS_CULL) { cull = (const SkRect*)reader->skip(sizeof(SkRect)); } canvas->drawAtlas(atlas, xform, tex, colors, count, mode, cull, paint); } break; case DRAW_BITMAP: { const SkPaint* paint = fPictureData->getPaint(reader); const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader)); const SkPoint& loc = reader->skipT<SkPoint>(); canvas->drawBitmap(bitmap, loc.fX, loc.fY, paint); } break; case DRAW_BITMAP_RECT_TO_RECT: { const SkPaint* paint = fPictureData->getPaint(reader); const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader)); const SkRect* src = get_rect_ptr(reader); // may be null const SkRect& dst = reader->skipT<SkRect>(); // required SkCanvas::DrawBitmapRectFlags flags; flags = (SkCanvas::DrawBitmapRectFlags) reader->readInt(); canvas->drawBitmapRectToRect(bitmap, src, dst, paint, flags); } break; case DRAW_BITMAP_MATRIX: { const SkPaint* paint = fPictureData->getPaint(reader); const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader)); SkMatrix matrix; reader->readMatrix(&matrix); SkAutoCanvasRestore acr(canvas, true); canvas->concat(matrix); canvas->drawBitmap(bitmap, 0, 0, paint); } break; case DRAW_BITMAP_NINE: { const SkPaint* paint = fPictureData->getPaint(reader); const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader)); const SkIRect& src = reader->skipT<SkIRect>(); const SkRect& dst = reader->skipT<SkRect>(); canvas->drawBitmapNine(bitmap, src, dst, paint); } break; case DRAW_CLEAR: canvas->clear(reader->readInt()); break; case DRAW_DATA: { // This opcode is now dead, just need to skip it for backwards compatibility size_t length = reader->readInt(); (void)reader->skip(length); // skip handles padding the read out to a multiple of 4 } break; case DRAW_DRRECT: { const SkPaint& paint = *fPictureData->getPaint(reader); SkRRect outer, inner; reader->readRRect(&outer); reader->readRRect(&inner); canvas->drawDRRect(outer, inner, paint); } break; case BEGIN_COMMENT_GROUP: reader->readString(); // deprecated (M44) break; case COMMENT: reader->readString(); reader->readString(); // deprecated (M44) break; case END_COMMENT_GROUP: // deprecated (M44) break; case DRAW_IMAGE: { const SkPaint* paint = fPictureData->getPaint(reader); const SkImage* image = fPictureData->getImage(reader); const SkPoint& loc = reader->skipT<SkPoint>(); canvas->drawImage(image, loc.fX, loc.fY, paint); } break; case DRAW_IMAGE_NINE: { const SkPaint* paint = fPictureData->getPaint(reader); const SkImage* image = fPictureData->getImage(reader); const SkIRect& center = reader->skipT<SkIRect>(); const SkRect& dst = reader->skipT<SkRect>(); canvas->drawImageNine(image, center, dst, paint); } break; case DRAW_IMAGE_RECT: { const SkPaint* paint = fPictureData->getPaint(reader); const SkImage* image = fPictureData->getImage(reader); const SkRect* src = get_rect_ptr(reader); // may be null const SkRect& dst = reader->skipT<SkRect>(); // required canvas->drawImageRect(image, src, dst, paint); } break; case DRAW_OVAL: { const SkPaint& paint = *fPictureData->getPaint(reader); canvas->drawOval(reader->skipT<SkRect>(), paint); } break; case DRAW_PAINT: canvas->drawPaint(*fPictureData->getPaint(reader)); break; case DRAW_PATCH: { const SkPaint& paint = *fPictureData->getPaint(reader); const SkPoint* cubics = (const SkPoint*)reader->skip(SkPatchUtils::kNumCtrlPts * sizeof(SkPoint)); uint32_t flag = reader->readInt(); const SkColor* colors = NULL; if (flag & DRAW_VERTICES_HAS_COLORS) { colors = (const SkColor*)reader->skip(SkPatchUtils::kNumCorners * sizeof(SkColor)); } const SkPoint* texCoords = NULL; if (flag & DRAW_VERTICES_HAS_TEXS) { texCoords = (const SkPoint*)reader->skip(SkPatchUtils::kNumCorners * sizeof(SkPoint)); } SkAutoTUnref<SkXfermode> xfer; if (flag & DRAW_VERTICES_HAS_XFER) { int mode = reader->readInt(); if (mode < 0 || mode > SkXfermode::kLastMode) { mode = SkXfermode::kModulate_Mode; } xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode)); } canvas->drawPatch(cubics, colors, texCoords, xfer, paint); } break; case DRAW_PATH: { const SkPaint& paint = *fPictureData->getPaint(reader); canvas->drawPath(fPictureData->getPath(reader), paint); } break; case DRAW_PICTURE: canvas->drawPicture(fPictureData->getPicture(reader)); break; case DRAW_PICTURE_MATRIX_PAINT: { const SkPaint* paint = fPictureData->getPaint(reader); SkMatrix matrix; reader->readMatrix(&matrix); const SkPicture* pic = fPictureData->getPicture(reader); canvas->drawPicture(pic, &matrix, paint); } break; case DRAW_POINTS: { const SkPaint& paint = *fPictureData->getPaint(reader); SkCanvas::PointMode mode = (SkCanvas::PointMode)reader->readInt(); size_t count = reader->readInt(); const SkPoint* pts = (const SkPoint*)reader->skip(sizeof(SkPoint)* count); canvas->drawPoints(mode, count, pts, paint); } break; case DRAW_POS_TEXT: { const SkPaint& paint = *fPictureData->getPaint(reader); TextContainer text; get_text(reader, &text); size_t points = reader->readInt(); const SkPoint* pos = (const SkPoint*)reader->skip(points * sizeof(SkPoint)); canvas->drawPosText(text.text(), text.length(), pos, paint); } break; case DRAW_POS_TEXT_TOP_BOTTOM: { const SkPaint& paint = *fPictureData->getPaint(reader); TextContainer text; get_text(reader, &text); size_t points = reader->readInt(); const SkPoint* pos = (const SkPoint*)reader->skip(points * sizeof(SkPoint)); const SkScalar top = reader->readScalar(); const SkScalar bottom = reader->readScalar(); if (!canvas->quickRejectY(top, bottom)) { canvas->drawPosText(text.text(), text.length(), pos, paint); } } break; case DRAW_POS_TEXT_H: { const SkPaint& paint = *fPictureData->getPaint(reader); TextContainer text; get_text(reader, &text); size_t xCount = reader->readInt(); const SkScalar constY = reader->readScalar(); const SkScalar* xpos = (const SkScalar*)reader->skip(xCount * sizeof(SkScalar)); canvas->drawPosTextH(text.text(), text.length(), xpos, constY, paint); } break; case DRAW_POS_TEXT_H_TOP_BOTTOM: { const SkPaint& paint = *fPictureData->getPaint(reader); TextContainer text; get_text(reader, &text); size_t xCount = reader->readInt(); const SkScalar* xpos = (const SkScalar*)reader->skip((3 + xCount) * sizeof(SkScalar)); const SkScalar top = *xpos++; const SkScalar bottom = *xpos++; const SkScalar constY = *xpos++; if (!canvas->quickRejectY(top, bottom)) { canvas->drawPosTextH(text.text(), text.length(), xpos, constY, paint); } } break; case DRAW_RECT: { const SkPaint& paint = *fPictureData->getPaint(reader); canvas->drawRect(reader->skipT<SkRect>(), paint); } break; case DRAW_RRECT: { const SkPaint& paint = *fPictureData->getPaint(reader); SkRRect rrect; reader->readRRect(&rrect); canvas->drawRRect(rrect, paint); } break; case DRAW_SPRITE: { const SkPaint* paint = fPictureData->getPaint(reader); const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader)); int left = reader->readInt(); int top = reader->readInt(); canvas->drawSprite(bitmap, left, top, paint); } break; case DRAW_TEXT: { const SkPaint& paint = *fPictureData->getPaint(reader); TextContainer text; get_text(reader, &text); SkScalar x = reader->readScalar(); SkScalar y = reader->readScalar(); canvas->drawText(text.text(), text.length(), x, y, paint); } break; case DRAW_TEXT_BLOB: { const SkPaint& paint = *fPictureData->getPaint(reader); const SkTextBlob* blob = fPictureData->getTextBlob(reader); SkScalar x = reader->readScalar(); SkScalar y = reader->readScalar(); canvas->drawTextBlob(blob, x, y, paint); } break; case DRAW_TEXT_TOP_BOTTOM: { const SkPaint& paint = *fPictureData->getPaint(reader); TextContainer text; get_text(reader, &text); const SkScalar* ptr = (const SkScalar*)reader->skip(4 * sizeof(SkScalar)); // ptr[0] == x // ptr[1] == y // ptr[2] == top // ptr[3] == bottom if (!canvas->quickRejectY(ptr[2], ptr[3])) { canvas->drawText(text.text(), text.length(), ptr[0], ptr[1], paint); } } break; case DRAW_TEXT_ON_PATH: { const SkPaint& paint = *fPictureData->getPaint(reader); TextContainer text; get_text(reader, &text); const SkPath& path = fPictureData->getPath(reader); SkMatrix matrix; reader->readMatrix(&matrix); canvas->drawTextOnPath(text.text(), text.length(), path, &matrix, paint); } break; case DRAW_VERTICES: { SkAutoTUnref<SkXfermode> xfer; const SkPaint& paint = *fPictureData->getPaint(reader); DrawVertexFlags flags = (DrawVertexFlags)reader->readInt(); SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader->readInt(); int vCount = reader->readInt(); const SkPoint* verts = (const SkPoint*)reader->skip(vCount * sizeof(SkPoint)); const SkPoint* texs = NULL; const SkColor* colors = NULL; const uint16_t* indices = NULL; int iCount = 0; if (flags & DRAW_VERTICES_HAS_TEXS) { texs = (const SkPoint*)reader->skip(vCount * sizeof(SkPoint)); } if (flags & DRAW_VERTICES_HAS_COLORS) { colors = (const SkColor*)reader->skip(vCount * sizeof(SkColor)); } if (flags & DRAW_VERTICES_HAS_INDICES) { iCount = reader->readInt(); indices = (const uint16_t*)reader->skip(iCount * sizeof(uint16_t)); } if (flags & DRAW_VERTICES_HAS_XFER) { int mode = reader->readInt(); if (mode < 0 || mode > SkXfermode::kLastMode) { mode = SkXfermode::kModulate_Mode; } xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode)); } canvas->drawVertices(vmode, vCount, verts, texs, colors, xfer, indices, iCount, paint); } break; case RESTORE: canvas->restore(); break; case ROTATE: canvas->rotate(reader->readScalar()); break; case SAVE: // SKPs with version < 29 also store a SaveFlags param. if (size > 4) { SkASSERT(8 == size); reader->readInt(); } canvas->save(); break; case SAVE_LAYER: { const SkRect* boundsPtr = get_rect_ptr(reader); const SkPaint* paint = fPictureData->getPaint(reader); canvas->saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader->readInt()); } break; case SCALE: { SkScalar sx = reader->readScalar(); SkScalar sy = reader->readScalar(); canvas->scale(sx, sy); } break; case SET_MATRIX: { SkMatrix matrix; reader->readMatrix(&matrix); matrix.postConcat(initialMatrix); canvas->setMatrix(matrix); } break; case SKEW: { SkScalar sx = reader->readScalar(); SkScalar sy = reader->readScalar(); canvas->skew(sx, sy); } break; case TRANSLATE: { SkScalar dx = reader->readScalar(); SkScalar dy = reader->readScalar(); canvas->translate(dx, dy); } break; default: SkASSERTF(false, "Unknown draw type: %d", op); } }
int main(void) { GLFWwindow* window; glfwSetErrorCallback(error_callback); if (!glfwInit()) { exit(EXIT_FAILURE); } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_SRGB_CAPABLE, GL_TRUE); window = glfwCreateWindow(kWidth, kHeight, "Simple example", NULL, NULL); if (!window) { glfwTerminate(); exit(EXIT_FAILURE); } glfwMakeContextCurrent(window); init_skia(kWidth, kHeight); SkAutoTUnref<SkImage> atlas; SkRSXform xform[kGrid*kGrid+1]; SkRect tex[kGrid*kGrid+1]; WallTimer timer; float times[32]; int currentTime; SkAutoTUnref<SkData> imageData(SkData::NewFromFileName("ship.png")); atlas.reset(SkImage::NewFromEncoded(imageData)); if (!atlas) { SkDebugf("\nCould not decode file ship.png\n"); cleanup_skia(); glfwDestroyWindow(window); glfwTerminate(); exit(EXIT_FAILURE); } SkScalar anchorX = atlas->width()*0.5f; SkScalar anchorY = atlas->height()*0.5f; int currIndex = 0; for (int x = 0; x < kGrid; x++) { for (int y = 0; y < kGrid; y++) { float xPos = (x / (kGrid - 1.0)) * kWidth; float yPos = (y / (kGrid - 1.0)) * kWidth; tex[currIndex] = SkRect::MakeLTRB(0.0f, 0.0f, atlas->width(), atlas->height()); xform[currIndex] = SkRSXform::MakeFromRadians(2.0f, SK_ScalarPI*0.5f, xPos, yPos, anchorX, anchorY); currIndex++; } } tex[currIndex] = SkRect::MakeLTRB(0.0f, 0.0f, atlas->width(), atlas->height()); xform[currIndex] = SkRSXform::MakeFromRadians(2.0f, SK_ScalarPI*0.5f, kWidth*0.5f, kHeight*0.5f, anchorX, anchorY); currentTime = 0; glfwSwapInterval(1); glfwSetKeyCallback(window, key_callback); // Draw to the surface via its SkCanvas. SkCanvas* canvas = sSurface->getCanvas(); // We don't manage this pointer's lifetime. SkPaint paint; paint.setFilterQuality(kLow_SkFilterQuality); paint.setColor(SK_ColorWHITE); paint.setTextSize(15.0f); while (!glfwWindowShouldClose(window)) { const float kCosDiff = 0.99984769515f; const float kSinDiff = 0.01745240643f; timer.start(); glfwPollEvents(); float meanTime = 0.0f; for (int i = 0; i < 32; ++i) { meanTime += times[i]; } meanTime /= 32.f; char outString[64]; float fps = 1000.f/meanTime; sprintf(outString, "fps: %f ms: %f", fps, meanTime); for (int i = 0; i < kGrid*kGrid+1; ++i) { SkScalar c = xform[i].fSCos; SkScalar s = xform[i].fSSin; SkScalar dx = c*anchorX - s*anchorY; SkScalar dy = s*anchorX + c*anchorY; xform[i].fSCos = kCosDiff*c - kSinDiff*s; xform[i].fSSin = kSinDiff*c + kCosDiff*s; dx -= xform[i].fSCos*anchorX - xform[i].fSSin*anchorY; dy -= xform[i].fSSin*anchorX + xform[i].fSCos*anchorY; xform[i].fTx += dx; xform[i].fTy += dy; } canvas->clear(SK_ColorBLACK); canvas->drawAtlas(atlas, xform, tex, nullptr, kGrid*kGrid+1, SkXfermode::kSrcOver_Mode, nullptr, &paint); canvas->drawText(outString, strlen(outString), 100.f, 100.f, paint); canvas->flush(); timer.end(); times[currentTime] = (float)(timer.fWall); currentTime = (currentTime + 1) & 0x1f; glfwSwapBuffers(window); } cleanup_skia(); glfwDestroyWindow(window); glfwTerminate(); exit(EXIT_SUCCESS); }
void AAHairlineBatch::onPrepareDraws(Target* target) const { // Setup the viewmatrix and localmatrix for the GrGeometryProcessor. SkMatrix invert; if (!this->viewMatrix().invert(&invert)) { return; } // we will transform to identity space if the viewmatrix does not have perspective bool hasPerspective = this->viewMatrix().hasPerspective(); const SkMatrix* geometryProcessorViewM = &SkMatrix::I(); const SkMatrix* geometryProcessorLocalM = &invert; const SkMatrix* toDevice = nullptr; const SkMatrix* toSrc = nullptr; if (hasPerspective) { geometryProcessorViewM = &this->viewMatrix(); geometryProcessorLocalM = &SkMatrix::I(); toDevice = &this->viewMatrix(); toSrc = &invert; } // This is hand inlined for maximum performance. PREALLOC_PTARRAY(128) lines; PREALLOC_PTARRAY(128) quads; PREALLOC_PTARRAY(128) conics; IntArray qSubdivs; FloatArray cWeights; int quadCount = 0; int instanceCount = fGeoData.count(); for (int i = 0; i < instanceCount; i++) { const Geometry& args = fGeoData[i]; quadCount += gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds, &lines, &quads, &conics, &qSubdivs, &cWeights); } int lineCount = lines.count() / 2; int conicCount = conics.count() / 3; // do lines first if (lineCount) { SkAutoTUnref<const GrGeometryProcessor> lineGP; { using namespace GrDefaultGeoProcFactory; Color color(this->color()); Coverage coverage(Coverage::kAttribute_Type); LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type); localCoords.fMatrix = geometryProcessorLocalM; lineGP.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords, *geometryProcessorViewM)); } SkAutoTUnref<const GrBuffer> linesIndexBuffer( ref_lines_index_buffer(target->resourceProvider())); const GrBuffer* vertexBuffer; int firstVertex; size_t vertexStride = lineGP->getVertexStride(); int vertexCount = kLineSegNumVertices * lineCount; LineVertex* verts = reinterpret_cast<LineVertex*>( target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex)); if (!verts|| !linesIndexBuffer) { SkDebugf("Could not allocate vertices\n"); return; } SkASSERT(lineGP->getVertexStride() == sizeof(LineVertex)); for (int i = 0; i < lineCount; ++i) { add_line(&lines[2*i], toSrc, this->coverage(), &verts); } GrMesh mesh; mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, linesIndexBuffer, firstVertex, kLineSegNumVertices, kIdxsPerLineSeg, lineCount, kLineSegsNumInIdxBuffer); target->draw(lineGP, mesh); } if (quadCount || conicCount) { SkAutoTUnref<const GrGeometryProcessor> quadGP( GrQuadEffect::Create(this->color(), *geometryProcessorViewM, kHairlineAA_GrProcessorEdgeType, target->caps(), *geometryProcessorLocalM, this->usesLocalCoords(), this->coverage())); SkAutoTUnref<const GrGeometryProcessor> conicGP( GrConicEffect::Create(this->color(), *geometryProcessorViewM, kHairlineAA_GrProcessorEdgeType, target->caps(), *geometryProcessorLocalM, this->usesLocalCoords(), this->coverage())); const GrBuffer* vertexBuffer; int firstVertex; SkAutoTUnref<const GrBuffer> quadsIndexBuffer( ref_quads_index_buffer(target->resourceProvider())); size_t vertexStride = sizeof(BezierVertex); int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * conicCount; void *vertices = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); if (!vertices || !quadsIndexBuffer) { SkDebugf("Could not allocate vertices\n"); return; } // Setup vertices BezierVertex* bezVerts = reinterpret_cast<BezierVertex*>(vertices); int unsubdivQuadCnt = quads.count() / 3; for (int i = 0; i < unsubdivQuadCnt; ++i) { SkASSERT(qSubdivs[i] >= 0); add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &bezVerts); } // Start Conics for (int i = 0; i < conicCount; ++i) { add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &bezVerts); } if (quadCount > 0) { GrMesh mesh; mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer, firstVertex, kQuadNumVertices, kIdxsPerQuad, quadCount, kQuadsNumInIdxBuffer); target->draw(quadGP, mesh); firstVertex += quadCount * kQuadNumVertices; } if (conicCount > 0) { GrMesh mesh; mesh.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer, firstVertex, kQuadNumVertices, kIdxsPerQuad, conicCount, kQuadsNumInIdxBuffer); target->draw(conicGP, mesh); } } }
void GrAtlasTextBatch::onPrepareDraws(Target* target) const { // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix. // TODO actually only invert if we don't have RGBA SkMatrix localMatrix; if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) { SkDebugf("Cannot invert viewmatrix\n"); return; } GrTexture* texture = fFontCache->getTexture(this->maskFormat()); if (!texture) { SkDebugf("Could not allocate backing texture for atlas\n"); return; } GrMaskFormat maskFormat = this->maskFormat(); SkAutoTUnref<const GrGeometryProcessor> gp; if (this->usesDistanceFields()) { gp.reset(this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(), texture)); } else { GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode); gp.reset(GrBitmapTextGeoProc::Create(this->color(), texture, params, maskFormat, localMatrix, this->usesLocalCoords())); } FlushInfo flushInfo; flushInfo.fGlyphsToFlush = 0; size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat)); target->initDraw(gp); int glyphCount = this->numGlyphs(); const GrBuffer* vertexBuffer; void* vertices = target->makeVertexSpace(vertexStride, glyphCount * kVerticesPerGlyph, &vertexBuffer, &flushInfo.fVertexOffset); flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer)); flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer()); if (!vertices || !flushInfo.fVertexBuffer) { SkDebugf("Could not allocate vertices\n"); return; } unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices); // We cache some values to avoid going to the glyphcache for the same fontScaler twice // in a row const SkDescriptor* desc = nullptr; SkGlyphCache* cache = nullptr; GrFontScaler* scaler = nullptr; SkTypeface* typeface = nullptr; GrBlobRegenHelper helper(this, target, &flushInfo, gp); for (int i = 0; i < fGeoCount; i++) { const Geometry& args = fGeoData[i]; Blob* blob = args.fBlob; size_t byteCount; void* blobVertices; int subRunGlyphCount; blob->regenInBatch(target, fFontCache, &helper, args.fRun, args.fSubRun, &cache, &typeface, &scaler, &desc, vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor, &blobVertices, &byteCount, &subRunGlyphCount); // now copy all vertices memcpy(currVertex, blobVertices, byteCount); #ifdef SK_DEBUG // bounds sanity check SkRect rect; rect.setLargestInverted(); SkPoint* vertex = (SkPoint*) ((char*)blobVertices); rect.growToInclude(vertex, vertexStride, kVerticesPerGlyph * subRunGlyphCount); if (this->usesDistanceFields()) { args.fViewMatrix.mapRect(&rect); } SkASSERT(fBounds.contains(rect)); #endif currVertex += byteCount; } // Make sure to attach the last cache if applicable if (cache) { SkGlyphCache::AttachCache(cache); } this->flush(target, &flushInfo); }