From 8f0be4e12173e1dcccad58883a98ecd5b0c93bf2 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Tue, 9 Feb 2016 13:38:06 -0500 Subject: [PATCH] Bug 1246756 - part 3 - update Skia to m49 branch. r=jrmuizel --- CLOBBER | 2 +- gfx/skia/skia/include/codec/SkAndroidCodec.h | 26 +- gfx/skia/skia/include/codec/SkCodec.h | 60 +- gfx/skia/skia/include/core/SkBitmap.h | 24 +- gfx/skia/skia/include/core/SkCanvas.h | 156 +- gfx/skia/skia/include/core/SkColorFilter.h | 7 - gfx/skia/skia/include/core/SkDevice.h | 24 +- gfx/skia/skia/include/core/SkDocument.h | 19 + gfx/skia/skia/include/core/SkDrawFilter.h | 2 + gfx/skia/skia/include/core/SkFixed.h | 8 +- gfx/skia/skia/include/core/SkFlattenable.h | 9 +- gfx/skia/skia/include/core/SkImage.h | 24 +- gfx/skia/skia/include/core/SkImageDecoder.h | 14 - gfx/skia/skia/include/core/SkImageEncoder.h | 8 + gfx/skia/skia/include/core/SkImageFilter.h | 70 +- gfx/skia/skia/include/core/SkImageGenerator.h | 20 +- gfx/skia/skia/include/core/SkMask.h | 2 + gfx/skia/skia/include/core/SkMaskFilter.h | 4 +- gfx/skia/skia/include/core/SkMatrix.h | 14 +- gfx/skia/skia/include/core/SkOSFile.h | 1 + gfx/skia/skia/include/core/SkPaint.h | 12 +- gfx/skia/skia/include/core/SkPath.h | 8 + gfx/skia/skia/include/core/SkPathMeasure.h | 6 +- gfx/skia/skia/include/core/SkPathRef.h | 1 + gfx/skia/skia/include/core/SkPixelRef.h | 5 +- .../skia/include/core/SkPixelSerializer.h | 10 +- gfx/skia/skia/include/core/SkPostConfig.h | 8 - gfx/skia/skia/include/core/SkPreConfig.h | 3 +- gfx/skia/skia/include/core/SkRRect.h | 6 + gfx/skia/skia/include/core/SkRect.h | 18 - gfx/skia/skia/include/core/SkRefCnt.h | 2 +- gfx/skia/skia/include/core/SkShader.h | 78 +- gfx/skia/skia/include/core/SkStream.h | 18 +- gfx/skia/skia/include/core/SkString.h | 17 +- gfx/skia/skia/include/core/SkTArray.h | 7 +- gfx/skia/skia/include/core/SkTDArray.h | 2 +- gfx/skia/skia/include/core/SkTLazy.h | 5 +- gfx/skia/skia/include/core/SkTime.h | 4 - gfx/skia/skia/include/core/SkTypes.h | 54 +- gfx/skia/skia/include/core/SkWriter32.h | 4 +- .../skia/include/effects/Sk1DPathEffect.h | 3 +- .../skia/include/effects/Sk2DPathEffect.h | 4 +- .../include/effects/SkAlphaThresholdFilter.h | 1 + .../skia/include/effects/SkBlurDrawLooper.h | 4 +- .../skia/include/effects/SkBlurImageFilter.h | 6 +- .../skia/include/effects/SkColorCubeFilter.h | 3 +- .../effects/SkColorFilterImageFilter.h | 2 +- .../include/effects/SkColorMatrixFilter.h | 25 +- .../skia/include/effects/SkCornerPathEffect.h | 5 +- .../skia/include/effects/SkDashPathEffect.h | 3 +- .../include/effects/SkDiscretePathEffect.h | 4 +- .../include/effects/SkDisplacementMapEffect.h | 11 +- .../include/effects/SkDropShadowImageFilter.h | 3 +- .../skia/include/effects/SkEmbossMaskFilter.h | 6 +- .../include/effects/SkLightingImageFilter.h | 2 +- .../effects/SkMatrixConvolutionImageFilter.h | 22 +- .../include/effects/SkMorphologyImageFilter.h | 3 +- .../include/effects/SkOffsetImageFilter.h | 2 +- .../skia/include/effects/SkPaintImageFilter.h | 45 + .../include/effects/SkPerlinNoiseShader.h | 1 - .../include/effects/SkRectShaderImageFilter.h | 52 - .../skia/include/effects/SkTileImageFilter.h | 1 + .../include/effects/SkXfermodeImageFilter.h | 6 +- gfx/skia/skia/include/gpu/GrCaps.h | 21 +- gfx/skia/skia/include/gpu/GrClip.h | 2 +- gfx/skia/skia/include/gpu/GrConfig.h | 10 +- gfx/skia/skia/include/gpu/GrContext.h | 21 +- gfx/skia/skia/include/gpu/GrContextOptions.h | 10 + gfx/skia/skia/include/gpu/GrDrawContext.h | 39 +- gfx/skia/skia/include/gpu/GrResourceKey.h | 10 +- gfx/skia/skia/include/gpu/GrTestUtils.h | 1 + gfx/skia/skia/include/gpu/GrTextureAccess.h | 55 +- gfx/skia/skia/include/gpu/GrTextureProvider.h | 42 +- gfx/skia/skia/include/gpu/GrTypes.h | 20 - gfx/skia/skia/include/gpu/GrTypesPriv.h | 69 +- gfx/skia/skia/include/gpu/SkGrPixelRef.h | 2 +- .../gpu/effects/GrPorterDuffXferProcessor.h | 6 + gfx/skia/skia/include/gpu/gl/SkGLContext.h | 11 +- .../skia/include/gpu/gl/SkNullGLContext.h | 7 +- .../include/gpu/gl/angle/SkANGLEGLContext.h | 19 +- .../command_buffer/SkCommandBufferGLContext.h | 5 +- gfx/skia/skia/include/pipe/SkGPipe.h | 174 -- gfx/skia/skia/include/ports/SkFontMgr.h | 8 + gfx/skia/skia/include/private/GrAuditTrail.h | 116 ++ gfx/skia/skia/include/private/GrSingleOwner.h | 55 + .../skia/include/private/SkFloatingPoint.h | 8 +- gfx/skia/skia/include/private/SkRecords.h | 10 +- .../skia/include/{core => private}/SkTDict.h | 0 gfx/skia/skia/include/private/SkTLogic.h | 210 +-- .../include/{core => private}/SkTSearch.h | 0 gfx/skia/skia/include/private/SkTemplates.h | 13 +- gfx/skia/skia/include/private/SkUniquePtr.h | 116 +- gfx/skia/skia/include/private/SkUtility.h | 32 - .../skia/include/svg/parser/SkSVGParser.h | 2 +- gfx/skia/skia/include/utils/SkCubicInterval.h | 22 - gfx/skia/skia/include/utils/SkCullPoints.h | 71 - gfx/skia/skia/include/utils/SkDumpCanvas.h | 3 +- gfx/skia/skia/include/utils/SkInterpolator.h | 13 +- gfx/skia/skia/include/utils/SkLuaCanvas.h | 3 +- gfx/skia/skia/include/utils/SkNWayCanvas.h | 3 +- .../skia/include/utils/SkNoSaveLayerCanvas.h | 5 +- .../skia/include/utils/SkPaintFilterCanvas.h | 19 +- gfx/skia/skia/include/utils/SkRTConf.h | 5 +- gfx/skia/skia/include/utils/win/SkHRESULT.h | 2 +- gfx/skia/skia/include/views/SkOSWindow_SDL.h | 31 +- .../include/{utils => views}/SkParsePaint.h | 0 gfx/skia/skia/include/views/SkView.h | 2 +- gfx/skia/skia/include/views/SkViewInflate.h | 2 +- .../skia/src/android/SkBitmapRegionCanvas.cpp | 3 +- .../skia/src/android/SkBitmapRegionCanvas.h | 12 +- .../skia/src/android/SkBitmapRegionCodec.cpp | 15 +- gfx/skia/skia/src/animator/SkDisplayType.h | 4 +- gfx/skia/skia/src/animator/SkDisplayTypes.h | 2 - gfx/skia/skia/src/animator/SkMemberInfo.h | 5 +- .../src/animator/SkOperandIterpolator.cpp | 4 +- gfx/skia/skia/src/animator/SkScript.h | 2 - gfx/skia/skia/src/animator/SkScript2.h | 3 +- gfx/skia/skia/src/animator/SkTime.cpp | 46 - gfx/skia/skia/src/codec/SkAndroidCodec.cpp | 62 +- gfx/skia/skia/src/codec/SkBmpCodec.cpp | 21 +- gfx/skia/skia/src/codec/SkBmpCodec.h | 11 +- gfx/skia/skia/src/codec/SkBmpRLECodec.cpp | 9 +- gfx/skia/skia/src/codec/SkBmpRLECodec.h | 1 + .../skia/src/codec/SkBmpStandardCodec.cpp | 96 +- gfx/skia/skia/src/codec/SkBmpStandardCodec.h | 9 +- gfx/skia/skia/src/codec/SkCodec.cpp | 74 +- .../skia/src/codec/SkCodecImageGenerator.cpp | 46 + .../skia/src/codec/SkCodecImageGenerator.h | 43 + gfx/skia/skia/src/codec/SkCodecPriv.h | 17 - gfx/skia/skia/src/codec/SkCodec_libico.h | 63 - gfx/skia/skia/src/codec/SkCodec_libpng.cpp | 124 +- gfx/skia/skia/src/codec/SkCodec_libpng.h | 17 +- .../{SkCodec_libgif.cpp => SkGifCodec.cpp} | 9 +- .../codec/{SkCodec_libgif.h => SkGifCodec.h} | 6 +- .../{SkCodec_libico.cpp => SkIcoCodec.cpp} | 184 +- gfx/skia/skia/src/codec/SkIcoCodec.h | 87 + gfx/skia/skia/src/codec/SkJpegCodec.cpp | 14 +- gfx/skia/skia/src/codec/SkJpegCodec.h | 10 +- gfx/skia/skia/src/codec/SkMaskSwizzler.cpp | 52 +- gfx/skia/skia/src/codec/SkMaskSwizzler.h | 4 +- gfx/skia/skia/src/codec/SkSampledCodec.cpp | 86 +- gfx/skia/skia/src/codec/SkSampledCodec.h | 4 - gfx/skia/skia/src/codec/SkSampler.h | 1 + gfx/skia/skia/src/codec/SkSwizzler.cpp | 245 +-- gfx/skia/skia/src/codec/SkSwizzler.h | 73 +- .../{SkCodec_wbmp.cpp => SkWbmpCodec.cpp} | 9 +- .../codec/{SkCodec_wbmp.h => SkWbmpCodec.h} | 2 +- .../skia/src/codec/SkWebpAdapterCodec.cpp | 9 +- gfx/skia/skia/src/codec/SkWebpAdapterCodec.h | 4 - gfx/skia/skia/src/codec/SkWebpCodec.cpp | 24 +- gfx/skia/skia/src/codec/SkWebpCodec.h | 8 +- gfx/skia/skia/src/core/Sk4px.h | 24 +- gfx/skia/skia/src/core/SkAAClip.cpp | 20 +- gfx/skia/skia/src/core/SkAntiRun.h | 1 - gfx/skia/skia/src/core/SkBitmap.cpp | 33 +- gfx/skia/skia/src/core/SkBitmapController.cpp | 6 + gfx/skia/skia/src/core/SkBitmapDevice.cpp | 4 +- gfx/skia/skia/src/core/SkBitmapFilter.cpp | 40 - gfx/skia/skia/src/core/SkBitmapFilter.h | 343 ++-- gfx/skia/skia/src/core/SkBitmapProcShader.cpp | 86 +- gfx/skia/skia/src/core/SkBitmapProcShader.h | 1 - gfx/skia/skia/src/core/SkBitmapProcState.cpp | 69 +- gfx/skia/skia/src/core/SkBitmapProcState.h | 45 +- .../core/SkBitmapProcState_matrixProcs.cpp | 16 +- .../core/SkBitmapProcState_matrix_template.h | 18 +- .../skia/src/core/SkBitmapProcState_procs.h | 111 -- .../skia/src/core/SkBitmapProcState_sample.h | 40 +- .../src/core/SkBitmapProcState_shaderproc.h | 9 +- gfx/skia/skia/src/core/SkBitmapScaler.cpp | 166 +- gfx/skia/skia/src/core/SkBitmapScaler.h | 10 + gfx/skia/skia/src/core/SkBlitMask.h | 2 +- gfx/skia/skia/src/core/SkBlitMask_D32.cpp | 36 +- gfx/skia/skia/src/core/SkBlitter.cpp | 3 +- gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp | 4 +- gfx/skia/skia/src/core/SkBlitter_RGB16.cpp | 144 +- gfx/skia/skia/src/core/SkBuffer.cpp | 2 +- gfx/skia/skia/src/core/SkCanvas.cpp | 376 +++-- gfx/skia/skia/src/core/SkColorFilter.cpp | 3 + .../skia/src/core/SkColorFilterShader.cpp | 136 ++ ...SkFilterShader.h => SkColorFilterShader.h} | 51 +- gfx/skia/skia/src/core/SkColorShader.h | 3 - gfx/skia/skia/src/core/SkComposeShader.cpp | 4 - gfx/skia/skia/src/core/SkConvolver.cpp | 25 +- gfx/skia/skia/src/core/SkConvolver.h | 21 +- gfx/skia/skia/src/core/SkCubicClipper.cpp | 6 +- gfx/skia/skia/src/core/SkCubicClipper.h | 1 + gfx/skia/skia/src/core/SkDevice.cpp | 31 +- gfx/skia/skia/src/core/SkDistanceFieldGen.cpp | 13 +- .../skia/{include => src}/core/SkDither.h | 0 gfx/skia/skia/src/core/SkDraw.cpp | 347 ++-- gfx/skia/skia/src/core/SkEdge.cpp | 12 +- gfx/skia/skia/src/core/SkEdge.h | 2 +- gfx/skia/skia/src/core/SkEdgeClipper.cpp | 13 +- gfx/skia/skia/src/core/SkFDot6.h | 6 +- gfx/skia/skia/src/core/SkFilterShader.cpp | 102 -- gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h | 34 +- gfx/skia/skia/src/core/SkFloatBits.cpp | 8 +- gfx/skia/skia/src/core/SkGeometry.cpp | 49 +- .../src/core/SkGlobalInitialization_core.cpp | 59 + gfx/skia/skia/src/core/SkImageCacherator.cpp | 56 +- gfx/skia/skia/src/core/SkImageCacherator.h | 7 +- gfx/skia/skia/src/core/SkImageFilter.cpp | 157 +- gfx/skia/skia/src/core/SkImageGenerator.cpp | 2 +- gfx/skia/skia/src/core/SkLightingShader.cpp | 28 +- .../src/core/SkLocalMatrixImageFilter.cpp | 5 +- .../skia/src/core/SkLocalMatrixShader.cpp | 23 +- gfx/skia/skia/src/core/SkMaskFilter.cpp | 2 - gfx/skia/skia/src/core/SkMatrix.cpp | 41 +- .../skia/src/core/SkMatrixImageFilter.cpp | 29 +- gfx/skia/skia/src/core/SkMatrixImageFilter.h | 4 +- gfx/skia/skia/src/core/SkMatrixUtils.h | 31 +- .../SkModeColorFilter.cpp} | 41 +- .../effects => src/core}/SkModeColorFilter.h | 19 +- gfx/skia/skia/src/core/SkMultiPictureDraw.cpp | 2 +- gfx/skia/skia/src/core/SkNx.h | 231 +-- gfx/skia/skia/src/core/SkOpts.cpp | 7 +- gfx/skia/skia/src/core/SkOpts.h | 5 + gfx/skia/skia/src/core/SkPaint.cpp | 31 +- gfx/skia/skia/src/core/SkPath.cpp | 446 +++-- gfx/skia/skia/src/core/SkPathEffect.cpp | 12 +- gfx/skia/skia/src/core/SkPathMeasure.cpp | 45 +- gfx/skia/skia/src/core/SkPathPriv.h | 26 +- gfx/skia/skia/src/core/SkPathRef.cpp | 23 +- gfx/skia/skia/src/core/SkPictureFlat.h | 14 +- .../skia/src/core/SkPictureImageGenerator.cpp | 3 +- gfx/skia/skia/src/core/SkPicturePlayback.cpp | 60 +- gfx/skia/skia/src/core/SkPictureRecord.cpp | 193 +-- gfx/skia/skia/src/core/SkPictureRecord.h | 5 +- gfx/skia/skia/src/core/SkPictureShader.cpp | 5 - gfx/skia/skia/src/core/SkPictureShader.h | 1 - gfx/skia/skia/src/core/SkPixelRef.cpp | 6 +- gfx/skia/skia/src/core/SkPixmap.cpp | 23 +- gfx/skia/skia/src/core/SkPx.h | 89 - gfx/skia/skia/src/core/SkRRect.cpp | 54 +- gfx/skia/skia/src/core/SkRWBuffer.cpp | 3 + gfx/skia/skia/src/core/SkRasterizer.cpp | 1 - gfx/skia/skia/src/core/SkRecord.cpp | 1 - gfx/skia/skia/src/core/SkRecord.h | 4 +- gfx/skia/skia/src/core/SkRecordDraw.cpp | 22 +- gfx/skia/skia/src/core/SkRecordOpts.cpp | 10 + gfx/skia/skia/src/core/SkRecorder.cpp | 11 +- gfx/skia/skia/src/core/SkRecorder.h | 3 +- gfx/skia/skia/src/core/SkRemote.cpp | 19 +- gfx/skia/skia/src/core/SkRemote.h | 2 +- gfx/skia/skia/src/core/SkScaleToSides.h | 61 + gfx/skia/skia/src/core/SkScan.h | 4 + gfx/skia/skia/src/core/SkScan_AntiPath.cpp | 8 +- gfx/skia/skia/src/core/SkScan_Antihair.cpp | 4 +- gfx/skia/skia/src/core/SkScan_Hairline.cpp | 215 ++- gfx/skia/skia/src/core/SkScan_Path.cpp | 50 +- gfx/skia/skia/src/core/SkShader.cpp | 23 - gfx/skia/skia/src/core/SkStream.cpp | 41 +- gfx/skia/skia/src/core/SkString.cpp | 33 +- gfx/skia/skia/src/core/SkStroke.cpp | 44 +- gfx/skia/skia/src/core/SkTLList.h | 10 +- gfx/skia/skia/src/core/SkTaskGroup.cpp | 69 +- gfx/skia/skia/src/core/SkTaskGroup.h | 54 +- gfx/skia/skia/src/core/SkTime.cpp | 41 + gfx/skia/skia/src/core/SkUtils.cpp | 8 +- gfx/skia/skia/src/core/SkValue.h | 81 + gfx/skia/skia/src/core/SkVarAlloc.cpp | 14 - gfx/skia/skia/src/core/SkWriteBuffer.cpp | 5 +- gfx/skia/skia/src/device/xps/SkXPSDevice.cpp | 13 +- gfx/skia/skia/src/doc/SkDocument_PDF.cpp | 19 +- .../effects/GrCircleBlurFragmentProcessor.cpp | 30 +- .../src/effects/SkAlphaThresholdFilter.cpp | 25 +- .../skia/src/effects/SkArithmeticMode_gpu.cpp | 22 +- .../skia/src/effects/SkBlurImageFilter.cpp | 86 +- gfx/skia/skia/src/effects/SkBlurMask.h | 28 +- .../skia/src/effects/SkBlurMaskFilter.cpp | 64 +- .../skia/src/effects/SkColorCubeFilter.cpp | 27 +- .../src/effects/SkColorFilterImageFilter.cpp | 7 +- .../skia/src/effects/SkColorMatrixFilter.cpp | 330 +--- .../skia/src/effects/SkComposeImageFilter.cpp | 6 +- .../src/effects/SkDisplacementMapEffect.cpp | 45 +- .../src/effects/SkDropShadowImageFilter.cpp | 24 +- .../skia/src/effects/SkEmbossMaskFilter.cpp | 2 +- gfx/skia/skia/src/effects/SkGpuBlurUtils.cpp | 27 +- gfx/skia/skia/src/effects/SkGpuBlurUtils.h | 3 +- .../src/effects/SkLightingImageFilter.cpp | 145 +- .../skia/src/effects/SkLumaColorFilter.cpp | 1 - .../src/effects/SkMagnifierImageFilter.cpp | 35 +- .../SkMatrixConvolutionImageFilter.cpp | 30 +- .../src/effects/SkMorphologyImageFilter.cpp | 56 +- .../skia/src/effects/SkOffsetImageFilter.cpp | 28 +- ...ImageFilter.cpp => SkPaintImageFilter.cpp} | 62 +- .../skia/src/effects/SkPerlinNoiseShader.cpp | 33 +- .../skia/src/effects/SkTableColorFilter.cpp | 18 +- .../skia/src/effects/SkTileImageFilter.cpp | 68 +- .../src/effects/SkXfermodeImageFilter.cpp | 50 +- .../skia/src/effects/gradients/SkClampRange.h | 4 +- .../effects/gradients/SkGradientShader.cpp | 64 +- .../effects/gradients/SkGradientShaderPriv.h | 8 +- .../effects/gradients/SkLinearGradient.cpp | 222 +-- .../src/effects/gradients/SkLinearGradient.h | 1 - .../effects/gradients/SkRadialGradient.cpp | 186 +- .../src/effects/gradients/SkRadialGradient.h | 1 - .../gradients/SkRadialGradient_Table.h | 139 -- .../src/effects/gradients/SkSweepGradient.cpp | 58 +- .../src/effects/gradients/SkSweepGradient.h | 1 - .../gradients/SkTwoPointConicalGradient.cpp | 3 - .../SkTwoPointConicalGradient_gpu.cpp | 106 +- gfx/skia/skia/src/gpu/GrAtlasTextBlob.cpp | 109 -- gfx/skia/skia/src/gpu/GrAtlasTextContext.cpp | 1398 --------------- gfx/skia/skia/src/gpu/GrAtlasTextContext.h | 193 --- gfx/skia/skia/src/gpu/GrAuditTrail.cpp | 121 ++ gfx/skia/skia/src/gpu/GrAutoLocaleSetter.h | 35 +- gfx/skia/skia/src/gpu/GrCaps.cpp | 17 +- gfx/skia/skia/src/gpu/GrClipMaskManager.cpp | 49 +- gfx/skia/skia/src/gpu/GrContext.cpp | 45 +- gfx/skia/skia/src/gpu/GrContextFactory.cpp | 126 +- gfx/skia/skia/src/gpu/GrContextFactory.h | 113 +- .../skia/src/gpu/GrDefaultGeoProcFactory.cpp | 33 +- gfx/skia/skia/src/gpu/GrDrawContext.cpp | 191 ++- gfx/skia/skia/src/gpu/GrDrawTarget.cpp | 119 +- gfx/skia/skia/src/gpu/GrDrawTarget.h | 90 +- gfx/skia/skia/src/gpu/GrDrawingManager.cpp | 17 +- gfx/skia/skia/src/gpu/GrDrawingManager.h | 12 +- gfx/skia/skia/src/gpu/GrFragmentProcessor.cpp | 11 +- gfx/skia/skia/src/gpu/GrGpu.cpp | 34 +- gfx/skia/skia/src/gpu/GrGpu.h | 45 + .../skia/src/gpu/GrImageIDTextureAdjuster.cpp | 51 +- .../skia/src/gpu/GrImageIDTextureAdjuster.h | 27 + gfx/skia/skia/src/gpu/GrLayerHoister.cpp | 16 +- gfx/skia/skia/src/gpu/GrMemoryPool.cpp | 27 +- gfx/skia/skia/src/gpu/GrMemoryPool.h | 17 +- gfx/skia/skia/src/gpu/GrOvalRenderer.cpp | 42 +- gfx/skia/skia/src/gpu/GrPath.h | 9 +- gfx/skia/skia/src/gpu/GrPathProcessor.cpp | 14 +- gfx/skia/skia/src/gpu/GrPathUtils.cpp | 14 +- gfx/skia/skia/src/gpu/GrPipeline.cpp | 42 +- gfx/skia/skia/src/gpu/GrPipeline.h | 12 +- gfx/skia/skia/src/gpu/GrProgramDesc.h | 9 +- gfx/skia/skia/src/gpu/GrRecordReplaceDraw.cpp | 16 +- gfx/skia/skia/{include => src}/gpu/GrRect.h | 0 gfx/skia/skia/src/gpu/GrResourceCache.h | 2 +- gfx/skia/skia/src/gpu/GrResourceProvider.cpp | 13 +- gfx/skia/skia/src/gpu/GrResourceProvider.h | 4 +- gfx/skia/skia/src/gpu/GrSWMaskHelper.cpp | 9 +- .../skia/src/gpu/GrSoftwarePathRenderer.cpp | 21 +- gfx/skia/skia/src/gpu/GrSwizzle.h | 136 ++ gfx/skia/skia/src/gpu/GrTessellator.cpp | 1470 ++++++++++++++++ gfx/skia/skia/src/gpu/GrTessellator.h | 40 + gfx/skia/skia/src/gpu/GrTest.cpp | 76 +- gfx/skia/skia/src/gpu/GrTest.h | 3 +- gfx/skia/skia/src/gpu/GrTextureAccess.cpp | 71 +- .../skia/src/gpu/GrTextureParamsAdjuster.cpp | 6 +- .../skia/src/gpu/GrTextureParamsAdjuster.h | 21 +- gfx/skia/skia/src/gpu/GrTextureProvider.cpp | 35 +- gfx/skia/skia/src/gpu/GrTracing.h | 96 +- gfx/skia/skia/src/gpu/GrTransferBuffer.h | 76 + gfx/skia/skia/src/gpu/SkGpuDevice.cpp | 286 ++-- gfx/skia/skia/src/gpu/SkGpuDevice.h | 21 +- .../skia/src/gpu/SkGpuDevice_drawTexture.cpp | 11 +- gfx/skia/skia/src/gpu/SkGrPixelRef.cpp | 20 +- .../gpu/batches/GrAAConvexPathRenderer.cpp | 16 +- .../src/gpu/batches/GrAAConvexTessellator.cpp | 2 +- .../batches/GrAADistanceFieldPathRenderer.cpp | 69 +- .../gpu/batches/GrAAHairLinePathRenderer.cpp | 1 + .../GrAALinearizingConvexPathRenderer.cpp | 5 +- .../skia/src/gpu/batches/GrAtlasTextBatch.cpp | 63 +- .../skia/src/gpu/batches/GrAtlasTextBatch.h | 43 +- gfx/skia/skia/src/gpu/batches/GrBatch.h | 4 + gfx/skia/skia/src/gpu/batches/GrClearBatch.h | 2 + .../skia/src/gpu/batches/GrCopySurfaceBatch.h | 1 + .../gpu/batches/GrDashLinePathRenderer.cpp | 1 + .../src/gpu/batches/GrDefaultPathRenderer.cpp | 10 +- .../skia/src/gpu/batches/GrDiscardBatch.h | 1 + gfx/skia/skia/src/gpu/batches/GrDrawBatch.h | 7 +- .../skia/src/gpu/batches/GrDrawPathBatch.cpp | 204 ++- .../skia/src/gpu/batches/GrDrawPathBatch.h | 170 +- .../batches/GrStencilAndCoverPathRenderer.cpp | 39 +- .../skia/src/gpu/batches/GrStencilPathBatch.h | 1 + .../batches/GrTessellatingPathRenderer.cpp | 1426 +--------------- .../skia/src/gpu/effects/GrBezierEffect.cpp | 183 +- .../skia/src/gpu/effects/GrBicubicEffect.cpp | 20 +- .../src/gpu/effects/GrBitmapTextGeoProc.cpp | 18 +- .../gpu/effects/GrConfigConversionEffect.cpp | 1 - .../src/gpu/effects/GrConstColorProcessor.cpp | 10 +- .../src/gpu/effects/GrConvexPolyEffect.cpp | 24 +- .../src/gpu/effects/GrConvolutionEffect.cpp | 27 +- .../src/gpu/effects/GrCoverageSetOpXP.cpp | 6 +- .../skia/src/gpu/effects/GrCustomXfermode.cpp | 6 +- .../skia/src/gpu/effects/GrDashingEffect.cpp | 22 +- .../skia/src/gpu/effects/GrDisableColorXP.cpp | 1 - .../gpu/effects/GrDistanceFieldGeoProc.cpp | 107 +- .../src/gpu/effects/GrDistanceFieldGeoProc.h | 8 +- .../skia/src/gpu/effects/GrDitherEffect.cpp | 1 - .../gpu/effects/GrMatrixConvolutionEffect.cpp | 43 +- .../skia/src/gpu/effects/GrOvalEffect.cpp | 91 +- .../gpu/effects/GrPorterDuffXferProcessor.cpp | 26 +- .../skia/src/gpu/effects/GrRRectEffect.cpp | 254 +-- .../src/gpu/effects/GrSimpleTextureEffect.cpp | 1 - .../skia/src/gpu/effects/GrTextureDomain.cpp | 14 +- .../skia/src/gpu/effects/GrTextureDomain.h | 2 + .../effects/GrXfermodeFragmentProcessor.cpp | 2 +- .../skia/src/gpu/effects/GrYUVtoRGBEffect.cpp | 10 +- .../skia/src/gpu/gl/GrGLAssembleInterface.cpp | 45 +- gfx/skia/skia/src/gpu/gl/GrGLBufferImpl.cpp | 10 +- gfx/skia/skia/src/gpu/gl/GrGLBufferImpl.h | 15 +- gfx/skia/skia/src/gpu/gl/GrGLCaps.cpp | 1103 +++++++----- gfx/skia/skia/src/gpu/gl/GrGLCaps.h | 279 +-- gfx/skia/skia/src/gpu/gl/GrGLDefines.h | 69 +- gfx/skia/skia/src/gpu/gl/GrGLGpu.cpp | 996 ++++++----- gfx/skia/skia/src/gpu/gl/GrGLGpu.h | 86 +- gfx/skia/skia/src/gpu/gl/GrGLIndexBuffer.cpp | 3 +- gfx/skia/skia/src/gpu/gl/GrGLInterface.cpp | 6 +- .../skia/src/gpu/gl/GrGLNameAllocator.cpp | 370 ---- gfx/skia/skia/src/gpu/gl/GrGLNameAllocator.h | 86 - gfx/skia/skia/src/gpu/gl/GrGLPath.cpp | 20 + .../skia/src/gpu/gl/GrGLPathRendering.cpp | 99 +- gfx/skia/skia/src/gpu/gl/GrGLPathRendering.h | 3 +- gfx/skia/skia/src/gpu/gl/GrGLProgram.cpp | 45 +- gfx/skia/skia/src/gpu/gl/GrGLProgram.h | 18 +- .../src/gpu/gl/GrGLProgramDataManager.cpp | 8 +- .../skia/src/gpu/gl/GrGLProgramDataManager.h | 1 - gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.cpp | 95 +- gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.h | 5 +- .../skia/src/gpu/gl/GrGLTransferBuffer.cpp | 51 + gfx/skia/skia/src/gpu/gl/GrGLTransferBuffer.h | 48 + .../skia/src/gpu/gl/GrGLUniformHandler.cpp | 90 + gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.h | 61 + gfx/skia/skia/src/gpu/gl/GrGLUtil.cpp | 20 +- gfx/skia/skia/src/gpu/gl/GrGLUtil.h | 6 + gfx/skia/skia/src/gpu/gl/GrGLVaryingHandler.h | 2 +- gfx/skia/skia/src/gpu/gl/GrGLVertexBuffer.cpp | 3 +- gfx/skia/skia/src/gpu/gl/SkGLContext.cpp | 23 + gfx/skia/skia/src/gpu/gl/SkNullGLContext.cpp | 51 +- .../gpu/gl/angle/GrGLCreateANGLEInterface.cpp | 2 +- .../src/gpu/gl/angle/SkANGLEGLContext.cpp | 7 +- .../gpu/gl/builders/GrGLProgramBuilder.cpp | 328 +--- .../src/gpu/gl/builders/GrGLProgramBuilder.h | 119 +- .../SkCommandBufferGLContext.cpp | 64 +- .../gpu/gl/debug/GrGLCreateDebugInterface.cpp | 7 +- .../skia/src/gpu/gl/debug/SkDebugGLContext.h | 5 +- .../gl/egl/SkCreatePlatformGLContext_egl.cpp | 2 +- .../skia/src/gpu/gl/mesa/SkMesaGLContext.h | 5 +- gfx/skia/skia/src/gpu/glsl/GrGLSL.h | 21 +- gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.cpp | 9 - gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.h | 27 +- .../src/gpu/glsl/GrGLSLFragmentProcessor.cpp | 6 +- .../src/gpu/glsl/GrGLSLFragmentProcessor.h | 13 +- .../gpu/glsl/GrGLSLFragmentShaderBuilder.cpp | 16 +- .../gpu/glsl/GrGLSLFragmentShaderBuilder.h | 1 + .../src/gpu/glsl/GrGLSLGeometryProcessor.cpp | 33 +- .../src/gpu/glsl/GrGLSLGeometryProcessor.h | 20 +- .../src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp | 18 +- .../src/gpu/glsl/GrGLSLPrimitiveProcessor.h | 15 +- .../src/gpu/glsl/GrGLSLProgramBuilder.cpp | 250 ++- .../skia/src/gpu/glsl/GrGLSLProgramBuilder.h | 204 +-- .../skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp | 84 +- .../skia/src/gpu/glsl/GrGLSLShaderBuilder.h | 2 + .../skia/src/gpu/glsl/GrGLSLTextureSampler.h | 4 - .../skia/src/gpu/glsl/GrGLSLUniformHandler.h | 79 + .../gpu/glsl/GrGLSLVertexShaderBuilder.cpp | 14 +- .../src/gpu/glsl/GrGLSLVertexShaderBuilder.h | 3 + .../skia/src/gpu/glsl/GrGLSLXferProcessor.cpp | 27 +- .../skia/src/gpu/glsl/GrGLSLXferProcessor.h | 17 +- .../skia/src/gpu/text/GrAtlasTextBlob.cpp | 516 ++++++ .../skia/src/gpu/{ => text}/GrAtlasTextBlob.h | 188 ++- .../skia/src/gpu/text/GrAtlasTextContext.cpp | 774 +++++++++ .../skia/src/gpu/text/GrAtlasTextContext.h | 126 ++ .../src/gpu/{ => text}/GrBatchFontCache.cpp | 0 .../src/gpu/{ => text}/GrBatchFontCache.h | 0 .../gpu/text/GrDistanceFieldAdjustTable.cpp | 93 + .../src/gpu/text/GrDistanceFieldAdjustTable.h | 31 + .../skia/src/gpu/{ => text}/GrFontScaler.cpp | 0 .../skia/src/gpu/{ => text}/GrFontScaler.h | 0 .../GrStencilAndCoverTextContext.cpp | 94 +- .../{ => text}/GrStencilAndCoverTextContext.h | 13 +- .../src/gpu/{ => text}/GrTextBlobCache.cpp | 3 + .../skia/src/gpu/{ => text}/GrTextBlobCache.h | 0 .../skia/src/gpu/{ => text}/GrTextContext.cpp | 130 +- .../skia/src/gpu/{ => text}/GrTextContext.h | 25 +- gfx/skia/skia/src/gpu/text/GrTextUtils.cpp | 206 +++ gfx/skia/skia/src/gpu/text/GrTextUtils.h | 71 + gfx/skia/skia/src/image/SkImage.cpp | 106 +- gfx/skia/skia/src/image/SkImagePriv.h | 8 - gfx/skia/skia/src/image/SkImage_Base.h | 14 +- gfx/skia/skia/src/image/SkImage_Generator.cpp | 7 +- gfx/skia/skia/src/image/SkImage_Gpu.cpp | 117 +- gfx/skia/skia/src/image/SkImage_Gpu.h | 4 +- gfx/skia/skia/src/image/SkImage_Raster.cpp | 6 +- gfx/skia/skia/src/image/SkSurface_Raster.cpp | 6 +- .../src/images/SkDecodingImageGenerator.cpp | 4 +- .../skia/src/images/SkImageDecoder_libgif.cpp | 4 +- .../skia/src/images/SkImageDecoder_libico.cpp | 4 +- .../src/images/SkImageDecoder_libjpeg.cpp | 13 +- .../skia/src/images/SkImageDecoder_libpng.cpp | 52 +- .../src/images/SkImageDecoder_libwebp.cpp | 4 +- gfx/skia/skia/src/images/SkImageEncoder.cpp | 30 +- gfx/skia/skia/src/opts/Sk4px_NEON.h | 77 +- gfx/skia/skia/src/opts/Sk4px_SSE2.h | 75 - gfx/skia/skia/src/opts/Sk4px_none.h | 31 - .../src/opts/SkBitmapProcState_arm_neon.cpp | 25 - .../src/opts/SkBitmapProcState_opts_SSE2.cpp | 114 -- .../src/opts/SkBitmapProcState_opts_SSE2.h | 3 - .../src/opts/SkBitmapProcState_opts_SSSE3.cpp | 34 - .../src/opts/SkBitmapProcState_opts_SSSE3.h | 8 - .../opts/SkBitmapProcState_opts_mips_dsp.cpp | 134 -- .../skia/src/opts/SkBlitRow_opts_arm_neon.cpp | 4 +- .../skia/src/opts/SkColorCubeFilter_opts.h | 10 +- gfx/skia/skia/src/opts/SkNx_avx.h | 38 +- gfx/skia/skia/src/opts/SkNx_neon.h | 65 +- gfx/skia/skia/src/opts/SkNx_sse.h | 139 +- gfx/skia/skia/src/opts/SkOpts_neon.cpp | 5 + gfx/skia/skia/src/opts/SkOpts_sse2.cpp | 5 + gfx/skia/skia/src/opts/SkOpts_sse41.cpp | 173 ++ gfx/skia/skia/src/opts/SkPx_neon.h | 188 --- gfx/skia/skia/src/opts/SkPx_none.h | 111 -- gfx/skia/skia/src/opts/SkPx_sse.h | 155 -- gfx/skia/skia/src/opts/SkSwizzler_opts.h | 153 ++ gfx/skia/skia/src/opts/SkXfermode_opts.h | 118 +- gfx/skia/skia/src/opts/opts_check_x86.cpp | 11 - .../skia/src/pathops/SkDLineIntersection.cpp | 2 +- gfx/skia/skia/src/pathops/SkOpAngle.cpp | 2 +- gfx/skia/skia/src/pathops/SkOpCoincidence.cpp | 9 + gfx/skia/skia/src/pathops/SkOpSegment.cpp | 6 +- gfx/skia/skia/src/pathops/SkPathOpsLine.cpp | 5 +- gfx/skia/skia/src/pathops/SkPathOpsQuad.cpp | 3 +- gfx/skia/skia/src/pathops/SkPathOpsTSect.h | 8 +- gfx/skia/skia/src/pathops/SkPathOpsTypes.cpp | 50 +- gfx/skia/skia/src/pathops/SkPathOpsTypes.h | 10 + gfx/skia/skia/src/pathops/SkReduceOrder.cpp | 4 +- gfx/skia/skia/src/pdf/SkPDFBitmap.cpp | 18 +- gfx/skia/skia/src/pdf/SkPDFBitmap.h | 2 +- gfx/skia/skia/src/pdf/SkPDFCanon.h | 3 + gfx/skia/skia/src/pdf/SkPDFDevice.cpp | 151 +- gfx/skia/skia/src/pdf/SkPDFFont.cpp | 9 +- gfx/skia/skia/src/pdf/SkPDFMetadata.cpp | 9 +- gfx/skia/skia/src/pipe/SkGPipePriv.h | 314 ---- gfx/skia/skia/src/pipe/SkGPipeRead.cpp | 1017 ----------- gfx/skia/skia/src/pipe/SkGPipeWrite.cpp | 1495 ----------------- .../src/pipe/utils/SamplePipeControllers.cpp | 115 -- .../src/pipe/utils/SamplePipeControllers.h | 87 - .../src/ports/SkFontMgr_android_parser.cpp | 11 +- .../skia/src/ports/SkFontMgr_android_parser.h | 2 +- .../ports/SkGlobalInitialization_chromium.cpp | 147 -- .../ports/SkGlobalInitialization_default.cpp | 143 +- .../skia/src/ports/SkImageDecoder_empty.cpp | 18 + .../skia/src/ports/SkImageGenerator_skia.cpp | 2 +- gfx/skia/skia/src/ports/SkOSEnvironment.cpp | 19 + gfx/skia/skia/src/ports/SkOSEnvironment.h | 15 + gfx/skia/skia/src/ports/SkOSFile_stdio.cpp | 8 + gfx/skia/skia/src/ports/SkTime_Unix.cpp | 33 - gfx/skia/skia/src/ports/SkTime_win.cpp | 36 - gfx/skia/skia/src/svg/parser/SkSVG.cpp | 7 +- gfx/skia/skia/src/utils/SkCubicInterval.cpp | 67 - gfx/skia/skia/src/utils/SkCullPoints.cpp | 211 --- gfx/skia/skia/src/utils/SkDashPath.cpp | 2 +- gfx/skia/skia/src/utils/SkDumpCanvas.cpp | 19 +- .../skia/src/utils/SkFrontBufferedStream.cpp | 18 +- gfx/skia/skia/src/utils/SkInterpolator.cpp | 4 +- gfx/skia/skia/src/utils/SkLua.cpp | 33 + gfx/skia/skia/src/utils/SkLuaCanvas.cpp | 20 +- gfx/skia/skia/src/utils/SkNWayCanvas.cpp | 14 +- .../skia/src/utils/SkPaintFilterCanvas.cpp | 119 +- gfx/skia/skia/src/utils/SkParsePath.cpp | 4 + gfx/skia/skia/src/utils/SkTFitsIn.h | 10 +- .../src/utils/android/SkAndroidSDKCanvas.cpp | 374 ----- .../src/utils/android/SkAndroidSDKCanvas.h | 112 -- .../skia/src/utils/debugger/SkDebugCanvas.cpp | 28 +- .../skia/src/utils/debugger/SkDebugCanvas.h | 3 +- .../skia/src/utils/debugger/SkDrawCommand.cpp | 97 +- .../skia/src/utils/debugger/SkDrawCommand.h | 29 +- .../src/utils/debugger/SkObjectParser.cpp | 13 +- .../skia/src/utils/debugger/SkObjectParser.h | 6 +- gfx/skia/skia/src/views/SkView.cpp | 245 ++- .../skia/src/views/sdl/SkOSWindow_SDL.cpp | 403 +++-- gfx/skia/skia/src/xml/SkDOM.cpp | 2 +- 570 files changed, 15509 insertions(+), 18891 deletions(-) create mode 100644 gfx/skia/skia/include/effects/SkPaintImageFilter.h delete mode 100644 gfx/skia/skia/include/effects/SkRectShaderImageFilter.h delete mode 100644 gfx/skia/skia/include/pipe/SkGPipe.h create mode 100644 gfx/skia/skia/include/private/GrAuditTrail.h create mode 100644 gfx/skia/skia/include/private/GrSingleOwner.h rename gfx/skia/skia/include/{core => private}/SkTDict.h (100%) rename gfx/skia/skia/include/{core => private}/SkTSearch.h (100%) delete mode 100644 gfx/skia/skia/include/private/SkUtility.h delete mode 100644 gfx/skia/skia/include/utils/SkCubicInterval.h delete mode 100644 gfx/skia/skia/include/utils/SkCullPoints.h rename gfx/skia/skia/include/{utils => views}/SkParsePaint.h (100%) create mode 100644 gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp create mode 100644 gfx/skia/skia/src/codec/SkCodecImageGenerator.h delete mode 100644 gfx/skia/skia/src/codec/SkCodec_libico.h rename gfx/skia/skia/src/codec/{SkCodec_libgif.cpp => SkGifCodec.cpp} (99%) rename gfx/skia/skia/src/codec/{SkCodec_libgif.h => SkGifCodec.h} (98%) rename gfx/skia/skia/src/codec/{SkCodec_libico.cpp => SkIcoCodec.cpp} (65%) create mode 100644 gfx/skia/skia/src/codec/SkIcoCodec.h rename gfx/skia/skia/src/codec/{SkCodec_wbmp.cpp => SkWbmpCodec.cpp} (96%) rename gfx/skia/skia/src/codec/{SkCodec_wbmp.h => SkWbmpCodec.h} (97%) delete mode 100644 gfx/skia/skia/src/core/SkBitmapFilter.cpp create mode 100644 gfx/skia/skia/src/core/SkColorFilterShader.cpp rename gfx/skia/skia/src/core/{SkFilterShader.h => SkColorFilterShader.h} (51%) rename gfx/skia/skia/{include => src}/core/SkDither.h (100%) delete mode 100644 gfx/skia/skia/src/core/SkFilterShader.cpp create mode 100644 gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp rename gfx/skia/skia/src/{effects/SkColorFilters.cpp => core/SkModeColorFilter.cpp} (85%) rename gfx/skia/skia/{include/effects => src/core}/SkModeColorFilter.h (82%) delete mode 100644 gfx/skia/skia/src/core/SkPx.h create mode 100644 gfx/skia/skia/src/core/SkScaleToSides.h create mode 100644 gfx/skia/skia/src/core/SkValue.h rename gfx/skia/skia/src/effects/{SkRectShaderImageFilter.cpp => SkPaintImageFilter.cpp} (50%) delete mode 100644 gfx/skia/skia/src/effects/gradients/SkRadialGradient_Table.h delete mode 100644 gfx/skia/skia/src/gpu/GrAtlasTextBlob.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrAtlasTextContext.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrAtlasTextContext.h create mode 100644 gfx/skia/skia/src/gpu/GrAuditTrail.cpp rename gfx/skia/skia/{include => src}/gpu/GrRect.h (100%) create mode 100644 gfx/skia/skia/src/gpu/GrSwizzle.h create mode 100644 gfx/skia/skia/src/gpu/GrTessellator.cpp create mode 100644 gfx/skia/skia/src/gpu/GrTessellator.h create mode 100755 gfx/skia/skia/src/gpu/GrTransferBuffer.h delete mode 100644 gfx/skia/skia/src/gpu/gl/GrGLNameAllocator.cpp delete mode 100644 gfx/skia/skia/src/gpu/gl/GrGLNameAllocator.h create mode 100755 gfx/skia/skia/src/gpu/gl/GrGLTransferBuffer.cpp create mode 100755 gfx/skia/skia/src/gpu/gl/GrGLTransferBuffer.h create mode 100644 gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.cpp create mode 100644 gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.h create mode 100644 gfx/skia/skia/src/gpu/glsl/GrGLSLUniformHandler.h create mode 100644 gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.cpp rename gfx/skia/skia/src/gpu/{ => text}/GrAtlasTextBlob.h (52%) create mode 100644 gfx/skia/skia/src/gpu/text/GrAtlasTextContext.cpp create mode 100644 gfx/skia/skia/src/gpu/text/GrAtlasTextContext.h rename gfx/skia/skia/src/gpu/{ => text}/GrBatchFontCache.cpp (100%) rename gfx/skia/skia/src/gpu/{ => text}/GrBatchFontCache.h (100%) create mode 100644 gfx/skia/skia/src/gpu/text/GrDistanceFieldAdjustTable.cpp create mode 100644 gfx/skia/skia/src/gpu/text/GrDistanceFieldAdjustTable.h rename gfx/skia/skia/src/gpu/{ => text}/GrFontScaler.cpp (100%) rename gfx/skia/skia/src/gpu/{ => text}/GrFontScaler.h (100%) rename gfx/skia/skia/src/gpu/{ => text}/GrStencilAndCoverTextContext.cpp (90%) rename gfx/skia/skia/src/gpu/{ => text}/GrStencilAndCoverTextContext.h (92%) rename gfx/skia/skia/src/gpu/{ => text}/GrTextBlobCache.cpp (94%) rename gfx/skia/skia/src/gpu/{ => text}/GrTextBlobCache.h (100%) rename gfx/skia/skia/src/gpu/{ => text}/GrTextContext.cpp (51%) rename gfx/skia/skia/src/gpu/{ => text}/GrTextContext.h (66%) create mode 100644 gfx/skia/skia/src/gpu/text/GrTextUtils.cpp create mode 100644 gfx/skia/skia/src/gpu/text/GrTextUtils.h delete mode 100644 gfx/skia/skia/src/opts/SkPx_neon.h delete mode 100644 gfx/skia/skia/src/opts/SkPx_none.h delete mode 100644 gfx/skia/skia/src/opts/SkPx_sse.h create mode 100644 gfx/skia/skia/src/opts/SkSwizzler_opts.h delete mode 100644 gfx/skia/skia/src/pipe/SkGPipePriv.h delete mode 100644 gfx/skia/skia/src/pipe/SkGPipeRead.cpp delete mode 100644 gfx/skia/skia/src/pipe/SkGPipeWrite.cpp delete mode 100644 gfx/skia/skia/src/pipe/utils/SamplePipeControllers.cpp delete mode 100644 gfx/skia/skia/src/pipe/utils/SamplePipeControllers.h delete mode 100644 gfx/skia/skia/src/ports/SkGlobalInitialization_chromium.cpp create mode 100644 gfx/skia/skia/src/ports/SkOSEnvironment.cpp create mode 100644 gfx/skia/skia/src/ports/SkOSEnvironment.h delete mode 100644 gfx/skia/skia/src/utils/SkCubicInterval.cpp delete mode 100644 gfx/skia/skia/src/utils/SkCullPoints.cpp delete mode 100644 gfx/skia/skia/src/utils/android/SkAndroidSDKCanvas.cpp delete mode 100644 gfx/skia/skia/src/utils/android/SkAndroidSDKCanvas.h diff --git a/CLOBBER b/CLOBBER index b78ee44b58a..99cbd754bb4 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,5 +22,5 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 1237983 - Investigate and remove the Bagheera Client implementation. +Bug 1246756 - Update Skia to m49 branch. diff --git a/gfx/skia/skia/include/codec/SkAndroidCodec.h b/gfx/skia/skia/include/codec/SkAndroidCodec.h index f979886a43e..c5578d3964c 100644 --- a/gfx/skia/skia/include/codec/SkAndroidCodec.h +++ b/gfx/skia/skia/include/codec/SkAndroidCodec.h @@ -50,7 +50,25 @@ public: /** * Format of the encoded data. */ - SkEncodedFormat getEncodedFormat() const { return this->onGetEncodedFormat(); } + SkEncodedFormat getEncodedFormat() const { return fCodec->getEncodedFormat(); } + + /** + * @param requestedColorType Color type requested by the client + * + * If it is possible to decode to requestedColorType, this returns + * requestedColorType. Otherwise, this returns whichever color type + * is suggested by the codec as the best match for the encoded data. + */ + SkColorType computeOutputColorType(SkColorType requestedColorType); + + /** + * @param requestedUnpremul Indicates if the client requested + * unpremultiplied output + * + * Returns the appropriate alpha type to decode to. If the image + * has alpha, the value of requestedUnpremul will be honored. + */ + SkAlphaType computeOutputAlphaType(bool requestedUnpremul); /** * Returns the dimensions of the scaled output image, for an input @@ -210,9 +228,9 @@ public: protected: - SkAndroidCodec(const SkImageInfo&); + SkAndroidCodec(SkCodec*); - virtual SkEncodedFormat onGetEncodedFormat() const = 0; + SkCodec* codec() const { return fCodec.get(); } virtual SkISize onGetSampledDimensions(int sampleSize) const = 0; @@ -226,5 +244,7 @@ private: // This will always be a reference to the info that is contained by the // embedded SkCodec. const SkImageInfo& fInfo; + + SkAutoTDelete fCodec; }; #endif // SkAndroidCodec_DEFINED diff --git a/gfx/skia/skia/include/codec/SkCodec.h b/gfx/skia/skia/include/codec/SkCodec.h index 9f28af010ed..597ebd039e8 100644 --- a/gfx/skia/skia/include/codec/SkCodec.h +++ b/gfx/skia/skia/include/codec/SkCodec.h @@ -25,10 +25,35 @@ class SkSampler; */ class SkCodec : SkNoncopyable { public: + /** + * Minimum number of bytes that must be buffered in SkStream input. + * + * An SkStream passed to NewFromStream must be able to use this many + * bytes to determine the image type. Then the same SkStream must be + * passed to the correct decoder to read from the beginning. + * + * This can be accomplished by implementing peek() to support peeking + * this many bytes, or by implementing rewind() to be able to rewind() + * after reading this many bytes. + */ + static size_t MinBufferedBytesNeeded(); + /** * If this stream represents an encoded image that we know how to decode, * return an SkCodec that can decode it. Otherwise return NULL. * + * As stated above, this call must be able to peek or read + * MinBufferedBytesNeeded to determine the correct format, and then start + * reading from the beginning. First it will attempt to peek, and it + * assumes that if less than MinBufferedBytesNeeded bytes (but more than + * zero) are returned, this is because the stream is shorter than this, + * so falling back to reading would not provide more data. If peek() + * returns zero bytes, this call will instead attempt to read(). This + * will require that the stream can be rewind()ed. + * + * If SkPngChunkReader is not NULL, take a ref and pass it to libpng if + * the image is a png. + * * If the SkPngChunkReader is not NULL then: * If the image is not a PNG, the SkPngChunkReader will be ignored. * If the image is a PNG, the SkPngChunkReader will be reffed. @@ -252,18 +277,6 @@ public: */ Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes); - /** - * Some images may initially report that they have alpha due to the format - * of the encoded data, but then never use any colors which have alpha - * less than 100%. This function can be called *after* decoding to - * determine if such an image truly had alpha. Calling it before decoding - * is undefined. - * FIXME: see skbug.com/3582. - */ - bool reallyHasAlpha() const { - return this->onReallyHasAlpha(); - } - /** * The remaining functions revolve around decoding scanlines. */ @@ -400,6 +413,8 @@ public: /** * An enum representing the order in which scanlines will be returned by * the scanline decoder. + * + * This is undefined before startScanlineDecode() is called. */ SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder(); } @@ -415,9 +430,9 @@ public: int nextScanline() const { return this->outputScanline(fCurrScanline); } /** - * Returns the output y-coordinate of the row that corresponds to an input - * y-coordinate. The input y-coordinate represents where the scanline - * is located in the encoded data. + * Returns the output y-coordinate of the row that corresponds to an input + * y-coordinate. The input y-coordinate represents where the scanline + * is located in the encoded data. * * This will equal inputScanline, except in the case of strangely * encoded image types (bottom-up bmps, interlaced gifs). @@ -459,8 +474,6 @@ protected: return false; } - virtual bool onReallyHasAlpha() const { return false; } - /** * If the stream was previously read, attempt to rewind. * @@ -529,14 +542,22 @@ protected: virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanlineOrder; } /** - * Update the next scanline. Used by interlaced png. + * Update the current scanline. Used by interlaced png. */ - void updateNextScanline(int newY) { fCurrScanline = newY; } + void updateCurrScanline(int newY) { fCurrScanline = newY; } const SkImageInfo& dstInfo() const { return fDstInfo; } const SkCodec::Options& options() const { return fOptions; } + /** + * Returns the number of scanlines that have been decoded so far. + * This is unaffected by the SkScanlineOrder. + * + * Returns -1 if we have not started a scanline decode. + */ + int currScanline() const { return fCurrScanline; } + virtual int onOutputScanline(int inputScanline) const; private: @@ -610,5 +631,6 @@ private: virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; } friend class SkSampledCodec; + friend class SkIcoCodec; }; #endif // SkCodec_DEFINED diff --git a/gfx/skia/skia/include/core/SkBitmap.h b/gfx/skia/skia/include/core/SkBitmap.h index eda13b3c523..a81e03eefa6 100644 --- a/gfx/skia/skia/include/core/SkBitmap.h +++ b/gfx/skia/skia/include/core/SkBitmap.h @@ -54,12 +54,24 @@ public: */ SkBitmap(const SkBitmap& src); + /** + * Copy the settings from the src into this bitmap. If the src has pixels + * allocated, ownership of the pixels will be taken. + */ + SkBitmap(SkBitmap&& src); + ~SkBitmap(); - /** Copies the src bitmap into this bitmap. Ownership of the src bitmap's pixels remains - with the src bitmap. + /** Copies the src bitmap into this bitmap. Ownership of the src + bitmap's pixels is shared with the src bitmap. */ SkBitmap& operator=(const SkBitmap& src); + + /** Copies the src bitmap into this bitmap. Takes ownership of the src + bitmap's pixels. + */ + SkBitmap& operator=(SkBitmap&& src); + /** Swap the fields of the two bitmaps. This routine is guaranteed to never fail or throw. */ // This method is not exported to java. @@ -294,6 +306,14 @@ public: return this->installPixels(info, pixels, rowBytes, NULL, NULL, NULL); } + /** + * Call installPixels with no ReleaseProc specified. This means + * that the caller must ensure that the specified pixels and + * colortable are valid for the lifetime of the created bitmap + * (and its pixelRef). + */ + bool installPixels(const SkPixmap&); + /** * Calls installPixels() with the value in the SkMask. The caller must * ensure that the specified mask pixels are valid for the lifetime diff --git a/gfx/skia/skia/include/core/SkCanvas.h b/gfx/skia/skia/include/core/SkCanvas.h index 53f6dda88b0..d1de626315e 100644 --- a/gfx/skia/skia/include/core/SkCanvas.h +++ b/gfx/skia/skia/include/core/SkCanvas.h @@ -37,6 +37,16 @@ class SkSurface; class SkSurface_Base; class SkTextBlob; +/* + * If you want the legacy cliptolayer flag (i.e. android), then you must have the new + * legacy saveflags. + */ +#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG +#ifndef SK_SUPPORT_LEGACY_SAVEFLAGS + #define SK_SUPPORT_LEGACY_SAVEFLAGS +#endif +#endif + /** \class SkCanvas A Canvas encapsulates all of the state about drawing into a device (bitmap). @@ -53,6 +63,10 @@ class SkTextBlob; etc. */ class SK_API SkCanvas : public SkRefCnt { + enum PrivateSaveLayerFlags { + kDontClipToLayer_PrivateSaveLayerFlag = 1 << 31, + }; + public: /** * Attempt to allocate raster canvas, matching the ImageInfo, that will draw directly into the @@ -281,6 +295,7 @@ public: /////////////////////////////////////////////////////////////////////////// +#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS enum SaveFlags { /** save the matrix state, restoring it on restore() */ // [deprecated] kMatrix_SaveFlag = 0x01, @@ -307,6 +322,7 @@ public: #endif kARGB_ClipLayer_SaveFlag = 0x1F }; +#endif /** This call saves the current matrix, clip, and drawFilter, and pushes a copy onto a private stack. Subsequent calls to translate, scale, @@ -336,6 +352,14 @@ public: return this->saveLayer(&bounds, paint); } + /** + * Temporary name. + * Will allow any requests for LCD text to be respected, so the caller must be careful to + * only draw on top of opaque sections of the layer to get good results. + */ + int saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint); + +#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS /** DEPRECATED - use saveLayer(const SkRect*, const SkPaint*) instead. This behaves the same as saveLayer(const SkRect*, const SkPaint*), @@ -353,6 +377,7 @@ public: */ SK_ATTR_EXTERNALLY_DEPRECATED("SaveFlags use is deprecated") int saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags); +#endif /** This behaves the same as save(), but in addition it allocates an offscreen bitmap. All drawing calls are directed there, and only when @@ -367,6 +392,7 @@ public: */ int saveLayerAlpha(const SkRect* bounds, U8CPU alpha); +#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS /** DEPRECATED - use saveLayerAlpha(const SkRect*, U8CPU) instead. This behaves the same as saveLayerAlpha(const SkRect*, U8CPU), @@ -383,6 +409,43 @@ public: */ SK_ATTR_EXTERNALLY_DEPRECATED("SaveFlags use is deprecated") int saveLayerAlpha(const SkRect* bounds, U8CPU alpha, SaveFlags flags); +#endif + + enum { + kIsOpaque_SaveLayerFlag = 1 << 0, + kPreserveLCDText_SaveLayerFlag = 1 << 1, + +#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG + kDontClipToLayer_Legacy_SaveLayerFlag = kDontClipToLayer_PrivateSaveLayerFlag, +#endif + }; + typedef uint32_t SaveLayerFlags; + + struct SaveLayerRec { + SaveLayerRec() + : fBounds(nullptr), fPaint(nullptr), fBackdrop(nullptr), fSaveLayerFlags(0) + {} + SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0) + : fBounds(bounds) + , fPaint(paint) + , fBackdrop(nullptr) + , fSaveLayerFlags(saveLayerFlags) + {} + SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, + SaveLayerFlags saveLayerFlags) + : fBounds(bounds) + , fPaint(paint) + , fBackdrop(backdrop) + , fSaveLayerFlags(saveLayerFlags) + {} + + const SkRect* fBounds; // optional + const SkPaint* fPaint; // optional + const SkImageFilter* fBackdrop; // optional + SaveLayerFlags fSaveLayerFlags; + }; + + int saveLayer(const SaveLayerRec&); /** This call balances a previous call to save(), and is used to remove all modifications to the matrix/clip/drawFilter state since the last save @@ -606,8 +669,8 @@ public: * This makes the contents of the canvas undefined. Subsequent calls that * require reading the canvas contents will produce undefined results. Examples * include blending and readPixels. The actual implementation is backend- - * dependent and one legal implementation is to do nothing. Like clear(), this - * ignores the clip. + * dependent and one legal implementation is to do nothing. This method + * ignores the current clip. * * This function should only be called if the caller intends to subsequently * draw to the canvas. The canvas may do real work at discard() time in order @@ -617,7 +680,7 @@ public: void discard() { this->onDiscard(); } /** - * Fill the entire canvas' bitmap (restricted to the current clip) with the + * Fill the entire canvas (restricted to the current clip) with the * specified paint. * @param paint The paint used to fill the canvas */ @@ -904,19 +967,6 @@ public: void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint = NULL); - /** Draw the specified bitmap, with its top/left corner at (x,y), - NOT transformed by the current matrix. Note: if the paint - contains a maskfilter that generates a mask which extends beyond the - bitmap's original width/height, then the bitmap will be drawn as if it - were in a Shader with CLAMP mode. Thus the color outside of the original - width/height will be the edge color replicated. - @param bitmap The bitmap to be drawn - @param left The position of the left side of the bitmap being drawn - @param top The position of the top side of the bitmap being drawn - @param paint The paint used to draw the bitmap, or NULL - */ - void drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint = NULL); - /** Draw the text, with origin at (x,y), using the specified paint. The origin is interpreted based on the Align setting in the paint. @param text The text to be drawn @@ -1223,14 +1273,15 @@ protected: // Subclass save/restore notifiers. // Overriders should call the corresponding INHERITED method up the inheritance chain. - // willSaveLayer()'s return value may suppress full layer allocation. + // getSaveLayerStrategy()'s return value may suppress full layer allocation. enum SaveLayerStrategy { kFullLayer_SaveLayerStrategy, - kNoLayer_SaveLayerStrategy + kNoLayer_SaveLayerStrategy, }; virtual void willSave() {} - virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) { + // Overriders should call the corresponding INHERITED method up the inheritance chain. + virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) { return kFullLayer_SaveLayerStrategy; } virtual void willRestore() {} @@ -1285,7 +1336,6 @@ protected: SrcRectConstraint); virtual void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*); - virtual void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*); enum ClipEdgeStyle { kHard_ClipEdgeStyle, @@ -1311,11 +1361,21 @@ protected: // returns false if the entire rectangle is entirely clipped out // If non-NULL, The imageFilter parameter will be used to expand the clip // and offscreen bounds for any margin required by the filter DAG. - bool clipRectBounds(const SkRect* bounds, SaveFlags flags, - SkIRect* intersection, + bool clipRectBounds(const SkRect* bounds, SaveLayerFlags, SkIRect* intersection, const SkImageFilter* imageFilter = NULL); +#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS + // Needed by SkiaCanvasProxy in Android. Make sure that class is updated + // before removing this method. + static uint32_t SaveLayerFlagsToSaveFlags(SaveLayerFlags); +#endif private: + static bool BoundsAffectsClip(SaveLayerFlags); +#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS + static uint32_t SaveFlagsToSaveLayerFlags(SaveFlags); +#endif + static SaveLayerFlags LegacySaveFlagsToSaveLayerFlags(uint32_t legacySaveFlags); + enum ShaderOverrideOpacity { kNone_ShaderOverrideOpacity, //!< there is no overriding shader (bitmap or image) kOpaque_ShaderOverrideOpacity, //!< the overriding shader is opaque @@ -1375,6 +1435,7 @@ private: friend class SkNoSaveLayerCanvas; // InitFlags friend class SkPictureImageFilter; // SkCanvas(SkBaseDevice*, SkSurfaceProps*, InitFlags) friend class SkPictureRecord; // predrawNotify (why does it need it? ) + friend class SkPicturePlayback; // SaveFlagsToSaveLayerFlags enum InitFlags { kDefault_InitFlags = 0, @@ -1406,7 +1467,7 @@ private: const SkRect& dst, const SkPaint* paint, SrcRectConstraint); void internalDrawPaint(const SkPaint& paint); - void internalSaveLayer(const SkRect* bounds, const SkPaint*, SaveFlags, SaveLayerStrategy); + void internalSaveLayer(const SaveLayerRec&, SaveLayerStrategy); void internalDrawDevice(SkBaseDevice*, int x, int y, const SkPaint*, bool isBitmapDevice); // shared by save() and saveLayer() @@ -1428,6 +1489,10 @@ private: */ bool wouldOverwriteEntireSurface(const SkRect*, const SkPaint*, ShaderOverrideOpacity) const; + /** + * Returns true if the paint's imagefilter can be invoked directly, without needed a layer. + */ + bool canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint&); /* These maintain a cache of the clip bounds in local coordinates, (converted to 2s-compliment if floats are slow). @@ -1505,49 +1570,7 @@ private: }; #define SkAutoCanvasRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoCanvasRestore) -/** - * If the caller wants read-only access to the pixels in a canvas, it can just - * call canvas->peekPixels(), since that is the fastest way to "peek" at the - * pixels on a raster-backed canvas. - * - * If the canvas has pixels, but they are not readily available to the CPU - * (e.g. gpu-backed), then peekPixels() will fail, but readPixels() will - * succeed (though be slower, since it will return a copy of the pixels). - * - * SkAutoROCanvasPixels encapsulates these two techniques, trying first to call - * peekPixels() (for performance), but if that fails, calling readPixels() and - * storing the copy locally. - * - * The caller must respect the restrictions associated with peekPixels(), since - * that may have been called: The returned information is invalidated if... - * - any API is called on the canvas (or its parent surface if present) - * - the canvas goes out of scope - */ -class SkAutoROCanvasPixels : SkNoncopyable { -public: - SkAutoROCanvasPixels(SkCanvas* canvas); - - // returns NULL on failure - const void* addr() const { return fAddr; } - - // undefined if addr() == NULL - size_t rowBytes() const { return fRowBytes; } - - // undefined if addr() == NULL - const SkImageInfo& info() const { return fInfo; } - - // helper that, if returns true, installs the pixels into the bitmap. Note - // that the bitmap may reference the address returned by peekPixels(), so - // the caller must respect the restrictions associated with peekPixels(). - bool asROBitmap(SkBitmap*) const; - -private: - SkBitmap fBitmap; // used if peekPixels() fails - const void* fAddr; // NULL on failure - SkImageInfo fInfo; - size_t fRowBytes; -}; - +#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS static inline SkCanvas::SaveFlags operator|(const SkCanvas::SaveFlags lhs, const SkCanvas::SaveFlags rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); @@ -1558,6 +1581,7 @@ static inline SkCanvas::SaveFlags& operator|=(SkCanvas::SaveFlags& lhs, lhs = lhs | rhs; return lhs; } +#endif class SkCanvasClipVisitor { public: diff --git a/gfx/skia/skia/include/core/SkColorFilter.h b/gfx/skia/skia/include/core/SkColorFilter.h index 57650fbd985..c5d084a22d0 100644 --- a/gfx/skia/skia/include/core/SkColorFilter.h +++ b/gfx/skia/skia/include/core/SkColorFilter.h @@ -106,13 +106,6 @@ public: */ static SkColorFilter* CreateModeFilter(SkColor c, SkXfermode::Mode mode); - /** Create a colorfilter that multiplies the RGB channels by one color, and - then adds a second color, pinning the result for each component to - [0..255]. The alpha components of the mul and add arguments - are ignored. - */ - static SkColorFilter* CreateLightingFilter(SkColor mul, SkColor add); - /** Construct a colorfilter whose effect is to first apply the inner filter and then apply * the outer filter to the result of the inner's. * The reference counts for outer and inner are incremented. diff --git a/gfx/skia/skia/include/core/SkDevice.h b/gfx/skia/skia/include/core/SkDevice.h index c52c579424a..65ec56f902f 100644 --- a/gfx/skia/skia/include/core/SkDevice.h +++ b/gfx/skia/skia/include/core/SkDevice.h @@ -333,16 +333,26 @@ protected: const SkPaint*); struct CreateInfo { - static SkPixelGeometry AdjustGeometry(const SkImageInfo&, TileUsage, SkPixelGeometry); + static SkPixelGeometry AdjustGeometry(const SkImageInfo&, TileUsage, SkPixelGeometry, + bool preserveLCDText); // The constructor may change the pixel geometry based on other parameters. CreateInfo(const SkImageInfo& info, TileUsage tileUsage, - SkPixelGeometry geo, - bool forImageFilter = false) + SkPixelGeometry geo) : fInfo(info) , fTileUsage(tileUsage) - , fPixelGeometry(AdjustGeometry(info, tileUsage, geo)) + , fPixelGeometry(AdjustGeometry(info, tileUsage, geo, false)) + , fForImageFilter(false) {} + + CreateInfo(const SkImageInfo& info, + TileUsage tileUsage, + SkPixelGeometry geo, + bool preserveLCDText, + bool forImageFilter) + : fInfo(info) + , fTileUsage(tileUsage) + , fPixelGeometry(AdjustGeometry(info, tileUsage, geo, preserveLCDText)) , fForImageFilter(forImageFilter) {} const SkImageInfo fInfo; @@ -374,9 +384,13 @@ private: friend class SkDeviceFilteredPaint; friend class SkImageFilter::DeviceProxy; friend class SkNoPixelsBitmapDevice; - friend class SkSurface_Raster; + /** + * Calls through to drawSprite, processing imagefilter as needed. + */ + void drawBitmapAsSprite(const SkDraw&, const SkBitmap&, int x, int y, const SkPaint&); + // used to change the backend's pixels (and possibly config/rowbytes) // but cannot change the width/height, so there should be no change to // any clip information. diff --git a/gfx/skia/skia/include/core/SkDocument.h b/gfx/skia/skia/include/core/SkDocument.h index 316d15a2534..6ee96b9ce3a 100644 --- a/gfx/skia/skia/include/core/SkDocument.h +++ b/gfx/skia/skia/include/core/SkDocument.h @@ -16,6 +16,7 @@ #include "SkTime.h" class SkCanvas; +class SkPixelSerializer; class SkWStream; /** SK_ScalarDefaultDPI is 72 DPI. @@ -57,6 +58,24 @@ public: static SkDocument* CreatePDF(SkWStream*, SkScalar dpi = SK_ScalarDefaultRasterDPI); + /** + * @param jpegEncoder For PDF documents, if a jpegEncoder is set, + * use it to encode SkImages and SkBitmaps as [JFIF]JPEGs. + * This feature is deprecated and is only supplied for + * backwards compatability. + * + * The prefered method to create PDFs with JPEG images is + * to use SkImage::NewFromEncoded() and not jpegEncoder. + * Chromium uses NewFromEncoded. + * + * If the encoder is unset, or if jpegEncoder->onEncode() + * returns NULL, fall back on encoding images losslessly + * with Deflate. + */ + static SkDocument* CreatePDF(SkWStream*, + SkScalar dpi, + SkPixelSerializer* jpegEncoder); + /** * Create a PDF-backed document, writing the results into a file. */ diff --git a/gfx/skia/skia/include/core/SkDrawFilter.h b/gfx/skia/skia/include/core/SkDrawFilter.h index 865df5f1e18..2812017b711 100644 --- a/gfx/skia/skia/include/core/SkDrawFilter.h +++ b/gfx/skia/skia/include/core/SkDrawFilter.h @@ -16,6 +16,8 @@ class SkCanvas; class SkPaint; /** + * DEPRECATED - use SkPaintFilterCanvas instead. + * * Right before something is being draw, filter() is called with the * paint. The filter may modify the paint as it wishes, which will then be * used for the actual drawing. Note: this modification only lasts for the diff --git a/gfx/skia/skia/include/core/SkFixed.h b/gfx/skia/skia/include/core/SkFixed.h index fefa718d0fe..f6dd3d60020 100644 --- a/gfx/skia/skia/include/core/SkFixed.h +++ b/gfx/skia/skia/include/core/SkFixed.h @@ -86,9 +86,9 @@ typedef int32_t SkFixed; #if defined(SK_SUPPORT_LEGACY_DIVBITS_UB) #define SkFixedDiv(numer, denom) SkDivBits(numer, denom, 16) #else - // TODO(reed): this clamp shouldn't be needed. Use SkToS32(). + // The divide may exceed 32 bits. Clamp to a signed 32 bit result. #define SkFixedDiv(numer, denom) \ - SkTPin(((int64_t)numer << 16) / denom, SK_MinS32, SK_MaxS32) + SkToS32(SkTPin((SkLeftShift((int64_t)numer, 16) / denom), SK_MinS32, SK_MaxS32)) #endif ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -145,9 +145,9 @@ inline SkFixed SkFixedMul_longlong(SkFixed a, SkFixed b) { typedef int64_t SkFixed3232; // 32.32 -#define SkIntToFixed3232(x) ((SkFixed3232)(x) << 32) +#define SkIntToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 32)) #define SkFixed3232ToInt(x) ((int)((x) >> 32)) -#define SkFixedToFixed3232(x) ((SkFixed3232)(x) << 16) +#define SkFixedToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 16)) #define SkFixed3232ToFixed(x) ((SkFixed)((x) >> 16)) #define SkFloatToFixed3232(x) ((SkFixed3232)((x) * (65536.0f * 65536.0f))) diff --git a/gfx/skia/skia/include/core/SkFlattenable.h b/gfx/skia/skia/include/core/SkFlattenable.h index bccabc18fa8..10cba1a2ec2 100644 --- a/gfx/skia/skia/include/core/SkFlattenable.h +++ b/gfx/skia/skia/include/core/SkFlattenable.h @@ -49,7 +49,7 @@ class SkPrivateEffectInitializer; #define SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(flattenable) \ private: \ static SkFlattenable* CreateProc(SkReadBuffer&); \ - friend class ::SkPrivateEffectInitializer; \ + friend class SkFlattenable::PrivateInitializer; \ public: \ Factory getFactory() const override { return CreateProc; } @@ -108,6 +108,13 @@ public: */ virtual void flatten(SkWriteBuffer&) const {} +protected: + class PrivateInitializer { + public: + static void InitCore(); + static void InitEffects(); + }; + private: static void InitializeFlattenablesIfNeeded(); diff --git a/gfx/skia/skia/include/core/SkImage.h b/gfx/skia/skia/include/core/SkImage.h index d6b10a8e186..62a9e9cf426 100644 --- a/gfx/skia/skia/include/core/SkImage.h +++ b/gfx/skia/skia/include/core/SkImage.h @@ -267,7 +267,7 @@ public: * attempt to reuse existing encoded data (as returned by refEncoded). * * We defer to the SkPixelSerializer both for vetting existing encoded data - * (useEncodedData) and for encoding the image (encodePixels) when no such data is + * (useEncodedData) and for encoding the image (encode) when no such data is * present or is rejected by the serializer. * * If not specified, we use a default serializer which 1) always accepts existing data @@ -324,28 +324,6 @@ public: */ bool isLazyGenerated() const; - /** - * Apply the specified filter to this image, and return the result as a new image. - * - * if forceResultToOriginalSize is true, then the resulting image will be the same size as the - * src, regardless of the normal output of the filter. - * - * If offset is non-null, it is set to the relative offset needed to draw the resulting image - * in the same logical place as the original. - * - * e.g. - * If the filter makes the result larger by a margin of 4 the output would be: - * result->width() == this->width + 8 - * result->height() == this->height + 8 - * offset.x() == -4 - * offset.y() == -4 - * - * If the filter fails to create a resulting image, null is returned, and the offset parameter - * (if specified) will be undefined. - */ - SkImage* applyFilter(SkImageFilter* filter, SkIPoint* offset, - bool forceResultToOriginalSize) const; - protected: SkImage(int width, int height, uint32_t uniqueID); diff --git a/gfx/skia/skia/include/core/SkImageDecoder.h b/gfx/skia/skia/include/core/SkImageDecoder.h index 30323b59ee5..5060a1e599d 100644 --- a/gfx/skia/skia/include/core/SkImageDecoder.h +++ b/gfx/skia/skia/include/core/SkImageDecoder.h @@ -16,8 +16,6 @@ #include "SkTRegistry.h" #include "SkTypes.h" -//#define SK_LEGACY_PEEKER - class SkStream; class SkStreamRewindable; @@ -129,18 +127,6 @@ public: */ bool getRequireUnpremultipliedColors() const { return fRequireUnpremultipliedColors; } -#ifdef SK_LEGACY_PEEKER - // Android subclasses SkImageDecoder::Peeker, which has been changed into SkPngChunkReader. - // Temporarily use this class until Android can be updated to directly inherit from - // SkPngChunkReader. - class Peeker : public SkPngChunkReader { - public: - bool readChunk(const char tag[], const void* data, size_t length) final { - return this->peek(tag, data, length); - } - virtual bool peek(const char tag[], const void* data, size_t length) = 0; - }; -#endif SkPngChunkReader* getPeeker() const { return fPeeker; } SkPngChunkReader* setPeeker(SkPngChunkReader*); diff --git a/gfx/skia/skia/include/core/SkImageEncoder.h b/gfx/skia/skia/include/core/SkImageEncoder.h index fc999dcc189..bb3341f836e 100644 --- a/gfx/skia/skia/include/core/SkImageEncoder.h +++ b/gfx/skia/skia/include/core/SkImageEncoder.h @@ -12,6 +12,8 @@ #include "SkTRegistry.h" class SkBitmap; +class SkPixelSerializer; +class SkPixmap; class SkData; class SkWStream; @@ -64,11 +66,17 @@ public: Type, int quality); static SkData* EncodeData(const SkBitmap&, Type, int quality); + static SkData* EncodeData(const SkPixmap&, Type, int quality); + static bool EncodeFile(const char file[], const SkBitmap&, Type, int quality); static bool EncodeStream(SkWStream*, const SkBitmap&, Type, int quality); + /** Uses SkImageEncoder to serialize images that are not already + encoded as SkImageEncoder::kPNG_Type images. */ + static SkPixelSerializer* CreatePixelSerializer(); + protected: /** * Encode bitmap 'bm' in the desired format, writing results to diff --git a/gfx/skia/skia/include/core/SkImageFilter.h b/gfx/skia/skia/include/core/SkImageFilter.h index d90df29c8bf..8153bacb793 100644 --- a/gfx/skia/skia/include/core/SkImageFilter.h +++ b/gfx/skia/skia/include/core/SkImageFilter.h @@ -42,33 +42,25 @@ public: virtual bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const = 0; virtual void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) = 0; virtual void purge() {} - }; - - enum SizeConstraint { - kExact_SizeConstraint, - kApprox_SizeConstraint, + virtual void purgeByImageFilterId(uint32_t) {} }; class Context { public: - Context(const SkMatrix& ctm, const SkIRect& clipBounds, Cache* cache, - SizeConstraint constraint) + Context(const SkMatrix& ctm, const SkIRect& clipBounds, Cache* cache) : fCTM(ctm) , fClipBounds(clipBounds) , fCache(cache) - , fSizeConstraint(constraint) {} const SkMatrix& ctm() const { return fCTM; } const SkIRect& clipBounds() const { return fClipBounds; } Cache* cache() const { return fCache; } - SizeConstraint sizeConstraint() const { return fSizeConstraint; } private: SkMatrix fCTM; SkIRect fClipBounds; Cache* fCache; - SizeConstraint fSizeConstraint; }; class CropRect { @@ -106,11 +98,17 @@ public: uint32_t fFlags; }; + enum TileUsage { + kPossible_TileUsage, //!< the created device may be drawn tiled + kNever_TileUsage, //!< the created device will never be drawn tiled + }; + class Proxy { public: virtual ~Proxy() {} - virtual SkBaseDevice* createDevice(int width, int height) = 0; + virtual SkBaseDevice* createDevice(int width, int height, + TileUsage usage = kNever_TileUsage) = 0; // Returns true if the proxy handled the filter itself. If this returns // false then the filter's code will be called. @@ -123,7 +121,8 @@ public: public: DeviceProxy(SkBaseDevice* device) : fDevice(device) {} - SkBaseDevice* createDevice(int width, int height) override; + SkBaseDevice* createDevice(int width, int height, + TileUsage usage = kNever_TileUsage) override; // Returns true if the proxy handled the filter itself. If this returns // false then the filter's code will be called. @@ -199,12 +198,7 @@ public: * replaced by the returned colorfilter. i.e. the two effects will affect drawing in the * same way. */ - bool asAColorFilter(SkColorFilter** filterPtr) const { - return this->countInputs() > 0 && - NULL == this->getInput(0) && - !this->affectsTransparentBlack() && - this->isColorFilterNode(filterPtr); - } + bool asAColorFilter(SkColorFilter** filterPtr) const; /** * Returns the number of inputs this filter will accept (some inputs can @@ -240,7 +234,7 @@ public: virtual void computeFastBounds(const SkRect&, SkRect*) const; // Can this filter DAG compute the resulting bounds of an object-space rectangle? - bool canComputeFastBounds() const; + virtual bool canComputeFastBounds() const; /** * If this filter can be represented by another filter + a localMatrix, return that filter, @@ -256,11 +250,6 @@ public: SkImageFilter* input = NULL); #if SK_SUPPORT_GPU - /** - * Wrap the given texture in a texture-backed SkBitmap. - */ - static void WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result); - // Helper function which invokes GPU filter processing on the // input at the specified "index". If the input is null, it leaves // "result" and "offset" untouched, and returns true. If the input @@ -268,7 +257,7 @@ public: // Otherwise, the filter will be processed in software and // uploaded to the GPU. bool filterInputGPU(int index, SkImageFilter::Proxy* proxy, const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* offset, bool relaxSizeConstraint = true) const; + SkBitmap* result, SkIPoint* offset) const; #endif SK_TO_STRING_PUREVIRT() @@ -351,6 +340,25 @@ protected: // implementation recursively unions all input bounds, or returns false if // no inputs. virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const; + enum MapDirection { + kForward_MapDirection, + kReverse_MapDirection + }; + + /** + * Performs a forwards or reverse mapping of the given rect to accommodate + * this filter's margin requirements. kForward_MapDirection is used to + * determine the destination pixels which would be touched by filtering + * the given given source rect (e.g., given source bitmap bounds, + * determine the optimal bounds of the filtered offscreen bitmap). + * kReverse_MapDirection is used to determine which pixels of the + * input(s) would be required to fill the given destination rect + * (e.g., clip bounds). NOTE: these operations may not be the + * inverse of the other. For example, blurring expands the given rect + * in both forward and reverse directions. Unlike + * onFilterBounds(), this function is non-recursive. + */ + virtual void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const; // Helper function which invokes filter processing on the input at the // specified "index". If the input is null, it leaves "result" and @@ -358,7 +366,7 @@ protected: // calls filterImage() on that input, and returns true on success. // i.e., return !getInput(index) || getInput(index)->filterImage(...); bool filterInput(int index, Proxy*, const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* offset, bool relaxSizeConstraint = true) const; + SkBitmap* result, SkIPoint* offset) const; /** * Return true (and return a ref'd colorfilter) if this node in the DAG is just a @@ -411,12 +419,12 @@ protected: const SkIRect& bounds) const; /** - * Returns true if this filter can cause transparent black pixels to become - * visible (ie., alpha > 0). The default implementation returns false. This - * function is non-recursive, i.e., only queries this filter and not its - * inputs. + * Creates a modified Context for use when recursing up the image filter DAG. + * The clip bounds are adjusted to accommodate any margins that this + * filter requires by calling this node's + * onFilterNodeBounds(..., kReverse_MapDirection). */ - virtual bool affectsTransparentBlack() const; + Context mapContext(const Context& ctx) const; private: friend class SkGraphics; diff --git a/gfx/skia/skia/include/core/SkImageGenerator.h b/gfx/skia/skia/include/core/SkImageGenerator.h index 66db5e48842..86e3053a069 100644 --- a/gfx/skia/skia/include/core/SkImageGenerator.h +++ b/gfx/skia/skia/include/core/SkImageGenerator.h @@ -22,6 +22,12 @@ class SkMatrix; class SkPaint; class SkPicture; +#ifdef SK_SUPPORT_LEGACY_REFENCODEDDATA_NOCTX + #define SK_REFENCODEDDATA_CTXPARAM +#else + #define SK_REFENCODEDDATA_CTXPARAM GrContext* ctx +#endif + /** * Takes ownership of SkImageGenerator. If this method fails for * whatever reason, it will return false and immediatetely delete @@ -64,12 +70,20 @@ public: /** * Return a ref to the encoded (i.e. compressed) representation, - * of this data. + * of this data. If the GrContext is non-null, then the caller is only interested in + * gpu-specific formats, so the impl may return null even if they have encoded data, + * assuming they know it is not suitable for the gpu. * * If non-NULL is returned, the caller is responsible for calling * unref() on the data when it is finished. */ - SkData* refEncodedData() { return this->onRefEncodedData(); } + SkData* refEncodedData(GrContext* ctx = nullptr) { +#ifdef SK_SUPPORT_LEGACY_REFENCODEDDATA_NOCTX + return this->onRefEncodedData(); +#else + return this->onRefEncodedData(ctx); +#endif + } /** * Return the ImageInfo associated with this generator. @@ -230,7 +244,7 @@ public: protected: SkImageGenerator(const SkImageInfo& info); - virtual SkData* onRefEncodedData(); + virtual SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM); virtual bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount); diff --git a/gfx/skia/skia/include/core/SkMask.h b/gfx/skia/skia/include/core/SkMask.h index 7be6aff614c..a6d56064787 100644 --- a/gfx/skia/skia/include/core/SkMask.h +++ b/gfx/skia/skia/include/core/SkMask.h @@ -17,6 +17,8 @@ the 3-channel 3D format. These are passed to SkMaskFilter objects. */ struct SkMask { + SkMask() : fImage(nullptr) {} + enum Format { kBW_Format, //!< 1bit per pixel mask (e.g. monochrome) kA8_Format, //!< 8bits per pixel mask (e.g. antialiasing) diff --git a/gfx/skia/skia/include/core/SkMaskFilter.h b/gfx/skia/skia/include/core/SkMaskFilter.h index 1fe1d9adafc..8d3d1caa676 100644 --- a/gfx/skia/skia/include/core/SkMaskFilter.h +++ b/gfx/skia/skia/include/core/SkMaskFilter.h @@ -184,9 +184,7 @@ protected: class NinePatch : ::SkNoncopyable { public: - NinePatch() : fCache(NULL) { - fMask.fImage = NULL; - } + NinePatch() : fCache(nullptr) { } ~NinePatch(); SkMask fMask; // fBounds must have [0,0] in its top-left diff --git a/gfx/skia/skia/include/core/SkMatrix.h b/gfx/skia/skia/include/core/SkMatrix.h index 97a53505ef3..0ebe3280e21 100644 --- a/gfx/skia/skia/include/core/SkMatrix.h +++ b/gfx/skia/skia/include/core/SkMatrix.h @@ -635,15 +635,17 @@ public: /** * Calculates the minimum scaling factor of the matrix as computed from the SVD of the upper - * left 2x2. If the matrix has perspective -1 is returned. + * left 2x2. If the max scale factor cannot be computed (for example overflow or perspective) + * -1 is returned. * - * @return minumum scale factor + * @return minimum scale factor */ SkScalar getMinScale() const; /** * Calculates the maximum scaling factor of the matrix as computed from the SVD of the upper - * left 2x2. If the matrix has perspective -1 is returned. + * left 2x2. If the max scale factor cannot be computed (for example overflow or perspective) + * -1 is returned. * * @return maximum scale factor */ @@ -651,10 +653,10 @@ public: /** * Gets both the min and max scale factors. The min scale factor is scaleFactors[0] and the max - * is scaleFactors[1]. If the matrix has perspective false will be returned and scaleFactors - * will be unchanged. + * is scaleFactors[1]. If the min/max scale factors cannot be computed false is returned and the + * values of scaleFactors[] are undefined. */ - bool getMinMaxScales(SkScalar scaleFactors[2]) const; + bool SK_WARN_UNUSED_RESULT getMinMaxScales(SkScalar scaleFactors[2]) const; /** * Attempt to decompose this matrix into a scale-only component and whatever remains, where diff --git a/gfx/skia/skia/include/core/SkOSFile.h b/gfx/skia/skia/include/core/SkOSFile.h index 39a16464583..f977327e255 100644 --- a/gfx/skia/skia/include/core/SkOSFile.h +++ b/gfx/skia/skia/include/core/SkOSFile.h @@ -41,6 +41,7 @@ size_t sk_fwrite(const void* buffer, size_t byteCount, FILE*); char* sk_fgets(char* str, int size, FILE* f); void sk_fflush(FILE*); +void sk_fsync(FILE*); bool sk_fseek(FILE*, size_t); bool sk_fmove(FILE*, long); diff --git a/gfx/skia/skia/include/core/SkPaint.h b/gfx/skia/skia/include/core/SkPaint.h index 2090ed23377..51e8848a00b 100644 --- a/gfx/skia/skia/include/core/SkPaint.h +++ b/gfx/skia/skia/include/core/SkPaint.h @@ -631,13 +631,6 @@ public: SkAnnotation* getAnnotation() const { return fAnnotation; } SkAnnotation* setAnnotation(SkAnnotation*); - /** - * Returns true if there is an annotation installed on this paint, and - * the annotation specifics no-drawing. - */ - SK_ATTR_DEPRECATED("use getAnnotation and check for non-null") - bool isNoDrawAnnotation() const { return this->getAnnotation() != NULL; } - /** * Return the paint's SkDrawLooper (if any). Does not affect the looper's * reference count. @@ -1089,12 +1082,11 @@ private: friend class SkCanvas; friend class SkDraw; friend class SkPDFDevice; - friend class GrBitmapTextContext; + friend class GrAtlasTextBlob; friend class GrAtlasTextContext; - friend class GrDistanceFieldTextContext; friend class GrStencilAndCoverTextContext; friend class GrPathRendering; - friend class GrTextContext; + friend class GrTextUtils; friend class GrGLPathRendering; friend class SkScalerContext; friend class SkTextToPathIter; diff --git a/gfx/skia/skia/include/core/SkPath.h b/gfx/skia/skia/include/core/SkPath.h index 33db8ac2496..4ce816f92f1 100644 --- a/gfx/skia/skia/include/core/SkPath.h +++ b/gfx/skia/skia/include/core/SkPath.h @@ -956,6 +956,14 @@ public: return (Verb) fRawIter.next(pts); } + /** Return what the next verb will be, but do not visit the next segment. + + @return The verb for the next segment + */ + Verb peek() const { + return (Verb) fRawIter.peek(); + } + SkScalar conicWeight() const { return fRawIter.conicWeight(); } diff --git a/gfx/skia/skia/include/core/SkPathMeasure.h b/gfx/skia/skia/include/core/SkPathMeasure.h index f6e606f0c06..7528736ba85 100644 --- a/gfx/skia/skia/include/core/SkPathMeasure.h +++ b/gfx/skia/skia/include/core/SkPathMeasure.h @@ -89,8 +89,12 @@ private: struct Segment { SkScalar fDistance; // total distance up to this point - unsigned fPtIndex : 15; // index into the fPts array + unsigned fPtIndex; // index into the fPts array +#ifdef SK_SUPPORT_LEGACY_PATH_MEASURE_TVALUE unsigned fTValue : 15; +#else + unsigned fTValue : 30; +#endif unsigned fType : 2; SkScalar getScalarT() const; diff --git a/gfx/skia/skia/include/core/SkPathRef.h b/gfx/skia/skia/include/core/SkPathRef.h index 86f55c9bcae..6d0ec627e8a 100644 --- a/gfx/skia/skia/include/core/SkPathRef.h +++ b/gfx/skia/skia/include/core/SkPathRef.h @@ -124,6 +124,7 @@ public: @return The verb for the current segment */ uint8_t next(SkPoint pts[4]); + uint8_t peek() const; SkScalar conicWeight() const { return *fConicWeights; } diff --git a/gfx/skia/skia/include/core/SkPixelRef.h b/gfx/skia/skia/include/core/SkPixelRef.h index 4591ed82bff..9cdcd85a798 100644 --- a/gfx/skia/skia/include/core/SkPixelRef.h +++ b/gfx/skia/skia/include/core/SkPixelRef.h @@ -225,7 +225,8 @@ public: return this->onGetYUV8Planes(sizes, planes, rowBytes, colorSpace); } - bool readPixels(SkBitmap* dst, const SkIRect* subset = NULL); + /** Populates dst with the pixels of this pixelRef, converting them to colorType. */ + bool readPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subset = NULL); /** * Makes a deep copy of this PixelRef, respecting the requested config. @@ -299,7 +300,7 @@ protected: * * The base class implementation returns false; */ - virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subsetOrNull); + virtual bool onReadPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subsetOrNull); // default impl returns NULL. virtual SkData* onRefEncodedData(); diff --git a/gfx/skia/skia/include/core/SkPixelSerializer.h b/gfx/skia/skia/include/core/SkPixelSerializer.h index d0892099098..b168f79dd11 100644 --- a/gfx/skia/skia/include/core/SkPixelSerializer.h +++ b/gfx/skia/skia/include/core/SkPixelSerializer.h @@ -9,9 +9,9 @@ #define SkPixelSerializer_DEFINED #include "SkRefCnt.h" +#include "SkPixmap.h" class SkData; -struct SkImageInfo; /** * Interface for serializing pixels, e.g. SkBitmaps in an SkPicture. @@ -32,14 +32,12 @@ public: * Call to get the client's version of encoding these pixels. If it * returns NULL, serialize the raw pixels. */ - SkData* encodePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes) { - return this->onEncodePixels(info, pixels, rowBytes); - } + SkData* encode(const SkPixmap& pixmap) { return this->onEncode(pixmap); } protected: /** * Return true if you want to serialize the encoded data, false if you want - * another version serialized (e.g. the result of encodePixels). + * another version serialized (e.g. the result of this->encode()). */ virtual bool onUseEncodedData(const void* data, size_t len) = 0; @@ -47,6 +45,6 @@ protected: * If you want to encode these pixels, return the encoded data as an SkData * Return null if you want to serialize the raw pixels. */ - virtual SkData* onEncodePixels(const SkImageInfo&, const void* pixels, size_t rowBytes) = 0; + virtual SkData* onEncode(const SkPixmap&) = 0; }; #endif // SkPixelSerializer_DEFINED diff --git a/gfx/skia/skia/include/core/SkPostConfig.h b/gfx/skia/skia/include/core/SkPostConfig.h index 717230ea06c..387ea5b1547 100644 --- a/gfx/skia/skia/include/core/SkPostConfig.h +++ b/gfx/skia/skia/include/core/SkPostConfig.h @@ -300,14 +300,6 @@ # endif #endif -#if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 - #define SK_VECTORCALL __vectorcall -#elif defined(SK_CPU_ARM32) - #define SK_VECTORCALL __attribute__((pcs("aapcs-vfp"))) -#else - #define SK_VECTORCALL -#endif - ////////////////////////////////////////////////////////////////////// #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1 diff --git a/gfx/skia/skia/include/core/SkPreConfig.h b/gfx/skia/skia/include/core/SkPreConfig.h index a593d2ff8cf..c17cc18e117 100644 --- a/gfx/skia/skia/include/core/SkPreConfig.h +++ b/gfx/skia/skia/include/core/SkPreConfig.h @@ -30,7 +30,8 @@ #define SK_BUILD_FOR_ANDROID #elif defined(linux) || defined(__linux) || defined(__FreeBSD__) || \ defined(__OpenBSD__) || defined(__sun) || defined(__NetBSD__) || \ - defined(__DragonFly__) || defined(__GLIBC__) || defined(__GNU__) + defined(__DragonFly__) || defined(__GLIBC__) || defined(__GNU__) || \ + defined(__unix__) #define SK_BUILD_FOR_UNIX #elif TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR #define SK_BUILD_FOR_IOS diff --git a/gfx/skia/skia/include/core/SkRRect.h b/gfx/skia/skia/include/core/SkRRect.h index 8d8cdbf02c7..994edd2cc1c 100644 --- a/gfx/skia/skia/include/core/SkRRect.h +++ b/gfx/skia/skia/include/core/SkRRect.h @@ -153,6 +153,12 @@ public: return rr; } + static SkRRect MakeRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { + SkRRect rr; + rr.setRectXY(rect, xRad, yRad); + return rr; + } + /** * Set this RR to match the supplied oval. All x radii will equal half the * width and all y radii will equal half the height. diff --git a/gfx/skia/skia/include/core/SkRect.h b/gfx/skia/skia/include/core/SkRect.h index fe276e6710b..4f649b7c732 100644 --- a/gfx/skia/skia/include/core/SkRect.h +++ b/gfx/skia/skia/include/core/SkRect.h @@ -824,24 +824,6 @@ public: SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)); } - /** - * Variant of round() that explicitly performs the rounding step (i.e. floor(x + 0.5)) using - * double instead of SkScalar (float). It does this by calling SkDScalarRoundToInt(), which - * may be slower than calling SkScalarRountToInt(), but gives slightly more accurate results. - * - * e.g. - * SkScalar x = 0.49999997f; - * int ix = SkScalarRoundToInt(x); - * SkASSERT(0 == ix); // <--- fails - * ix = SkDScalarRoundToInt(x); - * SkASSERT(0 == ix); // <--- succeeds - */ - void dround(SkIRect* dst) const { - SkASSERT(dst); - dst->set(SkDScalarRoundToInt(fLeft), SkDScalarRoundToInt(fTop), - SkDScalarRoundToInt(fRight), SkDScalarRoundToInt(fBottom)); - } - /** * Set the dst rectangle by rounding "out" this rectangle, choosing the * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom. diff --git a/gfx/skia/skia/include/core/SkRefCnt.h b/gfx/skia/skia/include/core/SkRefCnt.h index 6c608ac9393..7590032968c 100644 --- a/gfx/skia/skia/include/core/SkRefCnt.h +++ b/gfx/skia/skia/include/core/SkRefCnt.h @@ -216,7 +216,7 @@ public: void unref() const { if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) { SkDEBUGCODE(fRefCnt = 1;) // restore the 1 for our destructor's assert - delete (const Derived*)this; + delete (const Derived*)this; } } void deref() const { this->unref(); } diff --git a/gfx/skia/skia/include/core/SkShader.h b/gfx/skia/skia/include/core/SkShader.h index 34cb648022c..60ef280d5ec 100644 --- a/gfx/skia/skia/include/core/SkShader.h +++ b/gfx/skia/skia/include/core/SkShader.h @@ -15,6 +15,7 @@ #include "SkPaint.h" #include "../gpu/GrColor.h" +class SkColorFilter; class SkPath; class SkPicture; class SkXfermode; @@ -72,31 +73,14 @@ public: enum Flags { //!< set if all of the colors will be opaque - kOpaqueAlpha_Flag = 0x01, - - //! set if this shader's shadeSpan16() method can be called - kHasSpan16_Flag = 0x02, - - /** Set this bit if the shader's native data type is instrinsically 16 - bit, meaning that calling the 32bit shadeSpan() entry point will - mean the the impl has to up-sample 16bit data into 32bit. Used as a - a means of clearing a dither request if the it will have no effect - */ - kIntrinsicly16_Flag = 0x04, + kOpaqueAlpha_Flag = 1 << 0, /** set if the spans only vary in X (const in Y). e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient that varies from left-to-right. This flag specifies this for shadeSpan(). */ - kConstInY32_Flag = 0x08, - - /** same as kConstInY32_Flag, but is set if this is true for shadeSpan16 - which may not always be the case, since shadeSpan16 may be - predithered, which would mean it was not const in Y, even though - the 32bit shadeSpan() would be const. - */ - kConstInY16_Flag = 0x10 + kConstInY32_Flag = 1 << 1, }; /** @@ -136,12 +120,6 @@ public: */ virtual uint32_t getFlags() const { return 0; } - /** - * Return the alpha associated with the data returned by shadeSpan16(). If - * kHasSpan16_Flag is not set, this value is meaningless. - */ - virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; } - /** * Called for each span of the object being drawn. Your subclass should * set the appropriate colors (with premultiplied alpha) that correspond @@ -149,14 +127,12 @@ public: */ virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0; - typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count); - virtual ShadeProc asAShadeProc(void** ctx); - /** - * Called only for 16bit devices when getFlags() returns - * kOpaqueAlphaFlag | kHasSpan16_Flag + * The const void* ctx is only const because all the implementations are const. + * This can be changed to non-const if a new shade proc needs to change the ctx. */ - virtual void shadeSpan16(int x, int y, uint16_t[], int count); + typedef void (*ShadeProc)(const void* ctx, int x, int y, SkPMColor[], int count); + virtual ShadeProc asAShadeProc(void** ctx); /** * Similar to shadeSpan, but only returns the alpha-channel for a span. @@ -165,14 +141,6 @@ public: */ virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count); - /** - * Helper function that returns true if this shader's shadeSpan16() method - * can be called. - */ - bool canCallShadeSpan16() { - return SkShader::CanCallShadeSpan16(this->getFlags()); - } - // Notification from blitter::blitMask in case we need to see the non-alpha channels virtual void set3DMask(const SkMask*) {} @@ -215,13 +183,6 @@ public: */ virtual size_t contextSize() const; - /** - * Helper to check the flags to know if it is legal to call shadeSpan16() - */ - static bool CanCallShadeSpan16(uint32_t flags) { - return (flags & kHasSpan16_Flag) != 0; - } - /** * Returns true if this shader is just a bitmap, and if not null, returns the bitmap, * localMatrix, and tilemodes. If this is not a bitmap, returns false and ignores the @@ -342,8 +303,23 @@ public: #endif ////////////////////////////////////////////////////////////////////////// - // Factory methods for stock shaders + // Methods to create combinations or variants of shaders + /** + * Return a shader that will apply the specified localMatrix to this shader. + * The specified matrix will be applied before any matrix associated with this shader. + */ + SkShader* newWithLocalMatrix(const SkMatrix&) const; + + /** + * Create a new shader that produces the same colors as invoking this shader and then applying + * the colorfilter. + */ + SkShader* newWithColorFilter(SkColorFilter*) const; + + ////////////////////////////////////////////////////////////////////////// + // Factory methods for stock shaders + /** * Call this to create a new "empty" shader, that will not draw anything. */ @@ -394,14 +370,6 @@ public: const SkMatrix* localMatrix, const SkRect* tile); - /** - * Return a shader that will apply the specified localMatrix to the proxy shader. - * The specified matrix will be applied before any matrix associated with the proxy. - * - * Note: ownership of the proxy is not transferred (though a ref is taken). - */ - static SkShader* CreateLocalMatrixShader(SkShader* proxy, const SkMatrix& localMatrix); - /** * If this shader can be represented by another shader + a localMatrix, return that shader * and, if not NULL, the localMatrix. If not, return NULL and ignore the localMatrix parameter. diff --git a/gfx/skia/skia/include/core/SkStream.h b/gfx/skia/skia/include/core/SkStream.h index 2279f9ff10e..4502416fd96 100644 --- a/gfx/skia/skia/include/core/SkStream.h +++ b/gfx/skia/skia/include/core/SkStream.h @@ -65,17 +65,18 @@ public: /** * Attempt to peek at size bytes. - * If this stream supports peeking, and it can peek size bytes, copy size - * bytes into buffer, and return true. - * If the stream does not support peeking, or cannot peek size bytes, - * return false and leave buffer unchanged. + * If this stream supports peeking, copy min(size, peekable bytes) into + * buffer, and return the number of bytes copied. + * If the stream does not support peeking, or cannot peek any bytes, + * return 0 and leave buffer unchanged. * The stream is guaranteed to be in the same visible state after this * call, regardless of success or failure. - * @param buffer Must not be NULL. Destination to copy bytes. + * @param buffer Must not be NULL, and must be at least size bytes. Destination + * to copy bytes. * @param size Number of bytes to copy. - * @return Whether the peek was performed. + * @return The number of bytes peeked/copied. */ - virtual bool peek(void* /* buffer */, size_t /* size */) const { return false; } + virtual size_t peek(void* /*buffer*/, size_t /*size*/) const { return 0; } /** Returns true when all the bytes in the stream have been read. * This may return true early (when there are no more bytes to be read) @@ -325,7 +326,7 @@ public: size_t read(void* buffer, size_t size) override; bool isAtEnd() const override; - bool peek(void* buffer, size_t size) const override; + size_t peek(void* buffer, size_t size) const override; bool rewind() override; SkMemoryStream* duplicate() const override; @@ -359,6 +360,7 @@ public: bool write(const void* buffer, size_t size) override; void flush() override; + void fsync(); size_t bytesWritten() const override; private: diff --git a/gfx/skia/skia/include/core/SkString.h b/gfx/skia/skia/include/core/SkString.h index 9229d808a63..93514f2659f 100644 --- a/gfx/skia/skia/include/core/SkString.h +++ b/gfx/skia/skia/include/core/SkString.h @@ -267,7 +267,22 @@ template <> inline void SkTSwap(SkString& a, SkString& b) { a.swap(b); } +enum SkStrSplitMode { + // Strictly return all results. If the input is ",," and the separator is ',' this will return + // an array of three empty strings. + kStrict_SkStrSplitMode, + + // Only nonempty results will be added to the results. Multiple separators will be + // coalesced. Separators at the beginning and end of the input will be ignored. If the input is + // ",," and the separator is ',', this will return an empty vector. + kCoalesce_SkStrSplitMode +}; + // Split str on any characters in delimiters into out. (Think, strtok with a sane API.) -void SkStrSplit(const char* str, const char* delimiters, SkTArray* out); +void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode, + SkTArray* out); +inline void SkStrSplit(const char* str, const char* delimiters, SkTArray* out) { + SkStrSplit(str, delimiters, kCoalesce_SkStrSplitMode, out); +} #endif diff --git a/gfx/skia/skia/include/core/SkTArray.h b/gfx/skia/skia/include/core/SkTArray.h index 401f7084d6e..17cbc5c05ce 100644 --- a/gfx/skia/skia/include/core/SkTArray.h +++ b/gfx/skia/skia/include/core/SkTArray.h @@ -12,6 +12,7 @@ #include "SkTypes.h" #include +#include template class SkTArray; @@ -23,11 +24,11 @@ inline void copy(SkTArray* self, int dst, int src) { } template inline void copy(SkTArray* self, const T* array) { - memcpy(self->fMemArray, array, self->fCount * sizeof(T)); + sk_careful_memcpy(self->fMemArray, array, self->fCount * sizeof(T)); } template inline void copyAndDelete(SkTArray* self, char* newMemArray) { - memcpy(newMemArray, self->fMemArray, self->fCount * sizeof(T)); + sk_careful_memcpy(newMemArray, self->fMemArray, self->fCount * sizeof(T)); } template @@ -198,7 +199,7 @@ public: */ template T& emplace_back(Args&&... args) { T* newT = reinterpret_cast(this->push_back_raw(1)); - return *new (newT) T(skstd::forward(args)...); + return *new (newT) T(std::forward(args)...); } /** diff --git a/gfx/skia/skia/include/core/SkTDArray.h b/gfx/skia/skia/include/core/SkTDArray.h index 26c6c7f8956..b5332a2cc4a 100644 --- a/gfx/skia/skia/include/core/SkTDArray.h +++ b/gfx/skia/skia/include/core/SkTDArray.h @@ -45,7 +45,7 @@ public: SkTDArray tmp(src.fArray, src.fCount); this->swap(tmp); } else { - memcpy(fArray, src.fArray, sizeof(T) * src.fCount); + sk_careful_memcpy(fArray, src.fArray, sizeof(T) * src.fCount); fCount = src.fCount; } } diff --git a/gfx/skia/skia/include/core/SkTLazy.h b/gfx/skia/skia/include/core/SkTLazy.h index 60d816147f7..8032538c449 100644 --- a/gfx/skia/skia/include/core/SkTLazy.h +++ b/gfx/skia/skia/include/core/SkTLazy.h @@ -11,6 +11,7 @@ #include "../private/SkTemplates.h" #include "SkTypes.h" #include +#include /** * Efficient way to defer allocating/initializing a class until it is needed @@ -50,7 +51,7 @@ public: if (this->isValid()) { fPtr->~T(); } - fPtr = new (SkTCast(fStorage.get())) T(skstd::forward(args)...); + fPtr = new (SkTCast(fStorage.get())) T(std::forward(args)...); return fPtr; } @@ -130,6 +131,8 @@ class SkTCopyOnFirstWrite { public: SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {} + SkTCopyOnFirstWrite(const T* initial) : fObj(initial) {} + // Constructor for delayed initialization. SkTCopyOnFirstWrite() : fObj(NULL) {} diff --git a/gfx/skia/skia/include/core/SkTime.h b/gfx/skia/skia/include/core/SkTime.h index 2cfe3efcb45..3ff29aa25e1 100644 --- a/gfx/skia/skia/include/core/SkTime.h +++ b/gfx/skia/skia/include/core/SkTime.h @@ -38,10 +38,6 @@ public: static double GetNSecs(); }; -#if defined(SK_DEBUG) && defined(SK_BUILD_FOR_WIN32) - extern SkMSec gForceTickCount; -#endif - #define SK_TIME_FACTOR 1 /////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/include/core/SkTypes.h b/gfx/skia/skia/include/core/SkTypes.h index 5720c30970e..89708219947 100644 --- a/gfx/skia/skia/include/core/SkTypes.h +++ b/gfx/skia/skia/include/core/SkTypes.h @@ -24,6 +24,28 @@ #include +/** + * sk_careful_memcpy() is just like memcpy(), but guards against undefined behavior. + * + * It is undefined behavior to call memcpy() with null dst or src, even if len is 0. + * If an optimizer is "smart" enough, it can exploit this to do unexpected things. + * memcpy(dst, src, 0); + * if (src) { + * printf("%x\n", *src); + * } + * In this code the compiler can assume src is not null and omit the if (src) {...} check, + * unconditionally running the printf, crashing the program if src really is null. + * Of the compilers we pay attention to only GCC performs this optimization in practice. + */ +static inline void* sk_careful_memcpy(void* dst, const void* src, size_t len) { + // When we pass >0 len we had better already be passing valid pointers. + // So we just need to skip calling memcpy when len == 0. + if (len) { + memcpy(dst,src,len); + } + return dst; +} + /** \file SkTypes.h */ @@ -78,7 +100,10 @@ SK_API extern void* sk_calloc_throw(size_t size); // bzero is safer than memset, but we can't rely on it, so... sk_bzero() static inline void sk_bzero(void* buffer, size_t size) { - memset(buffer, 0, size); + // Please c.f. sk_careful_memcpy. It's undefined behavior to call memset(null, 0, 0). + if (size) { + memset(buffer, 0, size); + } } /////////////////////////////////////////////////////////////////////////////// @@ -222,12 +247,6 @@ typedef int S16CPU; */ typedef unsigned U16CPU; -/** - * Meant to be faster than bool (doesn't promise to be 0 or 1, - * just 0 or non-zero - */ -typedef int SkBool; - /** * Meant to be a small version of bool, for storage purposes. Will be 0 or 1 */ @@ -257,7 +276,7 @@ typedef uint8_t SkBool8; /** Returns 0 or 1 based on the condition */ -#define SkToBool(cond) ((cond) != 0) +#define SkToBool(cond) (!!(cond)) #define SK_MaxS16 32767 #define SK_MinS16 -32767 @@ -281,6 +300,14 @@ static inline bool SkIsU16(long x) { return (uint16_t)x == x; } +static inline int32_t SkLeftShift(int32_t value, int32_t shift) { + return (int32_t) ((uint32_t) value << shift); +} + +static inline int64_t SkLeftShift(int64_t value, int32_t shift) { + return (int64_t) ((uint64_t) value << shift); +} + ////////////////////////////////////////////////////////////////////////////// /** Returns the number of entries in an array (not a pointer) */ @@ -408,17 +435,6 @@ template static inline const T& SkTPin(const T& value, const T& min return SkTMax(SkTMin(value, max), min); } -static inline uint32_t SkSetClearShift(uint32_t bits, bool cond, - unsigned shift) { - SkASSERT((int)cond == 0 || (int)cond == 1); - return (bits & ~(1 << shift)) | ((int)cond << shift); -} - -static inline uint32_t SkSetClearMask(uint32_t bits, bool cond, - uint32_t mask) { - return cond ? bits | mask : bits & ~mask; -} - /////////////////////////////////////////////////////////////////////////////// /** Use to combine multiple bits in a bitmask in a type safe way. diff --git a/gfx/skia/skia/include/core/SkWriter32.h b/gfx/skia/skia/include/core/SkWriter32.h index 86c27a58dcc..1e7ec6d3483 100644 --- a/gfx/skia/skia/include/core/SkWriter32.h +++ b/gfx/skia/skia/include/core/SkWriter32.h @@ -165,7 +165,7 @@ public: */ void write(const void* values, size_t size) { SkASSERT(SkAlign4(size) == size); - memcpy(this->reserve(size), values, size); + sk_careful_memcpy(this->reserve(size), values, size); } /** @@ -186,7 +186,7 @@ public: * Write size bytes from src, and pad to 4 byte alignment with zeroes. */ void writePad(const void* src, size_t size) { - memcpy(this->reservePad(size), src, size); + sk_careful_memcpy(this->reservePad(size), src, size); } /** diff --git a/gfx/skia/skia/include/effects/Sk1DPathEffect.h b/gfx/skia/skia/include/effects/Sk1DPathEffect.h index 6a7804f1119..3419dc23b74 100644 --- a/gfx/skia/skia/include/effects/Sk1DPathEffect.h +++ b/gfx/skia/skia/include/effects/Sk1DPathEffect.h @@ -56,8 +56,7 @@ public: @param style how to transform path at each point (based on the current position and tangent) */ - static SkPath1DPathEffect* Create(const SkPath& path, SkScalar advance, SkScalar phase, - Style style) { + static SkPathEffect* Create(const SkPath& path, SkScalar advance, SkScalar phase, Style style) { return new SkPath1DPathEffect(path, advance, phase, style); } diff --git a/gfx/skia/skia/include/effects/Sk2DPathEffect.h b/gfx/skia/skia/include/effects/Sk2DPathEffect.h index fa12dcf0954..73da83c4b96 100644 --- a/gfx/skia/skia/include/effects/Sk2DPathEffect.h +++ b/gfx/skia/skia/include/effects/Sk2DPathEffect.h @@ -55,7 +55,7 @@ private: class SK_API SkLine2DPathEffect : public Sk2DPathEffect { public: - static SkLine2DPathEffect* Create(SkScalar width, const SkMatrix& matrix) { + static SkPathEffect* Create(SkScalar width, const SkMatrix& matrix) { return new SkLine2DPathEffect(width, matrix); } @@ -84,7 +84,7 @@ public: * Stamp the specified path to fill the shape, using the matrix to define * the latice. */ - static SkPath2DPathEffect* Create(const SkMatrix& matrix, const SkPath& path) { + static SkPathEffect* Create(const SkMatrix& matrix, const SkPath& path) { return new SkPath2DPathEffect(matrix, path); } diff --git a/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h b/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h index f409ee08c46..17521b6455d 100644 --- a/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h +++ b/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h @@ -22,6 +22,7 @@ public: */ static SkImageFilter* Create(const SkRegion& region, SkScalar innerThreshold, SkScalar outerThreshold, SkImageFilter* input = NULL); + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP(); }; #endif diff --git a/gfx/skia/skia/include/effects/SkBlurDrawLooper.h b/gfx/skia/skia/include/effects/SkBlurDrawLooper.h index 808557b9da7..930af15ff8f 100644 --- a/gfx/skia/skia/include/effects/SkBlurDrawLooper.h +++ b/gfx/skia/skia/include/effects/SkBlurDrawLooper.h @@ -35,8 +35,8 @@ public: kAll_BlurFlag = 0x07 }; - static SkBlurDrawLooper* Create(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy, - uint32_t flags = kNone_BlurFlag) { + static SkDrawLooper* Create(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy, + uint32_t flags = kNone_BlurFlag) { return new SkBlurDrawLooper(color, sigma, dx, dy, flags); } diff --git a/gfx/skia/skia/include/effects/SkBlurImageFilter.h b/gfx/skia/skia/include/effects/SkBlurImageFilter.h index c7193a435f0..5ae013d78e7 100644 --- a/gfx/skia/skia/include/effects/SkBlurImageFilter.h +++ b/gfx/skia/skia/include/effects/SkBlurImageFilter.h @@ -15,6 +15,9 @@ class SK_API SkBlurImageFilter : public SkImageFilter { public: static SkImageFilter* Create(SkScalar sigmaX, SkScalar sigmaY, SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { + if (0 == sigmaX && 0 == sigmaY && nullptr == cropRect) { + return SkSafeRef(input); + } return new SkBlurImageFilter(sigmaX, sigmaY, input, cropRect); } @@ -27,7 +30,8 @@ protected: void flatten(SkWriteBuffer&) const override; bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result, SkIPoint* offset) const override; - bool onFilterBounds(const SkIRect& src, const SkMatrix&, SkIRect* dst) const override; + void onFilterNodeBounds(const SkIRect& src, const SkMatrix&, + SkIRect* dst, MapDirection) const override; bool canFilterImageGPU() const override { return true; } bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const override; diff --git a/gfx/skia/skia/include/effects/SkColorCubeFilter.h b/gfx/skia/skia/include/effects/SkColorCubeFilter.h index f4a0c9009d0..a8a5e329dea 100644 --- a/gfx/skia/skia/include/effects/SkColorCubeFilter.h +++ b/gfx/skia/skia/include/effects/SkColorCubeFilter.h @@ -11,6 +11,7 @@ #include "SkColorFilter.h" #include "SkData.h" #include "../private/SkMutex.h" +#include "../private/SkTemplates.h" class SK_API SkColorCubeFilter : public SkColorFilter { public: @@ -55,7 +56,7 @@ private: SkScalar* fColorToFactors[2]; SkScalar* fColorToScalar; - SkAutoMalloc fLutStorage; + SkAutoTMalloc fLutStorage; const int fCubeDimension; diff --git a/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h b/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h index 200ec865001..db5d842c2fa 100644 --- a/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h +++ b/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h @@ -25,7 +25,7 @@ protected: bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result, SkIPoint* loc) const override; bool onIsColorFilterNode(SkColorFilter**) const override; - bool affectsTransparentBlack() const override; + bool canComputeFastBounds() const override; private: SkColorFilterImageFilter(SkColorFilter* cf, diff --git a/gfx/skia/skia/include/effects/SkColorMatrixFilter.h b/gfx/skia/skia/include/effects/SkColorMatrixFilter.h index bd2b939a434..7ffbf117cb2 100644 --- a/gfx/skia/skia/include/effects/SkColorMatrixFilter.h +++ b/gfx/skia/skia/include/effects/SkColorMatrixFilter.h @@ -13,13 +13,21 @@ class SK_API SkColorMatrixFilter : public SkColorFilter { public: - static SkColorMatrixFilter* Create(const SkColorMatrix& cm) { + static SkColorFilter* Create(const SkColorMatrix& cm) { return new SkColorMatrixFilter(cm); } - static SkColorMatrixFilter* Create(const SkScalar array[20]) { + static SkColorFilter* Create(const SkScalar array[20]) { return new SkColorMatrixFilter(array); } + /** + * Create a colorfilter that multiplies the RGB channels by one color, and + * then adds a second color, pinning the result for each component to + * [0..255]. The alpha components of the mul and add arguments + * are ignored. + */ + static SkColorFilter* CreateLightingFilter(SkColor mul, SkColor add); + void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override; uint32_t getFlags() const override; bool asColorMatrix(SkScalar matrix[20]) const override; @@ -29,11 +37,6 @@ public: const GrFragmentProcessor* asFragmentProcessor(GrContext*) const override; #endif - struct State { - int32_t fArray[20]; - int fShift; - }; - SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorMatrixFilter) @@ -46,13 +49,7 @@ protected: private: SkColorMatrix fMatrix; float fTranspose[SkColorMatrix::kCount]; // for Sk4s - - typedef void (*Proc)(const State&, unsigned r, unsigned g, unsigned b, - unsigned a, int32_t result[4]); - - Proc fProc; - State fState; - uint32_t fFlags; + uint32_t fFlags; void initState(const SkScalar array[20]); diff --git a/gfx/skia/skia/include/effects/SkCornerPathEffect.h b/gfx/skia/skia/include/effects/SkCornerPathEffect.h index 4c8908575db..13095f0e6c4 100644 --- a/gfx/skia/skia/include/effects/SkCornerPathEffect.h +++ b/gfx/skia/skia/include/effects/SkCornerPathEffect.h @@ -20,8 +20,7 @@ public: /** radius must be > 0 to have an effect. It specifies the distance from each corner that should be "rounded". */ - static SkCornerPathEffect* Create(SkScalar radius) { return new SkCornerPathEffect(radius); } - virtual ~SkCornerPathEffect(); + static SkPathEffect* Create(SkScalar radius) { return new SkCornerPathEffect(radius); } virtual bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override; @@ -34,6 +33,8 @@ public: #endif protected: + virtual ~SkCornerPathEffect(); + explicit SkCornerPathEffect(SkScalar radius); void flatten(SkWriteBuffer&) const override; diff --git a/gfx/skia/skia/include/effects/SkDashPathEffect.h b/gfx/skia/skia/include/effects/SkDashPathEffect.h index d3adeed99a6..3c1407b7257 100644 --- a/gfx/skia/skia/include/effects/SkDashPathEffect.h +++ b/gfx/skia/skia/include/effects/SkDashPathEffect.h @@ -36,8 +36,7 @@ public: Note: only affects stroked paths. */ - static SkDashPathEffect* Create(const SkScalar intervals[], int count, - SkScalar phase) { + static SkPathEffect* Create(const SkScalar intervals[], int count, SkScalar phase) { return new SkDashPathEffect(intervals, count, phase); } virtual ~SkDashPathEffect(); diff --git a/gfx/skia/skia/include/effects/SkDiscretePathEffect.h b/gfx/skia/skia/include/effects/SkDiscretePathEffect.h index b55dca86444..a49e2d89a7c 100644 --- a/gfx/skia/skia/include/effects/SkDiscretePathEffect.h +++ b/gfx/skia/skia/include/effects/SkDiscretePathEffect.h @@ -29,9 +29,7 @@ public: they can pass in a different seedAssist to get a different set of path segments. */ - static SkDiscretePathEffect* Create(SkScalar segLength, - SkScalar deviation, - uint32_t seedAssist=0) { + static SkPathEffect* Create(SkScalar segLength, SkScalar deviation, uint32_t seedAssist = 0) { return new SkDiscretePathEffect(segLength, deviation, seedAssist); } diff --git a/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h b/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h index 9513a54f15c..e94461795bd 100644 --- a/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h +++ b/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h @@ -23,11 +23,11 @@ public: ~SkDisplacementMapEffect(); - static SkDisplacementMapEffect* Create(ChannelSelectorType xChannelSelector, - ChannelSelectorType yChannelSelector, - SkScalar scale, SkImageFilter* displacement, - SkImageFilter* color = NULL, - const CropRect* cropRect = NULL); + static SkImageFilter* Create(ChannelSelectorType xChannelSelector, + ChannelSelectorType yChannelSelector, + SkScalar scale, SkImageFilter* displacement, + SkImageFilter* color = NULL, + const CropRect* cropRect = NULL); SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDisplacementMapEffect) @@ -40,6 +40,7 @@ public: virtual bool onFilterBounds(const SkIRect& src, const SkMatrix&, SkIRect* dst) const override; + void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const override; #if SK_SUPPORT_GPU bool canFilterImageGPU() const override { return true; } diff --git a/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h b/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h index bf4425e925f..bff1a420137 100644 --- a/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h +++ b/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h @@ -35,7 +35,8 @@ protected: void flatten(SkWriteBuffer&) const override; bool onFilterImage(Proxy*, const SkBitmap& source, const Context&, SkBitmap* result, SkIPoint* loc) const override; - bool onFilterBounds(const SkIRect& src, const SkMatrix&, SkIRect* dst) const override; + void onFilterNodeBounds(const SkIRect& src, const SkMatrix&, + SkIRect* dst, MapDirection) const override; private: SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor, diff --git a/gfx/skia/skia/include/effects/SkEmbossMaskFilter.h b/gfx/skia/skia/include/effects/SkEmbossMaskFilter.h index 41dfa2a66c4..72020bf3ce7 100644 --- a/gfx/skia/skia/include/effects/SkEmbossMaskFilter.h +++ b/gfx/skia/skia/include/effects/SkEmbossMaskFilter.h @@ -23,14 +23,14 @@ public: uint8_t fSpecular; // exponent, 4.4 right now }; - static SkEmbossMaskFilter* Create(SkScalar blurSigma, const Light& light); + static SkMaskFilter* Create(SkScalar blurSigma, const Light& light); // overrides from SkMaskFilter // This method is not exported to java. SkMask::Format getFormat() const override; // This method is not exported to java. - virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, - SkIPoint* margin) const override; + bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, + SkIPoint* margin) const override; SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkEmbossMaskFilter) diff --git a/gfx/skia/skia/include/effects/SkLightingImageFilter.h b/gfx/skia/skia/include/effects/SkLightingImageFilter.h index fb356c52e43..33cfceccb24 100644 --- a/gfx/skia/skia/include/effects/SkLightingImageFilter.h +++ b/gfx/skia/skia/include/effects/SkLightingImageFilter.h @@ -49,7 +49,7 @@ protected: void flatten(SkWriteBuffer&) const override; const SkImageFilterLight* light() const { return fLight.get(); } SkScalar surfaceScale() const { return fSurfaceScale; } - bool affectsTransparentBlack() const override { return true; } + bool canComputeFastBounds() const override { return false; } private: typedef SkImageFilter INHERITED; diff --git a/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h b/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h index 76349f430c1..7a2026c86b4 100644 --- a/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h +++ b/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h @@ -52,15 +52,15 @@ public: passed to filterImage() is used instead. @param cropRect The rectangle to which the output processing will be limited. */ - static SkMatrixConvolutionImageFilter* Create(const SkISize& kernelSize, - const SkScalar* kernel, - SkScalar gain, - SkScalar bias, - const SkIPoint& kernelOffset, - TileMode tileMode, - bool convolveAlpha, - SkImageFilter* input = NULL, - const CropRect* cropRect = NULL); + static SkImageFilter* Create(const SkISize& kernelSize, + const SkScalar* kernel, + SkScalar gain, + SkScalar bias, + const SkIPoint& kernelOffset, + TileMode tileMode, + bool convolveAlpha, + SkImageFilter* input = NULL, + const CropRect* cropRect = NULL); SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMatrixConvolutionImageFilter) @@ -79,8 +79,8 @@ protected: bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result, SkIPoint* loc) const override; - bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const override; - + void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const override; + bool canComputeFastBounds() const override; #if SK_SUPPORT_GPU bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&, diff --git a/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h b/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h index 29728fd9f7c..422bc019437 100644 --- a/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h +++ b/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h @@ -16,7 +16,8 @@ class SK_API SkMorphologyImageFilter : public SkImageFilter { public: void computeFastBounds(const SkRect& src, SkRect* dst) const override; - bool onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const override; + void onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst, MapDirection) const override; /** * All morphology procs have the same signature: src is the source buffer, dst the diff --git a/gfx/skia/skia/include/effects/SkOffsetImageFilter.h b/gfx/skia/skia/include/effects/SkOffsetImageFilter.h index 40f2ce33747..66b5515b376 100644 --- a/gfx/skia/skia/include/effects/SkOffsetImageFilter.h +++ b/gfx/skia/skia/include/effects/SkOffsetImageFilter.h @@ -30,7 +30,7 @@ protected: void flatten(SkWriteBuffer&) const override; bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result, SkIPoint* loc) const override; - bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const override; + void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const override; private: SkOffsetImageFilter(SkScalar dx, SkScalar dy, SkImageFilter* input, const CropRect*); diff --git a/gfx/skia/skia/include/effects/SkPaintImageFilter.h b/gfx/skia/skia/include/effects/SkPaintImageFilter.h new file mode 100644 index 00000000000..eee3630f310 --- /dev/null +++ b/gfx/skia/skia/include/effects/SkPaintImageFilter.h @@ -0,0 +1,45 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPaintImageFilter_DEFINED +#define SkPaintImageFilter_DEFINED + +#include "SkImageFilter.h" +#include "SkPaint.h" + +class SK_API SkPaintImageFilter : public SkImageFilter { +public: + /** Create a new image filter which fills the given rectangle using the + * given paint. If no rectangle is specified, an output is produced with + * the same bounds as the input primitive (even though the input + * primitive's pixels are not used for processing). + * @param paint Paint to use when filling the rect. + * @param rect Rectangle of output pixels. If NULL or a given crop edge is + * not specified, the source primitive's bounds are used + * instead. + */ + static SkImageFilter* Create(const SkPaint& paint, const CropRect* rect = NULL); + + bool canComputeFastBounds() const override; + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPaintImageFilter) + +protected: + void flatten(SkWriteBuffer&) const override; + bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result, + SkIPoint* loc) const override; + +private: + SkPaintImageFilter(const SkPaint& paint, const CropRect* rect); + + SkPaint fPaint; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h b/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h index 0cb1b47a9f4..ec7c08c8ea3 100644 --- a/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h +++ b/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h @@ -80,7 +80,6 @@ public: virtual ~PerlinNoiseShaderContext(); void shadeSpan(int x, int y, SkPMColor[], int count) override; - void shadeSpan16(int x, int y, uint16_t[], int count) override; private: SkPMColor shade(const SkPoint& point, StitchData& stitchData) const; diff --git a/gfx/skia/skia/include/effects/SkRectShaderImageFilter.h b/gfx/skia/skia/include/effects/SkRectShaderImageFilter.h deleted file mode 100644 index 9798af2d647..00000000000 --- a/gfx/skia/skia/include/effects/SkRectShaderImageFilter.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkRectShaderImageFilter_DEFINED -#define SkRectShaderImageFilter_DEFINED - -#include "SkImageFilter.h" -#include "SkRect.h" - -class SkShader; - -class SK_API SkRectShaderImageFilter : public SkImageFilter { -public: - /** Create a new image filter which fills the given rectangle with pixels - * produced by the given SkShader. If no rectangle is specified, an output - * is produced with the same bounds as the input primitive (even though - * the input primitive's pixels are not used for processing). - * @param s Shader to call for processing. Cannot be NULL. Will be - * ref'ed by the new image filter. - * @param rect Rectangle of output pixels in which to apply the shader. - * If NULL or a given crop edge is not specified, the source - * primitive's bounds are used instead. - */ - SK_ATTR_DEPRECATED("use Create(SkShader*, const CropRect*)") - static SkImageFilter* Create(SkShader* s, const SkRect& rect); - static SkImageFilter* Create(SkShader* s, const CropRect* rect = NULL); - - bool affectsTransparentBlack() const override; - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkRectShaderImageFilter) - -protected: - virtual ~SkRectShaderImageFilter(); - - void flatten(SkWriteBuffer&) const override; - bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result, - SkIPoint* loc) const override; - -private: - SkRectShaderImageFilter(SkShader* s, const CropRect* rect); - - SkShader* fShader; - - typedef SkImageFilter INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/effects/SkTileImageFilter.h b/gfx/skia/skia/include/effects/SkTileImageFilter.h index a2a1bb0fe13..ea75a3ec7f3 100644 --- a/gfx/skia/skia/include/effects/SkTileImageFilter.h +++ b/gfx/skia/skia/include/effects/SkTileImageFilter.h @@ -25,6 +25,7 @@ public: SkBitmap* dst, SkIPoint* offset) const override; bool onFilterBounds(const SkIRect& src, const SkMatrix&, SkIRect* dst) const override; + void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const override; void computeFastBounds(const SkRect& src, SkRect* dst) const override; SK_TO_STRING_OVERRIDE() diff --git a/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h b/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h index 57fd288f24f..d59b7a2b257 100644 --- a/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h +++ b/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h @@ -23,9 +23,9 @@ class SK_API SkXfermodeImageFilter : public SkImageFilter { public: virtual ~SkXfermodeImageFilter(); - static SkXfermodeImageFilter* Create(SkXfermode* mode, SkImageFilter* background, - SkImageFilter* foreground = NULL, - const CropRect* cropRect = NULL) { + static SkImageFilter* Create(SkXfermode* mode, SkImageFilter* background, + SkImageFilter* foreground = NULL, + const CropRect* cropRect = NULL) { SkImageFilter* inputs[2] = { background, foreground }; return new SkXfermodeImageFilter(mode, inputs, cropRect); } diff --git a/gfx/skia/skia/include/gpu/GrCaps.h b/gfx/skia/skia/include/gpu/GrCaps.h index 6d3b66af210..679777f9ddc 100644 --- a/gfx/skia/skia/include/gpu/GrCaps.h +++ b/gfx/skia/skia/include/gpu/GrCaps.h @@ -70,7 +70,7 @@ public: * called. */ const PrecisionInfo& getFloatShaderPrecisionInfo(GrShaderType shaderType, - GrSLPrecision precision) const { + GrSLPrecision precision) const { return fFloatPrecisions[shaderType][precision]; }; @@ -118,11 +118,7 @@ public: bool twoSidedStencilSupport() const { return fTwoSidedStencilSupport; } bool stencilWrapOpsSupport() const { return fStencilWrapOpsSupport; } bool discardRenderTargetSupport() const { return fDiscardRenderTargetSupport; } -#if GR_FORCE_GPU_TRACE_DEBUGGING - bool gpuTracingSupport() const { return true; } -#else bool gpuTracingSupport() const { return fGpuTracingSupport; } -#endif bool compressedTexSubImageSupport() const { return fCompressedTexSubImageSupport; } bool oversizedStencilSupport() const { return fOversizedStencilSupport; } bool textureBarrierSupport() const { return fTextureBarrierSupport; } @@ -194,15 +190,8 @@ public: // Will be 0 if MSAA is not supported int maxSampleCount() const { return fMaxSampleCount; } - bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const { - SkASSERT(kGrPixelConfigCnt > config); - return fConfigRenderSupport[config][withMSAA]; - } - - bool isConfigTexturable(GrPixelConfig config) const { - SkASSERT(kGrPixelConfigCnt > config); - return fConfigTextureSupport[config]; - } + virtual bool isConfigTexturable(GrPixelConfig config) const = 0; + virtual bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const = 0; bool suppressPrints() const { return fSuppressPrints; } @@ -270,10 +259,6 @@ protected: int fMaxTileSize; int fMaxSampleCount; - // The first entry for each config is without msaa and the second is with. - bool fConfigRenderSupport[kGrPixelConfigCnt][2]; - bool fConfigTextureSupport[kGrPixelConfigCnt]; - private: virtual void onApplyOptionsOverrides(const GrContextOptions&) {}; diff --git a/gfx/skia/skia/include/gpu/GrClip.h b/gfx/skia/skia/include/gpu/GrClip.h index 20196921943..cf6e65c9762 100644 --- a/gfx/skia/skia/include/gpu/GrClip.h +++ b/gfx/skia/skia/include/gpu/GrClip.h @@ -85,7 +85,7 @@ public: return this->irect() == other.irect(); break; } - + SkFAIL("This should not occur\n"); return false; } diff --git a/gfx/skia/skia/include/gpu/GrConfig.h b/gfx/skia/skia/include/gpu/GrConfig.h index ffacb939115..34666857e55 100644 --- a/gfx/skia/skia/include/gpu/GrConfig.h +++ b/gfx/skia/skia/include/gpu/GrConfig.h @@ -186,11 +186,11 @@ typedef unsigned __int64 uint64_t; #endif /** - * GR_FORCE_GPU_TRACE_DEBUGGING will force gpu tracing/debug markers to be turned on. The trace - * markers will be printed out instead of making the backend calls to push and pop them. + * Enable batch debugging output as json. The enabler of this flag is responsible for making sure + * GrAuditTrail is reset occasionally. + * TODO make this runtime configurable */ -#if !defined(GR_FORCE_GPU_TRACE_DEBUGGING) - #define GR_FORCE_GPU_TRACE_DEBUGGING 0 +#if !defined(GR_BATCH_DEBUGGING_OUTPUT) + #define GR_BATCH_DEBUGGING_OUTPUT 0 #endif - #endif diff --git a/gfx/skia/skia/include/gpu/GrContext.h b/gfx/skia/skia/include/gpu/GrContext.h index 70e7b9f2441..b60aea08130 100644 --- a/gfx/skia/skia/include/gpu/GrContext.h +++ b/gfx/skia/skia/include/gpu/GrContext.h @@ -15,9 +15,11 @@ #include "GrRenderTarget.h" #include "GrTextureProvider.h" #include "SkMatrix.h" -#include "../private/SkMutex.h" #include "SkPathEffect.h" #include "SkTypes.h" +#include "../private/GrAuditTrail.h" +#include "../private/GrSingleOwner.h" +#include "../private/SkMutex.h" struct GrBatchAtlasConfig; class GrBatchFontCache; @@ -354,9 +356,13 @@ public: /** Enumerates all cached GPU resources and dumps their memory to traceMemoryDump. */ void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; - /** Draw font cache texture to render target */ - void drawFontCache(const SkRect& rect, GrMaskFormat format, const SkPaint& paint, - GrRenderTarget* target); + /** Get pointer to atlas texture for given mask format */ + GrTexture* getFontAtlasTexture(GrMaskFormat format); + + GrAuditTrail* getAuditTrail() { return &fAuditTrail; } + + /** This is only useful for debug purposes */ + SkDEBUGCODE(GrSingleOwner* debugSingleOwner() const { return &fSingleOwner; } ) private: GrGpu* fGpu; @@ -391,6 +397,11 @@ private: SkMutex fReadPixelsMutex; SkMutex fTestPMConversionsMutex; + // In debug builds we guard against improper thread handling + // This guard is passed to the GrDrawingManager and, from there to all the + // GrDrawContexts. It is also passed to the GrTextureProvider and SkGpuDevice. + mutable GrSingleOwner fSingleOwner; + struct CleanUpData { PFCleanUpFunc fFunc; void* fInfo; @@ -402,6 +413,8 @@ private: SkAutoTDelete fDrawingManager; + GrAuditTrail fAuditTrail; + // TODO: have the CMM use drawContexts and rm this friending friend class GrClipMaskManager; // the CMM is friended just so it can call 'drawingManager' friend class GrDrawingManager; // for access to drawingManager for ProgramUnitTest diff --git a/gfx/skia/skia/include/gpu/GrContextOptions.h b/gfx/skia/skia/include/gpu/GrContextOptions.h index 52173eb7a0a..8e6368a3896 100644 --- a/gfx/skia/skia/include/gpu/GrContextOptions.h +++ b/gfx/skia/skia/include/gpu/GrContextOptions.h @@ -21,6 +21,8 @@ struct GrContextOptions { , fUseDrawInsteadOfPartialRenderTargetWrite(false) , fImmediateMode(false) , fClipBatchToBounds(false) + , fDrawBatchBounds(false) + , fMaxBatchLookback(-1) , fUseShaderSwizzling(false) {} // EXPERIMENTAL @@ -57,6 +59,14 @@ struct GrContextOptions { verify that the clip bounds are conservative. */ bool fClipBatchToBounds; + /** For debugging purposes draw a wireframe device bounds rect for each GrBatch. The wire + frame rect is draw before the GrBatch in order to visualize batches that draw outside + of their dev bounds. */ + bool fDrawBatchBounds; + + /** For debugging, override the default maximum look-back window for GrBatch combining. */ + int fMaxBatchLookback; + /** Force us to do all swizzling manually in the shader and don't rely on extensions to do swizzling. */ bool fUseShaderSwizzling; diff --git a/gfx/skia/skia/include/gpu/GrDrawContext.h b/gfx/skia/skia/include/gpu/GrDrawContext.h index 82cf362d579..9276e2b21ff 100644 --- a/gfx/skia/skia/include/gpu/GrDrawContext.h +++ b/gfx/skia/skia/include/gpu/GrDrawContext.h @@ -12,16 +12,17 @@ #include "GrRenderTarget.h" #include "SkRefCnt.h" #include "SkSurfaceProps.h" +#include "../private/GrSingleOwner.h" +class GrAuditTrail; class GrClip; class GrContext; class GrDrawBatch; +class GrDrawPathBatchBase; class GrDrawingManager; class GrDrawTarget; class GrPaint; class GrPathProcessor; -class GrPathRange; -class GrPathRangeDraw; class GrPipelineBuilder; class GrRenderTarget; class GrStrokeInfo; @@ -63,17 +64,6 @@ public: SkScalar x, SkScalar y, SkDrawFilter*, const SkIRect& clipBounds); - // drawPathsFromRange is thanks to GrStencilAndCoverTextContext - // TODO: remove once path batches can be created external to GrDrawTarget. - void drawPathsFromRange(const GrPipelineBuilder*, - const SkMatrix& viewMatrix, - const SkMatrix& localMatrix, - GrColor color, - GrPathRange* range, - GrPathRangeDraw* draw, - int /*GrPathRendering::FillType*/ fill, - const SkRect& bounds); - /** * Provides a perfomance hint that the render target's contents are allowed * to become undefined. @@ -274,17 +264,32 @@ public: */ void drawBatch(const GrClip&, const GrPaint&, GrDrawBatch*); + /** + * Draws a path batch. This needs to be separate from drawBatch because we install path stencil + * settings late. + * + * TODO: Figure out a better model that allows us to roll this method into drawBatch. + */ + void drawPathBatch(const GrPipelineBuilder&, GrDrawPathBatchBase*); + int width() const { return fRenderTarget->width(); } int height() const { return fRenderTarget->height(); } int numColorSamples() const { return fRenderTarget->numColorSamples(); } + GrRenderTarget* accessRenderTarget() { return fRenderTarget; } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // Functions intended for internal use only. + void internal_drawBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawBatch* batch); + private: - friend class GrAtlasTextContext; // for access to drawBatch + friend class GrAtlasTextBlob; // for access to drawBatch friend class GrDrawingManager; // for ctor SkDEBUGCODE(void validate() const;) - GrDrawContext(GrDrawingManager*, GrRenderTarget*, const SkSurfaceProps* surfaceProps); + GrDrawContext(GrDrawingManager*, GrRenderTarget*, const SkSurfaceProps* surfaceProps, + GrAuditTrail*, GrSingleOwner*); void internalDrawPath(GrPipelineBuilder*, const SkMatrix& viewMatrix, @@ -308,6 +313,10 @@ private: GrTextContext* fTextContext; // lazily gotten from GrContext::DrawingManager SkSurfaceProps fSurfaceProps; + GrAuditTrail* fAuditTrail; + + // In debug builds we guard against improper thread handling + SkDEBUGCODE(mutable GrSingleOwner* fSingleOwner;) }; #endif diff --git a/gfx/skia/skia/include/gpu/GrResourceKey.h b/gfx/skia/skia/include/gpu/GrResourceKey.h index 9958cfc8723..ff83a431044 100644 --- a/gfx/skia/skia/include/gpu/GrResourceKey.h +++ b/gfx/skia/skia/include/gpu/GrResourceKey.h @@ -293,11 +293,13 @@ private: #define GR_DECLARE_STATIC_UNIQUE_KEY(name) SK_DECLARE_STATIC_ONCE(name##_once) /** Place inside function where the key is used. */ -#define GR_DEFINE_STATIC_UNIQUE_KEY(name) \ - static GrUniqueKey name; \ - SkOnce(&name##_once, gr_init_static_unique_key_once, &name) +#define GR_DEFINE_STATIC_UNIQUE_KEY(name) \ + static SkAlignedSTStorage<1, GrUniqueKey> name##_storage; \ + SkOnce(&name##_once, gr_init_static_unique_key_once, &name##_storage); \ + static const GrUniqueKey& name = *reinterpret_cast(name##_storage.get()); -static inline void gr_init_static_unique_key_once(GrUniqueKey* key) { +static inline void gr_init_static_unique_key_once(SkAlignedSTStorage<1,GrUniqueKey>* keyStorage) { + GrUniqueKey* key = new (keyStorage->get()) GrUniqueKey; GrUniqueKey::Builder builder(key, GrUniqueKey::GenerateDomain(), 0); } diff --git a/gfx/skia/skia/include/gpu/GrTestUtils.h b/gfx/skia/skia/include/gpu/GrTestUtils.h index 91f36ea2d9c..8ffae09dddf 100644 --- a/gfx/skia/skia/include/gpu/GrTestUtils.h +++ b/gfx/skia/skia/include/gpu/GrTestUtils.h @@ -91,6 +91,7 @@ static inline uint8_t GrRandomCoverage(SkRandom* random) { switch (colorMode) { case kZero_CoverageMode: coverage = 0; + break; case kAllOnes_CoverageMode: coverage = 0xff; break; diff --git a/gfx/skia/skia/include/gpu/GrTextureAccess.h b/gfx/skia/skia/include/gpu/GrTextureAccess.h index e3ded34ff8c..124a75aabc0 100644 --- a/gfx/skia/skia/include/gpu/GrTextureAccess.h +++ b/gfx/skia/skia/include/gpu/GrTextureAccess.h @@ -14,60 +14,33 @@ #include "SkRefCnt.h" #include "SkShader.h" -/** A class representing the swizzle access pattern for a texture. Note that if the texture is - * an alpha-only texture then the alpha channel is substituted for other components. Any mangling - * to handle the r,g,b->a conversions for alpha textures is automatically included in the stage - * key. However, if a GrProcessor uses different swizzles based on its input then it must - * consider that variation in its key-generation. +/** + * Used to represent a texture that is required by a GrProcessor. It holds a GrTexture along with + * an associated GrTextureParams */ class GrTextureAccess : public SkNoncopyable { public: /** - * A default GrTextureAccess must have reset() called on it in a GrProcessor subclass's - * constructor if it will be accessible via GrProcessor::textureAccess(). + * Must be initialized before adding to a GrProcessor's texture access list. */ GrTextureAccess(); - /** - * Uses the default swizzle, "rgba". - */ GrTextureAccess(GrTexture*, const GrTextureParams&); + explicit GrTextureAccess(GrTexture*, GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode); - /** - * swizzle must be a string between one and four (inclusive) characters containing only 'r', - * 'g', 'b', and/or 'a'. - */ - GrTextureAccess(GrTexture*, const char* swizzle, const GrTextureParams&); - GrTextureAccess(GrTexture*, - const char* swizzle, - GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, - SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode); - void reset(GrTexture*, const GrTextureParams&); void reset(GrTexture*, GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode); - void reset(GrTexture*, const char* swizzle, const GrTextureParams&); - void reset(GrTexture*, - const char* swizzle, - GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, - SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode); - bool operator== (const GrTextureAccess& other) const { -#ifdef SK_DEBUG - // below assumes all chars in fSwizzle are initialized even if string is < 4 chars long. - SkASSERT(memcmp(fSwizzle, other.fSwizzle, sizeof(fSwizzle)-1) == - strcmp(fSwizzle, other.fSwizzle)); -#endif - return fParams == other.fParams && - (this->getTexture() == other.getTexture()) && - (0 == memcmp(fSwizzle, other.fSwizzle, sizeof(fSwizzle)-1)); + bool operator==(const GrTextureAccess& that) const { + return this->getTexture() == that.getTexture() && fParams == that.fParams; } - bool operator!= (const GrTextureAccess& other) const { return !(*this == other); } + bool operator!=(const GrTextureAccess& other) const { return !(*this == other); } GrTexture* getTexture() const { return fTexture.get(); } @@ -76,26 +49,14 @@ public: */ const GrGpuResourceRef* getProgramTexture() const { return &fTexture; } - /** - * Returns a string representing the swizzle. The string is is null-terminated. - */ - const char* getSwizzle() const { return fSwizzle; } - - /** Returns a mask indicating which components are referenced in the swizzle. The return - is a bitfield of GrColorComponentFlags. */ - uint32_t swizzleMask() const { return fSwizzleMask; } - const GrTextureParams& getParams() const { return fParams; } private: - void setSwizzle(const char*); typedef GrTGpuResourceRef ProgramTexture; ProgramTexture fTexture; GrTextureParams fParams; - uint32_t fSwizzleMask; - char fSwizzle[5]; typedef SkNoncopyable INHERITED; }; diff --git a/gfx/skia/skia/include/gpu/GrTextureProvider.h b/gfx/skia/skia/include/gpu/GrTextureProvider.h index 5635583d80f..338dddbaca8 100644 --- a/gfx/skia/skia/include/gpu/GrTextureProvider.h +++ b/gfx/skia/skia/include/gpu/GrTextureProvider.h @@ -11,6 +11,8 @@ #include "GrTexture.h" #include "SkImageFilter.h" +class GrSingleOwner; + class SK_API GrTextureProvider { public: /////////////////////////////////////////////////////////////////////////// @@ -42,15 +44,7 @@ public: } /** Finds a texture by unique key. If the texture is found it is ref'ed and returned. */ - GrTexture* findAndRefTextureByUniqueKey(const GrUniqueKey& key) { - GrGpuResource* resource = this->findAndRefResourceByUniqueKey(key); - if (resource) { - GrTexture* texture = static_cast(resource)->asTexture(); - SkASSERT(texture); - return texture; - } - return NULL; - } + GrTexture* findAndRefTextureByUniqueKey(const GrUniqueKey& key); /** * Determines whether a texture is associated with the unique key. If the texture is found it @@ -70,31 +64,6 @@ public: */ GrTexture* createApproxTexture(const GrSurfaceDesc&); - enum SizeConstraint { - kExact_SizeConstraint, - kApprox_SizeConstraint, - }; - - GrTexture* createTexture(const GrSurfaceDesc& desc, SizeConstraint constraint) { - switch (constraint) { - case kExact_SizeConstraint: - return this->createTexture(desc, true); - case kApprox_SizeConstraint: - return this->createApproxTexture(desc); - } - sk_throw(); - return nullptr; - } - - static SizeConstraint FromImageFilter(SkImageFilter::SizeConstraint constraint) { - if (SkImageFilter::kExact_SizeConstraint == constraint) { - return kExact_SizeConstraint; - } else { - SkASSERT(SkImageFilter::kApprox_SizeConstraint == constraint); - return kApprox_SizeConstraint; - } - } - /** Legacy function that no longer should be used. */ enum ScratchTexMatch { kExact_ScratchTexMatch, @@ -134,7 +103,7 @@ public: GrRenderTarget* wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc); protected: - GrTextureProvider(GrGpu* gpu, GrResourceCache* cache) : fCache(cache), fGpu(gpu) {} + GrTextureProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* singleOwner); /** * Assigns a unique key to a resource. If the key is associated with another resource that @@ -186,6 +155,9 @@ protected: private: GrResourceCache* fCache; GrGpu* fGpu; + + // In debug builds we guard against improper thread handling + SkDEBUGCODE(mutable GrSingleOwner* fSingleOwner;) }; #endif diff --git a/gfx/skia/skia/include/gpu/GrTypes.h b/gfx/skia/skia/include/gpu/GrTypes.h index cf3773c89ee..dbcb9a65833 100644 --- a/gfx/skia/skia/include/gpu/GrTypes.h +++ b/gfx/skia/skia/include/gpu/GrTypes.h @@ -363,26 +363,6 @@ static inline size_t GrBytesPerPixel(GrPixelConfig config) { } } -static inline size_t GrUnpackAlignment(GrPixelConfig config) { - SkASSERT(!GrPixelConfigIsCompressed(config)); - switch (config) { - case kAlpha_8_GrPixelConfig: - return 1; - case kRGB_565_GrPixelConfig: - case kRGBA_4444_GrPixelConfig: - case kAlpha_half_GrPixelConfig: - case kRGBA_half_GrPixelConfig: - return 2; - case kRGBA_8888_GrPixelConfig: - case kBGRA_8888_GrPixelConfig: - case kSRGBA_8888_GrPixelConfig: - case kRGBA_float_GrPixelConfig: - return 4; - default: - return 0; - } -} - static inline bool GrPixelConfigIsOpaque(GrPixelConfig config) { switch (config) { case kETC1_GrPixelConfig: diff --git a/gfx/skia/skia/include/gpu/GrTypesPriv.h b/gfx/skia/skia/include/gpu/GrTypesPriv.h index 6135c14c121..c46e25bd0d4 100644 --- a/gfx/skia/skia/include/gpu/GrTypesPriv.h +++ b/gfx/skia/skia/include/gpu/GrTypesPriv.h @@ -12,10 +12,10 @@ #include "SkTArray.h" #include "SkRect.h" -/** - * Types of shader-language-specific boxed variables we can create. (Currently only GrGLShaderVars, - * but should be applicable to other shader languages.) - */ + /** + * Types of shader-language-specific boxed variables we can create. (Currently only GrGLShaderVars, + * but should be applicable to other shader languages.) + */ enum GrSLType { kVoid_GrSLType, kFloat_GrSLType, @@ -26,8 +26,9 @@ enum GrSLType { kMat44f_GrSLType, kSampler2D_GrSLType, kSamplerExternal_GrSLType, + kSampler2DRect_GrSLType, - kLast_GrSLType = kSamplerExternal_GrSLType + kLast_GrSLType = kSampler2DRect_GrSLType }; static const int kGrSLTypeCount = kLast_GrSLType + 1; @@ -64,7 +65,7 @@ static const int kGrSLPrecisionCount = kLast_GrSLPrecision + 1; */ static inline int GrSLTypeVectorCount(GrSLType type) { SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); - static const int kCounts[] = { -1, 1, 2, 3, 4, -1, -1, -1, -1 }; + static const int kCounts[] = { -1, 1, 2, 3, 4, -1, -1, -1, -1, -1 }; return kCounts[type]; GR_STATIC_ASSERT(0 == kVoid_GrSLType); @@ -76,6 +77,7 @@ static inline int GrSLTypeVectorCount(GrSLType type) { GR_STATIC_ASSERT(6 == kMat44f_GrSLType); GR_STATIC_ASSERT(7 == kSampler2D_GrSLType); GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType); + GR_STATIC_ASSERT(9 == kSampler2DRect_GrSLType); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kCounts) == kGrSLTypeCount); } @@ -105,8 +107,49 @@ static inline bool GrSLTypeIsFloatType(GrSLType type) { GR_STATIC_ASSERT(6 == kMat44f_GrSLType); GR_STATIC_ASSERT(7 == kSampler2D_GrSLType); GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType); - GR_STATIC_ASSERT(9 == kGrSLTypeCount); + GR_STATIC_ASSERT(9 == kSampler2DRect_GrSLType); + GR_STATIC_ASSERT(10 == kGrSLTypeCount); } + +/** Returns the size in bytes for floating point GrSLTypes. For non floating point type returns 0 */ +static inline size_t GrSLTypeSize(GrSLType type) { + SkASSERT(GrSLTypeIsFloatType(type)); + static const size_t kSizes[] = { + 0, // kVoid_GrSLType + sizeof(float), // kFloat_GrSLType + 2 * sizeof(float), // kVec2f_GrSLType + 3 * sizeof(float), // kVec3f_GrSLType + 4 * sizeof(float), // kVec4f_GrSLType + 9 * sizeof(float), // kMat33f_GrSLType + 16 * sizeof(float), // kMat44f_GrSLType + 0, // kSampler2D_GrSLType + 0, // kSamplerExternal_GrSLType + 0 // kSampler2DRect_GrSLType + }; + return kSizes[type]; + + GR_STATIC_ASSERT(0 == kVoid_GrSLType); + GR_STATIC_ASSERT(1 == kFloat_GrSLType); + GR_STATIC_ASSERT(2 == kVec2f_GrSLType); + GR_STATIC_ASSERT(3 == kVec3f_GrSLType); + GR_STATIC_ASSERT(4 == kVec4f_GrSLType); + GR_STATIC_ASSERT(5 == kMat33f_GrSLType); + GR_STATIC_ASSERT(6 == kMat44f_GrSLType); + GR_STATIC_ASSERT(7 == kSampler2D_GrSLType); + GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType); + GR_STATIC_ASSERT(9 == kSampler2DRect_GrSLType); + GR_STATIC_ASSERT(10 == kGrSLTypeCount); +} + +static inline bool GrSLTypeIsSamplerType(GrSLType type) { + SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); + return type >= 7 && type <= 9; + + GR_STATIC_ASSERT(7 == kSampler2D_GrSLType); + GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType); + GR_STATIC_ASSERT(9 == kSampler2DRect_GrSLType); +} + ////////////////////////////////////////////////////////////////////////////// /** @@ -178,6 +221,7 @@ static inline GrSLType GrVertexAttribTypeToSLType(GrVertexAttribType type) { switch (type) { default: SkFAIL("Unsupported type conversion"); + return kVoid_GrSLType; case kUByte_GrVertexAttribType: case kFloat_GrVertexAttribType: return kFloat_GrSLType; @@ -267,6 +311,17 @@ private: SkIRect fRect; }; +/** + * Indicates the transfer direction for a transfer buffer + */ +enum TransferType { + /** Caller intends to use the buffer to transfer data to the GPU */ + kCpuToGpu_TransferType, + /** Caller intends to use the buffer to transfer data from the GPU */ + kGpuToCpu_TransferType +}; + + #ifdef SK_DEBUG // Takes a pointer to a GrCaps, and will suppress prints if required #define GrCapsDebugf(caps, ...) \ diff --git a/gfx/skia/skia/include/gpu/SkGrPixelRef.h b/gfx/skia/skia/include/gpu/SkGrPixelRef.h index c06154db10d..b4dbd9d73f3 100644 --- a/gfx/skia/skia/include/gpu/SkGrPixelRef.h +++ b/gfx/skia/skia/include/gpu/SkGrPixelRef.h @@ -49,7 +49,7 @@ public: protected: // overrides from SkPixelRef - bool onReadPixels(SkBitmap* dst, const SkIRect* subset) override; + bool onReadPixels(SkBitmap* dst, SkColorType, const SkIRect* subset) override; SkPixelRef* deepCopy(SkColorType, SkColorProfileType, const SkIRect* subset) override; void onNotifyPixelsChanged() override; diff --git a/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h b/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h index be014a6b048..457c6eabc8c 100644 --- a/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h +++ b/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h @@ -21,10 +21,16 @@ public: void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, GrXPFactory::InvariantBlendedColor*) const override; + + /** Because src-over is so common we special case it for performance reasons. If this returns + null then the SimpleSrcOverXP() below should be used. */ static GrXferProcessor* CreateSrcOverXferProcessor(const GrCaps& caps, const GrPipelineOptimizations& optimizations, bool hasMixedSamples, const GrXferProcessor::DstTexture*); + /** This XP implements non-LCD src-over using hw blend with no optimizations. It is returned + by reference because it is global and its ref-cnting methods are not thread safe. */ + static const GrXferProcessor& SimpleSrcOverXP(); static inline void SrcOverInvariantBlendedColor( GrColor inputColor, diff --git a/gfx/skia/skia/include/gpu/gl/SkGLContext.h b/gfx/skia/skia/include/gpu/gl/SkGLContext.h index 3420a479732..77fd325dd85 100644 --- a/gfx/skia/skia/include/gpu/gl/SkGLContext.h +++ b/gfx/skia/skia/include/gpu/gl/SkGLContext.h @@ -17,9 +17,9 @@ * This class is intended for Skia's testing needs and not for general * use. */ -class SK_API SkGLContext : public SkRefCnt { +class SK_API SkGLContext : public SkNoncopyable { public: - ~SkGLContext() override; + virtual ~SkGLContext(); bool isValid() const { return NULL != gl(); } @@ -41,6 +41,11 @@ public: virtual GrEGLImage texture2DToEGLImage(GrGLuint /*texID*/) const { return 0; } virtual void destroyEGLImage(GrEGLImage) const {} + /** Used for testing GL_TEXTURE_RECTANGLE integration. */ + GrGLint createTextureRectangle(int width, int height, GrGLenum internalFormat, + GrGLenum externalFormat, GrGLenum externalType, + GrGLvoid* data); + /** * Used for testing EGLImage integration. Takes a EGLImage and wraps it in a * GL_TEXTURE_EXTERNAL_OES. @@ -106,8 +111,6 @@ private: SkAutoTUnref fGL; friend class GLFenceSync; // For onPlatformGetProcAddress. - - typedef SkRefCnt INHERITED; }; /** Creates platform-dependent GL context object diff --git a/gfx/skia/skia/include/gpu/gl/SkNullGLContext.h b/gfx/skia/skia/include/gpu/gl/SkNullGLContext.h index 1f634382641..9e799a9fea4 100644 --- a/gfx/skia/skia/include/gpu/gl/SkNullGLContext.h +++ b/gfx/skia/skia/include/gpu/gl/SkNullGLContext.h @@ -14,7 +14,12 @@ class SK_API SkNullGLContext : public SkGLContext { public: ~SkNullGLContext() override; - static SkNullGLContext* Create(GrGLStandard); + static SkNullGLContext* Create(); + // FIXME: remove once Chromium has been updated. + static SkNullGLContext* Create(GrGLStandard forcedAPI) { + SkASSERT(forcedAPI == kNone_GrGLStandard); + (void)forcedAPI; return Create(); + } class ContextState; diff --git a/gfx/skia/skia/include/gpu/gl/angle/SkANGLEGLContext.h b/gfx/skia/skia/include/gpu/gl/angle/SkANGLEGLContext.h index 7858fff9649..ea5e877ca27 100644 --- a/gfx/skia/skia/include/gpu/gl/angle/SkANGLEGLContext.h +++ b/gfx/skia/skia/include/gpu/gl/angle/SkANGLEGLContext.h @@ -15,18 +15,25 @@ class SkANGLEGLContext : public SkGLContext { public: ~SkANGLEGLContext() override; - - static SkANGLEGLContext* Create(GrGLStandard forcedGpuAPI, bool useGLBackend) { - if (kGL_GrGLStandard == forcedGpuAPI) { - return NULL; - } - SkANGLEGLContext* ctx = new SkANGLEGLContext(useGLBackend); +#ifdef SK_BUILD_FOR_WIN + static SkANGLEGLContext* CreateDirectX() { + SkANGLEGLContext* ctx = new SkANGLEGLContext(false); if (!ctx->isValid()) { delete ctx; return NULL; } return ctx; } +#endif + static SkANGLEGLContext* CreateOpenGL() { + SkANGLEGLContext* ctx = new SkANGLEGLContext(true); + if (!ctx->isValid()) { + delete ctx; + return NULL; + } + return ctx; + } + GrEGLImage texture2DToEGLImage(GrGLuint texID) const override; void destroyEGLImage(GrEGLImage) const override; GrGLuint eglImageToExternalTexture(GrEGLImage) const override; diff --git a/gfx/skia/skia/include/gpu/gl/command_buffer/SkCommandBufferGLContext.h b/gfx/skia/skia/include/gpu/gl/command_buffer/SkCommandBufferGLContext.h index 7fece3c83c1..47f3fd967a3 100644 --- a/gfx/skia/skia/include/gpu/gl/command_buffer/SkCommandBufferGLContext.h +++ b/gfx/skia/skia/include/gpu/gl/command_buffer/SkCommandBufferGLContext.h @@ -16,10 +16,7 @@ class SkCommandBufferGLContext : public SkGLContext { public: ~SkCommandBufferGLContext() override; - static SkCommandBufferGLContext* Create(GrGLStandard forcedGpuAPI) { - if (kGL_GrGLStandard == forcedGpuAPI) { - return nullptr; - } + static SkCommandBufferGLContext* Create() { SkCommandBufferGLContext* ctx = new SkCommandBufferGLContext; if (!ctx->isValid()) { delete ctx; diff --git a/gfx/skia/skia/include/pipe/SkGPipe.h b/gfx/skia/skia/include/pipe/SkGPipe.h deleted file mode 100644 index 9446b8159f0..00000000000 --- a/gfx/skia/skia/include/pipe/SkGPipe.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - - -#ifndef SkGPipe_DEFINED -#define SkGPipe_DEFINED - -#include "SkFlattenable.h" -#include "SkPicture.h" -#include "SkWriter32.h" - -class SkCanvas; - -// XLib.h might have defined Status already (ugh) -#ifdef Status - #undef Status -#endif - -class SkGPipeReader { -public: - SkGPipeReader(); - SkGPipeReader(SkCanvas* target); - ~SkGPipeReader(); - - enum Status { - kDone_Status, //!< no more data expected from reader - kEOF_Status, //!< need more data from reader - kError_Status, //!< encountered error - kReadAtom_Status//!< finished reading an atom - }; - - enum PlaybackFlags { - kReadAtom_PlaybackFlag = 0x1, //!< playback a single command from the stream - kSilent_PlaybackFlag = 0x2, //!< playback without drawing - }; - - void setCanvas(SkCanvas*); - - /** - * Set a function for decoding bitmaps that have encoded data. - */ - void setBitmapDecoder(SkPicture::InstallPixelRefProc proc) { fProc = proc; } - - // data must be 4-byte aligned - // length must be a multiple of 4 - Status playback(const void* data, size_t length, uint32_t playbackFlags = 0, - size_t* bytesRead = NULL); -private: - SkCanvas* fCanvas; - class SkGPipeState* fState; - SkPicture::InstallPixelRefProc fProc; -}; - -/////////////////////////////////////////////////////////////////////////////// - -class SkGPipeCanvas; - -class SkGPipeController { -public: - SkGPipeController() : fCanvas(NULL) {} - virtual ~SkGPipeController(); - - /** - * Called periodically by the writer, to get a working buffer of RAM to - * write into. The actual size of the block is also returned, and must be - * actual >= minRequest. If NULL is returned, then actual is ignored and - * writing will stop. - * - * The returned block must be 4-byte aligned, and actual must be a - * multiple of 4. - * minRequest will always be a multiple of 4. - */ - virtual void* requestBlock(size_t minRequest, size_t* actual) = 0; - - /** - * This is called each time some atomic portion of the data has been - * written to the block (most recently returned by requestBlock()). - * If bytes == 0, then the writer has finished. - * - * bytes will always be a multiple of 4. - */ - virtual void notifyWritten(size_t bytes) = 0; - virtual int numberOfReaders() const { return 1; } - - /** - * Release resource references that are held in internal caches. - * This must only be called after the pipe has been completely flushed. - */ - void purgeCaches(); - -private: - friend class SkGPipeWriter; - void setCanvas(SkGPipeCanvas*); - - SkGPipeCanvas* fCanvas; -}; - -class SkGPipeWriter { -public: - SkGPipeWriter(); - ~SkGPipeWriter(); - - bool isRecording() const { return SkToBool(fCanvas); } - - enum Flags { - /** - * Tells the writer that the reader will be in a different process, so - * (for example) we cannot put function pointers in the stream. - */ - kCrossProcess_Flag = 1 << 0, - - /** - * Only meaningful if kCrossProcess_Flag is set. Tells the writer that - * in spite of being cross process, it will have shared address space - * with the reader, so the two can share large objects (like SkBitmaps). - */ - kSharedAddressSpace_Flag = 1 << 1, - - /** - * Tells the writer that there will be multiple threads reading the stream - * simultaneously. - */ - kSimultaneousReaders_Flag = 1 << 2, - }; - - SkCanvas* startRecording(SkGPipeController*, uint32_t flags = 0, - uint32_t width = kDefaultRecordingCanvasSize, - uint32_t height = kDefaultRecordingCanvasSize); - - // called in destructor, but can be called sooner once you know there - // should be no more drawing calls made into the recording canvas. - void endRecording(); - - /** - * Tells the writer to commit all recorded draw commands to the - * controller immediately. - * @param detachCurrentBlock Set to true to request that the next draw - * command be recorded in a new block. - */ - void flushRecording(bool detachCurrentBlock); - - /** - * Return the amount of bytes being used for recording. Note that this - * does not include the amount of storage written to the stream, which is - * controlled by the SkGPipeController. - * Currently only returns the amount used for SkBitmaps, since they are - * potentially unbounded (if the client is not calling playback). - */ - size_t storageAllocatedForRecording() const; - - /** - * Attempt to reduce the storage allocated for recording by evicting - * cache resources. - * @param bytesToFree minimum number of bytes that should be attempted to - * be freed. - * @return number of bytes actually freed. - */ - size_t freeMemoryIfPossible(size_t bytesToFree); - -private: - enum { - kDefaultRecordingCanvasSize = 32767, - }; - - SkGPipeCanvas* fCanvas; - SkWriter32 fWriter; -}; - -#endif diff --git a/gfx/skia/skia/include/ports/SkFontMgr.h b/gfx/skia/skia/include/ports/SkFontMgr.h index 8d57986a132..96a8501c485 100644 --- a/gfx/skia/skia/include/ports/SkFontMgr.h +++ b/gfx/skia/skia/include/ports/SkFontMgr.h @@ -43,6 +43,8 @@ public: * The caller must call unref() on the returned object. * Never returns NULL; will return an empty set if the name is not found. * + * Passing |nullptr| as the parameter will return the default system font. + * * It is possible that this will return a style set not accessible from * createStyleSet(int) due to hidden or auto-activated fonts. */ @@ -54,6 +56,9 @@ public: * object. Will never return NULL, as it will return the default font if * no matching font is found. * + * Passing |nullptr| as the parameter for |familyName| will return the + * default system font. + * * It is possible that this will return a style set not accessible from * createStyleSet(int) or matchFamily(const char[]) due to hidden or * auto-activated fonts. @@ -68,6 +73,9 @@ public: * Will return NULL if no family can be found for the character * in the system fallback. * + * Passing |nullptr| as the parameter for |familyName| will return the + * default system font. + * * bcp47[0] is the least significant fallback, bcp47[bcp47Count-1] is the * most significant. If no specified bcp47 codes match, any font with the * requested character will be matched. diff --git a/gfx/skia/skia/include/private/GrAuditTrail.h b/gfx/skia/skia/include/private/GrAuditTrail.h new file mode 100644 index 00000000000..fbaec84bb38 --- /dev/null +++ b/gfx/skia/skia/include/private/GrAuditTrail.h @@ -0,0 +1,116 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrAuditTrail_DEFINED +#define GrAuditTrail_DEFINED + +#include "GrConfig.h" +#include "SkRect.h" +#include "SkString.h" +#include "SkTArray.h" + +/* + * GrAuditTrail collects a list of draw ops, detailed information about those ops, and can dump them + * to json. + */ +class GrAuditTrail { +public: + GrAuditTrail() : fUniqueID(0) {} + + class AutoFrame { + public: + AutoFrame(GrAuditTrail* auditTrail, const char* name) + : fAuditTrail(auditTrail) { + if (GR_BATCH_DEBUGGING_OUTPUT) { + fAuditTrail->pushFrame(name); + } + } + + ~AutoFrame() { + if (GR_BATCH_DEBUGGING_OUTPUT) { + fAuditTrail->popFrame(); + } + } + + private: + GrAuditTrail* fAuditTrail; + }; + + void pushFrame(const char* name) { + SkASSERT(GR_BATCH_DEBUGGING_OUTPUT); + Frame* frame = new Frame; + if (fStack.empty()) { + fFrames.emplace_back(frame); + } else { + fStack.back()->fChildren.emplace_back(frame); + } + + frame->fUniqueID = fUniqueID++; + frame->fName = name; + fStack.push_back(frame); + } + + void popFrame() { + SkASSERT(GR_BATCH_DEBUGGING_OUTPUT); + fStack.pop_back(); + } + + void addBatch(const char* name, const SkRect& bounds) { + SkASSERT(GR_BATCH_DEBUGGING_OUTPUT && !fStack.empty()); + Batch* batch = new Batch; + fStack.back()->fChildren.emplace_back(batch); + batch->fName = name; + batch->fBounds = bounds; + } + + SkString toJson() const; + + void reset() { SkASSERT(GR_BATCH_DEBUGGING_OUTPUT && fStack.empty()); fFrames.reset(); } + +private: + // TODO if performance becomes an issue, we can move to using SkVarAlloc + struct Event { + virtual ~Event() {} + virtual SkString toJson() const=0; + + const char* fName; + uint64_t fUniqueID; + }; + + typedef SkTArray, true> FrameArray; + struct Frame : public Event { + SkString toJson() const override; + FrameArray fChildren; + }; + + struct Batch : public Event { + SkString toJson() const override; + SkRect fBounds; + }; + + static void JsonifyTArray(SkString* json, const char* name, const FrameArray& array); + + FrameArray fFrames; + SkTArray fStack; + uint64_t fUniqueID; +}; + +#define GR_AUDIT_TRAIL_INVOKE_GUARD(invoke, ...) \ + if (GR_BATCH_DEBUGGING_OUTPUT) { \ + invoke(__VA_ARGS__); \ + } + +#define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename) \ + GrAuditTrail::AutoFrame SK_MACRO_APPEND_LINE(auto_frame)(audit_trail, framename); + +#define GR_AUDIT_TRAIL_RESET(audit_trail) \ + GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail->reset); + +#define GR_AUDIT_TRAIL_ADDBATCH(audit_trail, batchname, bounds) \ + GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail->addBatch, batchname, bounds); + +#endif diff --git a/gfx/skia/skia/include/private/GrSingleOwner.h b/gfx/skia/skia/include/private/GrSingleOwner.h new file mode 100644 index 00000000000..64e63d3b19f --- /dev/null +++ b/gfx/skia/skia/include/private/GrSingleOwner.h @@ -0,0 +1,55 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSingleOwner_DEFINED +#define GrSingleOwner_DEFINED + +#include "SkTypes.h" + +#ifdef SK_DEBUG +#include "SkMutex.h" +#include "SkThreadID.h" + +// This is a debug tool to verify an object is only being used from one thread at a time. +class GrSingleOwner { +public: + GrSingleOwner() : fOwner(kIllegalThreadID), fReentranceCount(0) {} + + struct AutoEnforce { + AutoEnforce(GrSingleOwner* so) : fSO(so) { fSO->enter(); } + ~AutoEnforce() { fSO->exit(); } + + GrSingleOwner* fSO; + }; + +private: + void enter() { + SkAutoMutexAcquire lock(fMutex); + SkThreadID self = SkGetThreadID(); + SkASSERT(fOwner == self || fOwner == kIllegalThreadID); + fReentranceCount++; + fOwner = self; + } + + void exit() { + SkAutoMutexAcquire lock(fMutex); + SkASSERT(fOwner == SkGetThreadID()); + fReentranceCount--; + if (fReentranceCount == 0) { + fOwner = kIllegalThreadID; + } + } + + SkMutex fMutex; + SkThreadID fOwner; // guarded by fMutex + int fReentranceCount; // guarded by fMutex +}; +#else +class GrSingleOwner {}; // Provide a dummy implementation so we can pass pointers to constructors +#endif + +#endif diff --git a/gfx/skia/skia/include/private/SkFloatingPoint.h b/gfx/skia/skia/include/private/SkFloatingPoint.h index f7ee816b120..225e6ca9587 100644 --- a/gfx/skia/skia/include/private/SkFloatingPoint.h +++ b/gfx/skia/skia/include/private/SkFloatingPoint.h @@ -12,7 +12,7 @@ #include "SkTypes.h" -#include +#include #include // For _POSIX_VERSION @@ -95,9 +95,9 @@ static inline float sk_float_copysign(float x, float y) { return (bits << 1) == (0xFF << 24); } #else - #define sk_float_isfinite(x) isfinite(x) - #define sk_float_isnan(x) isnan(x) - #define sk_float_isinf(x) isinf(x) + #define sk_float_isfinite(x) std::isfinite(x) + #define sk_float_isnan(x) std::isnan(x) + #define sk_float_isinf(x) std::isinf(x) #endif #define sk_double_isnan(a) sk_float_isnan(a) diff --git a/gfx/skia/skia/include/private/SkRecords.h b/gfx/skia/skia/include/private/SkRecords.h index b856647aeed..ecd73a12d9b 100644 --- a/gfx/skia/skia/include/private/SkRecords.h +++ b/gfx/skia/skia/include/private/SkRecords.h @@ -10,6 +10,7 @@ #include "SkCanvas.h" #include "SkDrawable.h" +#include "SkImageFilter.h" #include "SkMatrix.h" #include "SkPath.h" #include "SkPicture.h" @@ -63,7 +64,6 @@ namespace SkRecords { M(DrawTextOnPath) \ M(DrawRRect) \ M(DrawRect) \ - M(DrawSprite) \ M(DrawTextBlob) \ M(DrawAtlas) \ M(DrawVertices) @@ -198,7 +198,8 @@ RECORD(Save, 0); RECORD(SaveLayer, 0, Optional bounds; Optional paint; - SkCanvas::SaveFlags flags); + RefBox backdrop; + SkCanvas::SaveLayerFlags saveLayerFlags); RECORD(SetMatrix, 0, TypedMatrix matrix); @@ -315,11 +316,6 @@ RECORD(DrawRRect, kDraw_Tag, RECORD(DrawRect, kDraw_Tag, SkPaint paint; SkRect rect); -RECORD(DrawSprite, kDraw_Tag|kHasImage_Tag, - Optional paint; - ImmutableBitmap bitmap; - int left; - int top); RECORD(DrawText, kDraw_Tag|kHasText_Tag, SkPaint paint; PODArray text; diff --git a/gfx/skia/skia/include/core/SkTDict.h b/gfx/skia/skia/include/private/SkTDict.h similarity index 100% rename from gfx/skia/skia/include/core/SkTDict.h rename to gfx/skia/skia/include/private/SkTDict.h diff --git a/gfx/skia/skia/include/private/SkTLogic.h b/gfx/skia/skia/include/private/SkTLogic.h index 604d9aa59da..7072b516e96 100644 --- a/gfx/skia/skia/include/private/SkTLogic.h +++ b/gfx/skia/skia/include/private/SkTLogic.h @@ -5,9 +5,10 @@ * found in the LICENSE file. * * - * This header provides some of the helpers (std::integral_constant) and - * type transformations (std::conditional) which will become available with - * C++11 in the type_traits header. + * This header provides some of the helpers (like std::enable_if_t) which will + * become available with C++14 in the type_traits header (in the skstd + * namespace). This header also provides several Skia specific additions such + * as SK_WHEN and the sknonstd namespace. */ #ifndef SkTLogic_DEFINED @@ -17,147 +18,98 @@ #include #include +#include + +#if SKIA_IMPLEMENTATION +#include +#endif + +#ifdef MOZ_SKIA +#include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" + +#if SKIA_IMPLEMENTATION +#include "mozilla/Function.h" +#endif + +namespace std { + using mozilla::Forward; + #define forward Forward + +#if SKIA_IMPLEMENTATION + using mozilla::IntegralConstant; + using mozilla::IsEmpty; + using mozilla::FalseType; + using mozilla::TrueType; + #define integral_constant IntegralConstant + #define is_empty IsEmpty + #define false_type FalseType + #define true_type TrueType + + using mozilla::Function; + #define function Function +#endif +} namespace skstd { -using nullptr_t = decltype(nullptr); +template using bool_constant = mozilla::IntegralConstant; -template struct integral_constant { - static const/*expr*/ T value = v; - using value_type = T; - using type = integral_constant; - //constexpr operator value_type() const noexcept { return value; } - //constexpr value_type operator()() const noexcept { return value; } -}; +template using conditional_t = typename mozilla::Conditional::Type; +template using enable_if_t = typename mozilla::EnableIf::Type; -template using bool_constant = integral_constant; +} -using true_type = bool_constant; -using false_type = bool_constant; +#else /* !MOZ_SKIA */ -template struct conditional { using type = T; }; -template struct conditional { using type = F; }; -template using conditional_t = typename conditional::type; +#include +#include -template struct enable_if { using type = T; }; -template struct enable_if {}; -template using enable_if_t = typename enable_if::type; +namespace skstd { -template struct remove_const { using type = T; }; -template struct remove_const { using type = T; }; -template using remove_const_t = typename remove_const::type; +template using bool_constant = std::integral_constant; -template struct remove_volatile { using type = T; }; -template struct remove_volatile { using type = T; }; -template using remove_volatile_t = typename remove_volatile::type; +template using conditional_t = typename std::conditional::type; +template using enable_if_t = typename std::enable_if::type; -template struct remove_cv { using type = remove_volatile_t>; }; -template using remove_cv_t = typename remove_cv::type; - -template struct remove_reference { using type = T; }; -template struct remove_reference { using type = T; }; -template struct remove_reference { using type = T; }; -template using remove_reference_t = typename remove_reference::type; - -template struct remove_extent { using type = T; }; -template struct remove_extent { using type = T; }; -template struct remove_extent { using type = T;}; -template using remove_extent_t = typename remove_extent::type; - -template struct is_same : false_type {}; -template struct is_same : true_type {}; - -template struct is_void : is_same> {}; - -template struct is_const : false_type {}; -template struct is_const : true_type {}; - -template struct is_volatile : false_type {}; -template struct is_volatile : true_type {}; - -template struct is_pointer_detector : false_type {}; -template struct is_pointer_detector : true_type {}; -template struct is_pointer : is_pointer_detector> {}; - -template struct is_reference : false_type {}; -template struct is_reference : true_type {}; -template struct is_reference : true_type {}; - -template struct is_lvalue_reference : false_type {}; -template struct is_lvalue_reference : true_type {}; - -template struct is_rvalue_reference : false_type {}; -template struct is_rvalue_reference : true_type {}; - -template struct is_class_detector { - using yes_type = uint8_t; - using no_type = uint16_t; - template static yes_type clazz(int U::*); - template static no_type clazz(...); - static const/*expr*/ bool value = sizeof(clazz(0)) == sizeof(yes_type) /*&& !is_union::value*/; -}; -template struct is_class : bool_constant::value> {}; - -template ::value> struct is_empty_detector { - struct Derived : public T { char unused; }; - static const/*expr*/ bool value = sizeof(Derived) == sizeof(char); -}; -template struct is_empty_detector { - static const/*expr*/ bool value = false; -}; -template struct is_empty : bool_constant::value> {}; - -template struct is_array : false_type {}; -template struct is_array : true_type {}; -template struct is_array : true_type {}; +template using remove_const_t = typename std::remove_const::type; +template using remove_volatile_t = typename std::remove_volatile::type; +template using remove_cv_t = typename std::remove_cv::type; +template using remove_pointer_t = typename std::remove_pointer::type; +template using remove_reference_t = typename std::remove_reference::type; +template using remove_extent_t = typename std::remove_extent::type; // template struct is_function< -// R [calling-convention] (Args...[, ...]) [const] [volatile] [&|&&]> : true_type {}; +// R [calling-convention] (Args...[, ...]) [const] [volatile] [&|&&]> : std::true_type {}; // The cv and ref-qualified versions are strange types we're currently avoiding, so not supported. +// These aren't supported in msvc either until vs2015u2. // On all platforms, variadic functions only exist in the c calling convention. -template struct is_function : false_type { }; +// mcvc 2013 introduced __vectorcall, but it wan't until 2015 that it was added to is_function. +template struct is_function : std::false_type {}; #if !defined(SK_BUILD_FOR_WIN) -template struct is_function : true_type {}; +template struct is_function : std::true_type {}; #else -template struct is_function : true_type {}; +template struct is_function : std::true_type {}; #if defined(_M_IX86) -template struct is_function : true_type {}; -template struct is_function : true_type {}; +template struct is_function : std::true_type {}; +template struct is_function : std::true_type {}; #endif #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 -template struct is_function : true_type {}; +template struct is_function : std::true_type {}; #endif #endif -template struct is_function : true_type {}; +template struct is_function : std::true_type {}; -template struct add_const { using type = const T; }; -template using add_const_t = typename add_const::type; +template using add_const_t = typename std::add_const::type; +template using add_volatile_t = typename std::add_volatile::type; +template using add_cv_t = typename std::add_cv::type; +template using add_pointer_t = typename std::add_pointer::type; +template using add_lvalue_reference_t = typename std::add_lvalue_reference::type; -template struct add_volatile { using type = volatile T; }; -template using add_volatile_t = typename add_volatile::type; - -template struct add_cv { using type = add_volatile_t>; }; -template using add_cv_t = typename add_cv::type; - -template struct add_pointer { using type = remove_reference_t*; }; -template using add_pointer_t = typename add_pointer::type; - -template ::value> struct add_lvalue_reference_init { using type = T; }; -template struct add_lvalue_reference_init { using type = T&; }; -template struct add_lvalue_reference : add_lvalue_reference_init { }; -template using add_lvalue_reference_t = typename add_lvalue_reference::type; - -template ::value> struct add_rvalue_reference_init { using type = T; }; -template struct add_rvalue_reference_init { using type = T&&; }; -template struct add_rvalue_reference : add_rvalue_reference_init {}; -template using add_rvalue_reference_t = typename add_rvalue_reference::type; - -/* This is 'just' a forward declaration. */ -template add_rvalue_reference_t declval() /*noexcept*/; - -template ::value||is_function::value||is_array::value> +template ::value || is_function::value || std::is_array::value> struct is_convertible_detector { - static const/*expr*/ bool value = is_void::value; + static const/*expr*/ bool value = std::is_void::value; }; template struct is_convertible_detector { using yes_type = uint8_t; @@ -166,22 +118,16 @@ template struct is_convertible_detector { template static void param_convertable_to(To); template - static decltype(param_convertable_to(declval()), yes_type()) convertible(int); + static decltype(param_convertable_to(std::declval()), yes_type()) convertible(int); template static no_type convertible(...); static const/*expr*/ bool value = sizeof(convertible(0)) == sizeof(yes_type); }; +// std::is_convertable is known to be broken (not work with incomplete types) in Android clang NDK. +// This is currently what prevents us from using std::unique_ptr. template struct is_convertible - : bool_constant::value> { }; - -template struct decay { - using U = remove_reference_t; - using type = conditional_t::value, - remove_extent_t*, - conditional_t::value, add_pointer_t, remove_cv_t>>; -}; -template using decay_t = typename decay::type; + : bool_constant::value> {}; } // namespace skstd @@ -193,12 +139,12 @@ namespace sknonstd { // std::experimental::propagate_const already exists for other purposes in TSv2. // These also follow the pattern used by boost. template struct copy_const { - using type = skstd::conditional_t::value, skstd::add_const_t, D>; + using type = skstd::conditional_t::value, skstd::add_const_t, D>; }; template using copy_const_t = typename copy_const::type; template struct copy_volatile { - using type = skstd::conditional_t::value, skstd::add_volatile_t, D>; + using type = skstd::conditional_t::value, skstd::add_volatile_t, D>; }; template using copy_volatile_t = typename copy_volatile::type; @@ -219,6 +165,8 @@ template using same_cv_t = typename same_cv::type } // namespace sknonstd +#endif /* MOZ_SKIA */ + // Just a pithier wrapper for enable_if_t. #define SK_WHEN(condition, T) skstd::enable_if_t diff --git a/gfx/skia/skia/include/core/SkTSearch.h b/gfx/skia/skia/include/private/SkTSearch.h similarity index 100% rename from gfx/skia/skia/include/core/SkTSearch.h rename to gfx/skia/skia/include/private/SkTSearch.h diff --git a/gfx/skia/skia/include/private/SkTemplates.h b/gfx/skia/skia/include/private/SkTemplates.h index 533cb264d16..81e23906e2d 100644 --- a/gfx/skia/skia/include/private/SkTemplates.h +++ b/gfx/skia/skia/include/private/SkTemplates.h @@ -14,7 +14,6 @@ #include "SkTLogic.h" #include "SkTypes.h" #include "SkUniquePtr.h" -#include "SkUtility.h" #include #include @@ -43,7 +42,7 @@ template static D* SkTAfter(S* ptr, size_t count = 1) { template static D* SkTAddOffset(S* ptr, size_t byteOffset) { // The intermediate char* has the same cv-ness as D as this produces better error messages. // This relies on the fact that reinterpret_cast can add constness, but cannot remove it. - return reinterpret_cast(reinterpret_cast*>(ptr) + byteOffset); + return reinterpret_cast((char*)(ptr) + byteOffset); } template struct SkFunctionWrapper { @@ -272,9 +271,10 @@ public: } /** Resize the memory area pointed to by the current ptr without preserving contents. */ - void reset(size_t count) { + T* reset(size_t count) { sk_free(fPtr); fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW); + return fPtr; } T* get() const { return fPtr; } @@ -295,6 +295,13 @@ public: return fPtr[index]; } + /** + * Releases the block back to the heap + */ + void free() { + this->reset(0); + } + /** * Transfer ownership of the ptr to the caller, setting the internal * pointer to NULL. Note that this differs from get(), which also returns diff --git a/gfx/skia/skia/include/private/SkUniquePtr.h b/gfx/skia/skia/include/private/SkUniquePtr.h index 289dc7d3448..43ce3172f0d 100644 --- a/gfx/skia/skia/include/private/SkUniquePtr.h +++ b/gfx/skia/skia/include/private/SkUniquePtr.h @@ -9,8 +9,19 @@ #define SkUniquePtr_DEFINED #include "SkTLogic.h" -#include "SkUtility.h" +#include +#include +#ifdef MOZ_SKIA +#include "mozilla/UniquePtr.h" + +namespace skstd { + using mozilla::DefaultDelete; + using mozilla::UniquePtr; + #define default_delete DefaultDelete + #define unique_ptr UniquePtr +} +#else namespace skstd { template struct default_delete { @@ -47,11 +58,11 @@ public: using deleter_type = D; private: - template + template ::value /*&& !is_final::value*/> struct compressed_base : private B { /*constexpr*/ compressed_base() : B() {} /*constexpr*/ compressed_base(const B& b) : B(b) {} - /*constexpr*/ compressed_base(const B&& b) : B(move(b)) {} + /*constexpr*/ compressed_base(B&& b) : B(std::move(b)) {} /*constexpr*/ B& get() /*noexcept*/ { return *this; } /*constexpr*/ B const& get() const /*noexcept*/ { return *this; } void swap(compressed_base&) /*noexcept*/ { } @@ -61,33 +72,31 @@ private: B fb; /*constexpr*/ compressed_base() : B() {} /*constexpr*/ compressed_base(const B& b) : fb(b) {} - /*constexpr*/ compressed_base(const B&& b) : fb(move(b)) {} + /*constexpr*/ compressed_base(B&& b) : fb(std::move(b)) {} /*constexpr*/ B& get() /*noexcept*/ { return fb; } /*constexpr*/ B const& get() const /*noexcept*/ { return fb; } void swap(compressed_base& that) /*noexcept*/ { SkTSwap(fb, that.fB); } }; - using compressed_deleter_type = compressed_base::value>; - - struct compressed_data : private compressed_deleter_type { + struct compressed_data : private compressed_base { pointer fPtr; - /*constexpr*/ compressed_data() : compressed_deleter_type(), fPtr() {} + /*constexpr*/ compressed_data() : compressed_base(), fPtr() {} /*constexpr*/ compressed_data(const pointer& ptr, const deleter_type& d) - : compressed_deleter_type(d), fPtr(ptr) {} + : compressed_base(d), fPtr(ptr) {} template ::value && is_convertible::value >> /*constexpr*/ compressed_data(U1&& ptr, U2&& d) - : compressed_deleter_type(skstd::forward(d)), fPtr(skstd::forward(ptr)) {} + : compressed_base(std::forward(d)), fPtr(std::forward(ptr)) {} /*constexpr*/ pointer& getPointer() /*noexcept*/ { return fPtr; } /*constexpr*/ pointer const& getPointer() const /*noexcept*/ { return fPtr; } /*constexpr*/ deleter_type& getDeleter() /*noexcept*/ { - return compressed_deleter_type::get(); + return compressed_base::get(); } /*constexpr*/ deleter_type const& getDeleter() const /*noexcept*/ { - return compressed_deleter_type::get(); + return compressed_base::get(); } void swap(compressed_data& that) /*noexcept*/ { - compressed_deleter_type::swap(static_cast(that)); + compressed_base::swap(static_cast>(that)); SkTSwap(fPtr, that.fPtr); } }; @@ -95,38 +104,41 @@ private: public: /*constexpr*/ unique_ptr() /*noexcept*/ : data() { - static_assert(!is_pointer::value, "Deleter is nullptr function pointer!"); + static_assert(!std::is_pointer::value, "Deleter nullptr function pointer!"); } - /*constexpr*/ unique_ptr(skstd::nullptr_t) /*noexcept*/ : unique_ptr() { } + /*constexpr*/ unique_ptr(std::nullptr_t) /*noexcept*/ : unique_ptr() { } explicit unique_ptr(pointer ptr) /*noexcept*/ : data(ptr, deleter_type()) { - static_assert(!is_pointer::value, "Deleter is nullptr function pointer!"); + static_assert(!std::is_pointer::value, "Deleter nullptr function pointer!"); } unique_ptr(pointer ptr, - conditional_t::value, deleter_type,const deleter_type&> d) + conditional_t::value, + deleter_type, const deleter_type&> d) /*noexcept*/ : data(ptr, d) {} unique_ptr(pointer ptr, remove_reference_t&& d) /*noexcept*/ - : data(move(ptr), move(d)) + : data(std::move(ptr), std::move(d)) { - static_assert(!is_reference::value, + static_assert(!std::is_reference::value, "Binding an rvalue reference deleter as an lvalue reference deleter is not allowed."); } unique_ptr(unique_ptr&& that) /*noexcept*/ - : data(that.release(), forward(that.get_deleter())) + : data(that.release(), std::forward(that.get_deleter())) {} template ::pointer, pointer>::value && - !is_array::value && - conditional_t::value, is_same, is_convertible>::value>> + !std::is_array::value && + conditional_t::value, + std::is_same, + is_convertible>::value>> unique_ptr(unique_ptr&& that) /*noexcept*/ - : data(that.release(), forward(that.get_deleter())) + : data(that.release(), std::forward(that.get_deleter())) {} ~unique_ptr() /*noexcept*/ { @@ -139,20 +151,20 @@ public: unique_ptr& operator=(unique_ptr&& that) /*noexcept*/ { reset(that.release()); - get_deleter() = forward(that.get_deleter()); + get_deleter() = std::forward(that.get_deleter()); return *this; } template enable_if_t< is_convertible::pointer, pointer>::value && - !is_array::value, + !std::is_array::value, unique_ptr&> operator=(unique_ptr&& that) /*noexcept*/ { reset(that.release()); - get_deleter() = forward(that.get_deleter()); + get_deleter() = std::forward(that.get_deleter()); return *this; } - unique_ptr& operator=(skstd::nullptr_t) /*noexcept*/ { + unique_ptr& operator=(std::nullptr_t) /*noexcept*/ { reset(); return *this; } @@ -219,11 +231,11 @@ public: using deleter_type = D; private: - template + template ::value /*&& !is_final::value*/> struct compressed_base : private B { /*constexpr*/ compressed_base() : B() {} /*constexpr*/ compressed_base(const B& b) : B(b) {} - /*constexpr*/ compressed_base(const B&& b) : B(move(b)) {} + /*constexpr*/ compressed_base(B&& b) : B(std::move(b)) {} /*constexpr*/ B& get() /*noexcept*/ { return *this; } /*constexpr*/ B const& get() const /*noexcept*/ { return *this; } void swap(compressed_base&) /*noexcept*/ { } @@ -233,33 +245,31 @@ private: B fb; /*constexpr*/ compressed_base() : B() {} /*constexpr*/ compressed_base(const B& b) : fb(b) {} - /*constexpr*/ compressed_base(const B&& b) : fb(move(b)) {} + /*constexpr*/ compressed_base(B&& b) : fb(std::move(b)) {} /*constexpr*/ B& get() /*noexcept*/ { return fb; } /*constexpr*/ B const& get() const /*noexcept*/ { return fb; } void swap(compressed_base& that) /*noexcept*/ { SkTSwap(fb, that.fB); } }; - using compressed_deleter_type = compressed_base::value>; - - struct compressed_data : private compressed_deleter_type { + struct compressed_data : private compressed_base { pointer fPtr; - /*constexpr*/ compressed_data() : compressed_deleter_type(), fPtr() {} + /*constexpr*/ compressed_data() : compressed_base(), fPtr() {} /*constexpr*/ compressed_data(const pointer& ptr, const deleter_type& d) - : compressed_deleter_type(d), fPtr(ptr) {} + : compressed_base(d), fPtr(ptr) {} template ::value && is_convertible::value >> /*constexpr*/ compressed_data(U1&& ptr, U2&& d) - : compressed_deleter_type(skstd::forward(d)), fPtr(skstd::forward(ptr)) {} + : compressed_base(std::forward(d)), fPtr(std::forward(ptr)) {} /*constexpr*/ pointer& getPointer() /*noexcept*/ { return fPtr; } /*constexpr*/ pointer const& getPointer() const /*noexcept*/ { return fPtr; } /*constexpr*/ deleter_type& getDeleter() /*noexcept*/ { - return compressed_deleter_type::get(); + return compressed_base::get(); } /*constexpr*/ deleter_type const& getDeleter() const /*noexcept*/ { - return compressed_deleter_type::get(); + return compressed_base::get(); } void swap(compressed_data& that) /*noexcept*/ { - compressed_deleter_type::swap(static_cast(that)); + compressed_base::swap(static_cast>(that)); SkTSwap(fPtr, that.fPtr); } }; @@ -267,29 +277,30 @@ private: public: /*constexpr*/ unique_ptr() /*noexcept*/ : data() { - static_assert(!is_pointer::value, "Deleter is nullptr function pointer!"); + static_assert(!std::is_pointer::value, "Deleter nullptr function pointer!"); } - /*constexpr*/ unique_ptr(skstd::nullptr_t) /*noexcept*/ : unique_ptr() { } + /*constexpr*/ unique_ptr(std::nullptr_t) /*noexcept*/ : unique_ptr() { } explicit unique_ptr(pointer ptr) /*noexcept*/ : data(ptr, deleter_type()) { - static_assert(!is_pointer::value, "Deleter is nullptr function pointer!"); + static_assert(!std::is_pointer::value, "Deleter nullptr function pointer!"); } unique_ptr(pointer ptr, - conditional_t::value, deleter_type,const deleter_type&> d) + conditional_t::value, + deleter_type, const deleter_type&> d) /*noexcept*/ : data(ptr, d) {} unique_ptr(pointer ptr, remove_reference_t&& d) /*noexcept*/ - : data(move(ptr), move(d)) + : data(std::move(ptr), std::move(d)) { - static_assert(!is_reference::value, + static_assert(!std::is_reference::value, "Binding an rvalue reference deleter as an lvalue reference deleter is not allowed."); } unique_ptr(unique_ptr&& that) /*noexcept*/ - : data(that.release(), forward(that.get_deleter())) + : data(that.release(), std::forward(that.get_deleter())) {} ~unique_ptr() { @@ -302,11 +313,11 @@ public: unique_ptr& operator=(unique_ptr&& that) /*noexcept*/ { reset(that.release()); - get_deleter() = forward(that.get_deleter()); + get_deleter() = std::forward(that.get_deleter()); return *this; } - unique_ptr& operator=(skstd::nullptr_t) /*noexcept*/ { + unique_ptr& operator=(std::nullptr_t) /*noexcept*/ { reset(); return *this; } @@ -367,13 +378,13 @@ inline bool operator==(const unique_ptr& a, const unique_ptr& b) } template -inline bool operator==(const unique_ptr& a, skstd::nullptr_t) /*noexcept*/ { +inline bool operator==(const unique_ptr& a, std::nullptr_t) /*noexcept*/ { //return !a; return !a.is_attached(); } template -inline bool operator==(skstd::nullptr_t, const unique_ptr& b) /*noexcept*/ { +inline bool operator==(std::nullptr_t, const unique_ptr& b) /*noexcept*/ { //return !b; return !b.is_attached(); } @@ -384,17 +395,18 @@ inline bool operator!=(const unique_ptr& a, const unique_ptr& b) } template -inline bool operator!=(const unique_ptr& a, skstd::nullptr_t) /*noexcept*/ { +inline bool operator!=(const unique_ptr& a, std::nullptr_t) /*noexcept*/ { //return (bool)a; return a.is_attached(); } template -inline bool operator!=(skstd::nullptr_t, const unique_ptr& b) /*noexcept*/ { +inline bool operator!=(std::nullptr_t, const unique_ptr& b) /*noexcept*/ { //return (bool)b; return b.is_attached(); } } // namespace skstd +#endif #endif diff --git a/gfx/skia/skia/include/private/SkUtility.h b/gfx/skia/skia/include/private/SkUtility.h deleted file mode 100644 index a96e8fe2926..00000000000 --- a/gfx/skia/skia/include/private/SkUtility.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkUtility_DEFINED -#define SkUtility_DEFINED - -#include "SkTLogic.h" - -namespace skstd { - -template inline remove_reference_t&& move(T&& t) { - return static_cast&&>(t); -} - -template inline T&& forward(remove_reference_t& t) /*noexcept*/ { - return static_cast(t); -} -template inline T&& forward(remove_reference_t&& t) /*noexcept*/ { - static_assert(!is_lvalue_reference::value, - "Forwarding an rvalue reference as an lvalue reference is not allowed."); - return static_cast(t); -} - -template add_rvalue_reference_t declval(); - -} // namespace skstd - -#endif diff --git a/gfx/skia/skia/include/svg/parser/SkSVGParser.h b/gfx/skia/skia/include/svg/parser/SkSVGParser.h index bb3ab905178..9a5c4157b18 100644 --- a/gfx/skia/skia/include/svg/parser/SkSVGParser.h +++ b/gfx/skia/skia/include/svg/parser/SkSVGParser.h @@ -11,7 +11,7 @@ #define SkSVGParser_DEFINED #include "SkMatrix.h" -#include "SkTDict.h" +#include "../private/SkTDict.h" #include "SkSVGPaintState.h" #include "SkSVGTypes.h" #include "SkStream.h" diff --git a/gfx/skia/skia/include/utils/SkCubicInterval.h b/gfx/skia/skia/include/utils/SkCubicInterval.h deleted file mode 100644 index 64d63cf2cdb..00000000000 --- a/gfx/skia/skia/include/utils/SkCubicInterval.h +++ /dev/null @@ -1,22 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkCubicInterval_DEFINED -#define SkCubicInterval_DEFINED - -#include "SkPoint.h" - -SkScalar SkEvalCubicInterval(SkScalar x1, SkScalar y1, - SkScalar x2, SkScalar y2, - SkScalar unitX); - -static inline SkScalar SkEvalCubicInterval(const SkPoint pts[2], SkScalar x) { - return SkEvalCubicInterval(pts[0].fX, pts[0].fY, - pts[1].fX, pts[1].fY, x); -} - -#endif diff --git a/gfx/skia/skia/include/utils/SkCullPoints.h b/gfx/skia/skia/include/utils/SkCullPoints.h deleted file mode 100644 index fafa0fc0858..00000000000 --- a/gfx/skia/skia/include/utils/SkCullPoints.h +++ /dev/null @@ -1,71 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkCullPoints_DEFINED -#define SkCullPoints_DEFINED - -#include "SkRect.h" - -class SkCullPoints { -public: - SkCullPoints(); - SkCullPoints(const SkIRect& r); - - void reset(const SkIRect& r); - - /** Start a contour at (x,y). Follow this with call(s) to lineTo(...) - */ - void moveTo(int x, int y); - - enum LineToResult { - kNo_Result, //!< line segment was completely clipped out - kLineTo_Result, //!< path.lineTo(pts[1]); - kMoveToLineTo_Result //!< path.moveTo(pts[0]); path.lineTo(pts[1]); - }; - /** Connect a line to the previous call to lineTo (or moveTo). - */ - LineToResult lineTo(int x, int y, SkIPoint pts[2]); - -private: - SkIRect fR; // the caller's rectangle - SkIPoint fAsQuad[4]; // cache of fR as 4 points - SkIPoint fPrevPt; // private state - LineToResult fPrevResult; // private state - - bool sect_test(int x0, int y0, int x1, int y1) const; -}; - -///////////////////////////////////////////////////////////////////////////////// - -class SkPath; - -/** \class SkCullPointsPath - - Similar to SkCullPoints, but this class handles the return values - from lineTo, and automatically builds a SkPath with the result(s). -*/ -class SkCullPointsPath { -public: - SkCullPointsPath(); - SkCullPointsPath(const SkIRect& r, SkPath* dst); - - void reset(const SkIRect& r, SkPath* dst); - - void moveTo(int x, int y); - void lineTo(int x, int y); - -private: - SkCullPoints fCP; - SkPath* fPath; -}; - -bool SkHitTestPath(const SkPath&, SkRect& target, bool hires); -bool SkHitTestPath(const SkPath&, SkScalar x, SkScalar y, bool hires); - -#endif diff --git a/gfx/skia/skia/include/utils/SkDumpCanvas.h b/gfx/skia/skia/include/utils/SkDumpCanvas.h index b853ba686b0..d4c6dbf81b6 100644 --- a/gfx/skia/skia/include/utils/SkDumpCanvas.h +++ b/gfx/skia/skia/include/utils/SkDumpCanvas.h @@ -73,7 +73,7 @@ public: protected: void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; void willRestore() override; void didConcat(const SkMatrix&) override; @@ -108,7 +108,6 @@ protected: const SkPaint*, SrcRectConstraint) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; void onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, diff --git a/gfx/skia/skia/include/utils/SkInterpolator.h b/gfx/skia/skia/include/utils/SkInterpolator.h index 18203d05d06..e062b38f65d 100644 --- a/gfx/skia/skia/include/utils/SkInterpolator.h +++ b/gfx/skia/skia/include/utils/SkInterpolator.h @@ -59,7 +59,7 @@ public: fFlags = SkToU8((fFlags & ~kReset) | (int)reset); } - Result timeToT(SkMSec time, SkScalar* T, int* index, SkBool* exact) const; + Result timeToT(SkMSec time, SkScalar* T, int* index, bool* exact) const; protected: enum Flags { @@ -121,8 +121,15 @@ private: typedef SkInterpolatorBase INHERITED; }; -/** Given all the parameters are [0...1], apply the cubic specified by (0,0) - (bx,by) (cx,cy) (1,1) to value, returning the answer, also [0...1]. +/** Interpolate a cubic curve, typically to provide an ease-in ease-out transition. + All the parameters are in the range of [0...1]. + The input value is treated as the x-coordinate of the cubic. + The output value is the y-coordinate on the cubic at the x-coordinate. + + @param value The x-coordinate pinned between [0..1]. + @param bx,by,cx,cy The cubic control points where the cubic is specified + as (0,0) (bx,by) (cx,cy) (1,1) + @return the corresponding y-coordinate value, from [0..1]. */ SkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by, SkScalar cx, SkScalar cy); diff --git a/gfx/skia/skia/include/utils/SkLuaCanvas.h b/gfx/skia/skia/include/utils/SkLuaCanvas.h index f07af0695bf..37e82be51dc 100644 --- a/gfx/skia/skia/include/utils/SkLuaCanvas.h +++ b/gfx/skia/skia/include/utils/SkLuaCanvas.h @@ -22,7 +22,7 @@ public: protected: void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; void willRestore() override; void didConcat(const SkMatrix&) override; @@ -54,7 +54,6 @@ protected: const SkPaint*, SrcRectConstraint) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; void onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, diff --git a/gfx/skia/skia/include/utils/SkNWayCanvas.h b/gfx/skia/skia/include/utils/SkNWayCanvas.h index a60836be574..8d824d7e2c2 100644 --- a/gfx/skia/skia/include/utils/SkNWayCanvas.h +++ b/gfx/skia/skia/include/utils/SkNWayCanvas.h @@ -30,7 +30,7 @@ protected: SkTDArray fList; void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; void willRestore() override; void didConcat(const SkMatrix&) override; @@ -65,7 +65,6 @@ protected: const SkPaint*, SrcRectConstraint) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; void onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, diff --git a/gfx/skia/skia/include/utils/SkNoSaveLayerCanvas.h b/gfx/skia/skia/include/utils/SkNoSaveLayerCanvas.h index 0cebefff18b..3d786c532c2 100644 --- a/gfx/skia/skia/include/utils/SkNoSaveLayerCanvas.h +++ b/gfx/skia/skia/include/utils/SkNoSaveLayerCanvas.h @@ -21,9 +21,8 @@ public: {} protected: - virtual SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint* paint, - SaveFlags flags) override { - this->INHERITED::willSaveLayer(bounds, paint, flags); + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override { + (void)this->INHERITED::getSaveLayerStrategy(rec); return kNoLayer_SaveLayerStrategy; } diff --git a/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h b/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h index d693758797c..909cf3b987d 100644 --- a/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h +++ b/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h @@ -9,10 +9,11 @@ #define SkPaintFilterCanvas_DEFINED #include "SkNWayCanvas.h" +#include "SkTLazy.h" /** \class SkPaintFilterCanvas - A utility proxy base class for implementing paint filters. + A utility proxy base class for implementing draw/paint filters. */ class SK_API SkPaintFilterCanvas : public SkNWayCanvas { public: @@ -48,13 +49,16 @@ public: protected: /** * Called with the paint that will be used to draw the specified type. - * The implementation may modify the paint as they wish. + * The implementation may modify the paint as they wish (using SkTCopyOnFirstWrite::writable). * - * Note: The base implementation calls onFilterPaint() for top-level/explicit paints only. + * The result bool is used to determine whether the draw op is to be + * executed (true) or skipped (false). + * + * Note: The base implementation calls onFilter() for top-level/explicit paints only. * To also filter encapsulated paints (e.g. SkPicture, SkTextBlob), clients may need to * override the relevant methods (i.e. drawPicture, drawTextBlob). */ - virtual void onFilterPaint(SkPaint* paint, Type type) const = 0; + virtual bool onFilter(SkTCopyOnFirstWrite* paint, Type type) const = 0; void onDrawPaint(const SkPaint&) override; void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; @@ -66,12 +70,13 @@ protected: void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, SrcRectConstraint) override; + void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint*, SrcRectConstraint) override; - void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, - const SkPaint*) override; - void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; + void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; void onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, diff --git a/gfx/skia/skia/include/utils/SkRTConf.h b/gfx/skia/skia/include/utils/SkRTConf.h index dc95cdbadbb..6c7963c64e6 100644 --- a/gfx/skia/skia/include/utils/SkRTConf.h +++ b/gfx/skia/skia/include/utils/SkRTConf.h @@ -9,11 +9,10 @@ #ifndef SkRTConf_DEFINED #define SkRTConf_DEFINED +#include "SkTArray.h" #include "SkString.h" #include "SkStream.h" - -#include "SkTDict.h" -#include "SkTArray.h" +#include "../private/SkTDict.h" /** \class SkRTConfBase Non-templated base class for the runtime configs diff --git a/gfx/skia/skia/include/utils/win/SkHRESULT.h b/gfx/skia/skia/include/utils/win/SkHRESULT.h index a6cc1d21b9d..a0ffd5935cd 100644 --- a/gfx/skia/skia/include/utils/win/SkHRESULT.h +++ b/gfx/skia/skia/include/utils/win/SkHRESULT.h @@ -17,7 +17,7 @@ void SkTraceHR(const char* file, unsigned long line, #ifdef SK_DEBUG #define SK_TRACEHR(_hr, _msg) SkTraceHR(__FILE__, __LINE__, _hr, _msg) #else -#define SK_TRACEHR(_hr, _msg) _hr +#define SK_TRACEHR(_hr, _msg) sk_ignore_unused_variable(_hr) #endif #define HR_GENERAL(_ex, _msg, _ret) {\ diff --git a/gfx/skia/skia/include/views/SkOSWindow_SDL.h b/gfx/skia/skia/include/views/SkOSWindow_SDL.h index c40ec2e301f..e08108add45 100644 --- a/gfx/skia/skia/include/views/SkOSWindow_SDL.h +++ b/gfx/skia/skia/include/views/SkOSWindow_SDL.h @@ -14,16 +14,11 @@ class SkOSWindow : public SkWindow { public: - SkOSWindow(void* screen); + SkOSWindow(void*); virtual ~SkOSWindow(); - static bool PostEvent(SkEvent* evt, SkEventSinkID, SkMSec delay) { - SkFAIL("not implemented\n"); - return false; - } - enum SkBackEndTypes { - kNone_BackEndType, + kNone_BackEndType, // TODO: remove this, it's not a real option. kNativeGL_BackEndType, #if SK_ANGLE kANGLE_BackEndType, @@ -39,25 +34,23 @@ public: bool makeFullscreen(); void setVsync(bool); void closeWindow(); - void loop() { - while (!fQuit) { - this->handleEvents(); - this->update(nullptr); - } - } + static void RunEventLoop(); protected: void onSetTitle(const char title[]) override; - void onHandleInval(const SkIRect&) override; - void onPDFSaved(const char title[], const char desc[], const char path[]) override; private: - void handleEvents(); - bool fQuit; - uint32_t fWindowFlags; + void createWindow(int msaaSampleCount); + void destroyWindow(); + void updateWindowTitle(); + static SkOSWindow* GetInstanceForWindowID(Uint32 windowID); + static bool HasDirtyWindows(); + static void UpdateDirtyWindows(); + static void HandleEvent(const SDL_Event&); + SDL_Window* fWindow; SDL_GLContext fGLContext; - + int fWindowMSAASampleCount; typedef SkWindow INHERITED; }; diff --git a/gfx/skia/skia/include/utils/SkParsePaint.h b/gfx/skia/skia/include/views/SkParsePaint.h similarity index 100% rename from gfx/skia/skia/include/utils/SkParsePaint.h rename to gfx/skia/skia/include/views/SkParsePaint.h diff --git a/gfx/skia/skia/include/views/SkView.h b/gfx/skia/skia/include/views/SkView.h index e099e0d405a..17eb3800f47 100644 --- a/gfx/skia/skia/include/views/SkView.h +++ b/gfx/skia/skia/include/views/SkView.h @@ -13,7 +13,7 @@ #include "SkEventSink.h" #include "SkRect.h" #include "SkDOM.h" -#include "SkTDict.h" +#include "../private/SkTDict.h" #include "SkMatrix.h" #include "SkMetaData.h" diff --git a/gfx/skia/skia/include/views/SkViewInflate.h b/gfx/skia/skia/include/views/SkViewInflate.h index db3689a8272..4ec36a67dff 100644 --- a/gfx/skia/skia/include/views/SkViewInflate.h +++ b/gfx/skia/skia/include/views/SkViewInflate.h @@ -11,7 +11,7 @@ #define SkViewInflate_DEFINED #include "SkDOM.h" -#include "SkTDict.h" +#include "../private/SkTDict.h" #include "SkEvent.h" class SkView; diff --git a/gfx/skia/skia/src/android/SkBitmapRegionCanvas.cpp b/gfx/skia/skia/src/android/SkBitmapRegionCanvas.cpp index bac5dc1ffc7..c7c42bd9a25 100644 --- a/gfx/skia/skia/src/android/SkBitmapRegionCanvas.cpp +++ b/gfx/skia/skia/src/android/SkBitmapRegionCanvas.cpp @@ -18,6 +18,7 @@ SkBitmapRegionCanvas::SkBitmapRegionCanvas(SkCodec* decoder) bool SkBitmapRegionCanvas::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator, const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType, bool requireUnpremul) { + // Reject color types not supported by this method if (kIndex_8_SkColorType == dstColorType || kGray_8_SkColorType == dstColorType) { SkCodecPrintf("Error: Color type not supported.\n"); @@ -34,8 +35,6 @@ bool SkBitmapRegionCanvas::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* alloca dstAlphaType = kPremul_SkAlphaType; } - // FIXME: Can we add checks and support kIndex8 or unpremultiplied alpha in special cases? - // Fix the input sampleSize if necessary. if (sampleSize < 1) { sampleSize = 1; diff --git a/gfx/skia/skia/src/android/SkBitmapRegionCanvas.h b/gfx/skia/skia/src/android/SkBitmapRegionCanvas.h index 2edbf1ff3bd..c01f96be3c4 100644 --- a/gfx/skia/skia/src/android/SkBitmapRegionCanvas.h +++ b/gfx/skia/skia/src/android/SkBitmapRegionCanvas.h @@ -14,8 +14,16 @@ * an SkCanvas. It uses the scanline decoder to subset the height. It then * will subset the width and scale by drawing to an SkCanvas. */ -// FIXME (msarett): This implementation does not support WEBP, because WEBP -// does not have a scanline decoder. +// FIXME: This class works well as a performance/quality comparison for +// SkBitmapRegionCodec, but it lacks several capabilities that are +// required by BitmapRegionDecoder in Android. +// (1) WEBP decodes - because SkWebpCodec does not have a scanline +// decoder. +// (2) Decodes to kGray8 and kIndex8. +// (3) Decodes to kUnpremul. +// (4) Correcting an invalid dstColorType. For example, if the +// client requests kRGB_565 for a non-opaque image, rather than +// fail, we need to go ahead and decode to kN32. class SkBitmapRegionCanvas : public SkBitmapRegionDecoder { public: diff --git a/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp b/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp index 415b60c5ab3..be3d5bcce71 100644 --- a/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp +++ b/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp @@ -17,7 +17,7 @@ SkBitmapRegionCodec::SkBitmapRegionCodec(SkAndroidCodec* codec) {} bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator, - const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType, + const SkIRect& desiredSubset, int sampleSize, SkColorType prefColorType, bool requireUnpremul) { // Fix the input sampleSize if necessary. @@ -50,10 +50,8 @@ bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocat SkISize scaledSize = fCodec->getSampledSubsetDimensions(sampleSize, subset); // Create the image info for the decode - SkAlphaType dstAlphaType = fCodec->getInfo().alphaType(); - if (kOpaque_SkAlphaType != dstAlphaType) { - dstAlphaType = requireUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType; - } + SkColorType dstColorType = fCodec->computeOutputColorType(prefColorType); + SkAlphaType dstAlphaType = fCodec->computeOutputAlphaType(requireUnpremul); SkImageInfo decodeInfo = SkImageInfo::Make(scaledSize.width(), scaledSize.height(), dstColorType, dstAlphaType); @@ -94,6 +92,13 @@ bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocat scaledOutHeight += scaledOutY + scaledExtraY; } SkImageInfo outInfo = decodeInfo.makeWH(scaledOutWidth, scaledOutHeight); + if (kGray_8_SkColorType == dstColorType) { + // The legacy implementations of BitmapFactory and BitmapRegionDecoder + // used kAlpha8 for grayscale images (before kGray8 existed). While + // the codec recognizes kGray8, we need to decode into a kAlpha8 + // bitmap in order to avoid a behavior change. + outInfo = SkImageInfo::MakeA8(scaledOutWidth, scaledOutHeight); + } bitmap->setInfo(outInfo); if (!bitmap->tryAllocPixels(allocator, colorTable.get())) { SkCodecPrintf("Error: Could not allocate pixels.\n"); diff --git a/gfx/skia/skia/src/animator/SkDisplayType.h b/gfx/skia/skia/src/animator/SkDisplayType.h index 474a65e8e60..8ffcd75feaa 100644 --- a/gfx/skia/skia/src/animator/SkDisplayType.h +++ b/gfx/skia/skia/src/animator/SkDisplayType.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,13 +5,14 @@ * found in the LICENSE file. */ - #ifndef SkDisplayType_DEFINED #define SkDisplayType_DEFINED #include "SkMath.h" #include "SkScalar.h" +typedef int SkBool; + #ifdef SK_DEBUG #define SK_DUMP_ENABLED #ifdef SK_BUILD_FOR_MAC diff --git a/gfx/skia/skia/src/animator/SkDisplayTypes.h b/gfx/skia/skia/src/animator/SkDisplayTypes.h index 07e8448a4c8..c24091f3989 100644 --- a/gfx/skia/skia/src/animator/SkDisplayTypes.h +++ b/gfx/skia/skia/src/animator/SkDisplayTypes.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,7 +5,6 @@ * found in the LICENSE file. */ - #ifndef SkDisplayTypes_DEFINED #define SkDisplayTypes_DEFINED diff --git a/gfx/skia/skia/src/animator/SkMemberInfo.h b/gfx/skia/skia/src/animator/SkMemberInfo.h index b62de663d49..709d66ac84f 100644 --- a/gfx/skia/skia/src/animator/SkMemberInfo.h +++ b/gfx/skia/skia/src/animator/SkMemberInfo.h @@ -18,6 +18,7 @@ #include "SkScript.h" #include "SkString.h" #include "SkIntArray.h" +#include class SkAnimateMaker; class SkDisplayable; @@ -111,11 +112,11 @@ struct SkMemberInfo { #define SK_MEMBER(_member, _type) \ { #_member, SK_OFFSETOF(BASE_CLASS, _member), SkType_##_type, \ - sizeof(skstd::declval()._member) / sizeof(SkScalar) } + sizeof(std::declval()._member) / sizeof(SkScalar) } #define SK_MEMBER_ALIAS(_member, _alias, _type) \ { #_member, SK_OFFSETOF(BASE_CLASS, _alias), SkType_##_type, \ - sizeof(skstd::declval()._alias) / sizeof(SkScalar) } + sizeof(std::declval()._alias) / sizeof(SkScalar) } #define SK_MEMBER_ARRAY(_member, _type) \ { #_member, SK_OFFSETOF(BASE_CLASS, _member), SkType_Array, \ diff --git a/gfx/skia/skia/src/animator/SkOperandIterpolator.cpp b/gfx/skia/skia/src/animator/SkOperandIterpolator.cpp index e6973e29f78..89ac44dea23 100644 --- a/gfx/skia/skia/src/animator/SkOperandIterpolator.cpp +++ b/gfx/skia/skia/src/animator/SkOperandIterpolator.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,7 +5,6 @@ * found in the LICENSE file. */ - #include "SkOperandInterpolator.h" #include "SkScript.h" @@ -60,7 +58,7 @@ SkInterpolatorBase::Result SkOperandInterpolator::timeToValues(SkMSec time, SkOp { SkScalar T; int index; - SkBool exact; + bool exact; Result result = timeToT(time, &T, &index, &exact); if (values) { diff --git a/gfx/skia/skia/src/animator/SkScript.h b/gfx/skia/skia/src/animator/SkScript.h index aa8d9a30c8a..074d10c3cc6 100644 --- a/gfx/skia/skia/src/animator/SkScript.h +++ b/gfx/skia/skia/src/animator/SkScript.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,7 +5,6 @@ * found in the LICENSE file. */ - #ifndef SkScript_DEFINED #define SkScript_DEFINED diff --git a/gfx/skia/skia/src/animator/SkScript2.h b/gfx/skia/skia/src/animator/SkScript2.h index d182e8c7c5d..f257adb4503 100644 --- a/gfx/skia/skia/src/animator/SkScript2.h +++ b/gfx/skia/skia/src/animator/SkScript2.h @@ -1,13 +1,14 @@ - /* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ + #ifndef SkScript2_DEFINED #define SkScript2_DEFINED +#include "SkDisplayType.h" #include "SkOperand2.h" #include "SkStream.h" #include "SkTDArray.h" diff --git a/gfx/skia/skia/src/animator/SkTime.cpp b/gfx/skia/skia/src/animator/SkTime.cpp index 560ccd2fc86..4ee60bf39d1 100644 --- a/gfx/skia/skia/src/animator/SkTime.cpp +++ b/gfx/skia/skia/src/animator/SkTime.cpp @@ -4,49 +4,3 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - -#include "SkTime.h" - -#ifdef SK_BUILD_FOR_WIN - -#ifdef SK_DEBUG -SkMSec gForceTickCount = (SkMSec) -1; -#endif - -void SkTime::GetDateTime(DateTime* t) { - if (t) { - SYSTEMTIME syst; - - ::GetLocalTime(&syst); - t->fYear = SkToU16(syst.wYear); - t->fMonth = SkToU8(syst.wMonth); - t->fDayOfWeek = SkToU8(syst.wDayOfWeek); - t->fDay = SkToU8(syst.wDay); - t->fHour = SkToU8(syst.wHour); - t->fMinute = SkToU8(syst.wMinute); - t->fSecond = SkToU8(syst.wSecond); - } -} - -#elif defined(xSK_BUILD_FOR_MAC) - -#include - -void SkTime::GetDateTime(DateTime* t) { - if (t) { - tm syst; - time_t tm; - - time(&tm); - localtime_r(&tm, &syst); - t->fYear = SkToU16(syst.tm_year); - t->fMonth = SkToU8(syst.tm_mon + 1); - t->fDayOfWeek = SkToU8(syst.tm_wday); - t->fDay = SkToU8(syst.tm_mday); - t->fHour = SkToU8(syst.tm_hour); - t->fMinute = SkToU8(syst.tm_min); - t->fSecond = SkToU8(syst.tm_sec); - } -} - -#endif diff --git a/gfx/skia/skia/src/codec/SkAndroidCodec.cpp b/gfx/skia/skia/src/codec/SkAndroidCodec.cpp index cf6e253d97e..d309d58501a 100644 --- a/gfx/skia/skia/src/codec/SkAndroidCodec.cpp +++ b/gfx/skia/skia/src/codec/SkAndroidCodec.cpp @@ -16,8 +16,9 @@ static bool is_valid_sample_size(int sampleSize) { return sampleSize > 0; } -SkAndroidCodec::SkAndroidCodec(const SkImageInfo& info) - : fInfo(info) +SkAndroidCodec::SkAndroidCodec(SkCodec* codec) + : fInfo(codec->getInfo()) + , fCodec(codec) {} SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) { @@ -34,11 +35,9 @@ SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader case kWBMP_SkEncodedFormat: case kBMP_SkEncodedFormat: case kGIF_SkEncodedFormat: + case kICO_SkEncodedFormat: return new SkSampledCodec(codec.detach()); default: - // FIXME: SkSampledCodec is temporarily disabled for other formats - // while focusing on the formats that are supported by - // BitmapRegionDecoder. return nullptr; } } @@ -51,6 +50,59 @@ SkAndroidCodec* SkAndroidCodec::NewFromData(SkData* data, SkPngChunkReader* chun return NewFromStream(new SkMemoryStream(data), chunkReader); } +SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorType) { + // The legacy GIF and WBMP decoders always decode to kIndex_8_SkColorType. + // We will maintain this behavior. + SkEncodedFormat format = this->getEncodedFormat(); + if (kGIF_SkEncodedFormat == format || kWBMP_SkEncodedFormat == format) { + return kIndex_8_SkColorType; + } + + SkColorType suggestedColorType = this->getInfo().colorType(); + switch (requestedColorType) { + case kARGB_4444_SkColorType: + case kN32_SkColorType: + return kN32_SkColorType; + case kIndex_8_SkColorType: + if (kIndex_8_SkColorType == suggestedColorType) { + return kIndex_8_SkColorType; + } + break; + case kAlpha_8_SkColorType: + // Fall through to kGray_8. Before kGray_8_SkColorType existed, + // we allowed clients to request kAlpha_8 when they wanted a + // grayscale decode. + case kGray_8_SkColorType: + if (kGray_8_SkColorType == suggestedColorType) { + return kGray_8_SkColorType; + } + break; + case kRGB_565_SkColorType: + if (kOpaque_SkAlphaType == this->getInfo().alphaType()) { + return kRGB_565_SkColorType; + } + break; + default: + break; + } + + // Android has limited support for kGray_8 (using kAlpha_8). We will not + // use kGray_8 for Android unless they specifically ask for it. + if (kGray_8_SkColorType == suggestedColorType) { + return kN32_SkColorType; + } + + // This may be kN32_SkColorType or kIndex_8_SkColorType. + return suggestedColorType; +} + +SkAlphaType SkAndroidCodec::computeOutputAlphaType(bool requestedUnpremul) { + if (kOpaque_SkAlphaType == this->getInfo().alphaType()) { + return kOpaque_SkAlphaType; + } + return requestedUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType; +} + SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const { if (!is_valid_sample_size(sampleSize)) { return SkISize::Make(0, 0); diff --git a/gfx/skia/skia/src/codec/SkBmpCodec.cpp b/gfx/skia/skia/src/codec/SkBmpCodec.cpp index 191c2ad8009..3302e4f752e 100644 --- a/gfx/skia/skia/src/codec/SkBmpCodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpCodec.cpp @@ -56,12 +56,10 @@ enum BmpInputFormat { /* * Checks the start of the stream to see if the image is a bitmap */ -bool SkBmpCodec::IsBmp(SkStream* stream) { +bool SkBmpCodec::IsBmp(const void* buffer, size_t bytesRead) { // TODO: Support "IC", "PT", "CI", "CP", "BA" const char bmpSig[] = { 'B', 'M' }; - char buffer[sizeof(bmpSig)]; - return stream->read(buffer, sizeof(bmpSig)) == sizeof(bmpSig) && - !memcmp(buffer, bmpSig, sizeof(bmpSig)); + return bytesRead >= sizeof(bmpSig) && !memcmp(buffer, bmpSig, sizeof(bmpSig)); } /* @@ -481,6 +479,8 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { // Return the codec switch (inputFormat) { case kStandard_BmpInputFormat: + // We require streams to have a memory base for Bmp-in-Ico decodes. + SkASSERT(!inIco || nullptr != stream->getMemoryBase()); *codecOut = new SkBmpStandardCodec(imageInfo, stream, bitsPerPixel, numColors, bytesPerColor, offset - bytesRead, rowOrder, inIco); return true; @@ -548,19 +548,6 @@ int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const { return height - y - 1; } -/* - * Compute the number of colors in the color table - */ -uint32_t SkBmpCodec::computeNumColors(uint32_t numColors) { - // Zero is a default for maxColors - // Also set numColors to maxColors when it is too large - uint32_t maxColors = 1 << fBitsPerPixel; - if (numColors == 0 || numColors >= maxColors) { - return maxColors; - } - return numColors; -} - SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { if (!conversion_possible(dstInfo, this->getInfo())) { diff --git a/gfx/skia/skia/src/codec/SkBmpCodec.h b/gfx/skia/skia/src/codec/SkBmpCodec.h index 65662ff1f86..5d77ca3fc8e 100644 --- a/gfx/skia/skia/src/codec/SkBmpCodec.h +++ b/gfx/skia/skia/src/codec/SkBmpCodec.h @@ -20,11 +20,7 @@ */ class SkBmpCodec : public SkCodec { public: - - /* - * Checks the start of the stream to see if the image is a bmp - */ - static bool IsBmp(SkStream*); + static bool IsBmp(const void*, size_t); /* * Assumes IsBmp was called and returned true @@ -80,11 +76,6 @@ protected: */ int32_t getDstRow(int32_t y, int32_t height) const; - /* - * Compute the number of colors in the color table - */ - uint32_t computeNumColors(uint32_t numColors); - /* * Accessors used by subclasses */ diff --git a/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp b/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp index 4cee274ffec..b01012644bf 100644 --- a/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp @@ -21,7 +21,7 @@ SkBmpRLECodec::SkBmpRLECodec(const SkImageInfo& info, SkStream* stream, size_t RLEBytes) : INHERITED(info, stream, bitsPerPixel, rowOrder) , fColorTable(nullptr) - , fNumColors(this->computeNumColors(numColors)) + , fNumColors(numColors) , fBytesPerColor(bytesPerColor) , fOffset(offset) , fStreamBuffer(new uint8_t[RLEBytes]) @@ -82,9 +82,12 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, // access memory outside of our color table array. *numColors = maxColors; } + // Don't bother reading more than maxColors. + const uint32_t numColorsToRead = + fNumColors == 0 ? maxColors : SkTMin(fNumColors, maxColors); // Read the color table from the stream - colorBytes = fNumColors * fBytesPerColor; + colorBytes = numColorsToRead * fBytesPerColor; SkAutoTDeleteArray cBuffer(new uint8_t[colorBytes]); if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) { SkCodecPrintf("Error: unable to read color table.\n"); @@ -93,7 +96,7 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, // Fill in the color table uint32_t i = 0; - for (; i < fNumColors; i++) { + for (; i < numColorsToRead; i++) { uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor); uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1); uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2); diff --git a/gfx/skia/skia/src/codec/SkBmpRLECodec.h b/gfx/skia/skia/src/codec/SkBmpRLECodec.h index fcf910d8e5e..df2a97d8450 100644 --- a/gfx/skia/skia/src/codec/SkBmpRLECodec.h +++ b/gfx/skia/skia/src/codec/SkBmpRLECodec.h @@ -90,6 +90,7 @@ private: SkSampler* getSampler(bool createIfNecessary) override; SkAutoTUnref fColorTable; // owned + // fNumColors is the number specified in the header, or 0 if not present in the header. const uint32_t fNumColors; const uint32_t fBytesPerColor; const uint32_t fOffset; diff --git a/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp b/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp index fd4d6d18bc2..85b40778b6c 100644 --- a/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp @@ -20,13 +20,14 @@ SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream SkCodec::SkScanlineOrder rowOrder, bool inIco) : INHERITED(info, stream, bitsPerPixel, rowOrder) , fColorTable(nullptr) - , fNumColors(this->computeNumColors(numColors)) + , fNumColors(numColors) , fBytesPerColor(bytesPerColor) , fOffset(offset) , fSwizzler(nullptr) , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bitsPerPixel()))) , fSrcBuffer(new uint8_t [fSrcRowBytes]) , fInIco(inIco) + , fAndMaskRowBytes(fInIco ? SkAlign4(compute_row_bytes(this->getInfo().width(), 1)) : 0) {} /* @@ -60,9 +61,6 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, *rowsDecoded = rows; return kIncompleteInput; } - if (fInIco) { - return this->decodeIcoMask(dstInfo, dst, dstRowBytes); - } return kSuccess; } @@ -82,9 +80,12 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, // access memory outside of our color table array. *numColors = maxColors; } + // Don't bother reading more than maxColors. + const uint32_t numColorsToRead = + fNumColors == 0 ? maxColors : SkTMin(fNumColors, maxColors); // Read the color table from the stream - colorBytes = fNumColors * fBytesPerColor; + colorBytes = numColorsToRead * fBytesPerColor; SkAutoTDeleteArray cBuffer(new uint8_t[colorBytes]); if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) { SkCodecPrintf("Error: unable to read color table.\n"); @@ -112,7 +113,7 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, // Fill in the color table uint32_t i = 0; - for (; i < fNumColors; i++) { + for (; i < numColorsToRead; i++) { uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor); uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1); uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2); @@ -227,9 +228,8 @@ SkCodec::Result SkBmpStandardCodec::prepareToDecode(const SkImageInfo& dstInfo, /* * Performs the bitmap decoding for standard input format */ -int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, - void* dst, size_t dstRowBytes, - const Options& opts) { +int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, + const Options& opts) { // Iterate over rows of the image const int height = dstInfo.height(); for (int y = 0; y < height; y++) { @@ -246,29 +246,77 @@ int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, fSwizzler->swizzle(dstRow, fSrcBuffer.get()); } - // Finished decoding the entire image + if (fInIco) { + const int startScanline = this->currScanline(); + if (startScanline < 0) { + // We are not performing a scanline decode. + // Just decode the entire ICO mask and return. + decodeIcoMask(this->stream(), dstInfo, dst, dstRowBytes); + return height; + } + + // In order to perform a scanline ICO decode, we must be able + // to skip ahead in the stream in order to apply the AND mask + // to the requested scanlines. + // We will do this by taking advantage of the fact that + // SkIcoCodec always uses a SkMemoryStream as its underlying + // representation of the stream. + const void* memoryBase = this->stream()->getMemoryBase(); + SkASSERT(nullptr != memoryBase); + SkASSERT(this->stream()->hasLength()); + SkASSERT(this->stream()->hasPosition()); + + const size_t length = this->stream()->getLength(); + const size_t currPosition = this->stream()->getPosition(); + + // Calculate how many bytes we must skip to reach the AND mask. + const int remainingScanlines = this->getInfo().height() - startScanline - height; + const size_t bytesToSkip = remainingScanlines * fSrcRowBytes + + startScanline * fAndMaskRowBytes; + const size_t subStreamStartPosition = currPosition + bytesToSkip; + if (subStreamStartPosition >= length) { + // FIXME: How can we indicate that this decode was actually incomplete? + return height; + } + + // Create a subStream to pass to decodeIcoMask(). It is useful to encapsulate + // the memory base into a stream in order to safely handle incomplete images + // without reading out of bounds memory. + const void* subStreamMemoryBase = SkTAddOffset(memoryBase, + subStreamStartPosition); + const size_t subStreamLength = length - subStreamStartPosition; + // This call does not transfer ownership of the subStreamMemoryBase. + SkMemoryStream subStream(subStreamMemoryBase, subStreamLength, false); + + // FIXME: If decodeIcoMask does not succeed, is there a way that we can + // indicate the decode was incomplete? + decodeIcoMask(&subStream, dstInfo, dst, dstRowBytes); + } + return height; } -// TODO (msarett): This function will need to be modified in order to perform row by row decodes -// when the Ico scanline decoder is implemented. -SkCodec::Result SkBmpStandardCodec::decodeIcoMask(const SkImageInfo& dstInfo, +void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes) { // BMP in ICO have transparency, so this cannot be 565, and this mask // prevents us from using kIndex8. The below code depends on the output // being an SkPMColor. SkASSERT(dstInfo.colorType() == kN32_SkColorType); - // The AND mask is always 1 bit per pixel - const int width = this->getInfo().width(); - const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1)); + // If we are sampling, make sure that we only mask the sampled pixels. + // We do not need to worry about sampling in the y-dimension because that + // should be handled by SkSampledCodec. + const int sampleX = fSwizzler->sampleX(); + const int sampledWidth = get_scaled_dimension(this->getInfo().width(), sampleX); + const int srcStartX = get_start_coord(sampleX); + SkPMColor* dstPtr = (SkPMColor*) dst; for (int y = 0; y < dstInfo.height(); y++) { // The srcBuffer will at least be large enough - if (stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) { + if (stream->read(fSrcBuffer.get(), fAndMaskRowBytes) != fAndMaskRowBytes) { SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); - return kIncompleteInput; + return; } int row = this->getDstRow(y, dstInfo.height()); @@ -276,17 +324,17 @@ SkCodec::Result SkBmpStandardCodec::decodeIcoMask(const SkImageInfo& dstInfo, SkPMColor* dstRow = SkTAddOffset(dstPtr, row * dstRowBytes); - for (int x = 0; x < width; x++) { + int srcX = srcStartX; + for (int dstX = 0; dstX < sampledWidth; dstX++) { int quotient; int modulus; - SkTDivMod(x, 8, "ient, &modulus); + SkTDivMod(srcX, 8, "ient, &modulus); uint32_t shift = 7 - modulus; - uint32_t alphaBit = - (fSrcBuffer.get()[quotient] >> shift) & 0x1; - dstRow[x] &= alphaBit - 1; + uint32_t alphaBit = (fSrcBuffer.get()[quotient] >> shift) & 0x1; + dstRow[dstX] &= alphaBit - 1; + srcX += sampleX; } } - return kSuccess; } uint32_t SkBmpStandardCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType) const { diff --git a/gfx/skia/skia/src/codec/SkBmpStandardCodec.h b/gfx/skia/skia/src/codec/SkBmpStandardCodec.h index d687eaad287..b7999001e12 100644 --- a/gfx/skia/skia/src/codec/SkBmpStandardCodec.h +++ b/gfx/skia/skia/src/codec/SkBmpStandardCodec.h @@ -75,9 +75,15 @@ private: int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts) override; - Result decodeIcoMask(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes); + /* + * @param stream This may be a pointer to the stream owned by the parent SkCodec + * or a sub-stream of the stream owned by the parent SkCodec. + * Either way, this stream is unowned. + */ + void decodeIcoMask(SkStream* stream, const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes); SkAutoTUnref fColorTable; // owned + // fNumColors is the number specified in the header, or 0 if not present in the header. const uint32_t fNumColors; const uint32_t fBytesPerColor; const uint32_t fOffset; @@ -85,6 +91,7 @@ private: const size_t fSrcRowBytes; SkAutoTDeleteArray fSrcBuffer; const bool fInIco; + const size_t fAndMaskRowBytes; // only used for fInIco decodes typedef SkBmpCodec INHERITED; }; diff --git a/gfx/skia/skia/src/codec/SkCodec.cpp b/gfx/skia/skia/src/codec/SkCodec.cpp index 11eb1f98479..04ee7c6a438 100644 --- a/gfx/skia/skia/src/codec/SkCodec.cpp +++ b/gfx/skia/skia/src/codec/SkCodec.cpp @@ -7,20 +7,20 @@ #include "SkBmpCodec.h" #include "SkCodec.h" -#include "SkData.h" -#include "SkCodec_libgif.h" -#include "SkCodec_libico.h" #include "SkCodec_libpng.h" -#include "SkCodec_wbmp.h" #include "SkCodecPriv.h" +#include "SkData.h" +#include "SkGifCodec.h" +#include "SkIcoCodec.h" #if !defined(GOOGLE3) #include "SkJpegCodec.h" #endif #include "SkStream.h" +#include "SkWbmpCodec.h" #include "SkWebpCodec.h" struct DecoderProc { - bool (*IsFormat)(SkStream*); + bool (*IsFormat)(const void*, size_t); SkCodec* (*NewFromStream)(SkStream*); }; @@ -35,6 +35,10 @@ static const DecoderProc gDecoderProcs[] = { { SkWbmpCodec::IsWbmp, SkWbmpCodec::NewFromStream } }; +size_t SkCodec::MinBufferedBytesNeeded() { + return WEBP_VP8_HEADER_SIZE; +} + SkCodec* SkCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) { if (!stream) { @@ -42,39 +46,49 @@ SkCodec* SkCodec::NewFromStream(SkStream* stream, } SkAutoTDelete streamDeleter(stream); - - SkAutoTDelete codec(nullptr); + + // 14 is enough to read all of the supported types. + const size_t bytesToRead = 14; + SkASSERT(bytesToRead <= MinBufferedBytesNeeded()); + + char buffer[bytesToRead]; + size_t bytesRead = stream->peek(buffer, bytesToRead); + + // It is also possible to have a complete image less than bytesToRead bytes + // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead. + // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter + // than bytesToRead, so pass that directly to the decoder. + // It also is possible the stream uses too small a buffer for peeking, but + // we trust the caller to use a large enough buffer. + + if (0 == bytesRead) { + // TODO: After implementing peek in CreateJavaOutputStreamAdaptor.cpp, this + // printf could be useful to notice failures. + // SkCodecPrintf("Encoded image data failed to peek!\n"); + + // It is possible the stream does not support peeking, but does support + // rewinding. + // Attempt to read() and pass the actual amount read to the decoder. + bytesRead = stream->read(buffer, bytesToRead); + if (!stream->rewind()) { + SkCodecPrintf("Encoded image data could not peek or rewind to determine format!\n"); + return nullptr; + } + } + // PNG is special, since we want to be able to supply an SkPngChunkReader. // But this code follows the same pattern as the loop. - const bool isPng = SkPngCodec::IsPng(stream); - if (!stream->rewind()) { - return NULL; - } - if (isPng) { - codec.reset(SkPngCodec::NewFromStream(streamDeleter.detach(), chunkReader)); + if (SkPngCodec::IsPng(buffer, bytesRead)) { + return SkPngCodec::NewFromStream(streamDeleter.detach(), chunkReader); } else { for (DecoderProc proc : gDecoderProcs) { - const bool correctFormat = proc.IsFormat(stream); - if (!stream->rewind()) { - return nullptr; - } - if (correctFormat) { - codec.reset(proc.NewFromStream(streamDeleter.detach())); - break; + if (proc.IsFormat(buffer, bytesRead)) { + return proc.NewFromStream(streamDeleter.detach()); } } } - // Set the max size at 128 megapixels (512 MB for kN32). - // This is about 4x smaller than a test image that takes a few minutes for - // dm to decode and draw. - const int32_t maxSize = 1 << 27; - if (codec && codec->getInfo().width() * codec->getInfo().height() > maxSize) { - SkCodecPrintf("Error: Image size too large, cannot decode.\n"); - return nullptr; - } else { - return codec.detach(); - } + return nullptr; } SkCodec* SkCodec::NewFromData(SkData* data, SkPngChunkReader* reader) { diff --git a/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp b/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp new file mode 100644 index 00000000000..2fef381ec1f --- /dev/null +++ b/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCodecImageGenerator.h" + +SkImageGenerator* SkCodecImageGenerator::NewFromEncodedCodec(SkData* data) { + SkCodec* codec = SkCodec::NewFromData(data); + if (nullptr == codec) { + return nullptr; + } + + return new SkCodecImageGenerator(codec, data); +} + +SkCodecImageGenerator::SkCodecImageGenerator(SkCodec* codec, SkData* data) + : INHERITED(codec->getInfo()) + , fCodec(codec) + , fData(SkRef(data)) +{} + +SkData* SkCodecImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { + return SkRef(fData.get()); +} + +bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + SkPMColor ctable[], int* ctableCount) { + + SkCodec::Result result = fCodec->getPixels(info, pixels, rowBytes, nullptr, ctable, + ctableCount); + switch (result) { + case SkCodec::kSuccess: + case SkCodec::kIncompleteInput: + return true; + default: + return false; + } +} + +bool SkCodecImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], + SkYUVColorSpace* colorSpace) { + return false; +} diff --git a/gfx/skia/skia/src/codec/SkCodecImageGenerator.h b/gfx/skia/skia/src/codec/SkCodecImageGenerator.h new file mode 100644 index 00000000000..80eacb19c88 --- /dev/null +++ b/gfx/skia/skia/src/codec/SkCodecImageGenerator.h @@ -0,0 +1,43 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCodec.h" +#include "SkData.h" +#include "SkImageGenerator.h" + +class SkCodecImageGenerator : public SkImageGenerator { +public: + /* + * If this data represents an encoded image that we know how to decode, + * return an SkCodecImageGenerator. Otherwise return nullptr. + * + * Refs the data if an image generator can be returned. Otherwise does + * not affect the data. + */ + static SkImageGenerator* NewFromEncodedCodec(SkData* data); + +protected: + SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) override; + + bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], + int* ctableCount) override; + + bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], + SkYUVColorSpace* colorSpace) override; + +private: + /* + * Takes ownership of codec + * Refs the data + */ + SkCodecImageGenerator(SkCodec* codec, SkData* data); + + SkAutoTDelete fCodec; + SkAutoTUnref fData; + + typedef SkImageGenerator INHERITED; +}; diff --git a/gfx/skia/skia/src/codec/SkCodecPriv.h b/gfx/skia/skia/src/codec/SkCodecPriv.h index 1b6723fd4af..27e2a63722d 100644 --- a/gfx/skia/skia/src/codec/SkCodecPriv.h +++ b/gfx/skia/skia/src/codec/SkCodecPriv.h @@ -11,26 +11,9 @@ #include "SkColorPriv.h" #include "SkColorTable.h" #include "SkImageInfo.h" -#include "SkSwizzler.h" #include "SkTypes.h" #include "SkUtils.h" -/* - * - * Helper routine for alpha result codes - * - */ -#define INIT_RESULT_ALPHA \ - uint8_t zeroAlpha = 0; \ - uint8_t maxAlpha = 0xFF; - -#define UPDATE_RESULT_ALPHA(alpha) \ - zeroAlpha |= (alpha); \ - maxAlpha &= (alpha); - -#define COMPUTE_RESULT_ALPHA \ - SkSwizzler::GetResult(zeroAlpha, maxAlpha); - // FIXME: Consider sharing with dm, nanbench, and tools. inline float get_scale_from_sample_size(int sampleSize) { return 1.0f / ((float) sampleSize); diff --git a/gfx/skia/skia/src/codec/SkCodec_libico.h b/gfx/skia/skia/src/codec/SkCodec_libico.h deleted file mode 100644 index 92675f4d740..00000000000 --- a/gfx/skia/skia/src/codec/SkCodec_libico.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkCodec.h" -#include "SkImageInfo.h" -#include "SkStream.h" -#include "SkTypes.h" - -/* - * This class implements the decoding for bmp images - */ -class SkIcoCodec : public SkCodec { -public: - - /* - * Checks the start of the stream to see if the image is a Ico or Cur - */ - static bool IsIco(SkStream*); - - /* - * Assumes IsIco was called and returned true - * Creates an Ico decoder - * Reads enough of the stream to determine the image format - */ - static SkCodec* NewFromStream(SkStream*); - -protected: - - /* - * Chooses the best dimensions given the desired scale - */ - SkISize onGetScaledDimensions(float desiredScale) const override; - - bool onDimensionsSupported(const SkISize&) override; - - /* - * Initiates the Ico decode - */ - Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, - SkPMColor*, int*, int*) override; - - SkEncodedFormat onGetEncodedFormat() const override { - return kICO_SkEncodedFormat; - } - -private: - - /* - * Constructor called by NewFromStream - * @param embeddedCodecs codecs for the embedded images, takes ownership - */ - SkIcoCodec(const SkImageInfo& srcInfo, - SkTArray, true>* embeddedCodecs); - - SkAutoTDelete, true>> - fEmbeddedCodecs; // owned - - typedef SkCodec INHERITED; -}; diff --git a/gfx/skia/skia/src/codec/SkCodec_libpng.cpp b/gfx/skia/skia/src/codec/SkCodec_libpng.cpp index 355d493309f..e8fd2a3cdd0 100644 --- a/gfx/skia/skia/src/codec/SkCodec_libpng.cpp +++ b/gfx/skia/skia/src/codec/SkCodec_libpng.cpp @@ -14,6 +14,7 @@ #include "SkSize.h" #include "SkStream.h" #include "SkSwizzler.h" +#include "SkTemplates.h" /////////////////////////////////////////////////////////////////////////////// // Helper macros @@ -153,7 +154,6 @@ bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { } int index = 0; - int transLessThanFF = 0; // Choose which function to use to create the color table. If the final destination's // colortype is unpremultiplied, the color table will store unpremultiplied colors. @@ -164,16 +164,10 @@ bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { proc = &SkPackARGB32NoCheck; } for (; index < numTrans; index++) { - transLessThanFF |= (int)*trans - 0xFF; *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue); palette++; } - if (transLessThanFF >= 0) { - // No transparent colors were found. - fAlphaState = kOpaque_AlphaState; - } - for (; index < numPalette; index++) { *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); palette++; @@ -206,17 +200,8 @@ bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { // Creation /////////////////////////////////////////////////////////////////////////////// -#define PNG_BYTES_TO_CHECK 4 - -bool SkPngCodec::IsPng(SkStream* stream) { - char buf[PNG_BYTES_TO_CHECK]; - if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { - return false; - } - if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { - return false; - } - return true; +bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) { + return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); } // Reads the header and initializes the output fields, if not NULL. @@ -267,8 +252,9 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, png_set_read_fn(png_ptr, static_cast(stream), sk_read_fn); #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - // FIXME: Does this need to be installed so early? - // hookup our chunkReader so we can see any user-chunks the caller may be interested in + // Hookup our chunkReader so we can see any user-chunks the caller may be interested in. + // This needs to be installed before we read the png header. Android may store ninepatch + // chunks in the header. if (chunkReader) { png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk); @@ -392,13 +378,7 @@ SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkRead , fSrcConfig(SkSwizzler::kUnknown) , fNumberPasses(numberPasses) , fBitDepth(bitDepth) -{ - if (info.alphaType() == kOpaque_SkAlphaType) { - fAlphaState = kOpaque_AlphaState; - } else { - fAlphaState = kUnknown_AlphaState; - } -} +{} SkPngCodec::~SkPngCodec() { this->destroyReadStruct(); @@ -512,7 +492,7 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* // error? int row = 0; // This must be declared above the call to setjmp to avoid memory leaks on incomplete images. - SkAutoMalloc storage; + SkAutoTMalloc storage; if (setjmp(png_jmpbuf(fPng_ptr))) { // Assume that any error that occurs while reading rows is caused by an incomplete input. if (fNumberPasses > 1) { @@ -534,7 +514,6 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* return kIncompleteInput; } - bool hasAlpha = false; // FIXME: We could split these out based on subclass. void* dstRow = dst; if (fNumberPasses > 1) { @@ -544,7 +523,7 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* const size_t srcRowBytes = width * bpp; storage.reset(width * height * bpp); - uint8_t* const base = static_cast(storage.get()); + uint8_t* const base = storage.get(); for (int i = 0; i < fNumberPasses; i++) { uint8_t* srcRow = base; @@ -558,27 +537,21 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* // Now swizzle it. uint8_t* srcRow = base; for (int y = 0; y < height; y++) { - hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); + fSwizzler->swizzle(dstRow, srcRow); dstRow = SkTAddOffset(dstRow, dstRowBytes); srcRow += srcRowBytes; } } else { storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConfig)); - uint8_t* srcRow = static_cast(storage.get()); + uint8_t* srcRow = storage.get(); for (; row < requestedInfo.height(); row++) { png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); // FIXME: Only call IsOpaque once, outside the loop. Same for onGetScanlines. - hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); + fSwizzler->swizzle(dstRow, srcRow); dstRow = SkTAddOffset(dstRow, dstRowBytes); } } - if (hasAlpha) { - fAlphaState = kHasAlpha_AlphaState; - } else { - fAlphaState = kOpaque_AlphaState; - } - // FIXME: do we need substituteTranspColor? Note that we cannot do it for // scanline decoding, but we could do it here. Alternatively, we could do // it as we go, instead of in post-processing like SkPNGImageDecoder. @@ -602,38 +575,12 @@ uint32_t SkPngCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType return INHERITED::onGetFillValue(colorType, alphaType); } -bool SkPngCodec::onReallyHasAlpha() const { - switch (fAlphaState) { - case kOpaque_AlphaState: - return false; - case kUnknown_AlphaState: - // Maybe the subclass knows? - return this->alphaInScanlineDecode() == kHasAlpha_AlphaState; - case kHasAlpha_AlphaState: - switch (this->alphaInScanlineDecode()) { - case kUnknown_AlphaState: - // Scanline decoder must not have been used. Return our knowledge. - return true; - case kOpaque_AlphaState: - // Scanline decoder was used, and did not find alpha in its subset. - return false; - case kHasAlpha_AlphaState: - return true; - } - } - - // All valid AlphaStates have been covered, so this should not be reached. - SkASSERT(false); - return true; -} - // Subclass of SkPngCodec which supports scanline decoding class SkPngScanlineDecoder : public SkPngCodec { public: SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth) : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1) - , fAlphaState(kUnknown_AlphaState) , fSrcRow(nullptr) {} @@ -649,9 +596,8 @@ public: return result; } - fAlphaState = kUnknown_AlphaState; fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig())); - fSrcRow = static_cast(fStorage.get()); + fSrcRow = fStorage.get(); return kSuccess; } @@ -665,22 +611,12 @@ public: } void* dstRow = dst; - bool hasAlpha = false; for (; row < count; row++) { png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); - hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, fSrcRow)); + this->swizzler()->swizzle(dstRow, fSrcRow); dstRow = SkTAddOffset(dstRow, rowBytes); } - if (hasAlpha) { - fAlphaState = kHasAlpha_AlphaState; - } else { - if (kUnknown_AlphaState == fAlphaState) { - fAlphaState = kOpaque_AlphaState; - } - // Otherwise, the AlphaState is unchanged. - } - return row; } @@ -699,13 +635,8 @@ public: return true; } - AlphaState alphaInScanlineDecode() const override { - return fAlphaState; - } - private: - AlphaState fAlphaState; - SkAutoMalloc fStorage; + SkAutoTMalloc fStorage; uint8_t* fSrcRow; typedef SkPngCodec INHERITED; @@ -718,7 +649,6 @@ public: SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses) : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, numberPasses) - , fAlphaState(kUnknown_AlphaState) , fHeight(-1) , fCanSkipRewind(false) { @@ -737,7 +667,6 @@ public: return result; } - fAlphaState = kUnknown_AlphaState; fHeight = dstInfo.height(); // FIXME: This need not be called on a second call to onStartScanlineDecode. fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig()); @@ -768,7 +697,7 @@ public: if (!this->rewindIfNeeded()) { return kCouldNotRewind; } - this->updateNextScanline(currScanline); + this->updateCurrScanline(currScanline); } if (setjmp(png_jmpbuf(this->png_ptr()))) { @@ -778,8 +707,8 @@ public: // fail on the first pass, we can still report than some scanlines are initialized. return 0; } - SkAutoMalloc storage(count * fSrcRowBytes); - uint8_t* storagePtr = static_cast(storage.get()); + SkAutoTMalloc storage(count * fSrcRowBytes); + uint8_t* storagePtr = storage.get(); uint8_t* srcRow; const int startRow = this->nextScanline(); for (int i = 0; i < this->numberPasses(); i++) { @@ -801,22 +730,12 @@ public: //swizzle the rows we care about srcRow = storagePtr; void* dstRow = dst; - bool hasAlpha = false; for (int y = 0; y < count; y++) { - hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, srcRow)); + this->swizzler()->swizzle(dstRow, srcRow); dstRow = SkTAddOffset(dstRow, dstRowBytes); srcRow += fSrcRowBytes; } - if (hasAlpha) { - fAlphaState = kHasAlpha_AlphaState; - } else { - if (kUnknown_AlphaState == fAlphaState) { - fAlphaState = kOpaque_AlphaState; - } - // Otherwise, the AlphaState is unchanged. - } - return count; } @@ -825,16 +744,11 @@ public: return true; } - AlphaState alphaInScanlineDecode() const override { - return fAlphaState; - } - SkScanlineOrder onGetScanlineOrder() const override { return kNone_SkScanlineOrder; } private: - AlphaState fAlphaState; int fHeight; size_t fSrcRowBytes; SkAutoMalloc fGarbageRow; diff --git a/gfx/skia/skia/src/codec/SkCodec_libpng.h b/gfx/skia/skia/src/codec/SkCodec_libpng.h index c2a5f4a7075..9a13a126701 100644 --- a/gfx/skia/skia/src/codec/SkCodec_libpng.h +++ b/gfx/skia/skia/src/codec/SkCodec_libpng.h @@ -19,7 +19,7 @@ class SkStream; class SkPngCodec : public SkCodec { public: - static bool IsPng(SkStream*); + static bool IsPng(const char*, size_t); // Assume IsPng was called and returned true. static SkCodec* NewFromStream(SkStream*, SkPngChunkReader* = NULL); @@ -32,7 +32,6 @@ protected: SkEncodedFormat onGetEncodedFormat() const override { return kPNG_SkEncodedFormat; } bool onRewind() override; uint32_t onGetFillValue(SkColorType colorType, SkAlphaType alphaType) const override; - bool onReallyHasAlpha() const final; // Helper to set up swizzler and color table. Also calls png_read_update_info. Result initializeSwizzler(const SkImageInfo& requestedInfo, const Options&, @@ -49,19 +48,6 @@ protected: SkSwizzler::SrcConfig srcConfig() const { return fSrcConfig; } int numberPasses() const { return fNumberPasses; } - enum AlphaState { - // This class has done no decoding, or threw away its knowledge (in - // scanline decodes). - kUnknown_AlphaState, - // This class found the image (possibly partial, in the case of a - // scanline decode) to be opaque. - kOpaque_AlphaState, - // Ths class found the image to have alpha. - kHasAlpha_AlphaState, - }; - - virtual AlphaState alphaInScanlineDecode() const = 0; - private: SkAutoTUnref fPngChunkReader; png_structp fPng_ptr; @@ -74,7 +60,6 @@ private: SkSwizzler::SrcConfig fSrcConfig; const int fNumberPasses; int fBitDepth; - AlphaState fAlphaState; bool decodePalette(bool premultiply, int* ctableCount); void destroyReadStruct(); diff --git a/gfx/skia/skia/src/codec/SkCodec_libgif.cpp b/gfx/skia/skia/src/codec/SkGifCodec.cpp similarity index 99% rename from gfx/skia/skia/src/codec/SkCodec_libgif.cpp rename to gfx/skia/skia/src/codec/SkGifCodec.cpp index 8021af95a2e..92470bf3a0c 100644 --- a/gfx/skia/skia/src/codec/SkCodec_libgif.cpp +++ b/gfx/skia/skia/src/codec/SkGifCodec.cpp @@ -5,10 +5,10 @@ * found in the LICENSE file. */ -#include "SkCodec_libgif.h" #include "SkCodecPriv.h" #include "SkColorPriv.h" #include "SkColorTable.h" +#include "SkGifCodec.h" #include "SkStream.h" #include "SkSwizzler.h" #include "SkUtils.h" @@ -16,9 +16,8 @@ /* * Checks the start of the stream to see if the image is a gif */ -bool SkGifCodec::IsGif(SkStream* stream) { - char buf[GIF_STAMP_LEN]; - if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) { +bool SkGifCodec::IsGif(const void* buf, size_t bytesRead) { + if (bytesRead >= GIF_STAMP_LEN) { if (memcmp(GIF_STAMP, buf, GIF_STAMP_LEN) == 0 || memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 || memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) @@ -508,7 +507,7 @@ SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, void SkGifCodec::handleScanlineFrame(int count, int* rowsBeforeFrame, int* rowsInFrame) { if (fFrameIsSubset) { - const int currRow = this->INHERITED::nextScanline(); + const int currRow = this->currScanline(); // The number of rows that remain to be skipped before reaching rows that we // actually must decode into. diff --git a/gfx/skia/skia/src/codec/SkCodec_libgif.h b/gfx/skia/skia/src/codec/SkGifCodec.h similarity index 98% rename from gfx/skia/skia/src/codec/SkCodec_libgif.h rename to gfx/skia/skia/src/codec/SkGifCodec.h index 200f176e329..ba48989cbbf 100644 --- a/gfx/skia/skia/src/codec/SkCodec_libgif.h +++ b/gfx/skia/skia/src/codec/SkGifCodec.h @@ -19,11 +19,7 @@ */ class SkGifCodec : public SkCodec { public: - - /* - * Checks the start of the stream to see if the image is a gif - */ - static bool IsGif(SkStream*); + static bool IsGif(const void*, size_t); /* * Assumes IsGif was called and returned true diff --git a/gfx/skia/skia/src/codec/SkCodec_libico.cpp b/gfx/skia/skia/src/codec/SkIcoCodec.cpp similarity index 65% rename from gfx/skia/skia/src/codec/SkCodec_libico.cpp rename to gfx/skia/skia/src/codec/SkIcoCodec.cpp index 8c5a1b34120..0280be304c4 100644 --- a/gfx/skia/skia/src/codec/SkCodec_libico.cpp +++ b/gfx/skia/skia/src/codec/SkIcoCodec.cpp @@ -6,23 +6,59 @@ */ #include "SkBmpCodec.h" -#include "SkCodec_libico.h" #include "SkCodec_libpng.h" #include "SkCodecPriv.h" #include "SkColorPriv.h" #include "SkData.h" +#include "SkIcoCodec.h" #include "SkStream.h" #include "SkTDArray.h" #include "SkTSort.h" +static bool ico_conversion_possible(const SkImageInfo& dstInfo) { + // We only support kN32_SkColorType. + // This makes sense for BMP-in-ICO. The presence of an AND + // mask (which changes colors and adds transparency) means that + // we cannot use k565 or kIndex8. + // FIXME: For PNG-in-ICO, we could technically support whichever + // color types that the png supports. + if (kN32_SkColorType != dstInfo.colorType()) { + return false; + } + + // We only support transparent alpha types. This is necessary for + // BMP-in-ICOs since there will be an AND mask. + // FIXME: For opaque PNG-in-ICOs, we should be able to support kOpaque. + return kPremul_SkAlphaType == dstInfo.alphaType() || + kUnpremul_SkAlphaType == dstInfo.alphaType(); +} + +static SkImageInfo fix_embedded_alpha(const SkImageInfo& dstInfo, SkAlphaType embeddedAlpha) { + // FIXME (msarett): ICO is considered non-opaque, even if the embedded BMP + // incorrectly claims it has no alpha. + switch (embeddedAlpha) { + case kPremul_SkAlphaType: + case kUnpremul_SkAlphaType: + // Use the requested alpha type if the embedded codec supports alpha. + embeddedAlpha = dstInfo.alphaType(); + break; + case kOpaque_SkAlphaType: + // If the embedded codec claims it is opaque, decode as if it is opaque. + break; + default: + SkASSERT(false); + break; + } + return dstInfo.makeAlphaType(embeddedAlpha); +} + /* * Checks the start of the stream to see if the image is an Ico or Cur */ -bool SkIcoCodec::IsIco(SkStream* stream) { +bool SkIcoCodec::IsIco(const void* buffer, size_t bytesRead) { const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' }; const char curSig[] = { '\x00', '\x00', '\x02', '\x00' }; - char buffer[sizeof(icoSig)]; - return stream->read(buffer, sizeof(icoSig)) == sizeof(icoSig) && + return bytesRead >= sizeof(icoSig) && (!memcmp(buffer, icoSig, sizeof(icoSig)) || !memcmp(buffer, curSig, sizeof(curSig))); } @@ -139,10 +175,8 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { bytesRead += size; // Check if the embedded codec is bmp or png and create the codec - const bool isPng = SkPngCodec::IsPng(embeddedStream); - SkAssertResult(embeddedStream->rewind()); SkCodec* codec = nullptr; - if (isPng) { + if (SkPngCodec::IsPng((const char*) data->bytes(), data->size())) { codec = SkPngCodec::NewFromStream(embeddedStream.detach()); } else { codec = SkBmpCodec::NewFromIco(embeddedStream.detach()); @@ -197,6 +231,7 @@ SkIcoCodec::SkIcoCodec(const SkImageInfo& info, SkTArray, true>* codecs) : INHERITED(info, nullptr) , fEmbeddedCodecs(codecs) + , fCurrScanlineCodec(nullptr) {} /* @@ -226,15 +261,21 @@ SkISize SkIcoCodec::onGetScaledDimensions(float desiredScale) const { return fEmbeddedCodecs->operator[](minIndex)->getInfo().dimensions(); } -bool SkIcoCodec::onDimensionsSupported(const SkISize& dim) { +int SkIcoCodec::chooseCodec(const SkISize& requestedSize, int startIndex) { + SkASSERT(startIndex >= 0); + // FIXME: Cache the index from onGetScaledDimensions? - for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) { - if (fEmbeddedCodecs->operator[](i)->getInfo().dimensions() == dim) { - return true; + for (int i = startIndex; i < fEmbeddedCodecs->count(); i++) { + if (fEmbeddedCodecs->operator[](i)->getInfo().dimensions() == requestedSize) { + return i; } } - return false; + return -1; +} + +bool SkIcoCodec::onDimensionsSupported(const SkISize& dim) { + return this->chooseCodec(dim, 0) >= 0; } /* @@ -249,54 +290,89 @@ SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, return kUnimplemented; } - if (!valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) { + if (!ico_conversion_possible(dstInfo)) { return kInvalidConversion; } - // We return invalid scale if there is no candidate image with matching - // dimensions. - Result result = kInvalidScale; - for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) { - SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](i); - // If the dimensions match, try to decode - if (dstInfo.dimensions() == embeddedCodec->getInfo().dimensions()) { - - // Perform the decode - // FIXME (msarett): ICO is considered non-opaque, even if the embedded BMP - // incorrectly claims it has no alpha. - SkAlphaType embeddedAlpha = embeddedCodec->getInfo().alphaType(); - switch (embeddedAlpha) { - case kPremul_SkAlphaType: - case kUnpremul_SkAlphaType: - // Use the requested alpha type if the embedded codec supports alpha. - embeddedAlpha = dstInfo.alphaType(); - break; - case kOpaque_SkAlphaType: - // If the embedded codec claims it is opaque, decode as if it is opaque. - break; - default: - SkASSERT(false); - break; - } - SkImageInfo info = dstInfo.makeAlphaType(embeddedAlpha); - result = embeddedCodec->getPixels(info, dst, dstRowBytes, &opts, colorTable, - colorCount); - // The embedded codec will handle filling incomplete images, so we will indicate - // that all of the rows are initialized. - *rowsDecoded = info.height(); - - // On a fatal error, keep trying to find an image to decode - if (kInvalidConversion == result || kInvalidInput == result || - kInvalidScale == result) { - SkCodecPrintf("Warning: Attempt to decode candidate ico failed.\n"); - continue; - } - - // On success or partial success, return the result - return result; + int index = 0; + SkCodec::Result result = kInvalidScale; + while (true) { + index = this->chooseCodec(dstInfo.dimensions(), index); + if (index < 0) { + break; } + + SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); + SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getInfo().alphaType()); + SkASSERT(decodeInfo.colorType() == kN32_SkColorType); + result = embeddedCodec->getPixels(decodeInfo, dst, dstRowBytes, &opts, colorTable, + colorCount); + + switch (result) { + case kSuccess: + case kIncompleteInput: + // The embedded codec will handle filling incomplete images, so we will indicate + // that all of the rows are initialized. + *rowsDecoded = decodeInfo.height(); + return result; + default: + // Continue trying to find a valid embedded codec on a failed decode. + break; + } + + index++; } SkCodecPrintf("Error: No matching candidate image in ico.\n"); return result; } + +SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, + const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount) { + if (!ico_conversion_possible(dstInfo)) { + return kInvalidConversion; + } + + int index = 0; + SkCodec::Result result = kInvalidScale; + while (true) { + index = this->chooseCodec(dstInfo.dimensions(), index); + if (index < 0) { + break; + } + + SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); + SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getInfo().alphaType()); + result = embeddedCodec->startScanlineDecode(decodeInfo, &options, colorTable, colorCount); + if (kSuccess == result) { + fCurrScanlineCodec = embeddedCodec; + return result; + } + + index++; + } + + SkCodecPrintf("Error: No matching candidate image in ico.\n"); + return result; +} + +int SkIcoCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { + SkASSERT(fCurrScanlineCodec); + return fCurrScanlineCodec->getScanlines(dst, count, rowBytes); +} + +bool SkIcoCodec::onSkipScanlines(int count) { + SkASSERT(fCurrScanlineCodec); + return fCurrScanlineCodec->skipScanlines(count); +} + +SkCodec::SkScanlineOrder SkIcoCodec::onGetScanlineOrder() const { + // FIXME: This function will possibly return the wrong value if it is called + // before startScanlineDecode(). + return fCurrScanlineCodec ? fCurrScanlineCodec->getScanlineOrder() : + INHERITED::onGetScanlineOrder(); +} + +SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) { + return fCurrScanlineCodec ? fCurrScanlineCodec->getSampler(createIfNecessary) : nullptr; +} diff --git a/gfx/skia/skia/src/codec/SkIcoCodec.h b/gfx/skia/skia/src/codec/SkIcoCodec.h new file mode 100644 index 00000000000..9a3f248af58 --- /dev/null +++ b/gfx/skia/skia/src/codec/SkIcoCodec.h @@ -0,0 +1,87 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCodec.h" +#include "SkImageInfo.h" +#include "SkStream.h" +#include "SkTypes.h" + +/* + * This class implements the decoding for bmp images + */ +class SkIcoCodec : public SkCodec { +public: + static bool IsIco(const void*, size_t); + + /* + * Assumes IsIco was called and returned true + * Creates an Ico decoder + * Reads enough of the stream to determine the image format + */ + static SkCodec* NewFromStream(SkStream*); + +protected: + + /* + * Chooses the best dimensions given the desired scale + */ + SkISize onGetScaledDimensions(float desiredScale) const override; + + bool onDimensionsSupported(const SkISize&) override; + + /* + * Initiates the Ico decode + */ + Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, + SkPMColor*, int*, int*) override; + + SkEncodedFormat onGetEncodedFormat() const override { + return kICO_SkEncodedFormat; + } + + SkScanlineOrder onGetScanlineOrder() const override; + +private: + + Result onStartScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, + SkPMColor inputColorPtr[], int* inputColorCount) override; + + int onGetScanlines(void* dst, int count, size_t rowBytes) override; + + bool onSkipScanlines(int count) override; + + SkSampler* getSampler(bool createIfNecessary) override; + + /* + * Searches fEmbeddedCodecs for a codec that matches requestedSize. + * The search starts at startIndex and ends when an appropriate codec + * is found, or we have reached the end of the array. + * + * @return the index of the matching codec or -1 if there is no + * matching codec between startIndex and the end of + * the array. + */ + int chooseCodec(const SkISize& requestedSize, int startIndex); + + /* + * Constructor called by NewFromStream + * @param embeddedCodecs codecs for the embedded images, takes ownership + */ + SkIcoCodec(const SkImageInfo& srcInfo, SkTArray, true>* embeddedCodecs); + + SkAutoTDelete, true>> fEmbeddedCodecs; // owned + + // Only used by the scanline decoder. onStartScanlineDecode() will set + // fCurrScanlineCodec to one of the fEmbeddedCodecs, if it can find a + // codec of the appropriate size. We will use fCurrScanlineCodec for + // subsequent calls to onGetScanlines() or onSkipScanlines(). + // fCurrScanlineCodec is owned by this class, but should not be an + // SkAutoTDelete. It will be deleted by the destructor of fEmbeddedCodecs. + SkCodec* fCurrScanlineCodec; + + typedef SkCodec INHERITED; +}; diff --git a/gfx/skia/skia/src/codec/SkJpegCodec.cpp b/gfx/skia/skia/src/codec/SkJpegCodec.cpp index 6e2fc84ec8b..7db772da638 100644 --- a/gfx/skia/skia/src/codec/SkJpegCodec.cpp +++ b/gfx/skia/skia/src/codec/SkJpegCodec.cpp @@ -23,11 +23,9 @@ extern "C" { #include "jpeglib.h" } -bool SkJpegCodec::IsJpeg(SkStream* stream) { +bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) { static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; - char buffer[sizeof(jpegSig)]; - return stream->read(buffer, sizeof(jpegSig)) == sizeof(jpegSig) && - !memcmp(buffer, jpegSig, sizeof(jpegSig)); + return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig)); } bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, @@ -352,12 +350,12 @@ void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, options)); fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); - fSrcRow = static_cast(fStorage.get()); + fSrcRow = fStorage.get(); } SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { if (!createIfNecessary || fSwizzler) { - SkASSERT(!fSwizzler || (fSrcRow && static_cast(fStorage.get()) == fSrcRow)); + SkASSERT(!fSwizzler || (fSrcRow && fStorage.get() == fSrcRow)); return fSwizzler; } @@ -435,8 +433,8 @@ int SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { #ifndef TURBO_HAS_SKIP // TODO (msarett): Avoid reallocating the memory buffer on each call to skip. static uint32_t jpeg_skip_scanlines(jpeg_decompress_struct* dinfo, int count) { - SkAutoMalloc storage(get_row_bytes(dinfo)); - uint8_t* storagePtr = static_cast(storage.get()); + SkAutoTMalloc storage(get_row_bytes(dinfo)); + uint8_t* storagePtr = storage.get(); for (int y = 0; y < count; y++) { if (1 != jpeg_read_scanlines(dinfo, &storagePtr, 1)) { return y; diff --git a/gfx/skia/skia/src/codec/SkJpegCodec.h b/gfx/skia/skia/src/codec/SkJpegCodec.h index 687cf4b4b8a..8e2db81b73a 100644 --- a/gfx/skia/skia/src/codec/SkJpegCodec.h +++ b/gfx/skia/skia/src/codec/SkJpegCodec.h @@ -13,6 +13,7 @@ #include "SkJpegDecoderMgr.h" #include "SkJpegUtility_codec.h" #include "SkStream.h" +#include "SkTemplates.h" extern "C" { #include "jpeglib.h" @@ -25,12 +26,7 @@ extern "C" { */ class SkJpegCodec : public SkCodec { public: - - /* - * Checks the start of the stream to see if the image is a jpeg - * Does not take ownership of the stream - */ - static bool IsJpeg(SkStream*); + static bool IsJpeg(const void*, size_t); /* * Assumes IsJpeg was called and returned true @@ -116,7 +112,7 @@ private: const int fReadyState; // scanline decoding - SkAutoMalloc fStorage; // Only used if sampling is needed + SkAutoTMalloc fStorage; // Only used if sampling is needed uint8_t* fSrcRow; // Only used if sampling is needed SkAutoTDelete fSwizzler; diff --git a/gfx/skia/skia/src/codec/SkMaskSwizzler.cpp b/gfx/skia/skia/src/codec/SkMaskSwizzler.cpp index e5facc1f0c7..01502cbd4ab 100644 --- a/gfx/skia/skia/src/codec/SkMaskSwizzler.cpp +++ b/gfx/skia/skia/src/codec/SkMaskSwizzler.cpp @@ -9,7 +9,7 @@ #include "SkColorPriv.h" #include "SkMaskSwizzler.h" -static SkSwizzler::ResultAlpha swizzle_mask16_to_n32_opaque( +static void swizzle_mask16_to_n32_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -24,54 +24,47 @@ static SkSwizzler::ResultAlpha swizzle_mask16_to_n32_opaque( dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue); srcPtr += sampleX; } - return SkSwizzler::kOpaque_ResultAlpha; } -static SkSwizzler::ResultAlpha swizzle_mask16_to_n32_unpremul( +static void swizzle_mask16_to_n32_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { // Use the masks to decode to the destination uint16_t* srcPtr = ((uint16_t*) srcRow) + startX; SkPMColor* dstPtr = (SkPMColor*) dstRow; - INIT_RESULT_ALPHA; for (int i = 0; i < width; i++) { uint16_t p = srcPtr[0]; uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - UPDATE_RESULT_ALPHA(alpha); dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue); srcPtr += sampleX; } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_mask16_to_n32_premul( +static void swizzle_mask16_to_n32_premul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { // Use the masks to decode to the destination uint16_t* srcPtr = ((uint16_t*) srcRow) + startX; SkPMColor* dstPtr = (SkPMColor*) dstRow; - INIT_RESULT_ALPHA; for (int i = 0; i < width; i++) { uint16_t p = srcPtr[0]; uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - UPDATE_RESULT_ALPHA(alpha); dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue); srcPtr += sampleX; } - return COMPUTE_RESULT_ALPHA; } // TODO (msarett): We have promoted a two byte per pixel image to 8888, only to // convert it back to 565. Instead, we should swizzle to 565 directly. -static SkSwizzler::ResultAlpha swizzle_mask16_to_565( +static void swizzle_mask16_to_565( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -86,10 +79,9 @@ static SkSwizzler::ResultAlpha swizzle_mask16_to_565( dstPtr[i] = SkPack888ToRGB16(red, green, blue); srcPtr += sampleX; } - return SkSwizzler::kOpaque_ResultAlpha; } -static SkSwizzler::ResultAlpha swizzle_mask24_to_n32_opaque( +static void swizzle_mask24_to_n32_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -104,52 +96,45 @@ static SkSwizzler::ResultAlpha swizzle_mask24_to_n32_opaque( dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue); srcRow += 3 * sampleX; } - return SkSwizzler::kOpaque_ResultAlpha; } -static SkSwizzler::ResultAlpha swizzle_mask24_to_n32_unpremul( +static void swizzle_mask24_to_n32_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { // Use the masks to decode to the destination srcRow += 3 * startX; SkPMColor* dstPtr = (SkPMColor*) dstRow; - INIT_RESULT_ALPHA; for (int i = 0; i < width; i++) { uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16; uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - UPDATE_RESULT_ALPHA(alpha); dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue); srcRow += 3 * sampleX; } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_mask24_to_n32_premul( +static void swizzle_mask24_to_n32_premul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { // Use the masks to decode to the destination srcRow += 3 * startX; SkPMColor* dstPtr = (SkPMColor*) dstRow; - INIT_RESULT_ALPHA; for (int i = 0; i < width; i++) { uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16; uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - UPDATE_RESULT_ALPHA(alpha); dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue); srcRow += 3 * sampleX; } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_mask24_to_565( +static void swizzle_mask24_to_565( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -164,10 +149,9 @@ static SkSwizzler::ResultAlpha swizzle_mask24_to_565( dstPtr[i] = SkPack888ToRGB16(red, green, blue); srcRow += 3 * sampleX; } - return SkSwizzler::kOpaque_ResultAlpha; } -static SkSwizzler::ResultAlpha swizzle_mask32_to_n32_opaque( +static void swizzle_mask32_to_n32_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -182,52 +166,45 @@ static SkSwizzler::ResultAlpha swizzle_mask32_to_n32_opaque( dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue); srcPtr += sampleX; } - return SkSwizzler::kOpaque_ResultAlpha; } -static SkSwizzler::ResultAlpha swizzle_mask32_to_n32_unpremul( +static void swizzle_mask32_to_n32_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { // Use the masks to decode to the destination uint32_t* srcPtr = ((uint32_t*) srcRow) + startX; SkPMColor* dstPtr = (SkPMColor*) dstRow; - INIT_RESULT_ALPHA; for (int i = 0; i < width; i++) { uint32_t p = srcPtr[0]; uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - UPDATE_RESULT_ALPHA(alpha); dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue); srcPtr += sampleX; } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_mask32_to_n32_premul( +static void swizzle_mask32_to_n32_premul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { // Use the masks to decode to the destination uint32_t* srcPtr = ((uint32_t*) srcRow) + startX; SkPMColor* dstPtr = (SkPMColor*) dstRow; - INIT_RESULT_ALPHA; for (int i = 0; i < width; i++) { uint32_t p = srcPtr[0]; uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - UPDATE_RESULT_ALPHA(alpha); dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue); srcPtr += sampleX; } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_mask32_to_565( +static void swizzle_mask32_to_565( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { // Use the masks to decode to the destination @@ -241,7 +218,6 @@ static SkSwizzler::ResultAlpha swizzle_mask32_to_565( dstPtr[i] = SkPack888ToRGB16(red, green, blue); srcPtr += sampleX; } - return SkSwizzler::kOpaque_ResultAlpha; } /* @@ -394,7 +370,7 @@ int SkMaskSwizzler::onSetSampleX(int sampleX) { * Swizzle the specified row * */ -SkSwizzler::ResultAlpha SkMaskSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) { +void SkMaskSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) { SkASSERT(nullptr != dst && nullptr != src); - return fRowProc(dst, src, fDstWidth, fMasks, fX0, fSampleX); + fRowProc(dst, src, fDstWidth, fMasks, fX0, fSampleX); } diff --git a/gfx/skia/skia/src/codec/SkMaskSwizzler.h b/gfx/skia/skia/src/codec/SkMaskSwizzler.h index e5da723ca5f..1dc1918f494 100644 --- a/gfx/skia/skia/src/codec/SkMaskSwizzler.h +++ b/gfx/skia/skia/src/codec/SkMaskSwizzler.h @@ -34,7 +34,7 @@ public: /* * Swizzle a row */ - SkSwizzler::ResultAlpha swizzle(void* dst, const uint8_t* SK_RESTRICT src); + void swizzle(void* dst, const uint8_t* SK_RESTRICT src); /** * Implement fill using a custom width. @@ -50,7 +50,7 @@ private: /* * Row procedure used for swizzle */ - typedef SkSwizzler::ResultAlpha (*RowProc)(void* dstRow, const uint8_t* srcRow, int width, + typedef void (*RowProc)(void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX); SkMaskSwizzler(SkMasks* masks, RowProc proc, int subsetWidth, int srcOffset); diff --git a/gfx/skia/skia/src/codec/SkSampledCodec.cpp b/gfx/skia/skia/src/codec/SkSampledCodec.cpp index 52e5648742e..e52470505dc 100644 --- a/gfx/skia/skia/src/codec/SkSampledCodec.cpp +++ b/gfx/skia/skia/src/codec/SkSampledCodec.cpp @@ -9,14 +9,15 @@ #include "SkCodecPriv.h" #include "SkMath.h" #include "SkSampledCodec.h" +#include "SkSampler.h" +#include "SkTemplates.h" SkSampledCodec::SkSampledCodec(SkCodec* codec) - : INHERITED(codec->getInfo()) - , fCodec(codec) + : INHERITED(codec) {} SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeSampleSize) const { - SkISize preSampledSize = fCodec->getInfo().dimensions(); + SkISize preSampledSize = this->codec()->getInfo().dimensions(); int sampleSize = *sampleSizePtr; SkASSERT(sampleSize > 1); @@ -25,7 +26,7 @@ SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeS } // Only JPEG supports native downsampling. - if (fCodec->getEncodedFormat() == kJPEG_SkEncodedFormat) { + if (this->codec()->getEncodedFormat() == kJPEG_SkEncodedFormat) { // See if libjpeg supports this scale directly switch (sampleSize) { case 2: @@ -33,7 +34,7 @@ SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeS case 8: // This class does not need to do any sampling. *sampleSizePtr = 1; - return fCodec->getScaledDimensions(get_scale_from_sample_size(sampleSize)); + return this->codec()->getScaledDimensions(get_scale_from_sample_size(sampleSize)); default: break; } @@ -47,8 +48,8 @@ SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeS if (0 == remainder) { float scale = get_scale_from_sample_size(supportedSampleSize); - // fCodec will scale to this size. - preSampledSize = fCodec->getScaledDimensions(scale); + // this->codec() will scale to this size. + preSampledSize = this->codec()->getScaledDimensions(scale); // And then this class will sample it. *sampleSizePtr = actualSampleSize; @@ -76,10 +77,10 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void codecOptions.fZeroInitialized = options.fZeroInitialized; SkIRect* subset = options.fSubset; - if (!subset || subset->size() == fCodec->getInfo().dimensions()) { - if (fCodec->dimensionsSupported(info.dimensions())) { - return fCodec->getPixels(info, pixels, rowBytes, &codecOptions, options.fColorPtr, - options.fColorCount); + if (!subset || subset->size() == this->codec()->getInfo().dimensions()) { + if (this->codec()->dimensionsSupported(info.dimensions())) { + return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions, + options.fColorPtr, options.fColorCount); } // If the native codec does not support the requested scale, scale by sampling. @@ -89,7 +90,7 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void // We are performing a subset decode. int sampleSize = options.fSampleSize; SkISize scaledSize = this->getSampledDimensions(sampleSize); - if (!fCodec->dimensionsSupported(scaledSize)) { + if (!this->codec()->dimensionsSupported(scaledSize)) { // If the native codec does not support the requested scale, scale by sampling. return this->sampledDecode(info, pixels, rowBytes, options); } @@ -104,24 +105,24 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void SkIRect scanlineSubset = SkIRect::MakeXYWH(scaledSubsetX, 0, scaledSubsetWidth, scaledSize.height()); codecOptions.fSubset = &scanlineSubset; - SkCodec::Result result = fCodec->startScanlineDecode(info.makeWH(scaledSize.width(), + SkCodec::Result result = this->codec()->startScanlineDecode(info.makeWH(scaledSize.width(), scaledSize.height()), &codecOptions, options.fColorPtr, options.fColorCount); if (SkCodec::kSuccess != result) { return result; } // At this point, we are only concerned with subsetting. Either no scale was - // requested, or the fCodec is handling the scale. - switch (fCodec->getScanlineOrder()) { + // requested, or the this->codec() is handling the scale. + switch (this->codec()->getScanlineOrder()) { case SkCodec::kTopDown_SkScanlineOrder: case SkCodec::kNone_SkScanlineOrder: { - if (!fCodec->skipScanlines(scaledSubsetY)) { - fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, + if (!this->codec()->skipScanlines(scaledSubsetY)) { + this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, scaledSubsetHeight, 0); return SkCodec::kIncompleteInput; } - int decodedLines = fCodec->getScanlines(pixels, scaledSubsetHeight, rowBytes); + int decodedLines = this->codec()->getScanlines(pixels, scaledSubsetHeight, rowBytes); if (decodedLines != scaledSubsetHeight) { return SkCodec::kIncompleteInput; } @@ -156,7 +157,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix if (options.fSubset) { // We will need to know about subsetting in the y-dimension in order to use the // scanline decoder. - // Update the subset to account for scaling done by fCodec. + // Update the subset to account for scaling done by this->codec(). SkIRect* subsetPtr = options.fSubset; // Do the divide ourselves, instead of calling get_scaled_dimension. If @@ -174,14 +175,14 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix } // Start the scanline decode. - SkCodec::Result result = fCodec->startScanlineDecode( + SkCodec::Result result = this->codec()->startScanlineDecode( info.makeWH(nativeSize.width(), nativeSize.height()), &sampledOptions, options.fColorPtr, options.fColorCount); if (SkCodec::kSuccess != result) { return result; } - SkSampler* sampler = fCodec->getSampler(true); + SkSampler* sampler = this->codec()->getSampler(true); if (!sampler) { return SkCodec::kUnimplemented; } @@ -201,23 +202,23 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix const int samplingOffsetY = get_start_coord(sampleY); const int startY = samplingOffsetY + subsetY; int dstHeight = info.height(); - switch(fCodec->getScanlineOrder()) { + switch(this->codec()->getScanlineOrder()) { case SkCodec::kTopDown_SkScanlineOrder: { - if (!fCodec->skipScanlines(startY)) { - fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, + if (!this->codec()->skipScanlines(startY)) { + this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, dstHeight, 0); return SkCodec::kIncompleteInput; } void* pixelPtr = pixels; for (int y = 0; y < dstHeight; y++) { - if (1 != fCodec->getScanlines(pixelPtr, 1, rowBytes)) { - fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, - dstHeight, y + 1); + if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) { + this->codec()->fillIncompleteImage(info, pixels, rowBytes, + options.fZeroInitialized, dstHeight, y + 1); return SkCodec::kIncompleteInput; } if (y < dstHeight - 1) { - if (!fCodec->skipScanlines(sampleY - 1)) { - fCodec->fillIncompleteImage(info, pixels, rowBytes, + if (!this->codec()->skipScanlines(sampleY - 1)) { + this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, dstHeight, y + 1); return SkCodec::kIncompleteInput; } @@ -232,15 +233,15 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix SkASSERT(0 == subsetY && nativeSize.height() == subsetHeight); int y; for (y = 0; y < nativeSize.height(); y++) { - int srcY = fCodec->nextScanline(); + int srcY = this->codec()->nextScanline(); if (is_coord_necessary(srcY, sampleY, dstHeight)) { void* pixelPtr = SkTAddOffset(pixels, rowBytes * get_dst_coord(srcY, sampleY)); - if (1 != fCodec->getScanlines(pixelPtr, 1, rowBytes)) { + if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) { break; } } else { - if (!fCodec->skipScanlines(1)) { + if (!this->codec()->skipScanlines(1)) { break; } } @@ -250,12 +251,13 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix return SkCodec::kSuccess; } - // We handle filling uninitialized memory here instead of using fCodec. - // fCodec does not know that we are sampling. - const uint32_t fillValue = fCodec->getFillValue(info.colorType(), info.alphaType()); + // We handle filling uninitialized memory here instead of using this->codec(). + // this->codec() does not know that we are sampling. + const uint32_t fillValue = this->codec()->getFillValue(info.colorType(), + info.alphaType()); const SkImageInfo fillInfo = info.makeWH(info.width(), 1); for (; y < nativeSize.height(); y++) { - int srcY = fCodec->outputScanline(y); + int srcY = this->codec()->outputScanline(y); if (!is_coord_necessary(srcY, sampleY, dstHeight)) { continue; } @@ -267,15 +269,15 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix } case SkCodec::kNone_SkScanlineOrder: { const int linesNeeded = subsetHeight - samplingOffsetY; - SkAutoMalloc storage(linesNeeded * rowBytes); - uint8_t* storagePtr = static_cast(storage.get()); + SkAutoTMalloc storage(linesNeeded * rowBytes); + uint8_t* storagePtr = storage.get(); - if (!fCodec->skipScanlines(startY)) { - fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, + if (!this->codec()->skipScanlines(startY)) { + this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, dstHeight, 0); return SkCodec::kIncompleteInput; } - int scanlines = fCodec->getScanlines(storagePtr, linesNeeded, rowBytes); + int scanlines = this->codec()->getScanlines(storagePtr, linesNeeded, rowBytes); for (int y = 0; y < dstHeight; y++) { memcpy(pixels, storagePtr, info.minRowBytes()); @@ -284,7 +286,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix } if (scanlines < dstHeight) { - // fCodec has already handled filling uninitialized memory. + // this->codec() has already handled filling uninitialized memory. return SkCodec::kIncompleteInput; } return SkCodec::kSuccess; diff --git a/gfx/skia/skia/src/codec/SkSampledCodec.h b/gfx/skia/skia/src/codec/SkSampledCodec.h index b3a59126d26..35e4f571d0d 100644 --- a/gfx/skia/skia/src/codec/SkSampledCodec.h +++ b/gfx/skia/skia/src/codec/SkSampledCodec.h @@ -23,8 +23,6 @@ public: protected: - SkEncodedFormat onGetEncodedFormat() const override { return fCodec->getEncodedFormat(); }; - SkISize onGetSampledDimensions(int sampleSize) const override; bool onGetSupportedSubset(SkIRect* desiredSubset) const override { return true; } @@ -57,8 +55,6 @@ private: SkCodec::Result sampledDecode(const SkImageInfo& info, void* pixels, size_t rowBytes, const AndroidOptions& options); - SkAutoTDelete fCodec; - typedef SkAndroidCodec INHERITED; }; #endif // SkSampledCodec_DEFINED diff --git a/gfx/skia/skia/src/codec/SkSampler.h b/gfx/skia/skia/src/codec/SkSampler.h index afabc1f9eb4..73e11c986e2 100644 --- a/gfx/skia/skia/src/codec/SkSampler.h +++ b/gfx/skia/skia/src/codec/SkSampler.h @@ -7,6 +7,7 @@ #ifndef SkSampler_DEFINED #define SkSampler_DEFINED +#include "SkCodec.h" #include "SkTypes.h" class SkSampler : public SkNoncopyable { diff --git a/gfx/skia/skia/src/codec/SkSwizzler.cpp b/gfx/skia/skia/src/codec/SkSwizzler.cpp index d783380294a..74d6c7f87fc 100644 --- a/gfx/skia/skia/src/codec/SkSwizzler.cpp +++ b/gfx/skia/skia/src/codec/SkSwizzler.cpp @@ -7,19 +7,12 @@ #include "SkCodecPriv.h" #include "SkColorPriv.h" +#include "SkOpts.h" #include "SkSwizzler.h" #include "SkTemplates.h" -SkSwizzler::ResultAlpha SkSwizzler::GetResult(uint8_t zeroAlpha, - uint8_t maxAlpha) { - // In the transparent case, this returns 0x0000 - // In the opaque case, this returns 0xFFFF - // If the row is neither transparent nor opaque, returns something else - return (((uint16_t) maxAlpha) << 8) | zeroAlpha; -} - // samples the row. Does not do anything else but sampling -static SkSwizzler::ResultAlpha sample565(void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, +static void sample565(void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]){ src += offset; @@ -28,8 +21,6 @@ static SkSwizzler::ResultAlpha sample565(void* SK_RESTRICT dstRow, const uint8_t dst[x] = src[1] << 8 | src[0]; src += deltaSrc; } - // 565 is always opaque - return SkSwizzler::kOpaque_ResultAlpha; } // TODO (msarett): Investigate SIMD optimizations for swizzle routines. @@ -42,7 +33,7 @@ static SkSwizzler::ResultAlpha sample565(void* SK_RESTRICT dstRow, const uint8_t // same as swizzle_bit_to_index and swizzle_bit_to_n32 except for value assigned to dst[x] -static SkSwizzler::ResultAlpha swizzle_bit_to_grayscale( +static void swizzle_bit_to_grayscale( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor* /*ctable*/) { @@ -61,15 +52,13 @@ static SkSwizzler::ResultAlpha swizzle_bit_to_grayscale( currByte = *(src += bitOffset / 8); dst[x] = ((currByte >> (7-bitIndex)) & 1) ? GRAYSCALE_WHITE : GRAYSCALE_BLACK; } - - return SkSwizzler::kOpaque_ResultAlpha; } #undef GRAYSCALE_BLACK #undef GRAYSCALE_WHITE // same as swizzle_bit_to_grayscale and swizzle_bit_to_n32 except for value assigned to dst[x] -static SkSwizzler::ResultAlpha swizzle_bit_to_index( +static void swizzle_bit_to_index( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor* /*ctable*/) { uint8_t* SK_RESTRICT dst = (uint8_t*) dstRow; @@ -87,12 +76,10 @@ static SkSwizzler::ResultAlpha swizzle_bit_to_index( currByte = *(src += bitOffset / 8); dst[x] = ((currByte >> (7-bitIndex)) & 1); } - - return SkSwizzler::kOpaque_ResultAlpha; } // same as swizzle_bit_to_grayscale and swizzle_bit_to_index except for value assigned to dst[x] -static SkSwizzler::ResultAlpha swizzle_bit_to_n32( +static void swizzle_bit_to_n32( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor* /*ctable*/) { SkPMColor* SK_RESTRICT dst = (SkPMColor*) dstRow; @@ -110,14 +97,12 @@ static SkSwizzler::ResultAlpha swizzle_bit_to_n32( currByte = *(src += bitOffset / 8); dst[x] = ((currByte >> (7 - bitIndex)) & 1) ? SK_ColorWHITE : SK_ColorBLACK; } - - return SkSwizzler::kOpaque_ResultAlpha; } #define RGB565_BLACK 0 #define RGB565_WHITE 0xFFFF -static SkSwizzler::ResultAlpha swizzle_bit_to_565( +static void swizzle_bit_to_565( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor* /*ctable*/) { uint16_t* SK_RESTRICT dst = (uint16_t*) dstRow; @@ -135,8 +120,6 @@ static SkSwizzler::ResultAlpha swizzle_bit_to_565( currByte = *(src += bitOffset / 8); dst[x] = ((currByte >> (7 - bitIndex)) & 1) ? RGB565_WHITE : RGB565_BLACK; } - - return SkSwizzler::kOpaque_ResultAlpha; } #undef RGB565_BLACK @@ -144,19 +127,17 @@ static SkSwizzler::ResultAlpha swizzle_bit_to_565( // kIndex1, kIndex2, kIndex4 -static SkSwizzler::ResultAlpha swizzle_small_index_to_index( +static void swizzle_small_index_to_index( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { uint8_t* dst = (uint8_t*) dstRow; - INIT_RESULT_ALPHA; src += offset / 8; int bitIndex = offset % 8; uint8_t currByte = *src; const uint8_t mask = (1 << bpp) - 1; uint8_t index = (currByte >> (8 - bpp - bitIndex)) & mask; dst[0] = index; - UPDATE_RESULT_ALPHA(ctable[index] >> SK_A32_SHIFT); for (int x = 1; x < dstWidth; x++) { int bitOffset = bitIndex + deltaSrc; @@ -164,12 +145,10 @@ static SkSwizzler::ResultAlpha swizzle_small_index_to_index( currByte = *(src += bitOffset / 8); index = (currByte >> (8 - bpp - bitIndex)) & mask; dst[x] = index; - UPDATE_RESULT_ALPHA(ctable[index] >> SK_A32_SHIFT); } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_small_index_to_565( +static void swizzle_small_index_to_565( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -188,22 +167,19 @@ static SkSwizzler::ResultAlpha swizzle_small_index_to_565( index = (currByte >> (8 - bpp - bitIndex)) & mask; dst[x] = SkPixel32ToPixel16(ctable[index]); } - return SkAlphaType::kOpaque_SkAlphaType; } -static SkSwizzler::ResultAlpha swizzle_small_index_to_n32( +static void swizzle_small_index_to_n32( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { SkPMColor* dst = (SkPMColor*) dstRow; - INIT_RESULT_ALPHA; src += offset / 8; int bitIndex = offset % 8; uint8_t currByte = *src; const uint8_t mask = (1 << bpp) - 1; uint8_t index = (currByte >> (8 - bpp - bitIndex)) & mask; dst[0] = ctable[index]; - UPDATE_RESULT_ALPHA(ctable[index] >> SK_A32_SHIFT); for (int x = 1; x < dstWidth; x++) { int bitOffset = bitIndex + deltaSrc; @@ -211,92 +187,69 @@ static SkSwizzler::ResultAlpha swizzle_small_index_to_n32( currByte = *(src += bitOffset / 8); index = (currByte >> (8 - bpp - bitIndex)) & mask; dst[x] = ctable[index]; - UPDATE_RESULT_ALPHA(ctable[index] >> SK_A32_SHIFT); } - return COMPUTE_RESULT_ALPHA; } // kIndex -static SkSwizzler::ResultAlpha swizzle_index_to_index( +static void swizzle_index_to_index( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { src += offset; uint8_t* SK_RESTRICT dst = (uint8_t*) dstRow; - INIT_RESULT_ALPHA; - // TODO (msarett): Should we skip the loop here and guess that the row is opaque/not opaque? - // SkScaledBitmap sampler just guesses that it is opaque. This is dangerous - // and probably wrong since gif and bmp (rarely) may have alpha. if (1 == deltaSrc) { memcpy(dst, src, dstWidth); - for (int x = 0; x < dstWidth; x++) { - UPDATE_RESULT_ALPHA(ctable[src[x]] >> SK_A32_SHIFT); - } } else { for (int x = 0; x < dstWidth; x++) { dst[x] = *src; - UPDATE_RESULT_ALPHA(ctable[*src] >> SK_A32_SHIFT); src += deltaSrc; } } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_index_to_n32( +static void swizzle_index_to_n32( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { src += offset; SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; - INIT_RESULT_ALPHA; for (int x = 0; x < dstWidth; x++) { SkPMColor c = ctable[*src]; - UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT); dst[x] = c; src += deltaSrc; } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_index_to_n32_skipZ( +static void swizzle_index_to_n32_skipZ( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { src += offset; SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; - INIT_RESULT_ALPHA; for (int x = 0; x < dstWidth; x++) { SkPMColor c = ctable[*src]; - UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT); if (c != 0) { dst[x] = c; } src += deltaSrc; } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_index_to_565( +static void swizzle_index_to_565( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bytesPerPixel, int deltaSrc, int offset, const SkPMColor ctable[]) { - // FIXME: Support dithering? Requires knowing y, which I think is a bigger - // change. src += offset; uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; for (int x = 0; x < dstWidth; x++) { dst[x] = SkPixel32ToPixel16(ctable[*src]); src += deltaSrc; } - return SkSwizzler::kOpaque_ResultAlpha; } - -#undef A32_MASK_IN_PLACE - // kGray -static SkSwizzler::ResultAlpha swizzle_gray_to_n32( +static void swizzle_gray_to_n32( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -306,10 +259,9 @@ static SkSwizzler::ResultAlpha swizzle_gray_to_n32( dst[x] = SkPackARGB32NoCheck(0xFF, *src, *src, *src); src += deltaSrc; } - return SkSwizzler::kOpaque_ResultAlpha; } -static SkSwizzler::ResultAlpha swizzle_gray_to_gray( +static void swizzle_gray_to_gray( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -323,25 +275,23 @@ static SkSwizzler::ResultAlpha swizzle_gray_to_gray( src += deltaSrc; } } - return SkSwizzler::kOpaque_ResultAlpha; } -static SkSwizzler::ResultAlpha swizzle_gray_to_565( +static void swizzle_gray_to_565( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bytesPerPixel, int deltaSrc, int offset, const SkPMColor ctable[]) { - // FIXME: Support dithering? + src += offset; uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; for (int x = 0; x < dstWidth; x++) { dst[x] = SkPack888ToRGB16(src[0], src[0], src[0]); src += deltaSrc; } - return SkSwizzler::kOpaque_ResultAlpha; } // kBGRX -static SkSwizzler::ResultAlpha swizzle_bgrx_to_n32( +static void swizzle_bgrx_to_n32( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -351,58 +301,50 @@ static SkSwizzler::ResultAlpha swizzle_bgrx_to_n32( dst[x] = SkPackARGB32NoCheck(0xFF, src[2], src[1], src[0]); src += deltaSrc; } - return SkSwizzler::kOpaque_ResultAlpha; } -static SkSwizzler::ResultAlpha swizzle_bgrx_to_565( +static void swizzle_bgrx_to_565( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { - // FIXME: Support dithering? + src += offset; uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; for (int x = 0; x < dstWidth; x++) { dst[x] = SkPack888ToRGB16(src[2], src[1], src[0]); src += deltaSrc; } - return SkSwizzler::kOpaque_ResultAlpha; } // kBGRA -static SkSwizzler::ResultAlpha swizzle_bgra_to_n32_unpremul( +static void swizzle_bgra_to_n32_unpremul( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { src += offset; SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; - INIT_RESULT_ALPHA; for (int x = 0; x < dstWidth; x++) { uint8_t alpha = src[3]; - UPDATE_RESULT_ALPHA(alpha); dst[x] = SkPackARGB32NoCheck(alpha, src[2], src[1], src[0]); src += deltaSrc; } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_bgra_to_n32_premul( +static void swizzle_bgra_to_n32_premul( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { src += offset; SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; - INIT_RESULT_ALPHA; for (int x = 0; x < dstWidth; x++) { uint8_t alpha = src[3]; - UPDATE_RESULT_ALPHA(alpha); - dst[x] = SkPreMultiplyARGB(alpha, src[2], src[1], src[0]); + dst[x] = SkPremultiplyARGBInline(alpha, src[2], src[1], src[0]); src += deltaSrc; } - return COMPUTE_RESULT_ALPHA; } // kRGBX -static SkSwizzler::ResultAlpha swizzle_rgbx_to_n32( +static void swizzle_rgbx_to_n32( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -412,72 +354,60 @@ static SkSwizzler::ResultAlpha swizzle_rgbx_to_n32( dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]); src += deltaSrc; } - return SkSwizzler::kOpaque_ResultAlpha; } -static SkSwizzler::ResultAlpha swizzle_rgbx_to_565( +static void swizzle_rgbx_to_565( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bytesPerPixel, int deltaSrc, int offset, const SkPMColor ctable[]) { - // FIXME: Support dithering? + src += offset; uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; for (int x = 0; x < dstWidth; x++) { dst[x] = SkPack888ToRGB16(src[0], src[1], src[2]); src += deltaSrc; } - return SkSwizzler::kOpaque_ResultAlpha; } - // kRGBA -static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul( +static void swizzle_rgba_to_n32_premul( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { src += offset; SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; - INIT_RESULT_ALPHA; for (int x = 0; x < dstWidth; x++) { unsigned alpha = src[3]; - UPDATE_RESULT_ALPHA(alpha); - dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); + dst[x] = SkPremultiplyARGBInline(alpha, src[0], src[1], src[2]); src += deltaSrc; } - return COMPUTE_RESULT_ALPHA; } -static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_unpremul( +static void fast_swizzle_rgba_to_n32_premul( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, + int offset, const SkPMColor ctable[]) { + + // This function must not be called if we are sampling. If we are not + // sampling, deltaSrc should equal bpp. + SkASSERT(deltaSrc == bpp); + +#ifdef SK_PMCOLOR_IS_RGBA + SkOpts::premul_xxxa((uint32_t*) dst, (const uint32_t*) (src + offset), width); +#else + SkOpts::premul_swaprb_xxxa((uint32_t*) dst, (const uint32_t*) (src + offset), width); +#endif +} + +static void swizzle_rgba_to_n32_unpremul( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { src += offset; uint32_t* SK_RESTRICT dst = reinterpret_cast(dstRow); - INIT_RESULT_ALPHA; for (int x = 0; x < dstWidth; x++) { unsigned alpha = src[3]; - UPDATE_RESULT_ALPHA(alpha); dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]); src += deltaSrc; } - return COMPUTE_RESULT_ALPHA; -} - -static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul_skipZ( - void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, - int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { - - src += offset; - SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; - INIT_RESULT_ALPHA; - for (int x = 0; x < dstWidth; x++) { - unsigned alpha = src[3]; - UPDATE_RESULT_ALPHA(alpha); - if (0 != alpha) { - dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); - } - src += deltaSrc; - } - return COMPUTE_RESULT_ALPHA; } // kCMYK @@ -525,7 +455,7 @@ static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul_skipZ( // R = C * K / 255 // G = M * K / 255 // B = Y * K / 255 -static SkSwizzler::ResultAlpha swizzle_cmyk_to_n32( +static void swizzle_cmyk_to_n32( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -539,12 +469,9 @@ static SkSwizzler::ResultAlpha swizzle_cmyk_to_n32( dst[x] = SkPackARGB32NoCheck(0xFF, r, g, b); src += deltaSrc; } - - // CMYK is always opaque - return SkSwizzler::kOpaque_ResultAlpha; } -static SkSwizzler::ResultAlpha swizzle_cmyk_to_565( +static void swizzle_cmyk_to_565( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -558,38 +485,26 @@ static SkSwizzler::ResultAlpha swizzle_cmyk_to_565( dst[x] = SkPack888ToRGB16(r, g, b); src += deltaSrc; } - - // CMYK is always opaque - return SkSwizzler::kOpaque_ResultAlpha; } -/** - FIXME: This was my idea to cheat in order to continue taking advantage of skipping zeroes. - This would be fine for drawing normally, but not for drawing with transfer modes. Being - honest means we can draw correctly with transfer modes, with the cost of not being able - to take advantage of Android's free unwritten pages. Something to keep in mind when we - decide whether to switch to unpremul default. -static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow, - const uint8_t* SK_RESTRICT src, - int dstWidth, int bitsPerPixel, int offset, - const SkPMColor[]) { - src += offset; - SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; - unsigned alphaMask = 0xFF; - for (int x = 0; x < dstWidth; x++) { - unsigned alpha = src[3]; - // NOTE: We cheat here. The caller requested unpremul and skip zeroes. It's possible - // the color components are not zero, but we skip them anyway, meaning they'll remain - // zero (implied by the request to skip zeroes). - if (0 != alpha) { - dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]); - } - src += deltaSrc; - alphaMask &= alpha; +template +void SkSwizzler::SkipLeading8888ZerosThen( + void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, + int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { + SkASSERT(!ctable); + + auto src32 = (const uint32_t*)(src+offset); + auto dst32 = (uint32_t*)dstRow; + + // This may miss opportunities to skip when the output is premultiplied, + // e.g. for a src pixel 0x00FFFFFF which is not zero but becomes zero after premultiplication. + while (dstWidth > 0 && *src32 == 0x00000000) { + dstWidth--; + dst32++; + src32 += deltaSrc/4; } - return alphaMask != 0xFF; + proc(dst32, (const uint8_t*)src32, dstWidth, bpp, deltaSrc, 0, ctable); } -*/ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, const SkPMColor* ctable, @@ -603,6 +518,7 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, && nullptr == ctable) { return nullptr; } + RowProc fastProc = nullptr; RowProc proc = nullptr; SkCodec::ZeroInitialized zeroInit = options.fZeroInitialized; switch (sc) { @@ -710,7 +626,6 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, } break; case kRGBX: - // TODO: Support other swizzles. switch (dstInfo.colorType()) { case kN32_SkColorType: proc = &swizzle_rgbx_to_n32; @@ -725,13 +640,18 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, switch (dstInfo.colorType()) { case kN32_SkColorType: if (dstInfo.alphaType() == kUnpremul_SkAlphaType) { - // Respect zeroInit? - proc = &swizzle_rgba_to_n32_unpremul; + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeading8888ZerosThen; + } else { + proc = &swizzle_rgba_to_n32_unpremul; + } } else { if (SkCodec::kYes_ZeroInitialized == zeroInit) { - proc = &swizzle_rgba_to_n32_premul_skipZ; + proc = &SkipLeading8888ZerosThen; + fastProc = &SkipLeading8888ZerosThen; } else { proc = &swizzle_rgba_to_n32_premul; + fastProc = &fast_swizzle_rgba_to_n32_premul; } } break; @@ -772,14 +692,11 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, default: break; } - if (nullptr == proc) { - return nullptr; - } // Store bpp in bytes if it is an even multiple, otherwise use bits int srcBPP = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : BitsPerPixel(sc); int dstBPP = SkColorTypeBytesPerPixel(dstInfo.colorType()); - + int srcOffset = 0; int srcWidth = dstInfo.width(); int dstOffset = 0; @@ -796,12 +713,14 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, srcWidth = frame->width(); } - return new SkSwizzler(proc, ctable, srcOffset, srcWidth, dstOffset, dstWidth, srcBPP, dstBPP); + return new SkSwizzler(fastProc, proc, ctable, srcOffset, srcWidth, dstOffset, dstWidth, + srcBPP, dstBPP); } -SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcOffset, int srcWidth, - int dstOffset, int dstWidth, int srcBPP, int dstBPP) - : fRowProc(proc) +SkSwizzler::SkSwizzler(RowProc fastProc, RowProc proc, const SkPMColor* ctable, int srcOffset, + int srcWidth, int dstOffset, int dstWidth, int srcBPP, int dstBPP) + : fFastProc(fastProc) + , fProc(proc) , fColorTable(ctable) , fSrcOffset(srcOffset) , fDstOffset(dstOffset) @@ -825,11 +744,15 @@ int SkSwizzler::onSetSampleX(int sampleX) { fSwizzleWidth = get_scaled_dimension(fSrcWidth, sampleX); fAllocatedWidth = get_scaled_dimension(fDstWidth, sampleX); + // The optimized swizzler routines do not (yet) support sampling. + fFastProc = nullptr; + return fAllocatedWidth; } -SkSwizzler::ResultAlpha SkSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) { +void SkSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) { SkASSERT(nullptr != dst && nullptr != src); - return fRowProc(SkTAddOffset(dst, fDstOffsetBytes), src, fSwizzleWidth, fSrcBPP, + RowProc proc = fFastProc ? fFastProc : fProc; + proc(SkTAddOffset(dst, fDstOffsetBytes), src, fSwizzleWidth, fSrcBPP, fSampleX * fSrcBPP, fSrcOffsetUnits, fColorTable); } diff --git a/gfx/skia/skia/src/codec/SkSwizzler.h b/gfx/skia/skia/src/codec/SkSwizzler.h index 7f5bbc6209b..e75ab43cfe0 100644 --- a/gfx/skia/skia/src/codec/SkSwizzler.h +++ b/gfx/skia/skia/src/codec/SkSwizzler.h @@ -36,42 +36,6 @@ public: kCMYK, }; - /* - * - * Result code for the alpha components of a row. - * - */ - typedef uint16_t ResultAlpha; - static const ResultAlpha kOpaque_ResultAlpha = 0xFFFF; - static const ResultAlpha kTransparent_ResultAlpha = 0x0000; - - /* - * - * Checks if the result of decoding a row indicates that the row was - * transparent. - * - */ - static bool IsTransparent(ResultAlpha r) { - return kTransparent_ResultAlpha == r; - } - - /* - * - * Checks if the result of decoding a row indicates that the row was - * opaque. - * - */ - static bool IsOpaque(ResultAlpha r) { - return kOpaque_ResultAlpha == r; - } - - /* - * - * Constructs the proper result code based on accumulated alpha masks - * - */ - static ResultAlpha GetResult(uint8_t zeroAlpha, uint8_t maxAlpha); - /* * * Returns bits per pixel for source config @@ -149,10 +113,8 @@ public: * subset decodes. * @param dst Where we write the output. * @param src The next row of the source data. - * @return A result code describing if the row was fully opaque, fully - * transparent, or neither */ - ResultAlpha swizzle(void* dst, const uint8_t* SK_RESTRICT src); + void swizzle(void* dst, const uint8_t* SK_RESTRICT src); /** * Implement fill using a custom width. @@ -163,6 +125,16 @@ public: SkSampler::Fill(fillInfo, dst, rowBytes, colorOrIndex, zeroInit); } + /** + * If fSampleX > 1, the swizzler is sampling every fSampleX'th pixel and + * discarding the rest. + * + * This getter is currently used by SkBmpStandardCodec for Bmp-in-Ico decodes. + * Ideally, the subclasses of SkCodec would have no knowledge of sampling, but + * this allows us to apply a transparency mask to pixels after swizzling. + */ + int sampleX() const { return fSampleX; } + private: /** @@ -177,12 +149,21 @@ private: * @param offset The offset before the first pixel to sample. Is in bytes or bits based on what deltaSrc is in. */ - typedef ResultAlpha (*RowProc)(void* SK_RESTRICT dstRow, - const uint8_t* SK_RESTRICT src, - int dstWidth, int bpp, int deltaSrc, int offset, - const SkPMColor ctable[]); + typedef void (*RowProc)(void* SK_RESTRICT dstRow, + const uint8_t* SK_RESTRICT src, + int dstWidth, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]); - const RowProc fRowProc; + template + static void SkipLeading8888ZerosThen(void* SK_RESTRICT dstRow, + const uint8_t* SK_RESTRICT src, + int dstWidth, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]); + + // May be NULL. We will not always be able to used an optimized function. + RowProc fFastProc; + // Always non-NULL. We use this if fFastProc is NULL. + const RowProc fProc; const SkPMColor* fColorTable; // Unowned pointer // Subset Swizzles @@ -269,8 +250,8 @@ private: // fBPP is bitsPerPixel const int fDstBPP; // Bytes per pixel for the destination color type - SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcOffset, int srcWidth, int dstOffset, - int dstWidth, int srcBPP, int dstBPP); + SkSwizzler(RowProc fastProc, RowProc proc, const SkPMColor* ctable, int srcOffset, + int srcWidth, int dstOffset, int dstWidth, int srcBPP, int dstBPP); int onSetSampleX(int) override; diff --git a/gfx/skia/skia/src/codec/SkCodec_wbmp.cpp b/gfx/skia/skia/src/codec/SkWbmpCodec.cpp similarity index 96% rename from gfx/skia/skia/src/codec/SkCodec_wbmp.cpp rename to gfx/skia/skia/src/codec/SkWbmpCodec.cpp index 8f8763fb90e..4dd0f2544d1 100644 --- a/gfx/skia/skia/src/codec/SkCodec_wbmp.cpp +++ b/gfx/skia/skia/src/codec/SkWbmpCodec.cpp @@ -9,8 +9,9 @@ #include "SkCodecPriv.h" #include "SkColorPriv.h" #include "SkColorTable.h" +#include "SkData.h" #include "SkStream.h" -#include "SkCodec_wbmp.h" +#include "SkWbmpCodec.h" // Each bit represents a pixel, so width is actually a number of bits. // A row will always be stored in bytes, so we round width up to the @@ -151,8 +152,10 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, return kSuccess; } -bool SkWbmpCodec::IsWbmp(SkStream* stream) { - return read_header(stream, nullptr); +bool SkWbmpCodec::IsWbmp(const void* buffer, size_t bytesRead) { + SkAutoTUnref data(SkData::NewWithoutCopy(buffer, bytesRead)); + SkMemoryStream stream(data); + return read_header(&stream, nullptr); } SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) { diff --git a/gfx/skia/skia/src/codec/SkCodec_wbmp.h b/gfx/skia/skia/src/codec/SkWbmpCodec.h similarity index 97% rename from gfx/skia/skia/src/codec/SkCodec_wbmp.h rename to gfx/skia/skia/src/codec/SkWbmpCodec.h index f54dd0f1662..fb062c94d59 100644 --- a/gfx/skia/skia/src/codec/SkCodec_wbmp.h +++ b/gfx/skia/skia/src/codec/SkWbmpCodec.h @@ -13,7 +13,7 @@ class SkWbmpCodec final : public SkCodec { public: - static bool IsWbmp(SkStream*); + static bool IsWbmp(const void*, size_t); /* * Assumes IsWbmp was called and returned true diff --git a/gfx/skia/skia/src/codec/SkWebpAdapterCodec.cpp b/gfx/skia/skia/src/codec/SkWebpAdapterCodec.cpp index fb1eacee77a..5aefe5d805e 100644 --- a/gfx/skia/skia/src/codec/SkWebpAdapterCodec.cpp +++ b/gfx/skia/skia/src/codec/SkWebpAdapterCodec.cpp @@ -10,17 +10,16 @@ #include "SkWebpAdapterCodec.h" SkWebpAdapterCodec::SkWebpAdapterCodec(SkWebpCodec* codec) - : INHERITED(codec->getInfo()) - , fCodec(codec) + : INHERITED(codec) {} SkISize SkWebpAdapterCodec::onGetSampledDimensions(int sampleSize) const { float scale = get_scale_from_sample_size(sampleSize); - return fCodec->getScaledDimensions(scale); + return this->codec()->getScaledDimensions(scale); } bool SkWebpAdapterCodec::onGetSupportedSubset(SkIRect* desiredSubset) const { - return fCodec->getValidSubset(desiredSubset); + return this->codec()->getValidSubset(desiredSubset); } SkCodec::Result SkWebpAdapterCodec::onGetAndroidPixels(const SkImageInfo& info, void* pixels, @@ -41,6 +40,6 @@ SkCodec::Result SkWebpAdapterCodec::onGetAndroidPixels(const SkImageInfo& info, SkCodec::Options codecOptions; codecOptions.fZeroInitialized = options.fZeroInitialized; codecOptions.fSubset = options.fSubset; - return fCodec->getPixels(info, pixels, rowBytes, &codecOptions, options.fColorPtr, + return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions, options.fColorPtr, options.fColorCount); } diff --git a/gfx/skia/skia/src/codec/SkWebpAdapterCodec.h b/gfx/skia/skia/src/codec/SkWebpAdapterCodec.h index ed0292a02e8..ece46a668ad 100644 --- a/gfx/skia/skia/src/codec/SkWebpAdapterCodec.h +++ b/gfx/skia/skia/src/codec/SkWebpAdapterCodec.h @@ -23,8 +23,6 @@ public: protected: - SkEncodedFormat onGetEncodedFormat() const override { return kWEBP_SkEncodedFormat; }; - SkISize onGetSampledDimensions(int sampleSize) const override; bool onGetSupportedSubset(SkIRect* desiredSubset) const override; @@ -34,8 +32,6 @@ protected: private: - SkAutoTDelete fCodec; - typedef SkAndroidCodec INHERITED; }; #endif // SkWebpAdapterCodec_DEFINED diff --git a/gfx/skia/skia/src/codec/SkWebpCodec.cpp b/gfx/skia/skia/src/codec/SkWebpCodec.cpp index 3c61b937622..6cfb3852948 100644 --- a/gfx/skia/skia/src/codec/SkWebpCodec.cpp +++ b/gfx/skia/skia/src/codec/SkWebpCodec.cpp @@ -20,26 +20,26 @@ #include "webp/decode.h" #include "webp/encode.h" -bool SkWebpCodec::IsWebp(SkStream* stream) { +bool SkWebpCodec::IsWebp(const void* buf, size_t bytesRead) { // WEBP starts with the following: // RIFFXXXXWEBPVP // Where XXXX is unspecified. - const char LENGTH = 14; - char bytes[LENGTH]; - if (stream->read(&bytes, LENGTH) != LENGTH) { - return false; - } - return !memcmp(bytes, "RIFF", 4) && !memcmp(&bytes[8], "WEBPVP", 6); + const char* bytes = static_cast(buf); + return bytesRead >= 14 && !memcmp(bytes, "RIFF", 4) && !memcmp(&bytes[8], "WEBPVP", 6); } -static const size_t WEBP_VP8_HEADER_SIZE = 30; - // Parse headers of RIFF container, and check for valid Webp (VP8) content. // NOTE: This calls peek instead of read, since onGetPixels will need these // bytes again. static bool webp_parse_header(SkStream* stream, SkImageInfo* info) { unsigned char buffer[WEBP_VP8_HEADER_SIZE]; - if (!stream->peek(buffer, WEBP_VP8_HEADER_SIZE)) { + SkASSERT(WEBP_VP8_HEADER_SIZE <= SkCodec::MinBufferedBytesNeeded()); + + const size_t bytesPeeked = stream->peek(buffer, WEBP_VP8_HEADER_SIZE); + if (bytesPeeked != WEBP_VP8_HEADER_SIZE) { + // Use read + rewind as a backup + if (stream->read(buffer, WEBP_VP8_HEADER_SIZE) != WEBP_VP8_HEADER_SIZE + || !stream->rewind()) return false; } @@ -230,8 +230,8 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, return kInvalidInput; } - SkAutoMalloc storage(BUFFER_SIZE); - uint8_t* buffer = static_cast(storage.get()); + SkAutoTMalloc storage(BUFFER_SIZE); + uint8_t* buffer = storage.get(); while (true) { const size_t bytesRead = stream()->read(buffer, BUFFER_SIZE); if (0 == bytesRead) { diff --git a/gfx/skia/skia/src/codec/SkWebpCodec.h b/gfx/skia/skia/src/codec/SkWebpCodec.h index 97b3920ce9a..dfc9f12ee98 100644 --- a/gfx/skia/skia/src/codec/SkWebpCodec.h +++ b/gfx/skia/skia/src/codec/SkWebpCodec.h @@ -15,20 +15,18 @@ class SkStream; +static const size_t WEBP_VP8_HEADER_SIZE = 30; + class SkWebpCodec final : public SkCodec { public: // Assumes IsWebp was called and returned true. static SkCodec* NewFromStream(SkStream*); - static bool IsWebp(SkStream*); + static bool IsWebp(const void*, size_t); protected: Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor*, int*, int*) override; SkEncodedFormat onGetEncodedFormat() const override { return kWEBP_SkEncodedFormat; } - bool onReallyHasAlpha() const override { - return this->getInfo().alphaType() != kOpaque_SkAlphaType; - } - SkISize onGetScaledDimensions(float desiredScale) const override; bool onDimensionsSupported(const SkISize&) override; diff --git a/gfx/skia/skia/src/core/Sk4px.h b/gfx/skia/skia/src/core/Sk4px.h index 3755488a4a2..05378a8bc83 100644 --- a/gfx/skia/skia/src/core/Sk4px.h +++ b/gfx/skia/skia/src/core/Sk4px.h @@ -48,14 +48,6 @@ public: void store2(SkPMColor[2]) const; void store1(SkPMColor[1]) const; - // Same as above for 565. - static Sk4px Load4(const SkPMColor16 src[4]); - static Sk4px Load2(const SkPMColor16 src[2]); - static Sk4px Load1(const SkPMColor16 src[1]); - void store4(SkPMColor16 dst[4]) const; - void store2(SkPMColor16 dst[2]) const; - void store1(SkPMColor16 dst[1]) const; - // 1, 2, or 4 SkPMColors with 16-bit components. // This is most useful as the result of a multiply, e.g. from mulWiden(). class Wide : public Sk16h { @@ -105,8 +97,8 @@ public: // A generic driver that maps fn over a src array into a dst array. // fn should take an Sk4px (4 src pixels) and return an Sk4px (4 dst pixels). - template - static void MapSrc(int n, Dst* dst, const SkPMColor* src, const Fn& fn) { + template + static void MapSrc(int n, SkPMColor* dst, const SkPMColor* src, const Fn& fn) { SkASSERT(dst); SkASSERT(src); // This looks a bit odd, but it helps loop-invariant hoisting across different calls to fn. @@ -137,8 +129,8 @@ public: } // As above, but with dst4' = fn(dst4, src4). - template - static void MapDstSrc(int n, Dst* dst, const SkPMColor* src, const Fn& fn) { + template + static void MapDstSrc(int n, SkPMColor* dst, const SkPMColor* src, const Fn& fn) { SkASSERT(dst); SkASSERT(src); while (n > 0) { @@ -167,8 +159,8 @@ public: } // As above, but with dst4' = fn(dst4, alpha4). - template - static void MapDstAlpha(int n, Dst* dst, const SkAlpha* a, const Fn& fn) { + template + static void MapDstAlpha(int n, SkPMColor* dst, const SkAlpha* a, const Fn& fn) { SkASSERT(dst); SkASSERT(a); while (n > 0) { @@ -197,8 +189,8 @@ public: } // As above, but with dst4' = fn(dst4, src4, alpha4). - template - static void MapDstSrcAlpha(int n, Dst* dst, const SkPMColor* src, const SkAlpha* a, + template + static void MapDstSrcAlpha(int n, SkPMColor* dst, const SkPMColor* src, const SkAlpha* a, const Fn& fn) { SkASSERT(dst); SkASSERT(src); diff --git a/gfx/skia/skia/src/core/SkAAClip.cpp b/gfx/skia/skia/src/core/SkAAClip.cpp index bbd1f555f08..71d212a2920 100644 --- a/gfx/skia/skia/src/core/SkAAClip.cpp +++ b/gfx/skia/skia/src/core/SkAAClip.cpp @@ -2056,9 +2056,10 @@ static inline uint16_t mergeOne(uint16_t value, unsigned alpha) { SkMulDiv255Round(b, alpha)); } -template void mergeT(const T* SK_RESTRICT src, int srcN, - const uint8_t* SK_RESTRICT row, int rowN, - T* SK_RESTRICT dst) { +template +void mergeT(const void* inSrc, int srcN, const uint8_t* SK_RESTRICT row, int rowN, void* inDst) { + const T* SK_RESTRICT src = static_cast(inSrc); + T* SK_RESTRICT dst = static_cast(inDst); for (;;) { SkASSERT(rowN > 0); SkASSERT(srcN > 0); @@ -2094,14 +2095,10 @@ static MergeAAProc find_merge_aa_proc(SkMask::Format format) { SkDEBUGFAIL("unsupported"); return nullptr; case SkMask::kA8_Format: - case SkMask::k3D_Format: { - void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT; - return (MergeAAProc)proc8; - } - case SkMask::kLCD16_Format: { - void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT; - return (MergeAAProc)proc16; - } + case SkMask::k3D_Format: + return mergeT ; + case SkMask::kLCD16_Format: + return mergeT; default: SkDEBUGFAIL("unsupported"); return nullptr; @@ -2168,7 +2165,6 @@ void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) { // if we're BW, we need to upscale to A8 (ugh) SkMask grayMask; - grayMask.fImage = nullptr; if (SkMask::kBW_Format == origMask.fFormat) { grayMask.fFormat = SkMask::kA8_Format; grayMask.fBounds = origMask.fBounds; diff --git a/gfx/skia/skia/src/core/SkAntiRun.h b/gfx/skia/skia/src/core/SkAntiRun.h index 9a0003935f7..d49a723b209 100644 --- a/gfx/skia/skia/src/core/SkAntiRun.h +++ b/gfx/skia/skia/src/core/SkAntiRun.h @@ -71,7 +71,6 @@ public: runs += x + 1; alpha += x + 1; x = 0; - lastAlpha += x; // we don't want the +1 SkDEBUGCODE(this->validate();) } diff --git a/gfx/skia/skia/src/core/SkBitmap.cpp b/gfx/skia/skia/src/core/SkBitmap.cpp index 6fd97dc2411..bdf1daafccc 100644 --- a/gfx/skia/skia/src/core/SkBitmap.cpp +++ b/gfx/skia/skia/src/core/SkBitmap.cpp @@ -17,6 +17,7 @@ #include "SkReadBuffer.h" #include "SkRect.h" #include "SkScalar.h" +#include "SkTemplates.h" #include "SkUnPreMultiply.h" #include "SkWriteBuffer.h" @@ -38,6 +39,8 @@ SkBitmap::SkBitmap(const SkBitmap& src) { SkDEBUGCODE(this->validate();) } +SkBitmap::SkBitmap(SkBitmap&& other) : SkBitmap() { this->swap(other); } + SkBitmap::~SkBitmap() { SkDEBUGCODE(this->validate();) this->freePixels(); @@ -71,6 +74,14 @@ SkBitmap& SkBitmap::operator=(const SkBitmap& src) { return *this; } +SkBitmap& SkBitmap::operator=(SkBitmap&& other) { + if (this != &other) { + this->swap(other); + other.reset(); + } + return *this; +} + void SkBitmap::swap(SkBitmap& other) { SkTSwap(fColorTable, other.fColorTable); SkTSwap(fPixelRef, other.fPixelRef); @@ -372,6 +383,12 @@ bool SkBitmap::installPixels(const SkImageInfo& requestedInfo, void* pixels, siz return true; } +bool SkBitmap::installPixels(const SkPixmap& pixmap) { + return this->installPixels(pixmap.info(), pixmap.writable_addr(), + pixmap.rowBytes(), pixmap.ctable(), + nullptr, nullptr); +} + bool SkBitmap::installMaskPixels(const SkMask& mask) { if (SkMask::kA8_Format != mask.fFormat) { this->reset(); @@ -572,10 +589,15 @@ SkColor SkBitmap::getColor(int x, int y) const { SkPMColor c = SkPixel4444ToPixel32(addr[0]); return SkUnPreMultiply::PMColorToColor(c); } - case kBGRA_8888_SkColorType: + case kBGRA_8888_SkColorType: { + uint32_t* addr = this->getAddr32(x, y); + SkPMColor c = SkSwizzle_BGRA_to_PMColor(addr[0]); + return SkUnPreMultiply::PMColorToColor(c); + } case kRGBA_8888_SkColorType: { uint32_t* addr = this->getAddr32(x, y); - return SkUnPreMultiply::PMColorToColor(addr[0]); + SkPMColor c = SkSwizzle_RGBA_to_PMColor(addr[0]); + return SkUnPreMultiply::PMColorToColor(c); } default: SkASSERT(false); @@ -806,7 +828,7 @@ bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) SkIRect subset; subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY, fInfo.width(), fInfo.height()); - if (fPixelRef->readPixels(&tmpSrc, &subset)) { + if (fPixelRef->readPixels(&tmpSrc, dstColorType, &subset)) { if (fPixelRef->info().alphaType() == kUnpremul_SkAlphaType) { // FIXME: The only meaningful implementation of readPixels // (GrPixelRef) assumes premultiplied pixels. @@ -1011,7 +1033,6 @@ bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, // compute our (larger?) dst bounds if we have a filter if (filter) { identity.reset(); - srcM.fImage = nullptr; if (!filter->filterMask(&dstM, srcM, identity, nullptr)) { goto NO_FILTER_CASE; } @@ -1071,8 +1092,8 @@ static void write_raw_pixels(SkWriteBuffer* buffer, const SkPixmap& pmap) { info.flatten(*buffer); const size_t size = snugRB * info.height(); - SkAutoMalloc storage(size); - char* dst = (char*)storage.get(); + SkAutoTMalloc storage(size); + char* dst = storage.get(); for (int y = 0; y < info.height(); ++y) { memcpy(dst, src, snugRB); dst += snugRB; diff --git a/gfx/skia/skia/src/core/SkBitmapController.cpp b/gfx/skia/skia/src/core/SkBitmapController.cpp index 233e81146f0..7182ea73829 100644 --- a/gfx/skia/skia/src/core/SkBitmapController.cpp +++ b/gfx/skia/skia/src/core/SkBitmapController.cpp @@ -100,6 +100,12 @@ bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmapProvider& pr if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) { return false; // no need for HQ } + +#ifndef SK_SUPPORT_LEGACY_HQ_DOWNSAMPLING + if (invScaleX > 1 || invScaleY > 1) { + return false; // only use HQ when upsampling + } +#endif const int dstW = SkScalarRoundToScalar(provider.width() / invScaleX); const int dstH = SkScalarRoundToScalar(provider.height() / invScaleY); diff --git a/gfx/skia/skia/src/core/SkBitmapDevice.cpp b/gfx/skia/skia/src/core/SkBitmapDevice.cpp index ac3b9df0827..a7ca7b71817 100644 --- a/gfx/skia/skia/src/core/SkBitmapDevice.cpp +++ b/gfx/skia/skia/src/core/SkBitmapDevice.cpp @@ -95,7 +95,7 @@ SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, if (!bitmap.setInfo(info)) { return nullptr; } - } else if (bitmap.info().isOpaque()) { + } else if (info.isOpaque()) { // If this bitmap is opaque, we don't have any sensible default color, // so we just return uninitialized pixels. if (!bitmap.tryAllocPixels(info)) { @@ -286,7 +286,7 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, if(bitmap.pixelRef()->getTexture()) { // Accelerated source canvas, don't use extractSubset but readPixels to get the subset. // This way, the pixels are copied in CPU memory instead of GPU memory. - bitmap.pixelRef()->readPixels(&tmpBitmap, &srcIR); + bitmap.pixelRef()->readPixels(&tmpBitmap, kN32_SkColorType, &srcIR); } else { if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { return; diff --git a/gfx/skia/skia/src/core/SkBitmapFilter.cpp b/gfx/skia/skia/src/core/SkBitmapFilter.cpp deleted file mode 100644 index 55a7092ba78..00000000000 --- a/gfx/skia/skia/src/core/SkBitmapFilter.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBitmapFilter.h" -#include "SkRTConf.h" -#include "SkTypes.h" - -#include - -// These are the per-scanline callbacks that are used when we must resort to -// resampling an image as it is blitted. Typically these are used only when -// the image is rotated or has some other complex transformation applied. -// Scaled images will usually be rescaled directly before rasterization. - -SK_CONF_DECLARE(const char *, c_bitmapFilter, "bitmap.filter", "mitchell", "Which scanline bitmap filter to use [mitchell, lanczos, hamming, gaussian, triangle, box]"); - -SkBitmapFilter *SkBitmapFilter::Allocate() { - if (!strcmp(c_bitmapFilter, "mitchell")) { - return new SkMitchellFilter(1.f / 3.f, 1.f / 3.f); - } else if (!strcmp(c_bitmapFilter, "lanczos")) { - return new SkLanczosFilter; - } else if (!strcmp(c_bitmapFilter, "hamming")) { - return new SkHammingFilter; - } else if (!strcmp(c_bitmapFilter, "gaussian")) { - return new SkGaussianFilter(2); - } else if (!strcmp(c_bitmapFilter, "triangle")) { - return new SkTriangleFilter; - } else if (!strcmp(c_bitmapFilter, "box")) { - return new SkBoxFilter; - } else { - SkDEBUGFAIL("Unknown filter type"); - } - - return nullptr; -} - diff --git a/gfx/skia/skia/src/core/SkBitmapFilter.h b/gfx/skia/skia/src/core/SkBitmapFilter.h index eb327d716c7..dc3ea693b83 100644 --- a/gfx/skia/skia/src/core/SkBitmapFilter.h +++ b/gfx/skia/skia/src/core/SkBitmapFilter.h @@ -12,6 +12,10 @@ #include "SkMath.h" #include "SkScalar.h" +#ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER +#include "SkNx.h" +#endif + // size of the precomputed bitmap filter tables for high quality filtering. // Used to precompute the shape of the filter kernel. // Table size chosen from experiments to see where I could start to see a difference. @@ -19,125 +23,200 @@ #define SKBITMAP_FILTER_TABLE_SIZE 128 class SkBitmapFilter { - public: - SkBitmapFilter(float width) - : fWidth(width), fInvWidth(1.f/width) { - fPrecomputed = false; - fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1); - } - - SkFixed lookup(float x) const { - if (!fPrecomputed) { - precomputeTable(); - } - int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); - SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); - return fFilterTable[filter_idx]; - } - - SkScalar lookupScalar(float x) const { - if (!fPrecomputed) { - precomputeTable(); - } - int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); - SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); - return fFilterTableScalar[filter_idx]; - } - - float width() const { return fWidth; } - float invWidth() const { return fInvWidth; } - virtual float evaluate(float x) const = 0; - virtual ~SkBitmapFilter() {} - - static SkBitmapFilter* Allocate(); - protected: - float fWidth; - float fInvWidth; - - float fLookupMultiplier; - - mutable bool fPrecomputed; - mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE]; - mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE]; - private: - void precomputeTable() const { - fPrecomputed = true; - SkFixed *ftp = fFilterTable; - SkScalar *ftpScalar = fFilterTableScalar; - for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) { - float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABLE_SIZE; - float filter_value = evaluate(fx); - *ftpScalar++ = filter_value; - *ftp++ = SkFloatToFixed(filter_value); - } - } -}; - -class SkMitchellFilter: public SkBitmapFilter { - public: - SkMitchellFilter(float b, float c, float width=2.0f) - : SkBitmapFilter(width), B(b), C(c) { - } - - float evaluate(float x) const override { - x = fabsf(x); - if (x > 2.f) { - return 0; - } else if (x > 1.f) { - return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x + - (-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f); - } else { - return ((12 - 9*B - 6*C) * x*x*x + - (-18 + 12*B + 6*C) * x*x + - (6 - 2*B)) * (1.f/6.f); - } - } - protected: - float B, C; -}; - -class SkGaussianFilter: public SkBitmapFilter { - public: - SkGaussianFilter(float a, float width=2.0f) - : SkBitmapFilter(width), alpha(a), expWidth(expf(-alpha * width * width)) { - } - - float evaluate(float x) const override { - return SkTMax(0.f, float(expf(-alpha*x*x) - expWidth)); - } - protected: - float alpha, expWidth; -}; - -class SkTriangleFilter: public SkBitmapFilter { - public: - SkTriangleFilter(float width=1) - : SkBitmapFilter(width) { - } - - float evaluate(float x) const override { - return SkTMax(0.f, fWidth - fabsf(x)); - } - protected: -}; - -class SkBoxFilter: public SkBitmapFilter { - public: - SkBoxFilter(float width=0.5f) - : SkBitmapFilter(width) { - } - - float evaluate(float x) const override { - return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f; - } - protected: -}; - -class SkHammingFilter: public SkBitmapFilter { public: - SkHammingFilter(float width=1.f) - : SkBitmapFilter(width) { + SkBitmapFilter(float width) : fWidth(width), fInvWidth(1.f/width) { + fPrecomputed = false; + fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1); } + virtual ~SkBitmapFilter() {} + + SkFixed lookup(float x) const { + if (!fPrecomputed) { + precomputeTable(); + } + int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); + SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); + return fFilterTable[filter_idx]; + } + + SkScalar lookupScalar(float x) const { + if (!fPrecomputed) { + precomputeTable(); + } + int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); + SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); + return fFilterTableScalar[filter_idx]; + } + + float width() const { return fWidth; } + float invWidth() const { return fInvWidth; } + virtual float evaluate(float x) const = 0; + +#ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER + virtual float evaluate_n(float val, float diff, int count, float* output) const { + float sum = 0; + for (int index = 0; index < count; index++) { + float filterValue = evaluate(val); + *output++ = filterValue; + sum += filterValue; + val += diff; + } + return sum; + } +#endif + +protected: + float fWidth; + float fInvWidth; + float fLookupMultiplier; + + mutable bool fPrecomputed; + mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE]; + mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE]; + +private: + void precomputeTable() const { + fPrecomputed = true; + SkFixed *ftp = fFilterTable; + SkScalar *ftpScalar = fFilterTableScalar; + for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) { + float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABLE_SIZE; + float filter_value = evaluate(fx); + *ftpScalar++ = filter_value; + *ftp++ = SkFloatToFixed(filter_value); + } + } +}; + +class SkMitchellFilter final : public SkBitmapFilter { +public: +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER + SkMitchellFilter() : INHERITED(2), B(1.f / 3), C(1.f / 3) {} +#else + SkMitchellFilter() + : INHERITED(2) + , fB(1.f / 3.f) + , fC(1.f / 3.f) + , fA1(-fB - 6*fC) + , fB1(6*fB + 30*fC) + , fC1(-12*fB - 48*fC) + , fD1(8*fB + 24*fC) + , fA2(12 - 9*fB - 6*fC) + , fB2(-18 + 12*fB + 6*fC) + , fD2(6 - 2*fB) + {} +#endif + + float evaluate(float x) const override { + x = fabsf(x); + if (x > 2.f) { + return 0; + } else if (x > 1.f) { +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER + return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x + + (-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f); +#else + return (((fA1 * x + fB1) * x + fC1) * x + fD1) * (1.f/6.f); +#endif + } else { +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER + return ((12 - 9*B - 6*C) * x*x*x + + (-18 + 12*B + 6*C) * x*x + + (6 - 2*B)) * (1.f/6.f); +#else + return ((fA2 * x + fB2) * x*x + fD2) * (1.f/6.f); +#endif + } + } + +#ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER + // TODO : native Sk4f abs + static Sk4f abs(const Sk4f& x) { + Sk4f neg = x < Sk4f(0); + return neg.thenElse(Sk4f(0) - x, x); + } + + Sk4f evalcore_n(const Sk4f& val) const { + Sk4f x = abs(val); + Sk4f over2 = x > Sk4f(2); + Sk4f over1 = x > Sk4f(1); + Sk4f poly1 = (((Sk4f(fA1) * x + Sk4f(fB1)) * x + Sk4f(fC1)) * x + Sk4f(fD1)) + * Sk4f(1.f/6.f); + Sk4f poly0 = ((Sk4f(fA2) * x + Sk4f(fB2)) * x*x + Sk4f(fD2)) * Sk4f(1.f/6.f); + return over2.thenElse(Sk4f(0), over1.thenElse(poly1, poly0)); + } + + float evaluate_n(float val, float diff, int count, float* output) const override { + Sk4f sum(0); + while (count >= 4) { + float v0 = val; + float v1 = val += diff; + float v2 = val += diff; + float v3 = val += diff; + val += diff; + Sk4f filterValue = evalcore_n(Sk4f(v0, v1, v2, v3)); + filterValue.store(output); + output += 4; + sum = sum + filterValue; + count -= 4; + } + float sums[4]; + sum.store(sums); + float result = sums[0] + sums[1] + sums[2] + sums[3]; + result += INHERITED::evaluate_n(val, diff, count, output); + return result; + } +#endif + + protected: +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER + float B, C; +#else + float fB, fC; + float fA1, fB1, fC1, fD1; + float fA2, fB2, fD2; +#endif +private: + typedef SkBitmapFilter INHERITED; +}; + +class SkGaussianFilter final : public SkBitmapFilter { + float fAlpha, fExpWidth; + +public: + SkGaussianFilter(float a, float width = 2) + : SkBitmapFilter(width) + , fAlpha(a) + , fExpWidth(expf(-a * width * width)) + {} + + float evaluate(float x) const override { + return SkTMax(0.f, float(expf(-fAlpha*x*x) - fExpWidth)); + } +}; + +class SkTriangleFilter final : public SkBitmapFilter { +public: + SkTriangleFilter(float width = 1) : SkBitmapFilter(width) {} + + float evaluate(float x) const override { + return SkTMax(0.f, fWidth - fabsf(x)); + } +}; + +class SkBoxFilter final : public SkBitmapFilter { +public: + SkBoxFilter(float width = 0.5f) : SkBitmapFilter(width) {} + + float evaluate(float x) const override { + return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f; + } +}; + +class SkHammingFilter final : public SkBitmapFilter { +public: + SkHammingFilter(float width = 1) : SkBitmapFilter(width) {} + float evaluate(float x) const override { if (x <= -fWidth || x >= fWidth) { return 0.0f; // Outside of the window. @@ -152,23 +231,21 @@ public: } }; -class SkLanczosFilter: public SkBitmapFilter { - public: - SkLanczosFilter(float width=3.f) - : SkBitmapFilter(width) { - } +class SkLanczosFilter final : public SkBitmapFilter { +public: + SkLanczosFilter(float width = 3.f) : SkBitmapFilter(width) {} - float evaluate(float x) const override { - if (x <= -fWidth || x >= fWidth) { - return 0.0f; // Outside of the window. - } - if (x > -FLT_EPSILON && x < FLT_EPSILON) { - return 1.0f; // Special case the discontinuity at the origin. - } - float xpi = x * static_cast(SK_ScalarPI); - return (sk_float_sin(xpi) / xpi) * // sinc(x) - sk_float_sin(xpi / fWidth) / (xpi / fWidth); // sinc(x/fWidth) - } + float evaluate(float x) const override { + if (x <= -fWidth || x >= fWidth) { + return 0.0f; // Outside of the window. + } + if (x > -FLT_EPSILON && x < FLT_EPSILON) { + return 1.0f; // Special case the discontinuity at the origin. + } + float xpi = x * static_cast(SK_ScalarPI); + return (sk_float_sin(xpi) / xpi) * // sinc(x) + sk_float_sin(xpi / fWidth) / (xpi / fWidth); // sinc(x/fWidth) + } }; diff --git a/gfx/skia/skia/src/core/SkBitmapProcShader.cpp b/gfx/skia/skia/src/core/SkBitmapProcShader.cpp index dd97380bbdb..804c6883207 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcShader.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProcShader.cpp @@ -68,11 +68,6 @@ void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const { buffer.writeUInt(fTileModeY); } -static bool only_scale_and_translate(const SkMatrix& matrix) { - unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; - return (matrix.getType() & ~mask) == 0; -} - bool SkBitmapProcShader::isOpaque() const { return fRawBitmap.isOpaque(); } @@ -104,53 +99,25 @@ SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, vo SkBitmapProvider(fRawBitmap), rec, storage); } +static bool only_scale_and_translate(const SkMatrix& matrix) { + unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; + return (matrix.getType() & ~mask) == 0; +} + SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(const SkShader& shader, const ContextRec& rec, SkBitmapProcState* state) : INHERITED(shader, rec) , fState(state) { - const SkPixmap& pixmap = fState->fPixmap; - bool isOpaque = pixmap.isOpaque(); - - // update fFlags - uint32_t flags = 0; - if (isOpaque && (255 == this->getPaintAlpha())) { - flags |= kOpaqueAlpha_Flag; + fFlags = 0; + if (fState->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) { + fFlags |= kOpaqueAlpha_Flag; } - switch (pixmap.colorType()) { - case kRGB_565_SkColorType: - flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag); - break; - case kIndex_8_SkColorType: - case kN32_SkColorType: - if (isOpaque) { - flags |= kHasSpan16_Flag; - } - break; - case kAlpha_8_SkColorType: - break; // never set kHasSpan16_Flag - default: - break; + if (1 == fState->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) { + fFlags |= kConstInY32_Flag; } - - if (rec.fPaint->isDither() && pixmap.colorType() != kRGB_565_SkColorType) { - // gradients can auto-dither in their 16bit sampler, but we don't so - // we clear the flag here. - flags &= ~kHasSpan16_Flag; - } - - // if we're only 1-pixel high, and we don't rotate, then we can claim this - if (1 == pixmap.height() && - only_scale_and_translate(this->getTotalInverse())) { - flags |= kConstInY32_Flag; - if (flags & kHasSpan16_Flag) { - flags |= kConstInY16_Flag; - } - } - - fFlags = flags; } SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() { @@ -174,7 +141,7 @@ void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMCo int count) { const SkBitmapProcState& state = *fState; if (state.getShaderProc32()) { - state.getShaderProc32()(state, x, y, dstC, count); + state.getShaderProc32()(&state, x, y, dstC, count); return; } @@ -221,37 +188,6 @@ SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asASha return nullptr; } -void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan16(int x, int y, uint16_t dstC[], - int count) { - const SkBitmapProcState& state = *fState; - if (state.getShaderProc16()) { - state.getShaderProc16()(state, x, y, dstC, count); - return; - } - - uint32_t buffer[BUF_MAX]; - SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); - SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16(); - int max = state.maxCountForBufferSize(sizeof(buffer)); - - SkASSERT(state.fPixmap.addr()); - - for (;;) { - int n = count; - if (n > max) { - n = max; - } - mproc(state, buffer, n, x, y); - sproc(state, buffer, n, dstC); - - if ((count -= n) == 0) { - break; - } - x += n; - dstC += n; - } -} - /////////////////////////////////////////////////////////////////////////////// #include "SkUnPreMultiply.h" diff --git a/gfx/skia/skia/src/core/SkBitmapProcShader.h b/gfx/skia/skia/src/core/SkBitmapProcShader.h index b69b0286167..0346eff0e2b 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcShader.h +++ b/gfx/skia/skia/src/core/SkBitmapProcShader.h @@ -43,7 +43,6 @@ protected: void shadeSpan(int x, int y, SkPMColor dstC[], int count) override; ShadeProc asAShadeProc(void** ctx) override; - void shadeSpan16(int x, int y, uint16_t dstC[], int count) override; uint32_t getFlags() const override { return fFlags; } diff --git a/gfx/skia/skia/src/core/SkBitmapProcState.cpp b/gfx/skia/skia/src/core/SkBitmapProcState.cpp index 5ec6721436e..b1438cb8a04 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProcState.cpp @@ -21,17 +21,16 @@ #if !SK_ARM_NEON_IS_NONE // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp -extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[]; extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*); -extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); -extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); +extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const void *, int, int, uint16_t*, int); +extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const void *, int, int, uint16_t*, int); extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*); -extern void SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int); -extern void Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int); +extern void SI8_opaque_D32_filter_DX_shaderproc_neon(const void *, int, int, uint32_t*, int); +extern void Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const void*, int, int, uint32_t*, int); #endif -extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState&, int, int, uint32_t*, int); +extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void*, int, int, uint32_t*, int); #define NAME_WRAP(x) x #include "SkBitmapProcState_filter.h" @@ -193,7 +192,6 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { fShaderProc32 = nullptr; fShaderProc16 = nullptr; fSampleProc32 = nullptr; - fSampleProc16 = nullptr; // recompute the triviality of the matrix here because we may have // changed it! @@ -336,45 +334,13 @@ bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp, SG8_alpha_D32_filter_DX, SG8_alpha_D32_filter_DX }; - - static const SampleProc16 gSkBitmapProcStateSample16[] = { - S32_D16_nofilter_DXDY, - S32_D16_nofilter_DX, - S32_D16_filter_DXDY, - S32_D16_filter_DX, - - S16_D16_nofilter_DXDY, - S16_D16_nofilter_DX, - S16_D16_filter_DXDY, - S16_D16_filter_DX, - - SI8_D16_nofilter_DXDY, - SI8_D16_nofilter_DX, - SI8_D16_filter_DXDY, - SI8_D16_filter_DX, - - // Don't support 4444 -> 565 - nullptr, nullptr, nullptr, nullptr, - // Don't support A8 -> 565 - nullptr, nullptr, nullptr, nullptr, - // Don't support G8 -> 565 (but we could) - nullptr, nullptr, nullptr, nullptr - }; #endif fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index]; index >>= 1; // shift away any opaque/alpha distinction - fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index]; // our special-case shaderprocs - if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) { - if (clampClamp) { - fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc); - } else if (SkShader::kRepeat_TileMode == fTileModeX && - SkShader::kRepeat_TileMode == fTileModeY) { - fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc); - } - } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) { + if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) { fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc); } else if (S32_opaque_D32_nofilter_DX == fSampleProc32 && clampClamp) { fShaderProc32 = Clamp_S32_opaque_D32_nofilter_DX_shaderproc; @@ -391,10 +357,11 @@ bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp, return true; } -static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s, +static void Clamp_S32_D32_nofilter_trans_shaderproc(const void* sIn, int x, int y, SkPMColor* SK_RESTRICT colors, int count) { + const SkBitmapProcState& s = *static_cast(sIn); SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0); SkASSERT(s.fInvKy == 0); SkASSERT(count > 0 && colors != nullptr); @@ -465,10 +432,11 @@ static inline int sk_int_mirror(int x, int n) { return x; } -static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s, +static void Repeat_S32_D32_nofilter_trans_shaderproc(const void* sIn, int x, int y, SkPMColor* SK_RESTRICT colors, int count) { + const SkBitmapProcState& s = *static_cast(sIn); SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0); SkASSERT(s.fInvKy == 0); SkASSERT(count > 0 && colors != nullptr); @@ -505,10 +473,11 @@ static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s, } } -static void S32_D32_constX_shaderproc(const SkBitmapProcState& s, +static void S32_D32_constX_shaderproc(const void* sIn, int x, int y, SkPMColor* SK_RESTRICT colors, int count) { + const SkBitmapProcState& s = *static_cast(sIn); SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0); SkASSERT(s.fInvKy == 0); SkASSERT(count > 0 && colors != nullptr); @@ -618,7 +587,7 @@ static void S32_D32_constX_shaderproc(const SkBitmapProcState& s, sk_memset32(colors, color, count); } -static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y, +static void DoNothing_shaderproc(const void*, int x, int y, SkPMColor* SK_RESTRICT colors, int count) { // if we get called, the matrix is too tricky, so we just draw nothing sk_memset32(colors, 0, count); @@ -811,8 +780,9 @@ int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const { /////////////////////// -void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState& s, int x, int y, +void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void* sIn, int x, int y, SkPMColor* SK_RESTRICT dst, int count) { + const SkBitmapProcState& s = *static_cast(sIn); SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0); @@ -820,13 +790,10 @@ void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState& s, in SkFractionalInt fx; int dstY; { - SkPoint pt; - s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf, - &pt); - fx = SkScalarToFractionalInt(pt.fY); + const SkBitmapProcStateAutoMapper mapper(s, x, y); const unsigned maxY = s.fPixmap.height() - 1; - dstY = SkClampMax(SkFractionalIntToInt(fx), maxY); - fx = SkScalarToFractionalInt(pt.fX); + dstY = SkClampMax(SkFractionalIntToInt(mapper.y()), maxY); + fx = mapper.x(); } const SkPMColor* SK_RESTRICT src = s.fPixmap.addr32(0, dstY); diff --git a/gfx/skia/skia/src/core/SkBitmapProcState.h b/gfx/skia/skia/src/core/SkBitmapProcState.h index 2ce76bc83ec..3f1d699cf22 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState.h @@ -12,6 +12,7 @@ #include "SkBitmapController.h" #include "SkBitmapFilter.h" #include "SkBitmapProvider.h" +#include "SkFloatBits.h" #include "SkMatrix.h" #include "SkMipMap.h" #include "SkPaint.h" @@ -31,11 +32,9 @@ struct SkBitmapProcState { SkBitmapProcState(const SkBitmap&, SkShader::TileMode tmx, SkShader::TileMode tmy); ~SkBitmapProcState(); - typedef void (*ShaderProc32)(const SkBitmapProcState&, int x, int y, - SkPMColor[], int count); + typedef void (*ShaderProc32)(const void* ctx, int x, int y, SkPMColor[], int count); - typedef void (*ShaderProc16)(const SkBitmapProcState&, int x, int y, - uint16_t[], int count); + typedef void (*ShaderProc16)(const void* ctx, int x, int y, uint16_t[], int count); typedef void (*MatrixProc)(const SkBitmapProcState&, uint32_t bitmapXY[], @@ -47,11 +46,6 @@ struct SkBitmapProcState { int count, SkPMColor colors[]); - typedef void (*SampleProc16)(const SkBitmapProcState&, - const uint32_t[], - int count, - uint16_t colors[]); - typedef U16CPU (*FixedTileProc)(SkFixed); // returns 0..0xFFFF typedef U16CPU (*FixedTileLowBitsProc)(SkFixed, int); // returns 0..0xF typedef U16CPU (*IntTileProc)(int value, int count); // returns 0..count-1 @@ -118,7 +112,6 @@ struct SkBitmapProcState { MatrixProc getMatrixProc() const { return fMatrixProc; } #endif SampleProc32 getSampleProc32() const { return fSampleProc32; } - SampleProc16 getSampleProc16() const { return fSampleProc16; } private: friend class SkBitmapProcShader; @@ -129,7 +122,6 @@ private: // These are used if the shaderproc is nullptr MatrixProc fMatrixProc; // chooseProcs SampleProc32 fSampleProc32; // chooseProcs - SampleProc16 fSampleProc16; // chooseProcs const SkBitmapProvider fProvider; @@ -195,9 +187,32 @@ void ClampX_ClampY_filter_affine(const SkBitmapProcState& s, uint32_t xy[], int count, int x, int y); void ClampX_ClampY_nofilter_affine(const SkBitmapProcState& s, uint32_t xy[], int count, int x, int y); -void S32_D16_filter_DX(const SkBitmapProcState& s, - const uint32_t* xy, int count, uint16_t* colors); -void S32_D16_filter_DXDY(const SkBitmapProcState& s, - const uint32_t* xy, int count, uint16_t* colors); + +// Helper class for mapping the middle of pixel (x, y) into SkFractionalInt bitmap space. +// TODO: filtered version which applies a fFilterOne{X,Y}/2 bias instead of epsilon? +class SkBitmapProcStateAutoMapper { +public: + SkBitmapProcStateAutoMapper(const SkBitmapProcState& s, int x, int y) { + SkPoint pt; + s.fInvProc(s.fInvMatrix, + SkIntToScalar(x) + SK_ScalarHalf, + SkIntToScalar(y) + SK_ScalarHalf, &pt); + + // SkFixed epsilon bias to ensure inverse-mapped bitmap coordinates are rounded + // consistently WRT geometry. Note that we only need the bias for positive scales: + // for negative scales, the rounding is intrinsically correct. + // We scale it to persist SkFractionalInt -> SkFixed conversions. + const SkFixed biasX = (s.fInvMatrix.getScaleX() > 0); + const SkFixed biasY = (s.fInvMatrix.getScaleY() > 0); + fX = SkScalarToFractionalInt(pt.x()) - SkFixedToFractionalInt(biasX); + fY = SkScalarToFractionalInt(pt.y()) - SkFixedToFractionalInt(biasY); + } + + SkFractionalInt x() const { return fX; } + SkFractionalInt y() const { return fY; } + +private: + SkFractionalInt fX, fY; +}; #endif diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp b/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp index 1870a0e50e9..1c4b7b6bcf4 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp @@ -95,18 +95,20 @@ static SkBitmapProcState::MatrixProc ClampX_ClampY_Procs[] = { }; #define MAKENAME(suffix) RepeatX_RepeatY ## suffix -#define TILEX_PROCF(fx, max) SK_USHIFT16(((fx) & 0xFFFF) * ((max) + 1)) -#define TILEY_PROCF(fy, max) SK_USHIFT16(((fy) & 0xFFFF) * ((max) + 1)) -#define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) -#define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) +#define TILEX_PROCF(fx, max) SK_USHIFT16((unsigned)((fx) & 0xFFFF) * ((max) + 1)) +#define TILEY_PROCF(fy, max) SK_USHIFT16((unsigned)((fy) & 0xFFFF) * ((max) + 1)) +#define TILEX_LOW_BITS(fx, max) (((unsigned)((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) +#define TILEY_LOW_BITS(fy, max) (((unsigned)((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) #include "SkBitmapProcState_matrix.h" struct RepeatTileProcs { static unsigned X(const SkBitmapProcState&, SkFixed fx, int max) { - return SK_USHIFT16(((fx) & 0xFFFF) * ((max) + 1)); + SkASSERT(max < 65535); + return SK_USHIFT16((unsigned)((fx) & 0xFFFF) * ((max) + 1)); } static unsigned Y(const SkBitmapProcState&, SkFixed fy, int max) { - return SK_USHIFT16(((fy) & 0xFFFF) * ((max) + 1)); + SkASSERT(max < 65535); + return SK_USHIFT16((unsigned)((fy) & 0xFFFF) * ((max) + 1)); } }; @@ -176,7 +178,7 @@ static inline U16CPU fixed_repeat(SkFixed x) { #endif static inline U16CPU fixed_mirror(SkFixed x) { - SkFixed s = x << 15 >> 31; + SkFixed s = SkLeftShift(x, 15) >> 31; // s is FFFFFFFF if we're on an odd interval, or 0 if an even interval return (x ^ s) & 0xFFFF; } diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_matrix_template.h b/gfx/skia/skia/src/core/SkBitmapProcState_matrix_template.h index 468013c30da..82fdddbecef 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_matrix_template.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState_matrix_template.h @@ -22,13 +22,10 @@ void NoFilterProc_Scale(const SkBitmapProcState& s, uint32_t xy[], const unsigned maxX = s.fPixmap.width() - 1; SkFractionalInt fx; { - SkPoint pt; - s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, - SkIntToScalar(y) + SK_ScalarHalf, &pt); - fx = SkScalarToFractionalInt(pt.fY); + const SkBitmapProcStateAutoMapper mapper(s, x, y); const unsigned maxY = s.fPixmap.height() - 1; - *xy++ = TileProc::Y(s, SkFractionalIntToFixed(fx), maxY); - fx = SkScalarToFractionalInt(pt.fX); + *xy++ = TileProc::Y(s, SkFractionalIntToFixed(mapper.y()), maxY); + fx = mapper.x(); } if (0 == maxX) { @@ -80,13 +77,10 @@ void NoFilterProc_Affine(const SkBitmapProcState& s, uint32_t xy[], SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask)) == 0); - SkPoint srcPt; - s.fInvProc(s.fInvMatrix, - SkIntToScalar(x) + SK_ScalarHalf, - SkIntToScalar(y) + SK_ScalarHalf, &srcPt); + const SkBitmapProcStateAutoMapper mapper(s, x, y); - SkFractionalInt fx = SkScalarToFractionalInt(srcPt.fX); - SkFractionalInt fy = SkScalarToFractionalInt(srcPt.fY); + SkFractionalInt fx = mapper.x(); + SkFractionalInt fy = mapper.y(); SkFractionalInt dx = s.fInvSxFractionalInt; SkFractionalInt dy = s.fInvKyFractionalInt; int maxX = s.fPixmap.width() - 1; diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_procs.h b/gfx/skia/skia/src/core/SkBitmapProcState_procs.h index 03e192719c5..cec079eae5f 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_procs.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState_procs.h @@ -1,4 +1,3 @@ - /* * Copyright 2011 Google Inc. * @@ -88,7 +87,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, #define FILTER_PROC(x, y, a, b, c, d, dst) NAME_WRAP(Filter_32_opaque)(x, y, a, b, c, d, dst) #define MAKENAME(suffix) NAME_WRAP(S32_opaque_D32 ## suffix) -#define DSTSIZE 32 #define SRCTYPE SkPMColor #define CHECKSTATE(state) SkASSERT(4 == state.fPixmap.info().bytesPerPixel()); \ SkASSERT(state.fAlphaScale == 256) @@ -100,7 +98,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, #define FILTER_PROC(x, y, a, b, c, d, dst) NAME_WRAP(Filter_32_alpha)(x, y, a, b, c, d, dst, alphaScale) #define MAKENAME(suffix) NAME_WRAP(S32_alpha_D32 ## suffix) -#define DSTSIZE 32 #define SRCTYPE SkPMColor #define CHECKSTATE(state) SkASSERT(4 == state.fPixmap.info().bytesPerPixel()); \ SkASSERT(state.fAlphaScale < 256) @@ -119,7 +116,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, } while (0) #define MAKENAME(suffix) NAME_WRAP(S16_opaque_D32 ## suffix) -#define DSTSIZE 32 #define SRCTYPE uint16_t #define CHECKSTATE(state) SkASSERT(kRGB_565_SkColorType == state.fPixmap.colorType()); \ SkASSERT(state.fAlphaScale == 256) @@ -135,7 +131,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, } while (0) #define MAKENAME(suffix) NAME_WRAP(S16_alpha_D32 ## suffix) -#define DSTSIZE 32 #define SRCTYPE uint16_t #define CHECKSTATE(state) SkASSERT(kRGB_565_SkColorType == state.fPixmap.colorType()); \ SkASSERT(state.fAlphaScale < 256) @@ -150,7 +145,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, #define FILTER_PROC(x, y, a, b, c, d, dst) NAME_WRAP(Filter_32_opaque)(x, y, a, b, c, d, dst) #define MAKENAME(suffix) NAME_WRAP(SI8_opaque_D32 ## suffix) -#define DSTSIZE 32 #define SRCTYPE uint8_t #define CHECKSTATE(state) SkASSERT(kIndex_8_SkColorType == state.fPixmap.colorType()); \ SkASSERT(state.fAlphaScale == 256) @@ -164,7 +158,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, #define FILTER_PROC(x, y, a, b, c, d, dst) NAME_WRAP(Filter_32_alpha)(x, y, a, b, c, d, dst, alphaScale) #define MAKENAME(suffix) NAME_WRAP(SI8_alpha_D32 ## suffix) -#define DSTSIZE 32 #define SRCTYPE uint8_t #define CHECKSTATE(state) SkASSERT(kIndex_8_SkColorType == state.fPixmap.colorType()); \ SkASSERT(state.fAlphaScale < 256) @@ -181,7 +174,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, #define FILTER_PROC(x, y, a, b, c, d, dst) *(dst) = Filter_4444_D32(x, y, a, b, c, d) #define MAKENAME(suffix) NAME_WRAP(S4444_opaque_D32 ## suffix) -#define DSTSIZE 32 #define SRCTYPE SkPMColor16 #define CHECKSTATE(state) SkASSERT(kARGB_4444_SkColorType == state.fPixmap.colorType()); \ SkASSERT(state.fAlphaScale == 256) @@ -197,7 +189,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, } while (0) #define MAKENAME(suffix) NAME_WRAP(S4444_alpha_D32 ## suffix) -#define DSTSIZE 32 #define SRCTYPE SkPMColor16 #define CHECKSTATE(state) SkASSERT(kARGB_4444_SkColorType == state.fPixmap.colorType()); \ SkASSERT(state.fAlphaScale < 256) @@ -216,7 +207,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, } while (0) #define MAKENAME(suffix) NAME_WRAP(SA8_alpha_D32 ## suffix) -#define DSTSIZE 32 #define SRCTYPE uint8_t #define CHECKSTATE(state) SkASSERT(kAlpha_8_SkColorType == state.fPixmap.colorType()); #define PREAMBLE(state) const SkPMColor pmColor = state.fPaintPMColor; @@ -235,7 +225,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, } while (0) #define MAKENAME(suffix) NAME_WRAP(SG8_alpha_D32 ## suffix) -#define DSTSIZE 32 #define SRCTYPE uint8_t #define CHECKSTATE(state) SkASSERT(kGray_8_SkColorType == state.fPixmap.colorType()); #define PREAMBLE(state) unsigned alphaScale = state.fAlphaScale @@ -243,105 +232,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, #define SRC_TO_FILTER(src) src #include "SkBitmapProcState_sample.h" -/***************************************************************************** - * - * D16 functions - * - */ - -// SRC == 8888 - -#undef FILTER_PROC -#define FILTER_PROC(x, y, a, b, c, d, dst) \ - do { \ - SkPMColor dstColor; \ - NAME_WRAP(Filter_32_opaque)(x, y, a, b, c, d, &dstColor); \ - (*dst) = SkPixel32ToPixel16(dstColor); \ - } while (0) - -#define MAKENAME(suffix) NAME_WRAP(S32_D16 ## suffix) -#define DSTSIZE 16 -#define SRCTYPE SkPMColor -#define CHECKSTATE(state) SkASSERT(4 == state.fPixmap.info().bytesPerPixel()); \ - SkASSERT(state.fPixmap.isOpaque()) -#define RETURNDST(src) SkPixel32ToPixel16(src) -#define SRC_TO_FILTER(src) src -#include "SkBitmapProcState_sample.h" - -// SRC == 565 - -#undef FILTER_PROC -#define FILTER_PROC(x, y, a, b, c, d, dst) \ - do { \ - uint32_t tmp = Filter_565_Expanded(x, y, a, b, c, d); \ - *(dst) = SkCompact_rgb_16((tmp) >> 5); \ - } while (0) - -#define MAKENAME(suffix) NAME_WRAP(S16_D16 ## suffix) -#define DSTSIZE 16 -#define SRCTYPE uint16_t -#define CHECKSTATE(state) SkASSERT(kRGB_565_SkColorType == state.fPixmap.colorType()) -#define RETURNDST(src) src -#define SRC_TO_FILTER(src) src -#include "SkBitmapProcState_sample.h" - -// SRC == Index8 - -#undef FILTER_PROC -#define FILTER_PROC(x, y, a, b, c, d, dst) \ - do { \ - uint32_t tmp = Filter_565_Expanded(x, y, a, b, c, d); \ - *(dst) = SkCompact_rgb_16((tmp) >> 5); \ - } while (0) - -#define MAKENAME(suffix) NAME_WRAP(SI8_D16 ## suffix) -#define DSTSIZE 16 -#define SRCTYPE uint8_t -#define CHECKSTATE(state) SkASSERT(kIndex_8_SkColorType == state.fPixmap.colorType()); \ - SkASSERT(state.fPixmap.isOpaque()) -#define PREAMBLE(state) const uint16_t* SK_RESTRICT table = state.fPixmap.ctable()->read16BitCache() -#define RETURNDST(src) table[src] -#define SRC_TO_FILTER(src) table[src] -#define POSTAMBLE(state) -#include "SkBitmapProcState_sample.h" - -/////////////////////////////////////////////////////////////////////////////// - -#undef FILTER_PROC -#define FILTER_PROC(x, y, a, b, c, d, dst) \ - do { \ - uint32_t tmp = Filter_565_Expanded(x, y, a, b, c, d); \ - *(dst) = SkCompact_rgb_16((tmp) >> 5); \ - } while (0) - - -// clamp - -#define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max) -#define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max) -#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF) -#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF) - -#define MAKENAME(suffix) NAME_WRAP(Clamp_S16_D16 ## suffix) -#define SRCTYPE uint16_t -#define DSTTYPE uint16_t -#define CHECKSTATE(state) SkASSERT(kRGB_565_SkColorType == state.fPixmap.colorType()) -#define SRC_TO_FILTER(src) src -#include "SkBitmapProcState_shaderproc.h" - - -#define TILEX_PROCF(fx, max) (((fx) & 0xFFFF) * ((max) + 1) >> 16) -#define TILEY_PROCF(fy, max) (((fy) & 0xFFFF) * ((max) + 1) >> 16) -#define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) -#define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) - -#define MAKENAME(suffix) NAME_WRAP(Repeat_S16_D16 ## suffix) -#define SRCTYPE uint16_t -#define DSTTYPE uint16_t -#define CHECKSTATE(state) SkASSERT(kRGB_565_SkColorType == state.fPixmap.colorType()) -#define SRC_TO_FILTER(src) src -#include "SkBitmapProcState_shaderproc.h" - #define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max) #define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max) @@ -352,7 +242,6 @@ static inline U8CPU Filter_8(unsigned x, unsigned y, #define FILTER_PROC(x, y, a, b, c, d, dst) NAME_WRAP(Filter_32_opaque)(x, y, a, b, c, d, dst) #define MAKENAME(suffix) NAME_WRAP(Clamp_SI8_opaque_D32 ## suffix) #define SRCTYPE uint8_t -#define DSTTYPE uint32_t #define CHECKSTATE(state) SkASSERT(kIndex_8_SkColorType == state.fPixmap.colorType()) #define PREAMBLE(state) const SkPMColor* SK_RESTRICT table = state.fPixmap.ctable()->readColors() #define SRC_TO_FILTER(src) table[src] diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_sample.h b/gfx/skia/skia/src/core/SkBitmapProcState_sample.h index f70b758ac23..4a022884d5c 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_sample.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState_sample.h @@ -7,40 +7,23 @@ #include "SkUtils.h" -#if DSTSIZE==32 - #define DSTTYPE SkPMColor -#elif DSTSIZE==16 - #define DSTTYPE uint16_t -#else - #error "need DSTSIZE to be 32 or 16" -#endif - -#if (DSTSIZE == 32) - #define BITMAPPROC_MEMSET(ptr, value, n) sk_memset32(ptr, value, n) -#elif (DSTSIZE == 16) - #define BITMAPPROC_MEMSET(ptr, value, n) sk_memset16(ptr, value, n) -#else - #error "unsupported DSTSIZE" -#endif - - // declare functions externally to suppress warnings. void MAKENAME(_nofilter_DXDY)(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, - int count, DSTTYPE* SK_RESTRICT colors); + int count, SkPMColor* SK_RESTRICT colors); void MAKENAME(_nofilter_DX)(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, - int count, DSTTYPE* SK_RESTRICT colors); + int count, SkPMColor* SK_RESTRICT colors); void MAKENAME(_filter_DX)(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, - int count, DSTTYPE* SK_RESTRICT colors); + int count, SkPMColor* SK_RESTRICT colors); void MAKENAME(_filter_DXDY)(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, - int count, DSTTYPE* SK_RESTRICT colors); + int count, SkPMColor* SK_RESTRICT colors); void MAKENAME(_nofilter_DXDY)(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, - int count, DSTTYPE* SK_RESTRICT colors) { + int count, SkPMColor* SK_RESTRICT colors) { SkASSERT(count > 0 && colors != nullptr); SkASSERT(kNone_SkFilterQuality == s.fFilterLevel); SkDEBUGCODE(CHECKSTATE(s);) @@ -82,7 +65,7 @@ void MAKENAME(_nofilter_DXDY)(const SkBitmapProcState& s, void MAKENAME(_nofilter_DX)(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, - int count, DSTTYPE* SK_RESTRICT colors) { + int count, SkPMColor* SK_RESTRICT colors) { SkASSERT(count > 0 && colors != nullptr); SkASSERT(s.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)); SkASSERT(kNone_SkFilterQuality == s.fFilterLevel); @@ -104,8 +87,8 @@ void MAKENAME(_nofilter_DX)(const SkBitmapProcState& s, if (1 == s.fPixmap.width()) { src = srcAddr[0]; - DSTTYPE dstValue = RETURNDST(src); - BITMAPPROC_MEMSET(colors, dstValue, count); + SkPMColor dstValue = RETURNDST(src); + sk_memset32(colors, dstValue, count); } else { int i; for (i = (count >> 2); i > 0; --i) { @@ -137,7 +120,7 @@ void MAKENAME(_nofilter_DX)(const SkBitmapProcState& s, void MAKENAME(_filter_DX)(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, - int count, DSTTYPE* SK_RESTRICT colors) { + int count, SkPMColor* SK_RESTRICT colors) { SkASSERT(count > 0 && colors != nullptr); SkASSERT(s.fFilterLevel != kNone_SkFilterQuality); SkDEBUGCODE(CHECKSTATE(s);) @@ -183,7 +166,7 @@ void MAKENAME(_filter_DX)(const SkBitmapProcState& s, } void MAKENAME(_filter_DXDY)(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, - int count, DSTTYPE* SK_RESTRICT colors) { + int count, SkPMColor* SK_RESTRICT colors) { SkASSERT(count > 0 && colors != nullptr); SkASSERT(s.fFilterLevel != kNone_SkFilterQuality); SkDEBUGCODE(CHECKSTATE(s);) @@ -225,8 +208,6 @@ void MAKENAME(_filter_DXDY)(const SkBitmapProcState& s, } #undef MAKENAME -#undef DSTSIZE -#undef DSTTYPE #undef SRCTYPE #undef CHECKSTATE #undef RETURNDST @@ -245,4 +226,3 @@ void MAKENAME(_filter_DXDY)(const SkBitmapProcState& s, #undef GET_FILTER_ROW #undef GET_FILTER_ROW_PROC #undef GET_FILTER_PROC -#undef BITMAPPROC_MEMSET diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_shaderproc.h b/gfx/skia/skia/src/core/SkBitmapProcState_shaderproc.h index 94b2d3b48c2..d41ff063e4d 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_shaderproc.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState_shaderproc.h @@ -1,4 +1,3 @@ - /* * Copyright 2011 Google Inc. * @@ -12,11 +11,10 @@ // Can't be static in the general case because some of these implementations // will be defined and referenced in different object files. -void SCALE_FILTER_NAME(const SkBitmapProcState& s, int x, int y, - DSTTYPE* SK_RESTRICT colors, int count); +void SCALE_FILTER_NAME(const void* sIn, int x, int y, SkPMColor* SK_RESTRICT colors, int count); -void SCALE_FILTER_NAME(const SkBitmapProcState& s, int x, int y, - DSTTYPE* SK_RESTRICT colors, int count) { +void SCALE_FILTER_NAME(const void* sIn, int x, int y, SkPMColor* SK_RESTRICT colors, int count) { + const SkBitmapProcState& s = *static_cast(sIn); SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0); SkASSERT(s.fInvKy == 0); @@ -84,7 +82,6 @@ void SCALE_FILTER_NAME(const SkBitmapProcState& s, int x, int y, #undef TILEY_LOW_BITS #undef MAKENAME #undef SRCTYPE -#undef DSTTYPE #undef CHECKSTATE #undef SRC_TO_FILTER #undef FILTER_TO_DST diff --git a/gfx/skia/skia/src/core/SkBitmapScaler.cpp b/gfx/skia/skia/src/core/SkBitmapScaler.cpp index 965955a2dcb..dc04691c79b 100644 --- a/gfx/skia/skia/src/core/SkBitmapScaler.cpp +++ b/gfx/skia/skia/src/core/SkBitmapScaler.cpp @@ -11,7 +11,6 @@ #include "SkImageInfo.h" #include "SkPixmap.h" #include "SkRect.h" -#include "SkScalar.h" #include "SkTArray.h" // SkResizeFilter ---------------------------------------------------------------- @@ -74,7 +73,7 @@ SkResizeFilter::SkResizeFilter(SkBitmapScaler::ResizeMethod method, fBitmapFilter = new SkTriangleFilter; break; case SkBitmapScaler::RESIZE_MITCHELL: - fBitmapFilter = new SkMitchellFilter(1.f / 3.f, 1.f / 3.f); + fBitmapFilter = new SkMitchellFilter; break; case SkBitmapScaler::RESIZE_HAMMING: fBitmapFilter = new SkHammingFilter; @@ -130,45 +129,65 @@ void SkResizeFilter::computeFilters(int srcSize, // to support the filtering function. float srcSupport = fBitmapFilter->width() / clampedScale; - // Speed up the divisions below by turning them into multiplies. float invScale = 1.0f / scale; - SkTArray filterValues(64); - SkTArray fixedFilterValues(64); + SkSTArray<64, float, true> filterValuesArray; + SkSTArray<64, SkConvolutionFilter1D::ConvolutionFixed, true> fixedFilterValuesArray; // Loop over all pixels in the output range. We will generate one set of // filter values for each one. Those values will tell us how to blend the // source pixels to compute the destination pixel. + + // This is the pixel in the source directly under the pixel in the dest. + // Note that we base computations on the "center" of the pixels. To see + // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x + // downscale should "cover" the pixels around the pixel with *its center* + // at coordinates (2.5, 2.5) in the source, not those around (0, 0). + // Hence we need to scale coordinates (0.5, 0.5), not (0, 0). +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER + int destLimit = SkScalarTruncToInt(SkScalarCeilToScalar(destSubsetHi) + - SkScalarFloorToScalar(destSubsetLo)); +#else + destSubsetLo = SkScalarFloorToScalar(destSubsetLo); + destSubsetHi = SkScalarCeilToScalar(destSubsetHi); + float srcPixel = (destSubsetLo + 0.5f) * invScale; + int destLimit = SkScalarTruncToInt(destSubsetHi - destSubsetLo); +#endif + output->reserveAdditional(destLimit, SkScalarCeilToInt(destLimit * srcSupport * 2)); +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER for (int destSubsetI = SkScalarFloorToInt(destSubsetLo); destSubsetI < SkScalarCeilToInt(destSubsetHi); - destSubsetI++) { - // Reset the arrays. We don't declare them inside so they can re-use the - // same malloc-ed buffer. - filterValues.reset(); - fixedFilterValues.reset(); - - // This is the pixel in the source directly under the pixel in the dest. - // Note that we base computations on the "center" of the pixels. To see - // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x - // downscale should "cover" the pixels around the pixel with *its center* - // at coordinates (2.5, 2.5) in the source, not those around (0, 0). - // Hence we need to scale coordinates (0.5, 0.5), not (0, 0). - float srcPixel = (static_cast(destSubsetI) + 0.5f) * invScale; - + destSubsetI++) +#else + for (int destI = 0; destI < destLimit; srcPixel += invScale, destI++) +#endif + { // Compute the (inclusive) range of source pixels the filter covers. +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER + float srcPixel = (static_cast(destSubsetI) + 0.5f) * invScale; int srcBegin = SkTMax(0, SkScalarFloorToInt(srcPixel - srcSupport)); int srcEnd = SkTMin(srcSize - 1, SkScalarCeilToInt(srcPixel + srcSupport)); +#else + float srcBegin = SkTMax(0.f, SkScalarFloorToScalar(srcPixel - srcSupport)); + float srcEnd = SkTMin(srcSize - 1.f, SkScalarCeilToScalar(srcPixel + srcSupport)); +#endif // Compute the unnormalized filter value at each location of the source // it covers. +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER float filterSum = 0.0f; // Sub of the filter values for normalizing. + int filterCount = srcEnd - srcBegin + 1; + filterValuesArray.reset(filterCount); for (int curFilterPixel = srcBegin; curFilterPixel <= srcEnd; curFilterPixel++) { - // Distance from the center of the filter, this is the filter coordinate - // in source space. We also need to consider the center of the pixel - // when comparing distance against 'srcPixel'. In the 5x downscale - // example used above the distance from the center of the filter to - // the pixel with coordinates (2, 2) should be 0, because its center - // is at (2.5, 2.5). +#endif + // Sum of the filter values for normalizing. + // Distance from the center of the filter, this is the filter coordinate + // in source space. We also need to consider the center of the pixel + // when comparing distance against 'srcPixel'. In the 5x downscale + // example used above the distance from the center of the filter to + // the pixel with coordinates (2, 2) should be 0, because its center + // is at (2.5, 2.5). +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER float srcFilterDist = ((static_cast(curFilterPixel) + 0.5f) - srcPixel); @@ -177,79 +196,108 @@ void SkResizeFilter::computeFilters(int srcSize, // Compute the filter value at that location. float filterValue = fBitmapFilter->evaluate(destFilterDist); - filterValues.push_back(filterValue); + filterValuesArray[curFilterPixel - srcBegin] = filterValue; filterSum += filterValue; } - SkASSERT(!filterValues.empty()); - +#else + float destFilterDist = (srcBegin + 0.5f - srcPixel) * clampedScale; + int filterCount = SkScalarTruncToInt(srcEnd - srcBegin) + 1; + SkASSERT(filterCount > 0); + filterValuesArray.reset(filterCount); + float filterSum = fBitmapFilter->evaluate_n(destFilterDist, clampedScale, filterCount, + filterValuesArray.begin()); +#endif // The filter must be normalized so that we don't affect the brightness of // the image. Convert to normalized fixed point. - short fixedSum = 0; - for (int i = 0; i < filterValues.count(); i++) { - short curFixed = output->FloatToFixed(filterValues[i] / filterSum); + int fixedSum = 0; + fixedFilterValuesArray.reset(filterCount); + const float* filterValues = filterValuesArray.begin(); + SkConvolutionFilter1D::ConvolutionFixed* fixedFilterValues = fixedFilterValuesArray.begin(); +#ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER + float invFilterSum = 1 / filterSum; +#endif + for (int fixedI = 0; fixedI < filterCount; fixedI++) { +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER + int curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] / filterSum); +#else + int curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] * invFilterSum); +#endif fixedSum += curFixed; - fixedFilterValues.push_back(curFixed); + fixedFilterValues[fixedI] = SkToS16(curFixed); } + SkASSERT(fixedSum <= 0x7FFF); // The conversion to fixed point will leave some rounding errors, which // we add back in to avoid affecting the brightness of the image. We // arbitrarily add this to the center of the filter array (this won't always // be the center of the filter function since it could get clipped on the // edges, but it doesn't matter enough to worry about that case). - short leftovers = output->FloatToFixed(1.0f) - fixedSum; - fixedFilterValues[fixedFilterValues.count() / 2] += leftovers; + int leftovers = SkConvolutionFilter1D::FloatToFixed(1) - fixedSum; + fixedFilterValues[filterCount / 2] += leftovers; // Now it's ready to go. - output->AddFilter(srcBegin, &fixedFilterValues[0], - static_cast(fixedFilterValues.count())); +#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER + output->AddFilter(srcBegin, fixedFilterValues, filterCount); +#else + output->AddFilter(SkScalarFloorToInt(srcBegin), fixedFilterValues, filterCount); +#endif } if (convolveProcs.fApplySIMDPadding) { - convolveProcs.fApplySIMDPadding( output ); + convolveProcs.fApplySIMDPadding(output); } } -bool SkBitmapScaler::Resize(SkBitmap* resultPtr, const SkPixmap& source, ResizeMethod method, - int destWidth, int destHeight, SkBitmap::Allocator* allocator) { - if (nullptr == source.addr() || source.colorType() != kN32_SkColorType || - source.width() < 1 || source.height() < 1) - { +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static bool valid_for_resize(const SkPixmap& source, int dstW, int dstH) { + // TODO: Seems like we shouldn't care about the swizzle of source, just that it's 8888 + return source.addr() && source.colorType() == kN32_SkColorType && + source.width() >= 1 && source.height() >= 1 && dstW >= 1 && dstH >= 1; +} + +bool SkBitmapScaler::Resize(const SkPixmap& result, const SkPixmap& source, ResizeMethod method) { + if (!valid_for_resize(source, result.width(), result.height())) { return false; } - - if (destWidth < 1 || destHeight < 1) { + if (!result.addr() || result.colorType() != source.colorType()) { return false; } SkConvolutionProcs convolveProcs= { 0, nullptr, nullptr, nullptr, nullptr }; PlatformConvolutionProcs(&convolveProcs); - SkRect destSubset = SkRect::MakeIWH(destWidth, destHeight); + SkRect destSubset = SkRect::MakeIWH(result.width(), result.height()); SkResizeFilter filter(method, source.width(), source.height(), - destWidth, destHeight, destSubset, convolveProcs); + result.width(), result.height(), destSubset, convolveProcs); // Get a subset encompassing this touched area. We construct the // offsets and row strides such that it looks like a new bitmap, while // referring to the old data. const uint8_t* sourceSubset = reinterpret_cast(source.addr()); - // Convolve into the result. - SkBitmap result; - result.setInfo(SkImageInfo::MakeN32(SkScalarCeilToInt(destSubset.width()), - SkScalarCeilToInt(destSubset.height()), - source.alphaType())); - result.allocPixels(allocator, nullptr); - if (!result.readyToDraw()) { - return false; + return BGRAConvolve2D(sourceSubset, static_cast(source.rowBytes()), + !source.isOpaque(), filter.xFilter(), filter.yFilter(), + static_cast(result.rowBytes()), + static_cast(result.writable_addr()), + convolveProcs, true); +} + +bool SkBitmapScaler::Resize(SkBitmap* resultPtr, const SkPixmap& source, ResizeMethod method, + int destWidth, int destHeight, SkBitmap::Allocator* allocator) { + // Preflight some of the checks, to avoid allocating the result if we don't need it. + if (!valid_for_resize(source, destWidth, destHeight)) { + return false; } - if (!BGRAConvolve2D(sourceSubset, static_cast(source.rowBytes()), - !source.isOpaque(), filter.xFilter(), filter.yFilter(), - static_cast(result.rowBytes()), - static_cast(result.getPixels()), - convolveProcs, true)) { + SkBitmap result; + result.setInfo(SkImageInfo::MakeN32(destWidth, destHeight, source.alphaType())); + result.allocPixels(allocator, nullptr); + + SkPixmap resultPM; + if (!result.peekPixels(&resultPM) || !Resize(resultPM, source, method)) { return false; } diff --git a/gfx/skia/skia/src/core/SkBitmapScaler.h b/gfx/skia/skia/src/core/SkBitmapScaler.h index 03feec3e127..3d734d6efc5 100644 --- a/gfx/skia/skia/src/core/SkBitmapScaler.h +++ b/gfx/skia/skia/src/core/SkBitmapScaler.h @@ -29,6 +29,16 @@ public: RESIZE_LastMethod = RESIZE_MITCHELL, }; + /** + * Given already-allocated src and dst pixmaps, this will scale the src pixels using the + * specified resize-method and write the results into the pixels pointed to by dst. + */ + static bool Resize(const SkPixmap& dst, const SkPixmap& src, ResizeMethod method); + + /** + * Helper function that manages allocating a bitmap to hold the dst pixels, and then calls + * the pixmap version of Resize. + */ static bool Resize(SkBitmap* result, const SkPixmap& src, ResizeMethod method, int dest_width, int dest_height, SkBitmap::Allocator* = nullptr); diff --git a/gfx/skia/skia/src/core/SkBlitMask.h b/gfx/skia/skia/src/core/SkBlitMask.h index f36f9f3d829..b53ff7dfd82 100644 --- a/gfx/skia/skia/src/core/SkBlitMask.h +++ b/gfx/skia/skia/src/core/SkBlitMask.h @@ -44,7 +44,7 @@ public: * onto a row of dst colors. The RowFactory that returns this function ptr * will have been told the formats for the mask and the dst. */ - typedef void (*RowProc)(void* dst, const void* mask, + typedef void (*RowProc)(SkPMColor* dst, const void* mask, const SkPMColor* src, int width); /** diff --git a/gfx/skia/skia/src/core/SkBlitMask_D32.cpp b/gfx/skia/skia/src/core/SkBlitMask_D32.cpp index 3cc791af4ed..c39ecfb7595 100644 --- a/gfx/skia/skia/src/core/SkBlitMask_D32.cpp +++ b/gfx/skia/skia/src/core/SkBlitMask_D32.cpp @@ -76,9 +76,9 @@ bool SkBlitMask::BlitColor(const SkPixmap& device, const SkMask& mask, /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -static void BW_RowProc_Blend(SkPMColor* SK_RESTRICT dst, - const uint8_t* SK_RESTRICT mask, - const SkPMColor* SK_RESTRICT src, int count) { +static void BW_RowProc_Blend( + SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) { + const uint8_t* SK_RESTRICT mask = static_cast(maskIn); int i, octuple = (count + 7) >> 3; for (i = 0; i < octuple; ++i) { int m = *mask++; @@ -105,9 +105,9 @@ static void BW_RowProc_Blend(SkPMColor* SK_RESTRICT dst, } } -static void BW_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, - const uint8_t* SK_RESTRICT mask, - const SkPMColor* SK_RESTRICT src, int count) { +static void BW_RowProc_Opaque( + SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) { + const uint8_t* SK_RESTRICT mask = static_cast(maskIn); int i, octuple = (count + 7) >> 3; for (i = 0; i < octuple; ++i) { int m = *mask++; @@ -134,9 +134,9 @@ static void BW_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, } } -static void A8_RowProc_Blend(SkPMColor* SK_RESTRICT dst, - const uint8_t* SK_RESTRICT mask, - const SkPMColor* SK_RESTRICT src, int count) { +static void A8_RowProc_Blend( + SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) { + const uint8_t* SK_RESTRICT mask = static_cast(maskIn); for (int i = 0; i < count; ++i) { if (mask[i]) { dst[i] = SkBlendARGB32(src[i], dst[i], mask[i]); @@ -153,9 +153,9 @@ static void A8_RowProc_Blend(SkPMColor* SK_RESTRICT dst, #define EXPAND1(v, m, s) (((v) >> 8) & (m)) * (s) #define COMBINE(e0, e1, m) ((((e0) >> 8) & (m)) | ((e1) & ~(m))) -static void A8_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, - const uint8_t* SK_RESTRICT mask, - const SkPMColor* SK_RESTRICT src, int count) { +static void A8_RowProc_Opaque( + SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) { + const uint8_t* SK_RESTRICT mask = static_cast(maskIn); for (int i = 0; i < count; ++i) { int m = mask[i]; if (m) { @@ -188,9 +188,9 @@ static int src_alpha_blend(int src, int dst, int srcA, int mask) { return dst + SkAlphaMul(src - SkAlphaMul(srcA, dst), mask); } -static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst, - const uint16_t* SK_RESTRICT mask, - const SkPMColor* SK_RESTRICT src, int count) { +static void LCD16_RowProc_Blend( + SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) { + const uint16_t* SK_RESTRICT mask = static_cast(maskIn); for (int i = 0; i < count; ++i) { uint16_t m = mask[i]; if (0 == m) { @@ -231,9 +231,9 @@ static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst, } } -static void LCD16_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, - const uint16_t* SK_RESTRICT mask, - const SkPMColor* SK_RESTRICT src, int count) { +static void LCD16_RowProc_Opaque( + SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) { + const uint16_t* SK_RESTRICT mask = static_cast(maskIn); for (int i = 0; i < count; ++i) { uint16_t m = mask[i]; if (0 == m) { diff --git a/gfx/skia/skia/src/core/SkBlitter.cpp b/gfx/skia/skia/src/core/SkBlitter.cpp index 064dc16eda4..b73be40a457 100644 --- a/gfx/skia/skia/src/core/SkBlitter.cpp +++ b/gfx/skia/skia/src/core/SkBlitter.cpp @@ -9,7 +9,6 @@ #include "SkAntiRun.h" #include "SkColor.h" #include "SkColorFilter.h" -#include "SkFilterShader.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkMask.h" @@ -858,7 +857,7 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, if (cf) { SkASSERT(shader); - shader = new SkFilterShader(shader, cf); + shader = shader->newWithColorFilter(cf); paint.writable()->setShader(shader)->unref(); // blitters should ignore the presence/absence of a filter, since // if there is one, the shader will take care of it. diff --git a/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp b/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp index e44ad02da57..a00ed86d8e0 100644 --- a/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp @@ -570,7 +570,7 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) SkXfermode* xfer = fXfermode; do { shaderContext->shadeSpan(x, y, span, width); - xfer->xfer32((SkPMColor*)dstRow, span, width, maskRow); + xfer->xfer32(reinterpret_cast(dstRow), span, width, maskRow); dstRow += dstRB; maskRow += maskRB; y += 1; @@ -578,7 +578,7 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) } else { do { shaderContext->shadeSpan(x, y, span, width); - proc(dstRow, maskRow, span, width); + proc(reinterpret_cast(dstRow), maskRow, span, width); dstRow += dstRB; maskRow += maskRB; y += 1; diff --git a/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp b/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp index 06dfeea1c18..38edd60a9dd 100644 --- a/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp @@ -134,20 +134,6 @@ private: typedef SkShaderBlitter INHERITED; }; -// used only if the shader can perform shadSpan16 -class SkRGB16_Shader16_Blitter : public SkRGB16_Shader_Blitter { -public: - SkRGB16_Shader16_Blitter(const SkPixmap& device, const SkPaint& paint, - SkShader::Context* shaderContext); - void blitH(int x, int y, int width) override; - virtual void blitAntiH(int x, int y, const SkAlpha* antialias, - const int16_t* runs) override; - void blitRect(int x, int y, int width, int height) override; - -private: - typedef SkRGB16_Shader_Blitter INHERITED; -}; - class SkRGB16_Shader_Xfermode_Blitter : public SkShaderBlitter { public: SkRGB16_Shader_Xfermode_Blitter(const SkPixmap& device, const SkPaint& paint, @@ -692,131 +678,6 @@ void SkRGB16_Blitter::blitRect(int x, int y, int width, int height) { /////////////////////////////////////////////////////////////////////////////// -SkRGB16_Shader16_Blitter::SkRGB16_Shader16_Blitter(const SkPixmap& device, - const SkPaint& paint, - SkShader::Context* shaderContext) - : SkRGB16_Shader_Blitter(device, paint, shaderContext) -{ - SkASSERT(SkShader::CanCallShadeSpan16(fShaderFlags)); -} - -void SkRGB16_Shader16_Blitter::blitH(int x, int y, int width) { - SkASSERT(x + width <= fDevice.width()); - - uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y); - SkShader::Context* shaderContext = fShaderContext; - - int alpha = shaderContext->getSpan16Alpha(); - if (0xFF == alpha) { - shaderContext->shadeSpan16(x, y, device, width); - } else { - uint16_t* span16 = (uint16_t*)fBuffer; - shaderContext->shadeSpan16(x, y, span16, width); - SkBlendRGB16(span16, device, SkAlpha255To256(alpha), width); - } -} - -void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) { - SkShader::Context* shaderContext = fShaderContext; - uint16_t* dst = fDevice.writable_addr16(x, y); - size_t dstRB = fDevice.rowBytes(); - int alpha = shaderContext->getSpan16Alpha(); - - if (0xFF == alpha) { - if (fShaderFlags & SkShader::kConstInY16_Flag) { - // have the shader blit directly into the device the first time - shaderContext->shadeSpan16(x, y, dst, width); - // and now just memcpy that line on the subsequent lines - if (--height > 0) { - const uint16_t* orig = dst; - do { - dst = (uint16_t*)((char*)dst + dstRB); - memcpy(dst, orig, width << 1); - } while (--height); - } - } else { // need to call shadeSpan16 for every line - do { - shaderContext->shadeSpan16(x, y, dst, width); - y += 1; - dst = (uint16_t*)((char*)dst + dstRB); - } while (--height); - } - } else { - int scale = SkAlpha255To256(alpha); - uint16_t* span16 = (uint16_t*)fBuffer; - if (fShaderFlags & SkShader::kConstInY16_Flag) { - shaderContext->shadeSpan16(x, y, span16, width); - do { - SkBlendRGB16(span16, dst, scale, width); - dst = (uint16_t*)((char*)dst + dstRB); - } while (--height); - } else { - do { - shaderContext->shadeSpan16(x, y, span16, width); - SkBlendRGB16(span16, dst, scale, width); - y += 1; - dst = (uint16_t*)((char*)dst + dstRB); - } while (--height); - } - } -} - -void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y, - const SkAlpha* SK_RESTRICT antialias, - const int16_t* SK_RESTRICT runs) { - SkShader::Context* shaderContext = fShaderContext; - SkPMColor* SK_RESTRICT span = fBuffer; - uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y); - - int alpha = shaderContext->getSpan16Alpha(); - uint16_t* span16 = (uint16_t*)span; - - if (0xFF == alpha) { - for (;;) { - int count = *runs; - if (count <= 0) { - break; - } - SkASSERT(count <= fDevice.width()); // don't overrun fBuffer - - int aa = *antialias; - if (aa == 255) { - // go direct to the device! - shaderContext->shadeSpan16(x, y, device, count); - } else if (aa) { - shaderContext->shadeSpan16(x, y, span16, count); - SkBlendRGB16(span16, device, SkAlpha255To256(aa), count); - } - device += count; - runs += count; - antialias += count; - x += count; - } - } else { // span alpha is < 255 - alpha = SkAlpha255To256(alpha); - for (;;) { - int count = *runs; - if (count <= 0) { - break; - } - SkASSERT(count <= fDevice.width()); // don't overrun fBuffer - - int aa = SkAlphaMul(*antialias, alpha); - if (aa) { - shaderContext->shadeSpan16(x, y, span16, count); - SkBlendRGB16(span16, device, SkAlpha255To256(aa), count); - } - - device += count; - runs += count; - antialias += count; - x += count; - } - } -} - -/////////////////////////////////////////////////////////////////////////////// - SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext) @@ -834,8 +695,7 @@ SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkPixmap& device, if (!(shaderFlags & SkShader::kOpaqueAlpha_Flag)) { flags |= SkBlitRow::kSrcPixelAlpha_Flag; } - // don't dither if the shader is really 16bit - if (paint.isDither() && !(shaderFlags & SkShader::kIntrinsicly16_Flag)) { + if (paint.isDither()) { flags |= SkBlitRow::kDither_Flag; } // used when we know our global alpha is 0xFF @@ -1047,8 +907,6 @@ SkBlitter* SkBlitter_ChooseD565(const SkPixmap& device, const SkPaint& paint, if (mode) { blitter = allocator->createT(device, paint, shaderContext); - } else if (shaderContext->canCallShadeSpan16()) { - blitter = allocator->createT(device, paint, shaderContext); } else { blitter = allocator->createT(device, paint, shaderContext); } diff --git a/gfx/skia/skia/src/core/SkBuffer.cpp b/gfx/skia/skia/src/core/SkBuffer.cpp index 86c3bed3f14..df8dc695946 100644 --- a/gfx/skia/skia/src/core/SkBuffer.cpp +++ b/gfx/skia/skia/src/core/SkBuffer.cpp @@ -35,7 +35,7 @@ size_t SkRBuffer::skipToAlign4() } bool SkRBufferWithSizeCheck::read(void* buffer, size_t size) { - fError = fError || (fPos + size > fStop); + fError = fError || (size > static_cast(fStop - fPos)); if (!fError && (size > 0)) { readNoSizeCheck(buffer, size); } diff --git a/gfx/skia/skia/src/core/SkCanvas.cpp b/gfx/skia/skia/src/core/SkCanvas.cpp index 1e49fe272df..e577b219326 100644 --- a/gfx/skia/skia/src/core/SkCanvas.cpp +++ b/gfx/skia/skia/src/core/SkCanvas.cpp @@ -17,6 +17,8 @@ #include "SkDrawLooper.h" #include "SkErrorInternals.h" #include "SkImage.h" +#include "SkImage_Base.h" +#include "SkMatrixUtils.h" #include "SkMetaData.h" #include "SkNinePatchIter.h" #include "SkPaintPriv.h" @@ -35,10 +37,12 @@ #include #if SK_SUPPORT_GPU +#include "GrContext.h" #include "GrRenderTarget.h" +#include "SkGr.h" #endif -#define SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS +#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0) /* * Return true if the drawing this rect would hit every pixels in the canvas. @@ -112,7 +116,6 @@ bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() { // experimental for faster tiled drawing... //#define SK_ENABLE_CLIP_QUICKREJECT - //#define SK_TRACE_SAVERESTORE #ifdef SK_TRACE_SAVERESTORE @@ -479,7 +482,7 @@ public: // Make rawBounds include all paint outsets except for those due to image filters. rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage); } - (void)canvas->internalSaveLayer(rawBounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag, + (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp), SkCanvas::kFullLayer_SaveLayerStrategy); fTempLayerForImageFilter = true; // we remove the imagefilter/xfermode inside doNext() @@ -592,6 +595,13 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { ////////// macros to place around the internal draw calls ////////////////// +#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \ + this->predrawNotify(); \ + AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \ + while (looper.next(SkDrawFilter::kBitmap_Type)) { \ + SkDrawIter iter(this); + + #define LOOPER_BEGIN_DRAWDEVICE(paint, type) \ this->predrawNotify(); \ AutoDrawLooper looper(this, fProps, paint, true); \ @@ -1044,15 +1054,15 @@ void SkCanvas::internalSave() { fClipStack->save(); } -static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { +bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) { #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG - return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; + return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag); #else return true; #endif } -bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, +bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags, SkIRect* intersection, const SkImageFilter* imageFilter) { SkIRect clipBounds; if (!this->getClipDeviceBounds(&clipBounds)) { @@ -1075,6 +1085,10 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, } else { bounds = nullptr; } +#else + if (bounds && !imageFilter->canComputeFastBounds()) { + bounds = nullptr; + } #endif } SkIRect ir; @@ -1085,7 +1099,7 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, r.roundOut(&ir); // early exit if the layer's bounds are clipped out if (!ir.intersect(clipBounds)) { - if (bounds_affects_clip(flags)) { + if (BoundsAffectsClip(saveLayerFlags)) { fCachedLocalClipBoundsDirty = true; fMCRec->fRasterClip.setEmpty(); } @@ -1096,7 +1110,7 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, } SkASSERT(!ir.isEmpty()); - if (bounds_affects_clip(flags)) { + if (BoundsAffectsClip(saveLayerFlags)) { // Simplify the current clips since they will be applied properly during restore() fCachedLocalClipBoundsDirty = true; fClipStack->clipDevRect(ir, SkRegion::kReplace_Op); @@ -1109,30 +1123,98 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, return true; } +#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS +uint32_t SkCanvas::SaveFlagsToSaveLayerFlags(SaveFlags flags) { + uint32_t layerFlags = 0; + + if (0 == (flags & kClipToLayer_SaveFlag)) { + layerFlags |= kDontClipToLayer_PrivateSaveLayerFlag; + } + if (0 == (flags & kHasAlphaLayer_SaveFlag)) { + layerFlags |= kIsOpaque_SaveLayerFlag; + } + return layerFlags; +} + +uint32_t SkCanvas::SaveLayerFlagsToSaveFlags(SaveLayerFlags layerFlags) { + uint32_t saveFlags = 0; + + if (0 == (layerFlags & kDontClipToLayer_PrivateSaveLayerFlag)) { + saveFlags |= kClipToLayer_SaveFlag; + } + if (0 == (layerFlags & kIsOpaque_SaveLayerFlag)) { + saveFlags |= kHasAlphaLayer_SaveFlag; + } + return saveFlags; +} +#endif + int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { - if (gIgnoreSaveLayerBounds) { - bounds = nullptr; - } - SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag); - fSaveCount += 1; - this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy); - return this->getSaveCount() - 1; + return this->saveLayer(SaveLayerRec(bounds, paint, 0)); } +#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) { + return this->saveLayer(SaveLayerRec(bounds, paint, SaveFlagsToSaveLayerFlags(flags))); +} +#endif + +int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) { + return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag)); +} + +int SkCanvas::saveLayer(const SaveLayerRec& origRec) { + SaveLayerRec rec(origRec); if (gIgnoreSaveLayerBounds) { - bounds = nullptr; + rec.fBounds = nullptr; } - SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags); + SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec); fSaveCount += 1; - this->internalSaveLayer(bounds, paint, flags, strategy); + this->internalSaveLayer(rec, strategy); return this->getSaveCount() - 1; } -void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags, - SaveLayerStrategy strategy) { +static void draw_filter_into_device(SkBaseDevice* src, const SkImageFilter* filter, + SkBaseDevice* dst, const SkMatrix& ctm) { + + SkBitmap srcBM; + +#if SK_SUPPORT_GPU + GrRenderTarget* srcRT = src->accessRenderTarget(); + if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) { + // When both the src & the dst are on the gpu but the src doesn't have a texture, + // we create a temporary texture for the draw. + // TODO: we should actually only copy the portion of the source needed to apply the image + // filter + GrContext* context = srcRT->getContext(); + SkAutoTUnref tex(context->textureProvider()->createTexture(srcRT->desc(), true)); + + context->copySurface(tex, srcRT); + + GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM); + } else +#endif + { + srcBM = src->accessBitmap(false); + } + + SkCanvas c(dst); + + SkAutoTUnref localF(filter->newWithLocalMatrix(ctm)); + SkPaint p; + p.setImageFilter(localF); + const SkScalar x = SkIntToScalar(src->getOrigin().x()); + const SkScalar y = SkIntToScalar(src->getOrigin().y()); + c.drawBitmap(srcBM, x, y, &p); +} + +void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) { + const SkRect* bounds = rec.fBounds; + const SkPaint* paint = rec.fPaint; + SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags; + #ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG - flags |= kClipToLayer_SaveFlag; + saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag; #endif // do this before we create the layer. We don't call the public save() since @@ -1142,7 +1224,7 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav fDeviceCMDirty = true; SkIRect ir; - if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : nullptr)) { + if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) { return; } @@ -1152,7 +1234,7 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav return; } - bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag); + bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag); SkPixelGeometry geo = fProps.pixelGeometry(); if (paint) { // TODO: perhaps add a query to filters so we might preserve opaqueness... @@ -1172,8 +1254,11 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav bool forceSpriteOnRestore = false; { + const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() || + (saveLayerFlags & kPreserveLCDText_SaveLayerFlag); const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage; - const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo); + const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo, + preserveLCDText, false); SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint); if (nullptr == newDev) { // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint) @@ -1188,8 +1273,12 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav } device = newDev; } - device->setOrigin(ir.fLeft, ir.fTop); + + if (rec.fBackdrop) { + draw_filter_into_device(fMCRec->fTopLayer->fDevice, rec.fBackdrop, device, fMCRec->fMatrix); + } + DeviceCM* layer = new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore); device->unref(); @@ -1200,9 +1289,16 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav } int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { - return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag); + if (0xFF == alpha) { + return this->saveLayer(bounds, nullptr); + } else { + SkPaint tmpPaint; + tmpPaint.setAlpha(alpha); + return this->saveLayer(bounds, &tmpPaint); + } } +#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, SaveFlags flags) { if (0xFF == alpha) { @@ -1213,6 +1309,7 @@ int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, return this->saveLayer(bounds, &tmpPaint, flags); } } +#endif void SkCanvas::internalRestore() { SkASSERT(fMCStack.count() != 0); @@ -1314,31 +1411,6 @@ bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) { return dev && dev->accessPixels(pmap); } -SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) { - fAddr = canvas->peekPixels(&fInfo, &fRowBytes); - if (nullptr == fAddr) { - fInfo = canvas->imageInfo(); - if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) { - return; // failure, fAddr is nullptr - } - if (!canvas->readPixels(&fBitmap, 0, 0)) { - return; // failure, fAddr is nullptr - } - fAddr = fBitmap.getPixels(); - fRowBytes = fBitmap.rowBytes(); - } - SkASSERT(fAddr); // success -} - -bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const { - if (fAddr) { - return bitmap->installPixels(fInfo, const_cast(fAddr), fRowBytes); - } else { - bitmap->reset(); - return false; - } -} - ///////////////////////////////////////////////////////////////////////////// void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, @@ -1361,10 +1433,13 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkBitmap& src = srcDev->accessBitmap(false); SkMatrix matrix = *iter.fMatrix; matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y())); +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height()); +#else + SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y()); +#endif SkAutoTUnref cache(dstDev->getImageFilterCache()); - SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), - SkImageFilter::kApprox_SizeConstraint); + SkImageFilter::Context ctx(matrix, clipBounds, cache.get()); if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) { SkPaint tmpUnfiltered(*paint); tmpUnfiltered.setImageFilter(nullptr); @@ -1381,56 +1456,8 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, LOOPER_END } -void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) { - if (gTreatSpriteAsBitmap) { - this->save(); - this->resetMatrix(); - this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint); - this->restore(); - return; - } - - TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()"); - if (bitmap.drawsNothing()) { - return; - } - SkDEBUGCODE(bitmap.validate();) - - SkPaint tmp; - if (nullptr == paint) { - paint = &tmp; - } - - LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) - - while (iter.next()) { - paint = &looper.paint(); - SkImageFilter* filter = paint->getImageFilter(); - SkIPoint pos = { x - iter.getX(), y - iter.getY() }; - if (filter && !iter.fDevice->canHandleImageFilter(filter)) { - SkImageFilter::DeviceProxy proxy(iter.fDevice); - SkBitmap dst; - SkIPoint offset = SkIPoint::Make(0, 0); - SkMatrix matrix = *iter.fMatrix; - matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y())); - const SkIRect clipBounds = bitmap.bounds(); - SkAutoTUnref cache(iter.fDevice->getImageFilterCache()); - SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), - SkImageFilter::kApprox_SizeConstraint); - if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) { - SkPaint tmpUnfiltered(*paint); - tmpUnfiltered.setImageFilter(nullptr); - iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), - tmpUnfiltered); - } - } else { - iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); - } - } - LOOPER_END -} - ///////////////////////////////////////////////////////////////////////////// + void SkCanvas::translate(SkScalar dx, SkScalar dy) { SkMatrix m; m.setTranslate(dx, dy); @@ -1903,11 +1930,13 @@ void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { } void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) { + RETURN_ON_NULL(image); this->onDrawImage(image, x, y, paint); } void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint) { + RETURN_ON_NULL(image); if (dst.isEmpty() || src.isEmpty()) { return; } @@ -1916,17 +1945,20 @@ void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRe void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint) { + RETURN_ON_NULL(image); this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint); } void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint) { + RETURN_ON_NULL(image); this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint, constraint); } void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, const SkPaint* paint) { + RETURN_ON_NULL(image); if (dst.isEmpty()) { return; } @@ -1973,16 +2005,10 @@ void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, con this->onDrawBitmapNine(bitmap, center, dst, paint); } -void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) { - if (bitmap.drawsNothing()) { - return; - } - this->onDrawSprite(bitmap, left, top, paint); -} - void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], const SkColor colors[], int count, SkXfermode::Mode mode, const SkRect* cull, const SkPaint* paint) { + RETURN_ON_NULL(atlas); if (count <= 0) { return; } @@ -2197,6 +2223,27 @@ void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { LOOPER_END } +bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) { + if (!paint.getImageFilter()) { + return false; + } + + const SkMatrix& ctm = this->getTotalMatrix(); + if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) { + return false; + } + + // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds. + // Once we can filter and the filter will return a result larger than itself, we should be + // able to remove this constraint. + // skbug.com/4526 + // + SkPoint pt; + ctm.mapXY(x, y, &pt); + SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h); + return ir.contains(fMCRec->fRasterClip.getBounds()); +} + void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()"); SkRect bounds = SkRect::MakeXYWH(x, y, @@ -2215,11 +2262,25 @@ void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const S if (nullptr == paint) { paint = lazy.init(); } - - LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds) - + + const bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), + *paint); + LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds) + while (iter.next()) { - iter.fDevice->drawImage(iter, image, x, y, looper.paint()); + const SkPaint& pnt = looper.paint(); + if (drawAsSprite && pnt.getImageFilter()) { + SkBitmap bitmap; + if (as_IB(image)->asBitmapForImageFilters(&bitmap)) { + SkPoint pt; + iter.fMatrix->mapXY(x, y, &pt); + iter.fDevice->drawBitmapAsSprite(iter, bitmap, + SkScalarRoundToInt(pt.fX), + SkScalarRoundToInt(pt.fY), pnt); + } + } else { + iter.fDevice->drawImage(iter, image, x, y, pnt); + } } LOOPER_END @@ -2228,10 +2289,8 @@ void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const S void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()"); - SkRect storage; - const SkRect* bounds = &dst; if (nullptr == paint || paint->canComputeFastBounds()) { - storage = dst; + SkRect storage = dst; if (paint) { paint->computeFastBounds(dst, &storage); } @@ -2244,7 +2303,7 @@ void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const Sk paint = lazy.init(); } - LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, bounds, + LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst, image->isOpaque()) while (iter.next()) { @@ -2281,12 +2340,23 @@ void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, cons bounds = &storage; } - LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) + const bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), + bitmap.height(), *paint); + LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds) while (iter.next()) { - iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); + const SkPaint& pnt = looper.paint(); + if (drawAsSprite && pnt.getImageFilter()) { + SkPoint pt; + iter.fMatrix->mapXY(x, y, &pt); + iter.fDevice->drawBitmapAsSprite(iter, bitmap, + SkScalarRoundToInt(pt.fX), + SkScalarRoundToInt(pt.fY), pnt); + } else { + iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); + } } - + LOOPER_END } @@ -2298,9 +2368,8 @@ void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, return; } - SkRect storage; - const SkRect* bounds = &dst; if (nullptr == paint || paint->canComputeFastBounds()) { + SkRect storage; if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { return; } @@ -2311,7 +2380,7 @@ void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, paint = lazy.init(); } - LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, bounds, + LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst, bitmap.isOpaque()) while (iter.next()) { @@ -2332,9 +2401,8 @@ void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, cons const SkPaint* paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()"); - SkRect storage; - const SkRect* bounds = &dst; if (nullptr == paint || paint->canComputeFastBounds()) { + SkRect storage; if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { return; } @@ -2345,7 +2413,7 @@ void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, cons paint = lazy.init(); } - LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) + LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) while (iter.next()) { iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint()); @@ -2359,9 +2427,8 @@ void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, c TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()"); SkDEBUGCODE(bitmap.validate();) - SkRect storage; - const SkRect* bounds = &dst; if (nullptr == paint || paint->canComputeFastBounds()) { + SkRect storage; if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { return; } @@ -2372,7 +2439,7 @@ void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, c paint = lazy.init(); } - LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) + LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) while (iter.next()) { iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint()); @@ -2461,14 +2528,14 @@ void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, start.fY); r.fTop = offset; r.fBottom = offset + height; - DrawRect(draw, paint, r, textSize); + DrawRect(draw, paint, r, 1); } if (flags & SkPaint::kStrikeThruText_Flag) { SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, start.fY); r.fTop = offset; r.fBottom = offset + height; - DrawRect(draw, paint, r, textSize); + DrawRect(draw, paint, r, 1); } } } @@ -2584,10 +2651,9 @@ void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& } void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) { + RETURN_ON_NULL(blob); TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()"); - if (blob) { - this->onDrawTextBlob(blob, x, y, paint); - } + this->onDrawTextBlob(blob, x, y, paint); } void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount, @@ -2638,23 +2704,21 @@ void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], } void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) { - if (dr) { - if (x || y) { - SkMatrix matrix = SkMatrix::MakeTrans(x, y); - this->onDrawDrawable(dr, &matrix); - } else { - this->onDrawDrawable(dr, nullptr); - } + RETURN_ON_NULL(dr); + if (x || y) { + SkMatrix matrix = SkMatrix::MakeTrans(x, y); + this->onDrawDrawable(dr, &matrix); + } else { + this->onDrawDrawable(dr, nullptr); } } void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) { - if (dr) { - if (matrix && matrix->isIdentity()) { - matrix = nullptr; - } - this->onDrawDrawable(dr, matrix); + RETURN_ON_NULL(dr); + if (matrix && matrix->isIdentity()) { + matrix = nullptr; } + this->onDrawDrawable(dr, matrix); } void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) { @@ -2824,17 +2888,17 @@ void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, #define kMaxPictureOpsToUnrollInsteadOfRef 1 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { + RETURN_ON_NULL(picture); + TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()"); - if (picture) { - if (matrix && matrix->isIdentity()) { - matrix = nullptr; - } - if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) { - SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); - picture->playback(this); - } else { - this->onDrawPicture(picture, matrix, paint); - } + if (matrix && matrix->isIdentity()) { + matrix = nullptr; + } + if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) { + SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); + picture->playback(this); + } else { + this->onDrawPicture(picture, matrix, paint); } } diff --git a/gfx/skia/skia/src/core/SkColorFilter.cpp b/gfx/skia/skia/src/core/SkColorFilter.cpp index 031f376eee1..747e5ee107c 100644 --- a/gfx/skia/skia/src/core/SkColorFilter.cpp +++ b/gfx/skia/skia/src/core/SkColorFilter.cpp @@ -140,7 +140,10 @@ SkColorFilter* SkColorFilter::CreateComposeFilter(SkColorFilter* outer, SkColorF return new SkComposeColorFilter(outer, inner, count); } +#include "SkModeColorFilter.h" + SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeColorFilter) +SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter) SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END diff --git a/gfx/skia/skia/src/core/SkColorFilterShader.cpp b/gfx/skia/skia/src/core/SkColorFilterShader.cpp new file mode 100644 index 00000000000..dc90f95762a --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorFilterShader.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorFilterShader.h" +#include "SkReadBuffer.h" +#include "SkWriteBuffer.h" +#include "SkShader.h" +#include "SkString.h" + +#if SK_SUPPORT_GPU +#include "GrFragmentProcessor.h" +#endif + +SkColorFilterShader::SkColorFilterShader(SkShader* shader, SkColorFilter* filter) + : fShader(SkRef(shader)) + , fFilter(SkRef(filter)) +{ + SkASSERT(shader); + SkASSERT(filter); +} + +SkFlattenable* SkColorFilterShader::CreateProc(SkReadBuffer& buffer) { + SkAutoTUnref shader(buffer.readShader()); + SkAutoTUnref filter(buffer.readColorFilter()); + if (!shader.get() || !filter.get()) { + return nullptr; + } + return new SkColorFilterShader(shader, filter); +} + +void SkColorFilterShader::flatten(SkWriteBuffer& buffer) const { + buffer.writeFlattenable(fShader); + buffer.writeFlattenable(fFilter); +} + +uint32_t SkColorFilterShader::FilterShaderContext::getFlags() const { + const SkColorFilterShader& filterShader = static_cast(fShader); + + uint32_t shaderF = fShaderContext->getFlags(); + uint32_t filterF = filterShader.fFilter->getFlags(); + + // if the filter might change alpha, clear the opaque flag in the shader + if (!(filterF & SkColorFilter::kAlphaUnchanged_Flag)) { + shaderF &= ~SkShader::kOpaqueAlpha_Flag; + } + return shaderF; +} + +SkShader::Context* SkColorFilterShader::onCreateContext(const ContextRec& rec, + void* storage) const { + char* shaderContextStorage = (char*)storage + sizeof(FilterShaderContext); + SkShader::Context* shaderContext = fShader->createContext(rec, shaderContextStorage); + if (nullptr == shaderContext) { + return nullptr; + } + return new (storage) FilterShaderContext(*this, shaderContext, rec); +} + +size_t SkColorFilterShader::contextSize() const { + return sizeof(FilterShaderContext) + fShader->contextSize(); +} + +SkColorFilterShader::FilterShaderContext::FilterShaderContext( + const SkColorFilterShader& filterShader, + SkShader::Context* shaderContext, + const ContextRec& rec) + : INHERITED(filterShader, rec) + , fShaderContext(shaderContext) +{} + +SkColorFilterShader::FilterShaderContext::~FilterShaderContext() { + fShaderContext->~Context(); +} + +void SkColorFilterShader::FilterShaderContext::shadeSpan(int x, int y, SkPMColor result[], + int count) { + const SkColorFilterShader& filterShader = static_cast(fShader); + + fShaderContext->shadeSpan(x, y, result, count); + filterShader.fFilter->filterSpan(result, count, result); +} + +#if SK_SUPPORT_GPU +///////////////////////////////////////////////////////////////////// + +const GrFragmentProcessor* SkColorFilterShader::asFragmentProcessor( + GrContext* context, + const SkMatrix& viewM, + const SkMatrix* localMatrix, + SkFilterQuality fq) const { + + SkAutoTUnref fp1(fShader->asFragmentProcessor(context, viewM, + localMatrix, fq)); + if (!fp1.get()) { + return nullptr; + } + + SkAutoTUnref fp2(fFilter->asFragmentProcessor(context)); + if (!fp2.get()) { + return fp1.release(); + } + + const GrFragmentProcessor* fpSeries[] = { fp1.get(), fp2.get() }; + + return GrFragmentProcessor::RunInSeries(fpSeries, 2); +} +#endif + +#ifndef SK_IGNORE_TO_STRING +void SkColorFilterShader::toString(SkString* str) const { + str->append("SkColorFilterShader: ("); + + str->append("Shader: "); + fShader->toString(str); + str->append(" Filter: "); + // TODO: add "fFilter->toString(str);" once SkColorFilter::toString is added + + this->INHERITED::toString(str); + + str->append(")"); +} +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SkShader* SkShader::newWithColorFilter(SkColorFilter* filter) const { + SkShader* base = const_cast(this); + if (!filter) { + return SkRef(base); + } + return new SkColorFilterShader(base, filter); +} diff --git a/gfx/skia/skia/src/core/SkFilterShader.h b/gfx/skia/skia/src/core/SkColorFilterShader.h similarity index 51% rename from gfx/skia/skia/src/core/SkFilterShader.h rename to gfx/skia/skia/src/core/SkColorFilterShader.h index ea5eaed34fe..e92908ee83d 100644 --- a/gfx/skia/skia/src/core/SkFilterShader.h +++ b/gfx/skia/skia/src/core/SkColorFilterShader.h @@ -1,57 +1,62 @@ /* - * Copyright 2012 Google Inc. + * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#ifndef SkFilterShader_DEFINED -#define SkFilterShader_DEFINED +#ifndef SkColorFilterShader_DEFINED +#define SkColorFilterShader_DEFINED +#include "SkColorFilter.h" #include "SkShader.h" -class SkColorFilter; - -class SkFilterShader : public SkShader { +class SkColorFilterShader : public SkShader { public: - SkFilterShader(SkShader* shader, SkColorFilter* filter); - virtual ~SkFilterShader(); - + SkColorFilterShader(SkShader* shader, SkColorFilter* filter); + size_t contextSize() const override; + +#if SK_SUPPORT_GPU + const GrFragmentProcessor* asFragmentProcessor(GrContext*, + const SkMatrix& viewM, + const SkMatrix* localMatrix, + SkFilterQuality) const override; +#endif class FilterShaderContext : public SkShader::Context { public: // Takes ownership of shaderContext and calls its destructor. - FilterShaderContext(const SkFilterShader&, SkShader::Context*, const ContextRec&); + FilterShaderContext(const SkColorFilterShader&, SkShader::Context*, const ContextRec&); virtual ~FilterShaderContext(); - + uint32_t getFlags() const override; - + void shadeSpan(int x, int y, SkPMColor[], int count) override; - + void set3DMask(const SkMask* mask) override { // forward to our proxy fShaderContext->set3DMask(mask); } - + private: SkShader::Context* fShaderContext; - + typedef SkShader::Context INHERITED; }; - + SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkFilterShader) - + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorFilterShader) + protected: void flatten(SkWriteBuffer&) const override; Context* onCreateContext(const ContextRec&, void* storage) const override; - - + + private: - SkShader* fShader; - SkColorFilter* fFilter; - + SkAutoTUnref fShader; + SkAutoTUnref fFilter; + typedef SkShader INHERITED; }; diff --git a/gfx/skia/skia/src/core/SkColorShader.h b/gfx/skia/skia/src/core/SkColorShader.h index e3fddb231a4..25a1d6c8d07 100644 --- a/gfx/skia/skia/src/core/SkColorShader.h +++ b/gfx/skia/skia/src/core/SkColorShader.h @@ -34,15 +34,12 @@ public: ColorShaderContext(const SkColorShader& shader, const ContextRec&); uint32_t getFlags() const override; - uint8_t getSpan16Alpha() const override; void shadeSpan(int x, int y, SkPMColor span[], int count) override; - void shadeSpan16(int x, int y, uint16_t span[], int count) override; void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) override; private: SkPMColor fPMColor; uint32_t fFlags; - uint16_t fColor16; typedef SkShader::Context INHERITED; }; diff --git a/gfx/skia/skia/src/core/SkComposeShader.cpp b/gfx/skia/skia/src/core/SkComposeShader.cpp index 0dc0da68ef9..d433ff2d435 100644 --- a/gfx/skia/skia/src/core/SkComposeShader.cpp +++ b/gfx/skia/skia/src/core/SkComposeShader.cpp @@ -137,10 +137,6 @@ void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor re SkXfermode* mode = static_cast(fShader).fMode; unsigned scale = SkAlpha255To256(this->getPaintAlpha()); -#ifdef SK_BUILD_FOR_ANDROID - scale = 256; // ugh -- maintain old bug/behavior for now -#endif - SkPMColor tmp[TMP_COLOR_COUNT]; if (nullptr == mode) { // implied SRC_OVER diff --git a/gfx/skia/skia/src/core/SkConvolver.cpp b/gfx/skia/skia/src/core/SkConvolver.cpp index 28d3ab139ce..c662e2ddaf0 100644 --- a/gfx/skia/skia/src/core/SkConvolver.cpp +++ b/gfx/skia/skia/src/core/SkConvolver.cpp @@ -3,9 +3,7 @@ // found in the LICENSE file. #include "SkConvolver.h" -#include "SkMath.h" -#include "SkSize.h" -#include "SkTypes.h" +#include "SkTArray.h" namespace { @@ -284,21 +282,6 @@ SkConvolutionFilter1D::SkConvolutionFilter1D() SkConvolutionFilter1D::~SkConvolutionFilter1D() { } -void SkConvolutionFilter1D::AddFilter(int filterOffset, - const float* filterValues, - int filterLength) { - SkASSERT(filterLength > 0); - - SkTArray fixedValues; - fixedValues.reset(filterLength); - - for (int i = 0; i < filterLength; ++i) { - fixedValues.push_back(FloatToFixed(filterValues[i])); - } - - AddFilter(filterOffset, &fixedValues[0], filterLength); -} - void SkConvolutionFilter1D::AddFilter(int filterOffset, const ConvolutionFixed* filterValues, int filterLength) { @@ -323,9 +306,7 @@ void SkConvolutionFilter1D::AddFilter(int filterOffset, filterLength = lastNonZero + 1 - firstNonZero; SkASSERT(filterLength > 0); - for (int i = firstNonZero; i <= lastNonZero; i++) { - fFilterValues.push_back(filterValues[i]); - } + fFilterValues.append(filterLength, &filterValues[firstNonZero]); } else { // Here all the factors were zeroes. filterLength = 0; @@ -339,7 +320,7 @@ void SkConvolutionFilter1D::AddFilter(int filterOffset, instance.fOffset = filterOffset; instance.fTrimmedLength = filterLength; instance.fLength = filterSize; - fFilters.push_back(instance); + fFilters.push(instance); fMaxFilter = SkTMax(fMaxFilter, filterLength); } diff --git a/gfx/skia/skia/src/core/SkConvolver.h b/gfx/skia/skia/src/core/SkConvolver.h index 00305fa9fab..4e23f6cc17a 100644 --- a/gfx/skia/skia/src/core/SkConvolver.h +++ b/gfx/skia/skia/src/core/SkConvolver.h @@ -6,8 +6,7 @@ #define SK_CONVOLVER_H #include "SkSize.h" -#include "SkTypes.h" -#include "SkTArray.h" +#include "SkTDArray.h" // avoid confusion with Mac OS X's math library (Carbon) #if defined(__APPLE__) @@ -58,6 +57,11 @@ public: // output image. int numValues() const { return static_cast(fFilters.count()); } + void reserveAdditional(int filterCount, int filterValueCount) { + fFilters.setReserve(fFilters.count() + filterCount); + fFilterValues.setReserve(fFilterValues.count() + filterValueCount); + } + // Appends the given list of scaling values for generating a given output // pixel. |filterOffset| is the distance from the edge of the image to where // the scaling factors start. The scaling factors apply to the source pixels @@ -68,13 +72,6 @@ public: // brighness of the image. // // The filterLength must be > 0. - // - // This version will automatically convert your input to ConvolutionFixed point. - SK_API void AddFilter(int filterOffset, - const float* filterValues, - int filterLength); - - // Same as the above version, but the input is already ConvolutionFixed point. void AddFilter(int filterOffset, const ConvolutionFixed* filterValues, int filterLength); @@ -112,7 +109,7 @@ public: // SIMD padding which happens outside of this class. void addFilterValue( ConvolutionFixed val ) { - fFilterValues.push_back( val ); + fFilterValues.push( val ); } private: struct FilterInstance { @@ -132,12 +129,12 @@ private: }; // Stores the information for each filter added to this class. - SkTArray fFilters; + SkTDArray fFilters; // We store all the filter values in this flat list, indexed by // |FilterInstance.data_location| to avoid the mallocs required for storing // each one separately. - SkTArray fFilterValues; + SkTDArray fFilterValues; // The maximum size of any filter we've added. int fMaxFilter; diff --git a/gfx/skia/skia/src/core/SkCubicClipper.cpp b/gfx/skia/skia/src/core/SkCubicClipper.cpp index 81ef18de7af..469fc222e33 100644 --- a/gfx/skia/skia/src/core/SkCubicClipper.cpp +++ b/gfx/skia/skia/src/core/SkCubicClipper.cpp @@ -20,7 +20,7 @@ void SkCubicClipper::setClip(const SkIRect& clip) { } -static bool chopMonoCubicAtY(SkPoint pts[4], SkScalar y, SkScalar* t) { +bool SkCubicClipper::ChopMonoAtY(const SkPoint pts[4], SkScalar y, SkScalar* t) { SkScalar ycrv[4]; ycrv[0] = pts[0].fY - y; ycrv[1] = pts[1].fY - y; @@ -131,7 +131,7 @@ bool SkCubicClipper::clipCubic(const SkPoint srcPts[4], SkPoint dst[4]) { SkPoint tmp[7]; // for SkChopCubicAt // are we partially above - if (dst[0].fY < ctop && chopMonoCubicAtY(dst, ctop, &t)) { + if (dst[0].fY < ctop && ChopMonoAtY(dst, ctop, &t)) { SkChopCubicAt(dst, tmp, t); dst[0] = tmp[3]; dst[1] = tmp[4]; @@ -139,7 +139,7 @@ bool SkCubicClipper::clipCubic(const SkPoint srcPts[4], SkPoint dst[4]) { } // are we partially below - if (dst[3].fY > cbot && chopMonoCubicAtY(dst, cbot, &t)) { + if (dst[3].fY > cbot && ChopMonoAtY(dst, cbot, &t)) { SkChopCubicAt(dst, tmp, t); dst[1] = tmp[1]; dst[2] = tmp[2]; diff --git a/gfx/skia/skia/src/core/SkCubicClipper.h b/gfx/skia/skia/src/core/SkCubicClipper.h index c52eabe4602..d7dc3812339 100644 --- a/gfx/skia/skia/src/core/SkCubicClipper.h +++ b/gfx/skia/skia/src/core/SkCubicClipper.h @@ -27,6 +27,7 @@ public: bool clipCubic(const SkPoint src[4], SkPoint dst[4]); + static bool ChopMonoAtY(const SkPoint pts[4], SkScalar y, SkScalar* t); private: SkRect fClip; }; diff --git a/gfx/skia/skia/src/core/SkDevice.cpp b/gfx/skia/skia/src/core/SkDevice.cpp index 34c171db907..8ff5827adae 100644 --- a/gfx/skia/skia/src/core/SkDevice.cpp +++ b/gfx/skia/skia/src/core/SkDevice.cpp @@ -55,7 +55,8 @@ const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) { SkPixelGeometry SkBaseDevice::CreateInfo::AdjustGeometry(const SkImageInfo& info, TileUsage tileUsage, - SkPixelGeometry geo) { + SkPixelGeometry geo, + bool preserveLCDText) { switch (tileUsage) { case kPossible_TileUsage: // (we think) for compatibility with old clients, we assume this layer can support LCD @@ -63,7 +64,7 @@ SkPixelGeometry SkBaseDevice::CreateInfo::AdjustGeometry(const SkImageInfo& info // our callers (reed/robertphilips). break; case kNever_TileUsage: - if (info.alphaType() != kOpaque_SkAlphaType) { + if (!preserveLCDText) { geo = kUnknown_SkPixelGeometry; } break; @@ -402,6 +403,32 @@ void SkBaseDevice::drawTextOnPath(const SkDraw& draw, const void* text, size_t b ////////////////////////////////////////////////////////////////////////////////////////// +void SkBaseDevice::drawBitmapAsSprite(const SkDraw& draw, const SkBitmap& bitmap, int x, int y, + const SkPaint& paint) { + SkImageFilter* filter = paint.getImageFilter(); + if (filter && !this->canHandleImageFilter(filter)) { + SkImageFilter::DeviceProxy proxy(this); + SkBitmap dst; + SkIPoint offset = SkIPoint::Make(0, 0); + SkMatrix matrix = *draw.fMatrix; + matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS + const SkIRect clipBounds = bitmap.bounds(); +#else + const SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-x, -y); +#endif + SkAutoTUnref cache(this->getImageFilterCache()); + SkImageFilter::Context ctx(matrix, clipBounds, cache.get()); + if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) { + SkPaint tmpUnfiltered(paint); + tmpUnfiltered.setImageFilter(nullptr); + this->drawSprite(draw, dst, x + offset.x(), y + offset.y(), tmpUnfiltered); + } + } else { + this->drawSprite(draw, bitmap, x, y, paint); + } +} + uint32_t SkBaseDevice::filterTextFlags(const SkPaint& paint) const { uint32_t flags = paint.getFlags(); diff --git a/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp b/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp index 30354e09f83..147aefad790 100755 --- a/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp +++ b/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp @@ -343,15 +343,10 @@ static bool generate_distance_field_from_image(unsigned char* distanceField, int dataWidth = width + 2*pad; int dataHeight = height + 2*pad; - // create temp data - size_t dataSize = dataWidth*dataHeight*sizeof(DFData); - SkAutoSMalloc<1024> dfStorage(dataSize); - DFData* dataPtr = (DFData*) dfStorage.get(); - sk_bzero(dataPtr, dataSize); - - SkAutoSMalloc<1024> edgeStorage(dataWidth*dataHeight*sizeof(char)); - unsigned char* edgePtr = (unsigned char*) edgeStorage.get(); - sk_bzero(edgePtr, dataWidth*dataHeight*sizeof(char)); + // create zeroed temp DFData+edge storage + SkAutoFree storage(sk_calloc_throw(dataWidth*dataHeight*(sizeof(DFData) + 1))); + DFData* dataPtr = (DFData*)storage.get(); + unsigned char* edgePtr = (unsigned char*)storage.get() + dataWidth*dataHeight*sizeof(DFData); // copy glyph into distance field storage init_glyph_data(dataPtr, edgePtr, copyPtr, diff --git a/gfx/skia/skia/include/core/SkDither.h b/gfx/skia/skia/src/core/SkDither.h similarity index 100% rename from gfx/skia/skia/include/core/SkDither.h rename to gfx/skia/skia/src/core/SkDither.h diff --git a/gfx/skia/skia/src/core/SkDraw.cpp b/gfx/skia/skia/src/core/SkDraw.cpp index e1a49d39b4a..246c31ba510 100644 --- a/gfx/skia/skia/src/core/SkDraw.cpp +++ b/gfx/skia/skia/src/core/SkDraw.cpp @@ -30,7 +30,6 @@ #include "SkTemplates.h" #include "SkTextMapStateProc.h" #include "SkTLazy.h" -#include "SkUtility.h" #include "SkUtils.h" #include "SkVertState.h" @@ -40,6 +39,9 @@ //#define TRACE_BITMAP_DRAWS +// Helper function to fix code gen bug on ARM64. +// See SkFindAndPlaceGlyph.h for more details. +void FixGCC49Arm64Bug(int v) { } /** Helper for allocating small blitters on the stack. */ @@ -905,10 +907,8 @@ void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { SkMask dstM; if (paint.getMaskFilter() && - paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, nullptr)) { + paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, nullptr)) { mask = &dstM; - } else { - dstM.fImage = nullptr; } SkAutoMaskFreeImage ami(dstM.fImage); @@ -1132,28 +1132,51 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, } } else { // hairline if (paint->isAntiAlias()) { + switch (paint->getStrokeCap()) { + case SkPaint::kButt_Cap: + proc = SkScan::AntiHairPath; + break; + case SkPaint::kSquare_Cap: + proc = SkScan::AntiHairSquarePath; + break; + case SkPaint::kRound_Cap: + proc = SkScan::AntiHairRoundPath; + break; + default: + proc SK_INIT_TO_AVOID_WARNING; + SkDEBUGFAIL("unknown paint cap type"); + } +#ifdef SK_SUPPORT_LEGACY_HAIR_IGNORES_CAPS proc = SkScan::AntiHairPath; +#endif } else { + switch (paint->getStrokeCap()) { + case SkPaint::kButt_Cap: + proc = SkScan::HairPath; + break; + case SkPaint::kSquare_Cap: + proc = SkScan::HairSquarePath; + break; + case SkPaint::kRound_Cap: + proc = SkScan::HairRoundPath; + break; + default: + proc SK_INIT_TO_AVOID_WARNING; + SkDEBUGFAIL("unknown paint cap type"); + } +#ifdef SK_SUPPORT_LEGACY_HAIR_IGNORES_CAPS proc = SkScan::HairPath; +#endif } } proc(*devPathPtr, *fRC, blitter); } -/** For the purposes of drawing bitmaps, if a matrix is "almost" translate - go ahead and treat it as if it were, so that subsequent code can go fast. - */ -static bool just_translate(const SkMatrix& matrix, const SkBitmap& bitmap) { - unsigned bits = 0; // TODO: find a way to allow the caller to tell us to - // respect filtering. - return SkTreatAsSprite(matrix, bitmap.width(), bitmap.height(), bits); -} - void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const { SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType); - if (just_translate(*fMatrix, bitmap)) { + if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) { int ix = SkScalarRoundToInt(fMatrix->getTranslateX()); int iy = SkScalarRoundToInt(fMatrix->getTranslateY()); @@ -1199,8 +1222,8 @@ void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, } // allocate (and clear) our temp buffer to hold the transformed bitmap - SkAutoMalloc storage(size); - mask.fImage = (uint8_t*)storage.get(); + SkAutoTMalloc storage(size); + mask.fImage = storage.get(); memset(mask.fImage, 0, size); // now draw our bitmap(src) into mask(dst), transformed by the matrix @@ -1268,7 +1291,8 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, return; } - if (bitmap.colorType() != kAlpha_8_SkColorType && just_translate(matrix, bitmap)) { + if (bitmap.colorType() != kAlpha_8_SkColorType + && SkTreatAsSprite(matrix, bitmap.dimensions(), paint)) { // // It is safe to call lock pixels now, since we know the matrix is // (more or less) identity. @@ -1423,170 +1447,120 @@ void SkDraw::drawText_asPaths(const char text[], size_t byteLength, #endif //////////////////////////////////////////////////////////////////////////////////////////////////// -struct SkDraw1Glyph { - const SkDraw* fDraw; - const SkRegion* fClip; - const SkAAClip* fAAClip; - SkBlitter* fBlitter; - SkGlyphCache* fCache; - const SkPaint* fPaint; - SkIRect fClipBounds; - /** Half the sampling frequency of the rasterized glyph in x. */ - SkScalar fHalfSampleX; - /** Half the sampling frequency of the rasterized glyph in y. */ - SkScalar fHalfSampleY; - /** Draws one glyph. - * - * The x and y are pre-biased, so implementations may just truncate them. - * i.e. half the sampling frequency has been added. - * e.g. 1/2 or 1/(2^(SkGlyph::kSubBits+1)) has already been added. - * This added bias can be found in fHalfSampleX,Y. - */ - typedef void (*Proc)(const SkDraw1Glyph&, Sk48Dot16 x, Sk48Dot16 y, const SkGlyph&); +class DrawOneGlyph { +public: + DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter) + : fUseRegionToDraw(UsingRegionToDraw(draw.fRC)) + , fGlyphCache(cache) + , fBlitter(blitter) + , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr) + , fDraw(draw) + , fPaint(paint) + , fClipBounds(PickClipBounds(draw)) { } - Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache, - const SkPaint&); + void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) { + position += rounding; + Sk48Dot16 fx = SkScalarTo48Dot16(position.fX); + Sk48Dot16 fy = SkScalarTo48Dot16(position.fY); + // Prevent glyphs from being drawn outside of or straddling the edge of device space. + if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || + (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) || + (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || + (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) { + return; + } + + int left = Sk48Dot16FloorToInt(fx); + int top = Sk48Dot16FloorToInt(fy); + SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); + + left += glyph.fLeft; + top += glyph.fTop; + + int right = left + glyph.fWidth; + int bottom = top + glyph.fHeight; + + SkMask mask; + mask.fBounds.set(left, top, right, bottom); + + if (fUseRegionToDraw) { + SkRegion::Cliperator clipper(*fClip, mask.fBounds); + + if (!clipper.done() && this->getImageData(glyph, &mask)) { + const SkIRect& cr = clipper.rect(); + do { + this->blitMask(mask, cr); + clipper.next(); + } while (!clipper.done()); + } + } else { + SkIRect storage; + SkIRect* bounds = &mask.fBounds; + + // this extra test is worth it, assuming that most of the time it succeeds + // since we can avoid writing to storage + if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) { + if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds)) + return; + bounds = &storage; + } + + if (this->getImageData(glyph, &mask)) { + this->blitMask(mask, *bounds); + } + } + } + +private: + static bool UsingRegionToDraw(const SkRasterClip* rClip) { + return rClip->isBW() && !rClip->isRect(); + } + + static SkIRect PickClipBounds(const SkDraw& draw) { + const SkRasterClip& rasterClip = *draw.fRC; + + if (rasterClip.isBW()) { + return rasterClip.bwRgn().getBounds(); + } else { + return rasterClip.aaRgn().getBounds(); + } + } + + bool getImageData(const SkGlyph& glyph, SkMask* mask) { + uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph)); + if (nullptr == bits) { + return false; // can't rasterize glyph + } + mask->fImage = bits; + mask->fRowBytes = glyph.rowBytes(); + mask->fFormat = static_cast(glyph.fMaskFormat); + return true; + } - // call this instead of fBlitter->blitMask() since this wrapper will handle - // the case when the mask is ARGB32_Format - // void blitMask(const SkMask& mask, const SkIRect& clip) const { if (SkMask::kARGB32_Format == mask.fFormat) { - this->blitMaskAsSprite(mask); + SkBitmap bm; + bm.installPixels( + SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()), + (SkPMColor*)mask.fImage, mask.fRowBytes); + + fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint); } else { fBlitter->blitMask(mask, clip); } } - // mask must be kARGB32_Format - void blitMaskAsSprite(const SkMask& mask) const; + const bool fUseRegionToDraw; + SkGlyphCache * const fGlyphCache; + SkBlitter * const fBlitter; + const SkRegion* const fClip; + const SkDraw& fDraw; + const SkPaint& fPaint; + const SkIRect fClipBounds; }; -static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy, - const SkGlyph& glyph) { - // Prevent glyphs from being drawn outside of or straddling the edge of device space. - if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || - (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) || - (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || - (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) - { - return; - } - - int left = Sk48Dot16FloorToInt(fx); - int top = Sk48Dot16FloorToInt(fy); - SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); - SkASSERT((nullptr == state.fClip && state.fAAClip) || - (state.fClip && nullptr == state.fAAClip && state.fClip->isRect())); - - left += glyph.fLeft; - top += glyph.fTop; - - int right = left + glyph.fWidth; - int bottom = top + glyph.fHeight; - - SkMask mask; - SkIRect storage; - SkIRect* bounds = &mask.fBounds; - - mask.fBounds.set(left, top, right, bottom); - - // this extra test is worth it, assuming that most of the time it succeeds - // since we can avoid writing to storage - if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) { - if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds)) - return; - bounds = &storage; - } - - uint8_t* aa = (uint8_t*)glyph.fImage; - if (nullptr == aa) { - aa = (uint8_t*)state.fCache->findImage(glyph); - if (nullptr == aa) { - return; // can't rasterize glyph - } - } - - mask.fRowBytes = glyph.rowBytes(); - mask.fFormat = static_cast(glyph.fMaskFormat); - mask.fImage = aa; - state.blitMask(mask, *bounds); -} - -static void D1G_RgnClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy, - const SkGlyph& glyph) { - int left = Sk48Dot16FloorToInt(fx); - int top = Sk48Dot16FloorToInt(fy); - SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); - SkASSERT(!state.fClip->isRect()); - - SkMask mask; - - left += glyph.fLeft; - top += glyph.fTop; - - mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); - SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); - - if (!clipper.done()) { - const SkIRect& cr = clipper.rect(); - const uint8_t* aa = (uint8_t*)state.fCache->findImage(glyph); - if (nullptr == aa) { - return; - } - - mask.fRowBytes = glyph.rowBytes(); - mask.fFormat = static_cast(glyph.fMaskFormat); - mask.fImage = (uint8_t*)aa; - do { - state.blitMask(mask, cr); - clipper.next(); - } while (!clipper.done()); - } -} - -SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache, - const SkPaint& pnt) { - fDraw = draw; - fBlitter = blitter; - fCache = cache; - fPaint = &pnt; - - if (cache->isSubpixel()) { - fHalfSampleX = fHalfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound); - } else { - fHalfSampleX = fHalfSampleY = SK_ScalarHalf; - } - - if (draw->fRC->isBW()) { - fAAClip = nullptr; - fClip = &draw->fRC->bwRgn(); - fClipBounds = fClip->getBounds(); - if (fClip->isRect()) { - return D1G_RectClip; - } else { - return D1G_RgnClip; - } - } else { // aaclip - fAAClip = &draw->fRC->aaRgn(); - fClip = nullptr; - fClipBounds = fAAClip->getBounds(); - return D1G_RectClip; - } -} - -void SkDraw1Glyph::blitMaskAsSprite(const SkMask& mask) const { - SkASSERT(SkMask::kARGB32_Format == mask.fFormat); - - SkBitmap bm; - bm.installPixels(SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()), - (SkPMColor*)mask.fImage, mask.fRowBytes); - - fDraw->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), *fPaint); -} - -/////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// void SkDraw::drawText(const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) const { @@ -1606,25 +1580,17 @@ void SkDraw::drawText(const char text[], size_t byteLength, return; } - SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); - SkGlyphCache* cache = autoCache.getCache(); - + SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); + SkGlyphCache* cache = autoCache.getCache(); // The Blitter Choose needs to be live while using the blitter below. SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); - - SkDraw1Glyph d1g; - SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint); + DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter()); SkFindAndPlaceGlyph::ProcessText( paint.getTextEncoding(), text, byteLength, - {x, y}, *fMatrix, paint.getTextAlign(), cache, - [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { - position += rounding; - proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph); - } - ); + {x, y}, *fMatrix, paint.getTextAlign(), cache, drawOneGlyph); } ////////////////////////////////////////////////////////////////////////////// @@ -1696,24 +1662,18 @@ void SkDraw::drawPosText(const char text[], size_t byteLength, return; } + SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); + SkGlyphCache* cache = autoCache.getCache(); + // The Blitter Choose needs to be live while using the blitter below. SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); - - SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); - SkGlyphCache* cache = autoCache.getCache(); - SkDraw1Glyph d1g; - SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint); - SkPaint::Align textAlignment = paint.getTextAlign(); + DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter()); + SkPaint::Align textAlignment = paint.getTextAlign(); SkFindAndPlaceGlyph::ProcessPosText( paint.getTextEncoding(), text, byteLength, - offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, - [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { - position += rounding; - proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph); - } - ); + offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, drawOneGlyph); } #if defined _WIN32 && _MSC_VER >= 1300 @@ -2042,7 +2002,6 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, srcM.fBounds = *bounds; srcM.fFormat = SkMask::kA8_Format; - srcM.fImage = nullptr; if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { return false; } diff --git a/gfx/skia/skia/src/core/SkEdge.cpp b/gfx/skia/skia/src/core/SkEdge.cpp index f91f5f87829..c64896f2e03 100644 --- a/gfx/skia/skia/src/core/SkEdge.cpp +++ b/gfx/skia/skia/src/core/SkEdge.cpp @@ -26,7 +26,7 @@ static inline SkFixed SkFDot6ToFixedDiv2(SkFDot6 value) { // we want to return SkFDot6ToFixed(value >> 1), but we don't want to throw // away data in value, so just perform a modify up-shift - return value << (16 - 6 - 1); + return SkLeftShift(value, 16 - 6 - 1); } ///////////////////////////////////////////////////////////////////////// @@ -214,8 +214,8 @@ int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift) // compute number of steps needed (1 << shift) { - SkFDot6 dx = ((x1 << 1) - x0 - x2) >> 2; - SkFDot6 dy = ((y1 << 1) - y0 - y2) >> 2; + SkFDot6 dx = (SkLeftShift(x1, 1) - x0 - x2) >> 2; + SkFDot6 dy = (SkLeftShift(y1, 1) - y0 - y2) >> 2; shift = diff_to_shift(dx, dy); SkASSERT(shift >= 0); } @@ -312,8 +312,8 @@ int SkQuadraticEdge::updateQuadratic() ///////////////////////////////////////////////////////////////////////// static inline int SkFDot6UpShift(SkFDot6 x, int upShift) { - SkASSERT((x << upShift >> upShift) == x); - return x << upShift; + SkASSERT((SkLeftShift(x, upShift) >> upShift) == x); + return SkLeftShift(x, upShift); } /* f(1/3) = (8a + 12b + 6c + d) / 27 @@ -403,7 +403,7 @@ int SkCubicEdge::setCubic(const SkPoint pts[4], int shift) { } fWinding = SkToS8(winding); - fCurveCount = SkToS8(-1 << shift); + fCurveCount = SkToS8(SkLeftShift(-1, shift)); fCurveShift = SkToU8(shift); fCubicDShift = SkToU8(downShift); diff --git a/gfx/skia/skia/src/core/SkEdge.h b/gfx/skia/skia/src/core/SkEdge.h index db6f43085da..c3adbf85cb2 100644 --- a/gfx/skia/skia/src/core/SkEdge.h +++ b/gfx/skia/skia/src/core/SkEdge.h @@ -15,7 +15,7 @@ #include "SkMath.h" // This correctly favors the lower-pixel when y0 is on a 1/2 pixel boundary -#define SkEdge_Compute_DY(top, y0) ((top << 6) + 32 - (y0)) +#define SkEdge_Compute_DY(top, y0) (SkLeftShift(top, 6) + 32 - (y0)) struct SkEdge { enum Type { diff --git a/gfx/skia/skia/src/core/SkEdgeClipper.cpp b/gfx/skia/skia/src/core/SkEdgeClipper.cpp index c6a4fb29713..55f9192aea1 100644 --- a/gfx/skia/skia/src/core/SkEdgeClipper.cpp +++ b/gfx/skia/skia/src/core/SkEdgeClipper.cpp @@ -358,14 +358,19 @@ void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) { } } +static bool quick_reject_in_y(const SkPoint pts[4], const SkRect& clip) { + Sk4s ys(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY); + Sk4s t(clip.top()); + Sk4s b(clip.bottom()); + + return (ys < t).allTrue() || (ys > b).allTrue(); +} + bool SkEdgeClipper::clipCubic(const SkPoint srcPts[4], const SkRect& clip) { fCurrPoint = fPoints; fCurrVerb = fVerbs; - SkRect bounds; - bounds.set(srcPts, 4); - - if (!quick_reject(bounds, clip)) { + if (!quick_reject_in_y(srcPts, clip)) { SkPoint monoY[10]; int countY = SkChopCubicAtYExtrema(srcPts, monoY); for (int y = 0; y <= countY; y++) { diff --git a/gfx/skia/skia/src/core/SkFDot6.h b/gfx/skia/skia/src/core/SkFDot6.h index 3da753da413..b5367298298 100644 --- a/gfx/skia/skia/src/core/SkFDot6.h +++ b/gfx/skia/skia/src/core/SkFDot6.h @@ -56,9 +56,9 @@ inline SkFDot6 SkScalarRoundToFDot6(SkScalar x, int shift = 0) #define SkFixedToFDot6(x) ((x) >> 10) inline SkFixed SkFDot6ToFixed(SkFDot6 x) { - SkASSERT((x << 10 >> 10) == x); + SkASSERT((SkLeftShift(x, 10) >> 10) == x); - return x << 10; + return SkLeftShift(x, 10); } #define SkScalarToFDot6(x) (SkFDot6)((x) * 64) @@ -68,7 +68,7 @@ inline SkFixed SkFDot6Div(SkFDot6 a, SkFDot6 b) { SkASSERT(b != 0); if (a == (int16_t)a) { - return (a << 16) / b; + return SkLeftShift(a, 16) / b; } else { return SkFixedDiv(a, b); } diff --git a/gfx/skia/skia/src/core/SkFilterShader.cpp b/gfx/skia/skia/src/core/SkFilterShader.cpp deleted file mode 100644 index b52c2be8c4f..00000000000 --- a/gfx/skia/skia/src/core/SkFilterShader.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkFilterShader.h" - -#include "SkColorFilter.h" -#include "SkReadBuffer.h" -#include "SkWriteBuffer.h" -#include "SkShader.h" -#include "SkString.h" - -SkFilterShader::SkFilterShader(SkShader* shader, SkColorFilter* filter) { - fShader = shader; - shader->ref(); - - fFilter = filter; - filter->ref(); -} - -SkFilterShader::~SkFilterShader() { - fFilter->unref(); - fShader->unref(); -} - -SkFlattenable* SkFilterShader::CreateProc(SkReadBuffer& buffer) { - SkAutoTUnref shader(buffer.readShader()); - SkAutoTUnref filter(buffer.readColorFilter()); - if (!shader.get() || !filter.get()) { - return nullptr; - } - return new SkFilterShader(shader, filter); -} - -void SkFilterShader::flatten(SkWriteBuffer& buffer) const { - buffer.writeFlattenable(fShader); - buffer.writeFlattenable(fFilter); -} - -uint32_t SkFilterShader::FilterShaderContext::getFlags() const { - const SkFilterShader& filterShader = static_cast(fShader); - - uint32_t shaderF = fShaderContext->getFlags(); - uint32_t filterF = filterShader.fFilter->getFlags(); - - // filters don't support 16bit, so clear the matching bit in the shader - shaderF &= ~SkShader::kHasSpan16_Flag; - - // if the filter might change alpha, clear the opaque flag in the shader - if (!(filterF & SkColorFilter::kAlphaUnchanged_Flag)) { - shaderF &= ~SkShader::kOpaqueAlpha_Flag; - } - return shaderF; -} - -SkShader::Context* SkFilterShader::onCreateContext(const ContextRec& rec, void* storage) const { - char* shaderContextStorage = (char*)storage + sizeof(FilterShaderContext); - SkShader::Context* shaderContext = fShader->createContext(rec, shaderContextStorage); - if (nullptr == shaderContext) { - return nullptr; - } - return new (storage) FilterShaderContext(*this, shaderContext, rec); -} - -size_t SkFilterShader::contextSize() const { - return sizeof(FilterShaderContext) + fShader->contextSize(); -} - -SkFilterShader::FilterShaderContext::FilterShaderContext(const SkFilterShader& filterShader, - SkShader::Context* shaderContext, - const ContextRec& rec) - : INHERITED(filterShader, rec) - , fShaderContext(shaderContext) {} - -SkFilterShader::FilterShaderContext::~FilterShaderContext() { - fShaderContext->~Context(); -} - -void SkFilterShader::FilterShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { - const SkFilterShader& filterShader = static_cast(fShader); - - fShaderContext->shadeSpan(x, y, result, count); - filterShader.fFilter->filterSpan(result, count, result); -} - -#ifndef SK_IGNORE_TO_STRING -void SkFilterShader::toString(SkString* str) const { - str->append("SkFilterShader: ("); - - str->append("Shader: "); - fShader->toString(str); - str->append(" Filter: "); - // TODO: add "fFilter->toString(str);" once SkColorFilter::toString is added - - this->INHERITED::toString(str); - - str->append(")"); -} -#endif diff --git a/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h b/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h index 278be07e0b8..c74a9820e42 100644 --- a/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h +++ b/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h @@ -14,6 +14,7 @@ #include "SkPaint.h" #include "SkTemplates.h" #include "SkUtils.h" +#include // Calculate a type with the same size as the max of all the Ts. // This must be top level because the is no specialization of inner classes. @@ -30,6 +31,16 @@ struct SkMaxSizeOf { sizeof(H) >= SkMaxSizeOf::value ? sizeof(H) : SkMaxSizeOf::value; }; + +// This is a temporary helper function to work around a bug in the code generation +// for aarch64 (arm) on GCC 4.9. This bug does not show up on other platforms, so it +// seems to be an aarch64 backend problem. +// +// GCC 4.9 on ARM64 does not generate the proper constructor code for PositionReader or +// GlyphFindAndPlace. The vtable is not set properly without adding the fixme code. +// The implementation is in SkDraw.cpp. +extern void FixGCC49Arm64Bug(int v); + class SkFindAndPlaceGlyph { public: template @@ -81,7 +92,7 @@ private: #define alignof __alignof #endif SkASSERT(alignof(Variant) <= alignof(Space)); - new(&fSpace) Variant(skstd::forward(args)...); + new(&fSpace) Variant(std::forward(args)...); } private: @@ -229,6 +240,9 @@ private: public: virtual ~PositionReaderInterface() { } virtual SkPoint nextPoint() = 0; + // This is only here to fix a GCC 4.9 aarch64 code gen bug. + // See comment at the top of the file. + virtual int forceUseForBug() = 0; }; class HorizontalPositions final : public PositionReaderInterface { @@ -241,6 +255,8 @@ private: return {x, 0}; } + int forceUseForBug() override { return 1; } + private: const SkScalar* fPositions; }; @@ -256,6 +272,8 @@ private: return to_return; } + int forceUseForBug() override { return 2; } + private: const SkScalar* fPositions; }; @@ -410,7 +428,9 @@ private: class GlyphFindAndPlaceSubpixel final : public GlyphFindAndPlaceInterface { public: GlyphFindAndPlaceSubpixel(LookupGlyph& glyphFinder) - : fGlyphFinder(glyphFinder) { } + : fGlyphFinder(glyphFinder) { + FixGCC49Arm64Bug(1); + } SkPoint findAndPositionGlyph( const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) override { @@ -464,6 +484,7 @@ private: public: GlyphFindAndPlaceFullPixel(LookupGlyph& glyphFinder) : fGlyphFinder(glyphFinder) { + FixGCC49Arm64Bug(2); // Kerning can only be used with SkPaint::kLeft_Align static_assert(!kUseKerning || SkPaint::kLeft_Align == kTextAlignment, "Kerning can only be used with left aligned text."); @@ -589,7 +610,7 @@ inline void SkFindAndPlaceGlyph::ProcessPosText( SkPoint mappedPoint = mapper.TranslationMapper::map( positions.HorizontalPositions::nextPoint()); positioner.Positioner::findAndPositionGlyph( - &cursor, mappedPoint, skstd::forward(processOneGlyph)); + &cursor, mappedPoint, std::forward(processOneGlyph)); } return; } @@ -601,6 +622,7 @@ inline void SkFindAndPlaceGlyph::ProcessPosText( } else { to_init->initialize(pos); } + positionReader->forceUseForBug(); } }; @@ -617,7 +639,7 @@ inline void SkFindAndPlaceGlyph::ProcessPosText( } }; - GlyphFindAndPlace findAndPosition{ + GlyphFindAndPlace findAndPosition { [&](typename GlyphFindAndPlace::Variants* to_init) { if (cache->isSubpixel()) { switch (textAlignment) { @@ -660,7 +682,7 @@ inline void SkFindAndPlaceGlyph::ProcessPosText( while (text < stop) { SkPoint mappedPoint = mapper->map(positionReader->nextPoint()); findAndPosition->findAndPositionGlyph( - &text, mappedPoint, skstd::forward(processOneGlyph)); + &text, mappedPoint, std::forward(processOneGlyph)); } } @@ -704,7 +726,7 @@ inline void SkFindAndPlaceGlyph::ProcessText( while (text < stop) { current = findAndPosition->findAndPositionGlyph( - &text, current, skstd::forward(processOneGlyph)); + &text, current, std::forward(processOneGlyph)); } } diff --git a/gfx/skia/skia/src/core/SkFloatBits.cpp b/gfx/skia/skia/src/core/SkFloatBits.cpp index 919fd0610f2..ea705513ac1 100644 --- a/gfx/skia/skia/src/core/SkFloatBits.cpp +++ b/gfx/skia/skia/src/core/SkFloatBits.cpp @@ -65,7 +65,7 @@ int32_t SkFloatBits_toIntCast(int32_t packed) { // same as (int)floor(float) int32_t SkFloatBits_toIntFloor(int32_t packed) { // curse you negative 0 - if ((packed << 1) == 0) { + if (SkLeftShift(packed, 1) == 0) { return 0; } @@ -104,7 +104,7 @@ int32_t SkFloatBits_toIntFloor(int32_t packed) { // same as (int)floor(float + 0.5) int32_t SkFloatBits_toIntRound(int32_t packed) { // curse you negative 0 - if ((packed << 1) == 0) { + if (SkLeftShift(packed, 1) == 0) { return 0; } @@ -134,7 +134,7 @@ int32_t SkFloatBits_toIntRound(int32_t packed) { // same as (int)ceil(float) int32_t SkFloatBits_toIntCeil(int32_t packed) { // curse you negative 0 - if ((packed << 1) == 0) { + if (SkLeftShift(packed, 1) == 0) { return 0; } @@ -200,6 +200,6 @@ float SkIntToFloatCast(int32_t value) { SkASSERT(shift >= 0 && shift <= 255); SkFloatIntUnion data; - data.fSignBitInt = (sign << 31) | (shift << 23) | (value & ~MATISSA_MAGIC_BIG); + data.fSignBitInt = SkLeftShift(sign, 31) | SkLeftShift(shift, 23) | (value & ~MATISSA_MAGIC_BIG); return data.fFloat; } diff --git a/gfx/skia/skia/src/core/SkGeometry.cpp b/gfx/skia/skia/src/core/SkGeometry.cpp index 01b618073ab..c25e18641a4 100644 --- a/gfx/skia/skia/src/core/SkGeometry.cpp +++ b/gfx/skia/skia/src/core/SkGeometry.cpp @@ -90,7 +90,13 @@ int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]) { SkScalar* r = roots; SkScalar R = B*B - 4*A*C; - if (R < 0 || SkScalarIsNaN(R)) { // complex roots + if (R < 0 || !SkScalarIsFinite(R)) { // complex roots + // if R is infinite, it's possible that it may still produce + // useful results if the operation was repeated in doubles + // the flipside is determining if the more precise answer + // isn't useful because surrounding machinery (e.g., subtracting + // the axis offset from C) already discards the extra precision + // more investigation and unit tests required... return 0; } R = SkScalarSqrt(R); @@ -1146,24 +1152,6 @@ int SkBuildQuadArc(const SkVector& uStart, const SkVector& uStop, // {t^2 (2 - 2 w), t (-2 + 2 w), 1} // -static SkScalar conic_eval_pos(const SkScalar src[], SkScalar w, SkScalar t) { - SkASSERT(src); - SkASSERT(t >= 0 && t <= SK_Scalar1); - - SkScalar src2w = SkScalarMul(src[2], w); - SkScalar C = src[0]; - SkScalar A = src[4] - 2 * src2w + C; - SkScalar B = 2 * (src2w - C); - SkScalar numer = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); - - B = 2 * (w - SK_Scalar1); - C = SK_Scalar1; - A = -B; - SkScalar denom = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); - - return numer / denom; -} - // F' = 2 (C t (1 + t (-1 + w)) - A (-1 + t) (t (-1 + w) - w) + B (1 - 2 t) w) // // t^2 : (2 P0 - 2 P2 - 2 P0 w + 2 P2 w) @@ -1230,18 +1218,6 @@ static void ratquad_mapTo3D(const SkPoint src[3], SkScalar w, SkP3D dst[]) { dst[2].set(src[2].fX * 1, src[2].fY * 1, 1); } -void SkConic::evalAt(SkScalar t, SkPoint* pt, SkVector* tangent) const { - SkASSERT(t >= 0 && t <= SK_Scalar1); - - if (pt) { - pt->set(conic_eval_pos(&fPts[0].fX, fW, t), - conic_eval_pos(&fPts[0].fY, fW, t)); - } - if (tangent) { - *tangent = evalTangentAt(t); - } -} - void SkConic::chopAt(SkScalar t, SkConic dst[2]) const { SkP3D tmp[3], tmp2[3]; @@ -1317,6 +1293,17 @@ SkVector SkConic::evalTangentAt(SkScalar t) const { return to_vector(quad_poly_eval(A, B, C, Sk2s(t))); } +void SkConic::evalAt(SkScalar t, SkPoint* pt, SkVector* tangent) const { + SkASSERT(t >= 0 && t <= SK_Scalar1); + + if (pt) { + *pt = this->evalAt(t); + } + if (tangent) { + *tangent = this->evalTangentAt(t); + } +} + static SkScalar subdivide_w_value(SkScalar w) { return SkScalarSqrt(SK_ScalarHalf + w * SK_ScalarHalf); } diff --git a/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp b/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp new file mode 100644 index 00000000000..ac37073eb31 --- /dev/null +++ b/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkBitmapProcShader.h" +#include "SkColorFilter.h" +#include "SkColorFilterShader.h" +#include "SkColorShader.h" +#include "SkComposeShader.h" +#include "SkEmptyShader.h" +#include "SkFlattenable.h" +#include "SkImageShader.h" +#include "SkLocalMatrixShader.h" +#include "SkOnce.h" +#include "SkPathEffect.h" +#include "SkPictureShader.h" +#include "SkMatrixImageFilter.h" +#include "SkXfermode.h" + +/* + * Registers all of the required effects subclasses for picture deserialization. + * + * Optional subclasses (e.g. Blur) should be registered in the ports/ version of this file, + * inside the InitEffects() method. + */ +void SkFlattenable::PrivateInitializer::InitCore() { + // Shader + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBitmapProcShader) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorFilterShader) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorShader) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeShader) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmptyShader) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLocalMatrixShader) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPictureShader) + + // PathEffect + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposePathEffect) + + // ImageFilter + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMatrixImageFilter) + + // ColorFilter + SkColorFilter::InitializeFlattenables(); + + // Xfermode + SkXfermode::InitializeFlattenables(); + + // Now initialize any optional/additional effects (implemented in src/ports) + InitEffects(); +}; + +SK_DECLARE_STATIC_ONCE(once); +void SkFlattenable::InitializeFlattenablesIfNeeded() { + SkOnce(&once, SkFlattenable::PrivateInitializer::InitCore); +} diff --git a/gfx/skia/skia/src/core/SkImageCacherator.cpp b/gfx/skia/skia/src/core/SkImageCacherator.cpp index f4a2ab734a5..572778e19ca 100644 --- a/gfx/skia/skia/src/core/SkImageCacherator.cpp +++ b/gfx/skia/skia/src/core/SkImageCacherator.cpp @@ -17,6 +17,7 @@ #if SK_SUPPORT_GPU #include "GrContext.h" #include "GrGpuResourcePriv.h" +#include "GrImageIDTextureAdjuster.h" #include "GrResourceKey.h" #include "GrTextureParams.h" #include "GrYUVProvider.h" @@ -68,9 +69,9 @@ SkImageCacherator::SkImageCacherator(SkImageGenerator* gen, const SkImageInfo& i , fUniqueID(uniqueID) {} -SkData* SkImageCacherator::refEncoded() { +SkData* SkImageCacherator::refEncoded(GrContext* ctx) { ScopedGenerator generator(this); - return generator->refEncodedData(); + return generator->refEncodedData(ctx); } static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) { @@ -258,7 +259,7 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(fInfo); // 3. Ask the generator to return a compressed form that the GPU might support - SkAutoTUnref data(this->refEncoded()); + SkAutoTUnref data(this->refEncoded(ctx)); if (data) { GrTexture* tex = load_compressed_into_texture(ctx, data, desc); if (tex) { @@ -289,60 +290,13 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key /////////////////////////////////////////////////////////////////////////////////////////////////// -#include "GrTextureParamsAdjuster.h" - -class Cacherator_GrTextureMaker : public GrTextureMaker { -public: - Cacherator_GrTextureMaker(GrContext* context, SkImageCacherator* cacher, const SkImage* client, - SkImage::CachingHint chint) - : INHERITED(context, cacher->info().width(), cacher->info().height()) - , fCacher(cacher) - , fClient(client) - , fCachingHint(chint) - { - if (client) { - GrMakeKeyFromImageID(&fOriginalKey, client->uniqueID(), - SkIRect::MakeWH(this->width(), this->height())); - } - } - -protected: - // TODO: consider overriding this, for the case where the underlying generator might be - // able to efficiently produce a "stretched" texture natively (e.g. picture-backed) - // GrTexture* generateTextureForParams(const CopyParams&) override; - - GrTexture* refOriginalTexture() override { - return fCacher->lockTexture(this->context(), fOriginalKey, fClient, fCachingHint); - } - - void makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey) override { - if (fOriginalKey.isValid()) { - MakeCopyKeyFromOrigKey(fOriginalKey, stretch, paramsCopyKey); - } - } - - void didCacheCopy(const GrUniqueKey& copyKey) override { - if (fClient) { - as_IB(fClient)->notifyAddedToCache(); - } - } - -private: - SkImageCacherator* fCacher; - const SkImage* fClient; - GrUniqueKey fOriginalKey; - SkImage::CachingHint fCachingHint; - - typedef GrTextureMaker INHERITED; -}; - GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParams& params, const SkImage* client, SkImage::CachingHint chint) { if (!ctx) { return nullptr; } - return Cacherator_GrTextureMaker(ctx, this, client, chint).refTextureForParams(params); + return GrImageTextureMaker(ctx, this, client, chint).refTextureForParams(params); } #else diff --git a/gfx/skia/skia/src/core/SkImageCacherator.h b/gfx/skia/skia/src/core/SkImageCacherator.h index bce39679c62..6b000668dd8 100644 --- a/gfx/skia/skia/src/core/SkImageCacherator.h +++ b/gfx/skia/skia/src/core/SkImageCacherator.h @@ -54,8 +54,11 @@ public: /** * If the underlying src naturally is represented by an encoded blob (in SkData), this returns * a ref to that data. If not, it returns null. + * + * If a GrContext is specified, then the caller is only interested in gpu-specific encoded + * formats, so others (e.g. PNG) can just return nullptr. */ - SkData* refEncoded(); + SkData* refEncoded(GrContext*); // Only return true if the generate has already been cached. bool lockAsBitmapOnlyIfAlreadyCached(SkBitmap*); @@ -95,7 +98,7 @@ private: const SkIPoint fOrigin; const uint32_t fUniqueID; - friend class Cacherator_GrTextureMaker; + friend class GrImageTextureMaker; }; #endif diff --git a/gfx/skia/skia/src/core/SkImageFilter.cpp b/gfx/skia/skia/src/core/SkImageFilter.cpp index 6a3286ed674..6fd098d2f7d 100644 --- a/gfx/skia/skia/src/core/SkImageFilter.cpp +++ b/gfx/skia/skia/src/core/SkImageFilter.cpp @@ -18,6 +18,7 @@ #include "SkReadBuffer.h" #include "SkRect.h" #include "SkTDynamicHash.h" +#include "SkTHash.h" #include "SkTInternalLList.h" #include "SkValidationUtils.h" #include "SkWriteBuffer.h" @@ -201,6 +202,7 @@ SkImageFilter::~SkImageFilter() { SkSafeUnref(fInputs[i]); } delete[] fInputs; + Cache::Get()->purgeByImageFilterId(fUniqueID); } SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer) @@ -263,25 +265,16 @@ bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src, } bool SkImageFilter::filterInput(int index, Proxy* proxy, const SkBitmap& src, - const Context& origCtx, - SkBitmap* result, SkIPoint* offset, - bool relaxSizeConstraint) const { + const Context& ctx, + SkBitmap* result, SkIPoint* offset) const { SkImageFilter* input = this->getInput(index); if (!input) { return true; } - - SizeConstraint constraint = origCtx.sizeConstraint(); - if (relaxSizeConstraint && (kExact_SizeConstraint == constraint)) { - constraint = kApprox_SizeConstraint; - } - Context ctx(origCtx.ctm(), origCtx.clipBounds(), origCtx.cache(), constraint); - - return input->filterImage(proxy, src, ctx, result, offset); + return input->filterImage(proxy, src, this->mapContext(ctx), result, offset); } -bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, - SkIRect* dst) const { +bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { SkASSERT(dst); return this->onFilterBounds(src, ctm, dst); } @@ -309,9 +302,6 @@ void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { } bool SkImageFilter::canComputeFastBounds() const { - if (this->affectsTransparentBlack()) { - return false; - } for (int i = 0; i < fInputCount; i++) { SkImageFilter* input = this->getInput(i); if (input && !input->canComputeFastBounds()) { @@ -321,10 +311,6 @@ bool SkImageFilter::canComputeFastBounds() const { return true; } -bool SkImageFilter::affectsTransparentBlack() const { - return false; -} - bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&, SkBitmap*, SkIPoint*) const { return false; @@ -348,8 +334,6 @@ bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Cont if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { return false; } - SkRect srcRect = SkRect::Make(bounds); - SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrContext* context = srcTexture->getContext(); GrSurfaceDesc desc; @@ -358,15 +342,11 @@ bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Cont desc.fHeight = bounds.height(); desc.fConfig = kRGBA_8888_GrPixelConfig; - SkAutoTUnref dst(context->textureProvider()->createTexture(desc, - GrTextureProvider::FromImageFilter(ctx.sizeConstraint()))); + SkAutoTUnref dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } - // setup new clip - GrClip clip(dstRect); - GrFragmentProcessor* fp; offset->fX = bounds.left(); offset->fY = bounds.top(); @@ -381,9 +361,12 @@ bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Cont SkAutoTUnref drawContext(context->drawContext(dst->asRenderTarget())); if (drawContext) { + SkRect srcRect = SkRect::Make(bounds); + SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); + GrClip clip(dstRect); drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); - WrapTexture(dst, bounds.width(), bounds.height(), result); + GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; } } @@ -391,6 +374,18 @@ bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Cont return false; } +bool SkImageFilter::asAColorFilter(SkColorFilter** filterPtr) const { + SkASSERT(nullptr != filterPtr); + if (!this->isColorFilterNode(filterPtr)) { + return false; + } + if (nullptr != this->getInput(0) || (*filterPtr)->affectsTransparentBlack()) { + (*filterPtr)->unref(); + return false; + } + return true; +} + bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src, const SkIPoint& srcOffset, SkIRect* dstBounds, SkIRect* srcBounds) const { @@ -400,7 +395,12 @@ bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src, } src.getBounds(srcBounds); srcBounds->offset(srcOffset); - return fCropRect.applyTo(*srcBounds, ctx, dstBounds) && srcBounds->intersect(*dstBounds); +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS + return fCropRect.applyTo(*srcBounds, ctx, dstBounds); +#else + this->onFilterNodeBounds(*srcBounds, ctx.ctm(), dstBounds, kForward_MapDirection); + return fCropRect.applyTo(*dstBounds, ctx, dstBounds); +#endif } bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src, @@ -408,7 +408,13 @@ bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitm SkIRect srcBounds; src.getBounds(&srcBounds); srcBounds.offset(*srcOffset); +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS if (!fCropRect.applyTo(srcBounds, ctx, bounds)) { +#else + SkIRect dstBounds; + this->onFilterNodeBounds(srcBounds, ctx.ctm(), &dstBounds, kForward_MapDirection); + if (!fCropRect.applyTo(dstBounds, ctx, bounds)) { +#endif return false; } @@ -436,26 +442,44 @@ bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, return true; } - SkIRect bounds; + SkIRect bounds, totalBounds; + this->onFilterNodeBounds(src, ctm, &bounds, kReverse_MapDirection); for (int i = 0; i < fInputCount; ++i) { SkImageFilter* filter = this->getInput(i); - SkIRect rect = src; - if (filter && !filter->filterBounds(src, ctm, &rect)) { + SkIRect rect = bounds; + if (filter && !filter->filterBounds(bounds, ctm, &rect)) { return false; } if (0 == i) { - bounds = rect; + totalBounds = rect; } else { - bounds.join(rect); + totalBounds.join(rect); } } // don't modify dst until now, so we don't accidentally change it in the // loop, but then return false on the next filter. - *dst = bounds; + *dst = totalBounds; return true; } +void SkImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix&, + SkIRect* dst, MapDirection) const { + *dst = src; +} + + +SkImageFilter::Context SkImageFilter::mapContext(const Context& ctx) const { +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS + return ctx; +#else + SkIRect clipBounds; + this->onFilterNodeBounds(ctx.clipBounds(), ctx.ctm(), &clipBounds, + MapDirection::kReverse_MapDirection); + return Context(ctx.ctm(), clipBounds, ctx.cache()); +#endif +} + bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&, const SkIRect&) const { return false; @@ -476,16 +500,9 @@ SkImageFilter* SkImageFilter::newWithLocalMatrix(const SkMatrix& matrix) const { #if SK_SUPPORT_GPU -void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) { - SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); - result->setInfo(info); - result->setPixelRef(new SkGrPixelRef(info, texture))->unref(); -} - bool SkImageFilter::filterInputGPU(int index, SkImageFilter::Proxy* proxy, - const SkBitmap& src, const Context& origCtx, - SkBitmap* result, SkIPoint* offset, - bool relaxSizeConstraint) const { + const SkBitmap& src, const Context& ctx, + SkBitmap* result, SkIPoint* offset) const { SkImageFilter* input = this->getInput(index); if (!input) { return true; @@ -494,21 +511,17 @@ bool SkImageFilter::filterInputGPU(int index, SkImageFilter::Proxy* proxy, // matrix with no clip and that the matrix, clip, and render target set before this function was // called are restored before we return to the caller. GrContext* context = src.getTexture()->getContext(); - - SizeConstraint constraint = origCtx.sizeConstraint(); - if (relaxSizeConstraint && (kExact_SizeConstraint == constraint)) { - constraint = kApprox_SizeConstraint; - } - Context ctx(origCtx.ctm(), origCtx.clipBounds(), origCtx.cache(), constraint); - - if (input->filterImage(proxy, src, ctx, result, offset)) { + if (input->filterImage(proxy, src, this->mapContext(ctx), result, offset)) { if (!result->getTexture()) { const SkImageInfo info = result->info(); if (kUnknown_SkColorType == info.colorType()) { return false; } SkAutoTUnref resultTex( - GrRefCachedBitmapTexture(context, *result,GrTextureParams::ClampNoFilter())); + GrRefCachedBitmapTexture(context, *result, GrTextureParams::ClampNoFilter())); + if (!resultTex) { + return false; + } result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref(); } return true; @@ -532,6 +545,7 @@ public: ++iter; delete v; } + fIdToKeys.foreach([](uint32_t, SkTArray** array) { delete *array; }); } struct Value { Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset) @@ -566,6 +580,13 @@ public: removeInternal(v); } Value* v = new Value(key, result, offset); + if (SkTArray** array = fIdToKeys.find(key.fUniqueID)) { + (*array)->push_back(key); + } else { + SkTArray* keyArray = new SkTArray(); + keyArray->push_back(key); + fIdToKeys.set(key.fUniqueID, keyArray); + } fLookup.add(v); fLRU.addToHead(v); fCurrentBytes += result.getSize(); @@ -588,6 +609,19 @@ public: } } + void purgeByImageFilterId(uint32_t uniqueID) override { + SkAutoMutexAcquire mutex(fMutex); + if (SkTArray** array = fIdToKeys.find(uniqueID)) { + for (auto& key : **array) { + if (Value* v = fLookup.find(key)) { + this->removeInternal(v); + } + } + fIdToKeys.remove(uniqueID); + delete *array; // This can be deleted outside the lock + } + } + private: void removeInternal(Value* v) { fCurrentBytes -= v->fBitmap.getSize(); @@ -596,11 +630,12 @@ private: delete v; } private: - SkTDynamicHash fLookup; - mutable SkTInternalLList fLRU; - size_t fMaxBytes; - size_t fCurrentBytes; - mutable SkMutex fMutex; + SkTDynamicHash fLookup; + SkTHashMap*> fIdToKeys; + mutable SkTInternalLList fLRU; + size_t fMaxBytes; + size_t fCurrentBytes; + mutable SkMutex fMutex; }; } // namespace @@ -620,10 +655,12 @@ void SkImageFilter::PurgeCache() { /////////////////////////////////////////////////////////////////////////////////////////////////// -SkBaseDevice* SkImageFilter::DeviceProxy::createDevice(int w, int h) { +SkBaseDevice* SkImageFilter::DeviceProxy::createDevice(int w, int h, TileUsage usage) { SkBaseDevice::CreateInfo cinfo(SkImageInfo::MakeN32Premul(w, h), - SkBaseDevice::kNever_TileUsage, + kPossible_TileUsage == usage ? SkBaseDevice::kPossible_TileUsage + : SkBaseDevice::kNever_TileUsage, kUnknown_SkPixelGeometry, + false, /* preserveLCDText */ true /*forImageFilter*/); SkBaseDevice* dev = fDevice->onCreateDevice(cinfo, nullptr); if (nullptr == dev) { diff --git a/gfx/skia/skia/src/core/SkImageGenerator.cpp b/gfx/skia/skia/src/core/SkImageGenerator.cpp index dcd3ad00b17..7d71b6701c3 100644 --- a/gfx/skia/skia/src/core/SkImageGenerator.cpp +++ b/gfx/skia/skia/src/core/SkImageGenerator.cpp @@ -137,7 +137,7 @@ bool SkImageGenerator::generateScaledPixels(const SkISize& scaledSize, ///////////////////////////////////////////////////////////////////////////////////////////// -SkData* SkImageGenerator::onRefEncodedData() { +SkData* SkImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { return nullptr; } diff --git a/gfx/skia/skia/src/core/SkLightingShader.cpp b/gfx/skia/skia/src/core/SkLightingShader.cpp index 147a7ef915c..a9fcac3b836 100644 --- a/gfx/skia/skia/src/core/SkLightingShader.cpp +++ b/gfx/skia/skia/src/core/SkLightingShader.cpp @@ -129,11 +129,12 @@ private: #include "GrCoordTransform.h" #include "GrFragmentProcessor.h" +#include "GrInvariantOutput.h" #include "GrTextureAccess.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "SkGr.h" #include "SkGrPriv.h" @@ -180,27 +181,28 @@ public: void emitCode(EmitArgs& args) override { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // add uniforms const char* lightDirUniName = nullptr; - fLightDirUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "LightDir", &lightDirUniName); + fLightDirUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, kDefault_GrSLPrecision, + "LightDir", &lightDirUniName); const char* lightColorUniName = nullptr; - fLightColorUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "LightColor", &lightColorUniName); + fLightColorUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, kDefault_GrSLPrecision, + "LightColor", &lightColorUniName); const char* ambientColorUniName = nullptr; - fAmbientColorUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "AmbientColor", &ambientColorUniName); + fAmbientColorUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, kDefault_GrSLPrecision, + "AmbientColor", &ambientColorUniName); const char* xformUniName = nullptr; - fXformUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "Xform", &xformUniName); + fXformUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "Xform", &xformUniName); fragBuilder->codeAppend("vec4 diffuseColor = "); fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fSamplers[0], diff --git a/gfx/skia/skia/src/core/SkLocalMatrixImageFilter.cpp b/gfx/skia/skia/src/core/SkLocalMatrixImageFilter.cpp index e4fc0ceb006..10d63ede66e 100644 --- a/gfx/skia/skia/src/core/SkLocalMatrixImageFilter.cpp +++ b/gfx/skia/skia/src/core/SkLocalMatrixImageFilter.cpp @@ -40,9 +40,8 @@ void SkLocalMatrixImageFilter::flatten(SkWriteBuffer& buffer) const { bool SkLocalMatrixImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { - Context localCtx(SkMatrix::Concat(ctx.ctm(), fLocalM), ctx.clipBounds(), ctx.cache(), - ctx.sizeConstraint()); - return this->filterInput(0, proxy, src, localCtx, result, offset, false); + Context localCtx(SkMatrix::Concat(ctx.ctm(), fLocalM), ctx.clipBounds(), ctx.cache()); + return this->filterInput(0, proxy, src, localCtx, result, offset); } bool SkLocalMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& matrix, diff --git a/gfx/skia/skia/src/core/SkLocalMatrixShader.cpp b/gfx/skia/skia/src/core/SkLocalMatrixShader.cpp index ce5a7cad713..336f1c49cfe 100644 --- a/gfx/skia/skia/src/core/SkLocalMatrixShader.cpp +++ b/gfx/skia/skia/src/core/SkLocalMatrixShader.cpp @@ -10,11 +10,11 @@ SkFlattenable* SkLocalMatrixShader::CreateProc(SkReadBuffer& buffer) { SkMatrix lm; buffer.readMatrix(&lm); - SkAutoTUnref shader(buffer.readShader()); - if (!shader.get()) { + SkAutoTUnref baseShader(buffer.readShader()); + if (!baseShader) { return nullptr; } - return SkShader::CreateLocalMatrixShader(shader, lm); + return baseShader->newWithLocalMatrix(lm); } void SkLocalMatrixShader::flatten(SkWriteBuffer& buffer) const { @@ -47,24 +47,21 @@ void SkLocalMatrixShader::toString(SkString* str) const { } #endif -SkShader* SkShader::CreateLocalMatrixShader(SkShader* proxy, const SkMatrix& localMatrix) { - if (nullptr == proxy) { - return nullptr; - } - +SkShader* SkShader::newWithLocalMatrix(const SkMatrix& localMatrix) const { if (localMatrix.isIdentity()) { - return SkRef(proxy); + return SkRef(const_cast(this)); } const SkMatrix* lm = &localMatrix; + SkShader* baseShader = const_cast(this); SkMatrix otherLocalMatrix; - SkAutoTUnref otherProxy(proxy->refAsALocalMatrixShader(&otherLocalMatrix)); - if (otherProxy.get()) { + SkAutoTUnref proxy(this->refAsALocalMatrixShader(&otherLocalMatrix)); + if (proxy) { otherLocalMatrix.preConcat(localMatrix); lm = &otherLocalMatrix; - proxy = otherProxy.get(); + baseShader = proxy.get(); } - return new SkLocalMatrixShader(proxy, *lm); + return new SkLocalMatrixShader(baseShader, *lm); } diff --git a/gfx/skia/skia/src/core/SkMaskFilter.cpp b/gfx/skia/skia/src/core/SkMaskFilter.cpp index 0753944a3b8..51c489721d4 100644 --- a/gfx/skia/skia/src/core/SkMaskFilter.cpp +++ b/gfx/skia/skia/src/core/SkMaskFilter.cpp @@ -19,7 +19,6 @@ #if SK_SUPPORT_GPU #include "GrTexture.h" #include "SkGr.h" -#include "SkGrPixelRef.h" #endif SkMaskFilter::NinePatch::~NinePatch() { @@ -349,7 +348,6 @@ bool SkMaskFilter::filterMaskGPU(GrTexture* src, void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { SkMask srcM, dstM; - srcM.fImage = nullptr; srcM.fBounds = src.roundOut(); srcM.fRowBytes = 0; srcM.fFormat = SkMask::kA8_Format; diff --git a/gfx/skia/skia/src/core/SkMatrix.cpp b/gfx/skia/skia/src/core/SkMatrix.cpp index b32f372bbdc..4b11fdf331a 100644 --- a/gfx/skia/skia/src/core/SkMatrix.cpp +++ b/gfx/skia/skia/src/core/SkMatrix.cpp @@ -156,7 +156,7 @@ uint8_t SkMatrix::computeTypeMask() const { } else { // Only test for scale explicitly if not affine, since affine sets the // scale bit. - if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) { + if ((m00 ^ kScalar1Int) | (m11 ^ kScalar1Int)) { mask |= kScale_Mask; } @@ -380,7 +380,20 @@ void SkMatrix::preScale(SkScalar sx, SkScalar sy) { fMat[kMScaleY] *= sy; fMat[kMPersp1] *= sy; +#ifndef SK_SUPPORT_LEGACY_PRESCALE_SEMANTICS + // Attempt to simplify our type when applying an inverse scale. + // TODO: The persp/affine preconditions are in place to keep the mask consistent with + // what computeTypeMask() would produce (persp/skew always implies kScale). + // We should investigate whether these flag dependencies are truly needed. + if (fMat[kMScaleX] == 1 && fMat[kMScaleY] == 1 + && !(fTypeMask & (kPerspective_Mask | kAffine_Mask))) { + this->clearTypeMask(kScale_Mask); + } else { + this->orTypeMask(kScale_Mask); + } +#else this->orTypeMask(kScale_Mask); +#endif } void SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) { @@ -1475,9 +1488,15 @@ template bool get_scale_factor(SkMatrix::TypeMask results[1] = apluscdiv2 + x; } } + if (SkScalarIsNaN(results[0])) { + return false; + } SkASSERT(results[0] >= 0); results[0] = SkScalarSqrt(results[0]); if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) { + if (SkScalarIsNaN(results[1])) { + return false; + } SkASSERT(results[1] >= 0); results[1] = SkScalarSqrt(results[1]); } @@ -1604,8 +1623,14 @@ void SkMatrix::toString(SkString* str) const { #include "SkMatrixUtils.h" -bool SkTreatAsSprite(const SkMatrix& mat, int width, int height, - unsigned subpixelBits) { +bool SkTreatAsSprite(const SkMatrix& mat, const SkISize& size, const SkPaint& paint) { + // Our path aa is 2-bits, and our rect aa is 8, so we could use 8, + // but in practice 4 seems enough (still looks smooth) and allows + // more slightly fractional cases to fall into the fast (sprite) case. + static const unsigned kAntiAliasSubpixelBits = 4; + + const unsigned subpixelBits = paint.isAntiAlias() ? kAntiAliasSubpixelBits : 0; + // quick reject on affine or perspective if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) { return false; @@ -1622,7 +1647,7 @@ bool SkTreatAsSprite(const SkMatrix& mat, int width, int height, } SkRect dst; - SkIRect isrc = { 0, 0, width, height }; + SkIRect isrc = SkIRect::MakeSize(size); { SkRect src; @@ -1635,10 +1660,10 @@ bool SkTreatAsSprite(const SkMatrix& mat, int width, int height, SkScalarRoundToInt(mat.getTranslateY())); if (subpixelBits) { - isrc.fLeft <<= subpixelBits; - isrc.fTop <<= subpixelBits; - isrc.fRight <<= subpixelBits; - isrc.fBottom <<= subpixelBits; + isrc.fLeft = SkLeftShift(isrc.fLeft, subpixelBits); + isrc.fTop = SkLeftShift(isrc.fTop, subpixelBits); + isrc.fRight = SkLeftShift(isrc.fRight, subpixelBits); + isrc.fBottom = SkLeftShift(isrc.fBottom, subpixelBits); const float scale = 1 << subpixelBits; dst.fLeft *= scale; diff --git a/gfx/skia/skia/src/core/SkMatrixImageFilter.cpp b/gfx/skia/skia/src/core/SkMatrixImageFilter.cpp index 4370ddadee2..4138ccf6775 100644 --- a/gfx/skia/skia/src/core/SkMatrixImageFilter.cpp +++ b/gfx/skia/skia/src/core/SkMatrixImageFilter.cpp @@ -97,30 +97,33 @@ void SkMatrixImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) cons getInput(0)->computeFastBounds(src, &bounds); } fTransform.mapRect(dst, bounds); +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS dst->join(bounds); // Work around for skia:3194 +#endif } -bool SkMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, - SkIRect* dst) const { - SkMatrix transformInverse; - if (!fTransform.invert(&transformInverse)) { - return false; - } +void SkMatrixImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst, MapDirection direction) const { SkMatrix matrix; if (!ctm.invert(&matrix)) { - return false; + *dst = src; + return; + } + if (kForward_MapDirection == direction) { + matrix.postConcat(fTransform); + } else { + SkMatrix transformInverse; + if (!fTransform.invert(&transformInverse)) { + *dst = src; + return; + } + matrix.postConcat(transformInverse); } - matrix.postConcat(transformInverse); matrix.postConcat(ctm); SkRect floatBounds; matrix.mapRect(&floatBounds, SkRect::Make(src)); SkIRect bounds = floatBounds.roundOut(); - if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { - return false; - } - *dst = bounds; - return true; } #ifndef SK_IGNORE_TO_STRING diff --git a/gfx/skia/skia/src/core/SkMatrixImageFilter.h b/gfx/skia/skia/src/core/SkMatrixImageFilter.h index 86734b629cf..09bfca9fe12 100644 --- a/gfx/skia/skia/src/core/SkMatrixImageFilter.h +++ b/gfx/skia/skia/src/core/SkMatrixImageFilter.h @@ -46,8 +46,8 @@ protected: virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result, SkIPoint* loc) const override; - virtual bool onFilterBounds(const SkIRect& src, const SkMatrix&, - SkIRect* dst) const override; + virtual void onFilterNodeBounds(const SkIRect& src, const SkMatrix&, + SkIRect* dst, MapDirection) const override; private: SkMatrix fTransform; diff --git a/gfx/skia/skia/src/core/SkMatrixUtils.h b/gfx/skia/skia/src/core/SkMatrixUtils.h index d1b6658d073..0e01fbe9539 100644 --- a/gfx/skia/skia/src/core/SkMatrixUtils.h +++ b/gfx/skia/skia/src/core/SkMatrixUtils.h @@ -8,37 +8,20 @@ #ifndef SkMatrixUtils_DEFINED #define SkMatrixUtils_DEFINED -#include "SkMatrix.h" +#include "SkSize.h" + +class SkMatrix; +class SkPaint; /** - * Number of subpixel bits used in skia's bilerp. - * See SkBitmapProcState_procs.h and SkBitmapProcState_filter.h - */ -#define kSkSubPixelBitsForBilerp 4 - -/** - * Given a matrix and width/height, return true if the computed dst-rect would + * Given a matrix, size and paint, return true if the computed dst-rect would * align such that there is a 1-to-1 coorspondence between src and dst pixels. * This can be called by drawing code to see if drawBitmap can be turned into * drawSprite (which is faster). * - * The src-rect is defined to be { 0, 0, width, height } - * - * The "closeness" test is based on the subpixelBits parameter. Pass 0 for - * round-to-nearest behavior (e.g. nearest neighbor sampling). Pass the number - * of subpixel-bits to simulate filtering. + * The src-rect is defined to be { 0, 0, size.width(), size.height() } */ -bool SkTreatAsSprite(const SkMatrix&, int width, int height, - unsigned subpixelBits); - -/** - * Calls SkTreatAsSprite() with default subpixelBits value to match Skia's - * filter-bitmap implementation (i.e. kSkSubPixelBitsForBilerp). - */ -static inline bool SkTreatAsSpriteFilter(const SkMatrix& matrix, - int width, int height) { - return SkTreatAsSprite(matrix, width, height, kSkSubPixelBitsForBilerp); -} +bool SkTreatAsSprite(const SkMatrix&, const SkISize& size, const SkPaint& paint); /** Decomposes the upper-left 2x2 of the matrix into a rotation (represented by the cosine and sine of the rotation angle), followed by a non-uniform scale, diff --git a/gfx/skia/skia/src/effects/SkColorFilters.cpp b/gfx/skia/skia/src/core/SkModeColorFilter.cpp similarity index 85% rename from gfx/skia/skia/src/effects/SkColorFilters.cpp rename to gfx/skia/skia/src/core/SkModeColorFilter.cpp index 4515c0d3fef..df1051abb0e 100644 --- a/gfx/skia/skia/src/effects/SkColorFilters.cpp +++ b/gfx/skia/skia/src/core/SkModeColorFilter.cpp @@ -14,7 +14,17 @@ #include "SkUtils.h" #include "SkString.h" #include "SkValidationUtils.h" -#include "SkColorMatrixFilter.h" + +////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef SK_IGNORE_TO_STRING +void SkModeColorFilter::toString(SkString* str) const { + str->append("SkModeColorFilter: color: 0x"); + str->appendHex(fColor); + str->append(" mode: "); + str->append(SkXfermode::ModeName(fMode)); +} +#endif bool SkModeColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) const { if (color) { @@ -101,7 +111,7 @@ const GrFragmentProcessor* SkModeColorFilter::asFragmentProcessor(GrContext*) co /////////////////////////////////////////////////////////////////////////////// -class Src_SkModeColorFilter : public SkModeColorFilter { +class Src_SkModeColorFilter final : public SkModeColorFilter { public: Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrc_Mode) {} @@ -113,7 +123,7 @@ private: typedef SkModeColorFilter INHERITED; }; -class SrcOver_SkModeColorFilter : public SkModeColorFilter { +class SrcOver_SkModeColorFilter final : public SkModeColorFilter { public: SrcOver_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrcOver_Mode) { } @@ -169,28 +179,3 @@ SkColorFilter* SkColorFilter::CreateModeFilter(SkColor color, SkXfermode::Mode m return SkModeColorFilter::Create(color, mode); } } - -/////////////////////////////////////////////////////////////////////////////// - -static SkScalar byte_to_scale(U8CPU byte) { - if (0xFF == byte) { - // want to get this exact - return 1; - } else { - return byte * 0.00392156862745f; - } -} - -SkColorFilter* SkColorFilter::CreateLightingFilter(SkColor mul, SkColor add) { - SkColorMatrix matrix; - matrix.setScale(byte_to_scale(SkColorGetR(mul)), - byte_to_scale(SkColorGetG(mul)), - byte_to_scale(SkColorGetB(mul)), - 1); - matrix.postTranslate(SkIntToScalar(SkColorGetR(add)), - SkIntToScalar(SkColorGetG(add)), - SkIntToScalar(SkColorGetB(add)), - 0); - return SkColorMatrixFilter::Create(matrix); -} - diff --git a/gfx/skia/skia/include/effects/SkModeColorFilter.h b/gfx/skia/skia/src/core/SkModeColorFilter.h similarity index 82% rename from gfx/skia/skia/include/effects/SkModeColorFilter.h rename to gfx/skia/skia/src/core/SkModeColorFilter.h index 06eec43572b..9fa7717b84d 100644 --- a/gfx/skia/skia/include/effects/SkModeColorFilter.h +++ b/gfx/skia/skia/src/core/SkModeColorFilter.h @@ -1,18 +1,16 @@ /* - * Copyright 2015 Google Inc. + * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#include "SkColorFilter.h" +#include "SkXfermode.h" + #ifndef SkModeColorFilter_DEFINED #define SkModeColorFilter_DEFINED -#include "SkColorFilter.h" -#include "SkColorPriv.h" -#include "SkString.h" -#include "SkXfermode.h" - class SkModeColorFilter : public SkColorFilter { public: static SkColorFilter* Create(SkColor color, SkXfermode::Mode mode) { @@ -28,12 +26,7 @@ public: void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override; #ifndef SK_IGNORE_TO_STRING - void toString(SkString* str) const override { - str->append("SkModeColorFilter: color: 0x"); - str->appendHex(fColor); - str->append(" mode: "); - str->append(SkXfermode::ModeName(fMode)); - } + void toString(SkString* str) const override; #endif #if SK_SUPPORT_GPU @@ -59,6 +52,8 @@ private: void updateCache(); + friend class SkColorFilter; + typedef SkColorFilter INHERITED; }; diff --git a/gfx/skia/skia/src/core/SkMultiPictureDraw.cpp b/gfx/skia/skia/src/core/SkMultiPictureDraw.cpp index 672bd628b7c..57456648581 100644 --- a/gfx/skia/skia/src/core/SkMultiPictureDraw.cpp +++ b/gfx/skia/skia/src/core/SkMultiPictureDraw.cpp @@ -94,7 +94,7 @@ void SkMultiPictureDraw::draw(bool flush) { fThreadSafeDrawData[i].draw(); } #else - sk_parallel_for(fThreadSafeDrawData.count(), [&](int i) { + SkTaskGroup().batch(fThreadSafeDrawData.count(), [&](int i) { fThreadSafeDrawData[i].draw(); }); #endif diff --git a/gfx/skia/skia/src/core/SkNx.h b/gfx/skia/skia/src/core/SkNx.h index 36a645cac12..684a31dcef1 100644 --- a/gfx/skia/skia/src/core/SkNx.h +++ b/gfx/skia/skia/src/core/SkNx.h @@ -9,8 +9,7 @@ #define SkNx_DEFINED -#define SKNX_NO_SIMDx // Remove the x to disable SIMD for all SkNx types. - +//#define SKNX_NO_SIMD #include "SkScalar.h" #include "SkTypes.h" @@ -25,7 +24,8 @@ namespace { // The default implementations just fall back on a pair of size N/2. - +// These support the union of operations we might do to ints and floats, but +// platform specializations might support fewer (e.g. no float <<, no int /). template class SkNx { public: @@ -55,14 +55,33 @@ public: SkNx operator + (const SkNx& o) const { return SkNx(fLo + o.fLo, fHi + o.fHi); } SkNx operator - (const SkNx& o) const { return SkNx(fLo - o.fLo, fHi - o.fHi); } SkNx operator * (const SkNx& o) const { return SkNx(fLo * o.fLo, fHi * o.fHi); } + SkNx operator / (const SkNx& o) const { return SkNx(fLo / o.fLo, fHi / o.fHi); } SkNx operator << (int bits) const { return SkNx(fLo << bits, fHi << bits); } SkNx operator >> (int bits) const { return SkNx(fLo >> bits, fHi >> bits); } + SkNx operator == (const SkNx& o) const { return SkNx(fLo == o.fLo, fHi == o.fHi); } + SkNx operator != (const SkNx& o) const { return SkNx(fLo != o.fLo, fHi != o.fHi); } + SkNx operator < (const SkNx& o) const { return SkNx(fLo < o.fLo, fHi < o.fHi); } + SkNx operator > (const SkNx& o) const { return SkNx(fLo > o.fLo, fHi > o.fHi); } + SkNx operator <= (const SkNx& o) const { return SkNx(fLo <= o.fLo, fHi <= o.fHi); } + SkNx operator >= (const SkNx& o) const { return SkNx(fLo >= o.fLo, fHi >= o.fHi); } + static SkNx Min(const SkNx& a, const SkNx& b) { return SkNx(SkNx::Min(a.fLo, b.fLo), SkNx::Min(a.fHi, b.fHi)); } - SkNx operator < (const SkNx& o) const { return SkNx(fLo < o.fLo, fHi < o.fHi); } + static SkNx Max(const SkNx& a, const SkNx& b) { + return SkNx(SkNx::Max(a.fLo, b.fLo), SkNx::Max(a.fHi, b.fHi)); + } + + SkNx sqrt() const { return SkNx(fLo.sqrt(), fHi.sqrt()); } + // Generally, increasing precision, increasing cost. + SkNx rsqrt0() const { return SkNx(fLo.rsqrt0(), fHi.rsqrt0()); } + SkNx rsqrt1() const { return SkNx(fLo.rsqrt1(), fHi.rsqrt1()); } + SkNx rsqrt2() const { return SkNx(fLo.rsqrt2(), fHi.rsqrt2()); } + + SkNx invert() const { return SkNx(fLo. invert(), fHi. invert()); } + SkNx approxInvert() const { return SkNx(fLo.approxInvert(), fHi.approxInvert()); } template T kth() const { SkASSERT(0 <= k && k < N); @@ -81,97 +100,7 @@ protected: SkNx fLo, fHi; }; -template -class SkNx { -public: - SkNx() {} - SkNx(float val) : fLo(val), fHi(val) {} - static SkNx Load(const float vals[N]) { - return SkNx(SkNx::Load(vals), SkNx::Load(vals+N/2)); - } - // FromBytes() and toBytes() specializations may assume their argument is N-byte aligned. - // E.g. Sk4f::FromBytes() may assume it's reading from a 4-byte-aligned pointer. - // Converts [0,255] bytes to [0.0, 255.0] floats. - static SkNx FromBytes(const uint8_t bytes[N]) { - return SkNx(SkNx::FromBytes(bytes), SkNx::FromBytes(bytes+N/2)); - } - - SkNx(float a, float b) : fLo(a), fHi(b) { REQUIRE(N==2); } - SkNx(float a, float b, float c, float d) : fLo(a,b), fHi(c,d) { REQUIRE(N==4); } - SkNx(float a, float b, float c, float d, float e, float f, float g, float h) - : fLo(a,b,c,d) - , fHi(e,f,g,h) { REQUIRE(N==8); } - - void store(float vals[N]) const { - fLo.store(vals); - fHi.store(vals+N/2); - } - // Please see note on FromBytes(). - // Clamps to [0.0,255.0] floats and truncates to [0,255] bytes. - void toBytes(uint8_t bytes[N]) const { - fLo.toBytes(bytes); - fHi.toBytes(bytes+N/2); - } - - // Some implementations can do this faster. - static void ToBytes(uint8_t bytes[4*N], - const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { - a.toBytes(bytes+0*N); - b.toBytes(bytes+1*N); - c.toBytes(bytes+2*N); - d.toBytes(bytes+3*N); - } - - SkNx operator + (const SkNx& o) const { return SkNx(fLo + o.fLo, fHi + o.fHi); } - SkNx operator - (const SkNx& o) const { return SkNx(fLo - o.fLo, fHi - o.fHi); } - SkNx operator * (const SkNx& o) const { return SkNx(fLo * o.fLo, fHi * o.fHi); } - SkNx operator / (const SkNx& o) const { return SkNx(fLo / o.fLo, fHi / o.fHi); } - - SkNx operator == (const SkNx& o) const { return SkNx(fLo == o.fLo, fHi == o.fHi); } - SkNx operator != (const SkNx& o) const { return SkNx(fLo != o.fLo, fHi != o.fHi); } - SkNx operator < (const SkNx& o) const { return SkNx(fLo < o.fLo, fHi < o.fHi); } - SkNx operator > (const SkNx& o) const { return SkNx(fLo > o.fLo, fHi > o.fHi); } - SkNx operator <= (const SkNx& o) const { return SkNx(fLo <= o.fLo, fHi <= o.fHi); } - SkNx operator >= (const SkNx& o) const { return SkNx(fLo >= o.fLo, fHi >= o.fHi); } - - static SkNx Min(const SkNx& l, const SkNx& r) { - return SkNx(SkNx::Min(l.fLo, r.fLo), SkNx::Min(l.fHi, r.fHi)); - } - static SkNx Max(const SkNx& l, const SkNx& r) { - return SkNx(SkNx::Max(l.fLo, r.fLo), SkNx::Max(l.fHi, r.fHi)); - } - - SkNx sqrt() const { return SkNx(fLo. sqrt(), fHi. sqrt()); } - - // Generally, increasing precision, increasing cost. - SkNx rsqrt0() const { return SkNx(fLo.rsqrt0(), fHi.rsqrt0()); } - SkNx rsqrt1() const { return SkNx(fLo.rsqrt1(), fHi.rsqrt1()); } - SkNx rsqrt2() const { return SkNx(fLo.rsqrt2(), fHi.rsqrt2()); } - - SkNx invert() const { return SkNx(fLo. invert(), fHi. invert()); } - SkNx approxInvert() const { return SkNx(fLo.approxInvert(), fHi.approxInvert()); } - - template float kth() const { - SkASSERT(0 <= k && k < N); - return k < N/2 ? fLo.template kth() : fHi.template kth(); - } - - bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } - bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } - SkNx thenElse(const SkNx& t, const SkNx& e) const { - return SkNx(fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi)); - } - -protected: - REQUIRE(0 == (N & (N-1))); - SkNx(const SkNx& lo, const SkNx& hi) : fLo(lo), fHi(hi) {} - - SkNx fLo, fHi; -}; - - // Bottom out the default implementations with scalars when nothing's been specialized. - template class SkNx<1,T> { public: @@ -190,42 +119,11 @@ public: SkNx operator + (const SkNx& o) const { return SkNx(fVal + o.fVal); } SkNx operator - (const SkNx& o) const { return SkNx(fVal - o.fVal); } SkNx operator * (const SkNx& o) const { return SkNx(fVal * o.fVal); } + SkNx operator / (const SkNx& o) const { return SkNx(fVal / o.fVal); } SkNx operator << (int bits) const { return SkNx(fVal << bits); } SkNx operator >> (int bits) const { return SkNx(fVal >> bits); } - static SkNx Min(const SkNx& a, const SkNx& b) { return SkNx(SkTMin(a.fVal, b.fVal)); } - SkNx operator <(const SkNx& o) const { return SkNx(fVal < o.fVal); } - - template T kth() const { - SkASSERT(0 == k); - return fVal; - } - - bool allTrue() const { return fVal; } - bool anyTrue() const { return fVal; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal ? t : e; } - -protected: - T fVal; -}; - -template <> -class SkNx<1,float> { -public: - SkNx() {} - SkNx(float val) : fVal(val) {} - static SkNx Load(const float vals[1]) { return SkNx(vals[0]); } - static SkNx FromBytes(const uint8_t bytes[1]) { return SkNx((float)bytes[0]); } - - void store(float vals[1]) const { vals[0] = fVal; } - void toBytes(uint8_t bytes[1]) const { bytes[0] = (uint8_t)(SkTMin(fVal, 255.0f)); } - - SkNx operator + (const SkNx& o) const { return SkNx(fVal + o.fVal); } - SkNx operator - (const SkNx& o) const { return SkNx(fVal - o.fVal); } - SkNx operator * (const SkNx& o) const { return SkNx(fVal * o.fVal); } - SkNx operator / (const SkNx& o) const { return SkNx(fVal / o.fVal); } - SkNx operator == (const SkNx& o) const { return SkNx(fVal == o.fVal); } SkNx operator != (const SkNx& o) const { return SkNx(fVal != o.fVal); } SkNx operator < (const SkNx& o) const { return SkNx(fVal < o.fVal); } @@ -233,33 +131,31 @@ public: SkNx operator <= (const SkNx& o) const { return SkNx(fVal <= o.fVal); } SkNx operator >= (const SkNx& o) const { return SkNx(fVal >= o.fVal); } - static SkNx Min(const SkNx& l, const SkNx& r) { return SkNx(SkTMin(l.fVal, r.fVal)); } - static SkNx Max(const SkNx& l, const SkNx& r) { return SkNx(SkTMax(l.fVal, r.fVal)); } + static SkNx Min(const SkNx& a, const SkNx& b) { return SkNx(SkTMin(a.fVal, b.fVal)); } + static SkNx Max(const SkNx& a, const SkNx& b) { return SkNx(SkTMax(a.fVal, b.fVal)); } - SkNx sqrt() const { return SkNx(sqrtf(fVal)); } - SkNx rsqrt0() const { return SkNx(1.0f / sqrtf(fVal)); } + SkNx sqrt () const { return SkNx(Sqrt(fVal)); } + SkNx rsqrt0() const { return this->sqrt().invert(); } SkNx rsqrt1() const { return this->rsqrt0(); } SkNx rsqrt2() const { return this->rsqrt1(); } - SkNx invert() const { return SkNx(1.0f / fVal); } + SkNx invert() const { return SkNx(1) / SkNx(fVal); } SkNx approxInvert() const { return this->invert(); } - template float kth() const { - SkASSERT(k == 0); + template T kth() const { + SkASSERT(0 == k); return fVal; } - bool allTrue() const { return this->pun() != 0; } - bool anyTrue() const { return this->pun() != 0; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { return this->pun() ? t : e; } + bool allTrue() const { return fVal != 0; } + bool anyTrue() const { return fVal != 0; } + SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e; } protected: - uint32_t pun() const { - union { float f; uint32_t i; } pun = { fVal }; - return pun.i; - } + static double Sqrt(double val) { return ::sqrt (val); } + static float Sqrt(float val) { return ::sqrtf(val); } - float fVal; + T fVal; }; // This default implementation can be specialized by ../opts/SkNx_foo.h @@ -296,7 +192,7 @@ SkNx SkNx_cast_fallback(const SkNx& src, SkIntSequence) { // This is a generic cast between two SkNx with the same number of elements N. E.g. // Sk4b bs = ...; // Load 4 bytes. -// Sk4f fs = SkNx_cast(bs); // (This will replace SkNf::FromBytes() one day.) +// Sk4f fs = SkNx_cast(bs); // Cast each byte to a float. // Sk4i is = SkNx_cast(fs); // Cast each float to int. // This can be specialized in ../opts/SkNx_foo.h if there's a better platform-specific cast. template @@ -306,31 +202,46 @@ SkNx SkNx_cast(const SkNx& src) { } // namespace - -// Include platform specific specializations if available. -#ifndef SKNX_NO_SIMD - #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX - #include "../opts/SkNx_avx.h" - #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 - #include "../opts/SkNx_sse.h" - #elif defined(SK_ARM_HAS_NEON) - #include "../opts/SkNx_neon.h" - #endif -#endif - -#undef REQUIRE - typedef SkNx<2, float> Sk2f; -typedef SkNx<2, float> Sk2s; typedef SkNx<4, float> Sk4f; -typedef SkNx<4, float> Sk4s; typedef SkNx<8, float> Sk8f; -typedef SkNx<8, float> Sk8s; -typedef SkNx<8, uint16_t> Sk8h; +typedef SkNx<2, double> Sk2d; +typedef SkNx<4, double> Sk4d; +typedef SkNx<8, double> Sk8d; + +typedef SkNx<2, SkScalar> Sk2s; +typedef SkNx<4, SkScalar> Sk4s; +typedef SkNx<8, SkScalar> Sk8s; + +typedef SkNx< 4, uint16_t> Sk4h; +typedef SkNx< 8, uint16_t> Sk8h; typedef SkNx<16, uint16_t> Sk16h; + +typedef SkNx< 4, uint8_t> Sk4b; +typedef SkNx< 8, uint8_t> Sk8b; typedef SkNx<16, uint8_t> Sk16b; typedef SkNx<4, int> Sk4i; +// Include platform specific specializations if available. +#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX + #include "../opts/SkNx_avx.h" +#elif !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + #include "../opts/SkNx_sse.h" +#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) + #include "../opts/SkNx_neon.h" +#else + static inline + void Sk4f_ToBytes(uint8_t p[16], const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) { + SkNx_cast(a).store(p+ 0); + SkNx_cast(b).store(p+ 4); + SkNx_cast(c).store(p+ 8); + SkNx_cast(d).store(p+12); + } +#endif + +#undef REQUIRE + + #endif//SkNx_DEFINED diff --git a/gfx/skia/skia/src/core/SkOpts.cpp b/gfx/skia/skia/src/core/SkOpts.cpp index fc70a570dbe..970672e32ca 100644 --- a/gfx/skia/skia/src/core/SkOpts.cpp +++ b/gfx/skia/skia/src/core/SkOpts.cpp @@ -16,11 +16,12 @@ #include "SkFloatingPoint_opts.h" #include "SkMatrix_opts.h" #include "SkMorphologyImageFilter_opts.h" +#include "SkSwizzler_opts.h" #include "SkTextureCompressor_opts.h" #include "SkUtils_opts.h" #include "SkXfermode_opts.h" -#if defined(SK_CPU_X86) +#if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS) #if defined(SK_BUILD_FOR_WIN32) #include static void cpuid (uint32_t abcd[4]) { __cpuid ((int*)abcd, 1); } @@ -84,6 +85,10 @@ namespace SkOpts { decltype(matrix_scale_translate) matrix_scale_translate = sk_default::matrix_scale_translate; decltype(matrix_affine) matrix_affine = sk_default::matrix_affine; + decltype( premul_xxxa) premul_xxxa = sk_default:: premul_xxxa; + decltype( swaprb_xxxa) swaprb_xxxa = sk_default:: swaprb_xxxa; + decltype(premul_swaprb_xxxa) premul_swaprb_xxxa = sk_default::premul_swaprb_xxxa; + // Each Init_foo() is defined in src/opts/SkOpts_foo.cpp. void Init_sse2(); void Init_ssse3(); diff --git a/gfx/skia/skia/src/core/SkOpts.h b/gfx/skia/skia/src/core/SkOpts.h index 1b94126cf72..85e38fe1396 100644 --- a/gfx/skia/skia/src/core/SkOpts.h +++ b/gfx/skia/skia/src/core/SkOpts.h @@ -57,6 +57,11 @@ namespace SkOpts { const SkColor*); extern SkMatrix::MapPtsProc matrix_translate, matrix_scale_translate, matrix_affine; + + typedef void (*Swizzle_8888_8888)(uint32_t[], const uint32_t[], int); + extern Swizzle_8888_8888 premul_xxxa, // BGRA -> bgrA or RGBA -> rgbA + swaprb_xxxa, // BGRA -> RGBA or RGBA -> BGRA + premul_swaprb_xxxa; // BGRA -> rgbA or RGBA -> bgrA } #endif//SkOpts_DEFINED diff --git a/gfx/skia/skia/src/core/SkPaint.cpp b/gfx/skia/skia/src/core/SkPaint.cpp index 2623052ec46..e5fe975bcd7 100644 --- a/gfx/skia/skia/src/core/SkPaint.cpp +++ b/gfx/skia/skia/src/core/SkPaint.cpp @@ -36,6 +36,10 @@ #include "SkSurfacePriv.h" #include "SkXfermode.h" +static inline uint32_t set_clear_mask(uint32_t bits, bool cond, uint32_t mask) { + return cond ? bits | mask : bits & ~mask; +} + // define this to get a printf for out-of-range parameter in setters // e.g. setTextSize(-1) //#define SK_REPORT_API_RANGE_CHECK @@ -184,51 +188,51 @@ void SkPaint::setFlags(uint32_t flags) { } void SkPaint::setAntiAlias(bool doAA) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doAA, kAntiAlias_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doAA, kAntiAlias_Flag)); } void SkPaint::setDither(bool doDither) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doDither, kDither_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doDither, kDither_Flag)); } void SkPaint::setSubpixelText(bool doSubpixel) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doSubpixel, kSubpixelText_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doSubpixel, kSubpixelText_Flag)); } void SkPaint::setLCDRenderText(bool doLCDRender) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doLCDRender, kLCDRenderText_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doLCDRender, kLCDRenderText_Flag)); } void SkPaint::setEmbeddedBitmapText(bool doEmbeddedBitmapText) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag)); } void SkPaint::setAutohinted(bool useAutohinter) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, useAutohinter, kAutoHinting_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, useAutohinter, kAutoHinting_Flag)); } void SkPaint::setLinearText(bool doLinearText) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doLinearText, kLinearText_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doLinearText, kLinearText_Flag)); } void SkPaint::setVerticalText(bool doVertical) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doVertical, kVerticalText_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doVertical, kVerticalText_Flag)); } void SkPaint::setUnderlineText(bool doUnderline) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doUnderline, kUnderlineText_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doUnderline, kUnderlineText_Flag)); } void SkPaint::setStrikeThruText(bool doStrikeThru) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doStrikeThru, kStrikeThruText_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doStrikeThru, kStrikeThruText_Flag)); } void SkPaint::setFakeBoldText(bool doFakeBold) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doFakeBold, kFakeBoldText_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doFakeBold, kFakeBoldText_Flag)); } void SkPaint::setDevKernText(bool doDevKern) { - this->setFlags(SkSetClearMask(fBitfields.fFlags, doDevKern, kDevKernText_Flag)); + this->setFlags(set_clear_mask(fBitfields.fFlags, doDevKern, kDevKernText_Flag)); } void SkPaint::setStyle(Style style) { @@ -1942,6 +1946,9 @@ void SkPaint::flatten(SkWriteBuffer& buffer) const { void SkPaint::unflatten(SkReadBuffer& buffer) { SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize); + if (!buffer.validateAvailable(kPODPaintSize)) { + return; + } const void* podData = buffer.skip(kPODPaintSize); const uint32_t* pod = reinterpret_cast(podData); diff --git a/gfx/skia/skia/src/core/SkPath.cpp b/gfx/skia/skia/src/core/SkPath.cpp index 351629d1252..4af2dad5262 100644 --- a/gfx/skia/skia/src/core/SkPath.cpp +++ b/gfx/skia/skia/src/core/SkPath.cpp @@ -6,6 +6,7 @@ */ #include "SkBuffer.h" +#include "SkCubicClipper.h" #include "SkErrorInternals.h" #include "SkGeometry.h" #include "SkMath.h" @@ -583,7 +584,7 @@ int SkPath::getPoints(SkPoint dst[], int max) const { SkASSERT(max >= 0); SkASSERT(!max || dst); int count = SkMin32(max, fPathRef->countPoints()); - memcpy(dst, fPathRef->points(), count * sizeof(SkPoint)); + sk_careful_memcpy(dst, fPathRef->points(), count * sizeof(SkPoint)); return fPathRef->countPoints(); } @@ -1908,6 +1909,13 @@ size_t SkPath::readFromMemory(const void* storage, size_t length) { uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3; fIsVolatile = (packed >> kIsVolatile_SerializationShift) & 0x1; SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer); + if (!pathRef) { + return 0; + } + + fPathRef.reset(pathRef); + SkDEBUGCODE(this->validate();) + buffer.skipToAlign4(); // compatibility check if (version < kPathPrivFirstDirection_Version) { @@ -1928,17 +1936,7 @@ size_t SkPath::readFromMemory(const void* storage, size_t length) { fFirstDirection = dir; } - size_t sizeRead = 0; - if (buffer.isValid()) { - fPathRef.reset(pathRef); - SkDEBUGCODE(this->validate();) - buffer.skipToAlign4(); - sizeRead = buffer.pos(); - } else if (pathRef) { - // If the buffer is not valid, pathRef should be nullptr - sk_throw(); - } - return sizeRead; + return buffer.pos(); } /////////////////////////////////////////////////////////////////////////////// @@ -2588,6 +2586,12 @@ bool SkPathPriv::CheapComputeFirstDirection(const SkPath& path, FirstDirection* /////////////////////////////////////////////////////////////////////////////// +static bool between(SkScalar a, SkScalar b, SkScalar c) { + SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0) + || (SkScalarNearlyZero(a) && SkScalarNearlyZero(b) && SkScalarNearlyZero(c))); + return (a - b) * (c - b) <= 0; +} + static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, SkScalar D, SkScalar t) { return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); @@ -2602,40 +2606,6 @@ static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c return eval_cubic_coeff(A, B, C, D, t); } -/* Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the - t value such that cubic(t) = target - */ -static void chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3, - SkScalar target, SkScalar* t) { - // SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3); - SkASSERT(c0 < target && target < c3); - - SkScalar D = c0 - target; - SkScalar A = c3 + 3*(c1 - c2) - c0; - SkScalar B = 3*(c2 - c1 - c1 + c0); - SkScalar C = 3*(c1 - c0); - - const SkScalar TOLERANCE = SK_Scalar1 / 4096; - SkScalar minT = 0; - SkScalar maxT = SK_Scalar1; - SkScalar mid; - int i; - for (i = 0; i < 16; i++) { - mid = SkScalarAve(minT, maxT); - SkScalar delta = eval_cubic_coeff(A, B, C, D, mid); - if (delta < 0) { - minT = mid; - delta = -delta; - } else { - maxT = mid; - } - if (delta < TOLERANCE) { - break; - } - } - *t = mid; -} - template static void find_minmax(const SkPoint pts[], SkScalar* minPtr, SkScalar* maxPtr) { SkScalar min, max; @@ -2648,19 +2618,31 @@ template static void find_minmax(const SkPoint pts[], *maxPtr = max; } -static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y) { - SkPoint storage[4]; +static bool checkOnCurve(SkScalar x, SkScalar y, const SkPoint& start, const SkPoint& end) { + if (start.fY == end.fY) { + return between(start.fX, x, end.fX) && x != end.fX; + } else { + return x == start.fX && y == start.fY; + } +} + +static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { + SkScalar y0 = pts[0].fY; + SkScalar y3 = pts[3].fY; int dir = 1; - if (pts[0].fY > pts[3].fY) { - storage[0] = pts[3]; - storage[1] = pts[2]; - storage[2] = pts[1]; - storage[3] = pts[0]; - pts = storage; + if (y0 > y3) { + SkTSwap(y0, y3); dir = -1; } - if (y < pts[0].fY || y >= pts[3].fY) { + if (y < y0 || y > y3) { + return 0; + } + if (checkOnCurve(x, y, pts[0], pts[3])) { + *onCurveCount += 1; + return 0; + } + if (y == y3) { return 0; } @@ -2676,22 +2658,47 @@ static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y) { // compute the actual x(t) value SkScalar t; - chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, &t); + SkAssertResult(SkCubicClipper::ChopMonoAtY(pts, y, &t)); SkScalar xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t); + if (SkScalarNearlyEqual(xt, x)) { + if (x != pts[3].fX || y != pts[3].fY) { // don't test end points; they're start points + *onCurveCount += 1; + return 0; + } + } return xt < x ? dir : 0; } -static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y) { +static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { SkPoint dst[10]; int n = SkChopCubicAtYExtrema(pts, dst); int w = 0; for (int i = 0; i <= n; ++i) { - w += winding_mono_cubic(&dst[i * 3], x, y); + w += winding_mono_cubic(&dst[i * 3], x, y, onCurveCount); } return w; } -static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y) { +static double conic_eval_numerator(const SkScalar src[], SkScalar w, SkScalar t) { + SkASSERT(src); + SkASSERT(t >= 0 && t <= 1); + SkScalar src2w = src[2] * w; + SkScalar C = src[0]; + SkScalar A = src[4] - 2 * src2w + C; + SkScalar B = 2 * (src2w - C); + return (A * t + B) * t + C; +} + + +static double conic_eval_denominator(SkScalar w, SkScalar t) { + SkScalar B = 2 * (w - 1); + SkScalar C = 1; + SkScalar A = -B; + return (A * t + B) * t + C; +} + +static int winding_mono_conic(const SkConic& conic, SkScalar x, SkScalar y, int* onCurveCount) { + const SkPoint* pts = conic.fPts; SkScalar y0 = pts[0].fY; SkScalar y2 = pts[2].fY; @@ -2700,35 +2707,41 @@ static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y) { SkTSwap(y0, y2); dir = -1; } - if (y < y0 || y >= y2) { + if (y < y0 || y > y2) { return 0; } - - // bounds check on X (not required. is it faster?) -#if 0 - if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) { + if (checkOnCurve(x, y, pts[0], pts[2])) { + *onCurveCount += 1; + return 0; + } + if (y == y2) { return 0; } -#endif SkScalar roots[2]; - int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY, - 2 * (pts[1].fY - pts[0].fY), - pts[0].fY - y, - roots); + SkScalar A = pts[2].fY; + SkScalar B = pts[1].fY * conic.fW - y * conic.fW + y; + SkScalar C = pts[0].fY; + A += C - 2 * B; // A = a + c - 2*(b*w - yCept*w + yCept) + B -= C; // B = b*w - w * yCept + yCept - a + C -= y; + int n = SkFindUnitQuadRoots(A, 2 * B, C, roots); SkASSERT(n <= 1); SkScalar xt; if (0 == n) { - SkScalar mid = SkScalarAve(y0, y2); - // Need [0] and [2] if dir == 1 - // and [2] and [0] if dir == -1 - xt = y < mid ? pts[1 - dir].fX : pts[dir - 1].fX; + // zero roots are returned only when y0 == y + // Need [0] if dir == 1 + // and [2] if dir == -1 + xt = pts[1 - dir].fX; } else { SkScalar t = roots[0]; - SkScalar C = pts[0].fX; - SkScalar A = pts[2].fX - 2 * pts[1].fX + C; - SkScalar B = 2 * (pts[1].fX - C); - xt = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); + xt = conic_eval_numerator(&pts[0].fX, conic.fW, t) / conic_eval_denominator(conic.fW, t); + } + if (SkScalarNearlyEqual(xt, x)) { + if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they're start points + *onCurveCount += 1; + return 0; + } } return xt < x ? dir : 0; } @@ -2745,7 +2758,75 @@ static bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2) { } } -static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y) { +static int winding_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar weight, + int* onCurveCount) { + SkConic conic(pts, weight); + SkConic chopped[2]; + // If the data points are very large, the conic may not be monotonic but may also + // fail to chop. Then, the chopper does not split the original conic in two. + bool isMono = is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY) || !conic.chopAtYExtrema(chopped); + int w = winding_mono_conic(isMono ? conic : chopped[0], x, y, onCurveCount); + if (!isMono) { + w += winding_mono_conic(chopped[1], x, y, onCurveCount); + } + return w; +} + +static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { + SkScalar y0 = pts[0].fY; + SkScalar y2 = pts[2].fY; + + int dir = 1; + if (y0 > y2) { + SkTSwap(y0, y2); + dir = -1; + } + if (y < y0 || y > y2) { + return 0; + } + if (checkOnCurve(x, y, pts[0], pts[2])) { + *onCurveCount += 1; + return 0; + } + if (y == y2) { + return 0; + } + // bounds check on X (not required. is it faster?) +#if 0 + if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) { + return 0; + } +#endif + + SkScalar roots[2]; + int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY, + 2 * (pts[1].fY - pts[0].fY), + pts[0].fY - y, + roots); + SkASSERT(n <= 1); + SkScalar xt; + if (0 == n) { + // zero roots are returned only when y0 == y + // Need [0] if dir == 1 + // and [2] if dir == -1 + xt = pts[1 - dir].fX; + } else { + SkScalar t = roots[0]; + SkScalar C = pts[0].fX; + SkScalar A = pts[2].fX - 2 * pts[1].fX + C; + SkScalar B = 2 * (pts[1].fX - C); + xt = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); + } + if (SkScalarNearlyEqual(xt, x)) { + if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they're start points + *onCurveCount += 1; + return 0; + } + } + return xt < x ? dir : 0; +} + +static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { SkPoint dst[5]; int n = 0; @@ -2753,14 +2834,14 @@ static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y) { n = SkChopQuadAtYExtrema(pts, dst); pts = dst; } - int w = winding_mono_quad(pts, x, y); + int w = winding_mono_quad(pts, x, y, onCurveCount); if (n > 0) { - w += winding_mono_quad(&pts[2], x, y); + w += winding_mono_quad(&pts[2], x, y, onCurveCount); } return w; } -static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y) { +static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { SkScalar x0 = pts[0].fX; SkScalar y0 = pts[0].fY; SkScalar x1 = pts[1].fX; @@ -2773,19 +2854,133 @@ static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y) { SkTSwap(y0, y1); dir = -1; } - if (y < y0 || y >= y1) { + if (y < y0 || y > y1) { return 0; } + if (checkOnCurve(x, y, pts[0], pts[1])) { + *onCurveCount += 1; + return 0; + } + if (y == y1) { + return 0; + } + SkScalar cross = SkScalarMul(x1 - x0, y - pts[0].fY) - SkScalarMul(dy, x - x0); - SkScalar cross = SkScalarMul(x1 - x0, y - pts[0].fY) - - SkScalarMul(dy, x - pts[0].fX); - - if (SkScalarSignAsInt(cross) == dir) { + if (!cross) { + // zero cross means the point is on the line, and since the case where + // y of the query point is at the end point is handled above, we can be + // sure that we're on the line (excluding the end point) here + if (x != x1 || y != pts[1].fY) { + *onCurveCount += 1; + } + dir = 0; + } else if (SkScalarSignAsInt(cross) == dir) { dir = 0; } return dir; } +static void tangent_cubic(const SkPoint pts[], SkScalar x, SkScalar y, + SkTDArray* tangents) { + if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY) + && !between(pts[2].fY, y, pts[3].fY)) { + return; + } + if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX) + && !between(pts[2].fX, x, pts[3].fX)) { + return; + } + SkPoint dst[10]; + int n = SkChopCubicAtYExtrema(pts, dst); + for (int i = 0; i <= n; ++i) { + SkPoint* c = &dst[i * 3]; + SkScalar t; + SkAssertResult(SkCubicClipper::ChopMonoAtY(c, y, &t)); + SkScalar xt = eval_cubic_pts(c[0].fX, c[1].fX, c[2].fX, c[3].fX, t); + if (!SkScalarNearlyEqual(x, xt)) { + continue; + } + SkVector tangent; + SkEvalCubicAt(c, t, nullptr, &tangent, nullptr); + tangents->push(tangent); + } +} + +static void tangent_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar w, + SkTDArray* tangents) { + if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) { + return; + } + if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) { + return; + } + SkScalar roots[2]; + SkScalar A = pts[2].fY; + SkScalar B = pts[1].fY * w - y * w + y; + SkScalar C = pts[0].fY; + A += C - 2 * B; // A = a + c - 2*(b*w - yCept*w + yCept) + B -= C; // B = b*w - w * yCept + yCept - a + C -= y; + int n = SkFindUnitQuadRoots(A, 2 * B, C, roots); + for (int index = 0; index < n; ++index) { + SkScalar t = roots[index]; + SkScalar xt = conic_eval_numerator(&pts[0].fX, w, t) / conic_eval_denominator(w, t); + if (!SkScalarNearlyEqual(x, xt)) { + continue; + } + SkConic conic(pts, w); + tangents->push(conic.evalTangentAt(t)); + } +} + +static void tangent_quad(const SkPoint pts[], SkScalar x, SkScalar y, + SkTDArray* tangents) { + if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) { + return; + } + if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) { + return; + } + SkScalar roots[2]; + int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY, + 2 * (pts[1].fY - pts[0].fY), + pts[0].fY - y, + roots); + for (int index = 0; index < n; ++index) { + SkScalar t = roots[index]; + SkScalar C = pts[0].fX; + SkScalar A = pts[2].fX - 2 * pts[1].fX + C; + SkScalar B = 2 * (pts[1].fX - C); + SkScalar xt = (A * t + B) * t + C; + if (!SkScalarNearlyEqual(x, xt)) { + continue; + } + tangents->push(SkEvalQuadTangentAt(pts, t)); + } +} + +static void tangent_line(const SkPoint pts[], SkScalar x, SkScalar y, + SkTDArray* tangents) { + SkScalar y0 = pts[0].fY; + SkScalar y1 = pts[1].fY; + if (!between(y0, y, y1)) { + return; + } + SkScalar x0 = pts[0].fX; + SkScalar x1 = pts[1].fX; + if (!between(x0, x, x1)) { + return; + } + SkScalar dx = x1 - x0; + SkScalar dy = y1 - y0; + if (!SkScalarNearlyEqual((x - x0) * dy, dx * (y - y0))) { + return; + } + SkVector v; + v.set(dx, dy); + tangents->push(v); +} + static bool contains_inclusive(const SkRect& r, SkScalar x, SkScalar y) { return r.fLeft <= x && x <= r.fRight && r.fTop <= y && y <= r.fBottom; } @@ -2803,6 +2998,7 @@ bool SkPath::contains(SkScalar x, SkScalar y) const { SkPath::Iter iter(*this, true); bool done = false; int w = 0; + int onCurveCount = 0; do { SkPoint pts[4]; switch (iter.next(pts, false)) { @@ -2810,32 +3006,84 @@ bool SkPath::contains(SkScalar x, SkScalar y) const { case SkPath::kClose_Verb: break; case SkPath::kLine_Verb: - w += winding_line(pts, x, y); + w += winding_line(pts, x, y, &onCurveCount); break; case SkPath::kQuad_Verb: - w += winding_quad(pts, x, y); + w += winding_quad(pts, x, y, &onCurveCount); break; case SkPath::kConic_Verb: - SkASSERT(0); + w += winding_conic(pts, x, y, iter.conicWeight(), &onCurveCount); break; case SkPath::kCubic_Verb: - w += winding_cubic(pts, x, y); + w += winding_cubic(pts, x, y, &onCurveCount); break; case SkPath::kDone_Verb: done = true; break; } } while (!done); - - switch (this->getFillType()) { - case SkPath::kEvenOdd_FillType: - case SkPath::kInverseEvenOdd_FillType: - w &= 1; - break; - default: - break; + bool evenOddFill = SkPath::kEvenOdd_FillType == this->getFillType() + || SkPath::kInverseEvenOdd_FillType == this->getFillType(); + if (evenOddFill) { + w &= 1; } - return SkToBool(w); + if (w) { + return !isInverse; + } + if (onCurveCount <= 1) { + return SkToBool(onCurveCount) ^ isInverse; + } + if ((onCurveCount & 1) || evenOddFill) { + return SkToBool(onCurveCount & 1) ^ isInverse; + } + // If the point touches an even number of curves, and the fill is winding, check for + // coincidence. Count coincidence as places where the on curve points have identical tangents. + iter.setPath(*this, true); + done = false; + SkTDArray tangents; + do { + SkPoint pts[4]; + int oldCount = tangents.count(); + switch (iter.next(pts, false)) { + case SkPath::kMove_Verb: + case SkPath::kClose_Verb: + break; + case SkPath::kLine_Verb: + tangent_line(pts, x, y, &tangents); + break; + case SkPath::kQuad_Verb: + tangent_quad(pts, x, y, &tangents); + break; + case SkPath::kConic_Verb: + tangent_conic(pts, x, y, iter.conicWeight(), &tangents); + break; + case SkPath::kCubic_Verb: + tangent_cubic(pts, x, y, &tangents); + break; + case SkPath::kDone_Verb: + done = true; + break; + } + if (tangents.count() > oldCount) { + int last = tangents.count() - 1; + const SkVector& tangent = tangents[last]; + if (SkScalarNearlyZero(tangent.lengthSqd())) { + tangents.remove(last); + } else { + for (int index = 0; index < last; ++index) { + const SkVector& test = tangents[index]; + if (SkScalarNearlyZero(test.cross(tangent)) + && SkScalarSignAsInt(tangent.fX * test.fX) <= 0 + && SkScalarSignAsInt(tangent.fY * test.fY) <= 0) { + tangents.remove(last); + tangents.removeShuffle(index); + break; + } + } + } + } + } while (!done); + return SkToBool(tangents.count()) ^ isInverse; } int SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2, diff --git a/gfx/skia/skia/src/core/SkPathEffect.cpp b/gfx/skia/skia/src/core/SkPathEffect.cpp index 2403ffcb30c..293bb53b2c4 100644 --- a/gfx/skia/skia/src/core/SkPathEffect.cpp +++ b/gfx/skia/skia/src/core/SkPathEffect.cpp @@ -67,7 +67,11 @@ void SkPairPathEffect::toString(SkString* str) const { SkFlattenable* SkComposePathEffect::CreateProc(SkReadBuffer& buffer) { SkAutoTUnref pe0(buffer.readPathEffect()); SkAutoTUnref pe1(buffer.readPathEffect()); - return SkComposePathEffect::Create(pe0, pe1); + if (pe0 && pe1) { + return SkComposePathEffect::Create(pe0, pe1); + } else { + return nullptr; + } } bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src, @@ -100,7 +104,11 @@ void SkComposePathEffect::toString(SkString* str) const { SkFlattenable* SkSumPathEffect::CreateProc(SkReadBuffer& buffer) { SkAutoTUnref pe0(buffer.readPathEffect()); SkAutoTUnref pe1(buffer.readPathEffect()); - return SkSumPathEffect::Create(pe0, pe1); + if (pe0 && pe1) { + return SkSumPathEffect::Create(pe0, pe1); + } else { + return nullptr; + } } bool SkSumPathEffect::filterPath(SkPath* dst, const SkPath& src, diff --git a/gfx/skia/skia/src/core/SkPathMeasure.cpp b/gfx/skia/skia/src/core/SkPathMeasure.cpp index caff6df399d..eb80cf3b831 100644 --- a/gfx/skia/skia/src/core/SkPathMeasure.cpp +++ b/gfx/skia/skia/src/core/SkPathMeasure.cpp @@ -20,11 +20,20 @@ enum { kConic_SegType, }; +#ifdef SK_SUPPORT_LEGACY_PATH_MEASURE_TVALUE #define kMaxTValue 32767 +#else +#define kMaxTValue 0x3FFFFFFF +#endif static inline SkScalar tValue2Scalar(int t) { SkASSERT((unsigned)t <= kMaxTValue); +#ifdef SK_SUPPORT_LEGACY_PATH_MEASURE_TVALUE return t * 3.05185e-5f; // t / 32767 +#else + const SkScalar kMaxTReciprocal = 1.0f / kMaxTValue; + return t * kMaxTReciprocal; +#endif } SkScalar SkPathMeasure::Segment::getScalarT() const { @@ -81,6 +90,28 @@ static bool cubic_too_curvy(const SkPoint pts[4]) { SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3)); } +/* from http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/ */ +static SkScalar compute_quad_len(const SkPoint pts[3]) { + SkPoint a,b; + a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX; + a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY; + b.fX = 2 * (pts[1].fX - pts[0].fX); + b.fY = 2 * (pts[1].fY - pts[0].fY); + SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY); + SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY); + SkScalar C = b.fX * b.fX + b.fY * b.fY; + + SkScalar Sabc = 2 * SkScalarSqrt(A + B + C); + SkScalar A_2 = SkScalarSqrt(A); + SkScalar A_32 = 2 * A * A_2; + SkScalar C_2 = 2 * SkScalarSqrt(C); + SkScalar BA = B / A_2; + + return (A_32 * Sabc + A_2 * B * (Sabc - C_2) + + (4 * C * A - B * B) * SkScalarLog((2 * A_2 + BA + Sabc) / (BA + C_2))) / (4 * A_32); +} + + SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3], SkScalar distance, int mint, int maxt, int ptIndex) { if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) { @@ -200,7 +231,19 @@ void SkPathMeasure::buildSegments() { case SkPath::kQuad_Verb: { SkScalar prevD = distance; - distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex); + if (false) { + SkScalar length = compute_quad_len(pts); + if (length) { + distance += length; + Segment* seg = fSegments.append(); + seg->fDistance = distance; + seg->fPtIndex = ptIndex; + seg->fType = kQuad_SegType; + seg->fTValue = kMaxTValue; + } + } else { + distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex); + } if (distance > prevD) { fPts.append(2, pts + 1); ptIndex += 2; diff --git a/gfx/skia/skia/src/core/SkPathPriv.h b/gfx/skia/skia/src/core/SkPathPriv.h index 51a1a800947..048c926ce22 100644 --- a/gfx/skia/skia/src/core/SkPathPriv.h +++ b/gfx/skia/skia/src/core/SkPathPriv.h @@ -55,9 +55,29 @@ public: return computedDir == dir; } - static bool LastVerbIsClose(const SkPath& path) { - int count = path.countVerbs(); - return count >= 1 && path.fPathRef->verbs()[~(count - 1)] == SkPath::Verb::kClose_Verb; + static bool IsClosedSingleContour(const SkPath& path) { + int verbCount = path.countVerbs(); + if (verbCount == 0) + return false; + int moveCount = 0; + auto verbs = path.fPathRef->verbs(); + for (int i = 0; i < verbCount; i++) { + switch (verbs[~i]) { // verbs are stored backwards; we use [~i] to get the i'th verb + case SkPath::Verb::kMove_Verb: + moveCount += 1; + if (moveCount > 1) { + return false; + } + break; + case SkPath::Verb::kClose_Verb: + if (i == verbCount - 1) { + return true; + } + return false; + default: break; + } + } + return false; } static void AddGenIDChangeListener(const SkPath& path, SkPathRef::GenIDChangeListener* listener) { diff --git a/gfx/skia/skia/src/core/SkPathRef.cpp b/gfx/skia/skia/src/core/SkPathRef.cpp index fa073db3e0f..a6aa5df3722 100644 --- a/gfx/skia/skia/src/core/SkPathRef.cpp +++ b/gfx/skia/skia/src/core/SkPathRef.cpp @@ -9,6 +9,7 @@ #include "SkOncePtr.h" #include "SkPath.h" #include "SkPathRef.h" +#include ////////////////////////////////////////////////////////////////////////////// SkPathRef::Editor::Editor(SkAutoTUnref* pathRef, @@ -72,7 +73,8 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref* dst, if (*dst != &src) { (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count()); - memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * sizeof(uint8_t)); + sk_careful_memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), + src.fVerbCnt * sizeof(uint8_t)); (*dst)->fConicWeights = src.fConicWeights; } @@ -141,10 +143,18 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) { bool isRRect = (packed >> kIsRRect_SerializationShift) & 1; int32_t verbCount, pointCount, conicCount; + ptrdiff_t maxPtrDiff = std::numeric_limits::max(); if (!buffer->readU32(&(ref->fGenerationID)) || !buffer->readS32(&verbCount) || + verbCount < 0 || + static_cast(verbCount) > maxPtrDiff/sizeof(uint8_t) || !buffer->readS32(&pointCount) || - !buffer->readS32(&conicCount)) { + pointCount < 0 || + static_cast(pointCount) > maxPtrDiff/sizeof(SkPoint) || + sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCount > + static_cast(maxPtrDiff) || + !buffer->readS32(&conicCount) || + conicCount < 0) { delete ref; return nullptr; } @@ -281,8 +291,8 @@ void SkPathRef::copy(const SkPathRef& ref, SkDEBUGCODE(this->validate();) this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(), additionalReserveVerbs, additionalReservePoints); - memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * sizeof(uint8_t)); - memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); + sk_careful_memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt*sizeof(uint8_t)); + sk_careful_memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); fConicWeights = ref.fConicWeights; fBoundsIsDirty = ref.fBoundsIsDirty; if (!fBoundsIsDirty) { @@ -579,6 +589,11 @@ uint8_t SkPathRef::Iter::next(SkPoint pts[4]) { return (uint8_t) verb; } +uint8_t SkPathRef::Iter::peek() const { + const uint8_t* next = fVerbs - 1; + return next <= fVerbStop ? (uint8_t) SkPath::kDone_Verb : *next; +} + #ifdef SK_DEBUG void SkPathRef::validate() const { this->INHERITED::validate(); diff --git a/gfx/skia/skia/src/core/SkPictureFlat.h b/gfx/skia/skia/src/core/SkPictureFlat.h index 8befca0538d..4eee04fcdab 100644 --- a/gfx/skia/skia/src/core/SkPictureFlat.h +++ b/gfx/skia/skia/src/core/SkPictureFlat.h @@ -51,7 +51,7 @@ enum DrawType { RESTORE, ROTATE, SAVE, - SAVE_LAYER, + SAVE_LAYER_SAVEFLAGS_DEPRECATED, SCALE, SET_MATRIX, SKEW, @@ -75,7 +75,10 @@ enum DrawType { DRAW_IMAGE_NINE, DRAW_IMAGE_RECT, - LAST_DRAWTYPE_ENUM = DRAW_IMAGE_RECT + SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016, + SAVE_LAYER_SAVELAYERREC, + + LAST_DRAWTYPE_ENUM = SAVE_LAYER_SAVELAYERREC, }; // In the 'match' method, this constant will match any flavor of DRAW_BITMAP* @@ -93,6 +96,13 @@ enum DrawAtlasFlags { DRAW_ATLAS_HAS_CULL = 1 << 1, }; +enum SaveLayerRecFlatFlags { + SAVELAYERREC_HAS_BOUNDS = 1 << 0, + SAVELAYERREC_HAS_PAINT = 1 << 1, + SAVELAYERREC_HAS_BACKDROP = 1 << 2, + SAVELAYERREC_HAS_FLAGS = 1 << 3, +}; + /////////////////////////////////////////////////////////////////////////////// // clipparams are packed in 5 bits // doAA:1 | regionOp:4 diff --git a/gfx/skia/skia/src/core/SkPictureImageGenerator.cpp b/gfx/skia/skia/src/core/SkPictureImageGenerator.cpp index 39caa55d0cf..398c6eb5dfc 100644 --- a/gfx/skia/skia/src/core/SkPictureImageGenerator.cpp +++ b/gfx/skia/skia/src/core/SkPictureImageGenerator.cpp @@ -108,8 +108,7 @@ bool SkPictureImageGenerator::onGenerateScaledPixels(const SkISize& scaledSize, matrix.postTranslate(-SkIntToScalar(scaledOrigin.x()), -SkIntToScalar(scaledOrigin.y())); SkBitmap bitmap; - if (!bitmap.installPixels(scaledPixels.info(), scaledPixels.writable_addr(), - scaledPixels.rowBytes())) { + if (!bitmap.installPixels(scaledPixels)) { return false; } diff --git a/gfx/skia/skia/src/core/SkPicturePlayback.cpp b/gfx/skia/skia/src/core/SkPicturePlayback.cpp index b994071cbb4..4b028f714e9 100644 --- a/gfx/skia/skia/src/core/SkPicturePlayback.cpp +++ b/gfx/skia/skia/src/core/SkPicturePlayback.cpp @@ -16,6 +16,28 @@ #include "SkTDArray.h" #include "SkTypes.h" +// matches old SkCanvas::SaveFlags +enum LegacySaveFlags { + kHasAlphaLayer_LegacySaveFlags = 0x04, + kClipToLayer_LegacySaveFlags = 0x10, +}; +#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS +static_assert(kHasAlphaLayer_LegacySaveFlags == (int)SkCanvas::kHasAlphaLayer_SaveFlag, ""); +static_assert(kClipToLayer_LegacySaveFlags == (int)SkCanvas::kClipToLayer_SaveFlag, ""); +#endif + +SkCanvas::SaveLayerFlags SkCanvas::LegacySaveFlagsToSaveLayerFlags(uint32_t flags) { + uint32_t layerFlags = 0; + + if (0 == (flags & kClipToLayer_LegacySaveFlags)) { + layerFlags |= SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag; + } + if (0 == (flags & kHasAlphaLayer_LegacySaveFlags)) { + layerFlags |= kIsOpaque_SaveLayerFlag; + } + return layerFlags; +} + /* * Read the next op code and chunk size from 'reader'. The returned size * is the entire size of the chunk (including the opcode). Thus, the @@ -368,11 +390,11 @@ void SkPicturePlayback::handleOp(SkReader32* reader, 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); + /* const SkPaint* paint = */ fPictureData->getPaint(reader); + /* const SkBitmap bitmap = */ shallow_copy(fPictureData->getBitmap(reader)); + /* int left = */ reader->readInt(); + /* int top = */ reader->readInt(); + // drawSprite removed dec-2015 } break; case DRAW_TEXT: { const SkPaint& paint = *fPictureData->getPaint(reader); @@ -455,10 +477,34 @@ void SkPicturePlayback::handleOp(SkReader32* reader, } canvas->save(); break; - case SAVE_LAYER: { + case SAVE_LAYER_SAVEFLAGS_DEPRECATED: { const SkRect* boundsPtr = get_rect_ptr(reader); const SkPaint* paint = fPictureData->getPaint(reader); - canvas->saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader->readInt()); + auto flags = SkCanvas::LegacySaveFlagsToSaveLayerFlags(reader->readInt()); + canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, flags)); + } break; + case SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016: { + const SkRect* boundsPtr = get_rect_ptr(reader); + const SkPaint* paint = fPictureData->getPaint(reader); + canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, reader->readInt())); + } break; + case SAVE_LAYER_SAVELAYERREC: { + SkCanvas::SaveLayerRec rec(nullptr, nullptr, nullptr, 0); + const uint32_t flatFlags = reader->readInt(); + if (flatFlags & SAVELAYERREC_HAS_BOUNDS) { + rec.fBounds = &reader->skipT(); + } + if (flatFlags & SAVELAYERREC_HAS_PAINT) { + rec.fPaint = fPictureData->getPaint(reader); + } + if (flatFlags & SAVELAYERREC_HAS_BACKDROP) { + const SkPaint* paint = fPictureData->getPaint(reader); + rec.fBackdrop = paint->getImageFilter(); + } + if (flatFlags & SAVELAYERREC_HAS_FLAGS) { + rec.fSaveLayerFlags = reader->readInt(); + } + canvas->saveLayer(rec); } break; case SCALE: { SkScalar sx = reader->readScalar(); diff --git a/gfx/skia/skia/src/core/SkPictureRecord.cpp b/gfx/skia/skia/src/core/SkPictureRecord.cpp index 2b56b74dad8..2822a1ac164 100644 --- a/gfx/skia/skia/src/core/SkPictureRecord.cpp +++ b/gfx/skia/skia/src/core/SkPictureRecord.cpp @@ -25,12 +25,6 @@ enum { // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc. static int const kUInt32Size = 4; -static const uint32_t kSaveSize = kUInt32Size; -#ifdef SK_DEBUG -static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size; -static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect); -#endif//SK_DEBUG - SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) : INHERITED(dimensions.width(), dimensions.height()) , fRecordFlags(flags) @@ -45,93 +39,6 @@ SkPictureRecord::~SkPictureRecord() { /////////////////////////////////////////////////////////////////////////////// -#ifdef SK_DEBUG -// Return the offset of the paint inside a given op's byte stream. A zero -// return value means there is no paint (and you really shouldn't be calling -// this method) -static inline size_t get_paint_offset(DrawType op, size_t opSize) { - // These offsets are where the paint would be if the op size doesn't overflow - static const uint8_t gPaintOffsets[] = { - 0, // UNUSED - no paint - 0, // CLIP_PATH - no paint - 0, // CLIP_REGION - no paint - 0, // CLIP_RECT - no paint - 0, // CLIP_RRECT - no paint - 0, // CONCAT - no paint - 1, // DRAW_BITMAP - right after op code - 1, // DRAW_BITMAP_MATRIX - right after op code, deprecated - 1, // DRAW_BITMAP_NINE - right after op code - 1, // DRAW_BITMAP_RECT - right after op code - 0, // DRAW_CLEAR - no paint - 0, // DRAW_DATA - no paint - 1, // DRAW_OVAL - right after op code - 1, // DRAW_PAINT - right after op code - 1, // DRAW_PATH - right after op code - 0, // DRAW_PICTURE - no paint - 1, // DRAW_POINTS - right after op code - 1, // DRAW_POS_TEXT - right after op code - 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code - 1, // DRAW_POS_TEXT_H - right after op code - 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code - 1, // DRAW_RECT - right after op code - 1, // DRAW_RRECT - right after op code - 1, // DRAW_SPRITE - right after op code - 1, // DRAW_TEXT - right after op code - 1, // DRAW_TEXT_ON_PATH - right after op code - 1, // DRAW_TEXT_TOP_BOTTOM - right after op code - 1, // DRAW_VERTICES - right after op code - 0, // RESTORE - no paint - 0, // ROTATE - no paint - 0, // SAVE - no paint - 0, // SAVE_LAYER - see below - this paint's location varies - 0, // SCALE - no paint - 0, // SET_MATRIX - no paint - 0, // SKEW - no paint - 0, // TRANSLATE - no paint - 0, // NOOP - no paint - 0, // BEGIN_GROUP - no paint - 0, // COMMENT - no paint - 0, // END_GROUP - no paint - 1, // DRAWDRRECT - right after op code - 0, // PUSH_CULL - no paint - 0, // POP_CULL - no paint - 1, // DRAW_PATCH - right after op code - 1, // DRAW_PICTURE_MATRIX_PAINT - right after op code - 1, // DRAW_TEXT_BLOB- right after op code - 1, // DRAW_IMAGE - right after op code - 1, // DRAW_IMAGE_RECT_STRICT - right after op code - 1, // DRAW_ATLAS - right after op code - 1, // DRAW_IMAGE_NINE - right after op code - 1, // DRAW_IMAGE_RECT - right after op code - }; - - static_assert(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1, "need_to_be_in_sync"); - SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM); - - int overflow = 0; - if (0 != (opSize & ~MASK_24) || opSize == MASK_24) { - // This op's size overflows so an extra uint32_t will be written - // after the op code - overflow = sizeof(uint32_t); - } - - if (SAVE_LAYER == op) { - static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size; - static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect); - - if (kSaveLayerNoBoundsSize == opSize) { - return kSaveLayerNoBoundsPaintOffset + overflow; - } else { - SkASSERT(kSaveLayerWithBoundsSize == opSize); - return kSaveLayerWithBoundsPaintOffset + overflow; - } - } - - SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method - return gPaintOffsets[op] * sizeof(uint32_t) + overflow; -} -#endif//SK_DEBUG - void SkPictureRecord::willSave() { // record the offset to us, making it non-positive to distinguish a save // from a clip entry. @@ -145,20 +52,19 @@ void SkPictureRecord::recordSave() { fContentInfo.onSave(); // op only - size_t size = kSaveSize; + size_t size = sizeof(kUInt32Size); size_t initialOffset = this->addDraw(SAVE, &size); this->validate(initialOffset, size); } -SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds, - const SkPaint* paint, SaveFlags flags) { +SkCanvas::SaveLayerStrategy SkPictureRecord::getSaveLayerStrategy(const SaveLayerRec& rec) { // record the offset to us, making it non-positive to distinguish a save // from a clip entry. fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); - this->recordSaveLayer(bounds, paint, flags); + this->recordSaveLayer(rec); - this->INHERITED::willSaveLayer(bounds, paint, flags); + (void)this->INHERITED::getSaveLayerStrategy(rec); /* No need for a (potentially very big) layer which we don't actually need at this time (and may not be able to afford since during record our clip starts out the size of the picture, which is often much larger @@ -167,26 +73,47 @@ SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds, return kNoLayer_SaveLayerStrategy; } -void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint, - SaveFlags flags) { +void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) { fContentInfo.onSaveLayer(); - // op + bool for 'bounds' + // op + flatflags size_t size = 2 * kUInt32Size; - if (bounds) { - size += sizeof(*bounds); // + rect + uint32_t flatFlags = 0; + + if (rec.fBounds) { + flatFlags |= SAVELAYERREC_HAS_BOUNDS; + size += sizeof(*rec.fBounds); + } + if (rec.fPaint) { + flatFlags |= SAVELAYERREC_HAS_PAINT; + size += sizeof(uint32_t); // index + } + if (rec.fBackdrop) { + flatFlags |= SAVELAYERREC_HAS_BACKDROP; + size += sizeof(uint32_t); // (paint) index + } + if (rec.fSaveLayerFlags) { + flatFlags |= SAVELAYERREC_HAS_FLAGS; + size += sizeof(uint32_t); } - // + paint index + flags - size += 2 * kUInt32Size; - - SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size); - - size_t initialOffset = this->addDraw(SAVE_LAYER, &size); - this->addRectPtr(bounds); - SkASSERT(initialOffset+get_paint_offset(SAVE_LAYER, size) == fWriter.bytesWritten()); - this->addPaintPtr(paint); - this->addInt(flags); + const size_t initialOffset = this->addDraw(SAVE_LAYER_SAVELAYERREC, &size); + this->addInt(flatFlags); + if (flatFlags & SAVELAYERREC_HAS_BOUNDS) { + this->addRect(*rec.fBounds); + } + if (flatFlags & SAVELAYERREC_HAS_PAINT) { + this->addPaintPtr(rec.fPaint); + } + if (flatFlags & SAVELAYERREC_HAS_BACKDROP) { + // overkill, but we didn't already track single flattenables, so using a paint for that + SkPaint paint; + paint.setImageFilter(const_cast(rec.fBackdrop)); + this->addPaint(paint); + } + if (flatFlags & SAVELAYERREC_HAS_FLAGS) { + this->addInt(rec.fSaveLayerFlags); + } this->validate(initialOffset, size); } @@ -321,7 +248,9 @@ void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t // assert that the final offset value points to a save verb uint32_t opSize; DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize); - SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp); + SkASSERT(SAVE_LAYER_SAVEFLAGS_DEPRECATED != drawOp); + SkASSERT(SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016 != drawOp); + SkASSERT(SAVE == drawOp || SAVE_LAYER_SAVELAYERREC == drawOp); } #endif } @@ -459,7 +388,6 @@ void SkPictureRecord::onDrawPaint(const SkPaint& paint) { // op + paint index size_t size = 2 * kUInt32Size; size_t initialOffset = this->addDraw(DRAW_PAINT, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_PAINT, size) == fWriter.bytesWritten()); this->addPaint(paint); this->validate(initialOffset, size); } @@ -471,7 +399,6 @@ void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint p // op + paint index + mode + count + point data size_t size = 4 * kUInt32Size + count * sizeof(SkPoint); size_t initialOffset = this->addDraw(DRAW_POINTS, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_POINTS, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addInt(mode); @@ -484,7 +411,6 @@ void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) { // op + paint index + rect size_t size = 2 * kUInt32Size + sizeof(oval); size_t initialOffset = this->addDraw(DRAW_OVAL, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_OVAL, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addRect(oval); this->validate(initialOffset, size); @@ -494,7 +420,6 @@ void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) { // op + paint index + rect size_t size = 2 * kUInt32Size + sizeof(rect); size_t initialOffset = this->addDraw(DRAW_RECT, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_RECT, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addRect(rect); this->validate(initialOffset, size); @@ -504,7 +429,6 @@ void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { // op + paint index + rrect size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory; size_t initialOffset = this->addDraw(DRAW_RRECT, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_RRECT, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addRRect(rrect); this->validate(initialOffset, size); @@ -515,7 +439,6 @@ void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, // op + paint index + rrects size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2; size_t initialOffset = this->addDraw(DRAW_DRRECT, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_DRRECT, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addRRect(outer); this->addRRect(inner); @@ -528,7 +451,6 @@ void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) { // op + paint index + path index size_t size = 3 * kUInt32Size; size_t initialOffset = this->addDraw(DRAW_PATH, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_PATH, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addPath(path); this->validate(initialOffset, size); @@ -539,7 +461,6 @@ void SkPictureRecord::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScal // op + paint index + bitmap index + left + top size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); size_t initialOffset = this->addDraw(DRAW_BITMAP, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP, size) == fWriter.bytesWritten()); this->addPaintPtr(paint); this->addBitmap(bitmap); this->addScalar(left); @@ -557,7 +478,6 @@ void SkPictureRecord::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src size += sizeof(dst); // + rect size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_RECT, size) == fWriter.bytesWritten()); this->addPaintPtr(paint); this->addBitmap(bitmap); this->addRectPtr(src); // may be null @@ -571,7 +491,6 @@ void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, // op + paint_index + image_index + x + y size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); size_t initialOffset = this->addDraw(DRAW_IMAGE, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE, size) == fWriter.bytesWritten()); this->addPaintPtr(paint); this->addImage(image); this->addScalar(x); @@ -589,8 +508,6 @@ void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, c size += sizeof(dst); // + rect size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE_RECT, size) - == fWriter.bytesWritten()); this->addPaintPtr(paint); this->addImage(image); this->addRectPtr(src); // may be null @@ -605,7 +522,6 @@ void SkPictureRecord::onDrawImageNine(const SkImage* img, const SkIRect& center, size_t size = 3 * kUInt32Size + sizeof(SkIRect) + sizeof(SkRect); size_t initialOffset = this->addDraw(DRAW_IMAGE_NINE, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE_NINE, size) == fWriter.bytesWritten()); this->addPaintPtr(paint); this->addImage(img); this->addIRect(center); @@ -618,7 +534,6 @@ void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& ce // op + paint index + bitmap id + center + dst rect size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten()); this->addPaintPtr(paint); this->addBitmap(bitmap); this->addIRect(center); @@ -626,19 +541,6 @@ void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& ce this->validate(initialOffset, size); } -void SkPictureRecord::onDrawSprite(const SkBitmap& bitmap, int left, int top, - const SkPaint* paint) { - // op + paint index + bitmap index + left + top - size_t size = 5 * kUInt32Size; - size_t initialOffset = this->addDraw(DRAW_SPRITE, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_SPRITE, size) == fWriter.bytesWritten()); - this->addPaintPtr(paint); - this->addBitmap(bitmap); - this->addInt(left); - this->addInt(top); - this->validate(initialOffset, size); -} - void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { // op + paint index + length + 'length' worth of chars + x + y @@ -646,7 +548,6 @@ void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x DrawType op = DRAW_TEXT; size_t initialOffset = this->addDraw(op, &size); - SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addText(text, byteLength); this->addScalar(x); @@ -664,7 +565,6 @@ void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const S DrawType op = DRAW_POS_TEXT; size_t initialOffset = this->addDraw(op, &size); - SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addText(text, byteLength); this->addInt(points); @@ -696,7 +596,6 @@ void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, cons const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(nullptr); size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addText(text, byteLength); this->addPath(path); @@ -710,7 +609,6 @@ void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScala // op + paint index + blob index + x/y size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size); - SkASSERT(initialOffset + get_paint_offset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addTextBlob(blob); @@ -733,8 +631,6 @@ void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* ma const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); size += m.writeToMemory(nullptr) + kUInt32Size; // matrix + paint initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size); - SkASSERT(initialOffset + get_paint_offset(DRAW_PICTURE_MATRIX_PAINT, size) - == fWriter.bytesWritten()); this->addPaintPtr(paint); this->addMatrix(m); this->addPicture(picture); @@ -781,7 +677,6 @@ void SkPictureRecord::onDrawVertices(VertexMode vmode, int vertexCount, } size_t initialOffset = this->addDraw(DRAW_VERTICES, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_VERTICES, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addInt(flags); this->addInt(vmode); @@ -828,7 +723,6 @@ void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors } size_t initialOffset = this->addDraw(DRAW_PATCH, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_PATCH, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addPatch(cubics); this->addInt(flag); @@ -865,7 +759,6 @@ void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], } size_t initialOffset = this->addDraw(DRAW_ATLAS, &size); - SkASSERT(initialOffset+get_paint_offset(DRAW_ATLAS, size) == fWriter.bytesWritten()); this->addPaintPtr(paint); this->addImage(atlas); this->addInt(flags); diff --git a/gfx/skia/skia/src/core/SkPictureRecord.h b/gfx/skia/skia/src/core/SkPictureRecord.h index 7e21fab1120..2e1e62a0212 100644 --- a/gfx/skia/skia/src/core/SkPictureRecord.h +++ b/gfx/skia/skia/src/core/SkPictureRecord.h @@ -153,7 +153,7 @@ protected: bool onPeekPixels(SkPixmap*) override { return false; } void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; void willRestore() override; void didConcat(const SkMatrix&) override; @@ -192,7 +192,6 @@ protected: const SkPaint*) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; void onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, @@ -219,7 +218,7 @@ protected: size_t recordClipPath(int pathID, SkRegion::Op op, bool doAA); size_t recordClipRegion(const SkRegion& region, SkRegion::Op op); void recordSave(); - void recordSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags); + void recordSaveLayer(const SaveLayerRec&); void recordRestore(bool fillInSkips = true); private: diff --git a/gfx/skia/skia/src/core/SkPictureShader.cpp b/gfx/skia/skia/src/core/SkPictureShader.cpp index 92e61573438..c803f7d878c 100644 --- a/gfx/skia/skia/src/core/SkPictureShader.cpp +++ b/gfx/skia/skia/src/core/SkPictureShader.cpp @@ -290,11 +290,6 @@ void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor ds fBitmapShaderContext->shadeSpan(x, y, dstC, count); } -void SkPictureShader::PictureShaderContext::shadeSpan16(int x, int y, uint16_t dstC[], int count) { - SkASSERT(fBitmapShaderContext); - fBitmapShaderContext->shadeSpan16(x, y, dstC, count); -} - #ifndef SK_IGNORE_TO_STRING void SkPictureShader::toString(SkString* str) const { static const char* gTileModeName[SkShader::kTileModeCount] = { diff --git a/gfx/skia/skia/src/core/SkPictureShader.h b/gfx/skia/skia/src/core/SkPictureShader.h index 2657bab74c1..02fc87f024a 100644 --- a/gfx/skia/skia/src/core/SkPictureShader.h +++ b/gfx/skia/skia/src/core/SkPictureShader.h @@ -62,7 +62,6 @@ private: ShadeProc asAShadeProc(void** ctx) override; void shadeSpan(int x, int y, SkPMColor dstC[], int count) override; - void shadeSpan16(int x, int y, uint16_t dstC[], int count) override; private: PictureShaderContext(const SkPictureShader&, const ContextRec&, SkShader* bitmapShader); diff --git a/gfx/skia/skia/src/core/SkPixelRef.cpp b/gfx/skia/skia/src/core/SkPixelRef.cpp index d7117617f62..0825760ccd5 100644 --- a/gfx/skia/skia/src/core/SkPixelRef.cpp +++ b/gfx/skia/skia/src/core/SkPixelRef.cpp @@ -307,13 +307,13 @@ void SkPixelRef::restoreMutability() { fMutability = kMutable; } -bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) { - return this->onReadPixels(dst, subset); +bool SkPixelRef::readPixels(SkBitmap* dst, SkColorType ct, const SkIRect* subset) { + return this->onReadPixels(dst, ct, subset); } /////////////////////////////////////////////////////////////////////////////////////////////////// -bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { +bool SkPixelRef::onReadPixels(SkBitmap* dst, SkColorType, const SkIRect* subset) { return false; } diff --git a/gfx/skia/skia/src/core/SkPixmap.cpp b/gfx/skia/skia/src/core/SkPixmap.cpp index 718be88c57a..943287bad30 100644 --- a/gfx/skia/skia/src/core/SkPixmap.cpp +++ b/gfx/skia/skia/src/core/SkPixmap.cpp @@ -163,9 +163,9 @@ bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const { // make rgb premultiplied if (255 != a) { - r = SkAlphaMul(r, a); - g = SkAlphaMul(g, a); - b = SkAlphaMul(b, a); + r = SkMulDiv255Round(r, a); + g = SkMulDiv255Round(g, a); + b = SkMulDiv255Round(b, a); } if (kARGB_4444_SkColorType == this->colorType()) { @@ -186,13 +186,14 @@ bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const { uint32_t* p = this->writable_addr32(area.fLeft, area.fTop); if (255 != a && kPremul_SkAlphaType == this->alphaType()) { - r = SkAlphaMul(r, a); - g = SkAlphaMul(g, a); - b = SkAlphaMul(b, a); + r = SkMulDiv255Round(r, a); + g = SkMulDiv255Round(g, a); + b = SkMulDiv255Round(b, a); } - uint32_t v = kRGBA_8888_SkColorType == this->colorType() ? - SkPackARGB_as_RGBA(a, r, g, b) : SkPackARGB_as_BGRA(a, r, g, b); - + uint32_t v = kRGBA_8888_SkColorType == this->colorType() + ? SkPackARGB_as_RGBA(a, r, g, b) + : SkPackARGB_as_BGRA(a, r, g, b); + while (--height >= 0) { sk_memset32(p, v, width); p = (uint32_t*)((char*)p + rowBytes); @@ -222,9 +223,7 @@ bool SkPixmap::scalePixels(const SkPixmap& dst, SkFilterQuality quality) const { } SkBitmap bitmap; - // we will only ready from this pixmap, but the bitmap setting takes void*, hence the cast - void* readOnlyAddr = const_cast(this->addr()); - if (!bitmap.installPixels(this->info(), readOnlyAddr, this->rowBytes())) { + if (!bitmap.installPixels(*this)) { return false; } bitmap.setIsVolatile(true); // so we don't try to cache it diff --git a/gfx/skia/skia/src/core/SkPx.h b/gfx/skia/skia/src/core/SkPx.h deleted file mode 100644 index 62ec598cd69..00000000000 --- a/gfx/skia/skia/src/core/SkPx.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkPx_DEFINED -#define SkPx_DEFINED - -#include "SkTypes.h" -#include "SkColorPriv.h" - -// We'll include one of src/opts/SkPx_{sse,neon,none}.h to define a type SkPx. -// -// SkPx represents up to SkPx::N 8888 pixels. It's agnostic to whether these -// are SkColors or SkPMColors; it only assumes that alpha is the high byte. -static_assert(SK_A32_SHIFT == 24, "For both SkColor and SkPMColor, alpha is always the high byte."); -// -// SkPx::Alpha represents up to SkPx::N 8-bit values, usually coverage or alpha. -// SkPx::Wide represents up to SkPx::N pixels with 16 bits per component. -// -// SkPx supports the following methods: -// static SkPx Dup(uint32_t); -// static SkPx Load(const uint32_t*); -// static SkPx Load(const uint32_t*, int n); // where 0 a -// Wide widenLo() const; // argb -> 0a0r0g0b -// Wide widenHi() const; // argb -> a0r0g0b0 -// Wide widenLoHi() const; // argb -> aarrggbb -// -// SkPx operator+(const SkPx&) const; -// SkPx operator-(const SkPx&) const; -// SkPx saturatedAdd(const SkPx&) const; -// -// Wide operator*(const Alpha&) const; // argb * A -> (a*A)(r*A)(g*A)(b*A) -// -// // Fast approximate (px*a+127)/255. -// // Never off by more than 1, and always correct when px or a is 0 or 255. -// // We use the approximation (px*a+px)/256. -// SkPx approxMulDiv255(const Alpha&) const; -// -// SkPx addAlpha(const Alpha&) const; // argb + A -> (a+A)rgb -// -// SkPx::Alpha supports the following methods: -// static Alpha Dup(uint8_t); -// static Alpha Load(const uint8_t*); -// static Alpha Load(const uint8_t*, int n); // where 0 255-a -// -// SkPx::Wide supports the following methods: -// Wide operator+(const Wide&); -// Wide operator-(const Wide&); -// Wide shl(); -// Wide shr(); -// -// // Return the high byte of each component of (*this + o.widenLo()). -// SkPx addNarrowHi(const SkPx& o); -// -// Methods left unwritten, but certainly to come: -// SkPx SkPx::operator<(const SkPx&) const; -// SkPx SkPx::thenElse(const SkPx& then, const SkPx& else) const; -// Wide Wide::operator<(const Wide&) const; -// Wide Wide::thenElse(const Wide& then, const Wide& else) const; -// -// SkPx Wide::div255() const; // Rounds, think (*this + 127) / 255. -// -// The different implementations of SkPx have complete freedom to choose -// SkPx::N and how they represent SkPx, SkPx::Alpha, and SkPx::Wide. -// -// All observable math must remain identical. - -#if defined(SKNX_NO_SIMD) - #include "../opts/SkPx_none.h" -#else - #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 - #include "../opts/SkPx_sse.h" - #elif defined(SK_ARM_HAS_NEON) - #include "../opts/SkPx_neon.h" - #else - #include "../opts/SkPx_none.h" - #endif -#endif - -#endif//SkPx_DEFINED diff --git a/gfx/skia/skia/src/core/SkRRect.cpp b/gfx/skia/skia/src/core/SkRRect.cpp index ad62e5bbae8..ca4fd561523 100644 --- a/gfx/skia/skia/src/core/SkRRect.cpp +++ b/gfx/skia/skia/src/core/SkRRect.cpp @@ -5,8 +5,10 @@ * found in the LICENSE file. */ +#include #include "SkRRect.h" #include "SkMatrix.h" +#include "SkScaleToSides.h" /////////////////////////////////////////////////////////////////////////////// @@ -109,28 +111,6 @@ void SkRRect::setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad SkDEBUGCODE(this->validate();) } -/* - * TODO: clean this guy up and possibly add to SkScalar.h - */ -static inline SkScalar SkScalarDecULP(SkScalar value) { -#if SK_SCALAR_IS_FLOAT - return SkBits2Float(SkFloat2Bits(value) - 1); -#else - #error "need impl for doubles" -#endif -} - - /** - * We need all combinations of predicates to be true to have a "safe" radius value. - */ -static SkScalar clamp_radius_check_predicates(SkScalar rad, SkScalar min, SkScalar max) { - SkASSERT(min < max); - if (rad > max - min || min + rad > max || max - rad < min) { - rad = SkScalarDecULP(rad); - } - return rad; -} - // These parameters intentionally double. Apropos crbug.com/463920, if one of the // radii is huge while the other is small, single precision math can completely // miss the fact that a scale is required. @@ -190,29 +170,21 @@ void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { // If f < 1, then all corner radii are reduced by multiplying them by f." double scale = 1.0; - scale = compute_min_scale(fRadii[0].fX, fRadii[1].fX, fRect.width(), scale); - scale = compute_min_scale(fRadii[1].fY, fRadii[2].fY, fRect.height(), scale); - scale = compute_min_scale(fRadii[2].fX, fRadii[3].fX, fRect.width(), scale); - scale = compute_min_scale(fRadii[3].fY, fRadii[0].fY, fRect.height(), scale); + // The sides of the rectangle may be larger than a float. + double width = (double)fRect.fRight - (double)fRect.fLeft; + double height = (double)fRect.fBottom - (double)fRect.fTop; + scale = compute_min_scale(fRadii[0].fX, fRadii[1].fX, width, scale); + scale = compute_min_scale(fRadii[1].fY, fRadii[2].fY, height, scale); + scale = compute_min_scale(fRadii[2].fX, fRadii[3].fX, width, scale); + scale = compute_min_scale(fRadii[3].fY, fRadii[0].fY, height, scale); if (scale < 1.0) { - for (int i = 0; i < 4; ++i) { - fRadii[i].fX *= scale; - fRadii[i].fY *= scale; - } + ScaleToSides::AdjustRadii(width, scale, &fRadii[0].fX, &fRadii[1].fX); + ScaleToSides::AdjustRadii(height, scale, &fRadii[1].fY, &fRadii[2].fY); + ScaleToSides::AdjustRadii(width, scale, &fRadii[2].fX, &fRadii[3].fX); + ScaleToSides::AdjustRadii(height, scale, &fRadii[3].fY, &fRadii[0].fY); } - // https://bug.skia.org/3239 -- its possible that we can hit the following inconsistency: - // rad == bounds.bottom - bounds.top - // bounds.bottom - radius < bounds.top - // YIKES - // We need to detect and "fix" this now, otherwise we can have the following wackiness: - // path.addRRect(rrect); - // rrect.rect() != path.getBounds() - for (int i = 0; i < 4; ++i) { - fRadii[i].fX = clamp_radius_check_predicates(fRadii[i].fX, fRect.fLeft, fRect.fRight); - fRadii[i].fY = clamp_radius_check_predicates(fRadii[i].fY, fRect.fTop, fRect.fBottom); - } // At this point we're either oval, simple, or complex (not empty or rect). this->computeType(); diff --git a/gfx/skia/skia/src/core/SkRWBuffer.cpp b/gfx/skia/skia/src/core/SkRWBuffer.cpp index e9147dc684f..0784378d99a 100644 --- a/gfx/skia/skia/src/core/SkRWBuffer.cpp +++ b/gfx/skia/skia/src/core/SkRWBuffer.cpp @@ -150,6 +150,9 @@ const void* SkROBuffer::Iter::data() const { } size_t SkROBuffer::Iter::size() const { + if (!fBlock) { + return 0; + } return SkTMin(fBlock->fUsed, fRemaining); } diff --git a/gfx/skia/skia/src/core/SkRasterizer.cpp b/gfx/skia/skia/src/core/SkRasterizer.cpp index 87b9caa2423..6a3ea106781 100644 --- a/gfx/skia/skia/src/core/SkRasterizer.cpp +++ b/gfx/skia/skia/src/core/SkRasterizer.cpp @@ -23,7 +23,6 @@ bool SkRasterizer::rasterize(const SkPath& fillPath, const SkMatrix& matrix, srcM.fFormat = SkMask::kA8_Format; srcM.fBounds.set(0, 0, 1, 1); - srcM.fImage = nullptr; if (!filter->filterMask(&dstM, srcM, matrix, &margin)) { return false; } diff --git a/gfx/skia/skia/src/core/SkRecord.cpp b/gfx/skia/skia/src/core/SkRecord.cpp index 2e03e993b82..ca0a8cdde6a 100644 --- a/gfx/skia/skia/src/core/SkRecord.cpp +++ b/gfx/skia/skia/src/core/SkRecord.cpp @@ -6,7 +6,6 @@ */ #include "SkRecord.h" -#include SkRecord::~SkRecord() { Destroyer destroyer; diff --git a/gfx/skia/skia/src/core/SkRecord.h b/gfx/skia/skia/src/core/SkRecord.h index 8901d62e919..866d1837ad5 100644 --- a/gfx/skia/skia/src/core/SkRecord.h +++ b/gfx/skia/skia/src/core/SkRecord.h @@ -138,13 +138,13 @@ private: }; template - SK_WHEN(skstd::is_empty::value, T*) allocCommand() { + SK_WHEN(std::is_empty::value, T*) allocCommand() { static T singleton = {}; return &singleton; } template - SK_WHEN(!skstd::is_empty::value, T*) allocCommand() { return this->alloc(); } + SK_WHEN(!std::is_empty::value, T*) allocCommand() { return this->alloc(); } void grow(); diff --git a/gfx/skia/skia/src/core/SkRecordDraw.cpp b/gfx/skia/skia/src/core/SkRecordDraw.cpp index 4847273f52a..5ca9517d3f8 100644 --- a/gfx/skia/skia/src/core/SkRecordDraw.cpp +++ b/gfx/skia/skia/src/core/SkRecordDraw.cpp @@ -78,7 +78,7 @@ template <> void Draw::draw(const NoOp&) {} #define DRAW(T, call) template <> void Draw::draw(const T& r) { fCanvas->call; } DRAW(Restore, restore()); DRAW(Save, save()); -DRAW(SaveLayer, saveLayer(r.bounds, r.paint, r.flags)); +DRAW(SaveLayer, saveLayer(SkCanvas::SaveLayerRec(r.bounds, r.paint, r.backdrop, r.saveLayerFlags))); DRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix))); DRAW(Concat, concat(r.matrix)); @@ -111,7 +111,6 @@ DRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint)); DRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint)); DRAW(DrawRRect, drawRRect(r.rrect, r.paint)); DRAW(DrawRect, drawRect(r.rect, r.paint)); -DRAW(DrawSprite, drawSprite(r.bitmap.shallowCopy(), r.left, r.top, r.paint)); DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint)); DRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint)); DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.paint)); @@ -221,6 +220,7 @@ private: int controlOps; // Number of control ops in this Save block, including the Save. Bounds bounds; // Bounds of everything in the block. const SkPaint* paint; // Unowned. If set, adjusts the bounds of all ops in this block. + SkMatrix ctm; }; // Only Restore, SetMatrix, and Concat change the CTM. @@ -301,6 +301,7 @@ private: sb.bounds = PaintMayAffectTransparentBlack(paint) ? fCurrentClipBounds : Bounds::MakeEmpty(); sb.paint = paint; + sb.ctm = this->fCTM; fSaveStack.push(sb); this->pushControl(); @@ -387,14 +388,6 @@ private: Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; } Bounds bounds(const NoOp&) const { return Bounds::MakeEmpty(); } // NoOps don't draw. - Bounds bounds(const DrawSprite& op) const { // Ignores the matrix, but respects the clip. - SkRect rect = Bounds::MakeXYWH(op.left, op.top, op.bitmap.width(), op.bitmap.height()); - if (!rect.intersect(fCurrentClipBounds)) { - return Bounds::MakeEmpty(); - } - return rect; - } - Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); } Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval, &op.paint); } Bounds bounds(const DrawRRect& op) const { @@ -563,9 +556,15 @@ private: bool adjustForSaveLayerPaints(SkRect* rect, int savesToIgnore = 0) const { for (int i = fSaveStack.count() - 1 - savesToIgnore; i >= 0; i--) { + SkMatrix inverse; + if (!fSaveStack[i].ctm.invert(&inverse)) { + return false; + } + inverse.mapRect(rect); if (!AdjustForPaint(fSaveStack[i].paint, rect)) { return false; } + fSaveStack[i].ctm.mapRect(rect); } return true; } @@ -693,7 +692,8 @@ private: // Store 'saveLayer ops from enclosing picture' + drawPict op + 'ops from sub-picture' dst.fKeySize = fSaveLayerOpStack.count() + src.fKeySize + 1; dst.fKey = new int[dst.fKeySize]; - memcpy(dst.fKey, fSaveLayerOpStack.begin(), fSaveLayerOpStack.count() * sizeof(int)); + sk_careful_memcpy(dst.fKey, fSaveLayerOpStack.begin(), + fSaveLayerOpStack.count() * sizeof(int)); dst.fKey[fSaveLayerOpStack.count()] = fFillBounds.currentOp(); memcpy(&dst.fKey[fSaveLayerOpStack.count()+1], src.fKey, src.fKeySize * sizeof(int)); } diff --git a/gfx/skia/skia/src/core/SkRecordOpts.cpp b/gfx/skia/skia/src/core/SkRecordOpts.cpp index d1520adf561..0121ea54fcc 100644 --- a/gfx/skia/skia/src/core/SkRecordOpts.cpp +++ b/gfx/skia/skia/src/core/SkRecordOpts.cpp @@ -177,6 +177,11 @@ struct SaveLayerDrawRestoreNooper { typedef Pattern, IsDraw, Is> Match; bool onMatch(SkRecord* record, Match* match, int begin, int end) { + if (match->first()->backdrop) { + // can't throw away the layer if we have a backdrop + return false; + } + // A SaveLayer's bounds field is just a hint, so we should be free to ignore it. SkPaint* layerPaint = match->first()->paint; if (nullptr == layerPaint) { @@ -224,6 +229,11 @@ struct SvgOpacityAndFilterLayerMergePass { Is, Is, Is> Match; bool onMatch(SkRecord* record, Match* match, int begin, int end) { + if (match->first()->backdrop) { + // can't throw away the layer if we have a backdrop + return false; + } + SkPaint* opacityPaint = match->first()->paint; if (nullptr == opacityPaint) { // There wasn't really any point to this SaveLayer at all. diff --git a/gfx/skia/skia/src/core/SkRecorder.cpp b/gfx/skia/skia/src/core/SkRecorder.cpp index d90b2c025ac..01c28dfc2b4 100644 --- a/gfx/skia/skia/src/core/SkRecorder.cpp +++ b/gfx/skia/skia/src/core/SkRecorder.cpp @@ -240,10 +240,6 @@ void SkRecorder::onDrawImageNine(const SkImage* image, const SkIRect& center, APPEND(DrawImageNine, this->copy(paint), image, center, dst); } -void SkRecorder::onDrawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) { - APPEND(DrawSprite, this->copy(paint), bitmap, left, top); -} - void SkRecorder::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { APPEND(DrawText, @@ -340,10 +336,9 @@ void SkRecorder::willSave() { APPEND(Save); } -SkCanvas::SaveLayerStrategy SkRecorder::willSaveLayer(const SkRect* bounds, - const SkPaint* paint, - SkCanvas::SaveFlags flags) { - APPEND(SaveLayer, this->copy(bounds), this->copy(paint), flags); +SkCanvas::SaveLayerStrategy SkRecorder::getSaveLayerStrategy(const SaveLayerRec& rec) { + APPEND(SaveLayer, + this->copy(rec.fBounds), this->copy(rec.fPaint), rec.fBackdrop, rec.fSaveLayerFlags); return SkCanvas::kNoLayer_SaveLayerStrategy; } diff --git a/gfx/skia/skia/src/core/SkRecorder.h b/gfx/skia/skia/src/core/SkRecorder.h index 92197a0a3c6..cd5bc8ad04e 100644 --- a/gfx/skia/skia/src/core/SkRecorder.h +++ b/gfx/skia/skia/src/core/SkRecorder.h @@ -54,7 +54,7 @@ public: void forgetRecord(); void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SkCanvas::SaveFlags) override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; void willRestore() override {} void didRestore() override; @@ -106,7 +106,6 @@ public: const SkPaint*) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; void onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, diff --git a/gfx/skia/skia/src/core/SkRemote.cpp b/gfx/skia/skia/src/core/SkRemote.cpp index 1209be014c6..22185cddb06 100644 --- a/gfx/skia/skia/src/core/SkRemote.cpp +++ b/gfx/skia/skia/src/core/SkRemote.cpp @@ -163,18 +163,17 @@ namespace SkRemote { void willSave() override { fEncoder-> save(); } void didRestore() override { fEncoder->restore(); } - SaveLayerStrategy willSaveLayer(const SkRect* bounds, - const SkPaint* paint, - SaveFlags flags) override { + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override { SkPath path; - if (bounds) { - path.addRect(*bounds); + if (rec.fBounds) { + path.addRect(*rec.fBounds); } const SkPaint defaultPaint; + const SkPaint* paint = rec.fPaint; if (!paint) { paint = &defaultPaint; } - fEncoder->saveLayer(this->id(path), this->commonIDs(*paint), flags); + fEncoder->saveLayer(this->id(path), this->commonIDs(*paint), rec.fSaveLayerFlags); return kNoLayer_SaveLayerStrategy; } @@ -500,11 +499,13 @@ namespace SkRemote { void save() override { fCanvas->save(); } void restore() override { fCanvas->restore(); } - void saveLayer(ID bounds, CommonIDs common, SkCanvas::SaveFlags flags) override { + void saveLayer(ID bounds, CommonIDs common, SkCanvas::SaveLayerFlags flags) override { SkPaint paint; this->applyCommon(common, &paint); SkRect rect; - fCanvas->saveLayer(fPath.find(bounds).isRect(&rect) ? &rect : nullptr, &paint, flags); + + fCanvas->saveLayer({ fPath.find(bounds).isRect(&rect) ? &rect : nullptr, + &paint, flags }); } void setMatrix(ID matrix) override { fCanvas->setMatrix(fMatrix.find(matrix)); } @@ -684,7 +685,7 @@ namespace SkRemote { void save() override { fWrapped-> save(); } void restore() override { fWrapped->restore(); } - void saveLayer(ID bounds, CommonIDs common, SkCanvas::SaveFlags flags) override { + void saveLayer(ID bounds, CommonIDs common, SkCanvas::SaveLayerFlags flags) override { fWrapped->saveLayer(bounds, common, flags); } diff --git a/gfx/skia/skia/src/core/SkRemote.h b/gfx/skia/skia/src/core/SkRemote.h index 924e63e220c..a1b1405b211 100644 --- a/gfx/skia/skia/src/core/SkRemote.h +++ b/gfx/skia/skia/src/core/SkRemote.h @@ -91,7 +91,7 @@ namespace SkRemote { virtual void save() = 0; virtual void restore() = 0; - virtual void saveLayer(ID bounds, CommonIDs, SkCanvas::SaveFlags) = 0; + virtual void saveLayer(ID bounds, CommonIDs, uint32_t saveLayerFlags) = 0; virtual void setMatrix(ID matrix) = 0; diff --git a/gfx/skia/skia/src/core/SkScaleToSides.h b/gfx/skia/skia/src/core/SkScaleToSides.h new file mode 100644 index 00000000000..77637a3ac2c --- /dev/null +++ b/gfx/skia/skia/src/core/SkScaleToSides.h @@ -0,0 +1,61 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkScaleToSides_DEFINED +#define SkScaleToSides_DEFINED + +#include +#include "SkScalar.h" +#include "SkTypes.h" + +class ScaleToSides { +public: + // This code assumes that a and b fit in in a float, and therefore the resulting smaller value + // of a and b will fit in a float. The side of the rectangle may be larger than a float. + // Scale must be less than or equal to the ratio limit / (*a + *b). + // This code assumes that NaN and Inf are never passed in. + static void AdjustRadii(double limit, double scale, SkScalar* a, SkScalar* b) { + SkASSERTF(scale < 1.0 && scale > 0.0, "scale: %g", scale); + + *a = (float)((double)*a * scale); + *b = (float)((double)*b * scale); + + // This check is conservative. (double)*a + (double)*b >= (double)(*a + *b) + if ((double)*a + (double)*b > limit) { + float* minRadius = a; + float* maxRadius = b; + + // Force minRadius to be the smaller of the two. + if (*minRadius > *maxRadius) { + SkTSwap(minRadius, maxRadius); + } + + // newMinRadius must be float in order to give the actual value of the radius. + // The newMinRadius will always be smaller than limit. The largest that minRadius can be + // is 1/2 the ratio of minRadius : (minRadius + maxRadius), therefore in the resulting + // division, minRadius can be no larger than 1/2 limit + ULP. + float newMinRadius = *minRadius; + + // Because newMaxRadius is the result of a double to float conversion, it can be larger + // than limit, but only by one ULP. + float newMaxRadius = (float)(limit - newMinRadius); + + // If newMaxRadius forces the total over the limit, then it needs to be + // reduced by one ULP to be less than limit - newMinRadius. + // Note: nexttowardf is a c99 call and should be std::nexttoward, but this is not + // implemented in the ARM compiler. + if ((double)newMaxRadius + (double)newMinRadius > limit) { + newMaxRadius = nexttowardf(newMaxRadius, 0.0); + } + *maxRadius = newMaxRadius; + } + + SkASSERTF(*a >= 0.0f && *b >= 0.0f, "a: %g, b: %g", *a, *b); + SkASSERTF((*a + *b) <= limit, "limit: %g, a: %g, b: %g", limit, *a, *b); + } +}; +#endif // ScaleToSides_DEFINED diff --git a/gfx/skia/skia/src/core/SkScan.h b/gfx/skia/skia/src/core/SkScan.h index ef448735696..7309a1dd8c3 100644 --- a/gfx/skia/skia/src/core/SkScan.h +++ b/gfx/skia/skia/src/core/SkScan.h @@ -56,6 +56,10 @@ public: static void AntiHairRect(const SkRect&, const SkRasterClip&, SkBlitter*); static void HairPath(const SkPath&, const SkRasterClip&, SkBlitter*); static void AntiHairPath(const SkPath&, const SkRasterClip&, SkBlitter*); + static void HairSquarePath(const SkPath&, const SkRasterClip&, SkBlitter*); + static void AntiHairSquarePath(const SkPath&, const SkRasterClip&, SkBlitter*); + static void HairRoundPath(const SkPath&, const SkRasterClip&, SkBlitter*); + static void AntiHairRoundPath(const SkPath&, const SkRasterClip&, SkBlitter*); private: friend class SkAAClip; diff --git a/gfx/skia/skia/src/core/SkScan_AntiPath.cpp b/gfx/skia/skia/src/core/SkScan_AntiPath.cpp index 6ea6b8b07ea..22bca7a55cf 100644 --- a/gfx/skia/skia/src/core/SkScan_AntiPath.cpp +++ b/gfx/skia/skia/src/core/SkScan_AntiPath.cpp @@ -91,11 +91,11 @@ BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlit, const SkIRect& ir, const const int right = sectBounds.right(); fLeft = left; - fSuperLeft = left << SHIFT; + fSuperLeft = SkLeftShift(left, SHIFT); fWidth = right - left; fTop = sectBounds.top(); fCurrIY = fTop - 1; - fCurrY = (fTop << SHIFT) - 1; + fCurrY = SkLeftShift(fTop, SHIFT) - 1; SkDEBUGCODE(fCurrX = -1;) } @@ -545,7 +545,7 @@ void MaskSuperBlitter::blitH(int x, int y, int width) { } #endif - x -= (fMask.fBounds.fLeft << SHIFT); + x -= SkLeftShift(fMask.fBounds.fLeft, SHIFT); // hack, until I figure out why my cubics (I think) go beyond the bounds if (x < 0) { @@ -592,7 +592,7 @@ static bool fitsInsideLimit(const SkRect& r, SkScalar max) { static int overflows_short_shift(int value, int shift) { const int s = 16 + shift; - return (value << s >> s) - value; + return (SkLeftShift(value, s) >> s) - value; } /** diff --git a/gfx/skia/skia/src/core/SkScan_Antihair.cpp b/gfx/skia/skia/src/core/SkScan_Antihair.cpp index b14e12bab8c..8ee0ba5f983 100644 --- a/gfx/skia/skia/src/core/SkScan_Antihair.cpp +++ b/gfx/skia/skia/src/core/SkScan_Antihair.cpp @@ -250,9 +250,9 @@ public: }; static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) { - SkASSERT((a << 16 >> 16) == a); + SkASSERT((SkLeftShift(a, 16) >> 16) == a); SkASSERT(b != 0); - return (a << 16) / b; + return SkLeftShift(a, 16) / b; } #define SkBITCOUNT(x) (sizeof(x) << 3) diff --git a/gfx/skia/skia/src/core/SkScan_Hairline.cpp b/gfx/skia/skia/src/core/SkScan_Hairline.cpp index 7a6e3ba1874..12553a4a54f 100644 --- a/gfx/skia/skia/src/core/SkScan_Hairline.cpp +++ b/gfx/skia/skia/src/core/SkScan_Hairline.cpp @@ -318,8 +318,69 @@ static void hair_cubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* bl lineproc(tmp, lines + 1, clip, blitter); } -static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, +static SkRect compute_nocheck_cubic_bounds(const SkPoint pts[4]) { + SkASSERT(SkScalarsAreFinite(&pts[0].fX, 8)); + + Sk2s min = Sk2s::Load(&pts[0].fX); + Sk2s max = min; + for (int i = 1; i < 4; ++i) { + Sk2s pair = Sk2s::Load(&pts[i].fX); + min = Sk2s::Min(min, pair); + max = Sk2s::Max(max, pair); + } + return { min.kth<0>(), min.kth<1>(), max.kth<0>(), max.kth<1>() }; +} + +static bool is_inverted(const SkRect& r) { + return r.fLeft > r.fRight || r.fTop > r.fBottom; +} + +// Can't call SkRect::intersects, since it cares about empty, and we don't (since we tracking +// something to be stroked, so empty can still draw something (e.g. horizontal line) +static bool geometric_overlap(const SkRect& a, const SkRect& b) { + SkASSERT(!is_inverted(a) && !is_inverted(b)); + return a.fLeft < b.fRight && b.fLeft < a.fRight && + a.fTop < b.fBottom && b.fTop < a.fBottom; +} + +// Can't call SkRect::contains, since it cares about empty, and we don't (since we tracking +// something to be stroked, so empty can still draw something (e.g. horizontal line) +static bool geometric_contains(const SkRect& outer, const SkRect& inner) { + SkASSERT(!is_inverted(outer) && !is_inverted(inner)); + return inner.fRight <= outer.fRight && inner.fLeft >= outer.fLeft && + inner.fBottom <= outer.fBottom && inner.fTop >= outer.fTop; +} + +//#define SK_SHOW_HAIRCLIP_STATS +#ifdef SK_SHOW_HAIRCLIP_STATS +static int gKillClip, gRejectClip, gClipCount; +#endif + +static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, const SkRect* insetClip, const SkRect* outsetClip, SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc) { + if (insetClip) { + SkASSERT(outsetClip); +#ifdef SK_SHOW_HAIRCLIP_STATS + gClipCount += 1; +#endif + SkRect bounds = compute_nocheck_cubic_bounds(pts); + if (!geometric_overlap(*outsetClip, bounds)) { +#ifdef SK_SHOW_HAIRCLIP_STATS + gRejectClip += 1; +#endif + return; + } else if (geometric_contains(*insetClip, bounds)) { + clip = nullptr; +#ifdef SK_SHOW_HAIRCLIP_STATS + gKillClip += 1; +#endif + } +#ifdef SK_SHOW_HAIRCLIP_STATS + if (0 == gClipCount % 256) + SkDebugf("kill %g reject %g total %d\n", 1.0*gKillClip / gClipCount, 1.0*gRejectClip/gClipCount, gClipCount); +#endif + } + if (quick_cubic_niceness_check(pts)) { hair_cubic(pts, clip, blitter, lineproc); } else { @@ -348,7 +409,59 @@ static int compute_quad_level(const SkPoint pts[3]) { return level; } -static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter, +/* Extend the points in the direction of the starting or ending tangent by 1/2 unit to + account for a round or square cap. If there's no distance between the end point and + the control point, use the next control point to create a tangent. If the curve + is degenerate, move the cap out 1/2 unit horizontally. */ +template +void extend_pts(SkPath::Verb prevVerb, SkPath::Verb nextVerb, SkPoint* pts, int ptCount) { + SkASSERT(SkPaint::kSquare_Cap == capStyle || SkPaint::kRound_Cap == capStyle); + // The area of a circle is PI*R*R. For a unit circle, R=1/2, and the cap covers half of that. + const SkScalar capOutset = SkPaint::kSquare_Cap == capStyle ? 0.5f : SK_ScalarPI / 8; + if (SkPath::kMove_Verb == prevVerb) { + SkPoint* first = pts; + SkPoint* ctrl = first; + int controls = ptCount - 1; + SkVector tangent; + do { + tangent = *first - *++ctrl; + } while (tangent.isZero() && --controls > 0); + if (tangent.isZero()) { + tangent.set(1, 0); + controls = ptCount - 1; // If all points are equal, move all but one + } else { + tangent.normalize(); + } + do { // If the end point and control points are equal, loop to move them in tandem. + first->fX += tangent.fX * capOutset; + first->fY += tangent.fY * capOutset; + ++first; + } while (++controls < ptCount); + } + if (SkPath::kMove_Verb == nextVerb || SkPath::kDone_Verb == nextVerb) { + SkPoint* last = &pts[ptCount - 1]; + SkPoint* ctrl = last; + int controls = ptCount - 1; + SkVector tangent; + do { + tangent = *last - *--ctrl; + } while (tangent.isZero() && --controls > 0); + if (tangent.isZero()) { + tangent.set(-1, 0); + controls = ptCount - 1; + } else { + tangent.normalize(); + } + do { + last->fX += tangent.fX * capOutset; + last->fY += tangent.fY * capOutset; + --last; + } while (++controls < ptCount); + } +} + +template +void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter, SkScan::HairRgnProc lineproc) { if (path.isEmpty()) { return; @@ -356,10 +469,13 @@ static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* SkAAClipBlitterWrapper wrap; const SkRegion* clip = nullptr; + SkRect insetStorage, outsetStorage; + const SkRect* insetClip = nullptr; + const SkRect* outsetClip = nullptr; { - const SkIRect ibounds = path.getBounds().roundOut().makeOutset(1, 1); - + const int capOut = SkPaint::kButt_Cap == capStyle ? 1 : 2; + const SkIRect ibounds = path.getBounds().roundOut().makeOutset(capOut, capOut); if (rclip.quickReject(ibounds)) { return; } @@ -371,25 +487,69 @@ static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter = wrap.getBlitter(); clip = &wrap.getRgn(); } + + /* + * We now cache two scalar rects, to use for culling per-segment (e.g. cubic). + * Since we're hairlining, the "bounds" of the control points isn't necessairly the + * limit of where a segment can draw (it might draw up to 1 pixel beyond in aa-hairs). + * + * Compute the pt-bounds per segment is easy, so we do that, and then inversely adjust + * the culling bounds so we can just do a straight compare per segment. + * + * insetClip is use for quick-accept (i.e. the segment is not clipped), so we inset + * it from the clip-bounds (since segment bounds can be off by 1). + * + * outsetClip is used for quick-reject (i.e. the segment is entirely outside), so we + * outset it from the clip-bounds. + */ + insetStorage.set(clip->getBounds()); + outsetStorage = insetStorage.makeOutset(1, 1); + insetStorage.inset(1, 1); + if (is_inverted(insetStorage)) { + /* + * our bounds checks assume the rects are never inverted. If insetting has + * created that, we assume that the area is too small to safely perform a + * quick-accept, so we just mark the rect as empty (so the quick-accept check + * will always fail. + */ + insetStorage.setEmpty(); // just so we don't pass an inverted rect + } + insetClip = &insetStorage; + outsetClip = &outsetStorage; } } - SkPath::Iter iter(path, false); - SkPoint pts[4]; - SkPath::Verb verb; - SkAutoConicToQuads converter; + SkPath::RawIter iter(path); + SkPoint pts[4], firstPt, lastPt; + SkPath::Verb verb, prevVerb; + SkAutoConicToQuads converter; - while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) { + if (SkPaint::kButt_Cap != capStyle) { + prevVerb = SkPath::kDone_Verb; + } + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { switch (verb) { case SkPath::kMove_Verb: + firstPt = lastPt = pts[0]; break; case SkPath::kLine_Verb: + if (SkPaint::kButt_Cap != capStyle) { + extend_pts(prevVerb, iter.peek(), pts, 2); + } lineproc(pts, 2, clip, blitter); + lastPt = pts[1]; break; case SkPath::kQuad_Verb: + if (SkPaint::kButt_Cap != capStyle) { + extend_pts(prevVerb, iter.peek(), pts, 3); + } hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc); + lastPt = pts[2]; break; case SkPath::kConic_Verb: { + if (SkPaint::kButt_Cap != capStyle) { + extend_pts(prevVerb, iter.peek(), pts, 3); + } // how close should the quads be to the original conic? const SkScalar tol = SK_Scalar1 / 4; const SkPoint* quadPts = converter.computeQuads(pts, @@ -399,25 +559,56 @@ static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* hairquad(quadPts, clip, blitter, level, lineproc); quadPts += 2; } + lastPt = pts[2]; break; } case SkPath::kCubic_Verb: { - haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc); + if (SkPaint::kButt_Cap != capStyle) { + extend_pts(prevVerb, iter.peek(), pts, 4); + } + haircubic(pts, clip, insetClip, outsetClip, blitter, kMaxCubicSubdivideLevel, lineproc); + lastPt = pts[3]; } break; case SkPath::kClose_Verb: + pts[0] = lastPt; + pts[1] = firstPt; + if (SkPaint::kButt_Cap != capStyle && prevVerb == SkPath::kMove_Verb) { + // cap moveTo/close to match svg expectations for degenerate segments + extend_pts(prevVerb, iter.peek(), pts, 2); + } + lineproc(pts, 2, clip, blitter); break; case SkPath::kDone_Verb: break; } + if (SkPaint::kButt_Cap != capStyle) { + prevVerb = verb; + } } } void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { - hair_path(path, clip, blitter, SkScan::HairLineRgn); + hair_path(path, clip, blitter, SkScan::HairLineRgn); } void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { - hair_path(path, clip, blitter, SkScan::AntiHairLineRgn); + hair_path(path, clip, blitter, SkScan::AntiHairLineRgn); +} + +void SkScan::HairSquarePath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { + hair_path(path, clip, blitter, SkScan::HairLineRgn); +} + +void SkScan::AntiHairSquarePath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { + hair_path(path, clip, blitter, SkScan::AntiHairLineRgn); +} + +void SkScan::HairRoundPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { + hair_path(path, clip, blitter, SkScan::HairLineRgn); +} + +void SkScan::AntiHairRoundPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { + hair_path(path, clip, blitter, SkScan::AntiHairLineRgn); } /////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/core/SkScan_Path.cpp b/gfx/skia/skia/src/core/SkScan_Path.cpp index fc79fc8537d..804148db360 100644 --- a/gfx/skia/skia/src/core/SkScan_Path.cpp +++ b/gfx/skia/skia/src/core/SkScan_Path.cpp @@ -450,8 +450,8 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte // now edge is the head of the sorted linklist - start_y <<= shiftEdgesUp; - stop_y <<= shiftEdgesUp; + start_y = SkLeftShift(start_y, shiftEdgesUp); + stop_y = SkLeftShift(stop_y, shiftEdgesUp); if (clipRect && start_y < clipRect->fTop) { start_y = clipRect->fTop; } @@ -559,6 +559,42 @@ static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) { return true; } +/** + * Variant of SkScalarRoundToInt, identical to SkDScalarRoundToInt except when the input fraction + * is 0.5. In this case only, round the value down. This is used to round the top and left + * of a rectangle, and corresponds to the way the scan converter treats the top and left edges. + */ +static inline int round_down_to_int(SkScalar x) { + double xx = x; + xx += 0.5; + double floorXX = floor(xx); + return (int)floorXX - (xx == floorXX); +} + +/** + * Variant of SkRect::round() that explicitly performs the rounding step (i.e. floor(x + 0.5)) + * using double instead of SkScalar (float). It does this by calling SkDScalarRoundToInt(), + * which may be slower than calling SkScalarRountToInt(), but gives slightly more accurate + * results. Also rounds top and left using double, flooring when the fraction is exactly 0.5f. + * + * e.g. + * SkScalar left = 0.5f; + * int ileft = SkScalarRoundToInt(left); + * SkASSERT(0 == ileft); // <--- fails + * int ileft = round_down_to_int(left); + * SkASSERT(0 == ileft); // <--- succeeds + * SkScalar right = 0.49999997f; + * int iright = SkScalarRoundToInt(right); + * SkASSERT(0 == iright); // <--- fails + * iright = SkDScalarRoundToInt(right); + * SkASSERT(0 == iright); // <--- succeeds + */ +static void round_asymmetric_to_int(const SkRect& src, SkIRect* dst) { + SkASSERT(dst); + dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop), + SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom)); +} + void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter) { if (origClip.isEmpty()) { @@ -578,11 +614,11 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, // don't reference "origClip" any more, just use clipPtr SkIRect ir; - // We deliberately call dround() instead of round(), since we can't afford to generate a - // bounds that is tighter than the corresponding SkEdges. The edge code basically converts - // the floats to fixed, and then "rounds". If we called round() instead of dround() here, - // we could generate the wrong ir for values like 0.4999997. - path.getBounds().dround(&ir); + // We deliberately call round_asymmetric_to_int() instead of round(), since we can't afford + // to generate a bounds that is tighter than the corresponding SkEdges. The edge code basically + // converts the floats to fixed, and then "rounds". If we called round() instead of + // round_asymmetric_to_int() here, we could generate the wrong ir for values like 0.4999997. + round_asymmetric_to_int(path.getBounds(), &ir); if (ir.isEmpty()) { if (path.isInverseFillType()) { blitter->blitRegion(*clipPtr); diff --git a/gfx/skia/skia/src/core/SkShader.cpp b/gfx/skia/skia/src/core/SkShader.cpp index 0ec1433a908..bd3876a69b9 100644 --- a/gfx/skia/skia/src/core/SkShader.cpp +++ b/gfx/skia/skia/src/core/SkShader.cpp @@ -119,15 +119,6 @@ SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) { #include "SkColorPriv.h" -void SkShader::Context::shadeSpan16(int x, int y, uint16_t span16[], int count) { - SkASSERT(span16); - SkASSERT(count > 0); - SkASSERT(this->canCallShadeSpan16()); - - // basically, if we get here, the subclass screwed up - SkDEBUGFAIL("kHasSpan16 flag is set, but shadeSpan16() not implemented"); -} - #define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space #define kTempColorCount (kTempColorQuadCount << 2) @@ -266,10 +257,6 @@ uint32_t SkColorShader::ColorShaderContext::getFlags() const { return fFlags; } -uint8_t SkColorShader::ColorShaderContext::getSpan16Alpha() const { - return SkGetPackedA32(fPMColor); -} - SkShader::Context* SkColorShader::onCreateContext(const ContextRec& rec, void* storage) const { return new (storage) ColorShaderContext(*this, rec); } @@ -285,9 +272,6 @@ SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shade unsigned g = SkColorGetG(color); unsigned b = SkColorGetB(color); - // we want this before we apply any alpha - fColor16 = SkPack888ToRGB16(r, g, b); - if (a != 255) { r = SkMulDiv255Round(r, a); g = SkMulDiv255Round(g, a); @@ -298,9 +282,6 @@ SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shade fFlags = kConstInY32_Flag; if (255 == a) { fFlags |= kOpaqueAlpha_Flag; - if (rec.fPaint->isDither() == false) { - fFlags |= kHasSpan16_Flag; - } } } @@ -308,10 +289,6 @@ void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[] sk_memset32(span, fPMColor, count); } -void SkColorShader::ColorShaderContext::shadeSpan16(int x, int y, uint16_t span[], int count) { - sk_memset16(span, fColor16, count); -} - void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { memset(alpha, SkGetPackedA32(fPMColor), count); } diff --git a/gfx/skia/skia/src/core/SkStream.cpp b/gfx/skia/skia/src/core/SkStream.cpp index 05867d91bfe..ef4c6baae43 100644 --- a/gfx/skia/skia/src/core/SkStream.cpp +++ b/gfx/skia/skia/src/core/SkStream.cpp @@ -367,18 +367,14 @@ size_t SkMemoryStream::read(void* buffer, size_t size) { return size; } -bool SkMemoryStream::peek(void* buffer, size_t size) const { +size_t SkMemoryStream::peek(void* buffer, size_t size) const { SkASSERT(buffer != nullptr); - const size_t position = fOffset; - if (size > fData->size() - position) { - // The stream is not large enough to satisfy this request. - return false; - } + + const size_t currentOffset = fOffset; SkMemoryStream* nonConstThis = const_cast(this); - SkDEBUGCODE(const size_t bytesRead =) nonConstThis->read(buffer, size); - SkASSERT(bytesRead == size); - nonConstThis->fOffset = position; - return true; + const size_t bytesRead = nonConstThis->read(buffer, size); + nonConstThis->fOffset = currentOffset; + return bytesRead; } bool SkMemoryStream::isAtEnd() const { @@ -467,6 +463,14 @@ void SkFILEWStream::flush() } } +void SkFILEWStream::fsync() +{ + flush(); + if (fFILE) { + sk_fsync(fFILE); + } +} + //////////////////////////////////////////////////////////////////////// SkMemoryWStream::SkMemoryWStream(void* buffer, size_t size) @@ -725,25 +729,26 @@ public: return fOffset == fSize; } - bool peek(void* buff, size_t size) const override { + size_t peek(void* buff, size_t bytesToPeek) const override { SkASSERT(buff != nullptr); - if (fOffset + size > fSize) { - return false; - } + + bytesToPeek = SkTMin(bytesToPeek, fSize - fOffset); + + size_t bytesLeftToPeek = bytesToPeek; char* buffer = static_cast(buff); const SkDynamicMemoryWStream::Block* current = fCurrent; size_t currentOffset = fCurrentOffset; - while (size) { + while (bytesLeftToPeek) { SkASSERT(current); size_t bytesFromCurrent = - SkTMin(current->written() - currentOffset, size); + SkTMin(current->written() - currentOffset, bytesLeftToPeek); memcpy(buffer, current->start() + currentOffset, bytesFromCurrent); - size -= bytesFromCurrent; + bytesLeftToPeek -= bytesFromCurrent; buffer += bytesFromCurrent; current = current->fNext; currentOffset = 0; } - return true; + return bytesToPeek; } bool rewind() override { diff --git a/gfx/skia/skia/src/core/SkString.cpp b/gfx/skia/skia/src/core/SkString.cpp index e730753fca2..64193c47e92 100644 --- a/gfx/skia/skia/src/core/SkString.cpp +++ b/gfx/skia/skia/src/core/SkString.cpp @@ -624,16 +624,35 @@ SkString SkStringPrintf(const char* format, ...) { return formattedOutput; } -void SkStrSplit(const char* str, const char* delimiters, SkTArray* out) { - const char* end = str + strlen(str); - while (str != end) { - // Find a token. - const size_t len = strcspn(str, delimiters); - out->push_back().set(str, len); - str += len; +void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode, + SkTArray* out) { + if (splitMode == kCoalesce_SkStrSplitMode) { // Skip any delimiters. str += strspn(str, delimiters); } + if (!*str) { + return; + } + + while (true) { + // Find a token. + const size_t len = strcspn(str, delimiters); + if (splitMode == kStrict_SkStrSplitMode || len > 0) { + out->push_back().set(str, len); + str += len; + } + + if (!*str) { + return; + } + if (splitMode == kCoalesce_SkStrSplitMode) { + // Skip any delimiters. + str += strspn(str, delimiters); + } else { + // Skip one delimiter. + str += 1; + } + } } #undef VSNPRINTF diff --git a/gfx/skia/skia/src/core/SkStroke.cpp b/gfx/skia/skia/src/core/SkStroke.cpp index 65267d11fd4..5a430752842 100644 --- a/gfx/skia/skia/src/core/SkStroke.cpp +++ b/gfx/skia/skia/src/core/SkStroke.cpp @@ -126,7 +126,7 @@ public: SkPoint moveToPt() const { return fFirstPt; } void moveTo(const SkPoint&); - void lineTo(const SkPoint&); + void lineTo(const SkPoint&, const SkPath::Iter* iter = nullptr); void quadTo(const SkPoint&, const SkPoint&); void conicTo(const SkPoint&, const SkPoint&, SkScalar weight); void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); @@ -187,6 +187,7 @@ private: int fRecursionDepth; // track stack depth to abort if numerics run amok bool fFoundTangents; // do less work until tangents meet (cubic) + bool fJoinCompleted; // previous join was not degenerate void addDegenerateLine(const SkQuadConstruct* ); static ReductionType CheckConicLinear(const SkConic& , SkPoint* reduction); @@ -273,6 +274,7 @@ bool SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal, void SkPathStroker::postJoinTo(const SkPoint& currPt, const SkVector& normal, const SkVector& unitNormal) { + fJoinCompleted = true; fPrevPt = currPt; fPrevUnitNormal = unitNormal; fPrevNormal = normal; @@ -359,6 +361,7 @@ void SkPathStroker::moveTo(const SkPoint& pt) { } fSegmentCount = 0; fFirstPt = fPrevPt = pt; + fJoinCompleted = false; } void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { @@ -366,11 +369,46 @@ void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY); } -void SkPathStroker::lineTo(const SkPoint& currPt) { +static bool has_valid_tangent(const SkPath::Iter* iter) { + SkPath::Iter copy = *iter; + SkPath::Verb verb; + SkPoint pts[4]; + while ((verb = copy.next(pts))) { + switch (verb) { + case SkPath::kMove_Verb: + return false; + case SkPath::kLine_Verb: + if (pts[0] == pts[1]) { + continue; + } + return true; + case SkPath::kQuad_Verb: + case SkPath::kConic_Verb: + if (pts[0] == pts[1] && pts[0] == pts[2]) { + continue; + } + return true; + case SkPath::kCubic_Verb: + if (pts[0] == pts[1] && pts[0] == pts[2] && pts[0] == pts[3]) { + continue; + } + return true; + case SkPath::kClose_Verb: + case SkPath::kDone_Verb: + return false; + } + } + return false; +} + +void SkPathStroker::lineTo(const SkPoint& currPt, const SkPath::Iter* iter) { if (SkStrokerPriv::CapFactory(SkPaint::kButt_Cap) == fCapper && fPrevPt.equalsWithinTolerance(currPt, SK_ScalarNearlyZero * fInvResScale)) { return; } + if (fPrevPt == currPt && (fJoinCompleted || (iter && has_valid_tangent(iter)))) { + return; + } SkVector normal, unitNormal; if (!this->preJoinTo(currPt, &normal, &unitNormal, true)) { @@ -1339,7 +1377,7 @@ void SkStroke::strokePath(const SkPath& src, SkPath* dst) const { stroker.moveTo(pts[0]); break; case SkPath::kLine_Verb: - stroker.lineTo(pts[1]); + stroker.lineTo(pts[1], &iter); lastSegment = SkPath::kLine_Verb; break; case SkPath::kQuad_Verb: diff --git a/gfx/skia/skia/src/core/SkTLList.h b/gfx/skia/skia/src/core/SkTLList.h index 211a4414135..48e81bdac18 100644 --- a/gfx/skia/skia/src/core/SkTLList.h +++ b/gfx/skia/skia/src/core/SkTLList.h @@ -10,7 +10,7 @@ #include "SkTInternalLList.h" #include "SkTypes.h" -#include "SkUtility.h" +#include /** Doubly-linked list of objects. The objects' lifetimes are controlled by the list. I.e. the the list creates the objects and they are deleted upon removal. This class block-allocates @@ -72,7 +72,7 @@ public: Node* node = this->createNode(); fList.addToHead(node); this->validate(); - return new (node->fObj) T(skstd::forward(args)...); + return new (node->fObj) T(std::forward(args)...); } /** Adds a new element to the list at the tail. */ @@ -81,7 +81,7 @@ public: Node* node = this->createNode(); fList.addToTail(node); this->validate(); - return new (node->fObj) T(skstd::forward(args)...); + return new (node->fObj) T(std::forward(args)...); } /** Adds a new element to the list before the location indicated by the iterator. If the @@ -91,7 +91,7 @@ public: Node* node = this->createNode(); fList.addBefore(node, location.getNode()); this->validate(); - return new (node->fObj) T(skstd::forward(args)...); + return new (node->fObj) T(std::forward(args)...); } /** Adds a new element to the list after the location indicated by the iterator. If the @@ -101,7 +101,7 @@ public: Node* node = this->createNode(); fList.addAfter(node, location.getNode()); this->validate(); - return new (node->fObj) T(skstd::forward(args)...); + return new (node->fObj) T(std::forward(args)...); } /** Convenience methods for getting an iterator initialized to the head/tail of the list. */ diff --git a/gfx/skia/skia/src/core/SkTaskGroup.cpp b/gfx/skia/skia/src/core/SkTaskGroup.cpp index 863195cfd3f..e4d4bee9a2f 100644 --- a/gfx/skia/skia/src/core/SkTaskGroup.cpp +++ b/gfx/skia/skia/src/core/SkTaskGroup.cpp @@ -9,6 +9,7 @@ #include "SkRunnable.h" #include "SkSemaphore.h" #include "SkSpinlock.h" +#include "SkTArray.h" #include "SkTDArray.h" #include "SkTaskGroup.h" #include "SkThreadUtils.h" @@ -43,23 +44,22 @@ public: if (!gGlobal) { // If we have no threads, run synchronously. return task->run(); } - gGlobal->add(&CallRunnable, task, pending); + gGlobal->add([task]() { task->run(); }, pending); } - static void Add(void (*fn)(void*), void* arg, SkAtomic* pending) { + static void Add(std::function fn, SkAtomic* pending) { if (!gGlobal) { - return fn(arg); + return fn(); } - gGlobal->add(fn, arg, pending); + gGlobal->add(fn, pending); } - static void Batch(void (*fn)(void*), void* args, int N, size_t stride, - SkAtomic* pending) { + static void Batch(int N, std::function fn, SkAtomic* pending) { if (!gGlobal) { - for (int i = 0; i < N; i++) { fn((char*)args + i*stride); } + for (int i = 0; i < N; i++) { fn(i); } return; } - gGlobal->batch(fn, args, N, stride, pending); + gGlobal->batch(N, fn, pending); } static void Wait(SkAtomic* pending) { @@ -76,16 +76,17 @@ public: // so we never call fWorkAvailable.wait(), which could sleep us if there's no work. // This means fWorkAvailable is only an upper bound on fWork.count(). AutoLock lock(&gGlobal->fWorkLock); - if (gGlobal->fWork.isEmpty()) { + if (gGlobal->fWork.empty()) { // Someone has picked up all the work (including ours). How nice of them! // (They may still be working on it, so we can't assert *pending == 0 here.) continue; } - gGlobal->fWork.pop(&work); + work = gGlobal->fWork.back(); + gGlobal->fWork.pop_back(); } // This Work isn't necessarily part of our SkTaskGroup of interest, but that's fine. // We threads gotta stick together. We're always making forward progress. - work.fn(work.arg); + work.fn(); work.pending->fetch_add(-1, sk_memory_order_release); // Pairs with load above. } } @@ -101,8 +102,7 @@ private: static void CallRunnable(void* arg) { static_cast(arg)->run(); } struct Work { - void (*fn)(void*); // A function to call, - void* arg; // its argument, + std::function fn; // A function to call SkAtomic* pending; // then decrement pending afterwards. }; @@ -117,39 +117,40 @@ private: } ~ThreadPool() { - SkASSERT(fWork.isEmpty()); // All SkTaskGroups should be destroyed by now. + SkASSERT(fWork.empty()); // All SkTaskGroups should be destroyed by now. // Send a poison pill to each thread. SkAtomic dummy(0); for (int i = 0; i < fThreads.count(); i++) { - this->add(nullptr, nullptr, &dummy); + this->add(nullptr, &dummy); } // Wait for them all to swallow the pill and die. for (int i = 0; i < fThreads.count(); i++) { fThreads[i]->join(); } - SkASSERT(fWork.isEmpty()); // Can't hurt to double check. + SkASSERT(fWork.empty()); // Can't hurt to double check. fThreads.deleteAll(); } - void add(void (*fn)(void*), void* arg, SkAtomic* pending) { - Work work = { fn, arg, pending }; + void add(std::function fn, SkAtomic* pending) { + Work work = { fn, pending }; pending->fetch_add(+1, sk_memory_order_relaxed); // No barrier needed. { AutoLock lock(&fWorkLock); - fWork.push(work); + fWork.push_back(work); } fWorkAvailable.signal(1); } - void batch(void (*fn)(void*), void* arg, int N, size_t stride, SkAtomic* pending) { + void batch(int N, std::function fn, SkAtomic* pending) { pending->fetch_add(+N, sk_memory_order_relaxed); // No barrier needed. { AutoLock lock(&fWorkLock); - Work* batch = fWork.append(N); for (int i = 0; i < N; i++) { - Work work = { fn, (char*)arg + i*stride, pending }; - batch[i] = work; + Work work; + work.fn = [i, fn]() { fn(i); }; + work.pending = pending; + fWork.push_back(work); } } fWorkAvailable.signal(N); @@ -163,24 +164,25 @@ private: pool->fWorkAvailable.wait(); { AutoLock lock(&pool->fWorkLock); - if (pool->fWork.isEmpty()) { + if (pool->fWork.empty()) { // Someone in Wait() stole our work (fWorkAvailable is an upper bound). // Well, that's fine, back to sleep for us. continue; } - pool->fWork.pop(&work); + work = pool->fWork.back(); + pool->fWork.pop_back(); } if (!work.fn) { return; // Poison pill. Time... to die. } - work.fn(work.arg); + work.fn(); work.pending->fetch_add(-1, sk_memory_order_release); // Pairs with load in Wait(). } } // fWorkLock must be held when reading or modifying fWork. SkSpinlock fWorkLock; - SkTDArray fWork; + SkTArray fWork; // A thread-safe upper bound for fWork.count(). // @@ -196,7 +198,6 @@ private: static ThreadPool* gGlobal; friend struct SkTaskGroup::Enabler; - friend int ::sk_parallel_for_thread_count(); }; ThreadPool* ThreadPool::gGlobal = nullptr; @@ -215,14 +216,8 @@ SkTaskGroup::SkTaskGroup() : fPending(0) {} void SkTaskGroup::wait() { ThreadPool::Wait(&fPending); } void SkTaskGroup::add(SkRunnable* task) { ThreadPool::Add(task, &fPending); } -void SkTaskGroup::add(void (*fn)(void*), void* arg) { ThreadPool::Add(fn, arg, &fPending); } -void SkTaskGroup::batch (void (*fn)(void*), void* args, int N, size_t stride) { - ThreadPool::Batch(fn, args, N, stride, &fPending); +void SkTaskGroup::add(std::function fn) { ThreadPool::Add(fn, &fPending); } +void SkTaskGroup::batch(int N, std::function fn) { + ThreadPool::Batch(N, fn, &fPending); } -int sk_parallel_for_thread_count() { - if (ThreadPool::gGlobal != nullptr) { - return ThreadPool::gGlobal->fThreads.count(); - } - return 0; -} diff --git a/gfx/skia/skia/src/core/SkTaskGroup.h b/gfx/skia/skia/src/core/SkTaskGroup.h index f68c528a1ff..802ee0603ed 100644 --- a/gfx/skia/skia/src/core/SkTaskGroup.h +++ b/gfx/skia/skia/src/core/SkTaskGroup.h @@ -29,70 +29,20 @@ public: // Neither add() method takes owership of any of its parameters. void add(SkRunnable*); - template - void add(void (*fn)(T*), T* arg) { this->add((void_fn)fn, (void*)arg); } + void add(std::function fn); // Add a batch of N tasks, all calling fn with different arguments. - // Equivalent to a loop over add(fn, arg), but with perhaps less synchronization overhead. - template - void batch(void (*fn)(T*), T* args, int N) { this->batch((void_fn)fn, args, N, sizeof(T)); } + void batch(int N, std::function fn); // Block until all Tasks previously add()ed to this SkTaskGroup have run. // You may safely reuse this SkTaskGroup after wait() returns. void wait(); private: - typedef void(*void_fn)(void*); - - void add (void_fn, void* arg); - void batch(void_fn, void* args, int N, size_t stride); - SkAtomic fPending; }; // Returns best estimate of number of CPU cores available to use. int sk_num_cores(); -int sk_parallel_for_thread_count(); - -// Call f(i) for i in [0, end). -template -void sk_parallel_for(int end, const Func& f) { - if (end <= 0) { return; } - - struct Chunk { - const Func* f; - int start, end; - }; - - // TODO(mtklein): this chunking strategy could probably use some tuning. - int max_chunks = sk_num_cores() * 2, - stride = (end + max_chunks - 1 ) / max_chunks, - nchunks = (end + stride - 1 ) / stride; - SkASSERT(nchunks <= max_chunks); - -#if defined(GOOGLE3) - // Stack frame size is limited in GOOGLE3. - SkAutoSTMalloc<512, Chunk> chunks(nchunks); -#else - // With the chunking strategy above this won't malloc until we have a machine with >512 cores. - SkAutoSTMalloc<1024, Chunk> chunks(nchunks); -#endif - - for (int i = 0; i < nchunks; i++) { - Chunk& c = chunks[i]; - c.f = &f; - c.start = i * stride; - c.end = SkTMin(c.start + stride, end); - SkASSERT(c.start < c.end); // Nothing will break if start >= end, but it's a wasted chunk. - } - - void(*run_chunk)(Chunk*) = [](Chunk* c) { - for (int i = c->start; i < c->end; i++) { - (*c->f)(i); - } - }; - SkTaskGroup().batch(run_chunk, chunks.get(), nchunks); -} - #endif//SkTaskGroup_DEFINED diff --git a/gfx/skia/skia/src/core/SkTime.cpp b/gfx/skia/skia/src/core/SkTime.cpp index 2f66057878f..841ea331146 100644 --- a/gfx/skia/skia/src/core/SkTime.cpp +++ b/gfx/skia/skia/src/core/SkTime.cpp @@ -8,6 +8,7 @@ #include "SkOncePtr.h" #include "SkString.h" #include "SkTime.h" +#include "SkTypes.h" void SkTime::DateTime::toISO8601(SkString* dst) const { if (dst) { @@ -24,6 +25,46 @@ void SkTime::DateTime::toISO8601(SkString* dst) const { } } + +#ifdef SK_BUILD_FOR_WIN32 + +#include "Windows.h" +void SkTime::GetDateTime(DateTime* dt) { + if (dt) { + SYSTEMTIME st; + GetSystemTime(&st); + dt->fTimeZoneMinutes = 0; + dt->fYear = st.wYear; + dt->fMonth = SkToU8(st.wMonth); + dt->fDayOfWeek = SkToU8(st.wDayOfWeek); + dt->fDay = SkToU8(st.wDay); + dt->fHour = SkToU8(st.wHour); + dt->fMinute = SkToU8(st.wMinute); + dt->fSecond = SkToU8(st.wSecond); + } +} + +#else // SK_BUILD_FOR_WIN32 + +#include +void SkTime::GetDateTime(DateTime* dt) { + if (dt) { + time_t m_time; + time(&m_time); + struct tm* tstruct; + tstruct = gmtime(&m_time); + dt->fTimeZoneMinutes = 0; + dt->fYear = tstruct->tm_year + 1900; + dt->fMonth = SkToU8(tstruct->tm_mon + 1); + dt->fDayOfWeek = SkToU8(tstruct->tm_wday); + dt->fDay = SkToU8(tstruct->tm_mday); + dt->fHour = SkToU8(tstruct->tm_hour); + dt->fMinute = SkToU8(tstruct->tm_min); + dt->fSecond = SkToU8(tstruct->tm_sec); + } +} +#endif // SK_BUILD_FOR_WIN32 + #if defined(_MSC_VER) // TODO: try std::chrono again with MSVC 2015? #include diff --git a/gfx/skia/skia/src/core/SkUtils.cpp b/gfx/skia/skia/src/core/SkUtils.cpp index b3f698b4e7b..f706cb9f25f 100644 --- a/gfx/skia/skia/src/core/SkUtils.cpp +++ b/gfx/skia/skia/src/core/SkUtils.cpp @@ -74,11 +74,11 @@ SkUnichar SkUTF8_ToUnichar(const char utf8[]) { if (hic < 0) { uint32_t mask = (uint32_t)~0x3F; - hic <<= 1; + hic = SkLeftShift(hic, 1); do { c = (c << 6) | (*++p & 0x3F); mask <<= 5; - } while ((hic <<= 1) < 0); + } while ((hic = SkLeftShift(hic, 1)) < 0); c &= ~mask; } return c; @@ -95,11 +95,11 @@ SkUnichar SkUTF8_NextUnichar(const char** ptr) { if (hic < 0) { uint32_t mask = (uint32_t)~0x3F; - hic <<= 1; + hic = SkLeftShift(hic, 1); do { c = (c << 6) | (*++p & 0x3F); mask <<= 5; - } while ((hic <<= 1) < 0); + } while ((hic = SkLeftShift(hic, 1)) < 0); c &= ~mask; } *ptr = (char*)p + 1; diff --git a/gfx/skia/skia/src/core/SkValue.h b/gfx/skia/skia/src/core/SkValue.h new file mode 100644 index 00000000000..4a53a38e3d7 --- /dev/null +++ b/gfx/skia/skia/src/core/SkValue.h @@ -0,0 +1,81 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkValue_DEFINED +#define SkValue_DEFINED + +#include "SkTypes.h" +#include "SkTemplates.h" + +class SkValue { +public: + enum Type : uint32_t { + // 0-255 are reserved for built-in SkValue types. + Null, + Byte , S16 , U16 , S32 , U32 , S64 , U64 , F32 , F64 , + Bytes, S16s, U16s, S32s, U32s, S64s, U64s, F32s, F64s, + Array, + + // 256-2147483647 may be used by Skia for public Object types. + + + // 2147483648+ won't be used by Skia. They're open for client-specific use, testing, etc. + }; + + enum Key : uint32_t { + // Each Object type may define its own namespace of Key values, + // so there are no pre-defined Keys here. + // + // This is just a reminder that they must fit in a uint32_t, + // and that their namespace is distinct from other uint32_ts (e.g. Type). + }; + + SkValue(); + SkValue(const SkValue&); + SkValue(SkValue&&); + + SkValue& operator=(const SkValue&); + SkValue& operator=(SkValue&&); + + ~SkValue(); + + static SkValue FromS32(int32_t); + static SkValue FromU32(uint32_t); + static SkValue FromF32(float); + static SkValue FromBytes(const void*, size_t); // Copies. + static SkValue Object(Type); + + Type type() const; + + // These remaining methods may assert they're called on a value of the appropriate type. + + int32_t s32() const; + uint32_t u32() const; + float f32() const; + + const void* bytes() const; + size_t count() const; + + void set(Key, SkValue); + const SkValue* get(Key) const; + void foreach(std::function) const; + +private: + class Bytes; + class Object; + + Type fType; + union { + int32_t fS32; + uint32_t fU32; + float fF32; + class Bytes* fBytes; + class Object* fObject; + }; +}; + +#endif//SkValue_DEFINED diff --git a/gfx/skia/skia/src/core/SkVarAlloc.cpp b/gfx/skia/skia/src/core/SkVarAlloc.cpp index 149f0515b0c..1fbd382c194 100644 --- a/gfx/skia/skia/src/core/SkVarAlloc.cpp +++ b/gfx/skia/skia/src/core/SkVarAlloc.cpp @@ -7,13 +7,6 @@ #include "SkVarAlloc.h" -// We use non-standard malloc diagnostic methods to make sure our allocations are sized well. -#if defined(SK_BUILD_FOR_MAC) - #include -#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_WIN32) -// #include -#endif - struct SkVarAlloc::Block { Block* prev; char* data() { return (char*)(this + 1); } @@ -60,11 +53,4 @@ void SkVarAlloc::makeSpace(size_t bytes) { fBlock = Block::Alloc(fBlock, alloc); fByte = fBlock->data(); fRemaining = alloc - sizeof(Block); - -#if defined(SK_BUILD_FOR_MAC) - SkASSERT(alloc == malloc_good_size(alloc)); -#elif defined(SK_BUILD_FOR_UNIX) && !defined(__UCLIBC__) - // TODO(mtklein): tune so we can assert something like this - //SkASSERT(alloc == malloc_usable_size(fBlock)); -#endif } diff --git a/gfx/skia/skia/src/core/SkWriteBuffer.cpp b/gfx/skia/skia/src/core/SkWriteBuffer.cpp index 1dfe0b3972c..f8b31954037 100644 --- a/gfx/skia/skia/src/core/SkWriteBuffer.cpp +++ b/gfx/skia/skia/src/core/SkWriteBuffer.cpp @@ -200,11 +200,8 @@ void SkWriteBuffer::writeBitmap(const SkBitmap& bitmap) { // see if the caller wants to manually encode SkAutoPixmapUnlock result; if (fPixelSerializer && bitmap.requestLock(&result)) { - const SkPixmap& pmap = result.pixmap(); SkASSERT(nullptr == fBitmapHeap); - SkAutoDataUnref data(fPixelSerializer->encodePixels(pmap.info(), - pmap.addr(), - pmap.rowBytes())); + SkAutoDataUnref data(fPixelSerializer->encode(result.pixmap())); if (data.get() != nullptr) { // if we have to "encode" the bitmap, then we assume there is no // offset to share, since we are effectively creating a new pixelref diff --git a/gfx/skia/skia/src/device/xps/SkXPSDevice.cpp b/gfx/skia/skia/src/device/xps/SkXPSDevice.cpp index 86c729c9e40..48233bb5543 100644 --- a/gfx/skia/skia/src/device/xps/SkXPSDevice.cpp +++ b/gfx/skia/skia/src/device/xps/SkXPSDevice.cpp @@ -1628,12 +1628,8 @@ void SkXPSDevice::drawPath(const SkDraw& d, //[Mask -> Mask] SkMask filteredMask; - if (filter && - filter->filterMask(&filteredMask, *mask, *d.fMatrix, nullptr)) { - + if (filter && filter->filterMask(&filteredMask, *mask, *d.fMatrix, nullptr)) { mask = &filteredMask; - } else { - filteredMask.fImage = nullptr; } SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); @@ -1675,13 +1671,8 @@ void SkXPSDevice::drawPath(const SkDraw& d, //[Mask -> Mask] SkMask filteredMask; - if (filter->filterMask(&filteredMask, - rasteredMask, - matrix, - nullptr)) { + if (filter->filterMask(&filteredMask, rasteredMask, matrix, nullptr)) { mask = &filteredMask; - } else { - filteredMask.fImage = nullptr; } SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); diff --git a/gfx/skia/skia/src/doc/SkDocument_PDF.cpp b/gfx/skia/skia/src/doc/SkDocument_PDF.cpp index ff7a038b6bf..fb560ea1e36 100644 --- a/gfx/skia/skia/src/doc/SkDocument_PDF.cpp +++ b/gfx/skia/skia/src/doc/SkDocument_PDF.cpp @@ -322,9 +322,12 @@ class SkDocument_PDF : public SkDocument { public: SkDocument_PDF(SkWStream* stream, void (*doneProc)(SkWStream*, bool), - SkScalar rasterDpi) + SkScalar rasterDpi, + SkPixelSerializer* jpegEncoder) : SkDocument(stream, doneProc) - , fRasterDpi(rasterDpi) {} + , fRasterDpi(rasterDpi) { + fCanon.fPixelSerializer.reset(SkSafeRef(jpegEncoder)); + } virtual ~SkDocument_PDF() { // subclasses must call close() in their destructors @@ -386,7 +389,15 @@ private: /////////////////////////////////////////////////////////////////////////////// SkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) { - return stream ? new SkDocument_PDF(stream, nullptr, dpi) : nullptr; + return stream ? new SkDocument_PDF(stream, nullptr, dpi, nullptr) : nullptr; +} + +SkDocument* SkDocument::CreatePDF(SkWStream* stream, + SkScalar dpi, + SkPixelSerializer* jpegEncoder) { + return stream + ? new SkDocument_PDF(stream, nullptr, dpi, jpegEncoder) + : nullptr; } SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) { @@ -396,5 +407,5 @@ SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) { return nullptr; } auto delete_wstream = [](SkWStream* stream, bool) { delete stream; }; - return new SkDocument_PDF(stream, delete_wstream, dpi); + return new SkDocument_PDF(stream, delete_wstream, dpi, nullptr); } diff --git a/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.cpp b/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.cpp index 8c9d2049286..83faa86fa2d 100644 --- a/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.cpp +++ b/gfx/skia/skia/src/effects/GrCircleBlurFragmentProcessor.cpp @@ -11,12 +11,13 @@ #if SK_SUPPORT_GPU #include "GrContext.h" +#include "GrInvariantOutput.h" #include "GrTextureProvider.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" class GrGLCircleBlurFragmentProcessor : public GrGLSLFragmentProcessor { public: @@ -39,12 +40,12 @@ void GrGLCircleBlurFragmentProcessor::emitCode(EmitArgs& args) { // The data is formatted as: // x,y - the center of the circle // z - the distance at which the intensity starts falling off (e.g., the start of the table) - // w - the size of the profile texture - fDataUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, - kDefault_GrSLPrecision, - "data", - &dataName); + // w - the inverse of the profile texture size + fDataUniform = args.fUniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, + kDefault_GrSLPrecision, + "data", + &dataName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char *fragmentPos = fragBuilder->fragmentPosition(); @@ -55,8 +56,13 @@ void GrGLCircleBlurFragmentProcessor::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("vec4 src=vec4(1);"); } - fragBuilder->codeAppendf("vec2 vec = %s.xy - %s.xy;", fragmentPos, dataName); - fragBuilder->codeAppendf("float dist = (length(vec) - %s.z + 0.5) / %s.w;", dataName, dataName); + // We just want to compute "length(vec) - %s.z + 0.5) * %s.w" but need to rearrange + // for precision + fragBuilder->codeAppendf("vec2 vec = vec2( (%s.x - %s.x) * %s.w , (%s.y - %s.y) * %s.w );", + fragmentPos, dataName, dataName, + fragmentPos, dataName, dataName); + fragBuilder->codeAppendf("float dist = length(vec) + ( 0.5 - %s.z ) * %s.w;", + dataName, dataName); fragBuilder->codeAppendf("float intensity = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "vec2(dist, 0.5)"); @@ -73,9 +79,9 @@ void GrGLCircleBlurFragmentProcessor::onSetData(const GrGLSLProgramDataManager& // The data is formatted as: // x,y - the center of the circle // z - the distance at which the intensity starts falling off (e.g., the start of the table) - // w - the size of the profile texture + // w - the inverse of the profile texture size pdman.set4f(fDataUniform, circle.centerX(), circle.centerY(), cbfp.offset(), - SkIntToScalar(cbfp.profileSize())); + 1.0f / cbfp.profileSize()); } /////////////////////////////////////////////////////////////////////////////// @@ -180,7 +186,7 @@ static inline void compute_profile_offset_and_size(float halfWH, float sigma, // The circle is bigger than the Gaussian. In this case we know the interior of the // blurred circle is solid. *offset = halfWH - 3 * sigma; // This location maps to 0.5f in the weights texture. - // It should always be 255. + // It should always be 255. *size = SkScalarCeilToInt(6*sigma); } else { // The Gaussian is bigger than the circle. diff --git a/gfx/skia/skia/src/effects/SkAlphaThresholdFilter.cpp b/gfx/skia/skia/src/effects/SkAlphaThresholdFilter.cpp index e6f1f088cba..b6be944220d 100644 --- a/gfx/skia/skia/src/effects/SkAlphaThresholdFilter.cpp +++ b/gfx/skia/skia/src/effects/SkAlphaThresholdFilter.cpp @@ -22,6 +22,7 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkAlphaThresholdFilterImpl) + friend void SkAlphaThresholdFilter::InitializeFlattenables(); protected: void flatten(SkWriteBuffer&) const override; @@ -40,6 +41,11 @@ private: typedef SkImageFilter INHERITED; }; +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkAlphaThresholdFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkAlphaThresholdFilterImpl) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END + + SkImageFilter* SkAlphaThresholdFilter::Create(const SkRegion& region, SkScalar innerThreshold, SkScalar outerThreshold, @@ -59,8 +65,8 @@ SkImageFilter* SkAlphaThresholdFilter::Create(const SkRegion& region, #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" class AlphaThresholdEffect : public GrFragmentProcessor { @@ -139,12 +145,13 @@ private: }; void GrGLAlphaThresholdEffect::emitCode(EmitArgs& args) { - fInnerThresholdVar = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "inner_threshold"); - fOuterThresholdVar = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "outer_threshold"); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fInnerThresholdVar = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "inner_threshold"); + fOuterThresholdVar = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "outer_threshold"); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); @@ -160,9 +167,9 @@ void GrGLAlphaThresholdEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppend(";\n"); fragBuilder->codeAppendf("\t\tfloat inner_thresh = %s;\n", - args.fBuilder->getUniformCStr(fInnerThresholdVar)); + uniformHandler->getUniformCStr(fInnerThresholdVar)); fragBuilder->codeAppendf("\t\tfloat outer_thresh = %s;\n", - args.fBuilder->getUniformCStr(fOuterThresholdVar)); + uniformHandler->getUniformCStr(fOuterThresholdVar)); fragBuilder->codeAppend("\t\tfloat mask = mask_color.a;\n"); fragBuilder->codeAppend("vec4 color = input_color;\n"); diff --git a/gfx/skia/skia/src/effects/SkArithmeticMode_gpu.cpp b/gfx/skia/skia/src/effects/SkArithmeticMode_gpu.cpp index a3793243ee6..ce8e426d412 100644 --- a/gfx/skia/skia/src/effects/SkArithmeticMode_gpu.cpp +++ b/gfx/skia/skia/src/effects/SkArithmeticMode_gpu.cpp @@ -15,8 +15,8 @@ #include "GrTexture.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLXferProcessor.h" static const bool gUseUnpremul = false; @@ -65,10 +65,10 @@ public: SkString dstColor("dstColor"); this->emitChild(0, nullptr, &dstColor, args); - fKUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "k"); - const char* kUni = args.fBuilder->getUniformCStr(fKUni); + fKUni = args.fUniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "k"); + const char* kUni = args.fUniformHandler->getUniformCStr(fKUni); add_arithmetic_code(fragBuilder, args.fInputColor, @@ -210,18 +210,18 @@ public: } private: - void emitBlendCodeForDstRead(GrGLSLXPBuilder* pb, - GrGLSLXPFragmentBuilder* fragBuilder, + void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, + GrGLSLUniformHandler* uniformHandler, const char* srcColor, const char* srcCoverage, const char* dstColor, const char* outColor, const char* outColorSecondary, const GrXferProcessor& proc) override { - fKUni = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "k"); - const char* kUni = pb->getUniformCStr(fKUni); + fKUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "k"); + const char* kUni = uniformHandler->getUniformCStr(fKUni); add_arithmetic_code(fragBuilder, srcColor, dstColor, outColor, kUni, fEnforcePMColor); diff --git a/gfx/skia/skia/src/effects/SkBlurImageFilter.cpp b/gfx/skia/skia/src/effects/SkBlurImageFilter.cpp index 928793de62f..a1d6a2f80e0 100644 --- a/gfx/skia/skia/src/effects/SkBlurImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkBlurImageFilter.cpp @@ -15,6 +15,7 @@ #include "SkWriteBuffer.h" #if SK_SUPPORT_GPU #include "GrContext.h" +#include "SkGr.h" #endif // This rather arbitrary-looking value results in a maximum box blur kernel size @@ -24,7 +25,7 @@ // raster paths. #define MAX_SIGMA SkIntToScalar(532) -static SkVector mapSigma(const SkSize& localSigma, const SkMatrix& ctm) { +static SkVector map_sigma(const SkSize& localSigma, const SkMatrix& ctm) { SkVector sigma = SkVector::Make(localSigma.width(), localSigma.height()); ctm.mapVectors(&sigma, 1); sigma.fX = SkMinScalar(SkScalarAbs(sigma.fX), MAX_SIGMA); @@ -82,9 +83,30 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy, } SkIRect srcBounds, dstBounds; - if (!this->applyCropRect(ctx, src, srcOffset, &dstBounds, &srcBounds)) { + if (!this->applyCropRect(this->mapContext(ctx), src, srcOffset, &dstBounds, &srcBounds)) { return false; } + if (!srcBounds.intersect(dstBounds)) { + return false; + } + + SkVector sigma = map_sigma(fSigma, ctx.ctm()); + + int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; + int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; + getBox3Params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX); + getBox3Params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY); + + if (kernelSizeX < 0 || kernelSizeY < 0) { + return false; + } + + if (kernelSizeX == 0 && kernelSizeY == 0) { + src.extractSubset(dst, srcBounds); + offset->fX = srcBounds.x(); + offset->fY = srcBounds.y(); + return true; + } SkAutoLockPixels alp(src); if (!src.getPixels()) { @@ -98,24 +120,6 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy, *dst = device->accessBitmap(false); SkAutoLockPixels alp_dst(*dst); - SkVector sigma = mapSigma(fSigma, ctx.ctm()); - - int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; - int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; - getBox3Params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX); - getBox3Params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY); - - if (kernelSizeX < 0 || kernelSizeY < 0) { - return false; - } - - if (kernelSizeX == 0 && kernelSizeY == 0) { - src.copyTo(dst, dst->colorType()); - offset->fX = dstBounds.x() + srcOffset.x(); - offset->fY = dstBounds.y() + srcOffset.y(); - return true; - } - SkAutoTUnref tempDevice(proxy->createDevice(dst->width(), dst->height())); if (!tempDevice) { return false; @@ -184,17 +188,12 @@ void SkBlurImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const SkScalarMul(fSigma.height(), SkIntToScalar(3))); } -bool SkBlurImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, - SkIRect* dst) const { - SkIRect bounds = src; - SkVector sigma = mapSigma(fSigma, ctm); - bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), - SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); - if (this->getInput(0) && !this->getInput(0)->filterBounds(bounds, ctm, &bounds)) { - return false; - } - *dst = bounds; - return true; +void SkBlurImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst, MapDirection) const { + *dst = src; + SkVector sigma = map_sigma(fSigma, ctm); + dst->outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), + SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); } bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, @@ -206,29 +205,36 @@ bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const return false; } SkIRect srcBounds, dstBounds; - if (!this->applyCropRect(ctx, input, srcOffset, &dstBounds, &srcBounds)) { + if (!this->applyCropRect(this->mapContext(ctx), input, srcOffset, &dstBounds, &srcBounds)) { return false; } - GrTexture* source = input.getTexture(); - SkVector sigma = mapSigma(fSigma, ctx.ctm()); + if (!srcBounds.intersect(dstBounds)) { + return false; + } + SkVector sigma = map_sigma(fSigma, ctx.ctm()); + if (sigma.x() == 0 && sigma.y() == 0) { + input.extractSubset(result, srcBounds); + offset->fX = srcBounds.x(); + offset->fY = srcBounds.y(); + return true; + } offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; srcBounds.offset(-srcOffset); dstBounds.offset(-srcOffset); SkRect srcBoundsF(SkRect::Make(srcBounds)); - auto constraint = GrTextureProvider::FromImageFilter(ctx.sizeConstraint()); - SkAutoTUnref tex(SkGpuBlurUtils::GaussianBlur(source->getContext(), - source, + GrTexture* inputTexture = input.getTexture(); + SkAutoTUnref tex(SkGpuBlurUtils::GaussianBlur(inputTexture->getContext(), + inputTexture, false, SkRect::Make(dstBounds), &srcBoundsF, sigma.x(), - sigma.y(), - constraint)); + sigma.y())); if (!tex) { return false; } - WrapTexture(tex, dstBounds.width(), dstBounds.height(), result); + GrWrapTextureInBitmap(tex, dstBounds.width(), dstBounds.height(), false, result); return true; #else SkDEBUGFAIL("Should not call in GPU-less build"); diff --git a/gfx/skia/skia/src/effects/SkBlurMask.h b/gfx/skia/skia/src/effects/SkBlurMask.h index b6c37fb4619..25f890e2636 100644 --- a/gfx/skia/skia/src/effects/SkBlurMask.h +++ b/gfx/skia/skia/src/effects/SkBlurMask.h @@ -15,14 +15,14 @@ class SkBlurMask { public: - static bool BlurRect(SkScalar sigma, SkMask *dst, const SkRect &src, SkBlurStyle, - SkIPoint *margin = nullptr, - SkMask::CreateMode createMode = - SkMask::kComputeBoundsAndRenderImage_CreateMode); - static bool BlurRRect(SkScalar sigma, SkMask *dst, const SkRRect &src, SkBlurStyle, - SkIPoint *margin = nullptr, - SkMask::CreateMode createMode = - SkMask::kComputeBoundsAndRenderImage_CreateMode); + static bool SK_WARN_UNUSED_RESULT BlurRect(SkScalar sigma, SkMask *dst, const SkRect &src, + SkBlurStyle, SkIPoint *margin = nullptr, + SkMask::CreateMode createMode = + SkMask::kComputeBoundsAndRenderImage_CreateMode); + static bool SK_WARN_UNUSED_RESULT BlurRRect(SkScalar sigma, SkMask *dst, const SkRRect &src, + SkBlurStyle, SkIPoint *margin = nullptr, + SkMask::CreateMode createMode = + SkMask::kComputeBoundsAndRenderImage_CreateMode); // forceQuality will prevent BoxBlur from falling back to the low quality approach when sigma // is very small -- this can be used predict the margin bump ahead of time without completely @@ -30,14 +30,16 @@ public: // but also being able to predict precisely at what pixels the blurred profile of e.g. a // rectangle will lie. - static bool BoxBlur(SkMask* dst, const SkMask& src, - SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, - SkIPoint* margin = nullptr, bool force_quality=false); + static bool SK_WARN_UNUSED_RESULT BoxBlur(SkMask* dst, const SkMask& src, + SkScalar sigma, SkBlurStyle style, SkBlurQuality, + SkIPoint* margin = nullptr, + bool forceQuality = false); // the "ground truth" blur does a gaussian convolution; it's slow // but useful for comparison purposes. - static bool BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src, SkBlurStyle, - SkIPoint* margin = nullptr); + static bool SK_WARN_UNUSED_RESULT BlurGroundTruth(SkScalar sigma, SkMask* dst, + const SkMask& src, + SkBlurStyle, SkIPoint* margin = nullptr); // If radius > 0, return the corresponding sigma, else return 0 static SkScalar ConvertRadiusToSigma(SkScalar radius); diff --git a/gfx/skia/skia/src/effects/SkBlurMaskFilter.cpp b/gfx/skia/skia/src/effects/SkBlurMaskFilter.cpp index 8dd82c5ac36..edd2fa4f695 100644 --- a/gfx/skia/skia/src/effects/SkBlurMaskFilter.cpp +++ b/gfx/skia/skia/src/effects/SkBlurMaskFilter.cpp @@ -24,14 +24,13 @@ #include "GrTexture.h" #include "GrFragmentProcessor.h" #include "GrInvariantOutput.h" -#include "SkGrPixelRef.h" #include "SkDraw.h" #include "effects/GrSimpleTextureEffect.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLTextureSampler.h" +#include "glsl/GrGLSLUniformHandler.h" #endif SkScalar SkBlurMaskFilter::ConvertRadiusToSigma(SkScalar radius) { @@ -353,7 +352,6 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma SkIPoint margin; SkMask srcM, dstM; srcM.fBounds = rrect.rect().roundOut(); - srcM.fImage = nullptr; srcM.fFormat = SkMask::kA8_Format; srcM.fRowBytes = 0; @@ -473,7 +471,6 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, SkIPoint margin; SkMask srcM, dstM; srcM.fBounds = rects[0].roundOut(); - srcM.fImage = nullptr; srcM.fFormat = SkMask::kA8_Format; srcM.fRowBytes = 0; @@ -720,21 +717,22 @@ void GrGLRectBlurEffect::GenKey(GrSLPrecision precision, GrProcessorKeyBuilder* void GrGLRectBlurEffect::emitCode(EmitArgs& args) { + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; const char *rectName; const char *profileSizeName; const char* precisionString = GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, fPrecision); - fProxyRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, - fPrecision, - "proxyRect", - &rectName); - fProfileSizeUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, - kDefault_GrSLPrecision, - "profileSize", - &profileSizeName); + fProxyRectUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, + fPrecision, + "proxyRect", + &rectName); + fProfileSizeUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, + kDefault_GrSLPrecision, + "profileSize", + &profileSizeName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char *fragmentPos = fragBuilder->fragmentPosition(); @@ -988,8 +986,10 @@ const GrFragmentProcessor* GrRRectBlurEffect::Create(GrTextureProvider* texProvi SkMask::kJustRenderImage_CreateMode, SkPaint::kFill_Style); SkMask blurredMask; - SkBlurMask::BoxBlur(&blurredMask, mask, sigma, kNormal_SkBlurStyle, kHigh_SkBlurQuality, - nullptr, true); + if (!SkBlurMask::BoxBlur(&blurredMask, mask, sigma, kNormal_SkBlurStyle, + kHigh_SkBlurQuality, nullptr, true)) { + return nullptr; + } unsigned int texSide = smallRectSide + 2*blurRadius; GrSurfaceDesc texDesc; @@ -1063,24 +1063,25 @@ void GrGLRRectBlurEffect::emitCode(EmitArgs& args) { const char *cornerRadiusName; const char *blurRadiusName; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // The proxy rect has left, top, right, and bottom edges correspond to // components x, y, z, and w, respectively. - fProxyRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, - kDefault_GrSLPrecision, - "proxyRect", - &rectName); - fCornerRadiusUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, - kDefault_GrSLPrecision, - "cornerRadius", - &cornerRadiusName); - fBlurRadiusUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, + fProxyRectUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, - "blurRadius", - &blurRadiusName); + "proxyRect", + &rectName); + fCornerRadiusUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, + kDefault_GrSLPrecision, + "cornerRadius", + &cornerRadiusName); + fBlurRadiusUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, + kDefault_GrSLPrecision, + "blurRadius", + &blurRadiusName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* fragmentPos = fragBuilder->fragmentPosition(); @@ -1239,8 +1240,7 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src, // gaussianBlur. Otherwise, we need to save it for later compositing. bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle); *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc, - clipRect, nullptr, xformedSigma, xformedSigma, - GrTextureProvider::kApprox_SizeConstraint); + clipRect, nullptr, xformedSigma, xformedSigma); if (nullptr == *result) { return false; } diff --git a/gfx/skia/skia/src/effects/SkColorCubeFilter.cpp b/gfx/skia/skia/src/effects/SkColorCubeFilter.cpp index a6f8e78e6e7..5f1f10d53f0 100644 --- a/gfx/skia/skia/src/effects/SkColorCubeFilter.cpp +++ b/gfx/skia/skia/src/effects/SkColorCubeFilter.cpp @@ -20,8 +20,8 @@ #include "SkGr.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #endif /////////////////////////////////////////////////////////////////////////////// @@ -99,7 +99,7 @@ void SkColorCubeFilter::ColorCubeProcesingCache::initProcessingLuts( // We need 256 SkScalar * 2 for fColorToFactors and 256 SkScalar // for fColorToScalar, so a total of 768 SkScalar. cache->fLutStorage.reset(512 * sizeof(int) + 768 * sizeof(SkScalar)); - uint8_t* storage = (uint8_t*)cache->fLutStorage.get(); + uint8_t* storage = cache->fLutStorage.get(); cache->fColorToIndex[0] = (int*)storage; cache->fColorToIndex[1] = cache->fColorToIndex[0] + 256; cache->fColorToFactors[0] = (SkScalar*)(storage + (512 * sizeof(int))); @@ -212,7 +212,7 @@ private: /////////////////////////////////////////////////////////////////////////////// GrColorCubeEffect::GrColorCubeEffect(GrTexture* colorCube) - : fColorCubeAccess(colorCube, "bgra", GrTextureParams::kBilerp_FilterMode) { + : fColorCubeAccess(colorCube, GrTextureParams::kBilerp_FilterMode) { this->initClassID(); this->addTextureAccess(&fColorCubeAccess); } @@ -246,14 +246,15 @@ void GrColorCubeEffect::GLSLProcessor::emitCode(EmitArgs& args) { args.fInputColor = "vec4(1)"; } - fColorCubeSizeUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "Size"); - const char* colorCubeSizeUni = args.fBuilder->getUniformCStr(fColorCubeSizeUni); - fColorCubeInvSizeUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "InvSize"); - const char* colorCubeInvSizeUni = args.fBuilder->getUniformCStr(fColorCubeInvSizeUni); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fColorCubeSizeUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "Size"); + const char* colorCubeSizeUni = uniformHandler->getUniformCStr(fColorCubeSizeUni); + fColorCubeInvSizeUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "InvSize"); + const char* colorCubeInvSizeUni = uniformHandler->getUniformCStr(fColorCubeInvSizeUni); const char* nonZeroAlpha = "nonZeroAlpha"; const char* unPMColor = "unPMColor"; @@ -286,11 +287,11 @@ void GrColorCubeEffect::GLSLProcessor::emitCode(EmitArgs& args) { // Apply the cube. fragBuilder->codeAppendf("%s = vec4(mix(", args.fOutputColor); fragBuilder->appendTextureLookup(args.fSamplers[0], cCoords1); - fragBuilder->codeAppend(".rgb, "); + fragBuilder->codeAppend(".bgr, "); fragBuilder->appendTextureLookup(args.fSamplers[0], cCoords2); // Premultiply color by alpha. Note that the input alpha is not modified by this shader. - fragBuilder->codeAppendf(".rgb, fract(%s.b)) * vec3(%s), %s.a);\n", + fragBuilder->codeAppendf(".bgr, fract(%s.b)) * vec3(%s), %s.a);\n", cubeIdx, nonZeroAlpha, args.fInputColor); } diff --git a/gfx/skia/skia/src/effects/SkColorFilterImageFilter.cpp b/gfx/skia/skia/src/effects/SkColorFilterImageFilter.cpp index 8d394aa17b4..b0e47505a73 100644 --- a/gfx/skia/skia/src/effects/SkColorFilterImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkColorFilterImageFilter.cpp @@ -99,8 +99,11 @@ bool SkColorFilterImageFilter::onIsColorFilterNode(SkColorFilter** filter) const return false; } -bool SkColorFilterImageFilter::affectsTransparentBlack() const { - return fColorFilter->affectsTransparentBlack(); +bool SkColorFilterImageFilter::canComputeFastBounds() const { + if (fColorFilter->affectsTransparentBlack()) { + return false; + } + return INHERITED::canComputeFastBounds(); } #ifndef SK_IGNORE_TO_STRING diff --git a/gfx/skia/skia/src/effects/SkColorMatrixFilter.cpp b/gfx/skia/skia/src/effects/SkColorMatrixFilter.cpp index 6e1c8ddb813..ce6ca5538b6 100644 --- a/gfx/skia/skia/src/effects/SkColorMatrixFilter.cpp +++ b/gfx/skia/skia/src/effects/SkColorMatrixFilter.cpp @@ -33,199 +33,26 @@ static void transpose_to_pmorder(float dst[20], const float src[20]) { } } -static int32_t rowmul4(const int32_t array[], unsigned r, unsigned g, - unsigned b, unsigned a) { - return array[0] * r + array[1] * g + array[2] * b + array[3] * a + array[4]; -} - -static int32_t rowmul3(const int32_t array[], unsigned r, unsigned g, - unsigned b) { - return array[0] * r + array[1] * g + array[2] * b + array[4]; -} - -static void General(const SkColorMatrixFilter::State& state, - unsigned r, unsigned g, unsigned b, unsigned a, - int32_t* SK_RESTRICT result) { - const int32_t* SK_RESTRICT array = state.fArray; - const int shift = state.fShift; - - result[0] = rowmul4(&array[0], r, g, b, a) >> shift; - result[1] = rowmul4(&array[5], r, g, b, a) >> shift; - result[2] = rowmul4(&array[10], r, g, b, a) >> shift; - result[3] = rowmul4(&array[15], r, g, b, a) >> shift; -} - -static void General16(const SkColorMatrixFilter::State& state, - unsigned r, unsigned g, unsigned b, unsigned a, - int32_t* SK_RESTRICT result) { - const int32_t* SK_RESTRICT array = state.fArray; - - result[0] = rowmul4(&array[0], r, g, b, a) >> 16; - result[1] = rowmul4(&array[5], r, g, b, a) >> 16; - result[2] = rowmul4(&array[10], r, g, b, a) >> 16; - result[3] = rowmul4(&array[15], r, g, b, a) >> 16; -} - -static void AffineAdd(const SkColorMatrixFilter::State& state, - unsigned r, unsigned g, unsigned b, unsigned a, - int32_t* SK_RESTRICT result) { - const int32_t* SK_RESTRICT array = state.fArray; - const int shift = state.fShift; - - result[0] = rowmul3(&array[0], r, g, b) >> shift; - result[1] = rowmul3(&array[5], r, g, b) >> shift; - result[2] = rowmul3(&array[10], r, g, b) >> shift; - result[3] = a; -} - -static void AffineAdd16(const SkColorMatrixFilter::State& state, - unsigned r, unsigned g, unsigned b, unsigned a, - int32_t* SK_RESTRICT result) { - const int32_t* SK_RESTRICT array = state.fArray; - - result[0] = rowmul3(&array[0], r, g, b) >> 16; - result[1] = rowmul3(&array[5], r, g, b) >> 16; - result[2] = rowmul3(&array[10], r, g, b) >> 16; - result[3] = a; -} - -static void ScaleAdd(const SkColorMatrixFilter::State& state, - unsigned r, unsigned g, unsigned b, unsigned a, - int32_t* SK_RESTRICT result) { - const int32_t* SK_RESTRICT array = state.fArray; - const int shift = state.fShift; - - // cast to (int) to keep the expression signed for the shift - result[0] = (array[SkColorMatrix::kR_Scale] * (int)r + array[4]) >> shift; - result[1] = (array[SkColorMatrix::kG_Scale] * (int)g + array[9]) >> shift; - result[2] = (array[SkColorMatrix::kB_Scale] * (int)b + array[14]) >> shift; - result[3] = a; -} - -static void ScaleAdd16(const SkColorMatrixFilter::State& state, - unsigned r, unsigned g, unsigned b, unsigned a, - int32_t* SK_RESTRICT result) { - const int32_t* SK_RESTRICT array = state.fArray; - - // cast to (int) to keep the expression signed for the shift - result[0] = (array[SkColorMatrix::kR_Scale] * (int)r + array[4]) >> 16; - result[1] = (array[SkColorMatrix::kG_Scale] * (int)g + array[9]) >> 16; - result[2] = (array[SkColorMatrix::kB_Scale] * (int)b + array[14]) >> 16; - result[3] = a; -} - -static void Add(const SkColorMatrixFilter::State& state, - unsigned r, unsigned g, unsigned b, unsigned a, - int32_t* SK_RESTRICT result) { - const int32_t* SK_RESTRICT array = state.fArray; - const int shift = state.fShift; - - result[0] = r + (array[SkColorMatrix::kR_Trans] >> shift); - result[1] = g + (array[SkColorMatrix::kG_Trans] >> shift); - result[2] = b + (array[SkColorMatrix::kB_Trans] >> shift); - result[3] = a; -} - -static void Add16(const SkColorMatrixFilter::State& state, - unsigned r, unsigned g, unsigned b, unsigned a, - int32_t* SK_RESTRICT result) { - const int32_t* SK_RESTRICT array = state.fArray; - - result[0] = r + (array[SkColorMatrix::kR_Trans] >> 16); - result[1] = g + (array[SkColorMatrix::kG_Trans] >> 16); - result[2] = b + (array[SkColorMatrix::kB_Trans] >> 16); - result[3] = a; -} - // src is [20] but some compilers won't accept __restrict__ on anything // but an raw pointer or reference void SkColorMatrixFilter::initState(const SkScalar* SK_RESTRICT src) { transpose_to_pmorder(fTranspose, src); - int32_t* array = fState.fArray; - SkFixed max = 0; - for (int i = 0; i < 20; i++) { - SkFixed value = SkScalarToFixed(src[i]); - array[i] = value; - value = SkAbs32(value); - max = SkMax32(max, value); - } - - /* All of fArray[] values must fit in 23 bits, to safely allow me to - multiply them by 8bit unsigned values, and get a signed answer without - overflow. This means clz needs to be 9 or bigger - */ - int bits = SkCLZ(max); - int32_t one = SK_Fixed1; - - fState.fShift = 16; // we are starting out as fixed 16.16 - if (bits < 9) { - bits = 9 - bits; - fState.fShift -= bits; - for (int i = 0; i < 20; i++) { - array[i] >>= bits; - } - one >>= bits; - } + const float* array = fMatrix.fMat; // check if we have to munge Alpha - int32_t changesAlpha = (array[15] | array[16] | array[17] | - (array[18] - one) | array[19]); - int32_t usesAlpha = (array[3] | array[8] | array[13]); - bool shiftIs16 = (16 == fState.fShift); + bool changesAlpha = (array[15] || array[16] || array[17] || (array[18] - 1) || array[19]); + bool usesAlpha = (array[3] || array[8] || array[13]); - if (changesAlpha | usesAlpha) { - fProc = shiftIs16 ? General16 : General; + if (changesAlpha || usesAlpha) { fFlags = changesAlpha ? 0 : SkColorFilter::kAlphaUnchanged_Flag; } else { fFlags = SkColorFilter::kAlphaUnchanged_Flag; - - int32_t needsScale = (array[SkColorMatrix::kR_Scale] - one) | - (array[SkColorMatrix::kG_Scale] - one) | - (array[SkColorMatrix::kB_Scale] - one); - - int32_t needs3x3 = array[1] | array[2] | // red off-axis - array[5] | array[7] | // green off-axis - array[10] | array[11]; // blue off-axis - - if (needs3x3) { - fProc = shiftIs16 ? AffineAdd16 : AffineAdd; - } else if (needsScale) { - fProc = shiftIs16 ? ScaleAdd16 : ScaleAdd; - } else if (array[SkColorMatrix::kR_Trans] | - array[SkColorMatrix::kG_Trans] | - array[SkColorMatrix::kB_Trans]) { - fProc = shiftIs16 ? Add16 : Add; - } else { - fProc = nullptr; // identity - } - } - - /* preround our add values so we get a rounded shift. We do this after we - analyze the array, so we don't miss the case where the caller has zeros - which could make us accidentally take the General or Add case. - */ - if (fProc) { - int32_t add = 1 << (fState.fShift - 1); - array[4] += add; - array[9] += add; - array[14] += add; - array[19] += add; } } /////////////////////////////////////////////////////////////////////////////// -static int32_t pin(int32_t value, int32_t max) { - if (value < 0) { - value = 0; - } - if (value > max) { - value = max; - } - return value; -} - SkColorMatrixFilter::SkColorMatrixFilter(const SkColorMatrix& cm) : fMatrix(cm) { this->initState(cm.fMat); } @@ -258,95 +85,45 @@ static Sk4f clamp_0_1(const Sk4f& x) { static SkPMColor round(const Sk4f& x) { SkPMColor c; - (x * Sk4f(255) + Sk4f(0.5f)).toBytes((uint8_t*)&c); + SkNx_cast(x * Sk4f(255) + Sk4f(0.5f)).store((uint8_t*)&c); return c; } void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const { - Proc proc = fProc; - if (nullptr == proc) { - if (src != dst) { - memcpy(dst, src, count * sizeof(SkPMColor)); + // c0-c3 are already in [0,1]. + const Sk4f c0 = Sk4f::Load(fTranspose + 0); + const Sk4f c1 = Sk4f::Load(fTranspose + 4); + const Sk4f c2 = Sk4f::Load(fTranspose + 8); + const Sk4f c3 = Sk4f::Load(fTranspose + 12); + // c4 (the translate vector) is in [0, 255]. Bring it back to [0,1]. + const Sk4f c4 = Sk4f::Load(fTranspose + 16)*Sk4f(1.0f/255); + + // todo: we could cache this in the constructor... + SkPMColor matrix_translate_pmcolor = round(premul(clamp_0_1(c4))); + + for (int i = 0; i < count; i++) { + const SkPMColor src_c = src[i]; + if (0 == src_c) { + dst[i] = matrix_translate_pmcolor; + continue; } - return; - } -#ifdef SK_SUPPORT_LEGACY_INT_COLORMATRIX - const bool use_floats = false; -#else - const bool use_floats = true; -#endif + Sk4f srcf = SkNx_cast(Sk4b::Load((const uint8_t*)&src_c)) * Sk4f(1.0f/255); - if (use_floats) { - // c0-c3 are already in [0,1]. - const Sk4f c0 = Sk4f::Load(fTranspose + 0); - const Sk4f c1 = Sk4f::Load(fTranspose + 4); - const Sk4f c2 = Sk4f::Load(fTranspose + 8); - const Sk4f c3 = Sk4f::Load(fTranspose + 12); - // c4 (the translate vector) is in [0, 255]. Bring it back to [0,1]. - const Sk4f c4 = Sk4f::Load(fTranspose + 16)*Sk4f(1.0f/255); - - // todo: we could cache this in the constructor... - SkPMColor matrix_translate_pmcolor = round(premul(clamp_0_1(c4))); - - for (int i = 0; i < count; i++) { - const SkPMColor src_c = src[i]; - if (0 == src_c) { - dst[i] = matrix_translate_pmcolor; - continue; - } - - Sk4f srcf = Sk4f::FromBytes((const uint8_t*)&src_c) * Sk4f(1.0f/255); - - if (0xFF != SkGetPackedA32(src_c)) { - srcf = unpremul(srcf); - } - - Sk4f r4 = SkNx_dup(srcf); - Sk4f g4 = SkNx_dup(srcf); - Sk4f b4 = SkNx_dup(srcf); - Sk4f a4 = SkNx_dup(srcf); - - // apply matrix - Sk4f dst4 = c0 * r4 + c1 * g4 + c2 * b4 + c3 * a4 + c4; - - // clamp, re-premul, and write - dst[i] = round(premul(clamp_0_1(dst4))); + if (0xFF != SkGetPackedA32(src_c)) { + srcf = unpremul(srcf); } - } else { - const State& state = fState; - int32_t result[4]; - const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); - for (int i = 0; i < count; i++) { - SkPMColor c = src[i]; + Sk4f r4 = SkNx_dup(srcf); + Sk4f g4 = SkNx_dup(srcf); + Sk4f b4 = SkNx_dup(srcf); + Sk4f a4 = SkNx_dup(srcf); - unsigned r = SkGetPackedR32(c); - unsigned g = SkGetPackedG32(c); - unsigned b = SkGetPackedB32(c); - unsigned a = SkGetPackedA32(c); + // apply matrix + Sk4f dst4 = c0 * r4 + c1 * g4 + c2 * b4 + c3 * a4 + c4; - // need our components to be un-premultiplied - if (255 != a) { - SkUnPreMultiply::Scale scale = table[a]; - r = SkUnPreMultiply::ApplyScale(scale, r); - g = SkUnPreMultiply::ApplyScale(scale, g); - b = SkUnPreMultiply::ApplyScale(scale, b); - - SkASSERT(r <= 255); - SkASSERT(g <= 255); - SkASSERT(b <= 255); - } - - proc(state, r, g, b, a, result); - - r = pin(result[0], SK_R32_MASK); - g = pin(result[1], SK_G32_MASK); - b = pin(result[2], SK_B32_MASK); - a = pin(result[3], SK_A32_MASK); - // re-prepremultiply if needed - dst[i] = SkPremultiplyARGBInline(a, r, g, b); - } + // clamp, re-premul, and write + dst[i] = round(premul(clamp_0_1(dst4))); } } @@ -387,8 +164,8 @@ SkColorFilter* SkColorMatrixFilter::newComposed(const SkColorFilter* innerFilter #include "GrInvariantOutput.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" class ColorMatrixEffect : public GrFragmentProcessor { public: @@ -408,12 +185,13 @@ public: GLSLProcessor(const GrProcessor&) {} virtual void emitCode(EmitArgs& args) override { - fMatrixHandle = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kMat44f_GrSLType, kDefault_GrSLPrecision, - "ColorMatrix"); - fVectorHandle = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "ColorMatrixVector"); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fMatrixHandle = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kMat44f_GrSLType, kDefault_GrSLPrecision, + "ColorMatrix"); + fVectorHandle = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "ColorMatrixVector"); if (nullptr == args.fInputColor) { // could optimize this case, but we aren't for now. @@ -426,9 +204,9 @@ public: args.fInputColor); fragBuilder->codeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n", args.fOutputColor, - args.fBuilder->getUniformCStr(fMatrixHandle), + uniformHandler->getUniformCStr(fMatrixHandle), args.fInputColor, - args.fBuilder->getUniformCStr(fVectorHandle)); + uniformHandler->getUniformCStr(fVectorHandle)); fragBuilder->codeAppendf("\t%s = clamp(%s, 0.0, 1.0);\n", args.fOutputColor, args.fOutputColor); fragBuilder->codeAppendf("\t%s.rgb *= %s.a;\n", args.fOutputColor, args.fOutputColor); @@ -560,3 +338,27 @@ void SkColorMatrixFilter::toString(SkString* str) const { str->append(")"); } #endif + +/////////////////////////////////////////////////////////////////////////////// + +static SkScalar byte_to_scale(U8CPU byte) { + if (0xFF == byte) { + // want to get this exact + return 1; + } else { + return byte * 0.00392156862745f; + } +} + +SkColorFilter* SkColorMatrixFilter::CreateLightingFilter(SkColor mul, SkColor add) { + SkColorMatrix matrix; + matrix.setScale(byte_to_scale(SkColorGetR(mul)), + byte_to_scale(SkColorGetG(mul)), + byte_to_scale(SkColorGetB(mul)), + 1); + matrix.postTranslate(SkIntToScalar(SkColorGetR(add)), + SkIntToScalar(SkColorGetG(add)), + SkIntToScalar(SkColorGetB(add)), + 0); + return SkColorMatrixFilter::Create(matrix); +} diff --git a/gfx/skia/skia/src/effects/SkComposeImageFilter.cpp b/gfx/skia/skia/src/effects/SkComposeImageFilter.cpp index 1be03a33708..a922d30d1e6 100644 --- a/gfx/skia/skia/src/effects/SkComposeImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkComposeImageFilter.cpp @@ -35,8 +35,10 @@ bool SkComposeImageFilter::onFilterImage(Proxy* proxy, SkMatrix outerMatrix(ctx.ctm()); outerMatrix.postTranslate(SkIntToScalar(-innerOffset.x()), SkIntToScalar(-innerOffset.y())); - Context outerContext(outerMatrix, ctx.clipBounds(), ctx.cache(), ctx.sizeConstraint()); - if (!this->filterInput(0, proxy, tmp, outerContext, result, &outerOffset, false)) { + SkIRect clipBounds = ctx.clipBounds(); + clipBounds.offset(-innerOffset.x(), -innerOffset.y()); + Context outerContext(outerMatrix, clipBounds, ctx.cache()); + if (!this->filterInput(0, proxy, tmp, outerContext, result, &outerOffset)) { return false; } diff --git a/gfx/skia/skia/src/effects/SkDisplacementMapEffect.cpp b/gfx/skia/skia/src/effects/SkDisplacementMapEffect.cpp index fe918581c42..30f980a5c63 100644 --- a/gfx/skia/skia/src/effects/SkDisplacementMapEffect.cpp +++ b/gfx/skia/skia/src/effects/SkDisplacementMapEffect.cpp @@ -16,11 +16,12 @@ #include "GrDrawContext.h" #include "GrCoordTransform.h" #include "GrInvariantOutput.h" +#include "SkGr.h" #include "effects/GrTextureDomain.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #endif namespace { @@ -164,12 +165,12 @@ bool channel_selector_type_is_valid(SkDisplacementMapEffect::ChannelSelectorType /////////////////////////////////////////////////////////////////////////////// -SkDisplacementMapEffect* SkDisplacementMapEffect::Create(ChannelSelectorType xChannelSelector, - ChannelSelectorType yChannelSelector, - SkScalar scale, - SkImageFilter* displacement, - SkImageFilter* color, - const CropRect* cropRect) { +SkImageFilter* SkDisplacementMapEffect::Create(ChannelSelectorType xChannelSelector, + ChannelSelectorType yChannelSelector, + SkScalar scale, + SkImageFilter* displacement, + SkImageFilter* color, + const CropRect* cropRect) { if (!channel_selector_type_is_valid(xChannelSelector) || !channel_selector_type_is_valid(yChannelSelector)) { return nullptr; @@ -268,16 +269,22 @@ void SkDisplacementMapEffect::computeFastBounds(const SkRect& src, SkRect* dst) } else { *dst = src; } - dst->outset(fScale * SK_ScalarHalf, fScale * SK_ScalarHalf); + dst->outset(SkScalarAbs(fScale) * SK_ScalarHalf, SkScalarAbs(fScale) * SK_ScalarHalf); +} + +void SkDisplacementMapEffect::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst, MapDirection) const { + *dst = src; + SkVector scale = SkVector::Make(fScale, fScale); + ctm.mapVectors(&scale, 1); + dst->outset(SkScalarCeilToInt(SkScalarAbs(scale.fX) * SK_ScalarHalf), + SkScalarCeilToInt(SkScalarAbs(scale.fY) * SK_ScalarHalf)); } bool SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { - SkIRect bounds = src; - SkVector scale = SkVector::Make(fScale, fScale); - ctm.mapVectors(&scale, 1); - bounds.outset(SkScalarCeilToInt(scale.fX * SK_ScalarHalf), - SkScalarCeilToInt(scale.fY * SK_ScalarHalf)); + SkIRect bounds; + this->onFilterNodeBounds(src, ctm, &bounds, kReverse_MapDirection); if (this->getColorInput()) { return this->getColorInput()->filterBounds(bounds, ctm, dst); } @@ -422,8 +429,7 @@ bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; - auto constraint = GrTextureProvider::FromImageFilter(ctx.sizeConstraint()); - SkAutoTUnref dst(context->textureProvider()->createTexture(desc, constraint)); + SkAutoTUnref dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; @@ -460,7 +466,7 @@ bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(colorBounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); - WrapTexture(dst, bounds.width(), bounds.height(), result); + GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; } @@ -549,9 +555,9 @@ GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() { void GrGLDisplacementMapEffect::emitCode(EmitArgs& args) { const GrTextureDomain& domain = args.fFp.cast().domain(); - fScaleUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, "Scale"); - const char* scaleUni = args.fBuilder->getUniformCStr(fScaleUni); + fScaleUni = args.fUniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, "Scale"); + const char* scaleUni = args.fUniformHandler->getUniformCStr(fScaleUni); const char* dColor = "dColor"; const char* cCoords = "cCoords"; const char* nearZero = "1e-6"; // Since 6.10352e−5 is the smallest half float, use @@ -610,6 +616,7 @@ void GrGLDisplacementMapEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppend("-vec2(0.5));\t\t"); fGLDomain.sampleTexture(fragBuilder, + args.fUniformHandler, args.fGLSLCaps, domain, args.fOutputColor, diff --git a/gfx/skia/skia/src/effects/SkDropShadowImageFilter.cpp b/gfx/skia/skia/src/effects/SkDropShadowImageFilter.cpp index 7519d5313d0..eb05cf09eca 100644 --- a/gfx/skia/skia/src/effects/SkDropShadowImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkDropShadowImageFilter.cpp @@ -116,25 +116,23 @@ void SkDropShadowImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) } } -bool SkDropShadowImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, - SkIRect* dst) const { - SkIRect bounds = src; +void SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst, MapDirection direction) const { + *dst = src; SkVector offsetVec = SkVector::Make(fDx, fDy); + if (kReverse_MapDirection == direction) { + offsetVec.negate(); + } ctm.mapVectors(&offsetVec, 1); - bounds.offset(-SkScalarCeilToInt(offsetVec.x()), - -SkScalarCeilToInt(offsetVec.y())); + dst->offset(SkScalarCeilToInt(offsetVec.x()), + SkScalarCeilToInt(offsetVec.y())); SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); ctm.mapVectors(&sigma, 1); - bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), - SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); + dst->outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), + SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { - bounds.join(src); + dst->join(src); } - if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { - return false; - } - *dst = bounds; - return true; } #ifndef SK_IGNORE_TO_STRING diff --git a/gfx/skia/skia/src/effects/SkEmbossMaskFilter.cpp b/gfx/skia/skia/src/effects/SkEmbossMaskFilter.cpp index 2607e255d9a..64afa49447d 100644 --- a/gfx/skia/skia/src/effects/SkEmbossMaskFilter.cpp +++ b/gfx/skia/skia/src/effects/SkEmbossMaskFilter.cpp @@ -13,7 +13,7 @@ #include "SkWriteBuffer.h" #include "SkString.h" -SkEmbossMaskFilter* SkEmbossMaskFilter::Create(SkScalar blurSigma, const Light& light) { +SkMaskFilter* SkEmbossMaskFilter::Create(SkScalar blurSigma, const Light& light) { return new SkEmbossMaskFilter(blurSigma, light); } diff --git a/gfx/skia/skia/src/effects/SkGpuBlurUtils.cpp b/gfx/skia/skia/src/effects/SkGpuBlurUtils.cpp index 8ab05dd8621..77a85018778 100644 --- a/gfx/skia/skia/src/effects/SkGpuBlurUtils.cpp +++ b/gfx/skia/skia/src/effects/SkGpuBlurUtils.cpp @@ -60,21 +60,21 @@ static void convolve_gaussian_1d(GrDrawContext* drawContext, texture, direction, radius, sigma, useBounds, bounds)); paint.addColorFragmentProcessor(conv); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); - SkMatrix localMatrix = SkMatrix::MakeTrans(srcOffset.x(), srcOffset.y()); + SkMatrix localMatrix = SkMatrix::MakeTrans(-srcOffset.x(), -srcOffset.y()); drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix); } static void convolve_gaussian_2d(GrDrawContext* drawContext, const GrClip& clip, - const SkRect& srcRect, + const SkRect& dstRect, + const SkPoint& srcOffset, GrTexture* texture, int radiusX, int radiusY, SkScalar sigmaX, SkScalar sigmaY, const SkRect* srcBounds) { - SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); - SkMatrix localMatrix = SkMatrix::MakeTrans(srcRect.x(), srcRect.y()); + SkMatrix localMatrix = SkMatrix::MakeTrans(-srcOffset.x(), -srcOffset.y()); SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); GrPaint paint; @@ -148,15 +148,15 @@ static void convolve_gaussian(GrDrawContext* drawContext, } if (midRect.isEmpty()) { // Blur radius covers srcBounds; use bounds over entire draw - convolve_gaussian_1d(drawContext, clip, dstRect, -srcOffset, texture, + convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, direction, radius, sigma, true, bounds); } else { // Draw right and left margins with bounds; middle without. - convolve_gaussian_1d(drawContext, clip, leftRect, -srcOffset, texture, + convolve_gaussian_1d(drawContext, clip, leftRect, srcOffset, texture, direction, radius, sigma, true, bounds); - convolve_gaussian_1d(drawContext, clip, rightRect, -srcOffset, texture, + convolve_gaussian_1d(drawContext, clip, rightRect, srcOffset, texture, direction, radius, sigma, true, bounds); - convolve_gaussian_1d(drawContext, clip, midRect, -srcOffset, texture, + convolve_gaussian_1d(drawContext, clip, midRect, srcOffset, texture, direction, radius, sigma, false, bounds); } } @@ -167,8 +167,7 @@ GrTexture* GaussianBlur(GrContext* context, const SkRect& dstBounds, const SkRect* srcBounds, float sigmaX, - float sigmaY, - GrTextureProvider::SizeConstraint constraint) { + float sigmaY) { SkASSERT(context); SkIRect clearRect; int scaleFactorX, radiusX; @@ -211,12 +210,12 @@ GrTexture* GaussianBlur(GrContext* context, GrTexture* tempTexture; SkAutoTUnref temp1, temp2; - temp1.reset(context->textureProvider()->createTexture(desc, constraint)); + temp1.reset(context->textureProvider()->createApproxTexture(desc)); dstTexture = temp1.get(); if (canClobberSrc) { tempTexture = srcTexture; } else { - temp2.reset(context->textureProvider()->createTexture(desc, constraint)); + temp2.reset(context->textureProvider()->createApproxTexture(desc)); tempTexture = temp2.get(); } @@ -269,6 +268,7 @@ GrTexture* GaussianBlur(GrContext* context, // 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 @@ -279,7 +279,7 @@ GrTexture* GaussianBlur(GrContext* context, if (!dstDrawContext) { return nullptr; } - convolve_gaussian_2d(dstDrawContext, clip, srcRect, + convolve_gaussian_2d(dstDrawContext, clip, srcRect, srcOffset, srcTexture, radiusX, radiusY, sigmaX, sigmaY, srcBounds); srcDrawContext.swap(dstDrawContext); @@ -288,7 +288,6 @@ GrTexture* GaussianBlur(GrContext* context, SkTSwap(dstTexture, tempTexture); } else { - srcRect = localDstBounds; scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); srcRect.roundOut(&srcRect); const SkIRect srcIRect = srcRect.roundOut(); diff --git a/gfx/skia/skia/src/effects/SkGpuBlurUtils.h b/gfx/skia/skia/src/effects/SkGpuBlurUtils.h index 84e3252cc2a..013d11b5172 100644 --- a/gfx/skia/skia/src/effects/SkGpuBlurUtils.h +++ b/gfx/skia/skia/src/effects/SkGpuBlurUtils.h @@ -40,8 +40,7 @@ namespace SkGpuBlurUtils { const SkRect& dstBounds, const SkRect* srcBounds, float sigmaX, - float sigmaY, - GrTextureProvider::SizeConstraint); + float sigmaY); #endif }; diff --git a/gfx/skia/skia/src/effects/SkLightingImageFilter.cpp b/gfx/skia/skia/src/effects/SkLightingImageFilter.cpp index 9b6a20f0efb..f701b4c8945 100644 --- a/gfx/skia/skia/src/effects/SkLightingImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkLightingImageFilter.cpp @@ -20,11 +20,12 @@ #include "GrFragmentProcessor.h" #include "GrInvariantOutput.h" #include "GrPaint.h" +#include "SkGr.h" #include "effects/GrSingleTextureEffect.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" class GrGLDiffuseLightingEffect; class GrGLSpecularLightingEffect; @@ -383,8 +384,7 @@ bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy, desc.fHeight = bounds.height(); desc.fConfig = kRGBA_8888_GrPixelConfig; - auto constraint = GrTextureProvider::FromImageFilter(ctx.sizeConstraint()); - SkAutoTUnref dst(context->textureProvider()->createTexture(desc, constraint)); + SkAutoTUnref dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } @@ -425,7 +425,7 @@ bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy, this->drawRect(drawContext, srcTexture, matrix, clip, bottom, kBottom_BoundaryMode, bounds); this->drawRect(drawContext, srcTexture, matrix, clip, bottomRight, kBottomRight_BoundaryMode, bounds); - WrapTexture(dst, bounds.width(), bounds.height(), result); + GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; } #endif @@ -599,7 +599,7 @@ public: * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions * below. It adds a vec3f uniform visible in the FS that represents the constant light color. */ - void emitLightColorUniform(GrGLSLFPBuilder*); + void emitLightColorUniform(GrGLSLUniformHandler*); /** * These two functions are called from GrGLLightingEffect's emitCode() function. @@ -609,8 +609,10 @@ public: * the FS. The default of emitLightColor appends the name of the constant light color uniform * and so this function only needs to be overridden if the light color varies spatially. */ - virtual void emitSurfaceToLight(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, const char* z) = 0; - virtual void emitLightColor(GrGLSLFPBuilder*, + virtual void emitSurfaceToLight(GrGLSLUniformHandler*, + GrGLSLFragmentBuilder*, + const char* z) = 0; + virtual void emitLightColor(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char *surfaceToLight); @@ -637,7 +639,7 @@ class GrGLDistantLight : public GrGLLight { public: virtual ~GrGLDistantLight() {} void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override; - void emitSurfaceToLight(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, const char* z) override; + void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override; private: typedef GrGLLight INHERITED; @@ -650,7 +652,7 @@ class GrGLPointLight : public GrGLLight { public: virtual ~GrGLPointLight() {} void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override; - void emitSurfaceToLight(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, const char* z) override; + void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override; private: typedef GrGLLight INHERITED; @@ -663,8 +665,8 @@ class GrGLSpotLight : public GrGLLight { public: virtual ~GrGLSpotLight() {} void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override; - void emitSurfaceToLight(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, const char* z) override; - void emitLightColor(GrGLSLFPBuilder*, + void emitSurfaceToLight(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char* z) override; + void emitLightColor(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, const char *surfaceToLight) override; @@ -1528,7 +1530,9 @@ protected: */ void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; - virtual void emitLightFunc(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, SkString* funcName) = 0; + virtual void emitLightFunc(GrGLSLUniformHandler*, + GrGLSLFragmentBuilder*, + SkString* funcName) = 0; private: typedef GrGLSLFragmentProcessor INHERITED; @@ -1544,7 +1548,7 @@ private: class GrGLDiffuseLightingEffect : public GrGLLightingEffect { public: GrGLDiffuseLightingEffect(const GrProcessor&); - void emitLightFunc(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, SkString* funcName) override; + void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, SkString* funcName) override; protected: void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; @@ -1560,7 +1564,7 @@ private: class GrGLSpecularLightingEffect : public GrGLLightingEffect { public: GrGLSpecularLightingEffect(const GrProcessor&); - void emitLightFunc(GrGLSLFPBuilder*, GrGLSLFragmentBuilder*, SkString* funcName) override; + void emitLightFunc(GrGLSLUniformHandler*, GrGLSLFragmentBuilder*, SkString* funcName) override; protected: void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; @@ -1657,16 +1661,17 @@ GrGLLightingEffect::~GrGLLightingEffect() { } void GrGLLightingEffect::emitCode(EmitArgs& args) { - fImageIncrementUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "ImageIncrement"); - fSurfaceScaleUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "SurfaceScale"); - fLight->emitLightColorUniform(args.fBuilder); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fImageIncrementUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "ImageIncrement"); + fSurfaceScaleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "SurfaceScale"); + fLight->emitLightColorUniform(uniformHandler); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString lightFunc; - this->emitLightFunc(args.fBuilder, fragBuilder, &lightFunc); + this->emitLightFunc(uniformHandler, fragBuilder, &lightFunc); static const GrGLSLShaderVar gSobelArgs[] = { GrGLSLShaderVar("a", kFloat_GrSLType), GrGLSLShaderVar("b", kFloat_GrSLType), @@ -1716,8 +1721,8 @@ void GrGLLightingEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str()); fragBuilder->codeAppend("\t\tfloat m[9];\n"); - const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni); - const char* surfScale = args.fBuilder->getUniformCStr(fSurfaceScaleUni); + const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); + const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni); int index = 0; for (int dy = 1; dy >= -1; dy--) { @@ -1732,11 +1737,11 @@ void GrGLLightingEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppend("\t\tvec3 surfaceToLight = "); SkString arg; arg.appendf("%s * m[4]", surfScale); - fLight->emitSurfaceToLight(args.fBuilder, fragBuilder, arg.c_str()); + fLight->emitSurfaceToLight(uniformHandler, fragBuilder, arg.c_str()); fragBuilder->codeAppend(";\n"); fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ", args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale); - fLight->emitLightColor(args.fBuilder, fragBuilder, "surfaceToLight"); + fLight->emitLightColor(uniformHandler, fragBuilder, "surfaceToLight"); fragBuilder->codeAppend(");\n"); SkString modulate; GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); @@ -1769,11 +1774,11 @@ GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc) : INHERITED(proc) { } -void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLFPBuilder* builder, +void GrGLDiffuseLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler, GrGLSLFragmentBuilder* fragBuilder, SkString* funcName) { const char* kd; - fKDUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, + fKDUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "KD", &kd); @@ -1853,19 +1858,19 @@ GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc) : INHERITED(proc) { } -void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLFPBuilder* builder, +void GrGLSpecularLightingEffect::emitLightFunc(GrGLSLUniformHandler* uniformHandler, GrGLSLFragmentBuilder* fragBuilder, SkString* funcName) { const char* ks; const char* shininess; - fKSUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks); - fShininessUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, - kDefault_GrSLPrecision, - "Shininess", - &shininess); + fKSUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks); + fShininessUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, + kDefault_GrSLPrecision, + "Shininess", + &shininess); static const GrGLSLShaderVar gLightArgs[] = { GrGLSLShaderVar("normal", kVec3f_GrSLType), @@ -1894,16 +1899,16 @@ void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman } /////////////////////////////////////////////////////////////////////////////// -void GrGLLight::emitLightColorUniform(GrGLSLFPBuilder* builder) { - fColorUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "LightColor"); +void GrGLLight::emitLightColorUniform(GrGLSLUniformHandler* uniformHandler) { + fColorUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, kDefault_GrSLPrecision, + "LightColor"); } -void GrGLLight::emitLightColor(GrGLSLFPBuilder* builder, +void GrGLLight::emitLightColor(GrGLSLUniformHandler* uniformHandler, GrGLSLFragmentBuilder* fragBuilder, const char *surfaceToLight) { - fragBuilder->codeAppend(builder->getUniformCStr(this->lightColorUni())); + fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni())); } void GrGLLight::setData(const GrGLSLProgramDataManager& pdman, @@ -1922,13 +1927,13 @@ void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman, setUniformNormal3(pdman, fDirectionUni, distantLight->direction()); } -void GrGLDistantLight::emitSurfaceToLight(GrGLSLFPBuilder* builder, +void GrGLDistantLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler, GrGLSLFragmentBuilder* fragBuilder, const char* z) { const char* dir; - fDirectionUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "LightDirection", &dir); + fDirectionUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, kDefault_GrSLPrecision, + "LightDirection", &dir); fragBuilder->codeAppend(dir); } @@ -1942,13 +1947,13 @@ void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman, setUniformPoint3(pdman, fLocationUni, pointLight->location()); } -void GrGLPointLight::emitSurfaceToLight(GrGLSLFPBuilder* builder, +void GrGLPointLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler, GrGLSLFragmentBuilder* fragBuilder, const char* z) { const char* loc; - fLocationUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "LightLocation", &loc); + fLocationUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, kDefault_GrSLPrecision, + "LightLocation", &loc); fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, fragBuilder->fragmentPosition(), z); } @@ -1968,43 +1973,43 @@ void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman, setUniformNormal3(pdman, fSUni, spotLight->s()); } -void GrGLSpotLight::emitSurfaceToLight(GrGLSLFPBuilder* builder, +void GrGLSpotLight::emitSurfaceToLight(GrGLSLUniformHandler* uniformHandler, GrGLSLFragmentBuilder* fragBuilder, const char* z) { const char* location; - fLocationUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "LightLocation", &location); + fLocationUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, kDefault_GrSLPrecision, + "LightLocation", &location); fragBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))", location, fragBuilder->fragmentPosition(), z); } -void GrGLSpotLight::emitLightColor(GrGLSLFPBuilder* builder, +void GrGLSpotLight::emitLightColor(GrGLSLUniformHandler* uniformHandler, GrGLSLFragmentBuilder* fragBuilder, const char *surfaceToLight) { - const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class. + const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class. const char* exponent; const char* cosInner; const char* cosOuter; const char* coneScale; const char* s; - fExponentUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "Exponent", &exponent); - fCosInnerConeAngleUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "CosInnerConeAngle", &cosInner); - fCosOuterConeAngleUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "CosOuterConeAngle", &cosOuter); - fConeScaleUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "ConeScale", &coneScale); - fSUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s); + fExponentUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "Exponent", &exponent); + fCosInnerConeAngleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "CosInnerConeAngle", &cosInner); + fCosOuterConeAngleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "CosOuterConeAngle", &cosOuter); + fConeScaleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "ConeScale", &coneScale); + fSUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s); static const GrGLSLShaderVar gLightColorArgs[] = { GrGLSLShaderVar("surfaceToLight", kVec3f_GrSLType) diff --git a/gfx/skia/skia/src/effects/SkLumaColorFilter.cpp b/gfx/skia/skia/src/effects/SkLumaColorFilter.cpp index a131b0f4345..acdebf8418b 100644 --- a/gfx/skia/skia/src/effects/SkLumaColorFilter.cpp +++ b/gfx/skia/skia/src/effects/SkLumaColorFilter.cpp @@ -15,7 +15,6 @@ #include "GrInvariantOutput.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #endif void SkLumaColorFilter::filterSpan(const SkPMColor src[], int count, diff --git a/gfx/skia/skia/src/effects/SkMagnifierImageFilter.cpp b/gfx/skia/skia/src/effects/SkMagnifierImageFilter.cpp index 911294444ab..45f630a0858 100644 --- a/gfx/skia/skia/src/effects/SkMagnifierImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkMagnifierImageFilter.cpp @@ -19,8 +19,8 @@ #include "effects/GrSingleTextureEffect.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" class GrMagnifierEffect : public GrSingleTextureEffect { @@ -120,31 +120,32 @@ GrGLMagnifierEffect::GrGLMagnifierEffect(const GrProcessor&) { } void GrGLMagnifierEffect::emitCode(EmitArgs& args) { - fOffsetVar = args.fBuilder->addUniform( - GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, "Offset"); - fInvZoomVar = args.fBuilder->addUniform( - GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, "InvZoom"); - fInvInsetVar = args.fBuilder->addUniform( - GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, "InvInset"); - fBoundsVar = args.fBuilder->addUniform( - GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, "Bounds"); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fOffsetVar = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "Offset"); + fInvZoomVar = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "InvZoom"); + fInvInsetVar = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "InvInset"); + fBoundsVar = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "Bounds"); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str()); fragBuilder->codeAppendf("\t\tvec2 zoom_coord = %s + %s * %s;\n", - args.fBuilder->getUniformCStr(fOffsetVar), + uniformHandler->getUniformCStr(fOffsetVar), coords2D.c_str(), - args.fBuilder->getUniformCStr(fInvZoomVar)); - const char* bounds = args.fBuilder->getUniformCStr(fBoundsVar); + uniformHandler->getUniformCStr(fInvZoomVar)); + const char* bounds = uniformHandler->getUniformCStr(fBoundsVar); fragBuilder->codeAppendf("\t\tvec2 delta = (coord - %s.xy) * %s.zw;\n", bounds, bounds); fragBuilder->codeAppendf("\t\tdelta = min(delta, vec2(1.0, 1.0) - delta);\n"); fragBuilder->codeAppendf("\t\tdelta = delta * %s;\n", - args.fBuilder->getUniformCStr(fInvInsetVar)); + uniformHandler->getUniformCStr(fInvInsetVar)); fragBuilder->codeAppend("\t\tfloat weight = 0.0;\n"); fragBuilder->codeAppend("\t\tif (delta.s < 2.0 && delta.t < 2.0) {\n"); diff --git a/gfx/skia/skia/src/effects/SkMatrixConvolutionImageFilter.cpp b/gfx/skia/skia/src/effects/SkMatrixConvolutionImageFilter.cpp index e58eec10f4e..a80ba45fdbf 100644 --- a/gfx/skia/skia/src/effects/SkMatrixConvolutionImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkMatrixConvolutionImageFilter.cpp @@ -47,7 +47,7 @@ SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter( SkASSERT(kernelOffset.fY >= 0 && kernelOffset.fY < kernelSize.fHeight); } -SkMatrixConvolutionImageFilter* SkMatrixConvolutionImageFilter::Create( +SkImageFilter* SkMatrixConvolutionImageFilter::Create( const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, @@ -280,7 +280,7 @@ bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy, } SkIRect bounds; - if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) { + if (!this->applyCropRect(this->mapContext(ctx), proxy, src, &srcOffset, &bounds, &src)) { return false; } @@ -322,17 +322,23 @@ bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy, return true; } -bool SkMatrixConvolutionImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, - SkIRect* dst) const { - SkIRect bounds = src; - bounds.fRight += fKernelSize.width() - 1; - bounds.fBottom += fKernelSize.height() - 1; - bounds.offset(-fKernelOffset); - if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { - return false; +void SkMatrixConvolutionImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst, MapDirection direction) const { + *dst = src; + int w = fKernelSize.width() - 1, h = fKernelSize.height() - 1; + dst->fRight += w; + dst->fBottom += h; + if (kReverse_MapDirection == direction) { + dst->offset(-fKernelOffset); + } else { + dst->offset(fKernelOffset - SkIPoint::Make(w, h)); } - *dst = bounds; - return true; +} + +bool SkMatrixConvolutionImageFilter::canComputeFastBounds() const { + // Because the kernel is applied in device-space, we have no idea what + // pixels it will affect in object-space. + return false; } #if SK_SUPPORT_GPU diff --git a/gfx/skia/skia/src/effects/SkMorphologyImageFilter.cpp b/gfx/skia/skia/src/effects/SkMorphologyImageFilter.cpp index 484ed57f37b..3f6bc947cfc 100644 --- a/gfx/skia/skia/src/effects/SkMorphologyImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkMorphologyImageFilter.cpp @@ -18,11 +18,12 @@ #include "GrDrawContext.h" #include "GrInvariantOutput.h" #include "GrTexture.h" +#include "SkGr.h" #include "effects/Gr1DKernelEffect.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #endif SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, @@ -70,7 +71,7 @@ bool SkMorphologyImageFilter::filterImageGeneric(SkMorphologyImageFilter::Proc p } SkIRect bounds; - if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) { + if (!this->applyCropRect(this->mapContext(ctx), proxy, src, &srcOffset, &bounds, &src)) { return false; } @@ -149,18 +150,13 @@ void SkMorphologyImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) dst->outset(SkIntToScalar(fRadius.width()), SkIntToScalar(fRadius.height())); } -bool SkMorphologyImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, - SkIRect* dst) const { - SkIRect bounds = src; +void SkMorphologyImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst, MapDirection) const { + *dst = src; SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()), SkIntToScalar(this->radius().height())); ctm.mapVectors(&radius, 1); - bounds.outset(SkScalarCeilToInt(radius.x()), SkScalarCeilToInt(radius.y())); - if (this->getInput(0) && !this->getInput(0)->filterBounds(bounds, ctm, &bounds)) { - return false; - } - *dst = bounds; - return true; + dst->outset(SkScalarCeilToInt(radius.x()), SkScalarCeilToInt(radius.y())); } SkFlattenable* SkErodeImageFilter::CreateProc(SkReadBuffer& buffer) { @@ -288,14 +284,15 @@ GrGLMorphologyEffect::GrGLMorphologyEffect(const GrProcessor& proc) { } void GrGLMorphologyEffect::emitCode(EmitArgs& args) { - fPixelSizeUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "PixelSize"); - const char* pixelSizeInc = args.fBuilder->getUniformCStr(fPixelSizeUni); - fRangeUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "Range"); - const char* range = args.fBuilder->getUniformCStr(fRangeUni); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fPixelSizeUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "PixelSize"); + const char* pixelSizeInc = uniformHandler->getUniformCStr(fPixelSizeUni); + fRangeUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "Range"); + const char* range = uniformHandler->getUniformCStr(fRangeUni); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); @@ -552,8 +549,7 @@ bool apply_morphology(const SkBitmap& input, const SkIRect& rect, GrMorphologyEffect::MorphologyType morphType, SkISize radius, - SkBitmap* dst, - GrTextureProvider::SizeConstraint constraint) { + SkBitmap* dst) { SkAutoTUnref srcTexture(SkRef(input.getTexture())); SkASSERT(srcTexture); GrContext* context = srcTexture->getContext(); @@ -571,14 +567,7 @@ bool apply_morphology(const SkBitmap& input, SkIRect srcRect = rect; if (radius.fWidth > 0) { - GrTextureProvider::SizeConstraint horiConstraint = constraint; - if (radius.fHeight > 0) { - // Optimization: we will fall through and allocate the "real" texture after this one - // so ours can be approximate (likely faster to allocate) - horiConstraint = GrTextureProvider::kApprox_SizeConstraint; - } - - GrTexture* scratch = context->textureProvider()->createTexture(desc, horiConstraint); + GrTexture* scratch = context->textureProvider()->createApproxTexture(desc); if (nullptr == scratch) { return false; } @@ -602,7 +591,7 @@ bool apply_morphology(const SkBitmap& input, srcRect = dstRect; } if (radius.fHeight > 0) { - GrTexture* scratch = context->textureProvider()->createTexture(desc, constraint); + GrTexture* scratch = context->textureProvider()->createApproxTexture(desc); if (nullptr == scratch) { return false; } @@ -618,7 +607,7 @@ bool apply_morphology(const SkBitmap& input, srcTexture.reset(scratch); } - SkImageFilter::WrapTexture(srcTexture, rect.width(), rect.height(), dst); + GrWrapTextureInBitmap(srcTexture, rect.width(), rect.height(), false, dst); return true; } @@ -636,7 +625,7 @@ bool SkMorphologyImageFilter::filterImageGPUGeneric(bool dilate, return false; } SkIRect bounds; - if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { + if (!this->applyCropRect(this->mapContext(ctx), proxy, input, &srcOffset, &bounds, &input)) { return false; } SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()), @@ -660,8 +649,7 @@ bool SkMorphologyImageFilter::filterImageGPUGeneric(bool dilate, GrMorphologyEffect::MorphologyType type = dilate ? GrMorphologyEffect::kDilate_MorphologyType : GrMorphologyEffect::kErode_MorphologyType; - if (!apply_morphology(input, srcBounds, type, SkISize::Make(width, height), result, - GrTextureProvider::FromImageFilter(ctx.sizeConstraint()))) { + if (!apply_morphology(input, srcBounds, type, SkISize::Make(width, height), result)) { return false; } offset->fX = bounds.left(); diff --git a/gfx/skia/skia/src/effects/SkOffsetImageFilter.cpp b/gfx/skia/skia/src/effects/SkOffsetImageFilter.cpp index 9da026b2793..e39c8d25062 100644 --- a/gfx/skia/skia/src/effects/SkOffsetImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkOffsetImageFilter.cpp @@ -20,11 +20,7 @@ bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, SkIPoint* offset) const { SkBitmap src = source; SkIPoint srcOffset = SkIPoint::Make(0, 0); -#ifdef SK_DISABLE_OFFSETIMAGEFILTER_OPTIMIZATION - if (false) { -#else if (!cropRectIsSet()) { -#endif if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) { return false; } @@ -70,24 +66,28 @@ void SkOffsetImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) cons } else { *dst = src; } +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS SkRect copy = *dst; +#endif dst->offset(fOffset.fX, fOffset.fY); +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS dst->join(copy); +#endif } -bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, - SkIRect* dst) const { +void SkOffsetImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst, MapDirection direction) const { SkVector vec; ctm.mapVectors(&vec, &fOffset, 1); - - SkIRect bounds = src; - bounds.offset(-SkScalarCeilToInt(vec.fX), -SkScalarCeilToInt(vec.fY)); - bounds.join(src); - if (getInput(0)) { - return getInput(0)->filterBounds(bounds, ctm, dst); + if (kReverse_MapDirection == direction) { + vec.negate(); } - *dst = bounds; - return true; + + *dst = src; + dst->offset(SkScalarCeilToInt(vec.fX), SkScalarCeilToInt(vec.fY)); +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS + dst->join(src); +#endif } SkFlattenable* SkOffsetImageFilter::CreateProc(SkReadBuffer& buffer) { diff --git a/gfx/skia/skia/src/effects/SkRectShaderImageFilter.cpp b/gfx/skia/skia/src/effects/SkPaintImageFilter.cpp similarity index 50% rename from gfx/skia/skia/src/effects/SkRectShaderImageFilter.cpp rename to gfx/skia/skia/src/effects/SkPaintImageFilter.cpp index 14837d02b15..d141f34dfb0 100644 --- a/gfx/skia/skia/src/effects/SkRectShaderImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkPaintImageFilter.cpp @@ -1,54 +1,39 @@ /* - * Copyright 2013 Google Inc. + * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#include "SkRectShaderImageFilter.h" +#include "SkPaintImageFilter.h" #include "SkBitmap.h" #include "SkCanvas.h" #include "SkDevice.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" -#include "SkShader.h" -SkImageFilter* SkRectShaderImageFilter::Create(SkShader* s, const SkRect& rect) { - SkASSERT(s); - uint32_t flags = CropRect::kHasAll_CropEdge; - if (rect.width() == 0 || rect.height() == 0) { - flags = 0x0; - } - CropRect cropRect(rect, flags); - return s ? new SkRectShaderImageFilter(s, &cropRect) : nullptr; +SkImageFilter* SkPaintImageFilter::Create(const SkPaint& paint, const CropRect* cropRect) { + return new SkPaintImageFilter(paint, cropRect); } -SkImageFilter* SkRectShaderImageFilter::Create(SkShader* s, const CropRect* cropRect) { - SkASSERT(s); - return s ? new SkRectShaderImageFilter(s, cropRect) : nullptr; -} - -SkRectShaderImageFilter::SkRectShaderImageFilter(SkShader* s, const CropRect* cropRect) +SkPaintImageFilter::SkPaintImageFilter(const SkPaint& paint, const CropRect* cropRect) : INHERITED(0, nullptr, cropRect) - , fShader(SkRef(s)) { + , fPaint(paint) { } -SkFlattenable* SkRectShaderImageFilter::CreateProc(SkReadBuffer& buffer) { +SkFlattenable* SkPaintImageFilter::CreateProc(SkReadBuffer& buffer) { SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0); - SkAutoTUnref shader(buffer.readShader()); - return Create(shader.get(), &common.cropRect()); + SkPaint paint; + buffer.readPaint(&paint); + return Create(paint, &common.cropRect()); } -void SkRectShaderImageFilter::flatten(SkWriteBuffer& buffer) const { +void SkPaintImageFilter::flatten(SkWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); - buffer.writeFlattenable(fShader); + buffer.writePaint(fPaint); } -SkRectShaderImageFilter::~SkRectShaderImageFilter() { - fShader->unref(); -} - -bool SkRectShaderImageFilter::onFilterImage(Proxy* proxy, +bool SkPaintImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const Context& ctx, SkBitmap* result, @@ -65,13 +50,15 @@ bool SkRectShaderImageFilter::onFilterImage(Proxy* proxy, } SkCanvas canvas(device.get()); - SkPaint paint; SkMatrix matrix(ctx.ctm()); matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); - SkSafeUnref(paint.setShader(SkShader::CreateLocalMatrixShader(fShader, matrix))); - SkRect rect = SkRect::MakeWH(SkIntToScalar(bounds.width()), SkIntToScalar(bounds.height())); - canvas.drawRect(rect, paint); + SkMatrix inverse; + if (matrix.invert(&inverse)) { + inverse.mapRect(&rect); + } + canvas.setMatrix(matrix); + canvas.drawRect(rect, fPaint); *result = device.get()->accessBitmap(false); offset->fX = bounds.fLeft; @@ -79,13 +66,16 @@ bool SkRectShaderImageFilter::onFilterImage(Proxy* proxy, return true; } -bool SkRectShaderImageFilter::affectsTransparentBlack() const { - return true; +bool SkPaintImageFilter::canComputeFastBounds() const { + // http:skbug.com/4627: "make computeFastBounds and onFilterBounds() CropRect-aware" + // computeFastBounds() doesn't currently take the crop rect into account, + // so we can't compute it. If a full crop rect is set, we should return true here. + return false; } #ifndef SK_IGNORE_TO_STRING -void SkRectShaderImageFilter::toString(SkString* str) const { - str->appendf("SkRectShaderImageFilter: ("); +void SkPaintImageFilter::toString(SkString* str) const { + str->appendf("SkPaintImageFilter: ("); str->append(")"); } #endif diff --git a/gfx/skia/skia/src/effects/SkPerlinNoiseShader.cpp b/gfx/skia/skia/src/effects/SkPerlinNoiseShader.cpp index 916cf78f0df..60e96017b2c 100644 --- a/gfx/skia/skia/src/effects/SkPerlinNoiseShader.cpp +++ b/gfx/skia/skia/src/effects/SkPerlinNoiseShader.cpp @@ -5,7 +5,6 @@ * found in the LICENSE file. */ -#include "SkDither.h" #include "SkPerlinNoiseShader.h" #include "SkColorFilter.h" #include "SkReadBuffer.h" @@ -22,8 +21,8 @@ #include "effects/GrConstColorProcessor.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #endif static const int kBlockSize = 256; @@ -467,19 +466,6 @@ void SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan( } } -void SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan16( - int x, int y, uint16_t result[], int count) { - SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y)); - StitchData stitchData; - DITHER_565_SCAN(y); - for (int i = 0; i < count; ++i) { - unsigned dither = DITHER_VALUE(x); - result[i] = SkDitherRGB32To565(shade(point, stitchData), dither); - DITHER_INC_X(x); - point.fX += SK_Scalar1; - } -} - ///////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU @@ -621,19 +607,20 @@ GrGLPerlinNoise::GrGLPerlinNoise(const GrProcessor& processor) void GrGLPerlinNoise::emitCode(EmitArgs& args) { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; SkString vCoords = fragBuilder->ensureFSCoords2D(args.fCoords, 0); - fBaseFrequencyUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "baseFrequency"); - const char* baseFrequencyUni = args.fBuilder->getUniformCStr(fBaseFrequencyUni); + fBaseFrequencyUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "baseFrequency"); + const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni); const char* stitchDataUni = nullptr; if (fStitchTiles) { - fStitchDataUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "stitchData"); - stitchDataUni = args.fBuilder->getUniformCStr(fStitchDataUni); + fStitchDataUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "stitchData"); + stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni); } // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8 diff --git a/gfx/skia/skia/src/effects/SkTableColorFilter.cpp b/gfx/skia/skia/src/effects/SkTableColorFilter.cpp index 9d97411042f..d9c07e254cc 100644 --- a/gfx/skia/skia/src/effects/SkTableColorFilter.cpp +++ b/gfx/skia/skia/src/effects/SkTableColorFilter.cpp @@ -337,8 +337,8 @@ SkColorFilter* SkTable_ColorFilter::newComposed(const SkColorFilter* innerFilter #include "effects/GrTextureStripAtlas.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" class ColorTableEffect : public GrFragmentProcessor { public: @@ -415,9 +415,9 @@ void GLColorTableEffect::onSetData(const GrGLSLProgramDataManager& pdm, const Gr void GLColorTableEffect::emitCode(EmitArgs& args) { const char* yoffsets; - fRGBAYValuesUni = args.fBuilder->addUniform(GrGLSLFPBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "yoffsets", &yoffsets); + fRGBAYValuesUni = args.fUniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "yoffsets", &yoffsets); static const float kColorScaleFactor = 255.0f / 256.0f; static const float kColorOffsetFactor = 1.0f / 512.0f; GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -442,22 +442,22 @@ void GLColorTableEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("\t\t%s.a = ", args.fOutputColor); coord.printf("vec2(coord.a, %s.a)", yoffsets); fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str()); - fragBuilder->codeAppend(";\n"); + fragBuilder->codeAppend(".a;\n"); fragBuilder->codeAppendf("\t\t%s.r = ", args.fOutputColor); coord.printf("vec2(coord.r, %s.r)", yoffsets); fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str()); - fragBuilder->codeAppend(";\n"); + fragBuilder->codeAppend(".a;\n"); fragBuilder->codeAppendf("\t\t%s.g = ", args.fOutputColor); coord.printf("vec2(coord.g, %s.g)", yoffsets); fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str()); - fragBuilder->codeAppend(";\n"); + fragBuilder->codeAppend(".a;\n"); fragBuilder->codeAppendf("\t\t%s.b = ", args.fOutputColor); coord.printf("vec2(coord.b, %s.b)", yoffsets); fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str()); - fragBuilder->codeAppend(";\n"); + fragBuilder->codeAppend(".a;\n"); fragBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", args.fOutputColor, args.fOutputColor); } @@ -487,7 +487,7 @@ const GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags) - : fTextureAccess(texture, "a") + : fTextureAccess(texture) , fFlags(flags) , fAtlas(atlas) , fRow(row) { diff --git a/gfx/skia/skia/src/effects/SkTileImageFilter.cpp b/gfx/skia/skia/src/effects/SkTileImageFilter.cpp index 52ea6a756f1..6da572b3b85 100644 --- a/gfx/skia/skia/src/effects/SkTileImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkTileImageFilter.cpp @@ -9,6 +9,7 @@ #include "SkBitmap.h" #include "SkCanvas.h" #include "SkDevice.h" +#include "SkOffsetImageFilter.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkMatrix.h" @@ -21,6 +22,16 @@ SkImageFilter* SkTileImageFilter::Create(const SkRect& srcRect, const SkRect& ds if (!SkIsValidRect(srcRect) || !SkIsValidRect(dstRect)) { return nullptr; } + if (srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height()) { + SkRect ir = dstRect; + if (!ir.intersect(srcRect)) { + return SkSafeRef(input); + } + CropRect cropRect(ir); + return SkOffsetImageFilter::Create(dstRect.x() - srcRect.x(), + dstRect.y() - srcRect.y(), + input, &cropRect); + } return new SkTileImageFilter(srcRect, dstRect, input); } @@ -35,6 +46,10 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, SkRect dstRect; ctx.ctm().mapRect(&dstRect, fDstRect); + if (!dstRect.intersect(SkRect::Make(ctx.clipBounds()))) { + offset->fX = offset->fY = 0; + return true; + } const SkIRect dstIRect = dstRect.roundOut(); int w = dstIRect.width(); int h = dstIRect.height(); @@ -48,15 +63,31 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, srcRect.roundOut(&srcIRect); srcIRect.offset(-srcOffset); SkBitmap subset; - SkIRect bounds; - source.getBounds(&bounds); + SkIRect srcBounds; + source.getBounds(&srcBounds); - if (!srcIRect.intersect(bounds)) { + if (!SkIRect::Intersects(srcIRect, srcBounds)) { offset->fX = offset->fY = 0; return true; - } else if (!source.extractSubset(&subset, srcIRect)) { - return false; } + if (srcBounds.contains(srcIRect)) { + if (!source.extractSubset(&subset, srcIRect)) { + return false; + } + } else { + SkAutoTUnref device(proxy->createDevice(srcIRect.width(), + srcIRect.height(), + kPossible_TileUsage)); + if (!device) { + return false; + } + SkCanvas canvas(device); + canvas.drawBitmap(src, SkIntToScalar(srcOffset.x()), + SkIntToScalar(srcOffset.y())); + subset = device->accessBitmap(false); + } + SkASSERT(subset.width() == srcIRect.width()); + SkASSERT(subset.height() == srcIRect.height()); SkAutoTUnref device(proxy->createDevice(w, h)); if (nullptr == device.get()) { @@ -66,12 +97,8 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); - SkMatrix shaderMatrix; - shaderMatrix.setTranslate(SkIntToScalar(srcOffset.fX), - SkIntToScalar(srcOffset.fY)); SkAutoTUnref shader(SkShader::CreateBitmapShader(subset, - SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, - &shaderMatrix)); + SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); paint.setShader(shader); canvas.translate(-dstRect.fLeft, -dstRect.fTop); canvas.drawRect(dstRect, paint); @@ -81,21 +108,30 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, return true; } +void SkTileImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst, MapDirection direction) const { + SkRect rect = kReverse_MapDirection == direction ? fSrcRect : fDstRect; + ctm.mapRect(&rect); + rect.roundOut(dst); +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS + dst->join(src); +#endif +} + bool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { - SkRect srcRect; - ctm.mapRect(&srcRect, fSrcRect); - SkIRect srcIRect; - srcRect.roundOut(&srcIRect); - srcIRect.join(src); - *dst = srcIRect; + this->onFilterNodeBounds(src, ctm, dst, kReverse_MapDirection); return true; } void SkTileImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS // This is a workaround for skia:3194. *dst = src; dst->join(fDstRect); +#else + *dst = fDstRect; +#endif } SkFlattenable* SkTileImageFilter::CreateProc(SkReadBuffer& buffer) { diff --git a/gfx/skia/skia/src/effects/SkXfermodeImageFilter.cpp b/gfx/skia/skia/src/effects/SkXfermodeImageFilter.cpp index 38d1e5e6b40..5f88240481b 100644 --- a/gfx/skia/skia/src/effects/SkXfermodeImageFilter.cpp +++ b/gfx/skia/skia/src/effects/SkXfermodeImageFilter.cpp @@ -147,47 +147,55 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, } 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 = src.width(); - desc.fHeight = src.height(); + desc.fWidth = bounds.width(); + desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; - auto constraint = GrTextureProvider::FromImageFilter(ctx.sizeConstraint()); - SkAutoTUnref dst(context->textureProvider()->createTexture(desc, constraint)); + SkAutoTUnref dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } GrPaint paint; - SkMatrix bgMatrix; - bgMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); - SkAutoTUnref bgFP( - GrSimpleTextureEffect::Create(backgroundTex, bgMatrix)); + SkMatrix backgroundMatrix; + backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); + backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), + SkIntToScalar(-backgroundOffset.fY)); + SkAutoTUnref 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 = GrCoordTransform::MakeDivByTextureWHMatrix(foregroundTex); - foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX), - SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY)); + SkMatrix foregroundMatrix; + foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); + foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), + SkIntToScalar(-foregroundOffset.fY)); - SkRect srcRect; - src.getBounds(&srcRect); - - SkAutoTUnref foregroundDomain(GrTextureDomainEffect::Create( + SkAutoTUnref foregroundFP(GrTextureDomainEffect::Create( foregroundTex, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode) ); - paint.addColorFragmentProcessor(foregroundDomain.get()); + paint.addColorFragmentProcessor(foregroundFP.get()); if (xferFP) { paint.addColorFragmentProcessor(xferFP)->unref(); } @@ -198,11 +206,13 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, return false; } - drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), srcRect); + SkMatrix matrix; + matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); + drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(bounds)); - offset->fX = backgroundOffset.fX; - offset->fY = backgroundOffset.fY; - WrapTexture(dst, src.width(), src.height(), result); + offset->fX = bounds.left(); + offset->fY = bounds.top(); + GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; } diff --git a/gfx/skia/skia/src/effects/gradients/SkClampRange.h b/gfx/skia/skia/src/effects/gradients/SkClampRange.h index 945f9a7ff18..d3d2d08c86d 100644 --- a/gfx/skia/skia/src/effects/gradients/SkClampRange.h +++ b/gfx/skia/skia/src/effects/gradients/SkClampRange.h @@ -12,8 +12,8 @@ #include "SkScalar.h" #define SkGradFixed SkFixed3232 -#define SkScalarToGradFixed SkScalarToFixed3232 -#define SkFixedToGradFixed SkFixedToFixed3232 +#define SkScalarToGradFixed(x) SkScalarToFixed3232(x) +#define SkFixedToGradFixed(x) SkFixedToFixed3232(x) #define SkGradFixedToFixed(x) (SkFixed)((x) >> 16) #define kFracMax_SkGradFixed 0xFFFFFFFFLL diff --git a/gfx/skia/skia/src/effects/gradients/SkGradientShader.cpp b/gfx/skia/skia/src/effects/gradients/SkGradientShader.cpp index e486e08a64b..ac70bc25e11 100644 --- a/gfx/skia/skia/src/effects/gradients/SkGradientShader.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkGradientShader.cpp @@ -314,11 +314,6 @@ SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext( if (shader.fColorsAreOpaque && paintAlpha == 0xFF) { fFlags |= kOpaqueAlpha_Flag; } - // we can do span16 as long as our individual colors are opaque, - // regardless of the paint's alpha - if (shader.fColorsAreOpaque) { - fFlags |= kHasSpan16_Flag; - } } SkGradientShaderBase::GradientShaderCache::GradientShaderCache( @@ -910,8 +905,8 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END #include "GrInvariantOutput.h" #include "gl/GrGLContext.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "SkGr.h" GrGLGradientEffect::GrGLGradientEffect() @@ -920,31 +915,32 @@ GrGLGradientEffect::GrGLGradientEffect() GrGLGradientEffect::~GrGLGradientEffect() { } -void GrGLGradientEffect::emitUniforms(GrGLSLFPBuilder* builder, const GrGradientEffect& ge) { +void GrGLGradientEffect::emitUniforms(GrGLSLUniformHandler* uniformHandler, + const GrGradientEffect& ge) { if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()) { // 2 Color case - fColorStartUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "GradientStartColor"); - fColorEndUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "GradientEndColor"); + fColorStartUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "GradientStartColor"); + fColorEndUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "GradientEndColor"); } else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) { // 3 Color Case - fColorStartUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "GradientStartColor"); - fColorMidUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "GradientMidColor"); - fColorEndUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "GradientEndColor"); + fColorStartUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "GradientStartColor"); + fColorMidUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "GradientMidColor"); + fColorEndUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "GradientEndColor"); } else { // if not a fast case - fFSYUni = builder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "GradientYCoordFS"); + fFSYUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "GradientYCoordFS"); } } @@ -1026,8 +1022,8 @@ uint32_t GrGLGradientEffect::GenBaseGradientKey(const GrProcessor& processor) { return key; } -void GrGLGradientEffect::emitColor(GrGLSLFPBuilder* builder, - GrGLSLFragmentBuilder* fragBuilder, +void GrGLGradientEffect::emitColor(GrGLSLFragmentBuilder* fragBuilder, + GrGLSLUniformHandler* uniformHandler, const GrGLSLCaps* glslCaps, const GrGradientEffect& ge, const char* gradientTValue, @@ -1036,8 +1032,8 @@ void GrGLGradientEffect::emitColor(GrGLSLFPBuilder* builder, const TextureSamplerArray& samplers) { if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()){ fragBuilder->codeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n", - builder->getUniformVariable(fColorStartUni).c_str(), - builder->getUniformVariable(fColorEndUni).c_str(), + uniformHandler->getUniformVariable(fColorStartUni).c_str(), + uniformHandler->getUniformVariable(fColorEndUni).c_str(), gradientTValue); // Note that we could skip this step if both colors are known to be opaque. Two // considerations: @@ -1055,20 +1051,20 @@ void GrGLGradientEffect::emitColor(GrGLSLFPBuilder* builder, fragBuilder->codeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n", gradientTValue); fragBuilder->codeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n", - builder->getUniformVariable(fColorStartUni).c_str()); + uniformHandler->getUniformVariable(fColorStartUni).c_str()); if (!glslCaps->canUseMinAndAbsTogether()) { // The Tegra3 compiler will sometimes never return if we have // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression. fragBuilder->codeAppend("\tfloat minAbs = abs(oneMinus2t);\n"); fragBuilder->codeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n"); fragBuilder->codeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n", - builder->getUniformVariable(fColorMidUni).c_str()); + uniformHandler->getUniformVariable(fColorMidUni).c_str()); } else { fragBuilder->codeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n", - builder->getUniformVariable(fColorMidUni).c_str()); + uniformHandler->getUniformVariable(fColorMidUni).c_str()); } fragBuilder->codeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n", - builder->getUniformVariable(fColorEndUni).c_str()); + uniformHandler->getUniformVariable(fColorEndUni).c_str()); if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n"); } @@ -1078,7 +1074,7 @@ void GrGLGradientEffect::emitColor(GrGLSLFPBuilder* builder, } else { fragBuilder->codeAppendf("\tvec2 coord = vec2(%s, %s);\n", gradientTValue, - builder->getUniformVariable(fFSYUni).c_str()); + uniformHandler->getUniformVariable(fFSYUni).c_str()); fragBuilder->codeAppendf("\t%s = ", outputColor); fragBuilder->appendTextureLookupAndModulate(inputColor, samplers[0], diff --git a/gfx/skia/skia/src/effects/gradients/SkGradientShaderPriv.h b/gfx/skia/skia/src/effects/gradients/SkGradientShaderPriv.h index 3c19152d902..f8a968d1a25 100644 --- a/gfx/skia/skia/src/effects/gradients/SkGradientShaderPriv.h +++ b/gfx/skia/skia/src/effects/gradients/SkGradientShaderPriv.h @@ -58,7 +58,7 @@ static inline SkFixed repeat_tileproc(SkFixed x) { #endif static inline SkFixed mirror_tileproc(SkFixed x) { - int s = x << 15 >> 31; + int s = SkLeftShift(x, 15) >> 31; return (x ^ s) & 0xFFFF; } @@ -419,14 +419,14 @@ protected: // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses // should call this method from their emitCode(). - void emitUniforms(GrGLSLFPBuilder* builder, const GrGradientEffect&); + void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&); // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using // native GLSL mix), and 4+ color gradients that use the traditional texture lookup. - void emitColor(GrGLSLFPBuilder* builder, - GrGLSLFragmentBuilder* fragBuilder, + void emitColor(GrGLSLFragmentBuilder* fragBuilder, + GrGLSLUniformHandler* uniformHandler, const GrGLSLCaps* caps, const GrGradientEffect&, const char* gradientTValue, diff --git a/gfx/skia/skia/src/effects/gradients/SkLinearGradient.cpp b/gfx/skia/skia/src/effects/gradients/SkLinearGradient.cpp index b2c22512367..6ba2fa8ea29 100644 --- a/gfx/skia/skia/src/effects/gradients/SkLinearGradient.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkLinearGradient.cpp @@ -9,10 +9,6 @@ static const float kInv255Float = 1.0f / 255; -static inline int repeat_bits(int x, const int bits) { - return x & ((1 << bits) - 1); -} - static inline int repeat_8bits(int x) { return x & 0xFF; } @@ -23,13 +19,6 @@ static inline int repeat_8bits(int x) { #pragma optimize("", off) #endif -static inline int mirror_bits(int x, const int bits) { - if (x & (1 << bits)) { - x = ~x; - } - return x & ((1 << bits) - 1); -} - static inline int mirror_8bits(int x) { if (x & 256) { x = ~x; @@ -102,17 +91,6 @@ SkLinearGradient::LinearGradientContext::LinearGradientContext( const SkLinearGradient& shader, const ContextRec& ctx) : INHERITED(shader, ctx) { - unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; - if ((fDstToIndex.getType() & ~mask) == 0) { - // when we dither, we are (usually) not const-in-Y - if ((fFlags & SkShader::kHasSpan16_Flag) && !ctx.fPaint->isDither()) { - // only claim this if we do have a 16bit mode (i.e. none of our - // colors have alpha), and if we are not dithering (which obviously - // is not const in Y). - fFlags |= SkShader::kConstInY16_Flag; - } - } - // setup for Sk4f int count = shader.fColorCount; fRecs.setCount(count); @@ -122,12 +100,7 @@ SkLinearGradient::LinearGradientContext::LinearGradientContext( SkDEBUGCODE(rec[0].fPosScale = SK_FloatNaN;) // should never get used for (int i = 1; i < count; ++i) { rec[i].fPos = SkTPin(shader.fOrigPos[i], rec[i - 1].fPos, 1.0f); - float diff = rec[i].fPos - rec[i - 1].fPos; - if (diff > 0) { - rec[i].fPosScale = 1.0f / diff; - } else { - rec[i].fPosScale = 0; - } + rec[i].fPosScale = 1.0f / (rec[i].fPos - rec[i - 1].fPos); } rec[count - 1].fPos = 1; // overwrite the last value just to be sure we end at 1.0 } else { @@ -155,7 +128,7 @@ SkLinearGradient::LinearGradientContext::LinearGradientContext( const Sk4f scale(1, 1, 1, paintAlpha); for (int i = 0; i < count; ++i) { uint32_t c = SkSwizzle_Color_to_PMColor(shader.fOrigColors[i]); - rec[i].fColor = Sk4f::FromBytes((const uint8_t*)&c) * scale; + rec[i].fColor = SkNx_cast(Sk4b::Load((const uint8_t*)&c)) * scale; if (i > 0) { SkASSERT(rec[i - 1].fPos <= rec[i].fPos); } @@ -167,7 +140,7 @@ SkLinearGradient::LinearGradientContext::LinearGradientContext( for (int i = 0; i < count; ++i) { SkPMColor pmc = SkPreMultiplyColor(shader.fOrigColors[i]); pmc = SkAlphaMulQ(pmc, alphaScale); - rec[i].fColor = Sk4f::FromBytes((const uint8_t*)&pmc); + rec[i].fColor = SkNx_cast(Sk4b::Load((const uint8_t*)&pmc)); if (i > 0) { SkASSERT(rec[i - 1].fPos <= rec[i].fPos); } @@ -287,7 +260,8 @@ void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SkASSERT(count > 0); const SkLinearGradient& linearGradient = static_cast(fShader); -#ifndef SK_SUPPORT_LEGACY_LINEAR_GRADIENT_TABLE +// Only use the Sk4f impl when known to be fast. +#if defined(SKNX_IS_FAST) if (SkShader::kClamp_TileMode == linearGradient.fTileMode && kLinear_MatrixClass == fDstToIndexClass) { @@ -351,176 +325,10 @@ SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { return kLinear_GradientType; } -static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other, - int count) { - if (reinterpret_cast(dst) & 2) { - *dst++ = value; - count -= 1; - SkTSwap(value, other); - } - - sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1); - - if (count & 1) { - dst[count - 1] = value; - } -} - -#define NO_CHECK_ITER_16 \ - do { \ - unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift; \ - SkASSERT(fi < SkGradientShaderBase::kCache16Count); \ - fx += dx; \ - *dstC++ = cache[toggle + fi]; \ - toggle = next_dither_toggle16(toggle); \ - } while (0) - -namespace { - -typedef void (*LinearShade16Proc)(TileProc proc, SkGradFixed dx, SkGradFixed fx, - uint16_t* dstC, const uint16_t* cache, - int toggle, int count); - -void shadeSpan16_linear_vertical(TileProc proc, SkGradFixed dx, SkGradFixed fx, - uint16_t* SK_RESTRICT dstC, - const uint16_t* SK_RESTRICT cache, - int toggle, int count) { - // we're a vertical gradient, so no change in a span - unsigned fi = proc(SkGradFixedToFixed(fx)) >> SkGradientShaderBase::kCache16Shift; - SkASSERT(fi < SkGradientShaderBase::kCache16Count); - dither_memset16(dstC, cache[toggle + fi], - cache[next_dither_toggle16(toggle) + fi], count); -} - -void shadeSpan16_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx, - uint16_t* SK_RESTRICT dstC, - const uint16_t* SK_RESTRICT cache, - int toggle, int count) { - SkClampRange range; - range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1); - range.validate(count); - - if ((count = range.fCount0) > 0) { - dither_memset16(dstC, - cache[toggle + range.fV0], - cache[next_dither_toggle16(toggle) + range.fV0], - count); - dstC += count; - } - if ((count = range.fCount1) > 0) { - int unroll = count >> 3; - fx = range.fFx1; - for (int i = 0; i < unroll; i++) { - NO_CHECK_ITER_16; NO_CHECK_ITER_16; - NO_CHECK_ITER_16; NO_CHECK_ITER_16; - NO_CHECK_ITER_16; NO_CHECK_ITER_16; - NO_CHECK_ITER_16; NO_CHECK_ITER_16; - } - if ((count &= 7) > 0) { - do { - NO_CHECK_ITER_16; - } while (--count != 0); - } - } - if ((count = range.fCount2) > 0) { - dither_memset16(dstC, - cache[toggle + range.fV1], - cache[next_dither_toggle16(toggle) + range.fV1], - count); - } -} - -void shadeSpan16_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx, - uint16_t* SK_RESTRICT dstC, - const uint16_t* SK_RESTRICT cache, - int toggle, int count) { - do { - unsigned fi = mirror_bits(SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift, - SkGradientShaderBase::kCache16Bits); - SkASSERT(fi < SkGradientShaderBase::kCache16Count); - fx += dx; - *dstC++ = cache[toggle + fi]; - toggle = next_dither_toggle16(toggle); - } while (--count != 0); -} - -void shadeSpan16_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx, - uint16_t* SK_RESTRICT dstC, - const uint16_t* SK_RESTRICT cache, - int toggle, int count) { - do { - unsigned fi = repeat_bits(SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift, - SkGradientShaderBase::kCache16Bits); - SkASSERT(fi < SkGradientShaderBase::kCache16Count); - fx += dx; - *dstC++ = cache[toggle + fi]; - toggle = next_dither_toggle16(toggle); - } while (--count != 0); -} -} - -static bool fixed_nearly_zero(SkFixed x) { - return SkAbs32(x) < (SK_Fixed1 >> 12); -} - -void SkLinearGradient::LinearGradientContext::shadeSpan16(int x, int y, - uint16_t* SK_RESTRICT dstC, int count) { - SkASSERT(count > 0); - - const SkLinearGradient& linearGradient = static_cast(fShader); - - SkPoint srcPt; - SkMatrix::MapXYProc dstProc = fDstToIndexProc; - TileProc proc = linearGradient.fTileProc; - const uint16_t* SK_RESTRICT cache = fCache->getCache16(); - int toggle = init_dither_toggle16(x, y); - - if (fDstToIndexClass != kPerspective_MatrixClass) { - dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, - SkIntToScalar(y) + SK_ScalarHalf, &srcPt); - SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX); - - if (fDstToIndexClass == kFixedStepInX_MatrixClass) { - SkFixed dxStorage[1]; - (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, nullptr); - // todo: do we need a real/high-precision value for dx here? - dx = SkFixedToGradFixed(dxStorage[0]); - } else { - SkASSERT(fDstToIndexClass == kLinear_MatrixClass); - dx = SkScalarToGradFixed(fDstToIndex.getScaleX()); - } - - LinearShade16Proc shadeProc = shadeSpan16_linear_repeat; - if (fixed_nearly_zero(SkGradFixedToFixed(dx))) { - shadeProc = shadeSpan16_linear_vertical; - } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) { - shadeProc = shadeSpan16_linear_clamp; - } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) { - shadeProc = shadeSpan16_linear_mirror; - } else { - SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode); - } - (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); - } else { - SkScalar dstX = SkIntToScalar(x); - SkScalar dstY = SkIntToScalar(y); - do { - dstProc(fDstToIndex, dstX, dstY, &srcPt); - unsigned fi = proc(SkScalarToFixed(srcPt.fX)); - SkASSERT(fi <= 0xFFFF); - - int index = fi >> kCache16Shift; - *dstC++ = cache[toggle + index]; - toggle = next_dither_toggle16(toggle); - - dstX += SK_Scalar1; - } while (--count != 0); - } -} - #if SK_SUPPORT_GPU -#include "gl/builders/GrGLProgramBuilder.h" +#include "glsl/GrGLSLCaps.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" #include "SkGr.h" ///////////////////////////////////////////////////////////////////// @@ -608,11 +416,11 @@ const GrFragmentProcessor* GrLinearGradient::TestCreate(GrProcessorTestData* d) void GrGLLinearGradient::emitCode(EmitArgs& args) { const GrLinearGradient& ge = args.fFp.cast(); - this->emitUniforms(args.fBuilder, ge); + this->emitUniforms(args.fUniformHandler, ge); SkString t = args.fFragBuilder->ensureFSCoords2D(args.fCoords, 0); t.append(".x"); - this->emitColor(args.fBuilder, - args.fFragBuilder, + this->emitColor(args.fFragBuilder, + args.fUniformHandler, args.fGLSLCaps, ge, t.c_str(), args.fOutputColor, @@ -675,7 +483,7 @@ find_forward(const SkLinearGradient::LinearGradientContext::Rec rec[], float til SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1); SkASSERT(rec[0].fPos <= rec[1].fPos); rec += 1; - while (rec->fPos < tiledX || rec->fPosScale == 0) { + while (rec->fPos < tiledX) { SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1); SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1); SkASSERT(rec[0].fPos <= rec[1].fPos); @@ -691,7 +499,7 @@ find_backward(const SkLinearGradient::LinearGradientContext::Rec rec[], float ti SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1); SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1); SkASSERT(rec[0].fPos <= rec[1].fPos); - while (tiledX < rec->fPos || rec[1].fPosScale == 0) { + while (tiledX < rec->fPos) { rec -= 1; SkASSERT(rec[0].fPos >= 0 && rec[0].fPos <= 1); SkASSERT(rec[1].fPos >= 0 && rec[1].fPos <= 1); @@ -702,7 +510,7 @@ find_backward(const SkLinearGradient::LinearGradientContext::Rec rec[], float ti template SkPMColor trunc_from_255(const Sk4f& x) { SkPMColor c; - x.toBytes((uint8_t*)&c); + SkNx_cast(x).store((uint8_t*)&c); if (apply_alpha) { c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c), SkGetPackedG32(c), SkGetPackedB32(c)); @@ -754,7 +562,7 @@ template void ramp(SkPMColor dstC[], int n, const Sk4f& c, co Sk4f cd3 = cd1 + dc2; while (n >= 4) { if (!apply_alpha) { - Sk4f::ToBytes((uint8_t*)dstC, cd0, cd1, cd2, cd3); + Sk4f_ToBytes((uint8_t*)dstC, cd0, cd1, cd2, cd3); dstC += 4; } else { *dstC++ = trunc_from_255(cd0); @@ -860,6 +668,8 @@ void SkLinearGradient::LinearGradientContext::shade4_dx_clamp(SkPMColor dstC[], } fx += n * dx; + // fx should now outside of the p0..p1 interval. However, due to float precision loss, + // its possible that fx is slightly too small/large, so we clamp it. if (dx_is_pos) { fx = SkTMax(fx, p1); } else { diff --git a/gfx/skia/skia/src/effects/gradients/SkLinearGradient.h b/gfx/skia/skia/src/effects/gradients/SkLinearGradient.h index 73efd2e778f..c8b91a55377 100644 --- a/gfx/skia/skia/src/effects/gradients/SkLinearGradient.h +++ b/gfx/skia/skia/src/effects/gradients/SkLinearGradient.h @@ -35,7 +35,6 @@ public: LinearGradientContext(const SkLinearGradient&, const ContextRec&); void shadeSpan(int x, int y, SkPMColor dstC[], int count) override; - void shadeSpan16(int x, int y, uint16_t dstC[], int count) override; struct Rec { Sk4fStorage fColor; diff --git a/gfx/skia/skia/src/effects/gradients/SkRadialGradient.cpp b/gfx/skia/skia/src/effects/gradients/SkRadialGradient.cpp index 7be8ed111b9..7e7ac7a4069 100644 --- a/gfx/skia/skia/src/effects/gradients/SkRadialGradient.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkRadialGradient.cpp @@ -7,46 +7,8 @@ */ #include "SkRadialGradient.h" -#include "SkRadialGradient_Table.h" #include "SkNx.h" -#define kSQRT_TABLE_BITS 11 -#define kSQRT_TABLE_SIZE (1 << kSQRT_TABLE_BITS) - -static_assert(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE, "SqrtTableSizesMatch"); - -#if 0 - -#include - -void SkRadialGradient_BuildTable() { - // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table - - FILE* file = ::fopen("SkRadialGradient_Table.h", "w"); - SkASSERT(file); - ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n"); - - for (int i = 0; i < kSQRT_TABLE_SIZE; i++) { - if ((i & 15) == 0) { - ::fprintf(file, "\t"); - } - - uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8); - - ::fprintf(file, "0x%02X", value); - if (i < kSQRT_TABLE_SIZE-1) { - ::fprintf(file, ", "); - } - if ((i & 15) == 15) { - ::fprintf(file, "\n"); - } - } - ::fprintf(file, "};\n"); - ::fclose(file); -} - -#endif - namespace { // GCC doesn't like using static functions as template arguments. So force these to be non-static. @@ -67,83 +29,6 @@ SkMatrix rad_to_unit_matrix(const SkPoint& center, SkScalar radius) { return matrix; } -typedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx, - SkScalar sfy, SkScalar sdy, - uint16_t* dstC, const uint16_t* cache, - int toggle, int count); - -void shadeSpan16_radial_clamp(SkScalar sfx, SkScalar sdx, - SkScalar sfy, SkScalar sdy, - uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, - int toggle, int count) { - const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table; - - /* knock these down so we can pin against +- 0x7FFF, which is an - immediate load, rather than 0xFFFF which is slower. This is a - compromise, since it reduces our precision, but that appears - to be visually OK. If we decide this is OK for all of our cases, - we could (it seems) put this scale-down into fDstToIndex, - to avoid having to do these extra shifts each time. - */ - SkFixed fx = SkScalarToFixed(sfx) >> 1; - SkFixed dx = SkScalarToFixed(sdx) >> 1; - SkFixed fy = SkScalarToFixed(sfy) >> 1; - SkFixed dy = SkScalarToFixed(sdy) >> 1; - // might perform this check for the other modes, - // but the win will be a smaller % of the total - if (dy == 0) { - fy = SkTPin(fy, -0xFFFF >> 1, 0xFFFF >> 1); - fy *= fy; - do { - unsigned xx = SkTPin(fx, -0xFFFF >> 1, 0xFFFF >> 1); - unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS); - fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); - fx += dx; - *dstC++ = cache[toggle + - (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)]; - toggle = next_dither_toggle16(toggle); - } while (--count != 0); - } else { - do { - unsigned xx = SkTPin(fx, -0xFFFF >> 1, 0xFFFF >> 1); - unsigned fi = SkTPin(fy, -0xFFFF >> 1, 0xFFFF >> 1); - fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS); - fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); - fx += dx; - fy += dy; - *dstC++ = cache[toggle + - (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)]; - toggle = next_dither_toggle16(toggle); - } while (--count != 0); - } -} - -template -void shadeSpan16_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, - uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, - int toggle, int count) { - do { - const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); - const unsigned fi = TileProc(dist); - SkASSERT(fi <= 0xFFFF); - *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache16Shift)]; - toggle = next_dither_toggle16(toggle); - fx += dx; - fy += dy; - } while (--count != 0); -} - -void shadeSpan16_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, - uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, - int toggle, int count) { - shadeSpan16_radial(fx, dx, fy, dy, dstC, cache, toggle, count); -} - -void shadeSpan16_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, - uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, - int toggle, int count) { - shadeSpan16_radial(fx, dx, fy, dy, dstC, cache, toggle, count); -} } // namespace @@ -167,64 +52,6 @@ SkRadialGradient::RadialGradientContext::RadialGradientContext( const SkRadialGradient& shader, const ContextRec& rec) : INHERITED(shader, rec) {} -void SkRadialGradient::RadialGradientContext::shadeSpan16(int x, int y, uint16_t* dstCParam, - int count) { - SkASSERT(count > 0); - - const SkRadialGradient& radialGradient = static_cast(fShader); - - uint16_t* SK_RESTRICT dstC = dstCParam; - - SkPoint srcPt; - SkMatrix::MapXYProc dstProc = fDstToIndexProc; - TileProc proc = radialGradient.fTileProc; - const uint16_t* SK_RESTRICT cache = fCache->getCache16(); - int toggle = init_dither_toggle16(x, y); - - if (fDstToIndexClass != kPerspective_MatrixClass) { - dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, - SkIntToScalar(y) + SK_ScalarHalf, &srcPt); - - SkScalar sdx = fDstToIndex.getScaleX(); - SkScalar sdy = fDstToIndex.getSkewY(); - - if (fDstToIndexClass == kFixedStepInX_MatrixClass) { - SkFixed storage[2]; - (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), - &storage[0], &storage[1]); - sdx = SkFixedToScalar(storage[0]); - sdy = SkFixedToScalar(storage[1]); - } else { - SkASSERT(fDstToIndexClass == kLinear_MatrixClass); - } - - RadialShade16Proc shadeProc = shadeSpan16_radial_repeat; - if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { - shadeProc = shadeSpan16_radial_clamp; - } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { - shadeProc = shadeSpan16_radial_mirror; - } else { - SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); - } - (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, - cache, toggle, count); - } else { // perspective case - SkScalar dstX = SkIntToScalar(x); - SkScalar dstY = SkIntToScalar(y); - do { - dstProc(fDstToIndex, dstX, dstY, &srcPt); - unsigned fi = proc(SkScalarToFixed(srcPt.length())); - SkASSERT(fi <= 0xFFFF); - - int index = fi >> (16 - kCache16Bits); - *dstC++ = cache[toggle + index]; - toggle = next_dither_toggle16(toggle); - - dstX += SK_Scalar1; - } while (--count != 0); - } -} - SkShader::GradientType SkRadialGradient::asAGradient(GradientInfo* info) const { if (info) { commonAsAGradient(info); @@ -307,7 +134,7 @@ void shadeSpan_radial_clamp2(SkScalar sfx, SkScalar sdx, SkScalar sfy, SkScalar dR = dR + ddR; uint8_t fi[4]; - dist.toBytes(fi); + SkNx_cast(dist).store(fi); for (int i = 0; i < 4; i++) { *dstC++ = cache[toggle + fi[i]]; @@ -319,7 +146,7 @@ void shadeSpan_radial_clamp2(SkScalar sfx, SkScalar sdx, SkScalar sfy, SkScalar Sk4f dist = Sk4f::Min(fast_sqrt(R), max); uint8_t fi[4]; - dist.toBytes(fi); + SkNx_cast(dist).store(fi); for (int i = 0; i < count; i++) { *dstC++ = cache[toggle + fi[i]]; toggle = next_dither_toggle(toggle); @@ -415,7 +242,8 @@ void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y, #if SK_SUPPORT_GPU #include "SkGr.h" -#include "gl/builders/GrGLProgramBuilder.h" +#include "glsl/GrGLSLCaps.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" class GrGLRadialGradient : public GrGLGradientEffect { public: @@ -499,12 +327,12 @@ const GrFragmentProcessor* GrRadialGradient::TestCreate(GrProcessorTestData* d) void GrGLRadialGradient::emitCode(EmitArgs& args) { const GrRadialGradient& ge = args.fFp.cast(); - this->emitUniforms(args.fBuilder, ge); + this->emitUniforms(args.fUniformHandler, ge); SkString t("length("); t.append(args.fFragBuilder->ensureFSCoords2D(args.fCoords, 0)); t.append(")"); - this->emitColor(args.fBuilder, - args.fFragBuilder, + this->emitColor(args.fFragBuilder, + args.fUniformHandler, args.fGLSLCaps, ge, t.c_str(), args.fOutputColor, diff --git a/gfx/skia/skia/src/effects/gradients/SkRadialGradient.h b/gfx/skia/skia/src/effects/gradients/SkRadialGradient.h index afffddd22d3..bd6fb3542fb 100644 --- a/gfx/skia/skia/src/effects/gradients/SkRadialGradient.h +++ b/gfx/skia/skia/src/effects/gradients/SkRadialGradient.h @@ -22,7 +22,6 @@ public: RadialGradientContext(const SkRadialGradient&, const ContextRec&); void shadeSpan(int x, int y, SkPMColor dstC[], int count) override; - void shadeSpan16(int x, int y, uint16_t dstC[], int count) override; private: typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED; diff --git a/gfx/skia/skia/src/effects/gradients/SkRadialGradient_Table.h b/gfx/skia/skia/src/effects/gradients/SkRadialGradient_Table.h deleted file mode 100644 index 9a8a5f816ef..00000000000 --- a/gfx/skia/skia/src/effects/gradients/SkRadialGradient_Table.h +++ /dev/null @@ -1,139 +0,0 @@ - -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -static const uint8_t gSqrt8Table[] = { - 0x00, 0x05, 0x08, 0x09, 0x0B, 0x0C, 0x0D, 0x0E, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x15, - 0x16, 0x17, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, - 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, - 0x27, 0x27, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, 0x2C, - 0x2D, 0x2D, 0x2D, 0x2E, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, - 0x32, 0x32, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x37, - 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3B, 0x3B, 0x3B, - 0x3B, 0x3C, 0x3C, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F, - 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, - 0x43, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, - 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x4A, 0x4A, 0x4A, 0x4A, - 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4E, - 0x4E, 0x4E, 0x4E, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, - 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, - 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, - 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5A, 0x5A, - 0x5A, 0x5A, 0x5A, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5D, - 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, - 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, - 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, - 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, - 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6C, 0x6C, 0x6C, - 0x6C, 0x6C, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, - 0x6E, 0x6E, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, - 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, - 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, - 0x75, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, - 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, - 0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, - 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, - 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8B, 0x8B, 0x8B, 0x8B, - 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8D, 0x8D, - 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, - 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9B, - 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, - 0x9C, 0x9C, 0x9C, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9E, 0x9E, 0x9E, - 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, - 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, - 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA3, - 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, - 0xA4, 0xA4, 0xA4, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA6, 0xA6, - 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, - 0xA7, 0xA7, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA9, 0xA9, 0xA9, - 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - 0xAA, 0xAA, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAC, 0xAC, 0xAC, - 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, - 0xAD, 0xAD, 0xAD, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAF, 0xAF, - 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, - 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB2, - 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, - 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, - 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB6, 0xB6, 0xB6, 0xB6, - 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, - 0xB7, 0xB7, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB9, 0xB9, - 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, - 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, - 0xBB, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBD, 0xBD, 0xBD, - 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, - 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC1, 0xC1, 0xC1, - 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, - 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, - 0xC3, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC5, 0xC5, 0xC5, - 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, - 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, - 0xC7, 0xC7, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC9, - 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xCA, 0xCA, 0xCA, 0xCA, - 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, - 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, - 0xCC, 0xCC, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCE, - 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCF, 0xCF, 0xCF, 0xCF, - 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, - 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, - 0xD1, 0xD1, 0xD1, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, - 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD4, 0xD4, 0xD4, - 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, - 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, - 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, - 0xD7, 0xD7, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, - 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xDA, 0xDA, - 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, - 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, - 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, - 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, - 0xDE, 0xDE, 0xDE, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, - 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE1, - 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE2, 0xE2, 0xE2, - 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, - 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, - 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, - 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, - 0xE6, 0xE6, 0xE6, 0xE6, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, - 0xE7, 0xE7, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, - 0xE8, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, - 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEB, 0xEB, - 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xEC, - 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xED, 0xED, 0xED, 0xED, - 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, - 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, - 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, - 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, - 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, - 0xF4, 0xF4, 0xF4, 0xF4, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, - 0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, - 0xF6, 0xF6, 0xF6, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, - 0xF7, 0xF7, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, - 0xF8, 0xF8, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, - 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, - 0xFA, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, - 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, - 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, - 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; diff --git a/gfx/skia/skia/src/effects/gradients/SkSweepGradient.cpp b/gfx/skia/skia/src/effects/gradients/SkSweepGradient.cpp index 3df71443375..ddff882e38b 100644 --- a/gfx/skia/skia/src/effects/gradients/SkSweepGradient.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkSweepGradient.cpp @@ -63,6 +63,9 @@ static unsigned SkATan2_255(float y, float x) { static const float g255Over2PI = 40.584510488433314f; float result = sk_float_atan2(y, x); + if (!SkScalarIsFinite(result)) { + return 0; + } if (result < 0) { result += 2 * SK_ScalarPI; } @@ -116,59 +119,14 @@ void SkSweepGradient::SweepGradientContext::shadeSpan(int x, int y, SkPMColor* S } } -void SkSweepGradient::SweepGradientContext::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, - int count) { - SkMatrix::MapXYProc proc = fDstToIndexProc; - const SkMatrix& matrix = fDstToIndex; - const uint16_t* SK_RESTRICT cache = fCache->getCache16(); - int toggle = init_dither_toggle16(x, y); - SkPoint srcPt; - - if (fDstToIndexClass != kPerspective_MatrixClass) { - proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, - SkIntToScalar(y) + SK_ScalarHalf, &srcPt); - SkScalar dx, fx = srcPt.fX; - SkScalar dy, fy = srcPt.fY; - - if (fDstToIndexClass == kFixedStepInX_MatrixClass) { - SkFixed storage[2]; - (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf, - &storage[0], &storage[1]); - dx = SkFixedToScalar(storage[0]); - dy = SkFixedToScalar(storage[1]); - } else { - SkASSERT(fDstToIndexClass == kLinear_MatrixClass); - dx = matrix.getScaleX(); - dy = matrix.getSkewY(); - } - - for (; count > 0; --count) { - int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits); - *dstC++ = cache[toggle + index]; - toggle = next_dither_toggle16(toggle); - fx += dx; - fy += dy; - } - } else { // perspective case - for (int stop = x + count; x < stop; x++) { - proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, - SkIntToScalar(y) + SK_ScalarHalf, &srcPt); - - int index = SkATan2_255(srcPt.fY, srcPt.fX); - index >>= (8 - kCache16Bits); - *dstC++ = cache[toggle + index]; - toggle = next_dither_toggle16(toggle); - } - } -} - ///////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU #include "SkGr.h" #include "gl/GrGLContext.h" -#include "gl/builders/GrGLProgramBuilder.h" +#include "glsl/GrGLSLCaps.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" class GrGLSweepGradient : public GrGLGradientEffect { public: @@ -247,7 +205,7 @@ const GrFragmentProcessor* GrSweepGradient::TestCreate(GrProcessorTestData* d) { void GrGLSweepGradient::emitCode(EmitArgs& args) { const GrSweepGradient& ge = args.fFp.cast(); - this->emitUniforms(args.fBuilder, ge); + this->emitUniforms(args.fUniformHandler, ge); SkString coords2D = args.fFragBuilder->ensureFSCoords2D(args.fCoords, 0); SkString t; // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi] @@ -260,8 +218,8 @@ void GrGLSweepGradient::emitCode(EmitArgs& args) { t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", coords2D.c_str(), coords2D.c_str()); } - this->emitColor(args.fBuilder, - args.fFragBuilder, + this->emitColor(args.fFragBuilder, + args.fUniformHandler, args.fGLSLCaps, ge, t.c_str(), args.fOutputColor, diff --git a/gfx/skia/skia/src/effects/gradients/SkSweepGradient.h b/gfx/skia/skia/src/effects/gradients/SkSweepGradient.h index 728a01474b4..a6a0971323b 100644 --- a/gfx/skia/skia/src/effects/gradients/SkSweepGradient.h +++ b/gfx/skia/skia/src/effects/gradients/SkSweepGradient.h @@ -22,7 +22,6 @@ public: SweepGradientContext(const SkSweepGradient& shader, const ContextRec&); void shadeSpan(int x, int y, SkPMColor dstC[], int count) override; - void shadeSpan16(int x, int y, uint16_t dstC[], int count) override; private: typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED; diff --git a/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp b/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp index 790e1153d85..918f2e06dde 100644 --- a/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp @@ -224,9 +224,6 @@ SkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradie const SkTwoPointConicalGradient& shader, const ContextRec& rec) : INHERITED(shader, rec) { - // we don't have a span16 proc - fFlags &= ~kHasSpan16_Flag; - // in general, we might discard based on computed-radius, so clear // this flag (todo: sometimes we can detect that we never discard...) fFlags &= ~kOpaqueAlpha_Flag; diff --git a/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp b/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp index 31ceda4f2ae..ac32e72c536 100644 --- a/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp +++ b/gfx/skia/skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp @@ -11,10 +11,12 @@ #include "SkTwoPointConicalGradient.h" #if SK_SUPPORT_GPU +#include "GrCoordTransform.h" +#include "GrInvariantOutput.h" #include "GrPaint.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" // For brevity typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; @@ -223,10 +225,11 @@ GLEdge2PtConicalEffect::GLEdge2PtConicalEffect(const GrProcessor&) void GLEdge2PtConicalEffect::emitCode(EmitArgs& args) { const Edge2PtConicalEffect& ge = args.fFp.cast(); - this->emitUniforms(args.fBuilder, ge); - fParamUni = args.fBuilder->addUniformArray(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "Conical2FSParams", 3); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + this->emitUniforms(uniformHandler, ge); + fParamUni = uniformHandler->addUniformArray(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "Conical2FSParams", 3); SkString cName("c"); SkString tName("t"); @@ -234,9 +237,9 @@ void GLEdge2PtConicalEffect::emitCode(EmitArgs& args) { SkString p1; // start radius squared SkString p2; // difference in radii (r1 - r0) - args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0); - args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1); - args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2); + uniformHandler->getUniformVariable(fParamUni).appendArrayAccess(0, &p0); + uniformHandler->getUniformVariable(fParamUni).appendArrayAccess(1, &p1); + uniformHandler->getUniformVariable(fParamUni).appendArrayAccess(2, &p2); // We interpolate the linear component in coords[1]. SkASSERT(args.fCoords[0].getType() == args.fCoords[1].getType()); @@ -270,8 +273,8 @@ void GLEdge2PtConicalEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(), p2.c_str(), p0.c_str()); fragBuilder->codeAppend("\t"); - this->emitColor(args.fBuilder, - fragBuilder, + this->emitColor(fragBuilder, + uniformHandler, args.fGLSLCaps, ge, tName.c_str(), @@ -505,16 +508,17 @@ GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrProcessor void GLFocalOutside2PtConicalEffect::emitCode(EmitArgs& args) { const FocalOutside2PtConicalEffect& ge = args.fFp.cast(); - this->emitUniforms(args.fBuilder, ge); - fParamUni = args.fBuilder->addUniformArray(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "Conical2FSParams", 2); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + this->emitUniforms(uniformHandler, ge); + fParamUni = uniformHandler->addUniformArray(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "Conical2FSParams", 2); SkString tName("t"); SkString p0; // focalX SkString p1; // 1 - focalX * focalX - args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0); - args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1); + uniformHandler->getUniformVariable(fParamUni).appendArrayAccess(0, &p0); + uniformHandler->getUniformVariable(fParamUni).appendArrayAccess(1, &p1); // if we have a vec3 from being in perspective, convert it to a vec2 first GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -543,8 +547,8 @@ void GLFocalOutside2PtConicalEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str()); fragBuilder->codeAppend("\t\t"); - this->emitColor(args.fBuilder, - fragBuilder, + this->emitColor(fragBuilder, + uniformHandler, args.fGLSLCaps, ge, tName.c_str(), @@ -714,15 +718,16 @@ GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrProcessor&) void GLFocalInside2PtConicalEffect::emitCode(EmitArgs& args) { const FocalInside2PtConicalEffect& ge = args.fFp.cast(); - this->emitUniforms(args.fBuilder, ge); - fFocalUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "Conical2FSParams"); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + this->emitUniforms(uniformHandler, ge); + fFocalUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "Conical2FSParams"); SkString tName("t"); // this is the distance along x-axis from the end center to focal point in // transformed coordinates - GrGLSLShaderVar focal = args.fBuilder->getUniformVariable(fFocalUni); + GrGLSLShaderVar focal = uniformHandler->getUniformVariable(fFocalUni); // if we have a vec3 from being in perspective, convert it to a vec2 first GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -731,10 +736,10 @@ void GLFocalInside2PtConicalEffect::emitCode(EmitArgs& args) { // t = p.x * focalX + length(p) fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(), - coords2D, focal.c_str(), coords2D); + coords2D, focal.c_str(), coords2D); - this->emitColor(args.fBuilder, - fragBuilder, + this->emitColor(fragBuilder, + uniformHandler, args.fGLSLCaps, ge, tName.c_str(), @@ -965,20 +970,21 @@ GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrProcessor void GLCircleInside2PtConicalEffect::emitCode(EmitArgs& args) { const CircleInside2PtConicalEffect& ge = args.fFp.cast(); - this->emitUniforms(args.fBuilder, ge); - fCenterUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "Conical2FSCenter"); - fParamUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "Conical2FSParams"); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + this->emitUniforms(uniformHandler, ge); + fCenterUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "Conical2FSCenter"); + fParamUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, kDefault_GrSLPrecision, + "Conical2FSParams"); SkString tName("t"); - GrGLSLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni); + GrGLSLShaderVar center = uniformHandler->getUniformVariable(fCenterUni); // params.x = A // params.y = B // params.z = C - GrGLSLShaderVar params = args.fBuilder->getUniformVariable(fParamUni); + GrGLSLShaderVar params = uniformHandler->getUniformVariable(fParamUni); // if we have a vec3 from being in perspective, convert it to a vec2 first GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -999,8 +1005,8 @@ void GLCircleInside2PtConicalEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n", tName.c_str(), params.c_str(), params.c_str()); - this->emitColor(args.fBuilder, - fragBuilder, + this->emitColor(fragBuilder, + uniformHandler, args.fGLSLCaps, ge, tName.c_str(), @@ -1201,20 +1207,21 @@ GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrProcess void GLCircleOutside2PtConicalEffect::emitCode(EmitArgs& args) { const CircleOutside2PtConicalEffect& ge = args.fFp.cast(); - this->emitUniforms(args.fBuilder, ge); - fCenterUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "Conical2FSCenter"); - fParamUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "Conical2FSParams"); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + this->emitUniforms(uniformHandler, ge); + fCenterUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "Conical2FSCenter"); + fParamUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "Conical2FSParams"); SkString tName("t"); - GrGLSLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni); + GrGLSLShaderVar center = uniformHandler->getUniformVariable(fCenterUni); // params.x = A // params.y = B // params.z = C - GrGLSLShaderVar params = args.fBuilder->getUniformVariable(fParamUni); + GrGLSLShaderVar params = uniformHandler->getUniformVariable(fParamUni); // if we have a vec3 from being in perspective, convert it to a vec2 first GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -1248,10 +1255,11 @@ void GLCircleOutside2PtConicalEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str()); } - fragBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str()); + fragBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", + tName.c_str(), params.c_str()); fragBuilder->codeAppend("\t\t"); - this->emitColor(args.fBuilder, - fragBuilder, + this->emitColor(fragBuilder, + uniformHandler, args.fGLSLCaps, ge, tName.c_str(), diff --git a/gfx/skia/skia/src/gpu/GrAtlasTextBlob.cpp b/gfx/skia/skia/src/gpu/GrAtlasTextBlob.cpp deleted file mode 100644 index 3fb7ac99c16..00000000000 --- a/gfx/skia/skia/src/gpu/GrAtlasTextBlob.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrAtlasTextBlob.h" - -#ifdef CACHE_SANITY_CHECK -void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlob& r) { - SkASSERT(l.fSize == r.fSize); - SkASSERT(l.fPool == r.fPool); - - SkASSERT(l.fBlurRec.fSigma == r.fBlurRec.fSigma); - SkASSERT(l.fBlurRec.fStyle == r.fBlurRec.fStyle); - SkASSERT(l.fBlurRec.fQuality == r.fBlurRec.fQuality); - - SkASSERT(l.fStrokeInfo.fFrameWidth == r.fStrokeInfo.fFrameWidth); - SkASSERT(l.fStrokeInfo.fMiterLimit == r.fStrokeInfo.fMiterLimit); - SkASSERT(l.fStrokeInfo.fJoin == r.fStrokeInfo.fJoin); - - SkASSERT(l.fBigGlyphs.count() == r.fBigGlyphs.count()); - for (int i = 0; i < l.fBigGlyphs.count(); i++) { - const BigGlyph& lBigGlyph = l.fBigGlyphs[i]; - const BigGlyph& rBigGlyph = r.fBigGlyphs[i]; - - SkASSERT(lBigGlyph.fPath == rBigGlyph.fPath); - // We can't assert that these have the same translations - } - - SkASSERT(l.fKey == r.fKey); - SkASSERT(l.fViewMatrix.cheapEqualTo(r.fViewMatrix)); - SkASSERT(l.fPaintColor == r.fPaintColor); - SkASSERT(l.fMaxMinScale == r.fMaxMinScale); - SkASSERT(l.fMinMaxScale == r.fMinMaxScale); - SkASSERT(l.fTextType == r.fTextType); - - SkASSERT(l.fRunCount == r.fRunCount); - for (int i = 0; i < l.fRunCount; i++) { - const Run& lRun = l.fRuns[i]; - const Run& rRun = r.fRuns[i]; - - if (lRun.fStrike.get()) { - SkASSERT(rRun.fStrike.get()); - SkASSERT(GrBatchTextStrike::GetKey(*lRun.fStrike) == - GrBatchTextStrike::GetKey(*rRun.fStrike)); - - } else { - SkASSERT(!rRun.fStrike.get()); - } - - if (lRun.fTypeface.get()) { - SkASSERT(rRun.fTypeface.get()); - SkASSERT(SkTypeface::Equal(lRun.fTypeface, rRun.fTypeface)); - } else { - SkASSERT(!rRun.fTypeface.get()); - } - - // We offset bounds right before flush time so they will not be correct here - //SkASSERT(lRun.fVertexBounds == rRun.fVertexBounds); - - SkASSERT(lRun.fDescriptor.getDesc()); - SkASSERT(rRun.fDescriptor.getDesc()); - SkASSERT(lRun.fDescriptor.getDesc()->equals(*rRun.fDescriptor.getDesc())); - - if (lRun.fOverrideDescriptor.get()) { - SkASSERT(lRun.fOverrideDescriptor->getDesc()); - SkASSERT(rRun.fOverrideDescriptor.get() && rRun.fOverrideDescriptor->getDesc());; - SkASSERT(lRun.fOverrideDescriptor->getDesc()->equals( - *rRun.fOverrideDescriptor->getDesc())); - } else { - SkASSERT(!rRun.fOverrideDescriptor.get()); - } - - // color can be changed - //SkASSERT(lRun.fColor == rRun.fColor); - SkASSERT(lRun.fInitialized == rRun.fInitialized); - SkASSERT(lRun.fDrawAsPaths == rRun.fDrawAsPaths); - - SkASSERT(lRun.fSubRunInfo.count() == rRun.fSubRunInfo.count()); - for(int j = 0; j < lRun.fSubRunInfo.count(); j++) { - const Run::SubRunInfo& lSubRun = lRun.fSubRunInfo[j]; - const Run::SubRunInfo& rSubRun = rRun.fSubRunInfo[j]; - - SkASSERT(lSubRun.fVertexStartIndex == rSubRun.fVertexStartIndex); - SkASSERT(lSubRun.fVertexEndIndex == rSubRun.fVertexEndIndex); - SkASSERT(lSubRun.fGlyphStartIndex == rSubRun.fGlyphStartIndex); - SkASSERT(lSubRun.fGlyphEndIndex == rSubRun.fGlyphEndIndex); - SkASSERT(lSubRun.fTextRatio == rSubRun.fTextRatio); - SkASSERT(lSubRun.fMaskFormat == rSubRun.fMaskFormat); - SkASSERT(lSubRun.fDrawAsDistanceFields == rSubRun.fDrawAsDistanceFields); - SkASSERT(lSubRun.fUseLCDText == rSubRun.fUseLCDText); - - //We can't compare the bulk use tokens with this method - /* - SkASSERT(lSubRun.fBulkUseToken.fPlotsToUpdate.count() == - rSubRun.fBulkUseToken.fPlotsToUpdate.count()); - SkASSERT(lSubRun.fBulkUseToken.fPlotAlreadyUpdated == - rSubRun.fBulkUseToken.fPlotAlreadyUpdated); - for (int k = 0; k < lSubRun.fBulkUseToken.fPlotsToUpdate.count(); k++) { - SkASSERT(lSubRun.fBulkUseToken.fPlotsToUpdate[k] == - rSubRun.fBulkUseToken.fPlotsToUpdate[k]); - }*/ - } - } -} - -#endif diff --git a/gfx/skia/skia/src/gpu/GrAtlasTextContext.cpp b/gfx/skia/skia/src/gpu/GrAtlasTextContext.cpp deleted file mode 100644 index 7d0d93684cd..00000000000 --- a/gfx/skia/skia/src/gpu/GrAtlasTextContext.cpp +++ /dev/null @@ -1,1398 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "GrAtlasTextContext.h" - -#include "GrBlurUtils.h" -#include "GrDrawContext.h" -#include "GrDrawTarget.h" -#include "GrFontScaler.h" -#include "GrStrokeInfo.h" -#include "GrTextBlobCache.h" -#include "GrTexturePriv.h" -#include "GrVertexBuffer.h" - -#include "SkAutoKern.h" -#include "SkColorPriv.h" -#include "SkColorFilter.h" -#include "SkDistanceFieldGen.h" -#include "SkDraw.h" -#include "SkDrawFilter.h" -#include "SkDrawProcs.h" -#include "SkFindAndPlaceGlyph.h" -#include "SkGlyphCache.h" -#include "SkGpuDevice.h" -#include "SkGrPriv.h" -#include "SkPath.h" -#include "SkRTConf.h" -#include "SkStrokeRec.h" -#include "SkTextBlob.h" -#include "SkTextMapStateProc.h" - -#include "batches/GrAtlasTextBatch.h" - -namespace { -static const int kMinDFFontSize = 18; -static const int kSmallDFFontSize = 32; -static const int kSmallDFFontLimit = 32; -static const int kMediumDFFontSize = 72; -static const int kMediumDFFontLimit = 72; -static const int kLargeDFFontSize = 162; -#ifdef SK_BUILD_FOR_ANDROID -static const int kLargeDFFontLimit = 384; -#else -static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; -#endif - -SkDEBUGCODE(static const int kExpectedDistanceAdjustTableSize = 8;) -}; - -GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps& surfaceProps) - : INHERITED(context, surfaceProps) - , fDistanceAdjustTable(new DistanceAdjustTable) { - // We overallocate vertices in our textblobs based on the assumption that A8 has the greatest - // vertexStride - static_assert(GrAtlasTextBatch::kGrayTextVASize >= GrAtlasTextBatch::kColorTextVASize && - GrAtlasTextBatch::kGrayTextVASize >= GrAtlasTextBatch::kLCDTextVASize, - "vertex_attribute_changed"); - fCurrStrike = nullptr; - fCache = context->getTextBlobCache(); -} - -void GrAtlasTextContext::DistanceAdjustTable::buildDistanceAdjustTable() { - - // This is used for an approximation of the mask gamma hack, used by raster and bitmap - // text. The mask gamma hack is based off of guessing what the blend color is going to - // be, and adjusting the mask so that when run through the linear blend will - // produce the value closest to the desired result. However, in practice this means - // that the 'adjusted' mask is just increasing or decreasing the coverage of - // the mask depending on what it is thought it will blit against. For black (on - // assumed white) this means that coverages are decreased (on a curve). For white (on - // assumed black) this means that coverages are increased (on a a curve). At - // middle (perceptual) gray (which could be blit against anything) the coverages - // remain the same. - // - // The idea here is that instead of determining the initial (real) coverage and - // then adjusting that coverage, we determine an adjusted coverage directly by - // essentially manipulating the geometry (in this case, the distance to the glyph - // edge). So for black (on assumed white) this thins a bit; for white (on - // assumed black) this fake bolds the geometry a bit. - // - // The distance adjustment is calculated by determining the actual coverage value which - // when fed into in the mask gamma table gives us an 'adjusted coverage' value of 0.5. This - // actual coverage value (assuming it's between 0 and 1) corresponds to a distance from the - // actual edge. So by subtracting this distance adjustment and computing without the - // the coverage adjustment we should get 0.5 coverage at the same point. - // - // This has several implications: - // For non-gray lcd smoothed text, each subpixel essentially is using a - // slightly different geometry. - // - // For black (on assumed white) this may not cover some pixels which were - // previously covered; however those pixels would have been only slightly - // covered and that slight coverage would have been decreased anyway. Also, some pixels - // which were previously fully covered may no longer be fully covered. - // - // For white (on assumed black) this may cover some pixels which weren't - // previously covered at all. - - int width, height; - size_t size; - -#ifdef SK_GAMMA_CONTRAST - SkScalar contrast = SK_GAMMA_CONTRAST; -#else - SkScalar contrast = 0.5f; -#endif - SkScalar paintGamma = SK_GAMMA_EXPONENT; - SkScalar deviceGamma = SK_GAMMA_EXPONENT; - - size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma, - &width, &height); - - SkASSERT(kExpectedDistanceAdjustTableSize == height); - fTable = new SkScalar[height]; - - SkAutoTArray data((int)size); - SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get()); - - // find the inverse points where we cross 0.5 - // binsearch might be better, but we only need to do this once on creation - for (int row = 0; row < height; ++row) { - uint8_t* rowPtr = data.get() + row*width; - for (int col = 0; col < width - 1; ++col) { - if (rowPtr[col] <= 127 && rowPtr[col + 1] >= 128) { - // compute point where a mask value will give us a result of 0.5 - float interp = (127.5f - rowPtr[col]) / (rowPtr[col + 1] - rowPtr[col]); - float borderAlpha = (col + interp) / 255.f; - - // compute t value for that alpha - // this is an approximate inverse for smoothstep() - float t = borderAlpha*(borderAlpha*(4.0f*borderAlpha - 6.0f) + 5.0f) / 3.0f; - - // compute distance which gives us that t value - const float kDistanceFieldAAFactor = 0.65f; // should match SK_DistanceFieldAAFactor - float d = 2.0f*kDistanceFieldAAFactor*t - kDistanceFieldAAFactor; - - fTable[row] = d; - break; - } - } - } -} - -GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, - const SkSurfaceProps& surfaceProps) { - return new GrAtlasTextContext(context, surfaceProps); -} - -bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, const SkMatrix& viewMatrix) { - return this->canDrawAsDistanceFields(skPaint, viewMatrix) || - !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); -} - -GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd) { - GrColor canonicalColor = paint.computeLuminanceColor(); - if (lcd) { - // This is the correct computation, but there are tons of cases where LCD can be overridden. - // For now we just regenerate if any run in a textblob has LCD. - // TODO figure out where all of these overrides are and see if we can incorporate that logic - // at a higher level *OR* use sRGB - SkASSERT(false); - //canonicalColor = SkMaskGamma::CanonicalColor(canonicalColor); - } else { - // A8, though can have mixed BMP text but it shouldn't matter because BMP text won't have - // gamma corrected masks anyways, nor color - U8CPU lum = SkComputeLuminance(SkColorGetR(canonicalColor), - SkColorGetG(canonicalColor), - SkColorGetB(canonicalColor)); - // reduce to our finite number of bits - canonicalColor = SkMaskGamma::CanonicalColor(SkColorSetRGB(lum, lum, lum)); - } - return canonicalColor; -} - -// TODO if this function ever shows up in profiling, then we can compute this value when the -// textblob is being built and cache it. However, for the time being textblobs mostly only have 1 -// run so this is not a big deal to compute here. -bool GrAtlasTextContext::HasLCD(const SkTextBlob* blob) { - SkTextBlobRunIterator it(blob); - for (; !it.done(); it.next()) { - if (it.isLCD()) { - return true; - } - } - return false; -} - -bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY, - const GrAtlasTextBlob& blob, const SkPaint& paint, - GrColor color, const SkMaskFilter::BlurRec& blurRec, - const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { - // If we have LCD text then our canonical color will be set to transparent, in this case we have - // to regenerate the blob on any color change - // We use the grPaint to get any color filter effects - if (blob.fKey.fCanonicalColor == SK_ColorTRANSPARENT && - blob.fPaintColor != color) { - return true; - } - - if (blob.fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) { - return true; - } - - if (blob.fViewMatrix.hasPerspective() && !blob.fViewMatrix.cheapEqualTo(viewMatrix)) { - return true; - } - - // We only cache one masked version - if (blob.fKey.fHasBlur && - (blob.fBlurRec.fSigma != blurRec.fSigma || - blob.fBlurRec.fStyle != blurRec.fStyle || - blob.fBlurRec.fQuality != blurRec.fQuality)) { - return true; - } - - // Similarly, we only cache one version for each style - if (blob.fKey.fStyle != SkPaint::kFill_Style && - (blob.fStrokeInfo.fFrameWidth != paint.getStrokeWidth() || - blob.fStrokeInfo.fMiterLimit != paint.getStrokeMiter() || - blob.fStrokeInfo.fJoin != paint.getStrokeJoin())) { - return true; - } - - // Mixed blobs must be regenerated. We could probably figure out a way to do integer scrolls - // for mixed blobs if this becomes an issue. - if (blob.hasBitmap() && blob.hasDistanceField()) { - // Identical viewmatrices and we can reuse in all cases - if (blob.fViewMatrix.cheapEqualTo(viewMatrix) && x == blob.fX && y == blob.fY) { - return false; - } - return true; - } - - if (blob.hasBitmap()) { - if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() || - blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() || - blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() || - blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { - return true; - } - - // We can update the positions in the cachedtextblobs without regenerating the whole blob, - // but only for integer translations. - // This cool bit of math will determine the necessary translation to apply to the already - // generated vertex coordinates to move them to the correct position - SkScalar transX = viewMatrix.getTranslateX() + - viewMatrix.getScaleX() * (x - blob.fX) + - viewMatrix.getSkewX() * (y - blob.fY) - - blob.fViewMatrix.getTranslateX(); - SkScalar transY = viewMatrix.getTranslateY() + - viewMatrix.getSkewY() * (x - blob.fX) + - viewMatrix.getScaleY() * (y - blob.fY) - - blob.fViewMatrix.getTranslateY(); - if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY) ) { - return true; - } - - (*outTransX) = transX; - (*outTransY) = transY; - } else if (blob.hasDistanceField()) { - // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different - // distance field being generated, so we have to regenerate in those cases - SkScalar newMaxScale = viewMatrix.getMaxScale(); - SkScalar oldMaxScale = blob.fViewMatrix.getMaxScale(); - SkScalar scaleAdjust = newMaxScale / oldMaxScale; - if (scaleAdjust < blob.fMaxMinScale || scaleAdjust > blob.fMinMaxScale) { - return true; - } - - (*outTransX) = x - blob.fX; - (*outTransY) = y - blob.fY; - } - - // It is possible that a blob has neither distanceField nor bitmaptext. This is in the case - // when all of the runs inside the blob are drawn as paths. In this case, we always regenerate - // the blob anyways at flush time, so no need to regenerate explicitly - return false; -} - - -inline SkGlyphCache* GrAtlasTextContext::setupCache(GrAtlasTextBlob::Run* run, - const SkPaint& skPaint, - const SkMatrix* viewMatrix, - bool noGamma) { - skPaint.getScalerContextDescriptor(&run->fDescriptor, fSurfaceProps, viewMatrix, noGamma); - run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); - return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc()); -} - -void GrAtlasTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarget* rt, - const GrClip& clip, const SkPaint& skPaint, - const SkMatrix& viewMatrix, const SkTextBlob* blob, - SkScalar x, SkScalar y, - SkDrawFilter* drawFilter, const SkIRect& clipBounds) { - // If we have been abandoned, then don't draw - if (fContext->abandoned()) { - return; - } - - SkAutoTUnref cacheBlob; - SkMaskFilter::BlurRec blurRec; - GrAtlasTextBlob::Key key; - // It might be worth caching these things, but its not clear at this time - // TODO for animated mask filters, this will fill up our cache. We need a safeguard here - const SkMaskFilter* mf = skPaint.getMaskFilter(); - bool canCache = !(skPaint.getPathEffect() || - (mf && !mf->asABlur(&blurRec)) || - drawFilter); - - if (canCache) { - bool hasLCD = HasLCD(blob); - - // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry - SkPixelGeometry pixelGeometry = hasLCD ? fSurfaceProps.pixelGeometry() : - kUnknown_SkPixelGeometry; - - // TODO we want to figure out a way to be able to use the canonical color on LCD text, - // see the note on ComputeCanonicalColor above. We pick a dummy value for LCD text to - // ensure we always match the same key - GrColor canonicalColor = hasLCD ? SK_ColorTRANSPARENT : - ComputeCanonicalColor(skPaint, hasLCD); - - key.fPixelGeometry = pixelGeometry; - key.fUniqueID = blob->uniqueID(); - key.fStyle = skPaint.getStyle(); - key.fHasBlur = SkToBool(mf); - key.fCanonicalColor = canonicalColor; - cacheBlob.reset(SkSafeRef(fCache->find(key))); - } - - SkScalar transX = 0.f; - SkScalar transY = 0.f; - - // Though for the time being runs in the textblob can override the paint, they only touch font - // info. - GrPaint grPaint; - if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &grPaint)) { - return; - } - - if (cacheBlob) { - if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, grPaint.getColor(), blurRec, - viewMatrix, x, y)) { - // We have to remake the blob because changes may invalidate our masks. - // TODO we could probably get away reuse most of the time if the pointer is unique, - // but we'd have to clear the subrun information - fCache->remove(cacheBlob); - cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint, - GrAtlasTextBatch::kGrayTextVASize))); - this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, - blob, x, y, drawFilter, clip); - } else { - // If we can reuse the blob, then make sure we update the blob's viewmatrix, and x/y - // offsets. Note, we offset the vertex bounds right before flushing - cacheBlob->fViewMatrix = viewMatrix; - cacheBlob->fX = x; - cacheBlob->fY = y; - fCache->makeMRU(cacheBlob); -#ifdef CACHE_SANITY_CHECK - { - int glyphCount = 0; - int runCount = 0; - GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob); - SkAutoTUnref sanityBlob(fCache->createBlob(glyphCount, runCount, - kGrayTextVASize)); - GrTextBlobCache::SetupCacheBlobKey(sanityBlob, key, blurRec, skPaint); - this->regenerateTextBlob(sanityBlob, skPaint, grPaint.getColor(), viewMatrix, - blob, x, y, drawFilter, clip); - GrAtlasTextBlob::AssertEqual(*sanityBlob, *cacheBlob); - } - -#endif - } - } else { - if (canCache) { - cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint, - GrAtlasTextBatch::kGrayTextVASize))); - } else { - cacheBlob.reset(fCache->createBlob(blob, GrAtlasTextBatch::kGrayTextVASize)); - } - this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, - blob, x, y, drawFilter, clip); - } - - this->flush(blob, cacheBlob, dc, rt, skPaint, grPaint, drawFilter, - clip, viewMatrix, clipBounds, x, y, transX, transY); -} - -inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, - const SkMatrix& viewMatrix) { - // TODO: support perspective (need getMaxScale replacement) - if (viewMatrix.hasPerspective()) { - return false; - } - - SkScalar maxScale = viewMatrix.getMaxScale(); - SkScalar scaledTextSize = maxScale*skPaint.getTextSize(); - // Hinted text looks far better at small resolutions - // Scaling up beyond 2x yields undesireable artifacts - if (scaledTextSize < kMinDFFontSize || scaledTextSize > kLargeDFFontLimit) { - return false; - } - - bool useDFT = fSurfaceProps.isUseDeviceIndependentFonts(); -#if SK_FORCE_DISTANCE_FIELD_TEXT - useDFT = true; -#endif - - if (!useDFT && scaledTextSize < kLargeDFFontSize) { - return false; - } - - // rasterizers and mask filters modify alpha, which doesn't - // translate well to distance - if (skPaint.getRasterizer() || skPaint.getMaskFilter() || - !fContext->caps()->shaderCaps()->shaderDerivativeSupport()) { - return false; - } - - // TODO: add some stroking support - if (skPaint.getStyle() != SkPaint::kFill_Style) { - return false; - } - - return true; -} - -void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, - const SkPaint& skPaint, GrColor color, - const SkMatrix& viewMatrix, - const SkTextBlob* blob, SkScalar x, SkScalar y, - SkDrawFilter* drawFilter, - const GrClip& clip) { - // The color here is the GrPaint color, and it is used to determine whether we - // have to regenerate LCD text blobs. - // We use this color vs the SkPaint color because it has the colorfilter applied. - cacheBlob->fPaintColor = color; - cacheBlob->fViewMatrix = viewMatrix; - cacheBlob->fX = x; - cacheBlob->fY = y; - - // Regenerate textblob - SkPaint runPaint = skPaint; - SkTextBlobRunIterator it(blob); - for (int run = 0; !it.done(); it.next(), run++) { - int glyphCount = it.glyphCount(); - size_t textLen = glyphCount * sizeof(uint16_t); - const SkPoint& offset = it.offset(); - // applyFontToPaint() always overwrites the exact same attributes, - // so it is safe to not re-seed the paint for this reason. - it.applyFontToPaint(&runPaint); - - if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) { - // A false return from filter() means we should abort the current draw. - runPaint = skPaint; - continue; - } - - runPaint.setFlags(FilterTextFlags(fSurfaceProps, runPaint)); - - // setup vertex / glyphIndex for the new run - if (run > 0) { - PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); - PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back(); - - newRun.fVertexStartIndex = lastRun.fVertexEndIndex; - newRun.fVertexEndIndex = lastRun.fVertexEndIndex; - - newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; - newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; - } - - if (this->canDrawAsDistanceFields(runPaint, viewMatrix)) { - cacheBlob->setHasDistanceField(); - SkPaint dfPaint = runPaint; - SkScalar textRatio; - this->initDistanceFieldPaint(cacheBlob, &dfPaint, &textRatio, viewMatrix); - Run& runIdx = cacheBlob->fRuns[run]; - PerSubRunInfo& subRun = runIdx.fSubRunInfo.back(); - subRun.fUseLCDText = runPaint.isLCDRenderText(); - subRun.fDrawAsDistanceFields = true; - - SkTDArray fallbackTxt; - SkTDArray fallbackPos; - SkPoint dfOffset; - int scalarsPerPosition = 2; - switch (it.positioning()) { - case SkTextBlob::kDefault_Positioning: { - this->internalDrawDFText(cacheBlob, run, dfPaint, color, viewMatrix, - (const char *)it.glyphs(), textLen, - x + offset.x(), y + offset.y(), textRatio, - &fallbackTxt, &fallbackPos, &dfOffset, runPaint); - break; - } - case SkTextBlob::kHorizontal_Positioning: { - scalarsPerPosition = 1; - dfOffset = SkPoint::Make(x, y + offset.y()); - this->internalDrawDFPosText(cacheBlob, run, dfPaint, color, viewMatrix, - (const char*)it.glyphs(), textLen, it.pos(), - scalarsPerPosition, dfOffset, textRatio, - &fallbackTxt, &fallbackPos); - break; - } - case SkTextBlob::kFull_Positioning: { - dfOffset = SkPoint::Make(x, y); - this->internalDrawDFPosText(cacheBlob, run, dfPaint, color, viewMatrix, - (const char*)it.glyphs(), textLen, it.pos(), - scalarsPerPosition, dfOffset, textRatio, - &fallbackTxt, &fallbackPos); - break; - } - } - if (fallbackTxt.count()) { - this->fallbackDrawPosText(cacheBlob, run, clip, color, runPaint, viewMatrix, - fallbackTxt, fallbackPos, scalarsPerPosition, dfOffset); - } - } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { - cacheBlob->fRuns[run].fDrawAsPaths = true; - } else { - cacheBlob->setHasBitmap(); - SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint, &viewMatrix, - false); - switch (it.positioning()) { - case SkTextBlob::kDefault_Positioning: - this->internalDrawBMPText(cacheBlob, run, cache, runPaint, color, viewMatrix, - (const char *)it.glyphs(), textLen, - x + offset.x(), y + offset.y()); - break; - case SkTextBlob::kHorizontal_Positioning: - this->internalDrawBMPPosText(cacheBlob, run, cache, runPaint, color, viewMatrix, - (const char*)it.glyphs(), textLen, it.pos(), 1, - SkPoint::Make(x, y + offset.y())); - break; - case SkTextBlob::kFull_Positioning: - this->internalDrawBMPPosText(cacheBlob, run, cache, runPaint, color, viewMatrix, - (const char*)it.glyphs(), textLen, it.pos(), 2, - SkPoint::Make(x, y)); - break; - } - SkGlyphCache::AttachCache(cache); - } - - if (drawFilter) { - // A draw filter may change the paint arbitrarily, so we must re-seed in this case. - runPaint = skPaint; - } - } -} - -inline void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob, - SkPaint* skPaint, - SkScalar* textRatio, - const SkMatrix& viewMatrix) { - // getMaxScale doesn't support perspective, so neither do we at the moment - SkASSERT(!viewMatrix.hasPerspective()); - SkScalar maxScale = viewMatrix.getMaxScale(); - SkScalar textSize = skPaint->getTextSize(); - SkScalar scaledTextSize = textSize; - // if we have non-unity scale, we need to choose our base text size - // based on the SkPaint's text size multiplied by the max scale factor - // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? - if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { - scaledTextSize *= maxScale; - } - - // We have three sizes of distance field text, and within each size 'bucket' there is a floor - // and ceiling. A scale outside of this range would require regenerating the distance fields - SkScalar dfMaskScaleFloor; - SkScalar dfMaskScaleCeil; - if (scaledTextSize <= kSmallDFFontLimit) { - dfMaskScaleFloor = kMinDFFontSize; - dfMaskScaleCeil = kSmallDFFontLimit; - *textRatio = textSize / kSmallDFFontSize; - skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize)); - } else if (scaledTextSize <= kMediumDFFontLimit) { - dfMaskScaleFloor = kSmallDFFontLimit; - dfMaskScaleCeil = kMediumDFFontLimit; - *textRatio = textSize / kMediumDFFontSize; - skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize)); - } else { - dfMaskScaleFloor = kMediumDFFontLimit; - dfMaskScaleCeil = kLargeDFFontLimit; - *textRatio = textSize / kLargeDFFontSize; - skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize)); - } - - // Because there can be multiple runs in the blob, we want the overall maxMinScale, and - // minMaxScale to make regeneration decisions. Specifically, we want the maximum minimum scale - // we can tolerate before we'd drop to a lower mip size, and the minimum maximum scale we can - // tolerate before we'd have to move to a large mip size. When we actually test these values - // we look at the delta in scale between the new viewmatrix and the old viewmatrix, and test - // against these values to decide if we can reuse or not(ie, will a given scale change our mip - // level) - SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScaleCeil); - blob->fMaxMinScale = SkMaxScalar(dfMaskScaleFloor / scaledTextSize, blob->fMaxMinScale); - blob->fMinMaxScale = SkMinScalar(dfMaskScaleCeil / scaledTextSize, blob->fMinMaxScale); - - skPaint->setLCDRenderText(false); - skPaint->setAutohinted(false); - skPaint->setHinting(SkPaint::kNormal_Hinting); - skPaint->setSubpixelText(true); -} - -inline void GrAtlasTextContext::fallbackDrawPosText(GrAtlasTextBlob* blob, - int runIndex, - const GrClip& clip, - GrColor color, - const SkPaint& skPaint, - const SkMatrix& viewMatrix, - const SkTDArray& fallbackTxt, - const SkTDArray& fallbackPos, - int scalarsPerPosition, - const SkPoint& offset) { - SkASSERT(fallbackTxt.count()); - blob->setHasBitmap(); - Run& run = blob->fRuns[runIndex]; - // Push back a new subrun to fill and set the override descriptor - run.push_back(); - run.fOverrideDescriptor.reset(new SkAutoDescriptor); - skPaint.getScalerContextDescriptor(run.fOverrideDescriptor, - fSurfaceProps, &viewMatrix, false); - SkGlyphCache* cache = SkGlyphCache::DetachCache(run.fTypeface, - run.fOverrideDescriptor->getDesc()); - this->internalDrawBMPPosText(blob, runIndex, cache, skPaint, color, viewMatrix, - fallbackTxt.begin(), fallbackTxt.count(), - fallbackPos.begin(), scalarsPerPosition, offset); - SkGlyphCache::AttachCache(cache); -} - -inline GrAtlasTextBlob* -GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, - const SkMatrix& viewMatrix, SkPaint* dfPaint, - SkScalar* textRatio) { - GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBatch::kGrayTextVASize); - - *dfPaint = origPaint; - this->initDistanceFieldPaint(blob, dfPaint, textRatio, viewMatrix); - blob->fViewMatrix = viewMatrix; - Run& run = blob->fRuns[0]; - PerSubRunInfo& subRun = run.fSubRunInfo.back(); - subRun.fUseLCDText = origPaint.isLCDRenderText(); - subRun.fDrawAsDistanceFields = true; - - return blob; -} - -inline GrAtlasTextBlob* -GrAtlasTextContext::createDrawTextBlob(const GrClip& clip, - const GrPaint& paint, const SkPaint& skPaint, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkIRect& regionClipBounds) { - int glyphCount = skPaint.countText(text, byteLength); - - GrAtlasTextBlob* blob; - if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { - SkPaint dfPaint; - SkScalar textRatio; - blob = this->setupDFBlob(glyphCount, skPaint, viewMatrix, &dfPaint, &textRatio); - - SkTDArray fallbackTxt; - SkTDArray fallbackPos; - SkPoint offset; - this->internalDrawDFText(blob, 0, dfPaint, paint.getColor(), viewMatrix, text, - byteLength, x, y, textRatio, &fallbackTxt, &fallbackPos, - &offset, skPaint); - if (fallbackTxt.count()) { - this->fallbackDrawPosText(blob, 0, clip, paint.getColor(), skPaint, viewMatrix, - fallbackTxt, fallbackPos, 2, offset); - } - } else { - blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBatch::kGrayTextVASize); - blob->fViewMatrix = viewMatrix; - - SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMatrix, false); - this->internalDrawBMPText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix, text, - byteLength, x, y); - SkGlyphCache::AttachCache(cache); - } - return blob; -} - -inline GrAtlasTextBlob* -GrAtlasTextContext::createDrawPosTextBlob(const GrClip& clip, - const GrPaint& paint, const SkPaint& skPaint, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkIRect& regionClipBounds) { - int glyphCount = skPaint.countText(text, byteLength); - - GrAtlasTextBlob* blob; - if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { - SkPaint dfPaint; - SkScalar textRatio; - blob = this->setupDFBlob(glyphCount, skPaint, viewMatrix, &dfPaint, &textRatio); - - SkTDArray fallbackTxt; - SkTDArray fallbackPos; - this->internalDrawDFPosText(blob, 0, dfPaint, paint.getColor(), viewMatrix, text, - byteLength, pos, scalarsPerPosition, offset, - textRatio, &fallbackTxt, &fallbackPos); - if (fallbackTxt.count()) { - this->fallbackDrawPosText(blob, 0, clip, paint.getColor(), skPaint, viewMatrix, - fallbackTxt, fallbackPos, scalarsPerPosition, offset); - } - } else { - blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBatch::kGrayTextVASize); - blob->fViewMatrix = viewMatrix; - SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMatrix, false); - this->internalDrawBMPPosText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix, text, - byteLength, pos, scalarsPerPosition, offset); - SkGlyphCache::AttachCache(cache); - } - return blob; -} - -void GrAtlasTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* rt, - const GrClip& clip, - const GrPaint& paint, const SkPaint& skPaint, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkIRect& regionClipBounds) { - SkAutoTUnref blob( - this->createDrawTextBlob(clip, paint, skPaint, viewMatrix, - text, byteLength, x, y, regionClipBounds)); - this->flush(blob, dc, rt, skPaint, paint, clip, regionClipBounds); -} - -void GrAtlasTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarget* rt, - const GrClip& clip, - const GrPaint& paint, const SkPaint& skPaint, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkIRect& regionClipBounds) { - SkAutoTUnref blob( - this->createDrawPosTextBlob(clip, paint, skPaint, viewMatrix, - text, byteLength, - pos, scalarsPerPosition, - offset, regionClipBounds)); - - this->flush(blob, dc, rt, skPaint, paint, clip, regionClipBounds); -} - -void GrAtlasTextContext::internalDrawBMPText(GrAtlasTextBlob* blob, int runIndex, - SkGlyphCache* cache, const SkPaint& skPaint, - GrColor color, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - SkScalar x, SkScalar y) { - SkASSERT(byteLength == 0 || text != nullptr); - - // nothing to draw - if (text == nullptr || byteLength == 0) { - return; - } - - fCurrStrike = nullptr; - - // Get GrFontScaler from cache - GrFontScaler* fontScaler = GetGrFontScaler(cache); - - SkFindAndPlaceGlyph::ProcessText( - skPaint.getTextEncoding(), text, byteLength, - {x, y}, viewMatrix, skPaint.getTextAlign(), - cache, - [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { - position += rounding; - this->bmpAppendGlyph( - blob, runIndex, glyph, - SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY), - color, fontScaler); - } - ); -} - -void GrAtlasTextContext::internalDrawBMPPosText(GrAtlasTextBlob* blob, int runIndex, - SkGlyphCache* cache, const SkPaint& skPaint, - GrColor color, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset) { - SkASSERT(byteLength == 0 || text != nullptr); - SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); - - // nothing to draw - if (text == nullptr || byteLength == 0) { - return; - } - - fCurrStrike = nullptr; - - // Get GrFontScaler from cache - GrFontScaler* fontScaler = GetGrFontScaler(cache); - - SkFindAndPlaceGlyph::ProcessPosText( - skPaint.getTextEncoding(), text, byteLength, - offset, viewMatrix, pos, scalarsPerPosition, - skPaint.getTextAlign(), cache, - [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { - position += rounding; - this->bmpAppendGlyph( - blob, runIndex, glyph, - SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY), - color, fontScaler); - } - ); -} - -void GrAtlasTextContext::internalDrawDFText(GrAtlasTextBlob* blob, int runIndex, - const SkPaint& skPaint, GrColor color, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - SkScalar x, SkScalar y, - SkScalar textRatio, - SkTDArray* fallbackTxt, - SkTDArray* fallbackPos, - SkPoint* offset, - const SkPaint& origPaint) { - SkASSERT(byteLength == 0 || text != nullptr); - - // nothing to draw - if (text == nullptr || byteLength == 0) { - return; - } - - SkDrawCacheProc glyphCacheProc = origPaint.getDrawCacheProc(); - SkAutoDescriptor desc; - origPaint.getScalerContextDescriptor(&desc, fSurfaceProps, nullptr, true); - SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(origPaint.getTypeface(), - desc.getDesc()); - - SkTArray positions; - - const char* textPtr = text; - SkFixed stopX = 0; - SkFixed stopY = 0; - SkFixed origin = 0; - switch (origPaint.getTextAlign()) { - case SkPaint::kRight_Align: origin = SK_Fixed1; break; - case SkPaint::kCenter_Align: origin = SK_FixedHalf; break; - case SkPaint::kLeft_Align: origin = 0; break; - } - - SkAutoKern autokern; - const char* stop = text + byteLength; - while (textPtr < stop) { - // don't need x, y here, since all subpixel variants will have the - // same advance - const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr, 0, 0); - - SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph); - positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width))); - - SkFixed height = glyph.fAdvanceY; - positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height))); - - stopX += width; - stopY += height; - } - SkASSERT(textPtr == stop); - - SkGlyphCache::AttachCache(origPaintCache); - - // now adjust starting point depending on alignment - SkScalar alignX = SkFixedToScalar(stopX); - SkScalar alignY = SkFixedToScalar(stopY); - if (origPaint.getTextAlign() == SkPaint::kCenter_Align) { - alignX = SkScalarHalf(alignX); - alignY = SkScalarHalf(alignY); - } else if (origPaint.getTextAlign() == SkPaint::kLeft_Align) { - alignX = 0; - alignY = 0; - } - x -= alignX; - y -= alignY; - *offset = SkPoint::Make(x, y); - - this->internalDrawDFPosText(blob, runIndex, skPaint, color, viewMatrix, text, byteLength, - positions.begin(), 2, *offset, textRatio, fallbackTxt, - fallbackPos); -} - -void GrAtlasTextContext::internalDrawDFPosText(GrAtlasTextBlob* blob, int runIndex, - const SkPaint& skPaint, GrColor color, - const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, - SkScalar textRatio, - SkTDArray* fallbackTxt, - SkTDArray* fallbackPos) { - - SkASSERT(byteLength == 0 || text != nullptr); - SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); - - // nothing to draw - if (text == nullptr || byteLength == 0) { - return; - } - - fCurrStrike = nullptr; - - SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); - SkGlyphCache* cache = this->setupCache(&blob->fRuns[runIndex], skPaint, nullptr, true); - GrFontScaler* fontScaler = GetGrFontScaler(cache); - - const char* stop = text + byteLength; - - if (SkPaint::kLeft_Align == skPaint.getTextAlign()) { - while (text < stop) { - const char* lastText = text; - // the last 2 parameters are ignored - const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); - - if (glyph.fWidth) { - SkScalar x = offset.x() + pos[0]; - SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0); - - if (!this->dfAppendGlyph(blob, - runIndex, - glyph, - x, y, color, fontScaler, - textRatio, viewMatrix)) { - // couldn't append, send to fallback - fallbackTxt->append(SkToInt(text-lastText), lastText); - *fallbackPos->append() = pos[0]; - if (2 == scalarsPerPosition) { - *fallbackPos->append() = pos[1]; - } - } - } - pos += scalarsPerPosition; - } - } else { - SkScalar alignMul = SkPaint::kCenter_Align == skPaint.getTextAlign() ? SK_ScalarHalf - : SK_Scalar1; - while (text < stop) { - const char* lastText = text; - // the last 2 parameters are ignored - const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); - - if (glyph.fWidth) { - SkScalar x = offset.x() + pos[0]; - SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0); - - SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul * textRatio; - SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul * textRatio; - - if (!this->dfAppendGlyph(blob, - runIndex, - glyph, - x - advanceX, y - advanceY, color, - fontScaler, - textRatio, - viewMatrix)) { - // couldn't append, send to fallback - fallbackTxt->append(SkToInt(text-lastText), lastText); - *fallbackPos->append() = pos[0]; - if (2 == scalarsPerPosition) { - *fallbackPos->append() = pos[1]; - } - } - } - pos += scalarsPerPosition; - } - } - - SkGlyphCache::AttachCache(cache); -} - -void GrAtlasTextContext::bmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, - const SkGlyph& skGlyph, - int vx, int vy, GrColor color, GrFontScaler* scaler) { - Run& run = blob->fRuns[runIndex]; - if (!fCurrStrike) { - fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); - } - - GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), - skGlyph.getSubXFixed(), - skGlyph.getSubYFixed(), - GrGlyph::kCoverage_MaskStyle); - GrGlyph* glyph = fCurrStrike->getGlyph(skGlyph, id, scaler); - if (!glyph) { - return; - } - - int x = vx + glyph->fBounds.fLeft; - int y = vy + glyph->fBounds.fTop; - - // keep them as ints until we've done the clip-test - int width = glyph->fBounds.width(); - int height = glyph->fBounds.height(); - - // If the glyph is too large we fall back to paths - if (glyph->fTooLargeForAtlas) { - this->appendGlyphPath(blob, glyph, scaler, skGlyph, SkIntToScalar(vx), SkIntToScalar(vy)); - return; - } - - GrMaskFormat format = glyph->fMaskFormat; - - PerSubRunInfo* subRun = &run.fSubRunInfo.back(); - if (run.fInitialized && subRun->fMaskFormat != format) { - subRun = &run.push_back(); - subRun->fStrike.reset(SkRef(fCurrStrike)); - } else if (!run.fInitialized) { - subRun->fStrike.reset(SkRef(fCurrStrike)); - } - - run.fInitialized = true; - - size_t vertexStride = GrAtlasTextBatch::GetVertexStride(format); - - SkRect r; - r.fLeft = SkIntToScalar(x); - r.fTop = SkIntToScalar(y); - r.fRight = r.fLeft + SkIntToScalar(width); - r.fBottom = r.fTop + SkIntToScalar(height); - subRun->fMaskFormat = format; - this->appendGlyphCommon(blob, &run, subRun, r, color, vertexStride, kA8_GrMaskFormat == format, - glyph); -} - -bool GrAtlasTextContext::dfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, - const SkGlyph& skGlyph, - SkScalar sx, SkScalar sy, GrColor color, - GrFontScaler* scaler, - SkScalar textRatio, const SkMatrix& viewMatrix) { - Run& run = blob->fRuns[runIndex]; - if (!fCurrStrike) { - fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); - } - - GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), - skGlyph.getSubXFixed(), - skGlyph.getSubYFixed(), - GrGlyph::kDistance_MaskStyle); - GrGlyph* glyph = fCurrStrike->getGlyph(skGlyph, id, scaler); - if (!glyph) { - return true; - } - - // fallback to color glyph support - if (kA8_GrMaskFormat != glyph->fMaskFormat) { - return false; - } - - SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); - SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); - SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceFieldInset); - SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFieldInset); - - SkScalar scale = textRatio; - dx *= scale; - dy *= scale; - width *= scale; - height *= scale; - sx += dx; - sy += dy; - SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); - - // TODO combine with the above - // If the glyph is too large we fall back to paths - if (glyph->fTooLargeForAtlas) { - this->appendGlyphPath(blob, glyph, scaler, skGlyph, sx - dx, sy - dy, scale, true); - return true; - } - - PerSubRunInfo* subRun = &run.fSubRunInfo.back(); - if (!run.fInitialized) { - subRun->fStrike.reset(SkRef(fCurrStrike)); - } - run.fInitialized = true; - SkASSERT(glyph->fMaskFormat == kA8_GrMaskFormat); - subRun->fMaskFormat = kA8_GrMaskFormat; - - size_t vertexStride = GrAtlasTextBatch::GetVertexStrideDf(kA8_GrMaskFormat, - subRun->fUseLCDText); - - bool useColorVerts = !subRun->fUseLCDText; - this->appendGlyphCommon(blob, &run, subRun, glyphRect, color, vertexStride, useColorVerts, - glyph); - return true; -} - -inline void GrAtlasTextContext::appendGlyphPath(GrAtlasTextBlob* blob, GrGlyph* glyph, - GrFontScaler* scaler, const SkGlyph& skGlyph, - SkScalar x, SkScalar y, SkScalar scale, - bool applyVM) { - if (nullptr == glyph->fPath) { - const SkPath* glyphPath = scaler->getGlyphPath(skGlyph); - if (!glyphPath) { - return; - } - - glyph->fPath = new SkPath(*glyphPath); - } - blob->fBigGlyphs.push_back(GrAtlasTextBlob::BigGlyph(*glyph->fPath, x, y, scale, applyVM)); -} - -inline void GrAtlasTextContext::appendGlyphCommon(GrAtlasTextBlob* blob, Run* run, - Run::SubRunInfo* subRun, - const SkRect& positions, GrColor color, - size_t vertexStride, bool useVertexColor, - GrGlyph* glyph) { - blob->fGlyphs[subRun->fGlyphEndIndex] = glyph; - run->fVertexBounds.joinNonEmptyArg(positions); - run->fColor = color; - - intptr_t vertex = reinterpret_cast(blob->fVertices + subRun->fVertexEndIndex); - - if (useVertexColor) { - // V0 - SkPoint* position = reinterpret_cast(vertex); - position->set(positions.fLeft, positions.fTop); - SkColor* colorPtr = reinterpret_cast(vertex + sizeof(SkPoint)); - *colorPtr = color; - vertex += vertexStride; - - // V1 - position = reinterpret_cast(vertex); - position->set(positions.fLeft, positions.fBottom); - colorPtr = reinterpret_cast(vertex + sizeof(SkPoint)); - *colorPtr = color; - vertex += vertexStride; - - // V2 - position = reinterpret_cast(vertex); - position->set(positions.fRight, positions.fBottom); - colorPtr = reinterpret_cast(vertex + sizeof(SkPoint)); - *colorPtr = color; - vertex += vertexStride; - - // V3 - position = reinterpret_cast(vertex); - position->set(positions.fRight, positions.fTop); - colorPtr = reinterpret_cast(vertex + sizeof(SkPoint)); - *colorPtr = color; - } else { - // V0 - SkPoint* position = reinterpret_cast(vertex); - position->set(positions.fLeft, positions.fTop); - vertex += vertexStride; - - // V1 - position = reinterpret_cast(vertex); - position->set(positions.fLeft, positions.fBottom); - vertex += vertexStride; - - // V2 - position = reinterpret_cast(vertex); - position->set(positions.fRight, positions.fBottom); - vertex += vertexStride; - - // V3 - position = reinterpret_cast(vertex); - position->set(positions.fRight, positions.fTop); - } - - subRun->fGlyphEndIndex++; - subRun->fVertexEndIndex += vertexStride * GrAtlasTextBatch::kVerticesPerGlyph; -} - -void GrAtlasTextContext::flushRunAsPaths(GrDrawContext* dc, - const SkTextBlobRunIterator& it, - const GrClip& clip, const SkPaint& skPaint, - SkDrawFilter* drawFilter, const SkMatrix& viewMatrix, - const SkIRect& clipBounds, SkScalar x, SkScalar y) { - SkPaint runPaint = skPaint; - - size_t textLen = it.glyphCount() * sizeof(uint16_t); - const SkPoint& offset = it.offset(); - - it.applyFontToPaint(&runPaint); - - if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) { - return; - } - - runPaint.setFlags(FilterTextFlags(fSurfaceProps, runPaint)); - - switch (it.positioning()) { - case SkTextBlob::kDefault_Positioning: - this->drawTextAsPath(dc, clip, runPaint, viewMatrix, - (const char *)it.glyphs(), - textLen, x + offset.x(), y + offset.y(), clipBounds); - break; - case SkTextBlob::kHorizontal_Positioning: - this->drawPosTextAsPath(dc, clip, runPaint, viewMatrix, - (const char*)it.glyphs(), - textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), - clipBounds); - break; - case SkTextBlob::kFull_Positioning: - this->drawPosTextAsPath(dc, clip, runPaint, viewMatrix, - (const char*)it.glyphs(), - textLen, it.pos(), 2, SkPoint::Make(x, y), clipBounds); - break; - } -} - -inline GrDrawBatch* -GrAtlasTextContext::createBatch(GrAtlasTextBlob* cacheBlob, const PerSubRunInfo& info, - int glyphCount, int run, int subRun, - GrColor color, SkScalar transX, SkScalar transY, - const SkPaint& skPaint) { - GrMaskFormat format = info.fMaskFormat; - GrColor subRunColor; - if (kARGB_GrMaskFormat == format) { - uint8_t paintAlpha = skPaint.getAlpha(); - subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha); - } else { - subRunColor = color; - } - - GrAtlasTextBatch* batch; - if (info.fDrawAsDistanceFields) { - SkColor filteredColor; - SkColorFilter* colorFilter = skPaint.getColorFilter(); - if (colorFilter) { - filteredColor = colorFilter->filterColor(skPaint.getColor()); - } else { - filteredColor = skPaint.getColor(); - } - bool useBGR = SkPixelGeometryIsBGR(fSurfaceProps.pixelGeometry()); - batch = GrAtlasTextBatch::CreateDistanceField(glyphCount, fContext->getBatchFontCache(), - fDistanceAdjustTable, filteredColor, - info.fUseLCDText, useBGR); - } else { - batch = GrAtlasTextBatch::CreateBitmap(format, glyphCount, fContext->getBatchFontCache()); - } - GrAtlasTextBatch::Geometry& geometry = batch->geometry(); - geometry.fBlob = SkRef(cacheBlob); - geometry.fRun = run; - geometry.fSubRun = subRun; - geometry.fColor = subRunColor; - geometry.fTransX = transX; - geometry.fTransY = transY; - batch->init(); - - return batch; -} - -inline void GrAtlasTextContext::flushRun(GrDrawContext* dc, GrPipelineBuilder* pipelineBuilder, - GrAtlasTextBlob* cacheBlob, int run, GrColor color, - SkScalar transX, SkScalar transY, - const SkPaint& skPaint) { - for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); subRun++) { - const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; - int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; - if (0 == glyphCount) { - continue; - } - - SkAutoTUnref batch(this->createBatch(cacheBlob, info, glyphCount, run, - subRun, color, transX, transY, - skPaint)); - dc->drawBatch(pipelineBuilder, batch); - } -} - -inline void GrAtlasTextContext::flushBigGlyphs(GrAtlasTextBlob* cacheBlob, - GrDrawContext* dc, - const GrClip& clip, const SkPaint& skPaint, - SkScalar transX, SkScalar transY, - const SkIRect& clipBounds) { - if (!cacheBlob->fBigGlyphs.count()) { - return; - } - - for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) { - GrAtlasTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i]; - bigGlyph.fVx += transX; - bigGlyph.fVy += transY; - SkMatrix ctm; - ctm.setScale(bigGlyph.fScale, bigGlyph.fScale); - ctm.postTranslate(bigGlyph.fVx, bigGlyph.fVy); - if (bigGlyph.fApplyVM) { - ctm.postConcat(cacheBlob->fViewMatrix); - } - - GrBlurUtils::drawPathWithMaskFilter(fContext, dc, clip, bigGlyph.fPath, - skPaint, ctm, nullptr, clipBounds, false); - } -} - -void GrAtlasTextContext::flush(const SkTextBlob* blob, - GrAtlasTextBlob* cacheBlob, - GrDrawContext* dc, - GrRenderTarget* rt, - const SkPaint& skPaint, - const GrPaint& grPaint, - SkDrawFilter* drawFilter, - const GrClip& clip, - const SkMatrix& viewMatrix, - const SkIRect& clipBounds, - SkScalar x, SkScalar y, - SkScalar transX, SkScalar transY) { - // We loop through the runs of the blob, flushing each. If any run is too large, then we flush - // it as paths - GrPipelineBuilder pipelineBuilder(grPaint, rt, clip); - - GrColor color = grPaint.getColor(); - - SkTextBlobRunIterator it(blob); - for (int run = 0; !it.done(); it.next(), run++) { - if (cacheBlob->fRuns[run].fDrawAsPaths) { - this->flushRunAsPaths(dc, it, clip, skPaint, - drawFilter, viewMatrix, clipBounds, x, y); - continue; - } - cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY); - this->flushRun(dc, &pipelineBuilder, cacheBlob, run, color, - transX, transY, skPaint); - } - - // Now flush big glyphs - this->flushBigGlyphs(cacheBlob, dc, clip, skPaint, transX, transY, clipBounds); -} - -void GrAtlasTextContext::flush(GrAtlasTextBlob* cacheBlob, - GrDrawContext* dc, - GrRenderTarget* rt, - const SkPaint& skPaint, - const GrPaint& grPaint, - const GrClip& clip, - const SkIRect& clipBounds) { - GrPipelineBuilder pipelineBuilder(grPaint, rt, clip); - - GrColor color = grPaint.getColor(); - for (int run = 0; run < cacheBlob->fRunCount; run++) { - this->flushRun(dc, &pipelineBuilder, cacheBlob, run, color, 0, 0, skPaint); - } - - // Now flush big glyphs - this->flushBigGlyphs(cacheBlob, dc, clip, skPaint, 0, 0, clipBounds); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifdef GR_TEST_UTILS - -DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { - static uint32_t gContextID = SK_InvalidGenID; - static GrAtlasTextContext* gTextContext = nullptr; - static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType); - - if (context->uniqueID() != gContextID) { - gContextID = context->uniqueID(); - delete gTextContext; - - // We don't yet test the fall back to paths in the GrTextContext base class. This is mostly - // because we don't really want to have a gpu device here. - // We enable distance fields by twiddling a knob on the paint - gTextContext = GrAtlasTextContext::Create(context, gSurfaceProps); - } - - // Setup dummy SkPaint / GrPaint - GrColor color = GrRandomColor(random); - SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); - SkPaint skPaint; - skPaint.setColor(color); - skPaint.setLCDRenderText(random->nextBool()); - skPaint.setAntiAlias(skPaint.isLCDRenderText() ? true : random->nextBool()); - skPaint.setSubpixelText(random->nextBool()); - - GrPaint grPaint; - if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &grPaint)) { - SkFAIL("couldn't convert paint\n"); - } - - const char* text = "The quick brown fox jumps over the lazy dog."; - int textLen = (int)strlen(text); - - // Setup clip - GrClip clip; - SkIRect noClip = SkIRect::MakeLargest(); - - // right now we don't handle textblobs, nor do we handle drawPosText. Since we only - // intend to test the batch with this unit test, that is okay. - SkAutoTUnref blob( - gTextContext->createDrawTextBlob(clip, grPaint, skPaint, viewMatrix, text, - static_cast(textLen), 0, 0, noClip)); - - SkScalar transX = static_cast(random->nextU()); - SkScalar transY = static_cast(random->nextU()); - const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]; - return gTextContext->createBatch(blob, info, textLen, 0, 0, color, transX, transY, skPaint); -} - -#endif diff --git a/gfx/skia/skia/src/gpu/GrAtlasTextContext.h b/gfx/skia/skia/src/gpu/GrAtlasTextContext.h deleted file mode 100644 index 2d445f35d8d..00000000000 --- a/gfx/skia/skia/src/gpu/GrAtlasTextContext.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrAtlasTextContext_DEFINED -#define GrAtlasTextContext_DEFINED - -#include "GrTextContext.h" - -#include "GrAtlasTextBlob.h" -#include "GrGeometryProcessor.h" -#include "SkTextBlobRunIterator.h" - -#ifdef GR_TEST_UTILS -#include "GrBatchTest.h" -#endif - -class GrDrawBatch; -class GrDrawContext; -class GrDrawTarget; -class GrPipelineBuilder; -class GrTextBlobCache; -class SkGlyph; - -/* - * This class implements GrTextContext using standard bitmap fonts, and can also process textblobs. - */ -class GrAtlasTextContext : public GrTextContext { -public: - static GrAtlasTextContext* Create(GrContext*, const SkSurfaceProps&); - -private: - GrAtlasTextContext(GrContext*, const SkSurfaceProps&); - ~GrAtlasTextContext() override {} - - bool canDraw(const SkPaint&, const SkMatrix& viewMatrix) override; - - void onDrawText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, - const SkMatrix& viewMatrix, const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkIRect& regionClipBounds) override; - void onDrawPosText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&, - const SkPaint&, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkIRect& regionClipBounds) override; - void drawTextBlob(GrDrawContext*, GrRenderTarget*, const GrClip&, const SkPaint&, - const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y, - SkDrawFilter*, const SkIRect& clipBounds) override; - - typedef GrAtlasTextBlob::Run Run; - typedef Run::SubRunInfo PerSubRunInfo; - - inline bool canDrawAsDistanceFields(const SkPaint&, const SkMatrix& viewMatrix); - GrAtlasTextBlob* setupDFBlob(int glyphCount, const SkPaint& origPaint, - const SkMatrix& viewMatrix, SkPaint* dfPaint, - SkScalar* textRatio); - void bmpAppendGlyph(GrAtlasTextBlob*, int runIndex, const SkGlyph&, int left, int top, - GrColor color, GrFontScaler*); - bool dfAppendGlyph(GrAtlasTextBlob*, int runIndex, const SkGlyph&, SkScalar sx, SkScalar sy, - GrColor color, GrFontScaler*, SkScalar textRatio, - const SkMatrix& viewMatrix); - inline void appendGlyphPath(GrAtlasTextBlob*, GrGlyph*, GrFontScaler*, const SkGlyph&, - SkScalar x, SkScalar y, SkScalar scale = 1.0f, - bool applyVM = false); - inline void appendGlyphCommon(GrAtlasTextBlob*, Run*, Run::SubRunInfo*, - const SkRect& positions, GrColor color, - size_t vertexStride, bool useVertexColor, - GrGlyph*); - - inline void flushRunAsPaths(GrDrawContext*, - const SkTextBlobRunIterator&, const GrClip& clip, - const SkPaint&, SkDrawFilter*, - const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, - SkScalar y); - inline GrDrawBatch* createBatch(GrAtlasTextBlob*, const PerSubRunInfo&, - int glyphCount, int run, int subRun, - GrColor, SkScalar transX, SkScalar transY, - const SkPaint&); - inline void flushRun(GrDrawContext*, GrPipelineBuilder*, GrAtlasTextBlob*, int run, GrColor, - SkScalar transX, SkScalar transY, const SkPaint&); - inline void flushBigGlyphs(GrAtlasTextBlob* cacheBlob, GrDrawContext*, - const GrClip& clip, const SkPaint& skPaint, - SkScalar transX, SkScalar transY, const SkIRect& clipBounds); - - // We have to flush SkTextBlobs differently from drawText / drawPosText - void flush(const SkTextBlob*, GrAtlasTextBlob*, GrDrawContext*, GrRenderTarget*, - const SkPaint&, const GrPaint&, SkDrawFilter*, const GrClip&, - const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y, - SkScalar transX, SkScalar transY); - void flush(GrAtlasTextBlob*, GrDrawContext*, GrRenderTarget*, const SkPaint&, - const GrPaint&, const GrClip&, const SkIRect& clipBounds); - - // A helper for drawing BitmapText in a run of distance fields - inline void fallbackDrawPosText(GrAtlasTextBlob*, int runIndex, - const GrClip&, GrColor color, - const SkPaint&, const SkMatrix& viewMatrix, - const SkTDArray& fallbackTxt, - const SkTDArray& fallbackPos, - int scalarsPerPosition, - const SkPoint& offset); - - void internalDrawBMPText(GrAtlasTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, - GrColor color, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - SkScalar x, SkScalar y); - void internalDrawBMPPosText(GrAtlasTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, - GrColor color, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset); - - void internalDrawDFText(GrAtlasTextBlob*, int runIndex, const SkPaint&, - GrColor color, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - SkScalar x, SkScalar y, - SkScalar textRatio, - SkTDArray* fallbackTxt, - SkTDArray* fallbackPos, - SkPoint* offset, const SkPaint& origPaint); - void internalDrawDFPosText(GrAtlasTextBlob*, int runIndex, const SkPaint&, - GrColor color, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, - SkScalar textRatio, - SkTDArray* fallbackTxt, - SkTDArray* fallbackPos); - - // sets up the descriptor on the blob and returns a detached cache. Client must attach - inline static GrColor ComputeCanonicalColor(const SkPaint&, bool lcd); - inline SkGlyphCache* setupCache(Run*, const SkPaint&, const SkMatrix* viewMatrix, bool noGamma); - static inline bool MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY, - const GrAtlasTextBlob&, const SkPaint&, GrColor, - const SkMaskFilter::BlurRec&, - const SkMatrix& viewMatrix, SkScalar x, SkScalar y); - void regenerateTextBlob(GrAtlasTextBlob* bmp, const SkPaint& skPaint, GrColor, - const SkMatrix& viewMatrix, - const SkTextBlob* blob, SkScalar x, SkScalar y, - SkDrawFilter* drawFilter, - const GrClip&); - inline static bool HasLCD(const SkTextBlob*); - inline void initDistanceFieldPaint(GrAtlasTextBlob*, SkPaint*, SkScalar* textRatio, - const SkMatrix&); - - // Test methods - // TODO this is really ugly. It'd be much nicer if positioning could be moved to batch - inline GrAtlasTextBlob* createDrawTextBlob(const GrClip&, const GrPaint&, - const SkPaint&, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - SkScalar x, SkScalar y, - const SkIRect& regionClipBounds); - inline GrAtlasTextBlob* createDrawPosTextBlob(const GrClip&, const GrPaint&, - const SkPaint&, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, - const SkIRect& regionClipBounds); - - // Distance field text needs this table to compute a value for use in the fragment shader. - // Because the GrAtlasTextContext can go out of scope before the final flush, this needs to be - // refcnted and malloced - struct DistanceAdjustTable : public SkNVRefCnt { - DistanceAdjustTable() { this->buildDistanceAdjustTable(); } - ~DistanceAdjustTable() { delete[] fTable; } - - const SkScalar& operator[] (int i) const { - return fTable[i]; - } - - private: - void buildDistanceAdjustTable(); - - SkScalar* fTable; - }; - - GrBatchTextStrike* fCurrStrike; - GrTextBlobCache* fCache; - SkAutoTUnref fDistanceAdjustTable; - - friend class GrTextBlobCache; - friend class GrAtlasTextBatch; - -#ifdef GR_TEST_UTILS - DRAW_BATCH_TEST_FRIEND(TextBlobBatch); -#endif - - typedef GrTextContext INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/GrAuditTrail.cpp b/gfx/skia/skia/src/gpu/GrAuditTrail.cpp new file mode 100644 index 00000000000..6ff04d11446 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrAuditTrail.cpp @@ -0,0 +1,121 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrAuditTrail.h" + +void GrAuditTrail::JsonifyTArray(SkString* json, const char* name, const FrameArray& array) { + if (array.count()) { + json->appendf("\"%s\": [", name); + for (int i = 0; i < array.count(); i++) { + json->append(array[i]->toJson()); + if (i < array.count() - 1) { + json->append(","); + } + } + json->append("]"); + } +} + +// This will pretty print a very small subset of json +// The parsing rules are straightforward, aside from the fact that we do not want an extra newline +// before ',' and after '}', so we have a comma exception rule. +class PrettyPrintJson { +public: + SkString prettify(const SkString& json) { + fPrettyJson.reset(); + fTabCount = 0; + fFreshLine = false; + fCommaException = false; + for (size_t i = 0; i < json.size(); i++) { + if ('[' == json[i] || '{' == json[i]) { + this->newline(); + this->appendChar(json[i]); + fTabCount++; + this->newline(); + } else if (']' == json[i] || '}' == json[i]) { + fTabCount--; + this->newline(); + this->appendChar(json[i]); + fCommaException = true; + } else if (',' == json[i]) { + this->appendChar(json[i]); + this->newline(); + } else { + this->appendChar(json[i]); + } + } + return fPrettyJson; + } +private: + void appendChar(char appendee) { + if (fCommaException && ',' != appendee) { + this->newline(); + } + this->tab(); + fPrettyJson += appendee; + fFreshLine = false; + fCommaException = false; + } + + void tab() { + if (fFreshLine) { + for (int i = 0; i < fTabCount; i++) { + fPrettyJson += '\t'; + } + } + } + + void newline() { + if (!fFreshLine) { + fFreshLine = true; + fPrettyJson += '\n'; + } + } + + SkString fPrettyJson; + int fTabCount; + bool fFreshLine; + bool fCommaException; +}; + +static SkString pretty_print_json(SkString json) { + class PrettyPrintJson prettyPrintJson; + return prettyPrintJson.prettify(json); +} + +SkString GrAuditTrail::toJson() const { + SkString json; + json.append("{"); + JsonifyTArray(&json, "Stacks", fFrames); + json.append("}"); + + // TODO if this becomes a performance issue we should make pretty print configurable + return pretty_print_json(json); +} + +SkString GrAuditTrail::Frame::toJson() const { + SkString json; + json.append("{"); + json.appendf("\"Name\": \"%s\",", fName); + JsonifyTArray(&json, "Frames", fChildren); + json.append("}"); + return json; +} + +SkString GrAuditTrail::Batch::toJson() const { + SkString json; + json.append("{"); + json.appendf("\"Name\": \"%s\",", fName); + json.append("\"Bounds\": {"); + json.appendf("\"Left\": %f,", fBounds.fLeft); + json.appendf("\"Right\": %f,", fBounds.fRight); + json.appendf("\"Top\": %f,", fBounds.fTop); + json.appendf("\"Bottom\": %f", fBounds.fBottom); + json.append("}"); + json.append("}"); + return json; +} diff --git a/gfx/skia/skia/src/gpu/GrAutoLocaleSetter.h b/gfx/skia/skia/src/gpu/GrAutoLocaleSetter.h index bcb23cfb29f..6bfff0cd897 100644 --- a/gfx/skia/skia/src/gpu/GrAutoLocaleSetter.h +++ b/gfx/skia/skia/src/gpu/GrAutoLocaleSetter.h @@ -10,6 +10,10 @@ #include "GrTypes.h" +#if defined(SK_BUILD_FOR_WIN) +#include "SkString.h" +#endif + #if !defined(SK_BUILD_FOR_ANDROID) #include #endif @@ -18,6 +22,12 @@ #include #endif +#if defined(SK_BUILD_FOR_ANDROID) || defined(__UCLIBC__) || defined(_NEWLIB_VERSION) +#define HAVE_LOCALE_T 0 +#else +#define HAVE_LOCALE_T 1 +#endif + /** * Helper class for ensuring that we don't use the wrong locale when building shaders. Android * doesn't support locale in the NDK, so this is a no-op there. @@ -26,9 +36,15 @@ class GrAutoLocaleSetter : public SkNoncopyable { public: GrAutoLocaleSetter (const char* name) { #if defined(SK_BUILD_FOR_WIN) - fOldPerThreadLocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); - fOldLocale = setlocale(LC_ALL, name); -#elif !defined(SK_BUILD_FOR_ANDROID) && !defined(__UCLIBC__) + fOldPerThreadLocale = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + char* oldLocale = setlocale(LC_ALL, name); + if (oldLocale) { + fOldLocale = oldLocale; + fShouldRestoreLocale = true; + } else { + fShouldRestoreLocale = false; + } +#elif HAVE_LOCALE_T fLocale = newlocale(LC_ALL, name, 0); if (fLocale) { fOldLocale = uselocale(fLocale); @@ -42,9 +58,11 @@ public: ~GrAutoLocaleSetter () { #if defined(SK_BUILD_FOR_WIN) - setlocale(LC_ALL, fOldLocale); + if (fShouldRestoreLocale) { + setlocale(LC_ALL, fOldLocale.c_str()); + } _configthreadlocale(fOldPerThreadLocale); -#elif !defined(SK_BUILD_FOR_ANDROID) && !defined(__UCLIBC__) +#elif HAVE_LOCALE_T if (fLocale) { uselocale(fOldLocale); freelocale(fLocale); @@ -55,12 +73,15 @@ public: private: #if defined(SK_BUILD_FOR_WIN) int fOldPerThreadLocale; - const char* fOldLocale; -#elif !defined(SK_BUILD_FOR_ANDROID) && !defined(__UCLIBC__) + bool fShouldRestoreLocale; + SkString fOldLocale; +#elif HAVE_LOCALE_T locale_t fOldLocale; locale_t fLocale; #endif }; +#undef HAVE_LOCALE_T + #endif diff --git a/gfx/skia/skia/src/gpu/GrCaps.cpp b/gfx/skia/skia/src/gpu/GrCaps.cpp index 7003cc5bfec..101d5f445b4 100644 --- a/gfx/skia/skia/src/gpu/GrCaps.cpp +++ b/gfx/skia/skia/src/gpu/GrCaps.cpp @@ -106,9 +106,6 @@ GrCaps::GrCaps(const GrContextOptions& options) { fMaxTextureSize = 1; fMaxSampleCount = 0; - memset(fConfigRenderSupport, 0, sizeof(fConfigRenderSupport)); - memset(fConfigTextureSupport, 0, sizeof(fConfigTextureSupport)); - fSuppressPrints = options.fSuppressPrints; fImmediateFlush = options.fImmediateMode; fDrawPathMasksToCompressedTextureSupport = options.fDrawPathToCompressedTexture; @@ -229,22 +226,24 @@ SkString GrCaps::dump() const { GR_STATIC_ASSERT(14 == kRGBA_half_GrPixelConfig); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kConfigNames) == kGrPixelConfigCnt); - SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][0]); - SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][1]); + SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig, false)); + SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig, true)); for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { + GrPixelConfig config = static_cast(i); r.appendf("%s is renderable: %s, with MSAA: %s\n", kConfigNames[i], - gNY[fConfigRenderSupport[i][0]], - gNY[fConfigRenderSupport[i][1]]); + gNY[this->isConfigRenderable(config, false)], + gNY[this->isConfigRenderable(config, true)]); } - SkASSERT(!fConfigTextureSupport[kUnknown_GrPixelConfig]); + SkASSERT(!this->isConfigTexturable(kUnknown_GrPixelConfig)); for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { + GrPixelConfig config = static_cast(i); r.appendf("%s is uploadable to a texture: %s\n", kConfigNames[i], - gNY[fConfigTextureSupport[i]]); + gNY[this->isConfigTexturable(config)]); } return r; diff --git a/gfx/skia/skia/src/gpu/GrClipMaskManager.cpp b/gfx/skia/skia/src/gpu/GrClipMaskManager.cpp index 9eaf415cce6..3168424cf87 100644 --- a/gfx/skia/skia/src/gpu/GrClipMaskManager.cpp +++ b/gfx/skia/skia/src/gpu/GrClipMaskManager.cpp @@ -20,6 +20,7 @@ #include "GrSWMaskHelper.h" #include "SkRasterClip.h" #include "SkTLazy.h" +#include "batches/GrRectBatchFactory.h" #include "effects/GrConvexPolyEffect.h" #include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrRRectEffect.h" @@ -47,6 +48,16 @@ static const GrFragmentProcessor* create_fp_for_mask(GrTexture* result, const Sk kDevice_GrCoordSet); } +static void draw_non_aa_rect(GrDrawTarget* drawTarget, + const GrPipelineBuilder& pipelineBuilder, + GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect) { + SkAutoTUnref batch(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect, + nullptr, nullptr)); + drawTarget->drawBatch(pipelineBuilder, batch); +} + // Does the path in 'element' require SW rendering? If so, return true (and, // optionally, set 'prOut' to NULL. If not, return false (and, optionally, set // 'prOut' to the non-SW path renderer that will do the job). @@ -506,20 +517,24 @@ bool GrClipMaskManager::drawElement(GrPipelineBuilder* pipelineBuilder, case Element::kEmpty_Type: SkDEBUGFAIL("Should never get here with an empty element."); break; - case Element::kRect_Type: + case Element::kRect_Type: { // TODO: Do rects directly to the accumulator using a aa-rect GrProcessor that covers // the entire mask bounds and writes 0 outside the rect. if (element->isAA()) { SkRect devRect = element->getRect(); viewMatrix.mapRect(&devRect); - fDrawTarget->drawAARect(*pipelineBuilder, color, viewMatrix, - element->getRect(), devRect); + SkAutoTUnref batch( + GrRectBatchFactory::CreateAAFill(color, viewMatrix, element->getRect(), + devRect)); + + fDrawTarget->drawBatch(*pipelineBuilder, batch); } else { - fDrawTarget->drawNonAARect(*pipelineBuilder, color, viewMatrix, - element->getRect()); + draw_non_aa_rect(fDrawTarget, *pipelineBuilder, color, viewMatrix, + element->getRect()); } return true; + } default: { SkPath path; element->asPath(&path); @@ -691,8 +706,8 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, backgroundPipelineBuilder.setStencil(kDrawOutsideElement); // The color passed in here does not matter since the coverageSetOpXP won't read it. - fDrawTarget->drawNonAARect(backgroundPipelineBuilder, GrColor_WHITE, translate, - clipSpaceIBounds); + draw_non_aa_rect(fDrawTarget, backgroundPipelineBuilder, GrColor_WHITE, translate, + SkRect::Make(clipSpaceIBounds)); } } else { GrPipelineBuilder pipelineBuilder; @@ -831,11 +846,8 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, if (Element::kRect_Type == element->getType()) { *pipelineBuilder.stencil() = gDrawToStencil; - // We need this AGP until everything is in GrBatch - fDrawTarget->drawNonAARect(pipelineBuilder, - GrColor_WHITE, - viewMatrix, - element->getRect()); + draw_non_aa_rect(fDrawTarget, pipelineBuilder, GrColor_WHITE, viewMatrix, + element->getRect()); } else { if (!clipPath.isEmpty()) { if (canRenderDirectToStencil) { @@ -873,11 +885,8 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, if (canDrawDirectToClip) { if (Element::kRect_Type == element->getType()) { - // We need this AGP until everything is in GrBatch - fDrawTarget->drawNonAARect(pipelineBuilder, - GrColor_WHITE, - viewMatrix, - element->getRect()); + draw_non_aa_rect(fDrawTarget, pipelineBuilder, GrColor_WHITE, viewMatrix, + element->getRect()); } else { GrPathRenderer::DrawPathArgs args; args.fTarget = fDrawTarget; @@ -893,10 +902,8 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, } else { // The view matrix is setup to do clip space -> stencil space translation, so // draw rect in clip space. - fDrawTarget->drawNonAARect(pipelineBuilder, - GrColor_WHITE, - viewMatrix, - SkRect::Make(clipSpaceIBounds)); + draw_non_aa_rect(fDrawTarget, pipelineBuilder, GrColor_WHITE, viewMatrix, + SkRect::Make(clipSpaceIBounds)); } } } diff --git a/gfx/skia/skia/src/gpu/GrContext.cpp b/gfx/skia/skia/src/gpu/GrContext.cpp index ad89672f3ba..e92014415c2 100644 --- a/gfx/skia/skia/src/gpu/GrContext.cpp +++ b/gfx/skia/skia/src/gpu/GrContext.cpp @@ -15,14 +15,16 @@ #include "GrResourceProvider.h" #include "GrSoftwarePathRenderer.h" #include "GrSurfacePriv.h" -#include "GrTextBlobCache.h" #include "SkConfig8888.h" #include "SkGrPriv.h" #include "effects/GrConfigConversionEffect.h" +#include "text/GrTextBlobCache.h" #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) +#define ASSERT_SINGLE_OWNER \ + SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);) #define RETURN_IF_ABANDONED if (fDrawingManager->abandoned()) { return; } #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->abandoned()) { return false; } #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->abandoned()) { return nullptr; } @@ -66,6 +68,7 @@ GrContext::GrContext() : fUniqueID(next_id()) { bool GrContext::init(GrBackend backend, GrBackendContext backendContext, const GrContextOptions& options) { + ASSERT_SINGLE_OWNER SkASSERT(!fGpu); fGpu = GrGpu::Create(backend, backendContext, options, this); @@ -77,10 +80,12 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext, } void GrContext::initCommon(const GrContextOptions& options) { + ASSERT_SINGLE_OWNER + fCaps = SkRef(fGpu->caps()); fResourceCache = new GrResourceCache(fCaps); fResourceCache->setOverBudgetCallback(OverBudgetCB, this); - fResourceProvider = new GrResourceProvider(fGpu, fResourceCache); + fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner); fLayerCache.reset(new GrLayerCache(this)); @@ -88,7 +93,9 @@ void GrContext::initCommon(const GrContextOptions& options) { GrDrawTarget::Options dtOptions; dtOptions.fClipBatchToBounds = options.fClipBatchToBounds; - fDrawingManager.reset(new GrDrawingManager(this, dtOptions)); + dtOptions.fDrawBatchBounds = options.fDrawBatchBounds; + dtOptions.fMaxBatchLookback = options.fMaxBatchLookback; + fDrawingManager.reset(new GrDrawingManager(this, dtOptions, &fSingleOwner)); // GrBatchFontCache will eventually replace GrFontCache fBatchFontCache = new GrBatchFontCache(this); @@ -97,6 +104,8 @@ void GrContext::initCommon(const GrContextOptions& options) { } GrContext::~GrContext() { + ASSERT_SINGLE_OWNER + if (!fGpu) { SkASSERT(!fCaps); return; @@ -119,6 +128,8 @@ GrContext::~GrContext() { } void GrContext::abandonContext() { + ASSERT_SINGLE_OWNER + fResourceProvider->abandon(); // Need to abandon the drawing manager first so all the render targets @@ -137,10 +148,13 @@ void GrContext::abandonContext() { } void GrContext::resetContext(uint32_t state) { + ASSERT_SINGLE_OWNER fGpu->markContextDirty(state); } void GrContext::freeGpuResources() { + ASSERT_SINGLE_OWNER + this->flush(); fBatchFontCache->freeAll(); @@ -152,6 +166,8 @@ void GrContext::freeGpuResources() { } void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const { + ASSERT_SINGLE_OWNER + if (resourceCount) { *resourceCount = fResourceCache->getBudgetedResourceCount(); } @@ -185,6 +201,7 @@ void GrContext::TextBlobCacheOverBudgetCB(void* data) { //////////////////////////////////////////////////////////////////////////////// void GrContext::flush(int flagsBitfield) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED if (kDiscard_FlushBit & flagsBitfield) { @@ -219,9 +236,11 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, int left, int top, int width, int height, GrPixelConfig srcConfig, const void* buffer, size_t rowBytes, uint32_t pixelOpsFlags) { + ASSERT_SINGLE_OWNER RETURN_FALSE_IF_ABANDONED ASSERT_OWNED_RESOURCE(surface); SkASSERT(surface); + GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::writeSurfacePixels"); this->testPMConversionsIfNecessary(pixelOpsFlags); @@ -357,9 +376,11 @@ bool GrContext::readSurfacePixels(GrSurface* src, int left, int top, int width, int height, GrPixelConfig dstConfig, void* buffer, size_t rowBytes, uint32_t flags) { + ASSERT_SINGLE_OWNER RETURN_FALSE_IF_ABANDONED ASSERT_OWNED_RESOURCE(src); SkASSERT(src); + GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::readSurfacePixels"); this->testPMConversionsIfNecessary(flags); SkAutoMutexAcquire ama(fReadPixelsMutex); @@ -484,6 +505,7 @@ bool GrContext::readSurfacePixels(GrSurface* src, } void GrContext::prepareSurfaceForExternalIO(GrSurface* surface) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkASSERT(surface); ASSERT_OWNED_RESOURCE(surface); @@ -498,7 +520,10 @@ void GrContext::prepareSurfaceForExternalIO(GrSurface* surface) { void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint, uint32_t pixelOpsFlags) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED + GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::copySurface"); + if (!src || !dst) { return; } @@ -524,6 +549,7 @@ void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRe } void GrContext::flushSurfaceWrites(GrSurface* surface) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED if (surface->surfacePriv().hasPendingWrite()) { this->flush(); @@ -533,6 +559,8 @@ void GrContext::flushSurfaceWrites(GrSurface* surface) { //////////////////////////////////////////////////////////////////////////////// int GrContext::getRecommendedSampleCount(GrPixelConfig config, SkScalar dpi) const { + ASSERT_SINGLE_OWNER + if (!this->caps()->isConfigRenderable(config, true)) { return 0; } @@ -550,10 +578,12 @@ int GrContext::getRecommendedSampleCount(GrPixelConfig config, GrDrawContext* GrContext::drawContext(GrRenderTarget* rt, const SkSurfaceProps* surfaceProps) { + ASSERT_SINGLE_OWNER return fDrawingManager->drawContext(rt, surfaceProps); } -bool GrContext::abandoned() const { +bool GrContext::abandoned() const { + ASSERT_SINGLE_OWNER return fDrawingManager->abandoned(); } @@ -568,6 +598,7 @@ void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { } void GrContext::testPMConversionsIfNecessary(uint32_t flags) { + ASSERT_SINGLE_OWNER if (SkToBool(kUnpremul_PixelOpsFlag & flags)) { SkAutoMutexAcquire ama(fTestPMConversionsMutex); if (!fDidTestPMConversions) { @@ -580,6 +611,7 @@ void GrContext::testPMConversionsIfNecessary(uint32_t flags) { const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture, bool swapRAndB, const SkMatrix& matrix) const { + ASSERT_SINGLE_OWNER // We should have already called this->testPMConversionsIfNecessary(). SkASSERT(fDidTestPMConversions); GrConfigConversionEffect::PMConversion pmToUPM = @@ -594,6 +626,7 @@ const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture, const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture, bool swapRAndB, const SkMatrix& matrix) const { + ASSERT_SINGLE_OWNER // We should have already called this->testPMConversionsIfNecessary(). SkASSERT(fDidTestPMConversions); GrConfigConversionEffect::PMConversion upmToPM = @@ -606,6 +639,7 @@ const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture, } bool GrContext::didFailPMUPMConversionTest() const { + ASSERT_SINGLE_OWNER // We should have already called this->testPMConversionsIfNecessary(). SkASSERT(fDidTestPMConversions); // The PM<->UPM tests fail or succeed together so we only need to check one. @@ -615,6 +649,7 @@ bool GrContext::didFailPMUPMConversionTest() const { ////////////////////////////////////////////////////////////////////////////// void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const { + ASSERT_SINGLE_OWNER if (maxTextures) { *maxTextures = fResourceCache->getMaxResourceCount(); } @@ -624,11 +659,13 @@ void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes } void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) { + ASSERT_SINGLE_OWNER fResourceCache->setLimits(maxTextures, maxTextureBytes); } ////////////////////////////////////////////////////////////////////////////// void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { + ASSERT_SINGLE_OWNER fResourceCache->dumpMemoryStatistics(traceMemoryDump); } diff --git a/gfx/skia/skia/src/gpu/GrContextFactory.cpp b/gfx/skia/skia/src/gpu/GrContextFactory.cpp index 424b3fda3a8..b7e48254c88 100755 --- a/gfx/skia/skia/src/gpu/GrContextFactory.cpp +++ b/gfx/skia/skia/src/gpu/GrContextFactory.cpp @@ -23,66 +23,106 @@ #include "gl/GrGLGpu.h" #include "GrCaps.h" -GrContextFactory::ContextInfo* GrContextFactory::getContextInfo(GLContextType type, - GrGLStandard forcedGpuAPI) { - for (int i = 0; i < fContexts.count(); ++i) { - if (forcedGpuAPI != kNone_GrGLStandard && - forcedGpuAPI != fContexts[i]->fGLContext->gl()->fStandard) - continue; +GrContextFactory::GrContextFactory() { } - if (fContexts[i]->fType == type) { - fContexts[i]->fGLContext->makeCurrent(); - return fContexts[i]; +GrContextFactory::GrContextFactory(const GrContextOptions& opts) + : fGlobalOptions(opts) { +} + +GrContextFactory::~GrContextFactory() { + this->destroyContexts(); +} + +void GrContextFactory::destroyContexts() { + for (Context& context : fContexts) { + if (context.fGLContext) { + context.fGLContext->makeCurrent(); + } + if (!context.fGrContext->unique()) { + context.fGrContext->abandonContext(); + } + context.fGrContext->unref(); + delete(context.fGLContext); + } + fContexts.reset(); +} + +void GrContextFactory::abandonContexts() { + for (Context& context : fContexts) { + if (context.fGLContext) { + context.fGLContext->makeCurrent(); + context.fGLContext->testAbandon(); + delete(context.fGLContext); + context.fGLContext = nullptr; + } + context.fGrContext->abandonContext(); + } +} + +GrContextFactory::ContextInfo GrContextFactory::getContextInfo(GLContextType type, + GLContextOptions options) { + for (int i = 0; i < fContexts.count(); ++i) { + Context& context = fContexts[i]; + if (!context.fGLContext) { + continue; + } + if (context.fType == type && + context.fOptions == options) { + context.fGLContext->makeCurrent(); + return ContextInfo(context.fGrContext, context.fGLContext); } } - SkAutoTUnref glCtx; + SkAutoTDelete glCtx; SkAutoTUnref grCtx; switch (type) { - case kNVPR_GLContextType: // fallthru case kNative_GLContextType: - glCtx.reset(SkCreatePlatformGLContext(forcedGpuAPI)); + glCtx.reset(SkCreatePlatformGLContext(kNone_GrGLStandard)); break; -#ifdef SK_ANGLE + 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::Create(forcedGpuAPI, false)); + glCtx.reset(SkANGLEGLContext::CreateDirectX()); break; +#endif case kANGLE_GL_GLContextType: - glCtx.reset(SkANGLEGLContext::Create(forcedGpuAPI, true)); + glCtx.reset(SkANGLEGLContext::CreateOpenGL()); break; #endif -#ifdef SK_COMMAND_BUFFER +#if SK_COMMAND_BUFFER case kCommandBuffer_GLContextType: - glCtx.reset(SkCommandBufferGLContext::Create(forcedGpuAPI)); + glCtx.reset(SkCommandBufferGLContext::Create()); break; #endif -#ifdef SK_MESA +#if SK_MESA case kMESA_GLContextType: - glCtx.reset(SkMesaGLContext::Create(forcedGpuAPI)); + glCtx.reset(SkMesaGLContext::Create()); break; #endif case kNull_GLContextType: - glCtx.reset(SkNullGLContext::Create(forcedGpuAPI)); + glCtx.reset(SkNullGLContext::Create()); break; case kDebug_GLContextType: - glCtx.reset(SkDebugGLContext::Create(forcedGpuAPI)); + glCtx.reset(SkDebugGLContext::Create()); break; } if (nullptr == glCtx.get()) { - return nullptr; + return ContextInfo(); } SkASSERT(glCtx->isValid()); // Block NVPR from non-NVPR types. SkAutoTUnref glInterface(SkRef(glCtx->gl())); - if (kNVPR_GLContextType != type) { + if (!(kEnableNVPR_GLContextOptions & options)) { glInterface.reset(GrGLInterfaceRemoveNVPR(glInterface)); if (!glInterface) { - return nullptr; - } - } else { - if (!glInterface->hasExtension("GL_NV_path_rendering")) { - return nullptr; + return ContextInfo(); } } @@ -94,30 +134,18 @@ GrContextFactory::ContextInfo* GrContextFactory::getContextInfo(GLContextType ty grCtx.reset(GrContext::Create(kOpenGL_GrBackend, p3dctx, fGlobalOptions)); #endif if (!grCtx.get()) { - return nullptr; + return ContextInfo(); } - // Warn if path rendering support is not available for the NVPR type. - if (kNVPR_GLContextType == type) { + if (kEnableNVPR_GLContextOptions & options) { if (!grCtx->caps()->shaderCaps()->pathRenderingSupport()) { - GrGpu* gpu = grCtx->getGpu(); - const GrGLContext* ctx = gpu->glContextForTesting(); - if (ctx) { - const GrGLubyte* verUByte; - GR_GL_CALL_RET(ctx->interface(), verUByte, GetString(GR_GL_VERSION)); - const char* ver = reinterpret_cast(verUByte); - SkDebugf("\nWARNING: nvprmsaa config requested, but driver path rendering " - "support not available. Maybe update the driver? Your driver version " - "string: \"%s\"\n", ver); - } else { - SkDebugf("\nWARNING: nvprmsaa config requested, but driver path rendering " - "support not available.\n"); - } + return ContextInfo(); } } - ContextInfo* ctx = fContexts.emplace_back(new ContextInfo); - ctx->fGLContext = SkRef(glCtx.get()); - ctx->fGrContext = SkRef(grCtx.get()); - ctx->fType = type; - return ctx; + Context& context = fContexts.push_back(); + context.fGLContext = glCtx.detach(); + context.fGrContext = SkRef(grCtx.get()); + context.fType = type; + context.fOptions = options; + return ContextInfo(context.fGrContext, context.fGLContext); } diff --git a/gfx/skia/skia/src/gpu/GrContextFactory.h b/gfx/skia/skia/src/gpu/GrContextFactory.h index c837e74a25b..7afa3108c69 100644 --- a/gfx/skia/skia/src/gpu/GrContextFactory.h +++ b/gfx/skia/skia/src/gpu/GrContextFactory.h @@ -23,35 +23,38 @@ */ class GrContextFactory : SkNoncopyable { public: - /** - * Types of GL contexts supported. For historical and testing reasons the native GrContext will - * not use "GL_NV_path_rendering" even when the driver supports it. There is a separate context - * type that does not remove NVPR support and which will fail when the driver does not support - * the extension. - */ enum GLContextType { - kNative_GLContextType, + kNative_GLContextType, //! OpenGL or OpenGL ES context. + kGL_GLContextType, //! OpenGL context. + kGLES_GLContextType, //! OpenGL ES context. #if SK_ANGLE - kANGLE_GLContextType, - kANGLE_GL_GLContextType, +#ifdef SK_BUILD_FOR_WIN + kANGLE_GLContextType, //! ANGLE on DirectX OpenGL ES context. +#endif + kANGLE_GL_GLContextType, //! ANGLE on OpenGL OpenGL ES context. #endif #if SK_COMMAND_BUFFER - kCommandBuffer_GLContextType, + kCommandBuffer_GLContextType, //! Chromium command buffer OpenGL ES context. #endif #if SK_MESA - kMESA_GLContextType, + kMESA_GLContextType, //! MESA OpenGL context #endif - /** Similar to kNative but does not filter NVPR. It will fail if the GL driver does not - support NVPR */ - kNVPR_GLContextType, - kNull_GLContextType, - kDebug_GLContextType, - - kLastGLContextType = kDebug_GLContextType + kNull_GLContextType, //! Non-rendering OpenGL mock context. + kDebug_GLContextType, //! Non-rendering, state verifying OpenGL context. + kLastGLContextType = kDebug_GLContextType }; static const int kGLContextTypeCnt = kLastGLContextType + 1; + /** + * Options for GL context creation. For historical and testing reasons the options will default + * to not using GL_NV_path_rendering extension even when the driver supports it. + */ + enum GLContextOptions { + kNone_GLContextOptions = 0, + kEnableNVPR_GLContextOptions = 0x1, + }; + static bool IsRenderingGLContext(GLContextType type) { switch (type) { case kNull_GLContextType: @@ -66,11 +69,15 @@ public: switch (type) { case kNative_GLContextType: return "native"; - case kNull_GLContextType: - return "null"; + case kGL_GLContextType: + return "gl"; + case kGLES_GLContextType: + return "gles"; #if SK_ANGLE +#ifdef SK_BUILD_FOR_WIN case kANGLE_GLContextType: return "angle"; +#endif case kANGLE_GL_GLContextType: return "angle-gl"; #endif @@ -82,8 +89,8 @@ public: case kMESA_GLContextType: return "mesa"; #endif - case kNVPR_GLContextType: - return "nvpr"; + case kNull_GLContextType: + return "null"; case kDebug_GLContextType: return "debug"; default: @@ -91,57 +98,47 @@ public: } } - explicit GrContextFactory(const GrContextOptions& opts) : fGlobalOptions(opts) { } - GrContextFactory() { } + explicit GrContextFactory(const GrContextOptions& opts); + GrContextFactory(); - ~GrContextFactory() { this->destroyContexts(); } + ~GrContextFactory(); - void destroyContexts() { - for (int i = 0; i < fContexts.count(); ++i) { - if (fContexts[i]->fGLContext) { // could be abandoned. - fContexts[i]->fGLContext->makeCurrent(); - } - fContexts[i]->fGrContext->unref(); - SkSafeUnref(fContexts[i]->fGLContext); - } - fContexts.reset(); - } - - void abandonContexts() { - for (int i = 0; i < fContexts.count(); ++i) { - if (fContexts[i]->fGLContext) { - fContexts[i]->fGLContext->testAbandon(); - SkSafeSetNull(fContexts[i]->fGLContext); - } - fContexts[i]->fGrContext->abandonContext(); - } - } + void destroyContexts(); + void abandonContexts(); struct ContextInfo { - GLContextType fType; - SkGLContext* fGLContext; - GrContext* fGrContext; + ContextInfo() + : fGrContext(nullptr), fGLContext(nullptr) { } + ContextInfo(GrContext* grContext, SkGLContext* glContext) + : fGrContext(grContext), fGLContext(glContext) { } + GrContext* fGrContext; + SkGLContext* fGLContext; //! Valid until the factory destroys it via abandonContexts() or + //! destroyContexts(). }; + /** * Get a context initialized with a type of GL context. It also makes the GL context current. - * Pointer is valid until destroyContexts() is called. */ - ContextInfo* getContextInfo(GLContextType type, GrGLStandard forcedGpuAPI = kNone_GrGLStandard); - + ContextInfo getContextInfo(GLContextType type, + GLContextOptions options = kNone_GLContextOptions); /** * Get a GrContext initialized with a type of GL context. It also makes the GL context current. */ - GrContext* get(GLContextType type, GrGLStandard forcedGpuAPI = kNone_GrGLStandard) { - if (ContextInfo* info = this->getContextInfo(type, forcedGpuAPI)) { - return info->fGrContext; - } - return nullptr; + GrContext* get(GLContextType type, + GLContextOptions options = kNone_GLContextOptions) { + return this->getContextInfo(type, options).fGrContext; } const GrContextOptions& getGlobalOptions() const { return fGlobalOptions; } private: - SkTArray, true> fContexts; - const GrContextOptions fGlobalOptions; + struct Context { + GLContextType fType; + GLContextOptions fOptions; + SkGLContext* fGLContext; + GrContext* fGrContext; + }; + SkTArray fContexts; + const GrContextOptions fGlobalOptions; }; #endif diff --git a/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.cpp b/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.cpp index 85339ea9b5f..25da4dcae92 100644 --- a/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.cpp +++ b/gfx/skia/skia/src/gpu/GrDefaultGeoProcFactory.cpp @@ -10,9 +10,9 @@ #include "GrInvariantOutput.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLVertexShaderBuilder.h" #include "glsl/GrGLSLVarying.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLUtil.h" /* @@ -64,10 +64,10 @@ public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const DefaultGeoProc& gp = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(gp); @@ -77,13 +77,14 @@ public: if (gp.hasVertexColor()) { varyingHandler->addPassThroughAttribute(gp.inColor(), args.fOutputColor); } else { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, + &fColorUniform); } } // Setup position - this->setupPosition(pb, - vertBuilder, + this->setupPosition(vertBuilder, + uniformHandler, gpArgs, gp.inPosition()->fName, gp.viewMatrix(), @@ -91,9 +92,9 @@ public: if (gp.hasExplicitLocalCoords()) { // emit transforms with explicit local coords - this->emitTransforms(pb, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, gp.inLocalCoords()->fName, gp.localMatrix(), @@ -101,17 +102,16 @@ public: args.fTransformsOut); } else if(gp.hasTransformedLocalCoords()) { // transforms have already been applied to vertex attributes on the cpu - this->emitTransforms(pb, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, gp.inLocalCoords()->fName, args.fTransformsIn, args.fTransformsOut); } else { // emit transforms with position - this->emitTransforms(pb, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, gp.inPosition()->fName, gp.localMatrix(), @@ -129,11 +129,12 @@ public: fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage); } else { const char* fragCoverage; - fCoverageUniform = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, - kDefault_GrSLPrecision, - "Coverage", - &fragCoverage); + fCoverageUniform = uniformHandler->addUniform( + GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, + kDefault_GrSLPrecision, + "Coverage", + &fragCoverage); fragBuilder->codeAppendf("%s = vec4(%s);", args.fOutputCoverage, fragCoverage); } } diff --git a/gfx/skia/skia/src/gpu/GrDrawContext.cpp b/gfx/skia/skia/src/gpu/GrDrawContext.cpp index c07b0602ea6..61616265012 100644 --- a/gfx/skia/skia/src/gpu/GrDrawContext.cpp +++ b/gfx/skia/skia/src/gpu/GrDrawContext.cpp @@ -6,7 +6,6 @@ * found in the LICENSE file. */ -#include "GrAtlasTextContext.h" #include "GrBatchTest.h" #include "GrColor.h" #include "GrDrawContext.h" @@ -16,7 +15,6 @@ #include "GrRenderTarget.h" #include "GrRenderTargetPriv.h" #include "GrResourceProvider.h" -#include "GrStencilAndCoverTextContext.h" #include "SkSurfacePriv.h" #include "batches/GrBatch.h" @@ -25,7 +23,14 @@ #include "batches/GrRectBatchFactory.h" #include "batches/GrNinePatch.h" // TODO Factory +#include "text/GrAtlasTextContext.h" +#include "text/GrStencilAndCoverTextContext.h" + +#include "../private/GrAuditTrail.h" + #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fDrawingManager->getContext()) +#define ASSERT_SINGLE_OWNER \ + SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) #define RETURN_IF_ABANDONED if (fDrawingManager->abandoned()) { return; } #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->abandoned()) { return false; } #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->abandoned()) { return nullptr; } @@ -47,12 +52,19 @@ private: // when the drawContext attempts to use it (via getDrawTarget). GrDrawContext::GrDrawContext(GrDrawingManager* drawingMgr, GrRenderTarget* rt, - const SkSurfaceProps* surfaceProps) + const SkSurfaceProps* surfaceProps, + GrAuditTrail* auditTrail, + GrSingleOwner* singleOwner) : fDrawingManager(drawingMgr) , fRenderTarget(rt) , fDrawTarget(SkSafeRef(rt->getLastDrawTarget())) , fTextContext(nullptr) - , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) { + , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) + , fAuditTrail(auditTrail) +#ifdef SK_DEBUG + , fSingleOwner(singleOwner) +#endif +{ SkDEBUGCODE(this->validate();) } @@ -68,10 +80,12 @@ void GrDrawContext::validate() const { #endif GrDrawContext::~GrDrawContext() { + ASSERT_SINGLE_OWNER SkSafeUnref(fDrawTarget); } GrDrawTarget* GrDrawContext::getDrawTarget() { + ASSERT_SINGLE_OWNER SkDEBUGCODE(this->validate();) if (!fDrawTarget || fDrawTarget->isClosed()) { @@ -82,8 +96,10 @@ GrDrawTarget* GrDrawContext::getDrawTarget() { } void GrDrawContext::copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::copySurface"); this->getDrawTarget()->copySurface(fRenderTarget, src, srcRect, dstPoint); } @@ -93,14 +109,16 @@ void GrDrawContext::drawText(const GrClip& clip, const GrPaint& grPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawText"); if (!fTextContext) { fTextContext = fDrawingManager->textContext(fSurfaceProps, fRenderTarget); } - fTextContext->drawText(this, fRenderTarget, clip, grPaint, skPaint, viewMatrix, + fTextContext->drawText(this, clip, grPaint, skPaint, viewMatrix, text, byteLength, x, y, clipBounds); } @@ -110,14 +128,16 @@ void GrDrawContext::drawPosText(const GrClip& clip, const GrPaint& grPaint, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPosText"); if (!fTextContext) { fTextContext = fDrawingManager->textContext(fSurfaceProps, fRenderTarget); } - fTextContext->drawPosText(this, fRenderTarget, clip, grPaint, skPaint, viewMatrix, text, byteLength, + fTextContext->drawPosText(this, clip, grPaint, skPaint, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset, clipBounds); } @@ -126,36 +146,23 @@ void GrDrawContext::drawTextBlob(const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* filter, const SkIRect& clipBounds) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawTextBlob"); if (!fTextContext) { fTextContext = fDrawingManager->textContext(fSurfaceProps, fRenderTarget); } - fTextContext->drawTextBlob(this, fRenderTarget, - clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds); -} - -void GrDrawContext::drawPathsFromRange(const GrPipelineBuilder* pipelineBuilder, - const SkMatrix& viewMatrix, - const SkMatrix& localMatrix, - GrColor color, - GrPathRange* range, - GrPathRangeDraw* draw, - int /*GrPathRendering::FillType*/ fill, - const SkRect& bounds) { - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - - this->getDrawTarget()->drawPathsFromRange(*pipelineBuilder, viewMatrix, localMatrix, color, - range, draw, (GrPathRendering::FillType) fill, - bounds); + fTextContext->drawTextBlob(this, clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds); } void GrDrawContext::discard() { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::discard"); AutoCheckFlush acf(fDrawingManager); this->getDrawTarget()->discard(fRenderTarget); @@ -164,8 +171,10 @@ void GrDrawContext::discard() { void GrDrawContext::clear(const SkIRect* rect, const GrColor color, bool canIgnoreRect) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::clear"); AutoCheckFlush acf(fDrawingManager); this->getDrawTarget()->clear(rect, color, canIgnoreRect, fRenderTarget); @@ -175,8 +184,10 @@ void GrDrawContext::clear(const SkIRect* rect, void GrDrawContext::drawPaint(const GrClip& clip, const GrPaint& origPaint, const SkMatrix& viewMatrix) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPaint"); // set rect to be big enough to fill the space, but not super-huge, so we // don't overflow fixed-point implementations @@ -214,11 +225,10 @@ void GrDrawContext::drawPaint(const GrClip& clip, AutoCheckFlush acf(fDrawingManager); GrPipelineBuilder pipelineBuilder(*paint, fRenderTarget, clip); - this->getDrawTarget()->drawNonAARect(pipelineBuilder, - paint->getColor(), - SkMatrix::I(), - r, - localMatrix); + SkAutoTUnref batch( + GrRectBatchFactory::CreateNonAAFill(paint->getColor(), SkMatrix::I(), r, nullptr, + &localMatrix)); + this->getDrawTarget()->drawBatch(pipelineBuilder, batch); } } @@ -240,8 +250,10 @@ void GrDrawContext::drawRect(const GrClip& clip, const SkMatrix& viewMatrix, const SkRect& rect, const GrStrokeInfo* strokeInfo) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRect"); // Dashing should've been devolved to a path in SkGpuDevice SkASSERT(!strokeInfo || !strokeInfo->isDashed()); @@ -284,47 +296,50 @@ void GrDrawContext::drawRect(const GrClip& clip, } } - GrColor color = paint.getColor(); - bool needAA = should_apply_coverage_aa(paint, fRenderTarget); - - // The fill path can handle rotation but not skew - // The stroke path needs the rect to remain axis aligned (no rotation or skew) - // None of our AA draw rect calls can handle perspective yet - bool canApplyAA = width >=0 ? viewMatrix.rectStaysRect() : - view_matrix_ok_for_aa_fill_rect(viewMatrix); - GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip); + GrColor color = paint.getColor(); - if (needAA && canApplyAA) { - SkASSERT(!viewMatrix.hasPerspective()); - SkAutoTUnref batch; + SkAutoTUnref batch; + if (should_apply_coverage_aa(paint, fRenderTarget)) { if (width >= 0) { - batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, *strokeInfo)); + // The stroke path needs the rect to remain axis aligned (no rotation or skew). + if (viewMatrix.rectStaysRect()) { + batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, + *strokeInfo)); + } } else { - SkRect devBoundRect; - viewMatrix.mapRect(&devBoundRect, rect); - batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect, devBoundRect)); + // The fill path can handle rotation but not skew. + if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) { + SkRect devBoundRect; + viewMatrix.mapRect(&devBoundRect, rect); + batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect, + devBoundRect)); + } } - this->getDrawTarget()->drawBatch(pipelineBuilder, batch); - return; - } - - if (width >= 0) { + if (!batch) { + SkPath path; + path.setIsVolatile(true); + path.addRect(rect); + this->internalDrawPath(&pipelineBuilder, viewMatrix, color, true, path, *strokeInfo); + SkASSERT(paint.isAntiAlias()); + return; + } + } else if (width >= 0) { // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic bool snapToPixelCenters = (0 == width && !fRenderTarget->isUnifiedMultisampled()); - SkAutoTUnref batch(GrRectBatchFactory::CreateNonAAStroke( - color, viewMatrix, rect, width, snapToPixelCenters)); + batch.reset(GrRectBatchFactory::CreateNonAAStroke(color, viewMatrix, rect, width, + snapToPixelCenters)); // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA // is enabled because it can cause ugly artifacts. pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag, snapToPixelCenters); - this->getDrawTarget()->drawBatch(pipelineBuilder, batch); } else { // filled BW rect - this->getDrawTarget()->drawNonAARect(pipelineBuilder, color, viewMatrix, rect); + batch.reset(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect, nullptr, nullptr)); } + this->getDrawTarget()->drawBatch(pipelineBuilder, batch); } void GrDrawContext::fillRectToRect(const GrClip& clip, @@ -332,25 +347,26 @@ void GrDrawContext::fillRectToRect(const GrClip& clip, const SkMatrix& viewMatrix, const SkRect& rectToDraw, const SkRect& localRect) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectToRect"); AutoCheckFlush acf(fDrawingManager); GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip); + SkAutoTUnref batch; if (should_apply_coverage_aa(paint, fRenderTarget) && view_matrix_ok_for_aa_fill_rect(viewMatrix)) { - SkAutoTUnref batch(GrAAFillRectBatch::CreateWithLocalRect( - paint.getColor(), viewMatrix, rectToDraw, localRect)); - if (batch) { - this->drawBatch(&pipelineBuilder, batch); - } + batch.reset(GrAAFillRectBatch::CreateWithLocalRect(paint.getColor(), viewMatrix, rectToDraw, + localRect)); } else { - this->getDrawTarget()->drawNonAARect(pipelineBuilder, - paint.getColor(), - viewMatrix, - rectToDraw, - localRect); + batch.reset(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rectToDraw, + &localRect, nullptr)); + } + + if (batch) { + this->drawBatch(&pipelineBuilder, batch); } } @@ -359,25 +375,25 @@ void GrDrawContext::fillRectWithLocalMatrix(const GrClip& clip, const SkMatrix& viewMatrix, const SkRect& rectToDraw, const SkMatrix& localMatrix) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectWithLocalMatrix"); AutoCheckFlush acf(fDrawingManager); GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip); + SkAutoTUnref batch; if (should_apply_coverage_aa(paint, fRenderTarget) && view_matrix_ok_for_aa_fill_rect(viewMatrix)) { - SkAutoTUnref batch(GrAAFillRectBatch::Create( - paint.getColor(), viewMatrix, localMatrix, rectToDraw)); - this->drawBatch(&pipelineBuilder, batch); + batch.reset(GrAAFillRectBatch::Create(paint.getColor(), viewMatrix, localMatrix, + rectToDraw)); } else { - this->getDrawTarget()->drawNonAARect(pipelineBuilder, - paint.getColor(), - viewMatrix, - rectToDraw, - localMatrix); + batch.reset(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rectToDraw, + nullptr, &localMatrix)); } + this->getDrawTarget()->drawBatch(pipelineBuilder, batch); } void GrDrawContext::drawVertices(const GrClip& clip, @@ -390,8 +406,10 @@ void GrDrawContext::drawVertices(const GrClip& clip, const GrColor colors[], const uint16_t indices[], int indexCount) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawVertices"); AutoCheckFlush acf(fDrawingManager); @@ -433,8 +451,10 @@ void GrDrawContext::drawAtlas(const GrClip& clip, const SkRSXform xform[], const SkRect texRect[], const SkColor colors[]) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawAtlas"); AutoCheckFlush acf(fDrawingManager); @@ -455,8 +475,10 @@ void GrDrawContext::drawRRect(const GrClip& clip, const SkMatrix& viewMatrix, const SkRRect& rrect, const GrStrokeInfo& strokeInfo) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRRect"); if (rrect.isEmpty()) { return; @@ -491,8 +513,10 @@ void GrDrawContext::drawDRRect(const GrClip& clip, const SkMatrix& viewMatrix, const SkRRect& outer, const SkRRect& inner) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawDRRect"); if (outer.isEmpty()) { return; @@ -528,8 +552,10 @@ void GrDrawContext::drawOval(const GrClip& clip, const SkMatrix& viewMatrix, const SkRect& oval, const GrStrokeInfo& strokeInfo) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawOval"); if (oval.isEmpty()) { return; @@ -564,8 +590,10 @@ void GrDrawContext::drawImageNine(const GrClip& clip, int imageHeight, const SkIRect& center, const SkRect& dst) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawImageNine"); AutoCheckFlush acf(fDrawingManager); @@ -630,8 +658,10 @@ static bool is_nested_rects(const SkMatrix& viewMatrix, void GrDrawContext::drawBatch(const GrClip& clip, const GrPaint& paint, GrDrawBatch* batch) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawBatch"); AutoCheckFlush acf(fDrawingManager); @@ -639,13 +669,27 @@ void GrDrawContext::drawBatch(const GrClip& clip, this->getDrawTarget()->drawBatch(pipelineBuilder, batch); } +void GrDrawContext::drawPathBatch(const GrPipelineBuilder& pipelineBuilder, + GrDrawPathBatchBase* batch) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPathBatch"); + + AutoCheckFlush acf(fDrawingManager); + + this->getDrawTarget()->drawPathBatch(pipelineBuilder, batch); +} + void GrDrawContext::drawPath(const GrClip& clip, const GrPaint& paint, const SkMatrix& viewMatrix, const SkPath& path, const GrStrokeInfo& strokeInfo) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPath"); if (path.isEmpty()) { if (path.isInverseFillType()) { @@ -703,6 +747,7 @@ void GrDrawContext::internalDrawPath(GrPipelineBuilder* pipelineBuilder, bool useAA, const SkPath& path, const GrStrokeInfo& strokeInfo) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkASSERT(!path.isEmpty()); @@ -799,8 +844,10 @@ void GrDrawContext::internalDrawPath(GrPipelineBuilder* pipelineBuilder, } void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrDrawBatch* batch) { + ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawBatch"); this->getDrawTarget()->drawBatch(*pipelineBuilder, batch); } diff --git a/gfx/skia/skia/src/gpu/GrDrawTarget.cpp b/gfx/skia/skia/src/gpu/GrDrawTarget.cpp index 9b7fa31ab03..e2e188eb12c 100644 --- a/gfx/skia/skia/src/gpu/GrDrawTarget.cpp +++ b/gfx/skia/skia/src/gpu/GrDrawTarget.cpp @@ -8,6 +8,7 @@ #include "GrDrawTarget.h" +#include "GrAuditTrail.h" #include "GrCaps.h" #include "GrGpu.h" #include "GrPath.h" @@ -20,6 +21,8 @@ #include "GrTexture.h" #include "GrVertexBuffer.h" +#include "SkStrokeRec.h" + #include "batches/GrClearBatch.h" #include "batches/GrCopySurfaceBatch.h" #include "batches/GrDiscardBatch.h" @@ -28,21 +31,26 @@ #include "batches/GrRectBatchFactory.h" #include "batches/GrStencilPathBatch.h" -#include "SkStrokeRec.h" - //////////////////////////////////////////////////////////////////////////////// +// Experimentally we have found that most batching occurs within the first 10 comparisons. +static const int kDefaultMaxBatchLookback = 10; + GrDrawTarget::GrDrawTarget(GrRenderTarget* rt, GrGpu* gpu, GrResourceProvider* resourceProvider, - const Options& options) + GrAuditTrail* auditTrail, const Options& options) : fGpu(SkRef(gpu)) , fResourceProvider(resourceProvider) - , fFlushing(false) + , fAuditTrail(auditTrail) , fFlags(0) , fRenderTarget(rt) { // TODO: Stop extracting the context (currently needed by GrClipMaskManager) fContext = fGpu->getContext(); fClipMaskManager.reset(new GrClipMaskManager(this, options.fClipBatchToBounds)); + fDrawBatchBounds = options.fDrawBatchBounds; + fMaxBatchLookback = (options.fMaxBatchLookback < 0) ? kDefaultMaxBatchLookback : + options.fMaxBatchLookback; + rt->setLastDrawTarget(this); #ifdef SK_DEBUG @@ -176,11 +184,6 @@ bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuil } void GrDrawTarget::prepareBatches(GrBatchFlushState* flushState) { - if (fFlushing) { - return; - } - fFlushing = true; - // Semi-usually the drawTargets are already closed at this point, but sometimes Ganesh // needs to flush mid-draw. In that case, the SkGpuDevice's drawTargets won't be closed // but need to be flushed anyway. Closing such drawTargets here will mean new @@ -195,11 +198,20 @@ void GrDrawTarget::prepareBatches(GrBatchFlushState* flushState) { void GrDrawTarget::drawBatches(GrBatchFlushState* flushState) { // Draw all the generated geometry. + SkRandom random; for (int i = 0; i < fBatches.count(); ++i) { + if (fDrawBatchBounds) { + const SkRect& bounds = fBatches[i]->bounds(); + SkIRect ibounds; + bounds.roundOut(&ibounds); + // In multi-draw buffer all the batches use the same render target and we won't need to + // get the batchs bounds. + if (GrRenderTarget* rt = fBatches[i]->renderTarget()) { + fGpu->drawDebugWireRect(rt, ibounds, 0xFF000000 | random.nextU()); + } + } fBatches[i]->draw(flushState); } - - fFlushing = false; } void GrDrawTarget::reset() { @@ -303,40 +315,13 @@ void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder, batch->unref(); } -void GrDrawTarget::drawPath(const GrPipelineBuilder& pipelineBuilder, - const SkMatrix& viewMatrix, - GrColor color, - const GrPath* path, - GrPathRendering::FillType fill) { - SkASSERT(path); - SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); - - GrDrawPathBatchBase* batch = GrDrawPathBatch::Create(viewMatrix, color, path); - this->drawPathBatch(pipelineBuilder, batch, fill); - batch->unref(); -} - -void GrDrawTarget::drawPathsFromRange(const GrPipelineBuilder& pipelineBuilder, - const SkMatrix& viewMatrix, - const SkMatrix& localMatrix, - GrColor color, - GrPathRange* range, - GrPathRangeDraw* draw, - GrPathRendering::FillType fill, - const SkRect& bounds) { - GrDrawPathBatchBase* batch = GrDrawPathRangeBatch::Create(viewMatrix, localMatrix, color, - range, draw, bounds); - this->drawPathBatch(pipelineBuilder, batch, fill); - batch->unref(); -} - void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder, - GrDrawPathBatchBase* batch, - GrPathRendering::FillType fill) { + GrDrawPathBatchBase* batch) { // This looks like drawBatch() but there is an added wrinkle that stencil settings get inserted // after setting up clipping but before onDrawBatch(). TODO: Figure out a better model for // handling stencil settings WRT interactions between pipeline(builder), clipmaskmanager, and // batches. + SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); GrPipelineBuilder::AutoRestoreStencil ars; GrAppliedClip clip; @@ -354,7 +339,7 @@ void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder, GrStencilSettings stencilSettings; GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt); - this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings); + this->getPathStencilSettingsForFilltype(batch->fillType(), sb, &stencilSettings); batch->setStencilSettings(stencilSettings); GrPipeline::CreateArgs args; @@ -365,46 +350,6 @@ void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder, this->recordBatch(batch); } -void GrDrawTarget::drawNonAARect(const GrPipelineBuilder& pipelineBuilder, - GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect) { - SkAutoTUnref batch(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect, - nullptr, nullptr)); - this->drawBatch(pipelineBuilder, batch); -} - -void GrDrawTarget::drawNonAARect(const GrPipelineBuilder& pipelineBuilder, - GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkMatrix& localMatrix) { - SkAutoTUnref batch(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect, - nullptr, &localMatrix)); - this->drawBatch(pipelineBuilder, batch); -} - -void GrDrawTarget::drawNonAARect(const GrPipelineBuilder& pipelineBuilder, - GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& localRect) { - SkAutoTUnref batch(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect, - &localRect, nullptr)); - this->drawBatch(pipelineBuilder, batch); -} - - -void GrDrawTarget::drawAARect(const GrPipelineBuilder& pipelineBuilder, - GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& devRect) { - SkAutoTUnref batch(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect, - devRect)); - this->drawBatch(pipelineBuilder, batch); -} - void GrDrawTarget::clear(const SkIRect* rect, GrColor color, bool canIgnoreRect, @@ -436,7 +381,11 @@ void GrDrawTarget::clear(const SkIRect* rect, GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); pipelineBuilder.setRenderTarget(renderTarget); - this->drawNonAARect(pipelineBuilder, color, SkMatrix::I(), *rect); + SkRect scalarRect = SkRect::Make(*rect); + SkAutoTUnref batch( + GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(), scalarRect, + nullptr, nullptr)); + this->drawBatch(pipelineBuilder, batch); } else { GrBatch* batch = new GrClearBatch(*rect, color, renderTarget); this->recordBatch(batch); @@ -483,9 +432,7 @@ void GrDrawTarget::recordBatch(GrBatch* batch) { // 1) check every draw // 2) intersect with something // 3) find a 'blocker' - // Experimentally we have found that most batching occurs within the first 10 comparisons. - static const int kMaxLookback = 10; - + GR_AUDIT_TRAIL_ADDBATCH(fAuditTrail, batch->name(), batch->bounds()); GrBATCH_INFO("Re-Recording (%s, B%u)\n" "\tBounds LRTB (%f, %f, %f, %f)\n", batch->name(), @@ -494,7 +441,7 @@ void GrDrawTarget::recordBatch(GrBatch* batch) { batch->bounds().fTop, batch->bounds().fBottom); GrBATCH_INFO(SkTabString(batch->dumpInfo(), 1).c_str()); GrBATCH_INFO("\tOutcome:\n"); - int maxCandidates = SkTMin(kMaxLookback, fBatches.count()); + int maxCandidates = SkTMin(fMaxBatchLookback, fBatches.count()); if (maxCandidates) { int i = 0; while (true) { diff --git a/gfx/skia/skia/src/gpu/GrDrawTarget.h b/gfx/skia/skia/src/gpu/GrDrawTarget.h index 7b0159e5d58..55c11da6674 100644 --- a/gfx/skia/skia/src/gpu/GrDrawTarget.h +++ b/gfx/skia/skia/src/gpu/GrDrawTarget.h @@ -34,22 +34,24 @@ //#define ENABLE_MDB 1 +class GrAuditTrail; class GrBatch; class GrClip; class GrCaps; class GrPath; class GrDrawPathBatchBase; -class GrPathRangeDraw; class GrDrawTarget final : public SkRefCnt { public: /** Options for GrDrawTarget behavior. */ struct Options { - Options () : fClipBatchToBounds(false) {} + Options () : fClipBatchToBounds(false), fDrawBatchBounds(false), fMaxBatchLookback(-1) {} bool fClipBatchToBounds; + bool fDrawBatchBounds; + int fMaxBatchLookback; }; - GrDrawTarget(GrRenderTarget*, GrGpu*, GrResourceProvider*, const Options&); + GrDrawTarget(GrRenderTarget*, GrGpu*, GrResourceProvider*, GrAuditTrail*, const Options&); ~GrDrawTarget() override; @@ -111,76 +113,13 @@ public: GrPathRendering::FillType); /** - * Draws a path. Fill must not be a hairline. It will respect the HW - * antialias flag on the GrPipelineBuilder (if possible in the 3D API). + * Draws a path batch. Fill must not be a hairline. It will respect the HW antialias flag on + * the GrPipelineBuilder (if possible in the 3D API). This needs to be separate from drawBatch + * because we install path stencil settings late. * - * TODO: Remove this function and construct the batch outside GrDrawTarget. + * TODO: Figure out a better model that allows us to roll this method into drawBatch. */ - void drawPath(const GrPipelineBuilder&, const SkMatrix& viewMatrix, GrColor color, - const GrPath*, GrPathRendering::FillType); - - /** - * Draws the aggregate path from combining multiple. Note that this will not - * always be equivalent to back-to-back calls to drawPath(). It will respect - * the HW antialias flag on the GrPipelineBuilder (if possible in the 3D API). - * - * TODO: Remove this function and construct the batch outside GrDrawTarget. - * - * @param draw The transforms and indices for the draw. - * This object must only be drawn once. The draw - * may modify its contents. - * @param fill Fill type for drawing all the paths - */ - void drawPathsFromRange(const GrPipelineBuilder&, - const SkMatrix& viewMatrix, - const SkMatrix& localMatrix, - GrColor color, - GrPathRange* range, - GrPathRangeDraw* draw, - GrPathRendering::FillType fill, - const SkRect& bounds); - - /** - * Helper function for drawing rects. - * - * @param rect the rect to draw - * @param localRect optional rect that specifies local coords to map onto - * rect. If nullptr then rect serves as the local coords. - * @param localMatrix Optional local matrix. The local coordinates are specified by localRect, - * or if it is nullptr by rect. This matrix applies to the coordinate implied by - * that rectangle before it is input to GrCoordTransforms that read local - * coordinates - */ - void drawNonAARect(const GrPipelineBuilder& pipelineBuilder, - GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect); - - void drawNonAARect(const GrPipelineBuilder& pipelineBuilder, - GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkMatrix& localMatrix); - - void drawNonAARect(const GrPipelineBuilder& pipelineBuilder, - GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& localRect); - - void drawNonAARect(const GrPipelineBuilder& ds, - GrColor color, - const SkMatrix& viewM, - const SkIRect& irect) { - SkRect rect = SkRect::Make(irect); - this->drawNonAARect(ds, color, viewM, rect); - } - - void drawAARect(const GrPipelineBuilder& pipelineBuilder, - GrColor color, - const SkMatrix& viewMatrix, - const SkRect& rect, - const SkRect& devRect); + void drawPathBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawPathBatchBase* batch); /** * Clear the passed in render target. Ignores the GrPipelineBuilder and clip. Clears the whole @@ -228,6 +167,8 @@ public: const CMMAccess cmmAccess() { return CMMAccess(this); } + GrAuditTrail* getAuditTrail() const { return fAuditTrail; } + private: friend class GrDrawingManager; // for resetFlag & TopoSortTraits @@ -287,8 +228,6 @@ private: GrXferProcessor::DstTexture*, const SkRect& batchBounds); - void drawPathBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawPathBatchBase* batch, - GrPathRendering::FillType fill); // Check to see if this set of draw commands has been sent out void getPathStencilSettingsForFilltype(GrPathRendering::FillType, const GrStencilAttachment*, @@ -310,7 +249,7 @@ private: GrContext* fContext; GrGpu* fGpu; GrResourceProvider* fResourceProvider; - bool fFlushing; + GrAuditTrail* fAuditTrail; SkDEBUGCODE(int fDebugID;) uint32_t fFlags; @@ -319,6 +258,9 @@ private: SkTDArray fDependencies; GrRenderTarget* fRenderTarget; + bool fDrawBatchBounds; + int fMaxBatchLookback; + typedef SkRefCnt INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/GrDrawingManager.cpp b/gfx/skia/skia/src/gpu/GrDrawingManager.cpp index 13167d4642d..90c77a5af0b 100644 --- a/gfx/skia/skia/src/gpu/GrDrawingManager.cpp +++ b/gfx/skia/skia/src/gpu/GrDrawingManager.cpp @@ -5,21 +5,24 @@ * found in the LICENSE file. */ -#include "GrAtlasTextContext.h" #include "GrDrawContext.h" #include "GrDrawingManager.h" #include "GrDrawTarget.h" #include "GrResourceProvider.h" #include "GrSoftwarePathRenderer.h" -#include "GrStencilAndCoverTextContext.h" #include "SkTTopoSort.h" +#include "text/GrAtlasTextContext.h" +#include "text/GrStencilAndCoverTextContext.h" void GrDrawingManager::cleanup() { for (int i = 0; i < fDrawTargets.count(); ++i) { fDrawTargets[i]->makeClosed(); // no drawTarget should receive a new command after this fDrawTargets[i]->clearRT(); + // We shouldn't need to do this, but it turns out some clients still hold onto drawtargets + // after a cleanup + fDrawTargets[i]->reset(); fDrawTargets[i]->unref(); } @@ -64,6 +67,11 @@ void GrDrawingManager::reset() { } void GrDrawingManager::flush() { + if (fFlushing) { + return; + } + fFlushing = true; + SkDEBUGCODE(bool result =) SkTTopoSort(&fDrawTargets); SkASSERT(result); @@ -107,6 +115,7 @@ void GrDrawingManager::flush() { #endif fFlushState.reset(); + fFlushing = false; } GrTextContext* GrDrawingManager::textContext(const SkSurfaceProps& props, @@ -153,7 +162,7 @@ GrDrawTarget* GrDrawingManager::newDrawTarget(GrRenderTarget* rt) { #endif GrDrawTarget* dt = new GrDrawTarget(rt, fContext->getGpu(), fContext->resourceProvider(), - fOptionsForDrawTargets); + fContext->getAuditTrail(), fOptionsForDrawTargets); *fDrawTargets.append() = dt; @@ -193,5 +202,5 @@ GrDrawContext* GrDrawingManager::drawContext(GrRenderTarget* rt, return nullptr; } - return new GrDrawContext(this, rt, surfaceProps); + return new GrDrawContext(this, rt, surfaceProps, fContext->getAuditTrail(), fSingleOwner); } diff --git a/gfx/skia/skia/src/gpu/GrDrawingManager.h b/gfx/skia/skia/src/gpu/GrDrawingManager.h index 672f7b08da7..df6c71a322e 100644 --- a/gfx/skia/skia/src/gpu/GrDrawingManager.h +++ b/gfx/skia/skia/src/gpu/GrDrawingManager.h @@ -16,6 +16,7 @@ class GrContext; class GrDrawContext; +class GrSingleOWner; class GrSoftwarePathRenderer; class GrTextContext; @@ -53,14 +54,17 @@ public: static bool ProgramUnitTest(GrContext* context, int maxStages); private: - GrDrawingManager(GrContext* context, const GrDrawTarget::Options& optionsForDrawTargets) + GrDrawingManager(GrContext* context, const GrDrawTarget::Options& optionsForDrawTargets, + GrSingleOwner* singleOwner) : fContext(context) , fOptionsForDrawTargets(optionsForDrawTargets) + , fSingleOwner(singleOwner) , fAbandoned(false) , fNVPRTextContext(nullptr) , fPathRendererChain(nullptr) , fSoftwarePathRenderer(nullptr) - , fFlushState(context->getGpu(), context->resourceProvider()) { + , fFlushState(context->getGpu(), context->resourceProvider()) + , fFlushing(false) { sk_bzero(fTextContexts, sizeof(fTextContexts)); } @@ -77,6 +81,9 @@ private: GrContext* fContext; GrDrawTarget::Options fOptionsForDrawTargets; + // In debug builds we guard against improper thread handling + GrSingleOwner* fSingleOwner; + bool fAbandoned; SkTDArray fDrawTargets; @@ -87,6 +94,7 @@ private: GrSoftwarePathRenderer* fSoftwarePathRenderer; GrBatchFlushState fFlushState; + bool fFlushing; }; #endif diff --git a/gfx/skia/skia/src/gpu/GrFragmentProcessor.cpp b/gfx/skia/skia/src/gpu/GrFragmentProcessor.cpp index 4cf2e73099a..f05b7aa0845 100644 --- a/gfx/skia/skia/src/gpu/GrFragmentProcessor.cpp +++ b/gfx/skia/skia/src/gpu/GrFragmentProcessor.cpp @@ -8,10 +8,12 @@ #include "GrFragmentProcessor.h" #include "GrCoordTransform.h" +#include "GrInvariantOutput.h" +#include "GrProcOptInfo.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "effects/GrConstColorProcessor.h" #include "effects/GrXfermodeFragmentProcessor.h" @@ -226,9 +228,10 @@ const GrFragmentProcessor* GrFragmentProcessor::OverrideInput(const GrFragmentPr GLFP() : fHaveSetColor(false) {} void emitCode(EmitArgs& args) override { const char* colorName; - fColorUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "Color", &colorName); + fColorUni = args.fUniformHandler->addUniform( + GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "Color", &colorName); this->emitChild(0, colorName, args); } diff --git a/gfx/skia/skia/src/gpu/GrGpu.cpp b/gfx/skia/skia/src/gpu/GrGpu.cpp index 439fe1b70fa..2815f612d60 100644 --- a/gfx/skia/skia/src/gpu/GrGpu.cpp +++ b/gfx/skia/skia/src/gpu/GrGpu.cpp @@ -20,6 +20,7 @@ #include "GrRenderTargetPriv.h" #include "GrStencilAttachment.h" #include "GrSurfacePriv.h" +#include "GrTransferBuffer.h" #include "GrVertexBuffer.h" #include "GrVertices.h" @@ -159,6 +160,13 @@ GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, bool budgeted, GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc, GrWrapOwnership ownership) { this->handleDirtyContext(); + if (!this->caps()->isConfigTexturable(desc.fConfig)) { + return nullptr; + } + if ((desc.fFlags & kRenderTarget_GrBackendTextureFlag) && + !this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { + return nullptr; + } GrTexture* tex = this->onWrapBackendTexture(desc, ownership); if (nullptr == tex) { return nullptr; @@ -175,6 +183,9 @@ GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc, GrWrapOwn GrRenderTarget* GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc, GrWrapOwnership ownership) { + if (!this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { + return nullptr; + } this->handleDirtyContext(); return this->onWrapBackendRenderTarget(desc, ownership); } @@ -197,6 +208,12 @@ GrIndexBuffer* GrGpu::createIndexBuffer(size_t size, bool dynamic) { return ib; } +GrTransferBuffer* GrGpu::createTransferBuffer(size_t size, TransferType type) { + this->handleDirtyContext(); + GrTransferBuffer* tb = this->onCreateTransferBuffer(size, type); + return tb; +} + void GrGpu::clear(const SkIRect& rect, GrColor color, GrRenderTarget* renderTarget) { @@ -317,7 +334,7 @@ bool GrGpu::writePixels(GrSurface* surface, int left, int top, int width, int height, GrPixelConfig config, const void* buffer, size_t rowBytes) { - if (!buffer) { + if (!buffer || !surface) { return false; } @@ -329,6 +346,21 @@ bool GrGpu::writePixels(GrSurface* surface, return false; } +bool GrGpu::transferPixels(GrSurface* surface, + int left, int top, int width, int height, + GrPixelConfig config, GrTransferBuffer* buffer, + size_t offset, size_t rowBytes) { + SkASSERT(buffer); + + this->handleDirtyContext(); + if (this->onTransferPixels(surface, left, top, width, height, config, + buffer, offset, rowBytes)) { + fStats.incTransfersToTexture(); + return true; + } + return false; +} + void GrGpu::resolveRenderTarget(GrRenderTarget* target) { SkASSERT(target); this->handleDirtyContext(); diff --git a/gfx/skia/skia/src/gpu/GrGpu.h b/gfx/skia/skia/src/gpu/GrGpu.h index aeaa595f8b6..3eaa3fc035e 100644 --- a/gfx/skia/skia/src/gpu/GrGpu.h +++ b/gfx/skia/skia/src/gpu/GrGpu.h @@ -31,6 +31,7 @@ class GrRenderTarget; class GrStencilAttachment; class GrSurface; class GrTexture; +class GrTransferBuffer; class GrVertexBuffer; class GrVertices; @@ -128,6 +129,17 @@ public: */ GrIndexBuffer* createIndexBuffer(size_t size, bool dynamic); + /** + * Creates a transfer buffer. + * + * @param size size in bytes of the index buffer + * @param toGpu true if used to transfer from the cpu to the gpu + * otherwise to be used to transfer from the gpu to the cpu + * + * @return The transfer buffer if successful, otherwise nullptr. + */ + GrTransferBuffer* createTransferBuffer(size_t size, TransferType type); + /** * Resolves MSAA. */ @@ -248,6 +260,25 @@ public: GrPixelConfig config, const void* buffer, size_t rowBytes); + /** + * Updates the pixels in a rectangle of a surface using a GrTransferBuffer + * + * @param surface The surface to write to. + * @param left left edge of the rectangle to write (inclusive) + * @param top top edge of the rectangle to write (inclusive) + * @param width width of rectangle to write in pixels. + * @param height height of rectangle to write in pixels. + * @param config the pixel config of the source buffer + * @param buffer GrTransferBuffer to read pixels from + * @param offset offset from the start of the buffer + * @param rowBytes number of bytes between consecutive rows. Zero + * means rows are tightly packed. + */ + bool transferPixels(GrSurface* surface, + int left, int top, int width, int height, + GrPixelConfig config, GrTransferBuffer* buffer, + size_t offset, size_t rowBytes); + /** * Clear the passed in render target. Ignores the draw state and clip. */ @@ -327,6 +358,7 @@ public: fShaderCompilations = 0; fTextureCreates = 0; fTextureUploads = 0; + fTransfersToTexture = 0; fStencilAttachmentCreates = 0; fNumDraws = 0; } @@ -339,6 +371,8 @@ public: void incTextureCreates() { fTextureCreates++; } int textureUploads() const { return fTextureUploads; } void incTextureUploads() { fTextureUploads++; } + int transfersToTexture() const { return fTransfersToTexture; } + void incTransfersToTexture() { fTransfersToTexture++; } void incStencilAttachmentCreates() { fStencilAttachmentCreates++; } void incNumDraws() { fNumDraws++; } void dump(SkString*); @@ -349,6 +383,7 @@ public: int fShaderCompilations; int fTextureCreates; int fTextureUploads; + int fTransfersToTexture; int fStencilAttachmentCreates; int fNumDraws; #else @@ -358,6 +393,7 @@ public: void incShaderCompilations() {} void incTextureCreates() {} void incTextureUploads() {} + void incTransfersToTexture() {} void incStencilAttachmentCreates() {} void incNumDraws() {} #endif @@ -387,6 +423,8 @@ public: // clears target's entire stencil buffer to 0 virtual void clearStencil(GrRenderTarget* target) = 0; + // draws an outline rectangle for debugging/visualization purposes. + virtual void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) = 0; // Determines whether a copy of a texture must be made in order to be compatible with // a given GrTextureParams. If so, the width, height and filter used for the copy are @@ -455,6 +493,7 @@ private: GrWrapOwnership) = 0; virtual GrVertexBuffer* onCreateVertexBuffer(size_t size, bool dynamic) = 0; virtual GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) = 0; + virtual GrTransferBuffer* onCreateTransferBuffer(size_t size, TransferType type) = 0; // overridden by backend-specific derived class to perform the clear. virtual void onClear(GrRenderTarget*, const SkIRect& rect, GrColor color) = 0; @@ -488,6 +527,12 @@ private: GrPixelConfig config, const void* buffer, size_t rowBytes) = 0; + // overridden by backend-specific derived class to perform the surface write + virtual bool onTransferPixels(GrSurface*, + int left, int top, int width, int height, + GrPixelConfig config, GrTransferBuffer* buffer, + size_t offset, size_t rowBytes) = 0; + // overridden by backend-specific derived class to perform the resolve virtual void onResolveRenderTarget(GrRenderTarget* target) = 0; diff --git a/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.cpp b/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.cpp index c37c0227758..2edff60553c 100644 --- a/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.cpp +++ b/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.cpp @@ -12,10 +12,15 @@ #include "SkBitmap.h" #include "SkGrPriv.h" #include "SkImage_Base.h" +#include "SkImageCacherator.h" #include "SkPixelRef.h" +static bool bmp_is_alpha_only(const SkBitmap& bm) { return kAlpha_8_SkColorType == bm.colorType(); } + GrBitmapTextureAdjuster::GrBitmapTextureAdjuster(const SkBitmap* bmp) - : INHERITED(bmp->getTexture(), SkIRect::MakeWH(bmp->width(), bmp->height())) + : INHERITED(bmp->getTexture(), + SkIRect::MakeWH(bmp->width(), bmp->height()), + bmp_is_alpha_only(*bmp)) , fBmp(bmp) {} void GrBitmapTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) { @@ -38,8 +43,15 @@ void GrBitmapTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) { ////////////////////////////////////////////////////////////////////////////// +// SkImage's don't have a way of communicating whether they're alpha-only. So we fallback to +// inspecting the texture. +static bool tex_image_is_alpha_only(const SkImage_Base& img) { + return GrPixelConfigIsAlphaOnly(img.peekTexture()->config()); +} + GrImageTextureAdjuster::GrImageTextureAdjuster(const SkImage_Base* img) - : INHERITED(img->peekTexture(), SkIRect::MakeWH(img->width(), img->height())) + : INHERITED(img->peekTexture(), SkIRect::MakeWH(img->width(), img->height()), + tex_image_is_alpha_only(*img)) , fImageBase(img) {} void GrImageTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) { @@ -58,7 +70,7 @@ void GrImageTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) { ////////////////////////////////////////////////////////////////////////////// GrBitmapTextureMaker::GrBitmapTextureMaker(GrContext* context, const SkBitmap& bitmap) - : INHERITED(context, bitmap.width(), bitmap.height()) + : INHERITED(context, bitmap.width(), bitmap.height(), bmp_is_alpha_only(bitmap)) , fBitmap(bitmap) { SkASSERT(!bitmap.getTexture()); if (!bitmap.isVolatile()) { @@ -96,3 +108,36 @@ void GrBitmapTextureMaker::makeCopyKey(const CopyParams& copyParams, GrUniqueKey void GrBitmapTextureMaker::didCacheCopy(const GrUniqueKey& copyKey) { GrInstallBitmapUniqueKeyInvalidator(copyKey, fBitmap.pixelRef()); } + +////////////////////////////////////////////////////////////////////////////// +static bool cacher_is_alpha_only(const SkImageCacherator& cacher) { + return kAlpha_8_SkColorType == cacher.info().colorType(); +} +GrImageTextureMaker::GrImageTextureMaker(GrContext* context, SkImageCacherator* cacher, + const SkImage* client, SkImage::CachingHint chint) + : INHERITED(context, cacher->info().width(), cacher->info().height(), + cacher_is_alpha_only(*cacher)) + , fCacher(cacher) + , fClient(client) + , fCachingHint(chint) { + if (client) { + GrMakeKeyFromImageID(&fOriginalKey, client->uniqueID(), + SkIRect::MakeWH(this->width(), this->height())); + } +} + +GrTexture* GrImageTextureMaker::refOriginalTexture() { + return fCacher->lockTexture(this->context(), fOriginalKey, fClient, fCachingHint); +} + +void GrImageTextureMaker::makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey) { + if (fOriginalKey.isValid() && SkImage::kAllow_CachingHint == fCachingHint) { + MakeCopyKeyFromOrigKey(fOriginalKey, stretch, paramsCopyKey); + } +} + +void GrImageTextureMaker::didCacheCopy(const GrUniqueKey& copyKey) { + if (fClient) { + as_IB(fClient)->notifyAddedToCache(); + } +} diff --git a/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.h b/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.h index a20902ed581..d8510feeaaf 100644 --- a/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.h +++ b/gfx/skia/skia/src/gpu/GrImageIDTextureAdjuster.h @@ -9,9 +9,11 @@ #define GrImageIDTextureAdjuster_DEFINED #include "GrTextureParamsAdjuster.h" +#include "SkImage.h" class SkBitmap; class SkImage_Base; +class SkImageCacherator; /** Implementation for texture-backed SkBitmaps. The bitmap must stay in scope and unmodified while this object exists. */ @@ -66,4 +68,29 @@ private: typedef GrTextureMaker INHERITED; }; +/** This class manages the conversion of generator-backed images to GrTextures. If the caching hint + is kAllow the image's ID is used for the cache key. */ +class GrImageTextureMaker : public GrTextureMaker { +public: + GrImageTextureMaker(GrContext* context, SkImageCacherator* cacher, const SkImage* client, + SkImage::CachingHint chint); + +protected: + // TODO: consider overriding this, for the case where the underlying generator might be + // able to efficiently produce a "stretched" texture natively (e.g. picture-backed) + // GrTexture* generateTextureForParams(const CopyParams&) override; + + GrTexture* refOriginalTexture() override; + void makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey) override; + void didCacheCopy(const GrUniqueKey& copyKey) override; + +private: + SkImageCacherator* fCacher; + const SkImage* fClient; + GrUniqueKey fOriginalKey; + SkImage::CachingHint fCachingHint; + + typedef GrTextureMaker INHERITED; +}; + #endif diff --git a/gfx/skia/skia/src/gpu/GrLayerHoister.cpp b/gfx/skia/skia/src/gpu/GrLayerHoister.cpp index 004e4d0e6eb..842ab56dfbd 100644 --- a/gfx/skia/skia/src/gpu/GrLayerHoister.cpp +++ b/gfx/skia/skia/src/gpu/GrLayerHoister.cpp @@ -12,7 +12,6 @@ #include "SkBigPicture.h" #include "SkCanvas.h" #include "SkGpuDevice.h" -#include "SkGrPixelRef.h" #include "SkLayerInfo.h" #include "SkRecordDraw.h" #include "SkSurface.h" @@ -277,15 +276,6 @@ void GrLayerHoister::DrawLayersToAtlas(GrContext* context, } } -SkBitmap wrap_texture(GrTexture* texture) { - SkASSERT(texture); - - SkBitmap result; - result.setInfo(texture->surfacePriv().info(kPremul_SkAlphaType)); - result.setPixelRef(new SkGrPixelRef(result.info(), texture))->unref(); - return result; -} - void GrLayerHoister::FilterLayer(GrContext* context, SkGpuDevice* device, const GrHoistedLayer& info) { @@ -311,10 +301,12 @@ void GrLayerHoister::FilterLayer(GrContext* context, // This cache is transient, and is freed (along with all its contained // textures) when it goes out of scope. SkAutoTUnref cache(SkImageFilter::Cache::Create(kDefaultCacheSize)); - SkImageFilter::Context filterContext(totMat, clipBounds, cache, SkImageFilter::kApprox_SizeConstraint); + SkImageFilter::Context filterContext(totMat, clipBounds, cache); SkImageFilter::DeviceProxy proxy(device); - const SkBitmap src = wrap_texture(layer->texture()); + SkBitmap src; + GrWrapTextureInBitmap(layer->texture(), layer->texture()->width(), layer->texture()->height(), + false, &src); if (!layer->filter()->filterImage(&proxy, src, filterContext, &filteredBitmap, &offset)) { // Filtering failed. Press on with the unfiltered version. diff --git a/gfx/skia/skia/src/gpu/GrMemoryPool.cpp b/gfx/skia/skia/src/gpu/GrMemoryPool.cpp index cc26452c19c..adf46846c88 100644 --- a/gfx/skia/skia/src/gpu/GrMemoryPool.cpp +++ b/gfx/skia/skia/src/gpu/GrMemoryPool.cpp @@ -21,7 +21,7 @@ GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize) { fMinAllocSize = GrSizeAlignUp(minAllocSize + kPerAllocPad, kAlignment), fPreallocSize = GrSizeAlignUp(preallocSize + kPerAllocPad, kAlignment); fPreallocSize = SkTMax(fPreallocSize, fMinAllocSize); - fSize = fPreallocSize; + fSize = 0; fHead = CreateBlock(fPreallocSize); fTail = fHead; @@ -40,8 +40,8 @@ GrMemoryPool::~GrMemoryPool() { void* GrMemoryPool::allocate(size_t size) { VALIDATE; - size = GrSizeAlignUp(size, kAlignment); size += kPerAllocPad; + size = GrSizeAlignUp(size, kAlignment); if (fTail->fFreeSize < size) { size_t blockSize = size; blockSize = SkTMax(blockSize, fMinAllocSize); @@ -55,11 +55,14 @@ void* GrMemoryPool::allocate(size_t size) { fSize += block->fSize; SkDEBUGCODE(++fAllocBlockCnt); } + SkASSERT(kAssignedMarker == fTail->fBlockSentinal); SkASSERT(fTail->fFreeSize >= size); intptr_t ptr = fTail->fCurrPtr; // We stash a pointer to the block header, just before the allocated space, // so that we can decrement the live count on delete in constant time. - *reinterpret_cast(ptr) = fTail; + AllocHeader* allocData = reinterpret_cast(ptr); + SkDEBUGCODE(allocData->fSentinal = kAssignedMarker); + allocData->fHeader = fTail; ptr += kPerAllocPad; fTail->fPrevPtr = fTail->fCurrPtr; fTail->fCurrPtr += size; @@ -74,7 +77,11 @@ void* GrMemoryPool::allocate(size_t size) { void GrMemoryPool::release(void* p) { VALIDATE; intptr_t ptr = reinterpret_cast(p) - kPerAllocPad; - BlockHeader* block = *reinterpret_cast(ptr); + AllocHeader* allocData = reinterpret_cast(ptr); + SkASSERT(kAssignedMarker == allocData->fSentinal); + SkDEBUGCODE(allocData->fSentinal = kFreedMarker); + BlockHeader* block = allocData->fHeader; + SkASSERT(kAssignedMarker == block->fBlockSentinal); if (1 == block->fLiveCount) { // the head block is special, it is reset rather than deleted if (fHead == block) { @@ -114,6 +121,7 @@ GrMemoryPool::BlockHeader* GrMemoryPool::CreateBlock(size_t size) { reinterpret_cast(sk_malloc_throw(paddedSize)); // we assume malloc gives us aligned memory SkASSERT(!(reinterpret_cast(block) % kAlignment)); + SkDEBUGCODE(block->fBlockSentinal = kAssignedMarker); block->fLiveCount = 0; block->fFreeSize = size; block->fCurrPtr = reinterpret_cast(block) + kHeaderSize; @@ -123,6 +131,8 @@ GrMemoryPool::BlockHeader* GrMemoryPool::CreateBlock(size_t size) { } void GrMemoryPool::DeleteBlock(BlockHeader* block) { + SkASSERT(kAssignedMarker == block->fBlockSentinal); + SkDEBUGCODE(block->fBlockSentinal = kFreedMarker); // FWIW sk_free(block); } @@ -133,6 +143,7 @@ void GrMemoryPool::validate() { SkASSERT(block); int allocCount = 0; do { + SkASSERT(kAssignedMarker == block->fBlockSentinal); allocCount += block->fLiveCount; SkASSERT(prev == block->fPrev); if (prev) { @@ -159,12 +170,16 @@ void GrMemoryPool::validate() { SkASSERT(ptrOffset == kHeaderSize); SkASSERT(userStart == block->fCurrPtr); } else { - SkASSERT(block == *reinterpret_cast(userStart)); + AllocHeader* allocData = reinterpret_cast(userStart); + SkASSERT(allocData->fSentinal == kAssignedMarker || + allocData->fSentinal == kFreedMarker); + SkASSERT(block == allocData->fHeader); } + prev = block; } while ((block = block->fNext)); SkASSERT(allocCount == fAllocationCnt); SkASSERT(prev == fTail); - SkASSERT(fAllocBlockCnt != 0 || fSize == fPreallocSize); + SkASSERT(fAllocBlockCnt != 0 || fSize == 0); #endif } diff --git a/gfx/skia/skia/src/gpu/GrMemoryPool.h b/gfx/skia/skia/src/gpu/GrMemoryPool.h index 4de641d9fcb..43826d354a1 100644 --- a/gfx/skia/skia/src/gpu/GrMemoryPool.h +++ b/gfx/skia/skia/src/gpu/GrMemoryPool.h @@ -44,7 +44,7 @@ public: bool isEmpty() const { return fTail == fHead && !fHead->fLiveCount; } /** - * Returns the total allocated size of the GrMemoryPool + * Returns the total allocated size of the GrMemoryPool minus any preallocated amount */ size_t size() const { return fSize; } @@ -58,6 +58,9 @@ private: void validate(); struct BlockHeader { +#ifdef SK_DEBUG + uint32_t fBlockSentinal; ///< known value to check for bad back pointers to blocks +#endif BlockHeader* fNext; ///< doubly-linked list of blocks. BlockHeader* fPrev; int fLiveCount; ///< number of outstanding allocations in the @@ -68,11 +71,21 @@ private: size_t fSize; ///< total allocated size of the block }; + static const uint32_t kAssignedMarker = 0xCDCDCDCD; + static const uint32_t kFreedMarker = 0xEFEFEFEF; + + struct AllocHeader { +#ifdef SK_DEBUG + uint32_t fSentinal; ///< known value to check for memory stomping (e.g., (CD)*) +#endif + BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides + }; + enum { // We assume this alignment is good enough for everybody. kAlignment = 8, kHeaderSize = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment), - kPerAllocPad = GR_CT_ALIGN_UP(sizeof(BlockHeader*), kAlignment), + kPerAllocPad = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment), }; size_t fSize; size_t fPreallocSize; diff --git a/gfx/skia/skia/src/gpu/GrOvalRenderer.cpp b/gfx/skia/skia/src/gpu/GrOvalRenderer.cpp index e13c0d11e4e..6cb203c05a7 100644 --- a/gfx/skia/skia/src/gpu/GrOvalRenderer.cpp +++ b/gfx/skia/skia/src/gpu/GrOvalRenderer.cpp @@ -19,14 +19,15 @@ #include "SkRRect.h" #include "SkStrokeRec.h" #include "SkTLazy.h" +#include "batches/GrRectBatchFactory.h" #include "batches/GrVertexBatch.h" #include "effects/GrRRectEffect.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLVarying.h" #include "glsl/GrGLSLVertexShaderBuilder.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLUtil.h" // TODO(joshualitt) - Break this file up during GrBatch post implementation cleanup @@ -98,9 +99,9 @@ public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const CircleEdgeEffect& ce = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(ce); @@ -112,16 +113,17 @@ public: GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // setup pass through color if (!ce.colorIgnored()) { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, + &fColorUniform); } // Setup position - this->setupPosition(pb, vertBuilder, gpArgs, ce.inPosition()->fName); + this->setupPosition(vertBuilder, gpArgs, ce.inPosition()->fName); // emit transforms - this->emitTransforms(args.fPB, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, ce.inPosition()->fName, ce.localMatrix(), @@ -254,9 +256,9 @@ public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const EllipseEdgeEffect& ee = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(ee); @@ -274,16 +276,17 @@ public: GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // setup pass through color if (!ee.colorIgnored()) { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, + &fColorUniform); } // Setup position - this->setupPosition(pb, vertBuilder, gpArgs, ee.inPosition()->fName); + this->setupPosition(vertBuilder, gpArgs, ee.inPosition()->fName); // emit transforms - this->emitTransforms(args.fPB, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, ee.inPosition()->fName, ee.localMatrix(), @@ -436,9 +439,9 @@ public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const DIEllipseEdgeEffect& ee = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(ee); @@ -456,21 +459,22 @@ public: GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // setup pass through color if (!ee.colorIgnored()) { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, + &fColorUniform); } // Setup position - this->setupPosition(pb, - vertBuilder, + this->setupPosition(vertBuilder, + uniformHandler, gpArgs, ee.inPosition()->fName, ee.viewMatrix(), &fViewMatrixUniform); // emit transforms - this->emitTransforms(args.fPB, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, ee.inPosition()->fName, args.fTransformsIn, @@ -1490,7 +1494,9 @@ bool GrOvalRenderer::DrawDRRect(GrDrawTarget* target, if (applyAA) { bounds.outset(SK_ScalarHalf, SK_ScalarHalf); } - target->drawNonAARect(pipelineBuilder, color, SkMatrix::I(), bounds, invert); + SkAutoTUnref batch(GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(), + bounds, nullptr, &invert)); + target->drawBatch(pipelineBuilder, batch); return true; } diff --git a/gfx/skia/skia/src/gpu/GrPath.h b/gfx/skia/skia/src/gpu/GrPath.h index 2edfd4cb5e6..09d317ef2f2 100644 --- a/gfx/skia/skia/src/gpu/GrPath.h +++ b/gfx/skia/skia/src/gpu/GrPath.h @@ -10,19 +10,19 @@ #include "GrGpuResource.h" #include "GrStrokeInfo.h" +#include "GrPathRendering.h" #include "SkPath.h" #include "SkRect.h" class GrPath : public GrGpuResource { public: - - /** * Initialize to a path with a fixed stroke. Stroke must not be hairline. */ GrPath(GrGpu* gpu, const SkPath& skPath, const GrStrokeInfo& stroke) : INHERITED(gpu, kCached_LifeCycle) - , fBounds(skPath.getBounds()) + , fBounds(SkRect::MakeEmpty()) + , fFillType(GrPathRendering::kWinding_FillType) #ifdef SK_DEBUG , fSkPath(skPath) , fStroke(stroke) @@ -35,12 +35,15 @@ public: const SkRect& getBounds() const { return fBounds; } + GrPathRendering::FillType getFillType() const { return fFillType; } #ifdef SK_DEBUG bool isEqualTo(const SkPath& path, const GrStrokeInfo& stroke) const; #endif protected: + // Subclass should init these. SkRect fBounds; + GrPathRendering::FillType fFillType; #ifdef SK_DEBUG SkPath fSkPath; GrStrokeInfo fStroke; diff --git a/gfx/skia/skia/src/gpu/GrPathProcessor.cpp b/gfx/skia/skia/src/gpu/GrPathProcessor.cpp index 66f94eaaab5..f1faa7d2397 100644 --- a/gfx/skia/skia/src/gpu/GrPathProcessor.cpp +++ b/gfx/skia/skia/src/gpu/GrPathProcessor.cpp @@ -11,7 +11,7 @@ #include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProcessorTypes.h" -#include "glsl/GrGLSLProgramBuilder.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" class GrGLPathProcessor : public GrGLSLPrimitiveProcessor { @@ -26,7 +26,6 @@ public: } void emitCode(EmitArgs& args) override { - GrGLSLGPBuilder* pb = args.fPB; GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const GrPathProcessor& pathProc = args.fGP.cast(); @@ -36,11 +35,12 @@ public: // Setup uniform color if (pathProc.overrides().readsColor()) { const char* stagedLocalVarName; - fColorUniform = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, - kDefault_GrSLPrecision, - "Color", - &stagedLocalVarName); + fColorUniform = args.fUniformHandler->addUniform( + GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, + kDefault_GrSLPrecision, + "Color", + &stagedLocalVarName); fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, stagedLocalVarName); } diff --git a/gfx/skia/skia/src/gpu/GrPathUtils.cpp b/gfx/skia/skia/src/gpu/GrPathUtils.cpp index 21d115569b4..f97a61e1f60 100644 --- a/gfx/skia/skia/src/gpu/GrPathUtils.cpp +++ b/gfx/skia/skia/src/gpu/GrPathUtils.cpp @@ -133,10 +133,10 @@ uint32_t GrPathUtils::generateCubicPoints(const SkPoint& p0, if (pointsLeft < 2 || (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd && p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) { - (*points)[0] = p3; - *points += 1; - return 1; - } + (*points)[0] = p3; + *points += 1; + return 1; + } SkPoint q[] = { { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) }, @@ -408,8 +408,8 @@ void convert_noninflect_cubic_to_quads(const SkPoint p[4], SkVector ab = p[1] - p[0]; SkVector dc = p[2] - p[3]; - if (ab.isZero()) { - if (dc.isZero()) { + if (ab.lengthSqd() < SK_ScalarNearlyZero) { + if (dc.lengthSqd() < SK_ScalarNearlyZero) { SkPoint* degQuad = quads->push_back_n(3); degQuad[0] = p[0]; degQuad[1] = p[0]; @@ -418,7 +418,7 @@ void convert_noninflect_cubic_to_quads(const SkPoint p[4], } ab = p[2] - p[0]; } - if (dc.isZero()) { + if (dc.lengthSqd() < SK_ScalarNearlyZero) { dc = p[1] - p[3]; } diff --git a/gfx/skia/skia/src/gpu/GrPipeline.cpp b/gfx/skia/skia/src/gpu/GrPipeline.cpp index 02edd4201e1..e1c733a6761 100644 --- a/gfx/skia/skia/src/gpu/GrPipeline.cpp +++ b/gfx/skia/skia/src/gpu/GrPipeline.cpp @@ -28,29 +28,30 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args, builder.hasMixedSamples(), &args.fDstTexture, *args.fCaps)); + if (!xferProcessor) { + 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, builder.hasMixedSamples(), &args.fDstTexture)); } - - if (!xferProcessor) { - return nullptr; - } - - GrColor overrideColor = GrColor_ILLEGAL; + GrColor overrideColor = GrColor_ILLEGAL; if (args.fOpts.fColorPOI.firstEffectiveProcessorIndex() != 0) { overrideColor = args.fOpts.fColorPOI.inputColorToFirstEffectiveProccesor(); } GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags; - optFlags = xferProcessor->getOptimizations(args.fOpts, - builder.getStencil().doesWrite(), - &overrideColor, - *args.fCaps); + const GrXferProcessor* xpForOpts = xferProcessor ? xferProcessor.get() : + &GrPorterDuffXPFactory::SimpleSrcOverXP(); + optFlags = xpForOpts->getOptimizations(args.fOpts, + builder.getStencil().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 @@ -167,14 +168,12 @@ void GrPipeline::addDependenciesTo(GrRenderTarget* rt) const { add_dependencies_for_processor(fFragmentProcessors[i].get(), rt); } - if (fXferProcessor.get()) { - const GrXferProcessor* xfer = fXferProcessor.get(); + const GrXferProcessor& xfer = this->getXferProcessor(); - for (int i = 0; i < xfer->numTextures(); ++i) { - GrTexture* texture = xfer->textureAccess(i).getTexture(); - SkASSERT(rt->getLastDrawTarget()); - rt->getLastDrawTarget()->addDependency(texture); - } + for (int i = 0; i < xfer.numTextures(); ++i) { + GrTexture* texture = xfer.textureAccess(i).getTexture(); + SkASSERT(rt->getLastDrawTarget()); + rt->getLastDrawTarget()->addDependency(texture); } } @@ -185,7 +184,7 @@ void GrPipeline::adjustProgramFromOptimizations(const GrPipelineBuilder& pipelin int* firstColorProcessorIdx, int* firstCoverageProcessorIdx) { fIgnoresCoverage = SkToBool(flags & GrXferProcessor::kIgnoreCoverage_OptFlag); - fReadsFragPosition = fXferProcessor->willReadFragmentPosition(); + fReadsFragPosition = this->getXferProcessor().willReadFragmentPosition(); if ((flags & GrXferProcessor::kIgnoreColor_OptFlag) || (flags & GrXferProcessor::kOverrideColor_OptFlag)) { @@ -221,8 +220,11 @@ bool GrPipeline::AreEqual(const GrPipeline& a, const GrPipeline& b, return false; } - if (!a.getXferProcessor()->isEqual(*b.getXferProcessor())) { - return false; + // Most of the time both are nullptr + if (a.fXferProcessor.get() || b.fXferProcessor.get()) { + if (!a.getXferProcessor().isEqual(b.getXferProcessor())) { + return false; + } } for (int i = 0; i < a.numFragmentProcessors(); i++) { diff --git a/gfx/skia/skia/src/gpu/GrPipeline.h b/gfx/skia/skia/src/gpu/GrPipeline.h index fbfe119ac0d..60d0cab1aba 100644 --- a/gfx/skia/skia/src/gpu/GrPipeline.h +++ b/gfx/skia/skia/src/gpu/GrPipeline.h @@ -103,7 +103,15 @@ public: } int numFragmentProcessors() const { return fFragmentProcessors.count(); } - const GrXferProcessor* getXferProcessor() const { return fXferProcessor.get(); } + const GrXferProcessor& getXferProcessor() const { + if (fXferProcessor.get()) { + return *fXferProcessor.get(); + } else { + // A null xp member means the common src-over case. GrXferProcessor's ref'ing + // mechanism is not thread safe so we do not hold a ref on this global. + return GrPorterDuffXPFactory::SimpleSrcOverXP(); + } + } const GrFragmentProcessor& getColorFragmentProcessor(int idx) const { SkASSERT(idx < this->numColorFragmentProcessors()); @@ -136,7 +144,7 @@ public: bool snapVerticesToPixelCenters() const { return SkToBool(fFlags & kSnapVertices_Flag); } GrXferBarrierType xferBarrierType(const GrCaps& caps) const { - return fXferProcessor->xferBarrierType(fRenderTarget.get(), caps); + return this->getXferProcessor().xferBarrierType(fRenderTarget.get(), caps); } /** diff --git a/gfx/skia/skia/src/gpu/GrProgramDesc.h b/gfx/skia/skia/src/gpu/GrProgramDesc.h index 13dd14935d8..63e060ee628 100644 --- a/gfx/skia/skia/src/gpu/GrProgramDesc.h +++ b/gfx/skia/skia/src/gpu/GrProgramDesc.h @@ -70,15 +70,16 @@ public: } struct KeyHeader { - uint8_t fFragPosKey; // set by GrGLShaderBuilder if there are - // effects that read the fragment position. - // Otherwise, 0. + // Set by GrGLShaderBuilder if there are effects that read the fragment position. Otherwise, + // 0. + uint8_t fFragPosKey; + // Set to uniquely idenitify any swizzling of the shader's output color(s). + uint8_t fOutputSwizzle; uint8_t fSnapVerticesToPixelCenters; int8_t fColorEffectCnt; int8_t fCoverageEffectCnt; uint8_t fIgnoresCoverage; }; - GR_STATIC_ASSERT(sizeof(KeyHeader) == 5); int numColorEffects() const { return this->header().fColorEffectCnt; diff --git a/gfx/skia/skia/src/gpu/GrRecordReplaceDraw.cpp b/gfx/skia/skia/src/gpu/GrRecordReplaceDraw.cpp index 28f27dfc1c7..1fe60407895 100644 --- a/gfx/skia/skia/src/gpu/GrRecordReplaceDraw.cpp +++ b/gfx/skia/skia/src/gpu/GrRecordReplaceDraw.cpp @@ -10,16 +10,11 @@ #include "GrRecordReplaceDraw.h" #include "SkBigPicture.h" #include "SkCanvasPriv.h" -#include "SkGrPixelRef.h" +#include "SkGr.h" #include "SkImage.h" #include "SkRecordDraw.h" #include "SkRecords.h" -static inline void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* result) { - SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); - result->setInfo(info); - result->setPixelRef(new SkGrPixelRef(info, texture))->unref(); -} static inline void draw_replacement_bitmap(GrCachedLayer* layer, SkCanvas* canvas) { @@ -30,10 +25,11 @@ static inline void draw_replacement_bitmap(GrCachedLayer* layer, SkCanvas* canva } SkBitmap bm; - wrap_texture(layer->texture(), - !layer->isAtlased() ? layer->rect().width() : layer->texture()->width(), - !layer->isAtlased() ? layer->rect().height() : layer->texture()->height(), - &bm); + GrWrapTextureInBitmap(layer->texture(), + !layer->isAtlased() ? layer->rect().width() : layer->texture()->width(), + !layer->isAtlased() ? layer->rect().height() : layer->texture()->height(), + false, + &bm); canvas->save(); canvas->setMatrix(SkMatrix::I()); diff --git a/gfx/skia/skia/include/gpu/GrRect.h b/gfx/skia/skia/src/gpu/GrRect.h similarity index 100% rename from gfx/skia/skia/include/gpu/GrRect.h rename to gfx/skia/skia/src/gpu/GrRect.h diff --git a/gfx/skia/skia/src/gpu/GrResourceCache.h b/gfx/skia/skia/src/gpu/GrResourceCache.h index a495f565b29..adbfb7919ff 100644 --- a/gfx/skia/skia/src/gpu/GrResourceCache.h +++ b/gfx/skia/skia/src/gpu/GrResourceCache.h @@ -60,7 +60,7 @@ public: // purged. Large values disable the feature (as the ring buffer of flush timestamps would be // large). This is currently the default until we decide to enable this feature // of the cache by default. - static const int kDefaultMaxUnusedFlushes = 1024; + static const int kDefaultMaxUnusedFlushes = 64; /** Used to access functionality needed by GrGpuResource for lifetime management. */ class ResourceAccess; diff --git a/gfx/skia/skia/src/gpu/GrResourceProvider.cpp b/gfx/skia/skia/src/gpu/GrResourceProvider.cpp index 38213e62663..19fa1cfbb69 100644 --- a/gfx/skia/skia/src/gpu/GrResourceProvider.cpp +++ b/gfx/skia/skia/src/gpu/GrResourceProvider.cpp @@ -19,7 +19,8 @@ GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); -GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache) : INHERITED(gpu, cache) { +GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner) + : INHERITED(gpu, cache, owner) { GR_DEFINE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); fQuadIndexBufferKey = gQuadIndexBufferKey; } @@ -146,6 +147,16 @@ GrVertexBuffer* GrResourceProvider::createVertexBuffer(size_t size, BufferUsage return this->gpu()->createVertexBuffer(size, dynamic); } +GrTransferBuffer* GrResourceProvider::createTransferBuffer(size_t size, TransferType type, + uint32_t flags) { + if (this->isAbandoned()) { + return nullptr; + } + + //bool noPendingIO = SkToBool(flags & kNoPendingIO_Flag); + return this->gpu()->createTransferBuffer(size, type); +} + GrBatchAtlas* GrResourceProvider::createAtlas(GrPixelConfig config, int width, int height, int numPlotsX, int numPlotsY, diff --git a/gfx/skia/skia/src/gpu/GrResourceProvider.h b/gfx/skia/skia/src/gpu/GrResourceProvider.h index 6c5737191b8..783c7c743b9 100644 --- a/gfx/skia/skia/src/gpu/GrResourceProvider.h +++ b/gfx/skia/skia/src/gpu/GrResourceProvider.h @@ -17,6 +17,7 @@ class GrBatchAtlas; class GrIndexBuffer; class GrPath; class GrRenderTarget; +class GrSingleOwner; class GrStencilAttachment; class GrStrokeInfo; class GrVertexBuffer; @@ -35,7 +36,7 @@ class SkTypeface; */ class GrResourceProvider : protected GrTextureProvider { public: - GrResourceProvider(GrGpu* gpu, GrResourceCache* cache); + GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner); template T* findAndRefTByUniqueKey(const GrUniqueKey& key) { return static_cast(this->findAndRefResourceByUniqueKey(key)); @@ -112,6 +113,7 @@ public: }; GrIndexBuffer* createIndexBuffer(size_t size, BufferUsage, uint32_t flags); GrVertexBuffer* createVertexBuffer(size_t size, BufferUsage, uint32_t flags); + GrTransferBuffer* createTransferBuffer(size_t size, TransferType, uint32_t flags); GrTexture* createApproxTexture(const GrSurfaceDesc& desc, uint32_t flags) { SkASSERT(0 == flags || kNoPendingIO_Flag == flags); diff --git a/gfx/skia/skia/src/gpu/GrSWMaskHelper.cpp b/gfx/skia/skia/src/gpu/GrSWMaskHelper.cpp index 6692e3d8333..34e44952863 100644 --- a/gfx/skia/skia/src/gpu/GrSWMaskHelper.cpp +++ b/gfx/skia/skia/src/gpu/GrSWMaskHelper.cpp @@ -7,17 +7,16 @@ #include "GrSWMaskHelper.h" -#include "GrPipelineBuilder.h" #include "GrCaps.h" #include "GrDrawTarget.h" #include "GrGpu.h" +#include "GrPipelineBuilder.h" #include "SkData.h" #include "SkDistanceFieldGen.h" #include "SkStrokeRec.h" -// TODO: try to remove this #include -#include "GrContext.h" +#include "batches/GrRectBatchFactory.h" namespace { @@ -372,5 +371,7 @@ void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture, GrTextureParams::kNone_FilterMode, kDevice_GrCoordSet))->unref(); - target->drawNonAARect(*pipelineBuilder, color, SkMatrix::I(), dstRect, invert); + SkAutoTUnref batch(GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(), + dstRect, nullptr, &invert)); + target->drawBatch(*pipelineBuilder, batch); } diff --git a/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.cpp b/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.cpp index a136886a640..af77c205b52 100644 --- a/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/GrSoftwarePathRenderer.cpp @@ -10,6 +10,7 @@ #include "GrContext.h" #include "GrSWMaskHelper.h" #include "GrVertexBuffer.h" +#include "batches/GrRectBatchFactory.h" //////////////////////////////////////////////////////////////////////////////// bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { @@ -65,6 +66,17 @@ bool get_path_and_clip_bounds(const GrPipelineBuilder* pipelineBuilder, } //////////////////////////////////////////////////////////////////////////////// +static void draw_non_aa_rect(GrDrawTarget* drawTarget, + const GrPipelineBuilder& pipelineBuilder, + GrColor color, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkMatrix& localMatrix) { + SkAutoTUnref batch(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect, + nullptr, &localMatrix)); + drawTarget->drawBatch(pipelineBuilder, batch); +} + void draw_around_inv_path(GrDrawTarget* target, GrPipelineBuilder* pipelineBuilder, GrColor color, @@ -80,22 +92,22 @@ void draw_around_inv_path(GrDrawTarget* target, if (devClipBounds.fTop < devPathBounds.fTop) { rect.iset(devClipBounds.fLeft, devClipBounds.fTop, devClipBounds.fRight, devPathBounds.fTop); - target->drawNonAARect(*pipelineBuilder, color, SkMatrix::I(), rect, invert); + draw_non_aa_rect(target, *pipelineBuilder, color, SkMatrix::I(), rect, invert); } if (devClipBounds.fLeft < devPathBounds.fLeft) { rect.iset(devClipBounds.fLeft, devPathBounds.fTop, devPathBounds.fLeft, devPathBounds.fBottom); - target->drawNonAARect(*pipelineBuilder, color, SkMatrix::I(), rect, invert); + draw_non_aa_rect(target, *pipelineBuilder, color, SkMatrix::I(), rect, invert); } if (devClipBounds.fRight > devPathBounds.fRight) { rect.iset(devPathBounds.fRight, devPathBounds.fTop, devClipBounds.fRight, devPathBounds.fBottom); - target->drawNonAARect(*pipelineBuilder, color, SkMatrix::I(), rect, invert); + draw_non_aa_rect(target, *pipelineBuilder, color, SkMatrix::I(), rect, invert); } if (devClipBounds.fBottom > devPathBounds.fBottom) { rect.iset(devClipBounds.fLeft, devPathBounds.fBottom, devClipBounds.fRight, devClipBounds.fBottom); - target->drawNonAARect(*pipelineBuilder, color, SkMatrix::I(), rect, invert); + draw_non_aa_rect(target, *pipelineBuilder, color, SkMatrix::I(), rect, invert); } } @@ -104,6 +116,7 @@ void draw_around_inv_path(GrDrawTarget* target, //////////////////////////////////////////////////////////////////////////////// // return true on success; false on failure bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrSoftwarePathRenderer::onDrawPath"); if (nullptr == fContext) { return false; } diff --git a/gfx/skia/skia/src/gpu/GrSwizzle.h b/gfx/skia/skia/src/gpu/GrSwizzle.h new file mode 100644 index 00000000000..48748803ddb --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrSwizzle.h @@ -0,0 +1,136 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSwizzle_DEFINED +#define GrSwizzle_DEFINED + +#include "GrTypes.h" +#include "GrColor.h" + +/** Represents a rgba swizzle. It can be converted either into a string or a eight bit int. + Currently there is no way to specify an arbitrary swizzle, just some static swizzles and an + assignment operator. That could be relaxed. */ +class GrSwizzle { +public: + GrSwizzle() { *this = RGBA(); } + + GrSwizzle(const GrSwizzle& that) { *this = that; } + + GrSwizzle& operator=(const GrSwizzle& that) { + memcpy(this, &that, sizeof(GrSwizzle)); + return *this; + } + + /** Recreates a GrSwizzle from the output of asKey() */ + void setFromKey(uint8_t key) { + fKey = key; + for (int i = 0; i < 4; ++i) { + fSwiz[i] = IdxToChar(key & 3); + key >>= 2; + } + SkASSERT(fSwiz[4] == 0); + } + + bool operator==(const GrSwizzle& that) const { return this->asUInt() == that.asUInt(); } + + bool operator!=(const GrSwizzle& that) const { return !(*this == that); } + + /** Compact representation of the swizzle suitable for a key. */ + uint8_t asKey() const { return fKey; } + + /** 4 char null terminated string consisting only of chars 'r', 'g', 'b', 'a'. */ + const char* c_str() const { return fSwiz; } + + /** Applies this swizzle to the input color and returns the swizzled color. */ + GrColor applyTo(GrColor color) const { + int idx; + uint32_t key = fKey; + // Index of the input color that should be mapped to output r. + idx = (key & 3); + uint32_t outR = (color >> idx * 8) & 0xFF; + key >>= 2; + idx = (key & 3); + uint32_t outG = (color >> idx * 8) & 0xFF; + key >>= 2; + idx = (key & 3); + uint32_t outB = (color >> idx * 8) & 0xFF; + key >>= 2; + idx = (key & 3); + uint32_t outA = (color >> idx * 8) & 0xFF; + return GrColorPackRGBA(outR, outG, outB, outA); + } + + static const GrSwizzle& RGBA() { + static GrSwizzle gRGBA("rgba"); + return gRGBA; + } + + static const GrSwizzle& AAAA() { + static GrSwizzle gAAAA("aaaa"); + return gAAAA; + } + + static const GrSwizzle& RRRR() { + static GrSwizzle gRRRR("rrrr"); + return gRRRR; + } + + static const GrSwizzle& BGRA() { + static GrSwizzle gBGRA("bgra"); + return gBGRA; + } + +private: + char fSwiz[5]; + uint8_t fKey; + + static int CharToIdx(char c) { + switch (c) { + case 'r': + return (GrColor_SHIFT_R / 8); + case 'g': + return (GrColor_SHIFT_G / 8); + case 'b': + return (GrColor_SHIFT_B / 8); + case 'a': + return (GrColor_SHIFT_A / 8); + default: + SkFAIL("Invalid swizzle char"); + return 0; + } + } + + static /* constexpr */ char IToC(int idx) { + return (8*idx) == GrColor_SHIFT_R ? 'r' : + (8*idx) == GrColor_SHIFT_G ? 'g' : + (8*idx) == GrColor_SHIFT_B ? 'b' : 'a'; + } + + static char IdxToChar(int c) { + // Hopefully this array gets computed at compile time. + static const char gStr[4] = { IToC(0), IToC(1), IToC(2), IToC(3) }; + return gStr[c]; + } + + explicit GrSwizzle(const char* str) { + SkASSERT(strlen(str) == 4); + fSwiz[0] = str[0]; + fSwiz[1] = str[1]; + fSwiz[2] = str[2]; + fSwiz[3] = str[3]; + fSwiz[4] = 0; + fKey = SkToU8(CharToIdx(fSwiz[0]) | (CharToIdx(fSwiz[1]) << 2) | + (CharToIdx(fSwiz[2]) << 4) | (CharToIdx(fSwiz[3]) << 6)); + } + + uint32_t* asUIntPtr() { return SkTCast(fSwiz); } + uint32_t asUInt() const { return *SkTCast(fSwiz); } + + GR_STATIC_ASSERT(sizeof(char[4]) == sizeof(uint32_t)); +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrTessellator.cpp b/gfx/skia/skia/src/gpu/GrTessellator.cpp new file mode 100644 index 00000000000..ea130cf15fe --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTessellator.cpp @@ -0,0 +1,1470 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrTessellator.h" + +#include "GrBatchFlushState.h" +#include "GrBatchTest.h" +#include "GrDefaultGeoProcFactory.h" +#include "GrPathUtils.h" +#include "GrVertices.h" +#include "GrResourceCache.h" +#include "GrResourceProvider.h" +#include "SkGeometry.h" +#include "SkChunkAlloc.h" + +#include "batches/GrVertexBatch.h" + +#include + +/* + * There are six stages to the algorithm: + * + * 1) Linearize the path contours into piecewise linear segments (path_to_contours()). + * 2) Build a mesh of edges connecting the vertices (build_edges()). + * 3) Sort the vertices in Y (and secondarily in X) (merge_sort()). + * 4) Simplify the mesh by inserting new vertices at intersecting edges (simplify()). + * 5) Tessellate the simplified mesh into monotone polygons (tessellate()). + * 6) Triangulate the monotone polygons directly into a vertex buffer (polys_to_triangles()). + * + * The vertex sorting in step (3) is a merge sort, since it plays well with the linked list + * of vertices (and the necessity of inserting new vertices on intersection). + * + * Stages (4) and (5) use an active edge list, which a list of all edges for which the + * sweep line has crossed the top vertex, but not the bottom vertex. It's sorted + * left-to-right based on the point where both edges are active (when both top vertices + * have been seen, so the "lower" top vertex of the two). If the top vertices are equal + * (shared), it's sorted based on the last point where both edges are active, so the + * "upper" bottom vertex. + * + * The most complex step is the simplification (4). It's based on the Bentley-Ottman + * line-sweep algorithm, but due to floating point inaccuracy, the intersection points are + * not exact and may violate the mesh topology or active edge list ordering. We + * accommodate this by adjusting the topology of the mesh and AEL to match the intersection + * points. This occurs in three ways: + * + * A) Intersections may cause a shortened edge to no longer be ordered with respect to its + * neighbouring edges at the top or bottom vertex. This is handled by merging the + * edges (merge_collinear_edges()). + * B) Intersections may cause an edge to violate the left-to-right ordering of the + * active edge list. This is handled by splitting the neighbour edge on the + * intersected vertex (cleanup_active_edges()). + * C) Shortening an edge may cause an active edge to become inactive or an inactive edge + * to become active. This is handled by removing or inserting the edge in the active + * edge list (fix_active_state()). + * + * The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and + * Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it + * currently uses a linked list for the active edge list, rather than a 2-3 tree as the + * paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also + * become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N) + * insertions and removals was greater than the cost of infrequent O(N) lookups with the + * linked list implementation. With the latter, all removals are O(1), and most insertions + * are O(1), since we know the adjacent edge in the active edge list based on the topology. + * Only type 2 vertices (see paper) require the O(N) lookups, and these are much less + * frequent. There may be other data structures worth investigating, however. + * + * Note that the orientation of the line sweep algorithms is determined by the aspect ratio of the + * path bounds. When the path is taller than it is wide, we sort vertices based on increasing Y + * coordinate, and secondarily by increasing X coordinate. When the path is wider than it is tall, + * we sort by increasing X coordinate, but secondarily by *decreasing* Y coordinate. This is so + * that the "left" and "right" orientation in the code remains correct (edges to the left are + * increasing in Y; edges to the right are decreasing in Y). That is, the setting rotates 90 + * degrees counterclockwise, rather that transposing. + */ + +#define LOGGING_ENABLED 0 + +#if LOGGING_ENABLED +#define LOG printf +#else +#define LOG(...) +#endif + +#define ALLOC_NEW(Type, args, alloc) new (alloc.allocThrow(sizeof(Type))) Type args + +namespace { + +struct Vertex; +struct Edge; +struct Poly; + +template +void insert(T* t, T* prev, T* next, T** head, T** tail) { + t->*Prev = prev; + t->*Next = next; + if (prev) { + prev->*Next = t; + } else if (head) { + *head = t; + } + if (next) { + next->*Prev = t; + } else if (tail) { + *tail = t; + } +} + +template +void remove(T* t, T** head, T** tail) { + if (t->*Prev) { + t->*Prev->*Next = t->*Next; + } else if (head) { + *head = t->*Next; + } + if (t->*Next) { + t->*Next->*Prev = t->*Prev; + } else if (tail) { + *tail = t->*Prev; + } + t->*Prev = t->*Next = nullptr; +} + +/** + * Vertices are used in three ways: first, the path contours are converted into a + * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices + * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing + * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid + * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of + * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since + * an individual Vertex from the path mesh may belong to multiple + * MonotonePolys, so the original Vertices cannot be re-used. + */ + +struct Vertex { + Vertex(const SkPoint& point) + : fPoint(point), fPrev(nullptr), fNext(nullptr) + , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr) + , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr) + , fProcessed(false) +#if LOGGING_ENABLED + , fID (-1.0f) +#endif + {} + SkPoint fPoint; // Vertex position + Vertex* fPrev; // Linked list of contours, then Y-sorted vertices. + Vertex* fNext; // " + Edge* fFirstEdgeAbove; // Linked list of edges above this vertex. + Edge* fLastEdgeAbove; // " + Edge* fFirstEdgeBelow; // Linked list of edges below this vertex. + Edge* fLastEdgeBelow; // " + bool fProcessed; // Has this vertex been seen in simplify()? +#if LOGGING_ENABLED + float fID; // Identifier used for logging. +#endif +}; + +/***************************************************************************************/ + +typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b); + +struct Comparator { + CompareFunc sweep_lt; + CompareFunc sweep_gt; +}; + +bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) { + return a.fX == b.fX ? a.fY > b.fY : a.fX < b.fX; +} + +bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) { + return a.fY == b.fY ? a.fX < b.fX : a.fY < b.fY; +} + +bool sweep_gt_horiz(const SkPoint& a, const SkPoint& b) { + return a.fX == b.fX ? a.fY < b.fY : a.fX > b.fX; +} + +bool sweep_gt_vert(const SkPoint& a, const SkPoint& b) { + return a.fY == b.fY ? a.fX > b.fX : a.fY > b.fY; +} + +inline SkPoint* emit_vertex(Vertex* v, SkPoint* data) { + *data++ = v->fPoint; + return data; +} + +SkPoint* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, SkPoint* data) { +#if WIREFRAME + data = emit_vertex(v0, data); + data = emit_vertex(v1, data); + data = emit_vertex(v1, data); + data = emit_vertex(v2, data); + data = emit_vertex(v2, data); + data = emit_vertex(v0, data); +#else + data = emit_vertex(v0, data); + data = emit_vertex(v1, data); + data = emit_vertex(v2, data); +#endif + return data; +} + +struct EdgeList { + EdgeList() : fHead(nullptr), fTail(nullptr) {} + Edge* fHead; + Edge* fTail; +}; + +/** + * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and + * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf(). + * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating + * point). For speed, that case is only tested by the callers which require it (e.g., + * cleanup_active_edges()). Edges also handle checking for intersection with other edges. + * Currently, this converts the edges to the parametric form, in order to avoid doing a division + * until an intersection has been confirmed. This is slightly slower in the "found" case, but + * a lot faster in the "not found" case. + * + * The coefficients of the line equation stored in double precision to avoid catastrphic + * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is + * correct in float, since it's a polynomial of degree 2. The intersect() function, being + * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its + * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of + * this file). + */ + +struct Edge { + Edge(Vertex* top, Vertex* bottom, int winding) + : fWinding(winding) + , fTop(top) + , fBottom(bottom) + , fLeft(nullptr) + , fRight(nullptr) + , fPrevEdgeAbove(nullptr) + , fNextEdgeAbove(nullptr) + , fPrevEdgeBelow(nullptr) + , fNextEdgeBelow(nullptr) + , fLeftPoly(nullptr) + , fRightPoly(nullptr) { + recompute(); + } + int fWinding; // 1 == edge goes downward; -1 = edge goes upward. + Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt). + Vertex* fBottom; // The bottom vertex in vertex-sort-order. + Edge* fLeft; // The linked list of edges in the active edge list. + Edge* fRight; // " + Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above". + Edge* fNextEdgeAbove; // " + Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below". + Edge* fNextEdgeBelow; // " + Poly* fLeftPoly; // The Poly to the left of this edge, if any. + Poly* fRightPoly; // The Poly to the right of this edge, if any. + double fDX; // The line equation for this edge, in implicit form. + double fDY; // fDY * x + fDX * y + fC = 0, for point (x, y) on the line. + double fC; + double dist(const SkPoint& p) const { + return fDY * p.fX - fDX * p.fY + fC; + } + bool isRightOf(Vertex* v) const { + return dist(v->fPoint) < 0.0; + } + bool isLeftOf(Vertex* v) const { + return dist(v->fPoint) > 0.0; + } + void recompute() { + fDX = static_cast(fBottom->fPoint.fX) - fTop->fPoint.fX; + fDY = static_cast(fBottom->fPoint.fY) - fTop->fPoint.fY; + fC = static_cast(fTop->fPoint.fY) * fBottom->fPoint.fX - + static_cast(fTop->fPoint.fX) * fBottom->fPoint.fY; + } + bool intersect(const Edge& other, SkPoint* p) { + LOG("intersecting %g -> %g with %g -> %g\n", + fTop->fID, fBottom->fID, + other.fTop->fID, other.fBottom->fID); + if (fTop == other.fTop || fBottom == other.fBottom) { + return false; + } + double denom = fDX * other.fDY - fDY * other.fDX; + if (denom == 0.0) { + return false; + } + double dx = static_cast(fTop->fPoint.fX) - other.fTop->fPoint.fX; + double dy = static_cast(fTop->fPoint.fY) - other.fTop->fPoint.fY; + double sNumer = dy * other.fDX - dx * other.fDY; + double tNumer = dy * fDX - dx * fDY; + // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early. + // This saves us doing the divide below unless absolutely necessary. + if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom) + : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) { + return false; + } + double s = sNumer / denom; + SkASSERT(s >= 0.0 && s <= 1.0); + p->fX = SkDoubleToScalar(fTop->fPoint.fX + s * fDX); + p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fDY); + return true; + } + bool isActive(EdgeList* activeEdges) const { + return activeEdges && (fLeft || fRight || activeEdges->fHead == this); + } +}; + +/***************************************************************************************/ + +struct Poly { + Poly(int winding) + : fWinding(winding) + , fHead(nullptr) + , fTail(nullptr) + , fActive(nullptr) + , fNext(nullptr) + , fPartner(nullptr) + , fCount(0) + { +#if LOGGING_ENABLED + static int gID = 0; + fID = gID++; + LOG("*** created Poly %d\n", fID); +#endif + } + typedef enum { kNeither_Side, kLeft_Side, kRight_Side } Side; + struct MonotonePoly { + MonotonePoly() + : fSide(kNeither_Side) + , fHead(nullptr) + , fTail(nullptr) + , fPrev(nullptr) + , fNext(nullptr) {} + Side fSide; + Vertex* fHead; + Vertex* fTail; + MonotonePoly* fPrev; + MonotonePoly* fNext; + bool addVertex(Vertex* v, Side side, SkChunkAlloc& alloc) { + Vertex* newV = ALLOC_NEW(Vertex, (v->fPoint), alloc); + bool done = false; + if (fSide == kNeither_Side) { + fSide = side; + } else { + done = side != fSide; + } + if (fHead == nullptr) { + fHead = fTail = newV; + } else if (fSide == kRight_Side) { + newV->fPrev = fTail; + fTail->fNext = newV; + fTail = newV; + } else { + newV->fNext = fHead; + fHead->fPrev = newV; + fHead = newV; + } + return done; + } + + SkPoint* emit(SkPoint* data) { + Vertex* first = fHead; + Vertex* v = first->fNext; + while (v != fTail) { + SkASSERT(v && v->fPrev && v->fNext); + Vertex* prev = v->fPrev; + Vertex* curr = v; + Vertex* next = v->fNext; + double ax = static_cast(curr->fPoint.fX) - prev->fPoint.fX; + double ay = static_cast(curr->fPoint.fY) - prev->fPoint.fY; + double bx = static_cast(next->fPoint.fX) - curr->fPoint.fX; + double by = static_cast(next->fPoint.fY) - curr->fPoint.fY; + if (ax * by - ay * bx >= 0.0) { + data = emit_triangle(prev, curr, next, data); + v->fPrev->fNext = v->fNext; + v->fNext->fPrev = v->fPrev; + if (v->fPrev == first) { + v = v->fNext; + } else { + v = v->fPrev; + } + } else { + v = v->fNext; + } + } + return data; + } + }; + Poly* addVertex(Vertex* v, Side side, SkChunkAlloc& alloc) { + LOG("addVertex() to %d at %g (%g, %g), %s side\n", fID, v->fID, v->fPoint.fX, v->fPoint.fY, + side == kLeft_Side ? "left" : side == kRight_Side ? "right" : "neither"); + Poly* partner = fPartner; + Poly* poly = this; + if (partner) { + fPartner = partner->fPartner = nullptr; + } + if (!fActive) { + fActive = ALLOC_NEW(MonotonePoly, (), alloc); + } + if (fActive->addVertex(v, side, alloc)) { + if (fTail) { + fActive->fPrev = fTail; + fTail->fNext = fActive; + fTail = fActive; + } else { + fHead = fTail = fActive; + } + if (partner) { + partner->addVertex(v, side, alloc); + poly = partner; + } else { + Vertex* prev = fActive->fSide == Poly::kLeft_Side ? + fActive->fHead->fNext : fActive->fTail->fPrev; + fActive = ALLOC_NEW(MonotonePoly, , alloc); + fActive->addVertex(prev, Poly::kNeither_Side, alloc); + fActive->addVertex(v, side, alloc); + } + } + fCount++; + return poly; + } + void end(Vertex* v, SkChunkAlloc& alloc) { + LOG("end() %d at %g, %g\n", fID, v->fPoint.fX, v->fPoint.fY); + if (fPartner) { + fPartner = fPartner->fPartner = nullptr; + } + addVertex(v, fActive->fSide == kLeft_Side ? kRight_Side : kLeft_Side, alloc); + } + SkPoint* emit(SkPoint *data) { + if (fCount < 3) { + return data; + } + LOG("emit() %d, size %d\n", fID, fCount); + for (MonotonePoly* m = fHead; m != nullptr; m = m->fNext) { + data = m->emit(data); + } + return data; + } + int fWinding; + MonotonePoly* fHead; + MonotonePoly* fTail; + MonotonePoly* fActive; + Poly* fNext; + Poly* fPartner; + int fCount; +#if LOGGING_ENABLED + int fID; +#endif +}; + +/***************************************************************************************/ + +bool coincident(const SkPoint& a, const SkPoint& b) { + return a == b; +} + +Poly* new_poly(Poly** head, Vertex* v, int winding, SkChunkAlloc& alloc) { + Poly* poly = ALLOC_NEW(Poly, (winding), alloc); + poly->addVertex(v, Poly::kNeither_Side, alloc); + poly->fNext = *head; + *head = poly; + return poly; +} + +Vertex* append_point_to_contour(const SkPoint& p, Vertex* prev, Vertex** head, + SkChunkAlloc& alloc) { + Vertex* v = ALLOC_NEW(Vertex, (p), alloc); +#if LOGGING_ENABLED + static float gID = 0.0f; + v->fID = gID++; +#endif + if (prev) { + prev->fNext = v; + v->fPrev = prev; + } else { + *head = v; + } + return v; +} + +Vertex* generate_quadratic_points(const SkPoint& p0, + const SkPoint& p1, + const SkPoint& p2, + SkScalar tolSqd, + Vertex* prev, + Vertex** head, + int pointsLeft, + SkChunkAlloc& alloc) { + SkScalar d = p1.distanceToLineSegmentBetweenSqd(p0, p2); + if (pointsLeft < 2 || d < tolSqd || !SkScalarIsFinite(d)) { + return append_point_to_contour(p2, prev, head, alloc); + } + + const SkPoint q[] = { + { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, + { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) }, + }; + const SkPoint r = { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) }; + + pointsLeft >>= 1; + prev = generate_quadratic_points(p0, q[0], r, tolSqd, prev, head, pointsLeft, alloc); + prev = generate_quadratic_points(r, q[1], p2, tolSqd, prev, head, pointsLeft, alloc); + return prev; +} + +Vertex* generate_cubic_points(const SkPoint& p0, + const SkPoint& p1, + const SkPoint& p2, + const SkPoint& p3, + SkScalar tolSqd, + Vertex* prev, + Vertex** head, + int pointsLeft, + SkChunkAlloc& alloc) { + SkScalar d1 = p1.distanceToLineSegmentBetweenSqd(p0, p3); + SkScalar d2 = p2.distanceToLineSegmentBetweenSqd(p0, p3); + if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) || + !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) { + return append_point_to_contour(p3, prev, head, alloc); + } + const SkPoint q[] = { + { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, + { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) }, + { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) } + }; + const SkPoint r[] = { + { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) }, + { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) } + }; + const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) }; + pointsLeft >>= 1; + prev = generate_cubic_points(p0, q[0], r[0], s, tolSqd, prev, head, pointsLeft, alloc); + prev = generate_cubic_points(s, r[1], q[2], p3, tolSqd, prev, head, pointsLeft, alloc); + return prev; +} + +// Stage 1: convert the input path to a set of linear contours (linked list of Vertices). + +void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, + Vertex** contours, SkChunkAlloc& alloc, bool *isLinear) { + SkScalar toleranceSqd = tolerance * tolerance; + + SkPoint pts[4]; + bool done = false; + *isLinear = true; + SkPath::Iter iter(path, false); + Vertex* prev = nullptr; + Vertex* head = nullptr; + if (path.isInverseFillType()) { + SkPoint quad[4]; + clipBounds.toQuad(quad); + for (int i = 3; i >= 0; i--) { + prev = append_point_to_contour(quad[i], prev, &head, alloc); + } + head->fPrev = prev; + prev->fNext = head; + *contours++ = head; + head = prev = nullptr; + } + SkAutoConicToQuads converter; + while (!done) { + SkPath::Verb verb = iter.next(pts); + switch (verb) { + case SkPath::kConic_Verb: { + SkScalar weight = iter.conicWeight(); + const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd); + for (int i = 0; i < converter.countQuads(); ++i) { + int pointsLeft = GrPathUtils::quadraticPointCount(quadPts, tolerance); + prev = generate_quadratic_points(quadPts[0], quadPts[1], quadPts[2], + toleranceSqd, prev, &head, pointsLeft, alloc); + quadPts += 2; + } + *isLinear = false; + break; + } + case SkPath::kMove_Verb: + if (head) { + head->fPrev = prev; + prev->fNext = head; + *contours++ = head; + } + head = prev = nullptr; + prev = append_point_to_contour(pts[0], prev, &head, alloc); + break; + case SkPath::kLine_Verb: { + prev = append_point_to_contour(pts[1], prev, &head, alloc); + break; + } + case SkPath::kQuad_Verb: { + int pointsLeft = GrPathUtils::quadraticPointCount(pts, tolerance); + prev = generate_quadratic_points(pts[0], pts[1], pts[2], toleranceSqd, prev, + &head, pointsLeft, alloc); + *isLinear = false; + break; + } + case SkPath::kCubic_Verb: { + int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); + prev = generate_cubic_points(pts[0], pts[1], pts[2], pts[3], + toleranceSqd, prev, &head, pointsLeft, alloc); + *isLinear = false; + break; + } + case SkPath::kClose_Verb: + if (head) { + head->fPrev = prev; + prev->fNext = head; + *contours++ = head; + } + head = prev = nullptr; + break; + case SkPath::kDone_Verb: + if (head) { + head->fPrev = prev; + prev->fNext = head; + *contours++ = head; + } + done = true; + break; + } + } +} + +inline bool apply_fill_type(SkPath::FillType fillType, int winding) { + switch (fillType) { + case SkPath::kWinding_FillType: + return winding != 0; + case SkPath::kEvenOdd_FillType: + return (winding & 1) != 0; + case SkPath::kInverseWinding_FillType: + return winding == 1; + case SkPath::kInverseEvenOdd_FillType: + return (winding & 1) == 1; + default: + SkASSERT(false); + return false; + } +} + +Edge* new_edge(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator& c) { + int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; + Vertex* top = winding < 0 ? next : prev; + Vertex* bottom = winding < 0 ? prev : next; + return ALLOC_NEW(Edge, (top, bottom, winding), alloc); +} + +void remove_edge(Edge* edge, EdgeList* edges) { + LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID); + SkASSERT(edge->isActive(edges)); + remove(edge, &edges->fHead, &edges->fTail); +} + +void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) { + LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID); + SkASSERT(!edge->isActive(edges)); + Edge* next = prev ? prev->fRight : edges->fHead; + insert(edge, prev, next, &edges->fHead, &edges->fTail); +} + +void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) { + if (v->fFirstEdgeAbove) { + *left = v->fFirstEdgeAbove->fLeft; + *right = v->fLastEdgeAbove->fRight; + return; + } + Edge* next = nullptr; + Edge* prev; + for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) { + if (prev->isLeftOf(v)) { + break; + } + next = prev; + } + *left = prev; + *right = next; + return; +} + +void find_enclosing_edges(Edge* edge, EdgeList* edges, Comparator& c, Edge** left, Edge** right) { + Edge* prev = nullptr; + Edge* next; + for (next = edges->fHead; next != nullptr; next = next->fRight) { + if ((c.sweep_gt(edge->fTop->fPoint, next->fTop->fPoint) && next->isRightOf(edge->fTop)) || + (c.sweep_gt(next->fTop->fPoint, edge->fTop->fPoint) && edge->isLeftOf(next->fTop)) || + (c.sweep_lt(edge->fBottom->fPoint, next->fBottom->fPoint) && + next->isRightOf(edge->fBottom)) || + (c.sweep_lt(next->fBottom->fPoint, edge->fBottom->fPoint) && + edge->isLeftOf(next->fBottom))) { + break; + } + prev = next; + } + *left = prev; + *right = next; + return; +} + +void fix_active_state(Edge* edge, EdgeList* activeEdges, Comparator& c) { + if (edge->isActive(activeEdges)) { + if (edge->fBottom->fProcessed || !edge->fTop->fProcessed) { + remove_edge(edge, activeEdges); + } + } else if (edge->fTop->fProcessed && !edge->fBottom->fProcessed) { + Edge* left; + Edge* right; + find_enclosing_edges(edge, activeEdges, c, &left, &right); + insert_edge(edge, left, activeEdges); + } +} + +void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) { + if (edge->fTop->fPoint == edge->fBottom->fPoint || + c.sweep_gt(edge->fTop->fPoint, edge->fBottom->fPoint)) { + return; + } + LOG("insert edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID); + Edge* prev = nullptr; + Edge* next; + for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) { + if (next->isRightOf(edge->fTop)) { + break; + } + prev = next; + } + insert( + edge, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove); +} + +void insert_edge_below(Edge* edge, Vertex* v, Comparator& c) { + if (edge->fTop->fPoint == edge->fBottom->fPoint || + c.sweep_gt(edge->fTop->fPoint, edge->fBottom->fPoint)) { + return; + } + LOG("insert edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID); + Edge* prev = nullptr; + Edge* next; + for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) { + if (next->isRightOf(edge->fBottom)) { + break; + } + prev = next; + } + insert( + edge, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow); +} + +void remove_edge_above(Edge* edge) { + LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID, + edge->fBottom->fID); + remove( + edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove); +} + +void remove_edge_below(Edge* edge) { + LOG("removing edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID, + edge->fTop->fID); + remove( + edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow); +} + +void erase_edge_if_zero_winding(Edge* edge, EdgeList* edges) { + if (edge->fWinding != 0) { + return; + } + LOG("erasing edge (%g -> %g)\n", edge->fTop->fID, edge->fBottom->fID); + remove_edge_above(edge); + remove_edge_below(edge); + if (edge->isActive(edges)) { + remove_edge(edge, edges); + } +} + +void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c); + +void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c) { + remove_edge_below(edge); + edge->fTop = v; + edge->recompute(); + insert_edge_below(edge, v, c); + fix_active_state(edge, activeEdges, c); + merge_collinear_edges(edge, activeEdges, c); +} + +void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c) { + remove_edge_above(edge); + edge->fBottom = v; + edge->recompute(); + insert_edge_above(edge, v, c); + fix_active_state(edge, activeEdges, c); + merge_collinear_edges(edge, activeEdges, c); +} + +void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c) { + if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) { + LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n", + edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, + edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); + other->fWinding += edge->fWinding; + erase_edge_if_zero_winding(other, activeEdges); + edge->fWinding = 0; + erase_edge_if_zero_winding(edge, activeEdges); + } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) { + other->fWinding += edge->fWinding; + erase_edge_if_zero_winding(other, activeEdges); + set_bottom(edge, other->fTop, activeEdges, c); + } else { + edge->fWinding += other->fWinding; + erase_edge_if_zero_winding(edge, activeEdges); + set_bottom(other, edge->fTop, activeEdges, c); + } +} + +void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c) { + if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) { + LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n", + edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, + edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); + other->fWinding += edge->fWinding; + erase_edge_if_zero_winding(other, activeEdges); + edge->fWinding = 0; + erase_edge_if_zero_winding(edge, activeEdges); + } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) { + edge->fWinding += other->fWinding; + erase_edge_if_zero_winding(edge, activeEdges); + set_top(other, edge->fBottom, activeEdges, c); + } else { + other->fWinding += edge->fWinding; + erase_edge_if_zero_winding(other, activeEdges); + set_top(edge, other->fBottom, activeEdges, c); + } +} + +void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c) { + if (edge->fPrevEdgeAbove && (edge->fTop == edge->fPrevEdgeAbove->fTop || + !edge->fPrevEdgeAbove->isLeftOf(edge->fTop))) { + merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, c); + } else if (edge->fNextEdgeAbove && (edge->fTop == edge->fNextEdgeAbove->fTop || + !edge->isLeftOf(edge->fNextEdgeAbove->fTop))) { + merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, c); + } + if (edge->fPrevEdgeBelow && (edge->fBottom == edge->fPrevEdgeBelow->fBottom || + !edge->fPrevEdgeBelow->isLeftOf(edge->fBottom))) { + merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, c); + } else if (edge->fNextEdgeBelow && (edge->fBottom == edge->fNextEdgeBelow->fBottom || + !edge->isLeftOf(edge->fNextEdgeBelow->fBottom))) { + merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, c); + } +} + +void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkChunkAlloc& alloc); + +void cleanup_active_edges(Edge* edge, EdgeList* activeEdges, Comparator& c, SkChunkAlloc& alloc) { + Vertex* top = edge->fTop; + Vertex* bottom = edge->fBottom; + if (edge->fLeft) { + Vertex* leftTop = edge->fLeft->fTop; + Vertex* leftBottom = edge->fLeft->fBottom; + if (c.sweep_gt(top->fPoint, leftTop->fPoint) && !edge->fLeft->isLeftOf(top)) { + split_edge(edge->fLeft, edge->fTop, activeEdges, c, alloc); + } else if (c.sweep_gt(leftTop->fPoint, top->fPoint) && !edge->isRightOf(leftTop)) { + split_edge(edge, leftTop, activeEdges, c, alloc); + } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) && + !edge->fLeft->isLeftOf(bottom)) { + split_edge(edge->fLeft, bottom, activeEdges, c, alloc); + } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) { + split_edge(edge, leftBottom, activeEdges, c, alloc); + } + } + if (edge->fRight) { + Vertex* rightTop = edge->fRight->fTop; + Vertex* rightBottom = edge->fRight->fBottom; + if (c.sweep_gt(top->fPoint, rightTop->fPoint) && !edge->fRight->isRightOf(top)) { + split_edge(edge->fRight, top, activeEdges, c, alloc); + } else if (c.sweep_gt(rightTop->fPoint, top->fPoint) && !edge->isLeftOf(rightTop)) { + split_edge(edge, rightTop, activeEdges, c, alloc); + } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) && + !edge->fRight->isRightOf(bottom)) { + split_edge(edge->fRight, bottom, activeEdges, c, alloc); + } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) && + !edge->isLeftOf(rightBottom)) { + split_edge(edge, rightBottom, activeEdges, c, alloc); + } + } +} + +void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkChunkAlloc& alloc) { + LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n", + edge->fTop->fID, edge->fBottom->fID, + v->fID, v->fPoint.fX, v->fPoint.fY); + if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) { + set_top(edge, v, activeEdges, c); + } else if (c.sweep_gt(v->fPoint, edge->fBottom->fPoint)) { + set_bottom(edge, v, activeEdges, c); + } else { + Edge* newEdge = ALLOC_NEW(Edge, (v, edge->fBottom, edge->fWinding), alloc); + insert_edge_below(newEdge, v, c); + insert_edge_above(newEdge, edge->fBottom, c); + set_bottom(edge, v, activeEdges, c); + cleanup_active_edges(edge, activeEdges, c, alloc); + fix_active_state(newEdge, activeEdges, c); + merge_collinear_edges(newEdge, activeEdges, c); + } +} + +void merge_vertices(Vertex* src, Vertex* dst, Vertex** head, Comparator& c, SkChunkAlloc& alloc) { + LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX, src->fPoint.fY, + src->fID, dst->fID); + for (Edge* edge = src->fFirstEdgeAbove; edge;) { + Edge* next = edge->fNextEdgeAbove; + set_bottom(edge, dst, nullptr, c); + edge = next; + } + for (Edge* edge = src->fFirstEdgeBelow; edge;) { + Edge* next = edge->fNextEdgeBelow; + set_top(edge, dst, nullptr, c); + edge = next; + } + remove(src, head, nullptr); +} + +Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c, + SkChunkAlloc& alloc) { + SkPoint p; + if (!edge || !other) { + return nullptr; + } + if (edge->intersect(*other, &p)) { + Vertex* v; + LOG("found intersection, pt is %g, %g\n", p.fX, p.fY); + if (p == edge->fTop->fPoint || c.sweep_lt(p, edge->fTop->fPoint)) { + split_edge(other, edge->fTop, activeEdges, c, alloc); + v = edge->fTop; + } else if (p == edge->fBottom->fPoint || c.sweep_gt(p, edge->fBottom->fPoint)) { + split_edge(other, edge->fBottom, activeEdges, c, alloc); + v = edge->fBottom; + } else if (p == other->fTop->fPoint || c.sweep_lt(p, other->fTop->fPoint)) { + split_edge(edge, other->fTop, activeEdges, c, alloc); + v = other->fTop; + } else if (p == other->fBottom->fPoint || c.sweep_gt(p, other->fBottom->fPoint)) { + split_edge(edge, other->fBottom, activeEdges, c, alloc); + v = other->fBottom; + } else { + Vertex* nextV = edge->fTop; + while (c.sweep_lt(p, nextV->fPoint)) { + nextV = nextV->fPrev; + } + while (c.sweep_lt(nextV->fPoint, p)) { + nextV = nextV->fNext; + } + Vertex* prevV = nextV->fPrev; + if (coincident(prevV->fPoint, p)) { + v = prevV; + } else if (coincident(nextV->fPoint, p)) { + v = nextV; + } else { + v = ALLOC_NEW(Vertex, (p), alloc); + LOG("inserting between %g (%g, %g) and %g (%g, %g)\n", + prevV->fID, prevV->fPoint.fX, prevV->fPoint.fY, + nextV->fID, nextV->fPoint.fX, nextV->fPoint.fY); +#if LOGGING_ENABLED + v->fID = (nextV->fID + prevV->fID) * 0.5f; +#endif + v->fPrev = prevV; + v->fNext = nextV; + prevV->fNext = v; + nextV->fPrev = v; + } + split_edge(edge, v, activeEdges, c, alloc); + split_edge(other, v, activeEdges, c, alloc); + } + return v; + } + return nullptr; +} + +void sanitize_contours(Vertex** contours, int contourCnt) { + for (int i = 0; i < contourCnt; ++i) { + SkASSERT(contours[i]); + for (Vertex* v = contours[i];;) { + if (coincident(v->fPrev->fPoint, v->fPoint)) { + LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY); + if (v->fPrev == v) { + contours[i] = nullptr; + break; + } + v->fPrev->fNext = v->fNext; + v->fNext->fPrev = v->fPrev; + if (contours[i] == v) { + contours[i] = v->fNext; + } + v = v->fPrev; + } else { + v = v->fNext; + if (v == contours[i]) break; + } + } + } +} + +void merge_coincident_vertices(Vertex** vertices, Comparator& c, SkChunkAlloc& alloc) { + for (Vertex* v = (*vertices)->fNext; v != nullptr; v = v->fNext) { + if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) { + v->fPoint = v->fPrev->fPoint; + } + if (coincident(v->fPrev->fPoint, v->fPoint)) { + merge_vertices(v->fPrev, v, vertices, c, alloc); + } + } +} + +// Stage 2: convert the contours to a mesh of edges connecting the vertices. + +Vertex* build_edges(Vertex** contours, int contourCnt, Comparator& c, SkChunkAlloc& alloc) { + Vertex* vertices = nullptr; + Vertex* prev = nullptr; + for (int i = 0; i < contourCnt; ++i) { + for (Vertex* v = contours[i]; v != nullptr;) { + Vertex* vNext = v->fNext; + Edge* edge = new_edge(v->fPrev, v, alloc, c); + if (edge->fWinding > 0) { + insert_edge_below(edge, v->fPrev, c); + insert_edge_above(edge, v, c); + } else { + insert_edge_below(edge, v, c); + insert_edge_above(edge, v->fPrev, c); + } + merge_collinear_edges(edge, nullptr, c); + if (prev) { + prev->fNext = v; + v->fPrev = prev; + } else { + vertices = v; + } + prev = v; + v = vNext; + if (v == contours[i]) break; + } + } + if (prev) { + prev->fNext = vertices->fPrev = nullptr; + } + return vertices; +} + +// Stage 3: sort the vertices by increasing sweep direction. + +Vertex* sorted_merge(Vertex* a, Vertex* b, Comparator& c); + +void front_back_split(Vertex* v, Vertex** pFront, Vertex** pBack) { + Vertex* fast; + Vertex* slow; + if (!v || !v->fNext) { + *pFront = v; + *pBack = nullptr; + } else { + slow = v; + fast = v->fNext; + + while (fast != nullptr) { + fast = fast->fNext; + if (fast != nullptr) { + slow = slow->fNext; + fast = fast->fNext; + } + } + + *pFront = v; + *pBack = slow->fNext; + slow->fNext->fPrev = nullptr; + slow->fNext = nullptr; + } +} + +void merge_sort(Vertex** head, Comparator& c) { + if (!*head || !(*head)->fNext) { + return; + } + + Vertex* a; + Vertex* b; + front_back_split(*head, &a, &b); + + merge_sort(&a, c); + merge_sort(&b, c); + + *head = sorted_merge(a, b, c); +} + +inline void append_vertex(Vertex* v, Vertex** head, Vertex** tail) { + insert(v, *tail, nullptr, head, tail); +} + +inline void append_vertex_list(Vertex* v, Vertex** head, Vertex** tail) { + insert(v, *tail, v->fNext, head, tail); +} + +Vertex* sorted_merge(Vertex* a, Vertex* b, Comparator& c) { + Vertex* head = nullptr; + Vertex* tail = nullptr; + + while (a && b) { + if (c.sweep_lt(a->fPoint, b->fPoint)) { + Vertex* next = a->fNext; + append_vertex(a, &head, &tail); + a = next; + } else { + Vertex* next = b->fNext; + append_vertex(b, &head, &tail); + b = next; + } + } + if (a) { + append_vertex_list(a, &head, &tail); + } + if (b) { + append_vertex_list(b, &head, &tail); + } + return head; +} + +// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges. + +void simplify(Vertex* vertices, Comparator& c, SkChunkAlloc& alloc) { + LOG("simplifying complex polygons\n"); + EdgeList activeEdges; + for (Vertex* v = vertices; v != nullptr; v = v->fNext) { + if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) { + continue; + } +#if LOGGING_ENABLED + LOG("\nvertex %g: (%g,%g)\n", v->fID, v->fPoint.fX, v->fPoint.fY); +#endif + Edge* leftEnclosingEdge = nullptr; + Edge* rightEnclosingEdge = nullptr; + bool restartChecks; + do { + restartChecks = false; + find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); + if (v->fFirstEdgeBelow) { + for (Edge* edge = v->fFirstEdgeBelow; edge != nullptr; edge = edge->fNextEdgeBelow) { + if (check_for_intersection(edge, leftEnclosingEdge, &activeEdges, c, alloc)) { + restartChecks = true; + break; + } + if (check_for_intersection(edge, rightEnclosingEdge, &activeEdges, c, alloc)) { + restartChecks = true; + break; + } + } + } else { + if (Vertex* pv = check_for_intersection(leftEnclosingEdge, rightEnclosingEdge, + &activeEdges, c, alloc)) { + if (c.sweep_lt(pv->fPoint, v->fPoint)) { + v = pv; + } + restartChecks = true; + } + + } + } while (restartChecks); + for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { + remove_edge(e, &activeEdges); + } + Edge* leftEdge = leftEnclosingEdge; + for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { + insert_edge(e, leftEdge, &activeEdges); + leftEdge = e; + } + v->fProcessed = true; + } +} + +// Stage 5: Tessellate the simplified mesh into monotone polygons. + +Poly* tessellate(Vertex* vertices, SkChunkAlloc& alloc) { + LOG("tessellating simple polygons\n"); + EdgeList activeEdges; + Poly* polys = nullptr; + for (Vertex* v = vertices; v != nullptr; v = v->fNext) { + if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) { + continue; + } +#if LOGGING_ENABLED + LOG("\nvertex %g: (%g,%g)\n", v->fID, v->fPoint.fX, v->fPoint.fY); +#endif + Edge* leftEnclosingEdge = nullptr; + Edge* rightEnclosingEdge = nullptr; + find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); + Poly* leftPoly = nullptr; + Poly* rightPoly = nullptr; + if (v->fFirstEdgeAbove) { + leftPoly = v->fFirstEdgeAbove->fLeftPoly; + rightPoly = v->fLastEdgeAbove->fRightPoly; + } else { + leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr; + rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr; + } +#if LOGGING_ENABLED + LOG("edges above:\n"); + for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { + LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID, + e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1); + } + LOG("edges below:\n"); + for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { + LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID, + e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1); + } +#endif + if (v->fFirstEdgeAbove) { + if (leftPoly) { + leftPoly = leftPoly->addVertex(v, Poly::kRight_Side, alloc); + } + if (rightPoly) { + rightPoly = rightPoly->addVertex(v, Poly::kLeft_Side, alloc); + } + for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) { + Edge* leftEdge = e; + Edge* rightEdge = e->fNextEdgeAbove; + SkASSERT(rightEdge->isRightOf(leftEdge->fTop)); + remove_edge(leftEdge, &activeEdges); + if (leftEdge->fRightPoly) { + leftEdge->fRightPoly->end(v, alloc); + } + if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != leftEdge->fRightPoly) { + rightEdge->fLeftPoly->end(v, alloc); + } + } + remove_edge(v->fLastEdgeAbove, &activeEdges); + if (!v->fFirstEdgeBelow) { + if (leftPoly && rightPoly && leftPoly != rightPoly) { + SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr); + rightPoly->fPartner = leftPoly; + leftPoly->fPartner = rightPoly; + } + } + } + if (v->fFirstEdgeBelow) { + if (!v->fFirstEdgeAbove) { + if (leftPoly && leftPoly == rightPoly) { + // Split the poly. + if (leftPoly->fActive->fSide == Poly::kLeft_Side) { + leftPoly = new_poly(&polys, leftEnclosingEdge->fTop, leftPoly->fWinding, + alloc); + leftPoly->addVertex(v, Poly::kRight_Side, alloc); + rightPoly->addVertex(v, Poly::kLeft_Side, alloc); + leftEnclosingEdge->fRightPoly = leftPoly; + } else { + rightPoly = new_poly(&polys, rightEnclosingEdge->fTop, rightPoly->fWinding, + alloc); + rightPoly->addVertex(v, Poly::kLeft_Side, alloc); + leftPoly->addVertex(v, Poly::kRight_Side, alloc); + rightEnclosingEdge->fLeftPoly = rightPoly; + } + } else { + if (leftPoly) { + leftPoly = leftPoly->addVertex(v, Poly::kRight_Side, alloc); + } + if (rightPoly) { + rightPoly = rightPoly->addVertex(v, Poly::kLeft_Side, alloc); + } + } + } + Edge* leftEdge = v->fFirstEdgeBelow; + leftEdge->fLeftPoly = leftPoly; + insert_edge(leftEdge, leftEnclosingEdge, &activeEdges); + for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge; + rightEdge = rightEdge->fNextEdgeBelow) { + insert_edge(rightEdge, leftEdge, &activeEdges); + int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0; + winding += leftEdge->fWinding; + if (winding != 0) { + Poly* poly = new_poly(&polys, v, winding, alloc); + leftEdge->fRightPoly = rightEdge->fLeftPoly = poly; + } + leftEdge = rightEdge; + } + v->fLastEdgeBelow->fRightPoly = rightPoly; + } +#if LOGGING_ENABLED + LOG("\nactive edges:\n"); + for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) { + LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID, + e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1); + } +#endif + } + return polys; +} + +// This is a driver function which calls stages 2-5 in turn. + +Poly* contours_to_polys(Vertex** contours, int contourCnt, const SkRect& pathBounds, + SkChunkAlloc& alloc) { + Comparator c; + if (pathBounds.width() > pathBounds.height()) { + c.sweep_lt = sweep_lt_horiz; + c.sweep_gt = sweep_gt_horiz; + } else { + c.sweep_lt = sweep_lt_vert; + c.sweep_gt = sweep_gt_vert; + } +#if LOGGING_ENABLED + for (int i = 0; i < contourCnt; ++i) { + Vertex* v = contours[i]; + SkASSERT(v); + LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); + for (v = v->fNext; v != contours[i]; v = v->fNext) { + LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); + } + } +#endif + sanitize_contours(contours, contourCnt); + Vertex* vertices = build_edges(contours, contourCnt, c, alloc); + if (!vertices) { + return nullptr; + } + + // Sort vertices in Y (secondarily in X). + merge_sort(&vertices, c); + merge_coincident_vertices(&vertices, c, alloc); +#if LOGGING_ENABLED + for (Vertex* v = vertices; v != nullptr; v = v->fNext) { + static float gID = 0.0f; + v->fID = gID++; + } +#endif + simplify(vertices, c, alloc); + return tessellate(vertices, alloc); +} + +Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, + int contourCnt, SkChunkAlloc& alloc, bool* isLinear) { + SkPath::FillType fillType = path.getFillType(); + if (SkPath::IsInverseFillType(fillType)) { + contourCnt++; + } + SkAutoTDeleteArray contours(new Vertex* [contourCnt]); + + path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, isLinear); + return contours_to_polys(contours.get(), contourCnt, path.getBounds(), alloc); +} + +void get_contour_count_and_size_estimate(const SkPath& path, SkScalar tolerance, int* contourCnt, + int* sizeEstimate) { + int maxPts = GrPathUtils::worstCasePointCount(path, contourCnt, tolerance); + if (maxPts <= 0) { + *contourCnt = 0; + return; + } + if (maxPts > ((int)SK_MaxU16 + 1)) { + SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); + *contourCnt = 0; + return; + } + // For the initial size of the chunk allocator, estimate based on the point count: + // one vertex per point for the initial passes, plus two for the vertices in the + // resulting Polys, since the same point may end up in two Polys. Assume minimal + // connectivity of one Edge per Vertex (will grow for intersections). + *sizeEstimate = maxPts * (3 * sizeof(Vertex) + sizeof(Edge)); +} + +int count_points(Poly* polys, SkPath::FillType fillType) { + int count = 0; + for (Poly* poly = polys; poly; poly = poly->fNext) { + if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3) { + count += (poly->fCount - 2) * (TESSELLATOR_WIREFRAME ? 6 : 3); + } + } + return count; +} + +} // namespace + +namespace GrTessellator { + +// Stage 6: Triangulate the monotone polygons into a vertex buffer. + +int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, + GrResourceProvider* resourceProvider, + SkAutoTUnref& vertexBuffer, bool canMapVB, bool* isLinear) { + int contourCnt; + int sizeEstimate; + get_contour_count_and_size_estimate(path, tolerance, &contourCnt, &sizeEstimate); + if (contourCnt <= 0) { + *isLinear = true; + return 0; + } + SkChunkAlloc alloc(sizeEstimate); + Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, isLinear); + SkPath::FillType fillType = path.getFillType(); + int count = count_points(polys, fillType); + if (0 == count) { + return 0; + } + + size_t size = count * sizeof(SkPoint); + if (!vertexBuffer.get() || vertexBuffer->gpuMemorySize() < size) { + vertexBuffer.reset(resourceProvider->createVertexBuffer( + size, GrResourceProvider::kStatic_BufferUsage, 0)); + } + if (!vertexBuffer.get()) { + SkDebugf("Could not allocate vertices\n"); + return 0; + } + SkPoint* verts; + if (canMapVB) { + verts = static_cast(vertexBuffer->map()); + } else { + verts = new SkPoint[count]; + } + SkPoint* end = verts; + for (Poly* poly = polys; poly; poly = poly->fNext) { + if (apply_fill_type(fillType, poly->fWinding)) { + end = poly->emit(end); + } + } + int actualCount = static_cast(end - verts); + LOG("actual count: %d\n", actualCount); + SkASSERT(actualCount <= count); + if (canMapVB) { + vertexBuffer->unmap(); + } else { + vertexBuffer->updateData(verts, actualCount * sizeof(SkPoint)); + delete[] verts; + } + + return actualCount; +} + +int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, + GrTessellator::WindingVertex** verts) { + int contourCnt; + int sizeEstimate; + get_contour_count_and_size_estimate(path, tolerance, &contourCnt, &sizeEstimate); + if (contourCnt <= 0) { + return 0; + } + SkChunkAlloc alloc(sizeEstimate); + bool isLinear; + Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, &isLinear); + SkPath::FillType fillType = path.getFillType(); + int count = count_points(polys, fillType); + if (0 == count) { + *verts = nullptr; + return 0; + } + + *verts = new GrTessellator::WindingVertex[count]; + GrTessellator::WindingVertex* vertsEnd = *verts; + SkPoint* points = new SkPoint[count]; + SkPoint* pointsEnd = points; + for (Poly* poly = polys; poly; poly = poly->fNext) { + if (apply_fill_type(fillType, poly->fWinding)) { + SkPoint* start = pointsEnd; + pointsEnd = poly->emit(pointsEnd); + while (start != pointsEnd) { + vertsEnd->fPos = *start; + vertsEnd->fWinding = poly->fWinding; + ++start; + ++vertsEnd; + } + } + } + int actualCount = static_cast(vertsEnd - *verts); + SkASSERT(actualCount <= count); + SkASSERT(pointsEnd - points == actualCount); + delete[] points; + return actualCount; +} + +} // namespace diff --git a/gfx/skia/skia/src/gpu/GrTessellator.h b/gfx/skia/skia/src/gpu/GrTessellator.h new file mode 100644 index 00000000000..4304920fbc0 --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTessellator.h @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTessellator_DEFINED +#define GrTessellator_DEFINED + +#include "SkPath.h" +#include "GrResourceProvider.h" + +/** + * Provides utility functions for converting paths to a collection of triangles. + */ + +#define TESSELLATOR_WIREFRAME 0 + +namespace GrTessellator { + +struct WindingVertex { + SkPoint fPos; + int fWinding; +}; + +// Triangulates a path to an array of vertices. Each triangle is represented as a set of three +// WindingVertex entries, each of which contains the position and winding count (which is the same +// for all three vertices of a triangle). The 'verts' out parameter is set to point to the resultant +// vertex array. CALLER IS RESPONSIBLE for deleting this buffer to avoid a memory leak! +int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, + WindingVertex** verts); + +int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, + GrResourceProvider* resourceProvider, + SkAutoTUnref& vertexBuffer, bool canMapVB, bool* isLinear); + +} + +#endif diff --git a/gfx/skia/skia/src/gpu/GrTest.cpp b/gfx/skia/skia/src/gpu/GrTest.cpp index b1c135474df..8174d76779b 100644 --- a/gfx/skia/skia/src/gpu/GrTest.cpp +++ b/gfx/skia/skia/src/gpu/GrTest.cpp @@ -9,16 +9,19 @@ #include "GrTest.h" #include "GrBatchAtlas.h" -#include "GrBatchFontCache.h" #include "GrContextOptions.h" #include "GrDrawContext.h" #include "GrDrawingManager.h" #include "GrGpuResourceCacheAccess.h" #include "GrResourceCache.h" -#include "GrTextBlobCache.h" + +#include "SkGpuDevice.h" #include "SkGrPriv.h" #include "SkString.h" +#include "text/GrBatchFontCache.h" +#include "text/GrTextBlobCache.h" + namespace GrTest { void SetupAlwaysEvictAtlas(GrContext* context) { // These sizes were selected because they allow each atlas to hold a single plot and will thus @@ -137,41 +140,40 @@ void GrContext::printGpuStats() const { SkDebugf("%s", out.c_str()); } -void GrContext::drawFontCache(const SkRect& rect, GrMaskFormat format, const SkPaint& paint, - GrRenderTarget* target) { +GrTexture* GrContext::getFontAtlasTexture(GrMaskFormat format) { GrBatchFontCache* cache = this->getBatchFontCache(); - GrTexture* atlas = cache->getTexture(format); - - SkAutoTUnref drawContext(this->drawContext(target)); - // TODO: add drawContext method to encapsulate this. + return cache->getTexture(format); +} +void SkGpuDevice::drawTexture(GrTexture* tex, const SkRect& dst, const SkPaint& paint) { GrPaint grPaint; SkMatrix mat; mat.reset(); - if (!SkPaintToGrPaint(this, paint, mat, &grPaint)) { + if (!SkPaintToGrPaint(this->context(), paint, mat, &grPaint)) { return; } SkMatrix textureMat; textureMat.reset(); - // TODO: use setScaleTranslate() - textureMat[SkMatrix::kMScaleX] = 1.0f/rect.width(); - textureMat[SkMatrix::kMScaleY] = 1.0f/rect.height(); - textureMat[SkMatrix::kMTransX] = -rect.fLeft/rect.width(); - textureMat[SkMatrix::kMTransY] = -rect.fTop/rect.height(); + textureMat[SkMatrix::kMScaleX] = 1.0f/dst.width(); + textureMat[SkMatrix::kMScaleY] = 1.0f/dst.height(); + textureMat[SkMatrix::kMTransX] = -dst.fLeft/dst.width(); + textureMat[SkMatrix::kMTransY] = -dst.fTop/dst.height(); - grPaint.addColorTextureProcessor(atlas, textureMat); + grPaint.addColorTextureProcessor(tex, textureMat); GrClip clip; - drawContext->drawRect(clip, grPaint, mat, rect); + fDrawContext->drawRect(clip, grPaint, mat, dst); } + #if GR_GPU_STATS void GrGpu::Stats::dump(SkString* out) { out->appendf("Render Target Binds: %d\n", fRenderTargetBinds); out->appendf("Shader Compilations: %d\n", fShaderCompilations); out->appendf("Textures Created: %d\n", fTextureCreates); out->appendf("Texture Uploads: %d\n", fTextureUploads); + out->appendf("Transfers to Texture: %d\n", fTransfersToTexture); out->appendf("Stencil Buffer Creates: %d\n", fStencilAttachmentCreates); out->appendf("Number of draws: %d\n", fNumDraws); } @@ -181,6 +183,7 @@ void GrGpu::Stats::dumpKeyValuePairs(SkTArray* keys, SkTArray* keys->push_back(SkString("shader_compilations")); values->push_back(fShaderCompilations); keys->push_back(SkString("textures_created")); values->push_back(fTextureCreates); keys->push_back(SkString("texture_uploads")); values->push_back(fTextureUploads); + keys->push_back(SkString("transfers_to_texture")); values->push_back(fTransfersToTexture); keys->push_back(SkString("stencil_buffer_creates")); values->push_back(fStencilAttachmentCreates); keys->push_back(SkString("number_of_draws")); values->push_back(fNumDraws); } @@ -247,6 +250,25 @@ void GrResourceCache::dumpStatsKeyValuePairs(SkTArray* keys, void GrResourceCache::changeTimestamp(uint32_t newTimestamp) { fTimestamp = newTimestamp; } +/////////////////////////////////////////////////////////////////////////////// + +#define ASSERT_SINGLE_OWNER \ + SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) +#define RETURN_IF_ABANDONED if (fDrawingManager->abandoned()) { return; } + +void GrDrawContext::internal_drawBatch(const GrPipelineBuilder& pipelineBuilder, + GrDrawBatch* batch) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::internal_drawBatch"); + + this->getDrawTarget()->drawBatch(pipelineBuilder, batch); +} + +#undef ASSERT_SINGLE_OWNER +#undef RETURN_IF_ABANDONED + /////////////////////////////////////////////////////////////////////////////// // Code for the mock context. It's built on a mock GrGpu class that does nothing. //// @@ -255,10 +277,19 @@ void GrResourceCache::changeTimestamp(uint32_t newTimestamp) { fTimestamp = newT class GrPipeline; +class MockCaps : public GrCaps { +public: + explicit MockCaps(const GrContextOptions& options) : INHERITED(options) {} + bool isConfigTexturable(GrPixelConfig config) const override { return false; } + bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { return false; } +private: + typedef GrCaps INHERITED; +}; + class MockGpu : public GrGpu { public: MockGpu(GrContext* context, const GrContextOptions& options) : INHERITED(context) { - fCaps.reset(new GrCaps(options)); + fCaps.reset(new MockCaps(options)); } ~MockGpu() override {} @@ -284,6 +315,8 @@ public: return false; } + void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override {}; + private: void onResetContext(uint32_t resetBits) override {} @@ -311,6 +344,8 @@ private: GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) override { return nullptr; } + GrTransferBuffer* onCreateTransferBuffer(size_t, TransferType) override { return nullptr; } + void onClear(GrRenderTarget*, const SkIRect& rect, GrColor color) override {} void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) override {} @@ -332,6 +367,13 @@ private: return false; } + bool onTransferPixels(GrSurface* surface, + int left, int top, int width, int height, + GrPixelConfig config, GrTransferBuffer* buffer, + size_t offset, size_t rowBytes) override { + return false; + } + void onResolveRenderTarget(GrRenderTarget* target) override { return; } GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*, diff --git a/gfx/skia/skia/src/gpu/GrTest.h b/gfx/skia/skia/src/gpu/GrTest.h index 297f51c1136..75eb53ac641 100644 --- a/gfx/skia/skia/src/gpu/GrTest.h +++ b/gfx/skia/skia/src/gpu/GrTest.h @@ -21,7 +21,8 @@ namespace GrTest { void SetupAlwaysEvictAtlas(GrContext*); }; -/** Allows a test to temporarily draw to a GrDrawTarget owned by a GrContext. Tests that use this +/** TODO Please do not use this if you can avoid it. We are in the process of deleting it. + Allows a test to temporarily draw to a GrDrawTarget owned by a GrContext. Tests that use this should be careful not to mix using the GrDrawTarget directly and drawing via SkCanvas or GrContext. In the future this object may provide some guards to prevent this. */ class GrTestTarget { diff --git a/gfx/skia/skia/src/gpu/GrTextureAccess.cpp b/gfx/skia/skia/src/gpu/GrTextureAccess.cpp index 7e1eda6211f..277c0e3833e 100644 --- a/gfx/skia/skia/src/gpu/GrTextureAccess.cpp +++ b/gfx/skia/skia/src/gpu/GrTextureAccess.cpp @@ -9,12 +9,7 @@ #include "GrColor.h" #include "GrTexture.h" -GrTextureAccess::GrTextureAccess() { -#ifdef SK_DEBUG - memcpy(fSwizzle, "void", 5); - fSwizzleMask = 0xbeeffeed; -#endif -} +GrTextureAccess::GrTextureAccess() {} GrTextureAccess::GrTextureAccess(GrTexture* texture, const GrTextureParams& params) { this->reset(texture, params); @@ -26,49 +21,12 @@ GrTextureAccess::GrTextureAccess(GrTexture* texture, this->reset(texture, filterMode, tileXAndY); } -GrTextureAccess::GrTextureAccess(GrTexture* texture, - const char* swizzle, - const GrTextureParams& params) { - this->reset(texture, swizzle, params); -} - -GrTextureAccess::GrTextureAccess(GrTexture* texture, - const char* swizzle, - GrTextureParams::FilterMode filterMode, - SkShader::TileMode tileXAndY) { - this->reset(texture, swizzle, filterMode, tileXAndY); -} - -void GrTextureAccess::reset(GrTexture* texture, - const char* swizzle, - const GrTextureParams& params) { - SkASSERT(texture); - SkASSERT(strlen(swizzle) >= 1 && strlen(swizzle) <= 4); - - fParams = params; - fTexture.set(SkRef(texture), kRead_GrIOType); - this->setSwizzle(swizzle); -} - -void GrTextureAccess::reset(GrTexture* texture, - const char* swizzle, - GrTextureParams::FilterMode filterMode, - SkShader::TileMode tileXAndY) { - SkASSERT(texture); - SkASSERT(strlen(swizzle) >= 1 && strlen(swizzle) <= 4); - - fParams.reset(tileXAndY, filterMode); - fTexture.set(SkRef(texture), kRead_GrIOType); - this->setSwizzle(swizzle); -} void GrTextureAccess::reset(GrTexture* texture, const GrTextureParams& params) { SkASSERT(texture); fTexture.set(SkRef(texture), kRead_GrIOType); fParams = params; - memcpy(fSwizzle, "rgba", 5); - fSwizzleMask = kRGBA_GrColorComponentFlags; } void GrTextureAccess::reset(GrTexture* texture, @@ -77,31 +35,4 @@ void GrTextureAccess::reset(GrTexture* texture, SkASSERT(texture); fTexture.set(SkRef(texture), kRead_GrIOType); fParams.reset(tileXAndY, filterMode); - memcpy(fSwizzle, "rgba", 5); - fSwizzleMask = kRGBA_GrColorComponentFlags; -} - -void GrTextureAccess::setSwizzle(const char* swizzle) { - fSwizzleMask = 0; - memset(fSwizzle, '\0', 5); - for (int i = 0; i < 4 && '\0' != swizzle[i]; ++i) { - fSwizzle[i] = swizzle[i]; - switch (swizzle[i]) { - case 'r': - fSwizzleMask |= kR_GrColorComponentFlag; - break; - case 'g': - fSwizzleMask |= kG_GrColorComponentFlag; - break; - case 'b': - fSwizzleMask |= kB_GrColorComponentFlag; - break; - case 'a': - fSwizzleMask |= kA_GrColorComponentFlag; - break; - default: - SkFAIL("Unexpected swizzle string character."); - break; - } - } } diff --git a/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.cpp b/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.cpp index 2aedad57ef2..336ab6b10c4 100644 --- a/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.cpp +++ b/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.cpp @@ -121,8 +121,10 @@ static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset, return copy.detach(); } -GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, const SkIRect& contentArea) - : INHERITED(contentArea.width(), contentArea.height()) +GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, + const SkIRect& contentArea, + bool isAlphaOnly) + : INHERITED(contentArea.width(), contentArea.height(), isAlphaOnly) , fOriginal(original) { SkASSERT(SkIRect::MakeWH(original->width(), original->height()).contains(contentArea)); if (contentArea.fLeft > 0 || contentArea.fTop > 0 || diff --git a/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.h b/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.h index ed9f142af0f..103bcbf7208 100644 --- a/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.h +++ b/gfx/skia/skia/src/gpu/GrTextureParamsAdjuster.h @@ -70,9 +70,13 @@ public: int width() const { return fWidth; } int height() const { return fHeight; } + bool isAlphaOnly() const { return fIsAlphaOnly; } protected: - GrTextureProducer(int width, int height) : fWidth(width), fHeight(height) {} + GrTextureProducer(int width, int height, bool isAlphaOnly) + : fWidth(width) + , fHeight(height) + , fIsAlphaOnly(isAlphaOnly) {} /** Helper for creating a key for a copy from an original key. */ static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey, @@ -104,8 +108,9 @@ protected: virtual void didCacheCopy(const GrUniqueKey& copyKey) = 0; private: - const int fWidth; - const int fHeight; + const int fWidth; + const int fHeight; + const bool fIsAlphaOnly; typedef SkNoncopyable INHERITED; }; @@ -133,11 +138,11 @@ public: protected: /** The whole texture is content. */ - explicit GrTextureAdjuster(GrTexture* original) - : INHERITED(original->width(), original->height()) + explicit GrTextureAdjuster(GrTexture* original, bool isAlphaOnly) + : INHERITED(original->width(), original->height(), isAlphaOnly) , fOriginal(original) {} - GrTextureAdjuster(GrTexture* original, const SkIRect& contentArea); + GrTextureAdjuster(GrTexture* original, const SkIRect& contentArea, bool isAlphaOnly); GrTexture* originalTexture() const { return fOriginal; } @@ -170,8 +175,8 @@ public: const GrTextureParams::FilterMode* filterOrNullForBicubic) override; protected: - GrTextureMaker(GrContext* context, int width, int height) - : INHERITED(width, height) + GrTextureMaker(GrContext* context, int width, int height, bool isAlphaOnly) + : INHERITED(width, height, isAlphaOnly) , fContext(context) {} /** diff --git a/gfx/skia/skia/src/gpu/GrTextureProvider.cpp b/gfx/skia/skia/src/gpu/GrTextureProvider.cpp index cb652f7a7fd..1c2f36535a0 100644 --- a/gfx/skia/skia/src/gpu/GrTextureProvider.cpp +++ b/gfx/skia/skia/src/gpu/GrTextureProvider.cpp @@ -10,6 +10,10 @@ #include "GrTexturePriv.h" #include "GrResourceCache.h" #include "GrGpu.h" +#include "../private/GrSingleOwner.h" + +#define ASSERT_SINGLE_OWNER \ + SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) enum ScratchTextureFlags { kExact_ScratchTextureFlag = 0x1, @@ -17,8 +21,18 @@ enum ScratchTextureFlags { kNoCreate_ScratchTextureFlag = 0x4, }; +GrTextureProvider::GrTextureProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* singleOwner) + : fCache(cache) + , fGpu(gpu) +#ifdef SK_DEBUG + , fSingleOwner(singleOwner) +#endif + { +} + GrTexture* GrTextureProvider::createTexture(const GrSurfaceDesc& desc, bool budgeted, const void* srcData, size_t rowBytes) { + ASSERT_SINGLE_OWNER if (this->isAbandoned()) { return nullptr; } @@ -44,11 +58,13 @@ GrTexture* GrTextureProvider::createTexture(const GrSurfaceDesc& desc, bool budg } GrTexture* GrTextureProvider::createApproxTexture(const GrSurfaceDesc& desc) { + ASSERT_SINGLE_OWNER return this->internalCreateApproxTexture(desc, 0); } GrTexture* GrTextureProvider::internalCreateApproxTexture(const GrSurfaceDesc& desc, uint32_t scratchFlags) { + ASSERT_SINGLE_OWNER if (this->isAbandoned()) { return nullptr; } @@ -62,6 +78,7 @@ GrTexture* GrTextureProvider::internalCreateApproxTexture(const GrSurfaceDesc& d GrTexture* GrTextureProvider::refScratchTexture(const GrSurfaceDesc& inDesc, uint32_t flags) { + ASSERT_SINGLE_OWNER SkASSERT(!this->isAbandoned()); SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig)); @@ -108,6 +125,7 @@ GrTexture* GrTextureProvider::refScratchTexture(const GrSurfaceDesc& inDesc, GrTexture* GrTextureProvider::wrapBackendTexture(const GrBackendTextureDesc& desc, GrWrapOwnership ownership) { + ASSERT_SINGLE_OWNER if (this->isAbandoned()) { return nullptr; } @@ -115,11 +133,13 @@ GrTexture* GrTextureProvider::wrapBackendTexture(const GrBackendTextureDesc& des } GrRenderTarget* GrTextureProvider::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) { + ASSERT_SINGLE_OWNER return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(desc, - kBorrow_GrWrapOwnership); + kBorrow_GrWrapOwnership); } void GrTextureProvider::assignUniqueKeyToResource(const GrUniqueKey& key, GrGpuResource* resource) { + ASSERT_SINGLE_OWNER if (this->isAbandoned() || !resource) { return; } @@ -127,9 +147,22 @@ void GrTextureProvider::assignUniqueKeyToResource(const GrUniqueKey& key, GrGpuR } bool GrTextureProvider::existsResourceWithUniqueKey(const GrUniqueKey& key) const { + ASSERT_SINGLE_OWNER return this->isAbandoned() ? false : fCache->hasUniqueKey(key); } GrGpuResource* GrTextureProvider::findAndRefResourceByUniqueKey(const GrUniqueKey& key) { + ASSERT_SINGLE_OWNER return this->isAbandoned() ? nullptr : fCache->findAndRefUniqueResource(key); } + +GrTexture* GrTextureProvider::findAndRefTextureByUniqueKey(const GrUniqueKey& key) { + ASSERT_SINGLE_OWNER + GrGpuResource* resource = this->findAndRefResourceByUniqueKey(key); + if (resource) { + GrTexture* texture = static_cast(resource)->asTexture(); + SkASSERT(texture); + return texture; + } + return NULL; +} diff --git a/gfx/skia/skia/src/gpu/GrTracing.h b/gfx/skia/skia/src/gpu/GrTracing.h index d758c0329d9..3dbc0ef17e0 100644 --- a/gfx/skia/skia/src/gpu/GrTracing.h +++ b/gfx/skia/skia/src/gpu/GrTracing.h @@ -58,74 +58,64 @@ private: /** * GR_CREATE_TRACE_MARKER will place begin and end trace markers for both * cpu and gpu (if gpu tracing enabled) for the current scope. - * marker is of type const char* and target is of type GrDrawTarget* + * name is of type const char* and target is of type GrDrawTarget* */ -#define GR_CREATE_TRACE_MARKER(name, target) \ - INTERNAL_GR_CREATE_TRACE_MARKER_SCOPED(name, target) +#define GR_CREATE_TRACE_MARKER(name, target) \ + /* Chromium tracing */ \ + static int SK_MACRO_APPEND_LINE(name_counter) = 0; \ + bool SK_MACRO_APPEND_LINE(gpuTracingEnabled); \ + TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), \ + &SK_MACRO_APPEND_LINE(gpuTracingEnabled)); \ + if (SK_MACRO_APPEND_LINE(gpuTracingEnabled)) { \ + INTERNAL_GR_CREATE_TRACE_MARKER_SCOPED(name, SK_MACRO_APPEND_LINE(name_counter), target) \ + } \ + INTERNAL_TRACE_EVENT_ADD_SCOPED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), name, \ + "id", SK_MACRO_APPEND_LINE(name_counter)); -#define GR_CREATE_TRACE_MARKER1(name, target, arg1_name, arg1_val) \ - INTERNAL_GR_CREATE_TRACE_MARKER_SCOPED(name, target, arg1_name, arg1_val) - -#define INTERNAL_GR_CREATE_TRACE_MARKER_SCOPED(name, target, ...) \ +#define INTERNAL_GR_CREATE_TRACE_MARKER_SCOPED(name, name_counter, target) \ static const char* SK_MACRO_APPEND_LINE(static_name) = name; \ - static int SK_MACRO_APPEND_LINE(name_counter) = 0; \ INTERNAL_GR_CREATE_TRACE_MARKER(SK_MACRO_APPEND_LINE(static_name), \ - SK_MACRO_APPEND_LINE(name_counter), \ - target, ##__VA_ARGS__) \ - sk_atomic_inc(&SK_MACRO_APPEND_LINE(name_counter)); + name_counter, \ + target) \ + sk_atomic_inc(&name_counter); #define INTERNAL_GR_CREATE_TRACE_MARKER(name, name_counter, target, ...) \ GR_CREATE_GPU_TRACE_MARKER(name, name_counter, target) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"),name, \ - "id", name_counter, ##__VA_ARGS__); -#if GR_FORCE_GPU_TRACE_DEBUGGING -#define GR_CREATE_GPU_TRACE_MARKER(name, name_counter, target) \ - GrGpuTraceMarkerGenerator SK_MACRO_APPEND_LINE(TMG)(target); \ - SK_MACRO_APPEND_LINE(TMG).initialize(name, &name_counter); -#else -#define GR_CREATE_GPU_TRACE_MARKER(name, name_counter, target) \ - GrGpuTraceMarkerGenerator SK_MACRO_APPEND_LINE(TMG)(target); \ - bool SK_MACRO_APPEND_LINE(gpuTracingEnabled); \ - TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), \ - &SK_MACRO_APPEND_LINE(gpuTracingEnabled)); \ - if (SK_MACRO_APPEND_LINE(gpuTracingEnabled)) { \ - SK_MACRO_APPEND_LINE(TMG).initialize(name, &name_counter); \ - } -#endif +#define GR_CREATE_GPU_TRACE_MARKER(name, name_counter, target) \ + GrGpuTraceMarkerGenerator SK_MACRO_APPEND_LINE(TMG)(target); \ + SK_MACRO_APPEND_LINE(TMG).initialize(name, &name_counter); \ -#define GR_CREATE_TRACE_MARKER_CONTEXT(name, context) \ - INTERNAL_GR_CREATE_TRACE_MARKER_SCOPED_C(name, context) +/** + * Context level GrTracing macros, classname and op are const char*, context is GrContext + * TODO can we just have one set of macros? Probably. + */ +#define GR_CREATE_TRACE_MARKER_CONTEXT(classname, op, context) \ + /* Chromium tracing */ \ + static int SK_MACRO_APPEND_LINE(name_counter) = 0; \ + bool SK_MACRO_APPEND_LINE(gpuTracingEnabled); \ + TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), \ + &SK_MACRO_APPEND_LINE(gpuTracingEnabled)); \ + if (SK_MACRO_APPEND_LINE(gpuTracingEnabled)) { \ + INTERNAL_GR_CREATE_TRACE_MARKER_SCOPED_C(classname "::" op, \ + SK_MACRO_APPEND_LINE(name_counter), context) \ + } \ + GR_AUDIT_TRAIL_AUTO_FRAME(context->getAuditTrail(), classname "::" op); \ + INTERNAL_TRACE_EVENT_ADD_SCOPED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), classname "::" op, \ + "id", SK_MACRO_APPEND_LINE(name_counter)); -#define GR_CREATE_TRACE_MARKER_CONTEXT1(name, context, arg1_name, arg1_val) \ - INTERNAL_GR_CREATE_TRACE_MARKER_SCOPED_C(name, context, arg1_name, arg1_val) - -#define INTERNAL_GR_CREATE_TRACE_MARKER_SCOPED_C(name, context, ...) \ +#define INTERNAL_GR_CREATE_TRACE_MARKER_SCOPED_C(name, name_counter, context) \ static const char* SK_MACRO_APPEND_LINE(static_name) = name; \ - static int SK_MACRO_APPEND_LINE(name_counter) = 0; \ INTERNAL_GR_CREATE_TRACE_MARKER_C(SK_MACRO_APPEND_LINE(static_name), \ - SK_MACRO_APPEND_LINE(name_counter), \ - context, ##__VA_ARGS__) \ - sk_atomic_inc(&SK_MACRO_APPEND_LINE(name_counter)); + name_counter, \ + context) \ + sk_atomic_inc(&name_counter); #define INTERNAL_GR_CREATE_TRACE_MARKER_C(name, name_counter, context, ...) \ GR_CREATE_GPU_TRACE_MARKER_C(name, name_counter, context) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"),name, \ - "id", name_counter, ##__VA_ARGS__); -#if GR_FORCE_GPU_TRACE_DEBUGGING -#define GR_CREATE_GPU_TRACE_MARKER_C(name, name_counter, context) \ - GrGpuTraceMarkerGeneratorContext SK_MACRO_APPEND_LINE(TMG)(context); \ - SK_MACRO_APPEND_LINE(TMG).initialize(name, &name_counter); -#else -#define GR_CREATE_GPU_TRACE_MARKER_C(name, name_counter, context) \ - GrGpuTraceMarkerGeneratorContext SK_MACRO_APPEND_LINE(TMG)(context); \ - bool SK_MACRO_APPEND_LINE(gpuTracingEnabled); \ - TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), \ - &SK_MACRO_APPEND_LINE(gpuTracingEnabled)); \ - if (SK_MACRO_APPEND_LINE(gpuTracingEnabled)) { \ - SK_MACRO_APPEND_LINE(TMG).initialize(name, &name_counter); \ - } -#endif +#define GR_CREATE_GPU_TRACE_MARKER_C(name, name_counter, context) \ + GrGpuTraceMarkerGeneratorContext SK_MACRO_APPEND_LINE(TMG)(context); \ + SK_MACRO_APPEND_LINE(TMG).initialize(name, &name_counter); \ #endif diff --git a/gfx/skia/skia/src/gpu/GrTransferBuffer.h b/gfx/skia/skia/src/gpu/GrTransferBuffer.h new file mode 100755 index 00000000000..bd80666fd6d --- /dev/null +++ b/gfx/skia/skia/src/gpu/GrTransferBuffer.h @@ -0,0 +1,76 @@ + +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef GrTransferBuffer_DEFINED +#define GrTransferBuffer_DEFINED + +#include "GrGpuResource.h" + +class GrTransferBuffer : public GrGpuResource { +public: + /** + * Maps the buffer to be written by the CPU. + * + * The previous content of the buffer is invalidated. It is an error + * to transfer to or from the buffer while it is mapped. It is an error to + * call map on an already mapped buffer. Must be matched by an unmap() call. + * Currently only one map at a time is supported (no nesting of map/unmap). + * + * Note that buffer mapping does not go through GrContext and therefore is + * not serialized with other operations. + * + * @return a pointer to the data or nullptr if the map fails. + */ + void* map() { return (fMapPtr = this->onMap()); } + + /** + * Unmaps the buffer. + * + * The pointer returned by the previous map call will no longer be valid. + */ + void unmap() { + SkASSERT(fMapPtr); + this->onUnmap(); + fMapPtr = nullptr; + } + + /** + * Returns the same ptr that map() returned at time of map or nullptr if the + * is not mapped. + * + * @return ptr to mapped buffer data or nullptr if buffer is not mapped. + */ + void* mapPtr() const { return fMapPtr; } + + /** + Queries whether the buffer has been mapped. + + @return true if the buffer is mapped, false otherwise. + */ + bool isMapped() const { return SkToBool(fMapPtr); } + +protected: + GrTransferBuffer(GrGpu* gpu, size_t gpuMemorySize) + : INHERITED(gpu, kUncached_LifeCycle) + , fGpuMemorySize(gpuMemorySize) { + } + +private: + virtual size_t onGpuMemorySize() const { return fGpuMemorySize; } + + virtual void* onMap() = 0; + virtual void onUnmap() = 0; + + void* fMapPtr; + size_t fGpuMemorySize; + + typedef GrGpuResource INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/SkGpuDevice.cpp b/gfx/skia/skia/src/gpu/SkGpuDevice.cpp index 6215c1b387f..0359b57ca5e 100644 --- a/gfx/skia/skia/src/gpu/SkGpuDevice.cpp +++ b/gfx/skia/skia/src/gpu/SkGpuDevice.cpp @@ -10,15 +10,12 @@ #include "GrBlurUtils.h" #include "GrContext.h" #include "SkDraw.h" -#include "GrDrawContext.h" -#include "GrFontScaler.h" #include "GrGpu.h" #include "GrGpuResourcePriv.h" #include "GrImageIDTextureAdjuster.h" #include "GrLayerHoister.h" #include "GrRecordReplaceDraw.h" #include "GrStrokeInfo.h" -#include "GrTextContext.h" #include "GrTracing.h" #include "SkCanvasPriv.h" #include "SkErrorInternals.h" @@ -27,6 +24,7 @@ #include "SkGr.h" #include "SkGrPriv.h" #include "SkImage_Base.h" +#include "SkImageCacherator.h" #include "SkImageFilter.h" #include "SkLayerInfo.h" #include "SkMaskFilter.h" @@ -48,9 +46,13 @@ #include "effects/GrDashingEffect.h" #include "effects/GrSimpleTextureEffect.h" #include "effects/GrTextureDomain.h" +#include "text/GrTextContext.h" #if SK_SUPPORT_GPU +#define ASSERT_SINGLE_OWNER \ + SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->debugSingleOwner());) + enum { kDefaultImageFilterCacheSize = 32 * 1024 * 1024 }; #if 0 @@ -171,13 +173,11 @@ SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkSurface::Budgeted budgete SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, int width, int height, const SkSurfaceProps* props, unsigned flags) : INHERITED(SkSurfacePropsCopyOrDefault(props)) -{ - fContext = SkRef(rt->getContext()); + , fContext(SkRef(rt->getContext())) + , fRenderTarget(SkRef(rt)) { fNeedClear = SkToBool(flags & kNeedClear_Flag); fOpaque = SkToBool(flags & kIsOpaque_Flag); - fRenderTarget = SkRef(rt); - SkAlphaType at = fOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; SkImageInfo info = rt->surfacePriv().info(at).makeWH(width, height); SkPixelRef* pr = new SkGrPixelRef(info, rt); @@ -226,15 +226,11 @@ GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::B return texture->asRenderTarget(); } -SkGpuDevice::~SkGpuDevice() { - fRenderTarget->unref(); - fContext->unref(); -} - /////////////////////////////////////////////////////////////////////////////// bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int x, int y) { + ASSERT_SINGLE_OWNER DO_DEFERRED_CLEAR(); // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels @@ -253,6 +249,7 @@ bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y) { + ASSERT_SINGLE_OWNER // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels GrPixelConfig config = SkImageInfo2GrPixelConfig(info); if (kUnknown_GrPixelConfig == config) { @@ -271,11 +268,13 @@ bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, siz } const SkBitmap& SkGpuDevice::onAccessBitmap() { + ASSERT_SINGLE_OWNER DO_DEFERRED_CLEAR(); return fLegacyBitmap; } bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) { + ASSERT_SINGLE_OWNER DO_DEFERRED_CLEAR(); // For compatibility with clients the know we're backed w/ a bitmap, and want to inspect its // genID. When we can hide/remove that fact, we can eliminate this call to notify. @@ -285,6 +284,7 @@ bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) { } void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) { + ASSERT_SINGLE_OWNER INHERITED::onAttachToCanvas(canvas); // Canvas promises that this ptr is valid until onDetachFromCanvas is called @@ -292,6 +292,7 @@ void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) { } void SkGpuDevice::onDetachFromCanvas() { + ASSERT_SINGLE_OWNER INHERITED::onDetachFromCanvas(); fClip.reset(); fClipStack.reset(nullptr); @@ -300,6 +301,7 @@ void SkGpuDevice::onDetachFromCanvas() { // call this every draw call, to ensure that the context reflects our state, // and not the state from some other canvas/device void SkGpuDevice::prepareDraw(const SkDraw& draw) { + ASSERT_SINGLE_OWNER SkASSERT(fClipStack.get()); SkASSERT(draw.fClipStack && draw.fClipStack == fClipStack); @@ -310,19 +312,22 @@ void SkGpuDevice::prepareDraw(const SkDraw& draw) { } GrRenderTarget* SkGpuDevice::accessRenderTarget() { + ASSERT_SINGLE_OWNER DO_DEFERRED_CLEAR(); return fRenderTarget; } void SkGpuDevice::clearAll() { + ASSERT_SINGLE_OWNER GrColor color = 0; - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::clearAll", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext); SkIRect rect = SkIRect::MakeWH(this->width(), this->height()); fDrawContext->clear(&rect, color, true); fNeedClear = false; } void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) { + ASSERT_SINGLE_OWNER // Caller must have accessed the render target, because it knows the rt must be replaced. SkASSERT(!fNeedClear); @@ -346,8 +351,7 @@ void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) { SkASSERT(fRenderTarget != newRT); - fRenderTarget->unref(); - fRenderTarget = newRT.detach(); + fRenderTarget.reset(newRT.detach()); #ifdef SK_DEBUG SkImageInfo info = fRenderTarget->surfacePriv().info(fOpaque ? kOpaque_SkAlphaType : @@ -363,8 +367,9 @@ void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) { /////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { + ASSERT_SINGLE_OWNER CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPaint", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext); GrPaint grPaint; if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { @@ -405,6 +410,8 @@ static bool needs_antialiasing(SkCanvas::PointMode mode, size_t count, const SkP void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { + ASSERT_SINGLE_OWNER + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext); CHECK_FOR_ANNOTATION(paint); CHECK_SHOULD_DRAW(draw); @@ -455,7 +462,8 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, /////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint& paint) { - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawRect", fContext); + ASSERT_SINGLE_OWNER + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext); CHECK_FOR_ANNOTATION(paint); CHECK_SHOULD_DRAW(draw); @@ -476,10 +484,6 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint usePath = true; } - if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) { - usePath = true; - } - if (usePath) { SkPath path; path.setIsVolatile(true); @@ -505,7 +509,8 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect, const SkPaint& paint) { - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawRRect", fContext); + ASSERT_SINGLE_OWNER + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext); CHECK_FOR_ANNOTATION(paint); CHECK_SHOULD_DRAW(draw); @@ -568,7 +573,8 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect, void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawDRRect", fContext); + ASSERT_SINGLE_OWNER + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext); CHECK_FOR_ANNOTATION(paint); CHECK_SHOULD_DRAW(draw); @@ -600,7 +606,8 @@ void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, ///////////////////////////////////////////////////////////////////////////// void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawOval", fContext); + ASSERT_SINGLE_OWNER + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext); CHECK_FOR_ANNOTATION(paint); CHECK_SHOULD_DRAW(draw); @@ -634,16 +641,10 @@ void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint /////////////////////////////////////////////////////////////////////////////// -static SkBitmap wrap_texture(GrTexture* texture, int width, int height) { - SkBitmap result; - result.setInfo(SkImageInfo::MakeN32Premul(width, height)); - result.setPixelRef(new SkGrPixelRef(result.info(), texture))->unref(); - return result; -} - void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) { + ASSERT_SINGLE_OWNER if (!origSrcPath.isInverseFillType() && !paint.getPathEffect() && !prePathMatrix) { bool isClosed; SkRect rect; @@ -664,7 +665,7 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, CHECK_FOR_ANNOTATION(paint); CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPath", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext); GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext, fClip, origSrcPath, paint, @@ -736,6 +737,7 @@ bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect, int maxTileSize, int* tileSize, SkIRect* clippedSubset) const { + ASSERT_SINGLE_OWNER // if it's larger than the max tile size, then we have no choice but tiling. if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) { determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, imageRect.size(), @@ -782,6 +784,7 @@ bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, int maxTileSize, int* tileSize, SkIRect* clippedSrcRect) const { + ASSERT_SINGLE_OWNER // if bitmap is explictly texture backed then just use the texture if (bitmap.getTexture()) { return false; @@ -794,6 +797,7 @@ bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr, SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality, const SkMatrix& viewMatrix) const { + ASSERT_SINGLE_OWNER // if image is explictly texture backed then just use the texture if (as_IB(image)->peekTexture()) { return false; @@ -828,15 +832,15 @@ void SkGpuDevice::drawBitmap(const SkDraw& origDraw, const SkBitmap& bitmap, const SkMatrix& m, const SkPaint& paint) { + ASSERT_SINGLE_OWNER CHECK_SHOULD_DRAW(origDraw); - bool alphaOnly = kAlpha_8_SkColorType == bitmap.colorType(); SkMatrix viewMatrix; viewMatrix.setConcat(*origDraw.fMatrix, m); if (bitmap.getTexture()) { GrBitmapTextureAdjuster adjuster(&bitmap); // We can use kFast here because we know texture-backed bitmaps don't support extractSubset. - this->drawTextureProducer(&adjuster, alphaOnly, nullptr, nullptr, - SkCanvas::kFast_SrcRectConstraint, viewMatrix, fClip, paint); + this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, + viewMatrix, fClip, paint); return; } int maxTileSize = fContext->caps()->maxTileSize(); @@ -881,8 +885,8 @@ void SkGpuDevice::drawBitmap(const SkDraw& origDraw, } } GrBitmapTextureMaker maker(fContext, bitmap); - this->drawTextureProducer(&maker, alphaOnly, nullptr, nullptr, - SkCanvas::kStrict_SrcRectConstraint, viewMatrix, fClip, paint); + this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kStrict_SrcRectConstraint, + viewMatrix, fClip, paint); } // This method outsets 'iRect' by 'outset' all around and then clamps its extents to @@ -929,6 +933,7 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, SkCanvas::SrcRectConstraint constraint, int tileSize, bool bicubic) { + ASSERT_SINGLE_OWNER // The following pixel lock is technically redundant, but it is desirable // to lock outside of the tile loop to prevent redecoding the whole image // at each tile in cases where 'bitmap' holds an SkDiscardablePixelRef that @@ -1121,13 +1126,15 @@ bool SkGpuDevice::filterTexture(GrContext* context, GrTexture* texture, const SkImageFilter* filter, const SkImageFilter::Context& ctx, SkBitmap* result, SkIPoint* offset) { + ASSERT_SINGLE_OWNER SkASSERT(filter); SkImageFilter::DeviceProxy proxy(this); if (filter->canFilterImageGPU()) { - return filter->filterImageGPU(&proxy, wrap_texture(texture, width, height), - ctx, result, offset); + SkBitmap bm; + GrWrapTextureInBitmap(texture, width, height, false, &bm); + return filter->filterImageGPU(&proxy, bm, ctx, result, offset); } else { return false; } @@ -1135,6 +1142,7 @@ bool SkGpuDevice::filterTexture(GrContext* context, GrTexture* texture, void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, int left, int top, const SkPaint& paint) { + ASSERT_SINGLE_OWNER // drawSprite is defined to be in device coords. CHECK_SHOULD_DRAW(draw); @@ -1163,11 +1171,15 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, SkIPoint offset = SkIPoint::Make(0, 0); SkMatrix matrix(*draw.fMatrix); matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top)); +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); +#else + SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-left, -top); +#endif SkAutoTUnref cache(getImageFilterCache()); // This cache is transient, and is freed (along with all its contained // textures) when it goes out of scope. - SkImageFilter::Context ctx(matrix, clipBounds, cache, SkImageFilter::kApprox_SizeConstraint); + SkImageFilter::Context ctx(matrix, clipBounds, cache); if (this->filterTexture(fContext, texture, w, h, filter, ctx, &filteredBitmap, &offset)) { texture = (GrTexture*) filteredBitmap.getTexture(); @@ -1210,12 +1222,12 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src, const SkRect& origDst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { + ASSERT_SINGLE_OWNER CHECK_SHOULD_DRAW(draw); - bool alphaOnly = kAlpha_8_SkColorType == bitmap.colorType(); if (bitmap.getTexture()) { GrBitmapTextureAdjuster adjuster(&bitmap); - this->drawTextureProducer(&adjuster, alphaOnly, src, &origDst, constraint, *draw.fMatrix, - fClip, paint); + this->drawTextureProducer(&adjuster, src, &origDst, constraint, *draw.fMatrix, fClip, + paint); return; } // The src rect is inferred to be the bmp bounds if not provided. Otherwise, the src rect must @@ -1292,13 +1304,14 @@ void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, } } GrBitmapTextureMaker maker(fContext, bitmap); - this->drawTextureProducer(&maker, alphaOnly, src, dst, constraint, *draw.fMatrix, fClip, paint); + this->drawTextureProducer(&maker, src, dst, constraint, *draw.fMatrix, fClip, paint); } void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, int x, int y, const SkPaint& paint) { + ASSERT_SINGLE_OWNER // clear of the source device must occur before CHECK_SHOULD_DRAW - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawDevice", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext); SkGpuDevice* dev = static_cast(device); // TODO: If the source device covers the whole of this device, we could @@ -1326,11 +1339,15 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, SkIPoint offset = SkIPoint::Make(0, 0); SkMatrix matrix(*draw.fMatrix); matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); +#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS SkIRect clipBounds = SkIRect::MakeWH(devTex->width(), devTex->height()); +#else + SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-x, -y); +#endif // This cache is transient, and is freed (along with all its contained // textures) when it goes out of scope. SkAutoTUnref cache(getImageFilterCache()); - SkImageFilter::Context ctx(matrix, clipBounds, cache, SkImageFilter::kApprox_SizeConstraint); + SkImageFilter::Context ctx(matrix, clipBounds, cache); if (this->filterTexture(fContext, devTex, device->width(), device->height(), filter, ctx, &filteredBitmap, &offset)) { devTex = filteredBitmap.getTexture(); @@ -1371,12 +1388,14 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, } bool SkGpuDevice::canHandleImageFilter(const SkImageFilter* filter) { + ASSERT_SINGLE_OWNER return filter->canFilterImageGPU(); } bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src, const SkImageFilter::Context& ctx, SkBitmap* result, SkIPoint* offset) { + ASSERT_SINGLE_OWNER // want explicitly our impl, so guard against a subclass of us overriding it if (!this->SkGpuDevice::canHandleImageFilter(filter)) { return false; @@ -1399,86 +1418,69 @@ bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src, filter, ctx, result, offset); } -static bool wrap_as_bm(GrContext* ctx, const SkImage* image, SkBitmap* bm) { - // TODO: It is wrong to assume these texture params here. - SkAutoTUnref tex(as_IB(image)->asTextureRef(ctx, GrTextureParams::ClampNoFilter())); - if (tex) { - GrWrapTextureInBitmap(tex, image->width(), image->height(), image->isOpaque(), bm); - return true; - } else { - return as_IB(image)->getROPixels(bm); - } -} - void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y, const SkPaint& paint) { - SkBitmap bm; - if (GrTexture* tex = as_IB(image)->peekTexture()) { + ASSERT_SINGLE_OWNER + SkMatrix viewMatrix = *draw.fMatrix; + viewMatrix.preTranslate(x, y); + if (as_IB(image)->peekTexture()) { CHECK_SHOULD_DRAW(draw); - SkMatrix viewMatrix = *draw.fMatrix; - viewMatrix.preTranslate(x, y); - bool alphaOnly = GrPixelConfigIsAlphaOnly(tex->config()); GrImageTextureAdjuster adjuster(as_IB(image)); - this->drawTextureProducer(&adjuster, alphaOnly, nullptr, nullptr, - SkCanvas::kFast_SrcRectConstraint, viewMatrix, fClip, paint); + this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, + viewMatrix, fClip, paint); return; } else { + SkBitmap bm; if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint, paint.getFilterQuality(), *draw.fMatrix)) { // only support tiling as bitmap at the moment, so force raster-version if (!as_IB(image)->getROPixels(&bm)) { return; } - } else { - if (!wrap_as_bm(this->context(), image, &bm)) { - return; - } + this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); + } else if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { + CHECK_SHOULD_DRAW(draw); + GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint); + this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, + viewMatrix, fClip, paint); + } else if (as_IB(image)->getROPixels(&bm)) { + this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); } } - this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); } void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { - if (GrTexture* tex = as_IB(image)->peekTexture()) { + ASSERT_SINGLE_OWNER + if (as_IB(image)->peekTexture()) { CHECK_SHOULD_DRAW(draw); GrImageTextureAdjuster adjuster(as_IB(image)); - bool alphaOnly = GrPixelConfigIsAlphaOnly(tex->config()); - this->drawTextureProducer(&adjuster, alphaOnly, src, &dst, constraint, *draw.fMatrix, - fClip, paint); + this->drawTextureProducer(&adjuster, src, &dst, constraint, *draw.fMatrix, fClip, paint); return; } SkBitmap bm; - SkMatrix viewMatrix = *draw.fMatrix; - viewMatrix.preScale(dst.width() / (src ? src->width() : image->width()), - dst.height() / (src ? src->height() : image->height())); - if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), viewMatrix)) { + SkMatrix totalMatrix = *draw.fMatrix; + totalMatrix.preScale(dst.width() / (src ? src->width() : image->width()), + dst.height() / (src ? src->height() : image->height())); + if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), totalMatrix)) { // only support tiling as bitmap at the moment, so force raster-version if (!as_IB(image)->getROPixels(&bm)) { return; } - } else { - if (!wrap_as_bm(this->context(), image, &bm)) { - return; - } + this->drawBitmapRect(draw, bm, src, dst, paint, constraint); + } else if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { + CHECK_SHOULD_DRAW(draw); + GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint); + this->drawTextureProducer(&maker, src, &dst, constraint, *draw.fMatrix, fClip, paint); + } else if (as_IB(image)->getROPixels(&bm)) { + this->drawBitmapRect(draw, bm, src, dst, paint, constraint); } - this->drawBitmapRect(draw, bm, src, dst, paint, constraint); } -void SkGpuDevice::drawImageNine(const SkDraw& draw, const SkImage* image, - const SkIRect& center, const SkRect& dst, const SkPaint& paint) { - // TODO write native implementation - SkBitmap bitmap; - if (!wrap_as_bm(this->context(), image, &bitmap)) { - return; - } - return this->drawBitmapNine(draw, bitmap, center, dst, paint); -} - -void SkGpuDevice::drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, const SkIRect& center, - const SkRect& dst, const SkPaint& paint) { - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawBitmapNine", fContext); +void SkGpuDevice::drawProducerNine(const SkDraw& draw, GrTextureProducer* producer, + const SkIRect& center, const SkRect& dst, const SkPaint& paint) { + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerNine", fContext); CHECK_FOR_ANNOTATION(paint); CHECK_SHOULD_DRAW(draw); @@ -1487,42 +1489,62 @@ void SkGpuDevice::drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, con fRenderTarget->isUnifiedMultisampled(); bool doBicubic; GrTextureParams::FilterMode textureFilterMode = - GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), *draw.fMatrix, SkMatrix::I(), - &doBicubic); - - // TODO handle bilerp(vie texture domains), MSAA(via snapping) + GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), *draw.fMatrix, SkMatrix::I(), + &doBicubic); if (useFallback || doBicubic || GrTextureParams::kNone_FilterMode != textureFilterMode) { - SkNinePatchIter iter(bitmap.width(), bitmap.height(), center, dst); + SkNinePatchIter iter(producer->width(), producer->height(), center, dst); SkRect srcR, dstR; while (iter.next(&srcR, &dstR)) { - this->drawBitmapRect(draw, bitmap, &srcR, dstR, paint, - SkCanvas::kStrict_SrcRectConstraint); + this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint, + *draw.fMatrix, fClip, paint); } return; } - GrTextureParams params = GrTextureParams::ClampNoFilter(); - - SkAutoTUnref texture(GrRefCachedBitmapTexture(this->context(), bitmap, params)); - if (nullptr == texture) { - return; - } - - SkMatrix texMatrix; - texMatrix.setIDiv(texture->width(), texture->height()); - - SkAutoTUnref fp(GrSimpleTextureEffect::Create(texture, texMatrix, - params)); - + static const GrTextureParams::FilterMode kMode = GrTextureParams::kNone_FilterMode; + SkAutoTUnref fp( + producer->createFragmentProcessor(SkMatrix::I(), + SkRect::MakeIWH(producer->width(), producer->height()), + GrTextureProducer::kNo_FilterConstraint, true, + &kMode)); GrPaint grPaint; if (!SkPaintToGrPaintWithTexture(this->context(), paint, *draw.fMatrix, fp, - kAlpha_8_SkColorType == bitmap.colorType(), &grPaint)) { + producer->isAlphaOnly(), &grPaint)) { return; } - fDrawContext->drawImageNine(fClip, grPaint, *draw.fMatrix, bitmap.width(), bitmap.height(), - center, dst); + fDrawContext->drawImageNine(fClip, grPaint, *draw.fMatrix, producer->width(), + producer->height(), center, dst); +} + +void SkGpuDevice::drawImageNine(const SkDraw& draw, const SkImage* image, + const SkIRect& center, const SkRect& dst, const SkPaint& paint) { + ASSERT_SINGLE_OWNER + if (as_IB(image)->peekTexture()) { + GrImageTextureAdjuster adjuster(as_IB(image)); + this->drawProducerNine(draw, &adjuster, center, dst, paint); + } else { + SkBitmap bm; + if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { + GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint); + this->drawProducerNine(draw, &maker, center, dst, paint); + } else if (as_IB(image)->getROPixels(&bm)) { + this->drawBitmapNine(draw, bm, center, dst, paint); + } + } +} + +void SkGpuDevice::drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, const SkIRect& center, + const SkRect& dst, const SkPaint& paint) { + ASSERT_SINGLE_OWNER + if (bitmap.getTexture()) { + GrBitmapTextureAdjuster adjuster(&bitmap); + this->drawProducerNine(draw, &adjuster, center, dst, paint); + } else { + GrBitmapTextureMaker maker(fContext, bitmap); + this->drawProducerNine(draw, &maker, center, dst, paint); + } } /////////////////////////////////////////////////////////////////////////////// @@ -1540,8 +1562,9 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, SkXfermode* xmode, const uint16_t indices[], int indexCount, const SkPaint& paint) { + ASSERT_SINGLE_OWNER CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawVertices", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext); // If both textures and vertex-colors are nullptr, strokes hairlines with the paint's color. if ((nullptr == texs || nullptr == paint.getShader()) && nullptr == colors) { @@ -1667,13 +1690,14 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, void SkGpuDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRSXform xform[], const SkRect texRect[], const SkColor colors[], int count, SkXfermode::Mode mode, const SkPaint& paint) { + ASSERT_SINGLE_OWNER if (paint.isAntiAlias()) { this->INHERITED::drawAtlas(draw, atlas, xform, texRect, colors, count, mode, paint); return; } CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawText", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext); SkPaint p(paint); p.setShader(atlas->newShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref(); @@ -1699,8 +1723,9 @@ void SkGpuDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRS void SkGpuDevice::drawText(const SkDraw& draw, const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { + ASSERT_SINGLE_OWNER CHECK_SHOULD_DRAW(draw); - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawText", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext); GrPaint grPaint; if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { @@ -1716,7 +1741,8 @@ void SkGpuDevice::drawText(const SkDraw& draw, const void* text, void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, size_t byteLength, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPosText", fContext); + ASSERT_SINGLE_OWNER + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPosText", fContext); CHECK_SHOULD_DRAW(draw); GrPaint grPaint; @@ -1733,7 +1759,8 @@ void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, size_t byteL void SkGpuDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint, SkDrawFilter* drawFilter) { - GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawTextBlob", fContext); + ASSERT_SINGLE_OWNER + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawTextBlob", fContext); CHECK_SHOULD_DRAW(draw); SkDEBUGCODE(this->validate();) @@ -1749,13 +1776,23 @@ bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const { } void SkGpuDevice::flush() { + ASSERT_SINGLE_OWNER DO_DEFERRED_CLEAR(); + + // Clear batch debugging output + // TODO not exactly sure where this should live + if (GR_BATCH_DEBUGGING_OUTPUT) { + SkDebugf("%s\n", fContext->getAuditTrail()->toJson().c_str()); + // TODO This currently crashes because not all ops are accounted for + GR_AUDIT_TRAIL_RESET(fContext->getAuditTrail()); + } fRenderTarget->prepareForExternalIO(); } /////////////////////////////////////////////////////////////////////////////// SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) { + ASSERT_SINGLE_OWNER GrSurfaceDesc desc; desc.fConfig = fRenderTarget->config(); desc.fFlags = kRenderTarget_GrSurfaceFlag; @@ -1788,6 +1825,7 @@ SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint } SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) { + ASSERT_SINGLE_OWNER // TODO: Change the signature of newSurface to take a budgeted parameter. static const SkSurface::Budgeted kBudgeted = SkSurface::kNo_Budgeted; return SkSurface::NewRenderTarget(fContext, kBudgeted, info, fRenderTarget->desc().fSampleCnt, @@ -1796,6 +1834,7 @@ SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* mainPicture, const SkMatrix* matrix, const SkPaint* paint) { + ASSERT_SINGLE_OWNER #ifndef SK_IGNORE_GPU_LAYER_HOISTING // todo: should handle this natively if (paint) { @@ -1869,6 +1908,7 @@ SkImageFilter::Cache* SkGpuDevice::NewImageFilterCache() { } SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() { + ASSERT_SINGLE_OWNER // We always return a transient cache, so it is freed after each // filter traversal. return SkGpuDevice::NewImageFilterCache(); diff --git a/gfx/skia/skia/src/gpu/SkGpuDevice.h b/gfx/skia/skia/src/gpu/SkGpuDevice.h index 5bf074d1203..19bef210381 100644 --- a/gfx/skia/skia/src/gpu/SkGpuDevice.h +++ b/gfx/skia/skia/src/gpu/SkGpuDevice.h @@ -15,6 +15,7 @@ #include "SkPicture.h" #include "SkRegion.h" #include "SkSurface.h" +#include "GrDrawContext.h" #include "GrContext.h" #include "GrSurfacePriv.h" @@ -53,7 +54,7 @@ public: static SkGpuDevice* Create(GrContext*, SkSurface::Budgeted, const SkImageInfo&, int sampleCount, const SkSurfaceProps*, InitContents); - virtual ~SkGpuDevice(); + ~SkGpuDevice() override {} SkGpuDevice* cloneDevice(const SkSurfaceProps& props) { SkBaseDevice* dev = this->onCreateDevice(CreateInfo(this->imageInfo(), kPossible_TileUsage, @@ -140,6 +141,9 @@ public: static SkImageFilter::Cache* NewImageFilterCache(); + // for debugging purposes only + void drawTexture(GrTexture*, const SkRect& dst, const SkPaint&); + protected: bool onReadPixels(const SkImageInfo&, void*, size_t, int, int) override; bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) override; @@ -150,12 +154,14 @@ protected: const SkMatrix*, const SkPaint*) override; private: - GrContext* fContext; + // We want these unreffed in DrawContext, RenderTarget, GrContext order. + SkAutoTUnref fContext; + SkAutoTUnref fRenderTarget; + SkAutoTUnref fDrawContext; + SkAutoTUnref fClipStack; SkIPoint fClipOrigin; - GrClip fClip; - SkAutoTUnref fDrawContext; - GrRenderTarget* fRenderTarget; + GrClip fClip;; // remove when our clients don't rely on accessBitmap() SkBitmap fLegacyBitmap; bool fNeedClear; @@ -228,7 +234,6 @@ private: bool bicubic); void drawTextureProducer(GrTextureProducer*, - bool alphaOnly, const SkRect* srcRect, const SkRect* dstRect, SkCanvas::SrcRectConstraint, @@ -237,7 +242,6 @@ private: const SkPaint&); void drawTextureProducerImpl(GrTextureProducer*, - bool alphaOnly, const SkRect& clippedSrcRect, const SkRect& clippedDstRect, SkCanvas::SrcRectConstraint, @@ -246,6 +250,9 @@ private: const GrClip&, const SkPaint&); + void drawProducerNine(const SkDraw&, GrTextureProducer*, const SkIRect& center, + const SkRect& dst, const SkPaint&); + bool drawDashLine(const SkPoint pts[2], const SkPaint& paint); static GrRenderTarget* CreateRenderTarget(GrContext*, SkSurface::Budgeted, const SkImageInfo&, diff --git a/gfx/skia/skia/src/gpu/SkGpuDevice_drawTexture.cpp b/gfx/skia/skia/src/gpu/SkGpuDevice_drawTexture.cpp index 0b1d3f1f08a..efbc6c98d59 100644 --- a/gfx/skia/skia/src/gpu/SkGpuDevice_drawTexture.cpp +++ b/gfx/skia/skia/src/gpu/SkGpuDevice_drawTexture.cpp @@ -88,7 +88,6 @@ static bool can_ignore_bilerp_constraint(const GrTextureProducer& producer, ////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::drawTextureProducer(GrTextureProducer* producer, - bool alphaOnly, const SkRect* srcRect, const SkRect* dstRect, SkCanvas::SrcRectConstraint constraint, @@ -135,12 +134,11 @@ void SkGpuDevice::drawTextureProducer(GrTextureProducer* producer, } } - this->drawTextureProducerImpl(producer, alphaOnly, clippedSrcRect, clippedDstRect, constraint, - viewMatrix, srcToDstMatrix, clip, paint); + this->drawTextureProducerImpl(producer, clippedSrcRect, clippedDstRect, constraint, viewMatrix, + srcToDstMatrix, clip, paint); } void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, - bool alphaTexture, const SkRect& clippedSrcRect, const SkRect& clippedDstRect, SkCanvas::SrcRectConstraint constraint, @@ -156,7 +154,7 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, // The shader expects proper local coords, so we can't replace local coords with texture coords // if the shader will be used. If we have a mask filter we will change the underlying geometry // that is rendered. - bool canUseTextureCoordsAsLocalCoords = !use_shader(alphaTexture, paint) && !mf; + bool canUseTextureCoordsAsLocalCoords = !use_shader(producer->isAlphaOnly(), paint) && !mf; bool doBicubic; GrTextureParams::FilterMode fm = @@ -204,7 +202,8 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, } GrPaint grPaint; - if (!SkPaintToGrPaintWithTexture(fContext, paint, viewMatrix, fp, alphaTexture, &grPaint)) { + if (!SkPaintToGrPaintWithTexture(fContext, paint, viewMatrix, fp, producer->isAlphaOnly(), + &grPaint)) { return; } diff --git a/gfx/skia/skia/src/gpu/SkGrPixelRef.cpp b/gfx/skia/skia/src/gpu/SkGrPixelRef.cpp index ad4f33f7d9e..de585b87e48 100644 --- a/gfx/skia/skia/src/gpu/SkGrPixelRef.cpp +++ b/gfx/skia/skia/src/gpu/SkGrPixelRef.cpp @@ -25,7 +25,7 @@ SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {} bool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) { fBitmap.reset(); // SkDebugf("---------- calling readpixels in support of lockpixels\n"); - if (!this->onReadPixels(&fBitmap, nullptr)) { + if (!this->onReadPixels(&fBitmap, this->info().colorType(), nullptr)) { SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n"); return false; } @@ -156,11 +156,20 @@ static bool tryAllocBitmapPixels(SkBitmap* bitmap) { } } -bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { +bool SkGrPixelRef::onReadPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subset) { if (nullptr == fSurface || fSurface->wasDestroyed()) { return false; } + GrPixelConfig config; + if (kRGBA_8888_SkColorType == colorType) { + config = kRGBA_8888_GrPixelConfig; + } else if (kBGRA_8888_SkColorType == colorType) { + config = kBGRA_8888_GrPixelConfig; + } else { + return false; + } + SkIRect bounds; if (subset) { bounds = *subset; @@ -173,7 +182,9 @@ bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { //Cache miss SkBitmap cachedBitmap; - cachedBitmap.setInfo(this->info().makeWH(bounds.width(), bounds.height())); + cachedBitmap.setInfo(SkImageInfo::Make(bounds.width(), bounds.height(), colorType, + this->info().alphaType(), + this->info().profileType())); // If we can't alloc the pixels, then fail if (!tryAllocBitmapPixels(&cachedBitmap)) { @@ -184,8 +195,7 @@ bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { void* buffer = cachedBitmap.getPixels(); bool readPixelsOk = fSurface->readPixels(bounds.fLeft, bounds.fTop, bounds.width(), bounds.height(), - kSkia8888_GrPixelConfig, - buffer, cachedBitmap.rowBytes()); + config, buffer, cachedBitmap.rowBytes()); if (!readPixelsOk) { return false; diff --git a/gfx/skia/skia/src/gpu/batches/GrAAConvexPathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrAAConvexPathRenderer.cpp index c5b7c579b7e..9fde34c186e 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAAConvexPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrAAConvexPathRenderer.cpp @@ -25,10 +25,12 @@ #include "SkString.h" #include "SkTraceEvent.h" #include "batches/GrVertexBatch.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" +#include "glsl/GrGLSLVertexShaderBuilder.h" GrAAConvexPathRenderer::GrAAConvexPathRenderer() { } @@ -549,9 +551,9 @@ public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const QuadEdgeEffect& qe = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(qe); @@ -563,16 +565,17 @@ public: GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (!qe.colorIgnored()) { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, + &fColorUniform); } // Setup position - this->setupPosition(pb, vertBuilder, gpArgs, qe.inPosition()->fName); + this->setupPosition(vertBuilder, gpArgs, qe.inPosition()->fName); // emit transforms - this->emitTransforms(args.fPB, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, qe.inPosition()->fName, qe.localMatrix(), @@ -999,6 +1002,7 @@ private: }; bool GrAAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrAAConvexPathRenderer::onDrawPath"); if (args.fPath->isEmpty()) { return true; } diff --git a/gfx/skia/skia/src/gpu/batches/GrAAConvexTessellator.cpp b/gfx/skia/skia/src/gpu/batches/GrAAConvexTessellator.cpp index efbcebb6bd7..c3d25948dee 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAAConvexTessellator.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrAAConvexTessellator.cpp @@ -840,7 +840,7 @@ void GrAAConvexTessellator::lineTo(SkPoint p, bool isCurve) { // floating point precision issues mean it can actually happen on paths that were determined // to be convex. if (duplicate_pt(p, this->lastPoint())) { - return; + return; } } SkScalar initialRingCoverage = fStrokeWidth < 0.0f ? 0.5f : 1.0f; diff --git a/gfx/skia/skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp index 0b14e4df4ec..e94cd591f3e 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp @@ -142,13 +142,13 @@ public: // in fPath since that path may have resulted from a SkStrokeRec::applyToPath call. uint32_t fGenID; SkStrokeRec fStroke; + GrColor fColor; bool fAntiAlias; }; - static GrDrawBatch* Create(const Geometry& geometry, GrColor color, const SkMatrix& viewMatrix, + static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix, GrBatchAtlas* atlas, PathCache* pathCache, PathDataList* pathList) { - return new AADistanceFieldPathBatch(geometry, color, viewMatrix, atlas, pathCache, - pathList); + return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, pathCache, pathList); } const char* name() const override { return "AADistanceFieldPathBatch"; } @@ -156,7 +156,7 @@ public: void computePipelineOptimizations(GrInitInvariantOutput* color, GrInitInvariantOutput* coverage, GrBatchToXPOverrides* overrides) const override { - color->setKnownFourComponents(fBatch.fColor); + color->setKnownFourComponents(fGeoData[0].fColor); coverage->setUnknownSingleComponent(); overrides->fUsePLSDstRead = false; } @@ -165,9 +165,9 @@ private: void initBatchTracker(const GrXPOverridesForBatch& overrides) override { // Handle any color overrides if (!overrides.readsColor()) { - fBatch.fColor = GrColor_ILLEGAL; + fGeoData[0].fColor = GrColor_ILLEGAL; } - overrides.getOverrideColorIfSet(&fBatch.fColor); + overrides.getOverrideColorIfSet(&fGeoData[0].fColor); // setup batch properties fBatch.fColorIgnored = !overrides.readsColor(); @@ -212,7 +212,7 @@ private: // allocate vertices size_t vertexStride = dfProcessor->getVertexStride(); - SkASSERT(vertexStride == 2 * sizeof(SkPoint)); + SkASSERT(vertexStride == 2 * sizeof(SkPoint) + sizeof(GrColor)); const GrVertexBuffer* vertexBuffer; void* vertices = target->makeVertexSpace(vertexStride, @@ -278,12 +278,12 @@ private: // Now set vertices intptr_t offset = reinterpret_cast(vertices); offset += i * kVerticesPerQuad * vertexStride; - SkPoint* positions = reinterpret_cast(offset); this->writePathVertices(target, atlas, this->pipeline(), dfProcessor, - positions, + offset, + args.fColor, vertexStride, this->viewMatrix(), args.fPath, @@ -296,11 +296,11 @@ private: SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } - AADistanceFieldPathBatch(const Geometry& geometry, GrColor color, const SkMatrix& viewMatrix, + AADistanceFieldPathBatch(const Geometry& geometry, + const SkMatrix& viewMatrix, GrBatchAtlas* atlas, PathCache* pathCache, PathDataList* pathList) : INHERITED(ClassID()) { - fBatch.fColor = color; fBatch.fViewMatrix = viewMatrix; fGeoData.push_back(geometry); @@ -342,9 +342,15 @@ private: SkIRect devPathBounds; scaledBounds.roundOut(&devPathBounds); // pad to allow room for antialiasing - devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt(kAntiAliasPad)); - // move origin to upper left corner - devPathBounds.offsetTo(0,0); + const int intPad = SkScalarCeilToInt(kAntiAliasPad); + // pre-move origin (after outset, will be 0,0) + int width = devPathBounds.width(); + int height = devPathBounds.height(); + devPathBounds.fLeft = intPad; + devPathBounds.fTop = intPad; + devPathBounds.fRight = intPad + width; + devPathBounds.fBottom = intPad + height; + devPathBounds.outset(intPad, intPad); // draw path to bitmap SkMatrix drawMatrix; @@ -381,8 +387,8 @@ private: // generate signed distance field devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); - int width = devPathBounds.width(); - int height = devPathBounds.height(); + width = devPathBounds.width(); + height = devPathBounds.height(); // TODO We should really generate this directly into the plot somehow SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); @@ -437,7 +443,8 @@ private: GrBatchAtlas* atlas, const GrPipeline* pipeline, const GrGeometryProcessor* gp, - SkPoint* positions, + intptr_t offset, + GrColor color, size_t vertexStride, const SkMatrix& viewMatrix, const SkPath& path, @@ -460,13 +467,21 @@ private: SkFixed tw = SkScalarToFixed(pathData->fBounds.width()); SkFixed th = SkScalarToFixed(pathData->fBounds.height()); + SkPoint* positions = reinterpret_cast(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; + } + // vertex texture coords - SkPoint* textureCoords = positions + 1; + SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(GrColor)); textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)), SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)), SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)), @@ -485,7 +500,7 @@ private: flushInfo->fInstancesToFlush = 0; } - GrColor color() const { return fBatch.fColor; } + GrColor color() const { return fGeoData[0].fColor; } const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } @@ -496,12 +511,7 @@ private: return false; } - // TODO we could actually probably do a bunch of this work on the CPU, ie map viewMatrix, - // maybe upload color via attribute - if (this->color() != that->color()) { - return false; - } - + // TODO We can position on the cpu if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { return false; } @@ -512,7 +522,6 @@ private: } struct BatchTracker { - GrColor fColor; SkMatrix fViewMatrix; bool fUsesLocalCoords; bool fColorIgnored; @@ -529,6 +538,8 @@ private: }; bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), + "GrAADistanceFieldPathRenderer::onDrawPath"); // we've already bailed on inverse filled paths, so this is safe if (args.fPath->isEmpty()) { return true; @@ -551,13 +562,14 @@ bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) { } else { args.fStroke->applyToPath(&geometry.fPath, *args.fPath); } + geometry.fColor = args.fColor; geometry.fAntiAlias = args.fAntiAlias; // Note: this is the generation ID of the _original_ path. When a new path is // generated due to stroking it is important that the original path's id is used // for caching. geometry.fGenID = args.fPath->getGenerationID(); - SkAutoTUnref batch(AADistanceFieldPathBatch::Create(geometry, args.fColor, + SkAutoTUnref batch(AADistanceFieldPathBatch::Create(geometry, *args.fViewMatrix, fAtlas, &fPathCache, &fPathList)); args.fTarget->drawBatch(*args.fPipelineBuilder, batch); @@ -629,11 +641,12 @@ DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) { GrColor color = GrRandomColor(random); AADistanceFieldPathBatch::Geometry geometry(GrTest::TestStrokeRec(random)); + geometry.fColor = color; geometry.fPath = GrTest::TestPath(random); geometry.fAntiAlias = random->nextBool(); geometry.fGenID = random->nextU(); - return AADistanceFieldPathBatch::Create(geometry, color, viewMatrix, + return AADistanceFieldPathBatch::Create(geometry, viewMatrix, gTestStruct.fAtlas, &gTestStruct.fPathCache, &gTestStruct.fPathList); diff --git a/gfx/skia/skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp index d6ad9d32c9c..6b7b3089000 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp @@ -974,6 +974,7 @@ static GrDrawBatch* create_hairline_batch(GrColor color, } bool GrAAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),"GrAAHairlinePathRenderer::onDrawPath"); SkIRect devClipBounds; GrRenderTarget* rt = args.fPipelineBuilder->getRenderTarget(); args.fPipelineBuilder->clip().getConservativeBounds(rt->width(), rt->height(), &devClipBounds); diff --git a/gfx/skia/skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp index 4b03c5a3f62..c830509a2a5 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp @@ -25,7 +25,6 @@ #include "SkPathPriv.h" #include "batches/GrVertexBatch.h" #include "glsl/GrGLSLGeometryProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" static const int DEFAULT_BUFFER_SIZE = 100; @@ -54,7 +53,7 @@ bool GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& arg } SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * args.fStroke->getWidth(); return strokeWidth >= 1.0f && strokeWidth <= kMaxStrokeWidth && !args.fStroke->isDashed() && - SkPathPriv::LastVerbIsClose(*args.fPath) && + SkPathPriv::IsClosedSingleContour(*args.fPath) && args.fStroke->getJoin() != SkPaint::Join::kRound_Join; } return args.fStroke->getStyle() == SkStrokeRec::kFill_Style; @@ -323,6 +322,8 @@ private: }; bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), + "GrAALinearizingConvexPathRenderer::onDrawPath"); if (args.fPath->isEmpty()) { return true; } diff --git a/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.cpp b/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.cpp index fa34036af6e..11b35c196b2 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.cpp @@ -7,7 +7,6 @@ #include "GrAtlasTextBatch.h" -#include "GrBatchFontCache.h" #include "GrBatchFlushState.h" #include "GrBatchTest.h" #include "GrResourceProvider.h" @@ -17,6 +16,7 @@ #include "effects/GrBitmapTextGeoProc.h" #include "effects/GrDistanceFieldGeoProc.h" +#include "text/GrBatchFontCache.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // A large template to handle regenerating the vertices of a textblob with as few branches as @@ -135,7 +135,7 @@ inline void GrAtlasTextBatch::regenBlob(Target* target, FlushInfo* flushInfo, Bl static_assert(!regenGlyphs || regenTexCoords, "must regenTexCoords along regenGlyphs"); GrBatchTextStrike* strike = nullptr; if (regenTexCoords) { - info->fBulkUseToken.reset(); + info->resetBulkUseToken(); // We can reuse if we have a valid strike and our descriptors / typeface are the // same. The override descriptor is only for the non distance field text within @@ -151,14 +151,14 @@ inline void GrAtlasTextBatch::regenBlob(Target* target, FlushInfo* flushInfo, Bl *desc = newDesc; *cache = SkGlyphCache::DetachCache(run->fTypeface, *desc); *scaler = GrTextContext::GetGrFontScaler(*cache); - strike = info->fStrike; + strike = info->strike(); *typeface = run->fTypeface; } if (regenGlyphs) { strike = fFontCache->getStrike(*scaler); } else { - strike = info->fStrike; + strike = info->strike(); } } @@ -166,7 +166,7 @@ inline void GrAtlasTextBatch::regenBlob(Target* target, FlushInfo* flushInfo, Bl for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) { GrGlyph* glyph = nullptr; if (regenTexCoords) { - size_t glyphOffset = glyphIdx + info->fGlyphStartIndex; + size_t glyphOffset = glyphIdx + info->glyphStartIndex(); if (regenGlyphs) { // Get the id from the old glyph, and use the new strike to lookup @@ -190,12 +190,12 @@ inline void GrAtlasTextBatch::regenBlob(Target* target, FlushInfo* flushInfo, Bl this->maskFormat()); SkASSERT(success); } - fFontCache->addGlyphToBulkAndSetUseToken(&info->fBulkUseToken, glyph, + fFontCache->addGlyphToBulkAndSetUseToken(info->bulkUseToken(), glyph, target->currentToken()); } intptr_t vertex = reinterpret_cast(blob->fVertices); - vertex += info->fVertexStartIndex; + vertex += info->vertexStartIndex(); vertex += vertexStride * glyphIdx * GrAtlasTextBatch::kVerticesPerGlyph; regen_vertices(vertex, glyph, vertexStride, this->usesDistanceFields(), transX, @@ -203,14 +203,14 @@ inline void GrAtlasTextBatch::regenBlob(Target* target, FlushInfo* flushInfo, Bl flushInfo->fGlyphsToFlush++; } - // We my have changed the color so update it here - run->fColor = color; + // We may have changed the color so update it here + info->setColor(color); if (regenTexCoords) { if (regenGlyphs) { - info->fStrike.reset(SkRef(strike)); + info->setStrike(strike); } - info->fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAtlasGeneration : - fFontCache->atlasGeneration(this->maskFormat()); + info->setAtlasGeneration(brokenRun ? GrBatchAtlas::kInvalidAtlasGeneration : + fFontCache->atlasGeneration(this->maskFormat())); } } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -312,12 +312,10 @@ void GrAtlasTextBatch::onPrepareDraws(Target* target) const { return; } - bool usesDistanceFields = this->usesDistanceFields(); GrMaskFormat maskFormat = this->maskFormat(); - bool isLCD = this->isLCD(); SkAutoTUnref gp; - if (usesDistanceFields) { + if (this->usesDistanceFields()) { gp.reset(this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(), texture)); } else { @@ -333,9 +331,7 @@ void GrAtlasTextBatch::onPrepareDraws(Target* target) const { FlushInfo flushInfo; flushInfo.fGlyphsToFlush = 0; size_t vertexStride = gp->getVertexStride(); - SkASSERT(vertexStride == (usesDistanceFields ? - GetVertexStrideDf(maskFormat, isLCD) : - GetVertexStride(maskFormat))); + SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat)); target->initDraw(gp, this->pipeline()); @@ -378,17 +374,13 @@ void GrAtlasTextBatch::onPrepareDraws(Target* target) const { // new strike, we instead keep our ref to the old strike and use the packed ids from // it. These ids will still be valid as long as we hold the ref. When we are done // updating our cache of the GrGlyph*s, we drop our ref on the old strike - bool regenerateGlyphs = info.fStrike->isAbandoned(); - bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen || + bool regenerateGlyphs = info.strike()->isAbandoned(); + bool regenerateTextureCoords = info.atlasGeneration() != currentAtlasGen || regenerateGlyphs; - bool regenerateColors; - if (usesDistanceFields) { - regenerateColors = !isLCD && run.fColor != args.fColor; - } else { - regenerateColors = kA8_GrMaskFormat == maskFormat && run.fColor != args.fColor; - } + bool regenerateColors = kARGB_GrMaskFormat != maskFormat && + info.color() != args.fColor; bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.f; - int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; + int glyphCount = info.glyphCount(); uint32_t regenMaskBits = kNoRegen; regenMaskBits |= regeneratePositions ? kRegenPos : 0; @@ -416,13 +408,14 @@ void GrAtlasTextBatch::onPrepareDraws(Target* target) const { // set use tokens for all of the glyphs in our subrun. This is only valid if we // have a valid atlas generation - fFontCache->setUseTokenBulk(info.fBulkUseToken, target->currentToken(), maskFormat); + fFontCache->setUseTokenBulk(*info.bulkUseToken(), target->currentToken(), + maskFormat); break; } // now copy all vertices - size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex; - memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCount); + size_t byteCount = info.byteCount(); + memcpy(currVertex, blob->fVertices + info.vertexStartIndex(), byteCount); currVertex += byteCount; } @@ -458,9 +451,7 @@ bool GrAtlasTextBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { } if (!this->usesDistanceFields()) { - // TODO we can often batch across LCD text if we have dual source blending and don't - // have to use the blend constant - if (kGrayscaleCoverageMask_MaskType != fMaskType && this->color() != that->color()) { + if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) { return false; } if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { @@ -478,11 +469,6 @@ bool GrAtlasTextBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { if (fUseBGR != that->fUseBGR) { return false; } - - // TODO see note above - if (kLCDDistanceField_MaskType == fMaskType && this->color() != that->color()) { - return false; - } } fBatch.fNumGlyphs += that->numGlyphs(); @@ -551,7 +537,6 @@ GrGeometryProcessor* GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatr flags, this->usesLocalCoords()); } else { - flags |= kColorAttr_DistanceFieldEffectFlag; #ifdef SK_GAMMA_APPLY_TO_A8 U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor); float correction = (*fDistanceAdjustTable)[lum >> kDistanceAdjustLumShift]; diff --git a/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.h b/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.h index 65fd07d7bb1..8f20313378c 100644 --- a/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.h +++ b/gfx/skia/skia/src/gpu/batches/GrAtlasTextBatch.h @@ -10,20 +10,16 @@ #include "batches/GrVertexBatch.h" -#include "GrAtlasTextContext.h" +#include "text/GrAtlasTextContext.h" +#include "text/GrDistanceFieldAdjustTable.h" class GrAtlasTextBatch : public GrVertexBatch { public: DEFINE_BATCH_CLASS_ID - static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); - // position + local coord - static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); - static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16); - static const int kVerticesPerGlyph = 4; + static const int kVerticesPerGlyph = GrAtlasTextBlob::kVerticesPerGlyph; static const int kIndicesPerGlyph = 6; - typedef GrAtlasTextContext::DistanceAdjustTable DistanceAdjustTable; typedef GrAtlasTextBlob Blob; typedef Blob::Run Run; typedef Run::SubRunInfo TextInfo; @@ -60,10 +56,11 @@ public: return batch; } - static GrAtlasTextBatch* CreateDistanceField(int glyphCount, GrBatchFontCache* fontCache, - const DistanceAdjustTable* distanceAdjustTable, - SkColor filteredColor, bool isLCD, - bool useBGR) { + static GrAtlasTextBatch* CreateDistanceField( + int glyphCount, GrBatchFontCache* fontCache, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + SkColor filteredColor, bool isLCD, + bool useBGR) { GrAtlasTextBatch* batch = new GrAtlasTextBatch; batch->fFontCache = fontCache; @@ -89,7 +86,7 @@ public: // We don't yet position distance field text on the cpu, so we have to map the vertex bounds // into device space const Run& run = geo.fBlob->fRuns[geo.fRun]; - if (run.fSubRunInfo[geo.fSubRun].fDrawAsDistanceFields) { + if (run.fSubRunInfo[geo.fSubRun].drawAsDistanceFields()) { SkRect bounds = run.fVertexBounds; fBatch.fViewMatrix.mapRect(&bounds); this->setBounds(bounds); @@ -102,26 +99,6 @@ public: SkString dumpInfo() const override; - static size_t GetVertexStride(GrMaskFormat maskFormat) { - switch (maskFormat) { - case kA8_GrMaskFormat: - return kGrayTextVASize; - case kARGB_GrMaskFormat: - return kColorTextVASize; - default: - return kLCDTextVASize; - } - } - - static size_t GetVertexStrideDf(GrMaskFormat maskFormat, bool useLCDText) { - SkASSERT(maskFormat == kA8_GrMaskFormat); - if (useLCDText) { - return kLCDTextVASize; - } else { - return kGrayTextVASize; - } - } - protected: void computePipelineOptimizations(GrInitInvariantOutput* color, GrInitInvariantOutput* coverage, @@ -220,7 +197,7 @@ private: GrBatchFontCache* fFontCache; // Distance field properties - SkAutoTUnref fDistanceAdjustTable; + SkAutoTUnref fDistanceAdjustTable; SkColor fFilteredColor; typedef GrVertexBatch INHERITED; diff --git a/gfx/skia/skia/src/gpu/batches/GrBatch.h b/gfx/skia/skia/src/gpu/batches/GrBatch.h index 03e396a29c2..a66d6ae308d 100644 --- a/gfx/skia/skia/src/gpu/batches/GrBatch.h +++ b/gfx/skia/skia/src/gpu/batches/GrBatch.h @@ -16,6 +16,7 @@ class GrCaps; class GrBatchFlushState; +class GrRenderTarget; /** * GrBatch is the base class for all Ganesh deferred geometry generators. To facilitate @@ -113,6 +114,9 @@ public: /** Used for spewing information about batches when debugging. */ virtual SkString dumpInfo() const = 0; + /** Can remove this when multi-draw-buffer lands */ + virtual GrRenderTarget* renderTarget() const = 0; + protected: // NOTE, compute some bounds, even if extremely conservative. Do *NOT* setLargest on the bounds // rect because we outset it for dst copy textures diff --git a/gfx/skia/skia/src/gpu/batches/GrClearBatch.h b/gfx/skia/skia/src/gpu/batches/GrClearBatch.h index 944485ca7eb..c38372c1e25 100644 --- a/gfx/skia/skia/src/gpu/batches/GrClearBatch.h +++ b/gfx/skia/skia/src/gpu/batches/GrClearBatch.h @@ -28,6 +28,7 @@ public: const char* name() const override { return "Clear"; } uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->getUniqueID(); } + GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); } SkString dumpInfo() const override { SkString string; @@ -71,6 +72,7 @@ public: const char* name() const override { return "ClearStencilClip"; } uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->getUniqueID(); } + GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); } SkString dumpInfo() const override { SkString string; diff --git a/gfx/skia/skia/src/gpu/batches/GrCopySurfaceBatch.h b/gfx/skia/skia/src/gpu/batches/GrCopySurfaceBatch.h index ed5e77f5b06..7bf8d8d8c27 100644 --- a/gfx/skia/skia/src/gpu/batches/GrCopySurfaceBatch.h +++ b/gfx/skia/skia/src/gpu/batches/GrCopySurfaceBatch.h @@ -26,6 +26,7 @@ public: GrRenderTarget* rt = fDst.get()->asRenderTarget(); return rt ? rt->getUniqueID() : 0; } + GrRenderTarget* renderTarget() const override { return fDst.get()->asRenderTarget(); } SkString dumpInfo() const override { SkString string; diff --git a/gfx/skia/skia/src/gpu/batches/GrDashLinePathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrDashLinePathRenderer.cpp index e26f5d76272..902dca6d862 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDashLinePathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrDashLinePathRenderer.cpp @@ -19,6 +19,7 @@ bool GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { } bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrDashLinePathRenderer::onDrawPath"); SkPoint pts[2]; SkAssertResult(args.fPath->isLine(pts)); return GrDashingEffect::DrawDashLine(args.fTarget, *args.fPipelineBuilder, args.fColor, diff --git a/gfx/skia/skia/src/gpu/batches/GrDefaultPathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrDefaultPathRenderer.cpp index c6ca1cafc77..c39a5306455 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDefaultPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrDefaultPathRenderer.cpp @@ -20,6 +20,7 @@ #include "SkTLazy.h" #include "SkTraceEvent.h" +#include "batches/GrRectBatchFactory.h" #include "batches/GrVertexBatch.h" GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport, @@ -289,7 +290,7 @@ private: } if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) { - SkDebugf("Cannot render path (%d)\n", maxVertices); + //SkDebugf("Cannot render path (%d)\n", maxVertices); return; } @@ -697,7 +698,10 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, } const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix; - target->drawNonAARect(*pipelineBuilder, color, viewM, bounds, localMatrix); + SkAutoTUnref batch( + GrRectBatchFactory::CreateNonAAFill(color, viewM, bounds, nullptr, + &localMatrix)); + target->drawBatch(*pipelineBuilder, batch); } else { if (passCount > 1) { pipelineBuilder->setDisableColorXPFactory(); @@ -726,6 +730,7 @@ bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { } bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrDefaultPathRenderer::onDrawPath"); return this->internalDrawPath(args.fTarget, args.fPipelineBuilder, args.fColor, @@ -736,6 +741,7 @@ bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { } void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),"GrDefaultPathRenderer::onStencilPath"); SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType()); SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType()); this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix, diff --git a/gfx/skia/skia/src/gpu/batches/GrDiscardBatch.h b/gfx/skia/skia/src/gpu/batches/GrDiscardBatch.h index aa443cf6034..65b6c4bf7d3 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDiscardBatch.h +++ b/gfx/skia/skia/src/gpu/batches/GrDiscardBatch.h @@ -26,6 +26,7 @@ public: const char* name() const override { return "Discard"; } uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->getUniqueID(); } + GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); } SkString dumpInfo() const override { SkString string; diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawBatch.h b/gfx/skia/skia/src/gpu/batches/GrDrawBatch.h index 8e738789812..4d4209ab404 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDrawBatch.h +++ b/gfx/skia/skia/src/gpu/batches/GrDrawBatch.h @@ -63,6 +63,11 @@ public: return this->pipeline()->getRenderTarget()->getUniqueID(); } + GrRenderTarget* renderTarget() const final { + SkASSERT(fPipelineInstalled); + return this->pipeline()->getRenderTarget(); + } + SkString dumpInfo() const override { SkString string; string.appendf("RT: %d\n", this->renderTargetUniqueID()); @@ -78,7 +83,7 @@ public: this->pipeline()->getCoverageFragmentProcessor(i).name(), this->pipeline()->getCoverageFragmentProcessor(i).dumpInfo().c_str()); } - string.appendf("XP: %s\n", this->pipeline()->getXferProcessor()->name()); + string.appendf("XP: %s\n", this->pipeline()->getXferProcessor().name()); return string; } diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.cpp b/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.cpp index 5209f907de2..ff625399322 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.cpp @@ -7,6 +7,10 @@ #include "GrDrawPathBatch.h" +static void pre_translate_transform_values(const float* xforms, + GrPathRendering::PathTransformType type, int count, + SkScalar x, SkScalar y, float* dst); + SkString GrDrawPathBatch::dumpInfo() const { SkString string; string.printf("PATH: 0x%p", fPath.get()); @@ -25,63 +29,59 @@ void GrDrawPathBatch::onDraw(GrBatchFlushState* state) { state->gpu()->pathRendering()->drawPath(args, fPath.get()); } -GrDrawPathRangeBatch::~GrDrawPathRangeBatch() { - for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { - (*iter.get())->unref(); - } -} - SkString GrDrawPathRangeBatch::dumpInfo() const { SkString string; - string.printf("RANGE: 0x%p COUNTS: [", *fDraws.head()); + string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get()); for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { - string.appendf("%d ,", (*iter.get())->count()); + string.appendf("%d, ", iter.get()->fInstanceData->count()); } string.remove(string.size() - 2, 2); string.append("]"); return string; } -bool GrDrawPathRangeBatch::isWinding() const { - static const GrStencilSettings::Face pathFace = GrStencilSettings::kFront_Face; - bool isWinding = kInvert_StencilOp != this->stencilSettings().passOp(pathFace); - if (isWinding) { - // Double check that it is in fact winding. - SkASSERT(kIncClamp_StencilOp == this->stencilSettings().passOp(pathFace)); - SkASSERT(kIncClamp_StencilOp == this->stencilSettings().failOp(pathFace)); - SkASSERT(0x1 != this->stencilSettings().writeMask(pathFace)); - SkASSERT(!this->stencilSettings().isTwoSided()); - } - return isWinding; -} - -GrDrawPathRangeBatch::GrDrawPathRangeBatch(const SkMatrix& viewMatrix, const SkMatrix& localMatrix, - GrColor color, GrPathRange* range, GrPathRangeDraw* draw, - const SkRect& bounds) - : INHERITED(ClassID(), viewMatrix, color) +GrDrawPathRangeBatch::GrDrawPathRangeBatch(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, + SkScalar y, GrColor color, + GrPathRendering::FillType fill, GrPathRange* range, + const InstanceData* instanceData, const SkRect& bounds) + : INHERITED(ClassID(), viewMatrix, color, fill) , fPathRange(range) - , fLocalMatrix(localMatrix) { - SkDEBUGCODE(draw->fUsedInBatch = true;) - fDraws.addToHead(SkRef(draw)); - fTotalPathCount = draw->count(); + , fTotalPathCount(instanceData->count()) + , fScale(scale) { + fDraws.addToHead()->set(instanceData, x, y); fBounds = bounds; } bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { GrDrawPathRangeBatch* that = t->cast(); - if (this->fPathRange.get() != that->fPathRange.get()) { - return false; - } - if (!GrPathRangeDraw::CanMerge(**this->fDraws.head(), **that->fDraws.head())) { + if (this->fPathRange.get() != that->fPathRange.get() || + this->transformType() != that->transformType() || + this->fScale != that->fScale || + this->color() != that->color() || + !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { return false; } if (!GrPipeline::AreEqual(*this->pipeline(), *that->pipeline(), false)) { return false; } - if (this->color() != that->color() || - !this->viewMatrix().cheapEqualTo(that->viewMatrix()) || - !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) { - return false; + switch (fDraws.head()->fInstanceData->transformType()) { + case GrPathRendering::kNone_PathTransformType: + if (this->fDraws.head()->fX != that->fDraws.head()->fX || + this->fDraws.head()->fY != that->fDraws.head()->fY) { + return false; + } + break; + case GrPathRendering::kTranslateX_PathTransformType: + if (this->fDraws.head()->fY != that->fDraws.head()->fY) { + return false; + } + break; + case GrPathRendering::kTranslateY_PathTransformType: + if (this->fDraws.head()->fX != that->fDraws.head()->fX) { + return false; + } + break; + default: break; } // TODO: Check some other things here. (winding, opaque, pathProc color, vm, ...) // Try to combine this call with the previous DrawPaths. We do this by stenciling all the @@ -90,54 +90,124 @@ bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { // work). Note that it's also possible for overlapping paths to cancel each other's winding // numbers, and we only partially account for this by not allowing even/odd paths to be // combined. (Glyphs in the same font tend to wind the same direction so it works out OK.) - if (!this->isWinding() || + if (GrPathRendering::kWinding_FillType != this->fillType() || this->stencilSettings() != that->stencilSettings() || this->overrides().willColorBlendWithDst()) { return false; } SkASSERT(!that->overrides().willColorBlendWithDst()); fTotalPathCount += that->fTotalPathCount; - while (GrPathRangeDraw** head = that->fDraws.head()) { - fDraws.addToTail(*head); - // We're stealing that's refs, so pop without unreffing. + while (Draw* head = that->fDraws.head()) { + Draw* draw = fDraws.addToTail(); + draw->fInstanceData.reset(head->fInstanceData.detach()); + draw->fX = head->fX; + draw->fY = head->fY; that->fDraws.popHead(); } return true; } void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) { - GrProgramDesc desc; + const Draw& head = *fDraws.head(); + + SkMatrix drawMatrix(this->viewMatrix()); + drawMatrix.preScale(fScale, fScale); + drawMatrix.preTranslate(head.fX, head.fY); + + SkMatrix localMatrix; + localMatrix.setScale(fScale, fScale); + localMatrix.preTranslate(head.fX, head.fY); + SkAutoTUnref pathProc(GrPathProcessor::Create(this->color(), this->overrides(), - this->viewMatrix(), - fLocalMatrix)); + drawMatrix, + localMatrix)); + + GrProgramDesc desc; state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline()); GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(), - &desc, &this->stencilSettings()); + &desc, &this->stencilSettings()); + if (fDraws.count() == 1) { - const GrPathRangeDraw& draw = **fDraws.head(); - state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), draw.indices(), - GrPathRange::kU16_PathIndexType, draw.transforms(), draw.transformType(), - draw.count()); + const InstanceData& instances = *head.fInstanceData; + state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), instances.indices(), + GrPathRange::kU16_PathIndexType, + instances.transformValues(), + instances.transformType(), + instances.count()); + } else { + int floatsPerTransform = GrPathRendering::PathTransformSize(this->transformType()); +#if defined(GOOGLE3) + //Stack frame size is limited in GOOGLE3. + SkAutoSTMalloc<512, float> transformStorage(floatsPerTransform * fTotalPathCount); + SkAutoSTMalloc<256, uint16_t> indexStorage(fTotalPathCount); +#else + SkAutoSTMalloc<4096, float> transformStorage(floatsPerTransform * fTotalPathCount); + SkAutoSTMalloc<2048, uint16_t> indexStorage(fTotalPathCount); +#endif + int idx = 0; + for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { + const Draw& draw = *iter.get(); + const InstanceData& instances = *draw.fInstanceData; + memcpy(&indexStorage[idx], instances.indices(), instances.count() * sizeof(uint16_t)); + pre_translate_transform_values(instances.transformValues(), this->transformType(), + instances.count(), + draw.fX - head.fX, draw.fY - head.fY, + &transformStorage[floatsPerTransform * idx]); + idx += instances.count(); + + // TODO: Support mismatched transform types if we start using more types other than 2D. + SkASSERT(instances.transformType() == this->transformType()); + } + SkASSERT(idx == fTotalPathCount); + + state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), indexStorage, + GrPathRange::kU16_PathIndexType, transformStorage, + this->transformType(), fTotalPathCount); + } +} + +inline void pre_translate_transform_values(const float* xforms, + GrPathRendering::PathTransformType type, int count, + SkScalar x, SkScalar y, float* dst) { + if (0 == x && 0 == y) { + memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * sizeof(float)); return; } - - GrPathRendering::PathTransformType transformType = (*fDraws.head())->transformType(); - int floatsPerTransform = GrPathRendering::PathTransformSize(transformType); - SkAutoSTMalloc<512, float> transformStorage(floatsPerTransform * fTotalPathCount); - SkAutoSTMalloc<256, uint16_t> indexStorage(fTotalPathCount); - uint16_t* indices = indexStorage.get(); - float* transforms = transformStorage.get(); - for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { - SkASSERT((*iter.get())->transformType() == transformType); - int cnt = (*iter.get())->count(); - memcpy(indices, (*iter.get())->indices(), cnt * sizeof(uint16_t)); - indices += cnt; - memcpy(transforms, (*iter.get())->transforms(), cnt * floatsPerTransform * sizeof(float)); - transforms += cnt * floatsPerTransform; + switch (type) { + case GrPathRendering::kNone_PathTransformType: + SkFAIL("Cannot pre-translate kNone_PathTransformType."); + break; + case GrPathRendering::kTranslateX_PathTransformType: + SkASSERT(0 == y); + for (int i = 0; i < count; i++) { + dst[i] = xforms[i] + x; + } + break; + case GrPathRendering::kTranslateY_PathTransformType: + SkASSERT(0 == x); + for (int i = 0; i < count; i++) { + dst[i] = xforms[i] + y; + } + break; + case GrPathRendering::kTranslate_PathTransformType: + for (int i = 0; i < 2 * count; i += 2) { + dst[i] = xforms[i] + x; + dst[i + 1] = xforms[i + 1] + y; + } + break; + case GrPathRendering::kAffine_PathTransformType: + for (int i = 0; i < 6 * count; i += 6) { + dst[i] = xforms[i]; + dst[i + 1] = xforms[i + 1]; + dst[i + 2] = xforms[i] * x + xforms[i + 1] * y + xforms[i + 2]; + dst[i + 3] = xforms[i + 3]; + dst[i + 4] = xforms[i + 4]; + dst[i + 5] = xforms[i + 3] * x + xforms[i + 4] * y + xforms[i + 5]; + } + break; + default: + SkFAIL("Unknown transform type."); + break; } - SkASSERT(indices - indexStorage.get() == fTotalPathCount); - state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), indexStorage.get(), - GrPathRange::kU16_PathIndexType, transformStorage.get(), transformType, - fTotalPathCount); } diff --git a/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.h b/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.h index 4067c808dc0..0b24fe0546d 100644 --- a/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.h +++ b/gfx/skia/skia/src/gpu/batches/GrDrawPathBatch.h @@ -27,13 +27,17 @@ public: overrides->fUsePLSDstRead = false; } + GrPathRendering::FillType fillType() const { return fFillType; } + void setStencilSettings(const GrStencilSettings& stencil) { fStencilSettings = stencil; } protected: - GrDrawPathBatchBase(uint32_t classID, const SkMatrix& viewMatrix, GrColor initialColor) + GrDrawPathBatchBase(uint32_t classID, const SkMatrix& viewMatrix, GrColor initialColor, + GrPathRendering::FillType fill) : INHERITED(classID) , fViewMatrix(viewMatrix) - , fColor(initialColor) {} + , fColor(initialColor) + , fFillType(fill) {} const GrStencilSettings& stencilSettings() const { return fStencilSettings; } const GrXPOverridesForBatch& overrides() const { return fOverrides; } @@ -48,6 +52,7 @@ private: SkMatrix fViewMatrix; GrColor fColor; + GrPathRendering::FillType fFillType; GrStencilSettings fStencilSettings; GrXPOverridesForBatch fOverrides; @@ -60,8 +65,8 @@ public: // This can't return a more abstract type because we install the stencil settings late :( static GrDrawPathBatchBase* Create(const SkMatrix& viewMatrix, GrColor color, - const GrPath* path) { - return new GrDrawPathBatch(viewMatrix, color, path); + GrPathRendering::FillType fill, const GrPath* path) { + return new GrDrawPathBatch(viewMatrix, color, fill, path); } const char* name() const override { return "DrawPath"; } @@ -69,8 +74,9 @@ public: SkString dumpInfo() const override; private: - GrDrawPathBatch(const SkMatrix& viewMatrix, GrColor color, const GrPath* path) - : INHERITED(ClassID(), viewMatrix, color) + GrDrawPathBatch(const SkMatrix& viewMatrix, GrColor color, GrPathRendering::FillType fill, + const GrPath* path) + : INHERITED(ClassID(), viewMatrix, color, fill) , fPath(path) { fBounds = path->getBounds(); viewMatrix.mapRect(&fBounds); @@ -87,83 +93,91 @@ private: typedef GrDrawPathBatchBase INHERITED; }; -/** - * This could be nested inside the batch class, but for now it must be declarable in a public - * header (GrDrawContext) - */ -class GrPathRangeDraw : public GrNonAtomicRef { -public: - typedef GrPathRendering::PathTransformType TransformType; - - static GrPathRangeDraw* Create(TransformType transformType, int reserveCnt) { - return new GrPathRangeDraw(transformType, reserveCnt); - } - - void append(uint16_t index, float transform[]) { - fTransforms.push_back_n(GrPathRendering::PathTransformSize(fTransformType), transform); - fIndices.push_back(index); - } - - int count() const { return fIndices.count(); } - - TransformType transformType() const { return fTransformType; } - - const float* transforms() const { return fTransforms.begin(); } - - const uint16_t* indices() const { return fIndices.begin(); } - - static bool CanMerge(const GrPathRangeDraw& a, const GrPathRangeDraw& b) { - return a.transformType() == b.transformType(); - } - -private: - GrPathRangeDraw(TransformType transformType, int reserveCnt) - : fTransformType(transformType) - , fIndices(reserveCnt) - , fTransforms(reserveCnt * GrPathRendering::PathTransformSize(transformType)) { - SkDEBUGCODE(fUsedInBatch = false;) - } - - // Reserve space for 64 paths where indices are 16 bit and transforms are translations. - static const int kIndexReserveCnt = 64; - static const int kTransformBufferReserveCnt = 2 * 64; - - GrPathRendering::PathTransformType fTransformType; - SkSTArray fIndices; - SkSTArray fTransforms; - - // To ensure we don't reuse these across batches. -#ifdef SK_DEBUG - bool fUsedInBatch; - friend class GrDrawPathRangeBatch; -#endif - - typedef GrNonAtomicRef INHERITED; -}; - // Template this if we decide to support index types other than 16bit class GrDrawPathRangeBatch final : public GrDrawPathBatchBase { public: + typedef GrPathRendering::PathTransformType TransformType; + DEFINE_BATCH_CLASS_ID - // This can't return a more abstract type because we install the stencil settings late :( - static GrDrawPathBatchBase* Create(const SkMatrix& viewMatrix, const SkMatrix& localMatrix, - GrColor color, GrPathRange* range, GrPathRangeDraw* draw, - const SkRect& bounds) { - return new GrDrawPathRangeBatch(viewMatrix, localMatrix, color, range, draw, bounds); - } + struct InstanceData : public SkNoncopyable { + public: + static InstanceData* Alloc(TransformType transformType, int reserveCnt) { + int transformSize = GrPathRendering::PathTransformSize(transformType); + uint8_t* ptr = (uint8_t*)sk_malloc_throw(Align32(sizeof(InstanceData)) + + Align32(reserveCnt * sizeof(uint16_t)) + + reserveCnt * transformSize * sizeof(float)); + InstanceData* instanceData = (InstanceData*)ptr; + instanceData->fIndices = (uint16_t*)&ptr[Align32(sizeof(InstanceData))]; + instanceData->fTransformValues = (float*)&ptr[Align32(sizeof(InstanceData)) + + Align32(reserveCnt * sizeof(uint16_t))]; + instanceData->fTransformType = transformType; + instanceData->fInstanceCount = 0; + instanceData->fRefCnt = 1; + SkDEBUGCODE(instanceData->fReserveCnt = reserveCnt;) + return instanceData; + } - ~GrDrawPathRangeBatch() override; + // Overload this method if we start using other transform types. + void append(uint16_t index, float x, float y) { + SkASSERT(GrPathRendering::kTranslate_PathTransformType == fTransformType); + SkASSERT(fInstanceCount < fReserveCnt); + fIndices[fInstanceCount] = index; + fTransformValues[2 * fInstanceCount] = x; + fTransformValues[2 * fInstanceCount + 1] = y; + ++fInstanceCount; + } + + TransformType transformType() const { return fTransformType; } + int count() const { return fInstanceCount; } + + const uint16_t* indices() const { return fIndices; } + uint16_t* indices() { return fIndices; } + + const float* transformValues() const { return fTransformValues; } + float* transformValues() { return fTransformValues; } + + void ref() const { ++fRefCnt; } + + void unref() const { + if (0 == --fRefCnt) { + sk_free(const_cast(this)); + } + } + + private: + static int Align32(int sizeInBytes) { return (sizeInBytes + 3) & ~3; } + + InstanceData() {} + ~InstanceData() {} + + uint16_t* fIndices; + float* fTransformValues; + TransformType fTransformType; + int fInstanceCount; + mutable int fRefCnt; + SkDEBUGCODE(int fReserveCnt;) + }; + + // This can't return a more abstract type because we install the stencil settings late :( + static GrDrawPathBatchBase* Create(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, + SkScalar y, GrColor color, GrPathRendering::FillType fill, + GrPathRange* range, const InstanceData* instanceData, + const SkRect& bounds) { + return new GrDrawPathRangeBatch(viewMatrix, scale, x, y, color, fill, range, instanceData, + bounds); + } const char* name() const override { return "DrawPathRange"; } SkString dumpInfo() const override; private: - inline bool isWinding() const; + GrDrawPathRangeBatch(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, SkScalar y, + GrColor color, GrPathRendering::FillType fill, GrPathRange* range, + const InstanceData* instanceData, const SkRect& bounds); - GrDrawPathRangeBatch(const SkMatrix& viewMatrix, const SkMatrix& localMatrix, GrColor color, - GrPathRange* range, GrPathRangeDraw* draw, const SkRect& bounds); + TransformType transformType() const { return fDraws.head()->fInstanceData->transformType(); } bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override; @@ -171,12 +185,24 @@ private: void onDraw(GrBatchFlushState* state) override; + struct Draw { + void set(const InstanceData* instanceData, SkScalar x, SkScalar y) { + fInstanceData.reset(SkRef(instanceData)); + fX = x; + fY = y; + } + + SkAutoTUnref fInstanceData; + SkScalar fX, fY; + }; + typedef GrPendingIOResource PendingPathRange; - typedef SkTLList DrawList; + typedef SkTLList DrawList; + PendingPathRange fPathRange; DrawList fDraws; int fTotalPathCount; - SkMatrix fLocalMatrix; + SkScalar fScale; typedef GrDrawPathBatchBase INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp index a11d2b46834..ada6dbf9637 100644 --- a/gfx/skia/skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp @@ -10,27 +10,13 @@ #include "GrStencilAndCoverPathRenderer.h" #include "GrCaps.h" #include "GrContext.h" +#include "GrDrawPathBatch.h" #include "GrGpu.h" #include "GrPath.h" #include "GrRenderTarget.h" #include "GrResourceProvider.h" #include "GrStrokeInfo.h" - -/* - * For now paths only natively support winding and even odd fill types - */ -static GrPathRendering::FillType convert_skpath_filltype(SkPath::FillType fill) { - switch (fill) { - default: - SkFAIL("Incomplete Switch\n"); - case SkPath::kWinding_FillType: - case SkPath::kInverseWinding_FillType: - return GrPathRendering::kWinding_FillType; - case SkPath::kEvenOdd_FillType: - case SkPath::kInverseEvenOdd_FillType: - return GrPathRendering::kEvenOdd_FillType; - } -} +#include "batches/GrRectBatchFactory.h" GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider, const GrCaps& caps) { @@ -78,13 +64,16 @@ static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const SkPath& s } void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), + "GrStencilAndCoverPathRenderer::onStencilPath"); SkASSERT(!args.fPath->isInverseFillType()); SkAutoTUnref p(get_gr_path(fResourceProvider, *args.fPath, *args.fStroke)); - args.fTarget->stencilPath(*args.fPipelineBuilder, *args.fViewMatrix, p, - convert_skpath_filltype(args.fPath->getFillType())); + args.fTarget->stencilPath(*args.fPipelineBuilder, *args.fViewMatrix, p, p->getFillType()); } bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), + "GrStencilAndCoverPathRenderer::onDrawPath"); SkASSERT(!args.fStroke->isHairlineStyle()); const SkPath& path = *args.fPath; GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder; @@ -114,8 +103,7 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { pipelineBuilder->setStencil(kInvertedStencilPass); // fake inverse with a stencil and cover - args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, - convert_skpath_filltype(path.getFillType())); + args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, p->getFillType()); SkMatrix invert = SkMatrix::I(); SkRect bounds = @@ -138,7 +126,11 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { if (pipelineBuilder->getRenderTarget()->hasMixedSamples()) { pipelineBuilder->disableState(GrPipelineBuilder::kHWAntialias_Flag); } - args.fTarget->drawNonAARect(*pipelineBuilder, args.fColor, viewM, bounds, invert); + + SkAutoTUnref batch( + GrRectBatchFactory::CreateNonAAFill(args.fColor, viewM, bounds, nullptr, + &invert)); + args.fTarget->drawBatch(*pipelineBuilder, batch); } else { GR_STATIC_CONST_SAME_STENCIL(kStencilPass, kZero_StencilOp, @@ -149,8 +141,9 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { 0xffff); pipelineBuilder->setStencil(kStencilPass); - args.fTarget->drawPath(*pipelineBuilder, viewMatrix, args.fColor, p, - convert_skpath_filltype(path.getFillType())); + SkAutoTUnref batch( + GrDrawPathBatch::Create(viewMatrix, args.fColor, p->getFillType(), p)); + args.fTarget->drawPathBatch(*pipelineBuilder, batch); } pipelineBuilder->stencil()->setDisabled(); diff --git a/gfx/skia/skia/src/gpu/batches/GrStencilPathBatch.h b/gfx/skia/skia/src/gpu/batches/GrStencilPathBatch.h index a0dcadb620e..33189c2885b 100644 --- a/gfx/skia/skia/src/gpu/batches/GrStencilPathBatch.h +++ b/gfx/skia/skia/src/gpu/batches/GrStencilPathBatch.h @@ -31,6 +31,7 @@ public: const char* name() const override { return "StencilPath"; } uint32_t renderTargetUniqueID() const override { return fRenderTarget.get()->getUniqueID(); } + GrRenderTarget* renderTarget() const override { return fRenderTarget.get(); } SkString dumpInfo() const override { SkString string; diff --git a/gfx/skia/skia/src/gpu/batches/GrTessellatingPathRenderer.cpp b/gfx/skia/skia/src/gpu/batches/GrTessellatingPathRenderer.cpp index 27e287e9c6b..81436baec02 100644 --- a/gfx/skia/skia/src/gpu/batches/GrTessellatingPathRenderer.cpp +++ b/gfx/skia/skia/src/gpu/batches/GrTessellatingPathRenderer.cpp @@ -14,7 +14,7 @@ #include "GrVertices.h" #include "GrResourceCache.h" #include "GrResourceProvider.h" -#include "SkChunkAlloc.h" +#include "GrTessellator.h" #include "SkGeometry.h" #include "batches/GrVertexBatch.h" @@ -22,1324 +22,29 @@ #include /* - * This path renderer tessellates the path into triangles, uploads the triangles to a - * vertex buffer, and renders them with a single draw call. It does not currently do + * This path renderer tessellates the path into triangles using GrTessellator, uploads the triangles + * to a vertex buffer, and renders them with a single draw call. It does not currently do * antialiasing, so it must be used in conjunction with multisampling. - * - * There are six stages to the algorithm: - * - * 1) Linearize the path contours into piecewise linear segments (path_to_contours()). - * 2) Build a mesh of edges connecting the vertices (build_edges()). - * 3) Sort the vertices in Y (and secondarily in X) (merge_sort()). - * 4) Simplify the mesh by inserting new vertices at intersecting edges (simplify()). - * 5) Tessellate the simplified mesh into monotone polygons (tessellate()). - * 6) Triangulate the monotone polygons directly into a vertex buffer (polys_to_triangles()). - * - * The vertex sorting in step (3) is a merge sort, since it plays well with the linked list - * of vertices (and the necessity of inserting new vertices on intersection). - * - * Stages (4) and (5) use an active edge list, which a list of all edges for which the - * sweep line has crossed the top vertex, but not the bottom vertex. It's sorted - * left-to-right based on the point where both edges are active (when both top vertices - * have been seen, so the "lower" top vertex of the two). If the top vertices are equal - * (shared), it's sorted based on the last point where both edges are active, so the - * "upper" bottom vertex. - * - * The most complex step is the simplification (4). It's based on the Bentley-Ottman - * line-sweep algorithm, but due to floating point inaccuracy, the intersection points are - * not exact and may violate the mesh topology or active edge list ordering. We - * accommodate this by adjusting the topology of the mesh and AEL to match the intersection - * points. This occurs in three ways: - * - * A) Intersections may cause a shortened edge to no longer be ordered with respect to its - * neighbouring edges at the top or bottom vertex. This is handled by merging the - * edges (merge_collinear_edges()). - * B) Intersections may cause an edge to violate the left-to-right ordering of the - * active edge list. This is handled by splitting the neighbour edge on the - * intersected vertex (cleanup_active_edges()). - * C) Shortening an edge may cause an active edge to become inactive or an inactive edge - * to become active. This is handled by removing or inserting the edge in the active - * edge list (fix_active_state()). - * - * The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and - * Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it - * currently uses a linked list for the active edge list, rather than a 2-3 tree as the - * paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also - * become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N) - * insertions and removals was greater than the cost of infrequent O(N) lookups with the - * linked list implementation. With the latter, all removals are O(1), and most insertions - * are O(1), since we know the adjacent edge in the active edge list based on the topology. - * Only type 2 vertices (see paper) require the O(N) lookups, and these are much less - * frequent. There may be other data structures worth investigating, however. - * - * Note that the orientation of the line sweep algorithms is determined by the aspect ratio of the - * path bounds. When the path is taller than it is wide, we sort vertices based on increasing Y - * coordinate, and secondarily by increasing X coordinate. When the path is wider than it is tall, - * we sort by increasing X coordinate, but secondarily by *decreasing* Y coordinate. This is so - * that the "left" and "right" orientation in the code remains correct (edges to the left are - * increasing in Y; edges to the right are decreasing in Y). That is, the setting rotates 90 - * degrees counterclockwise, rather that transposing. */ -#define LOGGING_ENABLED 0 -#define WIREFRAME 0 - -#if LOGGING_ENABLED -#define LOG printf -#else -#define LOG(...) -#endif - -#define ALLOC_NEW(Type, args, alloc) new (alloc.allocThrow(sizeof(Type))) Type args - namespace { -struct Vertex; -struct Edge; -struct Poly; - -template -void insert(T* t, T* prev, T* next, T** head, T** tail) { - t->*Prev = prev; - t->*Next = next; - if (prev) { - prev->*Next = t; - } else if (head) { - *head = t; - } - if (next) { - next->*Prev = t; - } else if (tail) { - *tail = t; - } -} - -template -void remove(T* t, T** head, T** tail) { - if (t->*Prev) { - t->*Prev->*Next = t->*Next; - } else if (head) { - *head = t->*Next; - } - if (t->*Next) { - t->*Next->*Prev = t->*Prev; - } else if (tail) { - *tail = t->*Prev; - } - t->*Prev = t->*Next = nullptr; -} - -/** - * Vertices are used in three ways: first, the path contours are converted into a - * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices - * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing - * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid - * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of - * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since - * an individual Vertex from the path mesh may belong to multiple - * MonotonePolys, so the original Vertices cannot be re-used. - */ - -struct Vertex { - Vertex(const SkPoint& point) - : fPoint(point), fPrev(nullptr), fNext(nullptr) - , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr) - , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr) - , fProcessed(false) -#if LOGGING_ENABLED - , fID (-1.0f) -#endif - {} - SkPoint fPoint; // Vertex position - Vertex* fPrev; // Linked list of contours, then Y-sorted vertices. - Vertex* fNext; // " - Edge* fFirstEdgeAbove; // Linked list of edges above this vertex. - Edge* fLastEdgeAbove; // " - Edge* fFirstEdgeBelow; // Linked list of edges below this vertex. - Edge* fLastEdgeBelow; // " - bool fProcessed; // Has this vertex been seen in simplify()? -#if LOGGING_ENABLED - float fID; // Identifier used for logging. -#endif -}; - -/***************************************************************************************/ - -typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b); - -struct Comparator { - CompareFunc sweep_lt; - CompareFunc sweep_gt; -}; - -bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) { - return a.fX == b.fX ? a.fY > b.fY : a.fX < b.fX; -} - -bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) { - return a.fY == b.fY ? a.fX < b.fX : a.fY < b.fY; -} - -bool sweep_gt_horiz(const SkPoint& a, const SkPoint& b) { - return a.fX == b.fX ? a.fY < b.fY : a.fX > b.fX; -} - -bool sweep_gt_vert(const SkPoint& a, const SkPoint& b) { - return a.fY == b.fY ? a.fX > b.fX : a.fY > b.fY; -} - -inline SkPoint* emit_vertex(Vertex* v, SkPoint* data) { - *data++ = v->fPoint; - return data; -} - -SkPoint* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, SkPoint* data) { -#if WIREFRAME - data = emit_vertex(v0, data); - data = emit_vertex(v1, data); - data = emit_vertex(v1, data); - data = emit_vertex(v2, data); - data = emit_vertex(v2, data); - data = emit_vertex(v0, data); -#else - data = emit_vertex(v0, data); - data = emit_vertex(v1, data); - data = emit_vertex(v2, data); -#endif - return data; -} - -struct EdgeList { - EdgeList() : fHead(nullptr), fTail(nullptr) {} - Edge* fHead; - Edge* fTail; -}; - -/** - * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and - * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf(). - * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating - * point). For speed, that case is only tested by the callers which require it (e.g., - * cleanup_active_edges()). Edges also handle checking for intersection with other edges. - * Currently, this converts the edges to the parametric form, in order to avoid doing a division - * until an intersection has been confirmed. This is slightly slower in the "found" case, but - * a lot faster in the "not found" case. - * - * The coefficients of the line equation stored in double precision to avoid catastrphic - * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is - * correct in float, since it's a polynomial of degree 2. The intersect() function, being - * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its - * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of - * this file). - */ - -struct Edge { - Edge(Vertex* top, Vertex* bottom, int winding) - : fWinding(winding) - , fTop(top) - , fBottom(bottom) - , fLeft(nullptr) - , fRight(nullptr) - , fPrevEdgeAbove(nullptr) - , fNextEdgeAbove(nullptr) - , fPrevEdgeBelow(nullptr) - , fNextEdgeBelow(nullptr) - , fLeftPoly(nullptr) - , fRightPoly(nullptr) { - recompute(); - } - int fWinding; // 1 == edge goes downward; -1 = edge goes upward. - Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt). - Vertex* fBottom; // The bottom vertex in vertex-sort-order. - Edge* fLeft; // The linked list of edges in the active edge list. - Edge* fRight; // " - Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above". - Edge* fNextEdgeAbove; // " - Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below". - Edge* fNextEdgeBelow; // " - Poly* fLeftPoly; // The Poly to the left of this edge, if any. - Poly* fRightPoly; // The Poly to the right of this edge, if any. - double fDX; // The line equation for this edge, in implicit form. - double fDY; // fDY * x + fDX * y + fC = 0, for point (x, y) on the line. - double fC; - double dist(const SkPoint& p) const { - return fDY * p.fX - fDX * p.fY + fC; - } - bool isRightOf(Vertex* v) const { - return dist(v->fPoint) < 0.0; - } - bool isLeftOf(Vertex* v) const { - return dist(v->fPoint) > 0.0; - } - void recompute() { - fDX = static_cast(fBottom->fPoint.fX) - fTop->fPoint.fX; - fDY = static_cast(fBottom->fPoint.fY) - fTop->fPoint.fY; - fC = static_cast(fTop->fPoint.fY) * fBottom->fPoint.fX - - static_cast(fTop->fPoint.fX) * fBottom->fPoint.fY; - } - bool intersect(const Edge& other, SkPoint* p) { - LOG("intersecting %g -> %g with %g -> %g\n", - fTop->fID, fBottom->fID, - other.fTop->fID, other.fBottom->fID); - if (fTop == other.fTop || fBottom == other.fBottom) { - return false; - } - double denom = fDX * other.fDY - fDY * other.fDX; - if (denom == 0.0) { - return false; - } - double dx = static_cast(fTop->fPoint.fX) - other.fTop->fPoint.fX; - double dy = static_cast(fTop->fPoint.fY) - other.fTop->fPoint.fY; - double sNumer = dy * other.fDX - dx * other.fDY; - double tNumer = dy * fDX - dx * fDY; - // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early. - // This saves us doing the divide below unless absolutely necessary. - if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom) - : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) { - return false; - } - double s = sNumer / denom; - SkASSERT(s >= 0.0 && s <= 1.0); - p->fX = SkDoubleToScalar(fTop->fPoint.fX + s * fDX); - p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fDY); - return true; - } - bool isActive(EdgeList* activeEdges) const { - return activeEdges && (fLeft || fRight || activeEdges->fHead == this); - } -}; - -/***************************************************************************************/ - -struct Poly { - Poly(int winding) - : fWinding(winding) - , fHead(nullptr) - , fTail(nullptr) - , fActive(nullptr) - , fNext(nullptr) - , fPartner(nullptr) - , fCount(0) - { -#if LOGGING_ENABLED - static int gID = 0; - fID = gID++; - LOG("*** created Poly %d\n", fID); -#endif - } - typedef enum { kNeither_Side, kLeft_Side, kRight_Side } Side; - struct MonotonePoly { - MonotonePoly() - : fSide(kNeither_Side) - , fHead(nullptr) - , fTail(nullptr) - , fPrev(nullptr) - , fNext(nullptr) {} - Side fSide; - Vertex* fHead; - Vertex* fTail; - MonotonePoly* fPrev; - MonotonePoly* fNext; - bool addVertex(Vertex* v, Side side, SkChunkAlloc& alloc) { - Vertex* newV = ALLOC_NEW(Vertex, (v->fPoint), alloc); - bool done = false; - if (fSide == kNeither_Side) { - fSide = side; - } else { - done = side != fSide; - } - if (fHead == nullptr) { - fHead = fTail = newV; - } else if (fSide == kRight_Side) { - newV->fPrev = fTail; - fTail->fNext = newV; - fTail = newV; - } else { - newV->fNext = fHead; - fHead->fPrev = newV; - fHead = newV; - } - return done; - } - - SkPoint* emit(SkPoint* data) { - Vertex* first = fHead; - Vertex* v = first->fNext; - while (v != fTail) { - SkASSERT(v && v->fPrev && v->fNext); - Vertex* prev = v->fPrev; - Vertex* curr = v; - Vertex* next = v->fNext; - double ax = static_cast(curr->fPoint.fX) - prev->fPoint.fX; - double ay = static_cast(curr->fPoint.fY) - prev->fPoint.fY; - double bx = static_cast(next->fPoint.fX) - curr->fPoint.fX; - double by = static_cast(next->fPoint.fY) - curr->fPoint.fY; - if (ax * by - ay * bx >= 0.0) { - data = emit_triangle(prev, curr, next, data); - v->fPrev->fNext = v->fNext; - v->fNext->fPrev = v->fPrev; - if (v->fPrev == first) { - v = v->fNext; - } else { - v = v->fPrev; - } - } else { - v = v->fNext; - } - } - return data; - } - }; - Poly* addVertex(Vertex* v, Side side, SkChunkAlloc& alloc) { - LOG("addVertex() to %d at %g (%g, %g), %s side\n", fID, v->fID, v->fPoint.fX, v->fPoint.fY, - side == kLeft_Side ? "left" : side == kRight_Side ? "right" : "neither"); - Poly* partner = fPartner; - Poly* poly = this; - if (partner) { - fPartner = partner->fPartner = nullptr; - } - if (!fActive) { - fActive = ALLOC_NEW(MonotonePoly, (), alloc); - } - if (fActive->addVertex(v, side, alloc)) { - if (fTail) { - fActive->fPrev = fTail; - fTail->fNext = fActive; - fTail = fActive; - } else { - fHead = fTail = fActive; - } - if (partner) { - partner->addVertex(v, side, alloc); - poly = partner; - } else { - Vertex* prev = fActive->fSide == Poly::kLeft_Side ? - fActive->fHead->fNext : fActive->fTail->fPrev; - fActive = ALLOC_NEW(MonotonePoly, , alloc); - fActive->addVertex(prev, Poly::kNeither_Side, alloc); - fActive->addVertex(v, side, alloc); - } - } - fCount++; - return poly; - } - void end(Vertex* v, SkChunkAlloc& alloc) { - LOG("end() %d at %g, %g\n", fID, v->fPoint.fX, v->fPoint.fY); - if (fPartner) { - fPartner = fPartner->fPartner = nullptr; - } - addVertex(v, fActive->fSide == kLeft_Side ? kRight_Side : kLeft_Side, alloc); - } - SkPoint* emit(SkPoint *data) { - if (fCount < 3) { - return data; - } - LOG("emit() %d, size %d\n", fID, fCount); - for (MonotonePoly* m = fHead; m != nullptr; m = m->fNext) { - data = m->emit(data); - } - return data; - } - int fWinding; - MonotonePoly* fHead; - MonotonePoly* fTail; - MonotonePoly* fActive; - Poly* fNext; - Poly* fPartner; - int fCount; -#if LOGGING_ENABLED - int fID; -#endif -}; - -/***************************************************************************************/ - -bool coincident(const SkPoint& a, const SkPoint& b) { - return a == b; -} - -Poly* new_poly(Poly** head, Vertex* v, int winding, SkChunkAlloc& alloc) { - Poly* poly = ALLOC_NEW(Poly, (winding), alloc); - poly->addVertex(v, Poly::kNeither_Side, alloc); - poly->fNext = *head; - *head = poly; - return poly; -} - -Vertex* append_point_to_contour(const SkPoint& p, Vertex* prev, Vertex** head, - SkChunkAlloc& alloc) { - Vertex* v = ALLOC_NEW(Vertex, (p), alloc); -#if LOGGING_ENABLED - static float gID = 0.0f; - v->fID = gID++; -#endif - if (prev) { - prev->fNext = v; - v->fPrev = prev; - } else { - *head = v; - } - return v; -} - -Vertex* generate_quadratic_points(const SkPoint& p0, - const SkPoint& p1, - const SkPoint& p2, - SkScalar tolSqd, - Vertex* prev, - Vertex** head, - int pointsLeft, - SkChunkAlloc& alloc) { - SkScalar d = p1.distanceToLineSegmentBetweenSqd(p0, p2); - if (pointsLeft < 2 || d < tolSqd || !SkScalarIsFinite(d)) { - return append_point_to_contour(p2, prev, head, alloc); - } - - const SkPoint q[] = { - { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, - { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) }, - }; - const SkPoint r = { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) }; - - pointsLeft >>= 1; - prev = generate_quadratic_points(p0, q[0], r, tolSqd, prev, head, pointsLeft, alloc); - prev = generate_quadratic_points(r, q[1], p2, tolSqd, prev, head, pointsLeft, alloc); - return prev; -} - -Vertex* generate_cubic_points(const SkPoint& p0, - const SkPoint& p1, - const SkPoint& p2, - const SkPoint& p3, - SkScalar tolSqd, - Vertex* prev, - Vertex** head, - int pointsLeft, - SkChunkAlloc& alloc) { - SkScalar d1 = p1.distanceToLineSegmentBetweenSqd(p0, p3); - SkScalar d2 = p2.distanceToLineSegmentBetweenSqd(p0, p3); - if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) || - !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) { - return append_point_to_contour(p3, prev, head, alloc); - } - const SkPoint q[] = { - { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, - { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) }, - { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) } - }; - const SkPoint r[] = { - { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) }, - { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) } - }; - const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) }; - pointsLeft >>= 1; - prev = generate_cubic_points(p0, q[0], r[0], s, tolSqd, prev, head, pointsLeft, alloc); - prev = generate_cubic_points(s, r[1], q[2], p3, tolSqd, prev, head, pointsLeft, alloc); - return prev; -} - -// Stage 1: convert the input path to a set of linear contours (linked list of Vertices). - -void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, - Vertex** contours, SkChunkAlloc& alloc, bool *isLinear) { - - SkScalar toleranceSqd = tolerance * tolerance; - - SkPoint pts[4]; - bool done = false; - *isLinear = true; - SkPath::Iter iter(path, false); - Vertex* prev = nullptr; - Vertex* head = nullptr; - if (path.isInverseFillType()) { - SkPoint quad[4]; - clipBounds.toQuad(quad); - for (int i = 3; i >= 0; i--) { - prev = append_point_to_contour(quad[i], prev, &head, alloc); - } - head->fPrev = prev; - prev->fNext = head; - *contours++ = head; - head = prev = nullptr; - } - SkAutoConicToQuads converter; - while (!done) { - SkPath::Verb verb = iter.next(pts); - switch (verb) { - case SkPath::kConic_Verb: { - SkScalar weight = iter.conicWeight(); - const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd); - for (int i = 0; i < converter.countQuads(); ++i) { - int pointsLeft = GrPathUtils::quadraticPointCount(quadPts, tolerance); - prev = generate_quadratic_points(quadPts[0], quadPts[1], quadPts[2], - toleranceSqd, prev, &head, pointsLeft, alloc); - quadPts += 2; - } - *isLinear = false; - break; - } - case SkPath::kMove_Verb: - if (head) { - head->fPrev = prev; - prev->fNext = head; - *contours++ = head; - } - head = prev = nullptr; - prev = append_point_to_contour(pts[0], prev, &head, alloc); - break; - case SkPath::kLine_Verb: { - prev = append_point_to_contour(pts[1], prev, &head, alloc); - break; - } - case SkPath::kQuad_Verb: { - int pointsLeft = GrPathUtils::quadraticPointCount(pts, tolerance); - prev = generate_quadratic_points(pts[0], pts[1], pts[2], toleranceSqd, prev, - &head, pointsLeft, alloc); - *isLinear = false; - break; - } - case SkPath::kCubic_Verb: { - int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); - prev = generate_cubic_points(pts[0], pts[1], pts[2], pts[3], - toleranceSqd, prev, &head, pointsLeft, alloc); - *isLinear = false; - break; - } - case SkPath::kClose_Verb: - if (head) { - head->fPrev = prev; - prev->fNext = head; - *contours++ = head; - } - head = prev = nullptr; - break; - case SkPath::kDone_Verb: - if (head) { - head->fPrev = prev; - prev->fNext = head; - *contours++ = head; - } - done = true; - break; - } - } -} - -inline bool apply_fill_type(SkPath::FillType fillType, int winding) { - switch (fillType) { - case SkPath::kWinding_FillType: - return winding != 0; - case SkPath::kEvenOdd_FillType: - return (winding & 1) != 0; - case SkPath::kInverseWinding_FillType: - return winding == 1; - case SkPath::kInverseEvenOdd_FillType: - return (winding & 1) == 1; - default: - SkASSERT(false); - return false; - } -} - -Edge* new_edge(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator& c) { - int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; - Vertex* top = winding < 0 ? next : prev; - Vertex* bottom = winding < 0 ? prev : next; - return ALLOC_NEW(Edge, (top, bottom, winding), alloc); -} - -void remove_edge(Edge* edge, EdgeList* edges) { - LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID); - SkASSERT(edge->isActive(edges)); - remove(edge, &edges->fHead, &edges->fTail); -} - -void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) { - LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID); - SkASSERT(!edge->isActive(edges)); - Edge* next = prev ? prev->fRight : edges->fHead; - insert(edge, prev, next, &edges->fHead, &edges->fTail); -} - -void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) { - if (v->fFirstEdgeAbove) { - *left = v->fFirstEdgeAbove->fLeft; - *right = v->fLastEdgeAbove->fRight; - return; - } - Edge* next = nullptr; - Edge* prev; - for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) { - if (prev->isLeftOf(v)) { - break; - } - next = prev; - } - *left = prev; - *right = next; - return; -} - -void find_enclosing_edges(Edge* edge, EdgeList* edges, Comparator& c, Edge** left, Edge** right) { - Edge* prev = nullptr; - Edge* next; - for (next = edges->fHead; next != nullptr; next = next->fRight) { - if ((c.sweep_gt(edge->fTop->fPoint, next->fTop->fPoint) && next->isRightOf(edge->fTop)) || - (c.sweep_gt(next->fTop->fPoint, edge->fTop->fPoint) && edge->isLeftOf(next->fTop)) || - (c.sweep_lt(edge->fBottom->fPoint, next->fBottom->fPoint) && - next->isRightOf(edge->fBottom)) || - (c.sweep_lt(next->fBottom->fPoint, edge->fBottom->fPoint) && - edge->isLeftOf(next->fBottom))) { - break; - } - prev = next; - } - *left = prev; - *right = next; - return; -} - -void fix_active_state(Edge* edge, EdgeList* activeEdges, Comparator& c) { - if (edge->isActive(activeEdges)) { - if (edge->fBottom->fProcessed || !edge->fTop->fProcessed) { - remove_edge(edge, activeEdges); - } - } else if (edge->fTop->fProcessed && !edge->fBottom->fProcessed) { - Edge* left; - Edge* right; - find_enclosing_edges(edge, activeEdges, c, &left, &right); - insert_edge(edge, left, activeEdges); - } -} - -void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) { - if (edge->fTop->fPoint == edge->fBottom->fPoint || - c.sweep_gt(edge->fTop->fPoint, edge->fBottom->fPoint)) { - return; - } - LOG("insert edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID); - Edge* prev = nullptr; - Edge* next; - for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) { - if (next->isRightOf(edge->fTop)) { - break; - } - prev = next; - } - insert( - edge, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove); -} - -void insert_edge_below(Edge* edge, Vertex* v, Comparator& c) { - if (edge->fTop->fPoint == edge->fBottom->fPoint || - c.sweep_gt(edge->fTop->fPoint, edge->fBottom->fPoint)) { - return; - } - LOG("insert edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID); - Edge* prev = nullptr; - Edge* next; - for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) { - if (next->isRightOf(edge->fBottom)) { - break; - } - prev = next; - } - insert( - edge, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow); -} - -void remove_edge_above(Edge* edge) { - LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID, - edge->fBottom->fID); - remove( - edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove); -} - -void remove_edge_below(Edge* edge) { - LOG("removing edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID, - edge->fTop->fID); - remove( - edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow); -} - -void erase_edge_if_zero_winding(Edge* edge, EdgeList* edges) { - if (edge->fWinding != 0) { - return; - } - LOG("erasing edge (%g -> %g)\n", edge->fTop->fID, edge->fBottom->fID); - remove_edge_above(edge); - remove_edge_below(edge); - if (edge->isActive(edges)) { - remove_edge(edge, edges); - } -} - -void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c); - -void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c) { - remove_edge_below(edge); - edge->fTop = v; - edge->recompute(); - insert_edge_below(edge, v, c); - fix_active_state(edge, activeEdges, c); - merge_collinear_edges(edge, activeEdges, c); -} - -void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c) { - remove_edge_above(edge); - edge->fBottom = v; - edge->recompute(); - insert_edge_above(edge, v, c); - fix_active_state(edge, activeEdges, c); - merge_collinear_edges(edge, activeEdges, c); -} - -void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c) { - if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) { - LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n", - edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, - edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); - other->fWinding += edge->fWinding; - erase_edge_if_zero_winding(other, activeEdges); - edge->fWinding = 0; - erase_edge_if_zero_winding(edge, activeEdges); - } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) { - other->fWinding += edge->fWinding; - erase_edge_if_zero_winding(other, activeEdges); - set_bottom(edge, other->fTop, activeEdges, c); - } else { - edge->fWinding += other->fWinding; - erase_edge_if_zero_winding(edge, activeEdges); - set_bottom(other, edge->fTop, activeEdges, c); - } -} - -void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c) { - if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) { - LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n", - edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, - edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); - other->fWinding += edge->fWinding; - erase_edge_if_zero_winding(other, activeEdges); - edge->fWinding = 0; - erase_edge_if_zero_winding(edge, activeEdges); - } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) { - edge->fWinding += other->fWinding; - erase_edge_if_zero_winding(edge, activeEdges); - set_top(other, edge->fBottom, activeEdges, c); - } else { - other->fWinding += edge->fWinding; - erase_edge_if_zero_winding(other, activeEdges); - set_top(edge, other->fBottom, activeEdges, c); - } -} - -void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c) { - if (edge->fPrevEdgeAbove && (edge->fTop == edge->fPrevEdgeAbove->fTop || - !edge->fPrevEdgeAbove->isLeftOf(edge->fTop))) { - merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, c); - } else if (edge->fNextEdgeAbove && (edge->fTop == edge->fNextEdgeAbove->fTop || - !edge->isLeftOf(edge->fNextEdgeAbove->fTop))) { - merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, c); - } - if (edge->fPrevEdgeBelow && (edge->fBottom == edge->fPrevEdgeBelow->fBottom || - !edge->fPrevEdgeBelow->isLeftOf(edge->fBottom))) { - merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, c); - } else if (edge->fNextEdgeBelow && (edge->fBottom == edge->fNextEdgeBelow->fBottom || - !edge->isLeftOf(edge->fNextEdgeBelow->fBottom))) { - merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, c); - } -} - -void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkChunkAlloc& alloc); - -void cleanup_active_edges(Edge* edge, EdgeList* activeEdges, Comparator& c, SkChunkAlloc& alloc) { - Vertex* top = edge->fTop; - Vertex* bottom = edge->fBottom; - if (edge->fLeft) { - Vertex* leftTop = edge->fLeft->fTop; - Vertex* leftBottom = edge->fLeft->fBottom; - if (c.sweep_gt(top->fPoint, leftTop->fPoint) && !edge->fLeft->isLeftOf(top)) { - split_edge(edge->fLeft, edge->fTop, activeEdges, c, alloc); - } else if (c.sweep_gt(leftTop->fPoint, top->fPoint) && !edge->isRightOf(leftTop)) { - split_edge(edge, leftTop, activeEdges, c, alloc); - } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) && - !edge->fLeft->isLeftOf(bottom)) { - split_edge(edge->fLeft, bottom, activeEdges, c, alloc); - } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) { - split_edge(edge, leftBottom, activeEdges, c, alloc); - } - } - if (edge->fRight) { - Vertex* rightTop = edge->fRight->fTop; - Vertex* rightBottom = edge->fRight->fBottom; - if (c.sweep_gt(top->fPoint, rightTop->fPoint) && !edge->fRight->isRightOf(top)) { - split_edge(edge->fRight, top, activeEdges, c, alloc); - } else if (c.sweep_gt(rightTop->fPoint, top->fPoint) && !edge->isLeftOf(rightTop)) { - split_edge(edge, rightTop, activeEdges, c, alloc); - } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) && - !edge->fRight->isRightOf(bottom)) { - split_edge(edge->fRight, bottom, activeEdges, c, alloc); - } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) && - !edge->isLeftOf(rightBottom)) { - split_edge(edge, rightBottom, activeEdges, c, alloc); - } - } -} - -void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkChunkAlloc& alloc) { - LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n", - edge->fTop->fID, edge->fBottom->fID, - v->fID, v->fPoint.fX, v->fPoint.fY); - if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) { - set_top(edge, v, activeEdges, c); - } else if (c.sweep_gt(v->fPoint, edge->fBottom->fPoint)) { - set_bottom(edge, v, activeEdges, c); - } else { - Edge* newEdge = ALLOC_NEW(Edge, (v, edge->fBottom, edge->fWinding), alloc); - insert_edge_below(newEdge, v, c); - insert_edge_above(newEdge, edge->fBottom, c); - set_bottom(edge, v, activeEdges, c); - cleanup_active_edges(edge, activeEdges, c, alloc); - fix_active_state(newEdge, activeEdges, c); - merge_collinear_edges(newEdge, activeEdges, c); - } -} - -void merge_vertices(Vertex* src, Vertex* dst, Vertex** head, Comparator& c, SkChunkAlloc& alloc) { - LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX, src->fPoint.fY, - src->fID, dst->fID); - for (Edge* edge = src->fFirstEdgeAbove; edge;) { - Edge* next = edge->fNextEdgeAbove; - set_bottom(edge, dst, nullptr, c); - edge = next; - } - for (Edge* edge = src->fFirstEdgeBelow; edge;) { - Edge* next = edge->fNextEdgeBelow; - set_top(edge, dst, nullptr, c); - edge = next; - } - remove(src, head, nullptr); -} - -Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c, - SkChunkAlloc& alloc) { - SkPoint p; - if (!edge || !other) { - return nullptr; - } - if (edge->intersect(*other, &p)) { - Vertex* v; - LOG("found intersection, pt is %g, %g\n", p.fX, p.fY); - if (p == edge->fTop->fPoint || c.sweep_lt(p, edge->fTop->fPoint)) { - split_edge(other, edge->fTop, activeEdges, c, alloc); - v = edge->fTop; - } else if (p == edge->fBottom->fPoint || c.sweep_gt(p, edge->fBottom->fPoint)) { - split_edge(other, edge->fBottom, activeEdges, c, alloc); - v = edge->fBottom; - } else if (p == other->fTop->fPoint || c.sweep_lt(p, other->fTop->fPoint)) { - split_edge(edge, other->fTop, activeEdges, c, alloc); - v = other->fTop; - } else if (p == other->fBottom->fPoint || c.sweep_gt(p, other->fBottom->fPoint)) { - split_edge(edge, other->fBottom, activeEdges, c, alloc); - v = other->fBottom; - } else { - Vertex* nextV = edge->fTop; - while (c.sweep_lt(p, nextV->fPoint)) { - nextV = nextV->fPrev; - } - while (c.sweep_lt(nextV->fPoint, p)) { - nextV = nextV->fNext; - } - Vertex* prevV = nextV->fPrev; - if (coincident(prevV->fPoint, p)) { - v = prevV; - } else if (coincident(nextV->fPoint, p)) { - v = nextV; - } else { - v = ALLOC_NEW(Vertex, (p), alloc); - LOG("inserting between %g (%g, %g) and %g (%g, %g)\n", - prevV->fID, prevV->fPoint.fX, prevV->fPoint.fY, - nextV->fID, nextV->fPoint.fX, nextV->fPoint.fY); -#if LOGGING_ENABLED - v->fID = (nextV->fID + prevV->fID) * 0.5f; -#endif - v->fPrev = prevV; - v->fNext = nextV; - prevV->fNext = v; - nextV->fPrev = v; - } - split_edge(edge, v, activeEdges, c, alloc); - split_edge(other, v, activeEdges, c, alloc); - } - return v; - } - return nullptr; -} - -void sanitize_contours(Vertex** contours, int contourCnt) { - for (int i = 0; i < contourCnt; ++i) { - SkASSERT(contours[i]); - for (Vertex* v = contours[i];;) { - if (coincident(v->fPrev->fPoint, v->fPoint)) { - LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY); - if (v->fPrev == v) { - contours[i] = nullptr; - break; - } - v->fPrev->fNext = v->fNext; - v->fNext->fPrev = v->fPrev; - if (contours[i] == v) { - contours[i] = v->fNext; - } - v = v->fPrev; - } else { - v = v->fNext; - if (v == contours[i]) break; - } - } - } -} - -void merge_coincident_vertices(Vertex** vertices, Comparator& c, SkChunkAlloc& alloc) { - for (Vertex* v = (*vertices)->fNext; v != nullptr; v = v->fNext) { - if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) { - v->fPoint = v->fPrev->fPoint; - } - if (coincident(v->fPrev->fPoint, v->fPoint)) { - merge_vertices(v->fPrev, v, vertices, c, alloc); - } - } -} - -// Stage 2: convert the contours to a mesh of edges connecting the vertices. - -Vertex* build_edges(Vertex** contours, int contourCnt, Comparator& c, SkChunkAlloc& alloc) { - Vertex* vertices = nullptr; - Vertex* prev = nullptr; - for (int i = 0; i < contourCnt; ++i) { - for (Vertex* v = contours[i]; v != nullptr;) { - Vertex* vNext = v->fNext; - Edge* edge = new_edge(v->fPrev, v, alloc, c); - if (edge->fWinding > 0) { - insert_edge_below(edge, v->fPrev, c); - insert_edge_above(edge, v, c); - } else { - insert_edge_below(edge, v, c); - insert_edge_above(edge, v->fPrev, c); - } - merge_collinear_edges(edge, nullptr, c); - if (prev) { - prev->fNext = v; - v->fPrev = prev; - } else { - vertices = v; - } - prev = v; - v = vNext; - if (v == contours[i]) break; - } - } - if (prev) { - prev->fNext = vertices->fPrev = nullptr; - } - return vertices; -} - -// Stage 3: sort the vertices by increasing sweep direction. - -Vertex* sorted_merge(Vertex* a, Vertex* b, Comparator& c); - -void front_back_split(Vertex* v, Vertex** pFront, Vertex** pBack) { - Vertex* fast; - Vertex* slow; - if (!v || !v->fNext) { - *pFront = v; - *pBack = nullptr; - } else { - slow = v; - fast = v->fNext; - - while (fast != nullptr) { - fast = fast->fNext; - if (fast != nullptr) { - slow = slow->fNext; - fast = fast->fNext; - } - } - - *pFront = v; - *pBack = slow->fNext; - slow->fNext->fPrev = nullptr; - slow->fNext = nullptr; - } -} - -void merge_sort(Vertex** head, Comparator& c) { - if (!*head || !(*head)->fNext) { - return; - } - - Vertex* a; - Vertex* b; - front_back_split(*head, &a, &b); - - merge_sort(&a, c); - merge_sort(&b, c); - - *head = sorted_merge(a, b, c); -} - -inline void append_vertex(Vertex* v, Vertex** head, Vertex** tail) { - insert(v, *tail, nullptr, head, tail); -} - -inline void append_vertex_list(Vertex* v, Vertex** head, Vertex** tail) { - insert(v, *tail, v->fNext, head, tail); -} - -Vertex* sorted_merge(Vertex* a, Vertex* b, Comparator& c) { - Vertex* head = nullptr; - Vertex* tail = nullptr; - - while (a && b) { - if (c.sweep_lt(a->fPoint, b->fPoint)) { - Vertex* next = a->fNext; - append_vertex(a, &head, &tail); - a = next; - } else { - Vertex* next = b->fNext; - append_vertex(b, &head, &tail); - b = next; - } - } - if (a) { - append_vertex_list(a, &head, &tail); - } - if (b) { - append_vertex_list(b, &head, &tail); - } - return head; -} - -// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges. - -void simplify(Vertex* vertices, Comparator& c, SkChunkAlloc& alloc) { - LOG("simplifying complex polygons\n"); - EdgeList activeEdges; - for (Vertex* v = vertices; v != nullptr; v = v->fNext) { - if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) { - continue; - } -#if LOGGING_ENABLED - LOG("\nvertex %g: (%g,%g)\n", v->fID, v->fPoint.fX, v->fPoint.fY); -#endif - Edge* leftEnclosingEdge = nullptr; - Edge* rightEnclosingEdge = nullptr; - bool restartChecks; - do { - restartChecks = false; - find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); - if (v->fFirstEdgeBelow) { - for (Edge* edge = v->fFirstEdgeBelow; edge != nullptr; edge = edge->fNextEdgeBelow) { - if (check_for_intersection(edge, leftEnclosingEdge, &activeEdges, c, alloc)) { - restartChecks = true; - break; - } - if (check_for_intersection(edge, rightEnclosingEdge, &activeEdges, c, alloc)) { - restartChecks = true; - break; - } - } - } else { - if (Vertex* pv = check_for_intersection(leftEnclosingEdge, rightEnclosingEdge, - &activeEdges, c, alloc)) { - if (c.sweep_lt(pv->fPoint, v->fPoint)) { - v = pv; - } - restartChecks = true; - } - - } - } while (restartChecks); - for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { - remove_edge(e, &activeEdges); - } - Edge* leftEdge = leftEnclosingEdge; - for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { - insert_edge(e, leftEdge, &activeEdges); - leftEdge = e; - } - v->fProcessed = true; - } -} - -// Stage 5: Tessellate the simplified mesh into monotone polygons. - -Poly* tessellate(Vertex* vertices, SkChunkAlloc& alloc) { - LOG("tessellating simple polygons\n"); - EdgeList activeEdges; - Poly* polys = nullptr; - for (Vertex* v = vertices; v != nullptr; v = v->fNext) { - if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) { - continue; - } -#if LOGGING_ENABLED - LOG("\nvertex %g: (%g,%g)\n", v->fID, v->fPoint.fX, v->fPoint.fY); -#endif - Edge* leftEnclosingEdge = nullptr; - Edge* rightEnclosingEdge = nullptr; - find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); - Poly* leftPoly = nullptr; - Poly* rightPoly = nullptr; - if (v->fFirstEdgeAbove) { - leftPoly = v->fFirstEdgeAbove->fLeftPoly; - rightPoly = v->fLastEdgeAbove->fRightPoly; - } else { - leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr; - rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr; - } -#if LOGGING_ENABLED - LOG("edges above:\n"); - for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { - LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID, - e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1); - } - LOG("edges below:\n"); - for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { - LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID, - e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1); - } -#endif - if (v->fFirstEdgeAbove) { - if (leftPoly) { - leftPoly = leftPoly->addVertex(v, Poly::kRight_Side, alloc); - } - if (rightPoly) { - rightPoly = rightPoly->addVertex(v, Poly::kLeft_Side, alloc); - } - for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) { - Edge* leftEdge = e; - Edge* rightEdge = e->fNextEdgeAbove; - SkASSERT(rightEdge->isRightOf(leftEdge->fTop)); - remove_edge(leftEdge, &activeEdges); - if (leftEdge->fRightPoly) { - leftEdge->fRightPoly->end(v, alloc); - } - if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != leftEdge->fRightPoly) { - rightEdge->fLeftPoly->end(v, alloc); - } - } - remove_edge(v->fLastEdgeAbove, &activeEdges); - if (!v->fFirstEdgeBelow) { - if (leftPoly && rightPoly && leftPoly != rightPoly) { - SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr); - rightPoly->fPartner = leftPoly; - leftPoly->fPartner = rightPoly; - } - } - } - if (v->fFirstEdgeBelow) { - if (!v->fFirstEdgeAbove) { - if (leftPoly && leftPoly == rightPoly) { - // Split the poly. - if (leftPoly->fActive->fSide == Poly::kLeft_Side) { - leftPoly = new_poly(&polys, leftEnclosingEdge->fTop, leftPoly->fWinding, - alloc); - leftPoly->addVertex(v, Poly::kRight_Side, alloc); - rightPoly->addVertex(v, Poly::kLeft_Side, alloc); - leftEnclosingEdge->fRightPoly = leftPoly; - } else { - rightPoly = new_poly(&polys, rightEnclosingEdge->fTop, rightPoly->fWinding, - alloc); - rightPoly->addVertex(v, Poly::kLeft_Side, alloc); - leftPoly->addVertex(v, Poly::kRight_Side, alloc); - rightEnclosingEdge->fLeftPoly = rightPoly; - } - } else { - if (leftPoly) { - leftPoly = leftPoly->addVertex(v, Poly::kRight_Side, alloc); - } - if (rightPoly) { - rightPoly = rightPoly->addVertex(v, Poly::kLeft_Side, alloc); - } - } - } - Edge* leftEdge = v->fFirstEdgeBelow; - leftEdge->fLeftPoly = leftPoly; - insert_edge(leftEdge, leftEnclosingEdge, &activeEdges); - for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge; - rightEdge = rightEdge->fNextEdgeBelow) { - insert_edge(rightEdge, leftEdge, &activeEdges); - int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0; - winding += leftEdge->fWinding; - if (winding != 0) { - Poly* poly = new_poly(&polys, v, winding, alloc); - leftEdge->fRightPoly = rightEdge->fLeftPoly = poly; - } - leftEdge = rightEdge; - } - v->fLastEdgeBelow->fRightPoly = rightPoly; - } -#if LOGGING_ENABLED - LOG("\nactive edges:\n"); - for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) { - LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID, - e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1); - } -#endif - } - return polys; -} - -// This is a driver function which calls stages 2-5 in turn. - -Poly* contours_to_polys(Vertex** contours, int contourCnt, Comparator& c, SkChunkAlloc& alloc) { -#if LOGGING_ENABLED - for (int i = 0; i < contourCnt; ++i) { - Vertex* v = contours[i]; - SkASSERT(v); - LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); - for (v = v->fNext; v != contours[i]; v = v->fNext) { - LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); - } - } -#endif - sanitize_contours(contours, contourCnt); - Vertex* vertices = build_edges(contours, contourCnt, c, alloc); - if (!vertices) { - return nullptr; - } - - // Sort vertices in Y (secondarily in X). - merge_sort(&vertices, c); - merge_coincident_vertices(&vertices, c, alloc); -#if LOGGING_ENABLED - for (Vertex* v = vertices; v != nullptr; v = v->fNext) { - static float gID = 0.0f; - v->fID = gID++; - } -#endif - simplify(vertices, c, alloc); - return tessellate(vertices, alloc); -} - -// Stage 6: Triangulate the monotone polygons into a vertex buffer. - -SkPoint* polys_to_triangles(Poly* polys, SkPath::FillType fillType, SkPoint* data) { - SkPoint* d = data; - for (Poly* poly = polys; poly; poly = poly->fNext) { - if (apply_fill_type(fillType, poly->fWinding)) { - d = poly->emit(d); - } - } - return d; -} - struct TessInfo { SkScalar fTolerance; int fCount; }; +// When the SkPathRef genID changes, invalidate a corresponding GrResource described by key. +class PathInvalidator : public SkPathRef::GenIDChangeListener { +public: + explicit PathInvalidator(const GrUniqueKey& key) : fMsg(key) {} +private: + GrUniqueKeyInvalidatedMessage fMsg; + + void onChange() override { + SkMessageBus::Post(fMsg); + } +}; + bool cache_match(GrVertexBuffer* vertexBuffer, SkScalar tol, int* actualCount) { if (!vertexBuffer) { return false; @@ -1354,27 +59,11 @@ bool cache_match(GrVertexBuffer* vertexBuffer, SkScalar tol, int* actualCount) { return false; } -}; +} // namespace GrTessellatingPathRenderer::GrTessellatingPathRenderer() { } -namespace { - -// When the SkPathRef genID changes, invalidate a corresponding GrResource described by key. -class PathInvalidator : public SkPathRef::GenIDChangeListener { -public: - explicit PathInvalidator(const GrUniqueKey& key) : fMsg(key) {} -private: - GrUniqueKeyInvalidatedMessage fMsg; - - void onChange() override { - SkMessageBus::Post(fMsg); - } -}; - -} // namespace - bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { // This path renderer can draw all fill styles, all stroke styles except hairlines, but does // not do antialiasing. It can do convex and concave paths, but we'll leave the convex ones to @@ -1435,90 +124,23 @@ private: } stroke.setFillStyle(); } - SkRect pathBounds = path.getBounds(); - Comparator c; - if (pathBounds.width() > pathBounds.height()) { - c.sweep_lt = sweep_lt_horiz; - c.sweep_gt = sweep_gt_horiz; - } else { - c.sweep_lt = sweep_lt_vert; - c.sweep_gt = sweep_gt_vert; - } SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; + SkRect pathBounds = path.getBounds(); SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMatrix, pathBounds); - int contourCnt; - int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol); - if (maxPts <= 0) { - return 0; - } - if (maxPts > ((int)SK_MaxU16 + 1)) { - SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); - return 0; - } - SkPath::FillType fillType = path.getFillType(); - if (SkPath::IsInverseFillType(fillType)) { - contourCnt++; - } - LOG("got %d pts, %d contours\n", maxPts, contourCnt); - SkAutoTDeleteArray contours(new Vertex* [contourCnt]); - - // For the initial size of the chunk allocator, estimate based on the point count: - // one vertex per point for the initial passes, plus two for the vertices in the - // resulting Polys, since the same point may end up in two Polys. Assume minimal - // connectivity of one Edge per Vertex (will grow for intersections). - SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); bool isLinear; - path_to_contours(path, tol, fClipBounds, contours.get(), alloc, &isLinear); - Poly* polys; - polys = contours_to_polys(contours.get(), contourCnt, c, alloc); - int count = 0; - for (Poly* poly = polys; poly; poly = poly->fNext) { - if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3) { - count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); - } - } - if (0 == count) { - return 0; - } - - size_t size = count * sizeof(SkPoint); - if (!vertexBuffer.get() || vertexBuffer->gpuMemorySize() < size) { - vertexBuffer.reset(resourceProvider->createVertexBuffer( - size, GrResourceProvider::kStatic_BufferUsage, 0)); - } - if (!vertexBuffer.get()) { - SkDebugf("Could not allocate vertices\n"); - return 0; - } - SkPoint* verts; - if (canMapVB) { - verts = static_cast(vertexBuffer->map()); - } else { - verts = new SkPoint[count]; - } - SkPoint* end = polys_to_triangles(polys, fillType, verts); - int actualCount = static_cast(end - verts); - LOG("actual count: %d\n", actualCount); - SkASSERT(actualCount <= count); - if (canMapVB) { - vertexBuffer->unmap(); - } else { - vertexBuffer->updateData(verts, actualCount * sizeof(SkPoint)); - delete[] verts; - } - - + int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, resourceProvider, + vertexBuffer, canMapVB, &isLinear); if (!fPath.isVolatile()) { TessInfo info; info.fTolerance = isLinear ? 0 : tol; - info.fCount = actualCount; + info.fCount = count; SkAutoTUnref data(SkData::NewWithCopy(&info, sizeof(info))); key->setCustomData(data.get()); resourceProvider->assignUniqueKeyToResource(*key, vertexBuffer.get()); SkPathPriv::AddGenIDChangeListener(fPath, new PathInvalidator(*key)); } - return actualCount; + return count; } void onPrepareDraws(Target* target) const override { @@ -1574,8 +196,8 @@ private: target->initDraw(gp, this->pipeline()); SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); - GrPrimitiveType primitiveType = WIREFRAME ? kLines_GrPrimitiveType - : kTriangles_GrPrimitiveType; + GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimitiveType + : kTriangles_GrPrimitiveType; GrVertices vertices; vertices.init(primitiveType, vertexBuffer.get(), 0, actualCount); target->draw(vertices); @@ -1627,6 +249,8 @@ private: }; bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { + GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), + "GrTessellatingPathRenderer::onDrawPath"); SkASSERT(!args.fAntiAlias); const GrRenderTarget* rt = args.fPipelineBuilder->getRenderTarget(); if (nullptr == rt) { diff --git a/gfx/skia/skia/src/gpu/effects/GrBezierEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrBezierEffect.cpp index 13672da6ea2..fdb737dab46 100644 --- a/gfx/skia/skia/src/gpu/effects/GrBezierEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrBezierEffect.cpp @@ -7,11 +7,13 @@ #include "GrBezierEffect.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLUtil.h" #include "glsl/GrGLSLVarying.h" +#include "glsl/GrGLSLVertexShaderBuilder.h" class GrGLConicEffect : public GrGLSLGeometryProcessor { public: @@ -73,63 +75,98 @@ GrGLConicEffect::GrGLConicEffect(const GrGeometryProcessor& processor) } void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; const GrConicEffect& gp = args.fGP.cast(); GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(gp); GrGLSLVertToFrag v(kVec4f_GrSLType); - varyingHandler->addVarying("ConicCoeffs", &v); + varyingHandler->addVarying("ConicCoeffs", &v, kHigh_GrSLPrecision); vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inConicCoeffs()->fName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (!gp.colorIgnored()) { - this->setupUniformColor(args.fPB, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); } // Setup position - this->setupPosition(pb, - vertBuilder, + this->setupPosition(vertBuilder, + uniformHandler, gpArgs, gp.inPosition()->fName, gp.viewMatrix(), &fViewMatrixUniform); // emit transforms with position - this->emitTransforms(pb, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, gp.inPosition()->fName, gp.localMatrix(), args.fTransformsIn, args.fTransformsOut); - fragBuilder->codeAppend("float edgeAlpha;"); + // TODO: this precision check should actually be a check on the number of bits + // high and medium provide and the selection of the lowest level that suffices. + // Additionally we should assert that the upstream code only lets us get here if + // either high or medium provides the required number of bits. + GrSLPrecision precision = kHigh_GrSLPrecision; + const GrShaderCaps::PrecisionInfo& highP = args.fGLSLCaps->getFloatShaderPrecisionInfo( + kFragment_GrShaderType, + kHigh_GrSLPrecision); + if (!highP.supported()) { + precision = kMedium_GrSLPrecision; + } + + GrGLSLShaderVar edgeAlpha("edgeAlpha", kFloat_GrSLType, 0, precision); + GrGLSLShaderVar dklmdx("dklmdx", kVec3f_GrSLType, 0, precision); + GrGLSLShaderVar dklmdy("dklmdy", kVec3f_GrSLType, 0, precision); + GrGLSLShaderVar dfdx("dfdx", kFloat_GrSLType, 0, precision); + GrGLSLShaderVar dfdy("dfdy", kFloat_GrSLType, 0, precision); + GrGLSLShaderVar gF("gF", kVec2f_GrSLType, 0, precision); + GrGLSLShaderVar gFM("gFM", kFloat_GrSLType, 0, precision); + GrGLSLShaderVar func("func", kFloat_GrSLType, 0, precision); + + fragBuilder->declAppend(edgeAlpha); + fragBuilder->declAppend(dklmdx); + fragBuilder->declAppend(dklmdy); + fragBuilder->declAppend(dfdx); + fragBuilder->declAppend(dfdy); + fragBuilder->declAppend(gF); + fragBuilder->declAppend(gFM); + fragBuilder->declAppend(func); switch (fEdgeType) { case kHairlineAA_GrProcessorEdgeType: { SkAssertResult(fragBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); - fragBuilder->codeAppendf("vec3 dklmdx = dFdx(%s.xyz);", v.fsIn()); - fragBuilder->codeAppendf("vec3 dklmdy = dFdy(%s.xyz);", v.fsIn()); - fragBuilder->codeAppendf("float dfdx =" - "2.0 * %s.x * dklmdx.x - %s.y * dklmdx.z - %s.z * dklmdx.y;", - v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppendf("float dfdy =" - "2.0 * %s.x * dklmdy.x - %s.y * dklmdy.z - %s.z * dklmdy.y;", - v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppend("vec2 gF = vec2(dfdx, dfdy);"); - fragBuilder->codeAppend("float gFM = sqrt(dot(gF, gF));"); - fragBuilder->codeAppendf("float func = %s.x*%s.x - %s.y*%s.z;", v.fsIn(), v.fsIn(), - v.fsIn(), v.fsIn()); - fragBuilder->codeAppend("func = abs(func);"); - fragBuilder->codeAppend("edgeAlpha = func / gFM;"); - fragBuilder->codeAppend("edgeAlpha = max(1.0 - edgeAlpha, 0.0);"); + fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); + fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); + fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", + dfdx.c_str(), + v.fsIn(), dklmdx.c_str(), + v.fsIn(), dklmdx.c_str(), + v.fsIn(), dklmdx.c_str()); + fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", + dfdy.c_str(), + v.fsIn(), dklmdy.c_str(), + v.fsIn(), dklmdy.c_str(), + v.fsIn(), dklmdy.c_str()); + fragBuilder->codeAppendf("%s = vec2(%s, %s);", gF.c_str(), dfdx.c_str(), dfdy.c_str()); + fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", + gFM.c_str(), gF.c_str(), gF.c_str()); + fragBuilder->codeAppendf("%s = %s.x*%s.x - %s.y*%s.z;", + func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); + fragBuilder->codeAppendf("%s = abs(%s);", func.c_str(), func.c_str()); + fragBuilder->codeAppendf("%s = %s / %s;", + edgeAlpha.c_str(), func.c_str(), gFM.c_str()); + fragBuilder->codeAppendf("%s = max(1.0 - %s, 0.0);", + edgeAlpha.c_str(), edgeAlpha.c_str()); // Add line below for smooth cubic ramp // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);"); break; @@ -137,28 +174,38 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { case kFillAA_GrProcessorEdgeType: { SkAssertResult(fragBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); - fragBuilder->codeAppendf("vec3 dklmdx = dFdx(%s.xyz);", v.fsIn()); - fragBuilder->codeAppendf("vec3 dklmdy = dFdy(%s.xyz);", v.fsIn()); - fragBuilder->codeAppendf("float dfdx =" - "2.0 * %s.x * dklmdx.x - %s.y * dklmdx.z - %s.z * dklmdx.y;", - v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppendf("float dfdy =" - "2.0 * %s.x * dklmdy.x - %s.y * dklmdy.z - %s.z * dklmdy.y;", - v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppend("vec2 gF = vec2(dfdx, dfdy);"); - fragBuilder->codeAppend("float gFM = sqrt(dot(gF, gF));"); - fragBuilder->codeAppendf("float func = %s.x * %s.x - %s.y * %s.z;", v.fsIn(), v.fsIn(), - v.fsIn(), v.fsIn()); - fragBuilder->codeAppend("edgeAlpha = func / gFM;"); - fragBuilder->codeAppend("edgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);"); + fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); + fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); + fragBuilder->codeAppendf("%s =" + "2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", + dfdx.c_str(), + v.fsIn(), dklmdx.c_str(), + v.fsIn(), dklmdx.c_str(), + v.fsIn(), dklmdx.c_str()); + fragBuilder->codeAppendf("%s =" + "2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", + dfdy.c_str(), + v.fsIn(), dklmdy.c_str(), + v.fsIn(), dklmdy.c_str(), + v.fsIn(), dklmdy.c_str()); + fragBuilder->codeAppendf("%s = vec2(%s, %s);", gF.c_str(), dfdx.c_str(), dfdy.c_str()); + fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", + gFM.c_str(), gF.c_str(), gF.c_str()); + fragBuilder->codeAppendf("%s = %s.x * %s.x - %s.y * %s.z;", + func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); + fragBuilder->codeAppendf("%s = %s / %s;", + edgeAlpha.c_str(), func.c_str(), gFM.c_str()); + fragBuilder->codeAppendf("%s = clamp(1.0 - %s, 0.0, 1.0);", + edgeAlpha.c_str(), edgeAlpha.c_str()); // Add line below for smooth cubic ramp // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);"); break; } case kFillBW_GrProcessorEdgeType: { - fragBuilder->codeAppendf("edgeAlpha = %s.x * %s.x - %s.y * %s.z;", v.fsIn(), v.fsIn(), - v.fsIn(), v.fsIn()); - fragBuilder->codeAppend("edgeAlpha = float(edgeAlpha < 0.0);"); + fragBuilder->codeAppendf("%s = %s.x * %s.x - %s.y * %s.z;", + edgeAlpha.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); + fragBuilder->codeAppendf("%s = float(%s < 0.0);", + edgeAlpha.c_str(), edgeAlpha.c_str()); break; } default: @@ -168,14 +215,16 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { // TODO should we really be doing this? if (gp.coverageScale() != 0xff) { const char* coverageScale; - fCoverageScaleUniform = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, - kDefault_GrSLPrecision, - "Coverage", - &coverageScale); - fragBuilder->codeAppendf("%s = vec4(%s * edgeAlpha);", args.fOutputCoverage, coverageScale); + fCoverageScaleUniform = uniformHandler->addUniform( + GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, + kHigh_GrSLPrecision, + "Coverage", + &coverageScale); + fragBuilder->codeAppendf("%s = vec4(%s * %s);", + args.fOutputCoverage, coverageScale, edgeAlpha.c_str()); } else { - fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage); + fragBuilder->codeAppendf("%s = vec4(%s);", args.fOutputCoverage, edgeAlpha.c_str()); } } @@ -301,10 +350,10 @@ GrGLQuadEffect::GrGLQuadEffect(const GrGeometryProcessor& processor) } void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; const GrQuadEffect& gp = args.fGP.cast(); GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(gp); @@ -316,21 +365,21 @@ void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (!gp.colorIgnored()) { - this->setupUniformColor(args.fPB, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); } // Setup position - this->setupPosition(pb, - vertBuilder, + this->setupPosition(vertBuilder, + uniformHandler, gpArgs, gp.inPosition()->fName, gp.viewMatrix(), &fViewMatrixUniform); // emit transforms with position - this->emitTransforms(pb, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, gp.inPosition()->fName, gp.localMatrix(), @@ -384,11 +433,12 @@ void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { if (0xff != gp.coverageScale()) { const char* coverageScale; - fCoverageScaleUniform = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, - kDefault_GrSLPrecision, - "Coverage", - &coverageScale); + fCoverageScaleUniform = uniformHandler->addUniform( + GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, + kDefault_GrSLPrecision, + "Coverage", + &coverageScale); fragBuilder->codeAppendf("%s = vec4(%s * edgeAlpha);", args.fOutputCoverage, coverageScale); } else { fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage); @@ -507,6 +557,7 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; const GrCubicEffect& gp = args.fGP.cast(); GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(gp); @@ -518,21 +569,21 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (!gp.colorIgnored()) { - this->setupUniformColor(args.fPB, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); } // Setup position - this->setupPosition(args.fPB, - vertBuilder, + this->setupPosition(vertBuilder, + uniformHandler, gpArgs, gp.inPosition()->fName, gp.viewMatrix(), &fViewMatrixUniform); // emit transforms with position - this->emitTransforms(args.fPB, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, gp.inPosition()->fName, args.fTransformsIn, @@ -602,8 +653,8 @@ void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", gFM.c_str(), gF.c_str(), gF.c_str()); fragBuilder->codeAppendf("%s = %s.x * %s.x * %s.x - %s.y * %s.z;", - func.c_str(), v.fsIn(), v.fsIn(), - v.fsIn(), v.fsIn(), v.fsIn()); + func.c_str(), + v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); fragBuilder->codeAppendf("%s = %s / %s;", edgeAlpha.c_str(), func.c_str(), gFM.c_str()); fragBuilder->codeAppendf("%s = clamp(1.0 - %s, 0.0, 1.0);", diff --git a/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.cpp index 8efcffdf030..37ac4ab7663 100644 --- a/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrBicubicEffect.cpp @@ -8,8 +8,8 @@ #include "GrBicubicEffect.h" #include "GrInvariantOutput.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #define DS(x) SkDoubleToScalar(x) @@ -52,15 +52,16 @@ GrGLBicubicEffect::GrGLBicubicEffect(const GrProcessor&) { void GrGLBicubicEffect::emitCode(EmitArgs& args) { const GrTextureDomain& domain = args.fFp.cast().domain(); - fCoefficientsUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kMat44f_GrSLType, kDefault_GrSLPrecision, - "Coefficients"); - fImageIncrementUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "ImageIncrement"); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fCoefficientsUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kMat44f_GrSLType, kDefault_GrSLPrecision, + "Coefficients"); + fImageIncrementUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "ImageIncrement"); - const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni); - const char* coeff = args.fBuilder->getUniformCStr(fCoefficientsUni); + const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); + const char* coeff = uniformHandler->getUniformCStr(fCoefficientsUni); SkString cubicBlendName; @@ -98,6 +99,7 @@ void GrGLBicubicEffect::emitCode(EmitArgs& args) { SkString sampleVar; sampleVar.printf("rowColors[%d]", x); fDomain.sampleTexture(fragBuilder, + args.fUniformHandler, args.fGLSLCaps, domain, sampleVar.c_str(), diff --git a/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp b/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp index 594646256e5..6fd353849e1 100644 --- a/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp @@ -10,8 +10,8 @@ #include "GrTexture.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" #include "glsl/GrGLSLVertexShaderBuilder.h" @@ -22,9 +22,9 @@ public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const GrBitmapTextGeoProc& cte = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(cte); @@ -49,17 +49,18 @@ public: if (cte.hasVertexColor()) { varyingHandler->addPassThroughAttribute(cte.inColor(), args.fOutputColor); } else { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, + &fColorUniform); } } // Setup position - this->setupPosition(pb, vertBuilder, gpArgs, cte.inPosition()->fName); + this->setupPosition(vertBuilder, gpArgs, cte.inPosition()->fName); // emit transforms - this->emitTransforms(args.fPB, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, cte.inPosition()->fName, cte.localMatrix(), @@ -143,9 +144,8 @@ GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color, GrTexture* texture, this->initClassID(); fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType)); - // TODO we could think about removing this attribute if color is ignored, but unfortunately - // we don't do text positioning in batch, so we can't quite do that yet. - bool hasVertexColor = kA8_GrMaskFormat == fMaskFormat; + bool hasVertexColor = kA8_GrMaskFormat == fMaskFormat || + kA565_GrMaskFormat == fMaskFormat; if (hasVertexColor) { fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType)); } diff --git a/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.cpp index 4df894b40a6..129d057b7f1 100644 --- a/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrConfigConversionEffect.cpp @@ -13,7 +13,6 @@ #include "SkMatrix.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" class GrGLConfigConversionEffect : public GrGLSLFragmentProcessor { public: diff --git a/gfx/skia/skia/src/gpu/effects/GrConstColorProcessor.cpp b/gfx/skia/skia/src/gpu/effects/GrConstColorProcessor.cpp index cf567aac5c4..03b0fa40542 100644 --- a/gfx/skia/skia/src/gpu/effects/GrConstColorProcessor.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrConstColorProcessor.cpp @@ -6,10 +6,11 @@ */ #include "effects/GrConstColorProcessor.h" +#include "GrInvariantOutput.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" class GLConstColorProcessor : public GrGLSLFragmentProcessor { public: @@ -18,9 +19,10 @@ public: void emitCode(EmitArgs& args) override { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* colorUni; - fColorUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kMedium_GrSLPrecision, "constantColor", - &colorUni); + fColorUniform = args.fUniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kMedium_GrSLPrecision, + "constantColor", + &colorUni); GrConstColorProcessor::InputMode mode = args.fFp.cast().inputMode(); if (!args.fInputColor) { mode = GrConstColorProcessor::kIgnore_InputMode; diff --git a/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.cpp index 13df7bc4bd6..dc7a5285013 100644 --- a/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrConvexPolyEffect.cpp @@ -10,8 +10,8 @@ #include "SkPathPriv.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" ////////////////////////////////////////////////////////////////////////////// class AARectEffect : public GrFragmentProcessor { @@ -105,11 +105,11 @@ void GLAARectEffect::emitCode(EmitArgs& args) { const char *rectName; // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5), // respectively. - fRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, - kDefault_GrSLPrecision, - "rect", - &rectName); + fRectUniform = args.fUniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, + kDefault_GrSLPrecision, + "rect", + &rectName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* fragmentPos = fragBuilder->fragmentPosition(); @@ -191,12 +191,12 @@ void GrGLConvexPolyEffect::emitCode(EmitArgs& args) { const GrConvexPolyEffect& cpe = args.fFp.cast(); const char *edgeArrayName; - fEdgeUniform = args.fBuilder->addUniformArray(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, - kDefault_GrSLPrecision, - "edges", - cpe.getEdgeCount(), - &edgeArrayName); + fEdgeUniform = args.fUniformHandler->addUniformArray(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, + kDefault_GrSLPrecision, + "edges", + cpe.getEdgeCount(), + &edgeArrayName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppend("\t\tfloat alpha = 1.0;\n"); fragBuilder->codeAppend("\t\tfloat edge;\n"); diff --git a/gfx/skia/skia/src/gpu/effects/GrConvolutionEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrConvolutionEffect.cpp index 8e05f4789b7..fb68a29420c 100644 --- a/gfx/skia/skia/src/gpu/effects/GrConvolutionEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrConvolutionEffect.cpp @@ -8,8 +8,8 @@ #include "GrConvolutionEffect.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" // For brevity typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; @@ -48,17 +48,18 @@ GrGLConvolutionEffect::GrGLConvolutionEffect(const GrProcessor& processor) { } void GrGLConvolutionEffect::emitCode(EmitArgs& args) { - fImageIncrementUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "ImageIncrement"); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fImageIncrementUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "ImageIncrement"); if (this->useBounds()) { - fBoundsUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "Bounds"); + fBoundsUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "Bounds"); } - fKernelUni = args.fBuilder->addUniformArray(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "Kernel", this->width()); + fKernelUni = uniformHandler->addUniformArray(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "Kernel", this->width()); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); @@ -66,8 +67,8 @@ void GrGLConvolutionEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", args.fOutputColor); int width = this->width(); - const GrGLSLShaderVar& kernel = args.fBuilder->getUniformVariable(fKernelUni); - const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni); + const GrGLSLShaderVar& kernel = uniformHandler->getUniformVariable(fKernelUni); + const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); fragBuilder->codeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str(), fRadius, imgInc); @@ -82,7 +83,7 @@ void GrGLConvolutionEffect::emitCode(EmitArgs& args) { // We used to compute a bool indicating whether we're in bounds or not, cast it to a // float, and then mul weight*texture_sample by the float. However, the Adreno 430 seems // to have a bug that caused corruption. - const char* bounds = args.fBuilder->getUniformCStr(fBoundsUni); + const char* bounds = uniformHandler->getUniformCStr(fBoundsUni); const char* component = this->direction() == Gr1DKernelEffect::kY_Direction ? "y" : "x"; fragBuilder->codeAppendf("if (coord.%s >= %s.x && coord.%s <= %s.y) {", component, bounds, component, bounds); diff --git a/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.cpp b/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.cpp index 219ed0b505c..7761a6445ac 100644 --- a/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrCoverageSetOpXP.cpp @@ -12,8 +12,8 @@ #include "GrProcessor.h" #include "GrProcOptInfo.h" #include "glsl/GrGLSLBlend.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLXferProcessor.h" class CoverageSetOpXP : public GrXferProcessor { @@ -200,8 +200,8 @@ public: } private: - void emitBlendCodeForDstRead(GrGLSLXPBuilder* pb, - GrGLSLXPFragmentBuilder* fragBuilder, + void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, + GrGLSLUniformHandler* uniformHandler, const char* srcColor, const char* srcCoverage, const char* dstColor, diff --git a/gfx/skia/skia/src/gpu/effects/GrCustomXfermode.cpp b/gfx/skia/skia/src/gpu/effects/GrCustomXfermode.cpp index d2aff6042c2..04ff4a746ba 100644 --- a/gfx/skia/skia/src/gpu/effects/GrCustomXfermode.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrCustomXfermode.cpp @@ -20,8 +20,8 @@ #include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLXferProcessor.h" bool GrCustomXfermode::IsSupportedMode(SkXfermode::Mode mode) { @@ -158,8 +158,8 @@ private: } } - void emitBlendCodeForDstRead(GrGLSLXPBuilder* pb, - GrGLSLXPFragmentBuilder* fragBuilder, + void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, + GrGLSLUniformHandler* uniformHandler, const char* srcColor, const char* srcCoverage, const char* dstColor, diff --git a/gfx/skia/skia/src/gpu/effects/GrDashingEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrDashingEffect.cpp index e62ede0a33c..1516efd2b21 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDashingEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrDashingEffect.cpp @@ -23,8 +23,8 @@ #include "batches/GrVertexBatch.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" #include "glsl/GrGLSLVertexShaderBuilder.h" @@ -863,9 +863,9 @@ GLDashingCircleEffect::GLDashingCircleEffect() { void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { const DashingCircleEffect& dce = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(dce); @@ -883,16 +883,16 @@ void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (!dce.colorIgnored()) { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); } // Setup position - this->setupPosition(pb, vertBuilder, gpArgs, dce.inPosition()->fName); + this->setupPosition(vertBuilder, gpArgs, dce.inPosition()->fName); // emit transforms - this->emitTransforms(args.fPB, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, dce.inPosition()->fName, dce.localMatrix(), @@ -1075,10 +1075,10 @@ GLDashingLineEffect::GLDashingLineEffect() { void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { const DashingLineEffect& de = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(de); @@ -1097,16 +1097,16 @@ void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (!de.colorIgnored()) { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); + this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); } // Setup position - this->setupPosition(pb, vertBuilder, gpArgs, de.inPosition()->fName); + this->setupPosition(vertBuilder, gpArgs, de.inPosition()->fName); // emit transforms - this->emitTransforms(args.fPB, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, de.inPosition()->fName, de.localMatrix(), diff --git a/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.cpp b/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.cpp index e669f8b0240..70e40e4a14a 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrDisableColorXP.cpp @@ -8,7 +8,6 @@ #include "effects/GrDisableColorXP.h" #include "GrProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLXferProcessor.h" diff --git a/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp index cf77157e0d3..7a63a62dec6 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp @@ -13,8 +13,8 @@ #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLUtil.h" #include "glsl/GrGLSLVarying.h" #include "glsl/GrGLSLVertexShaderBuilder.h" @@ -26,7 +26,6 @@ class GrGLDistanceFieldA8TextGeoProc : public GrGLSLGeometryProcessor { public: GrGLDistanceFieldA8TextGeoProc() : fViewMatrix(SkMatrix::InvalidMatrix()) - , fColor(GrColor_ILLEGAL) #ifdef SK_GAMMA_APPLY_TO_A8 , fDistanceAdjust(-1.0f) #endif @@ -35,13 +34,13 @@ public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldA8TextGeoProc& dfTexEffect = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLFragmentBuilder* 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); @@ -50,32 +49,28 @@ public: // adjust based on gamma const char* distanceAdjustUniName = nullptr; // width, height, 1/(3*width) - fDistanceAdjustUni = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "DistanceAdjust", &distanceAdjustUniName); + fDistanceAdjustUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "DistanceAdjust", &distanceAdjustUniName); #endif // Setup pass through color if (!dfTexEffect.colorIgnored()) { - if (dfTexEffect.hasVertexColor()) { - varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); - } else { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); - } + varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); } // Setup position - this->setupPosition(pb, - vertBuilder, + this->setupPosition(vertBuilder, + uniformHandler, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(), &fViewMatrixUniform); // emit transforms - this->emitTransforms(pb, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, args.fTransformsIn, @@ -173,13 +168,6 @@ public: GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix); pdman.setMatrix3f(fViewMatrixUniform, viewMatrix); } - - if (dfa8gp.color() != fColor && !dfa8gp.hasVertexColor()) { - float c[4]; - GrColorToRGBAFloat(dfa8gp.color(), c); - pdman.set4fv(fColorUniform, 1, c); - fColor = dfa8gp.color(); - } } static inline void GenKey(const GrGeometryProcessor& gp, @@ -187,8 +175,7 @@ public: GrProcessorKeyBuilder* b) { const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast(); uint32_t key = dfTexEffect.getFlags(); - key |= dfTexEffect.hasVertexColor() << 16; - key |= dfTexEffect.colorIgnored() << 17; + key |= dfTexEffect.colorIgnored() << 16; key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25; b->add32(key); @@ -202,8 +189,6 @@ public: private: SkMatrix fViewMatrix; - GrColor fColor; - UniformHandle fColorUniform; UniformHandle fViewMatrixUniform; #ifdef SK_GAMMA_APPLY_TO_A8 float fDistanceAdjust; @@ -237,9 +222,7 @@ GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color, this->initClassID(); fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision)); - if (flags & kColorAttr_DistanceFieldEffectFlag) { - fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType)); - } + fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType)); fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords", kVec2s_GrVertexAttribType)); this->addTextureAccess(&fTextureAccess); @@ -290,19 +273,18 @@ class GrGLDistanceFieldPathGeoProc : public GrGLSLGeometryProcessor { public: GrGLDistanceFieldPathGeoProc() : fViewMatrix(SkMatrix::InvalidMatrix()) - , fColor(GrColor_ILLEGAL) , fTextureSize(SkISize::Make(-1, -1)) {} void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldPathGeoProc& dfTexEffect = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLFragmentBuilder* 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); @@ -312,35 +294,31 @@ public: // setup pass through color if (!dfTexEffect.colorIgnored()) { - if (dfTexEffect.hasVertexColor()) { - varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); - } else { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); - } + varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); } vertBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName); // Setup position - this->setupPosition(pb, - vertBuilder, + this->setupPosition(vertBuilder, + uniformHandler, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(), &fViewMatrixUniform); // emit transforms - this->emitTransforms(pb, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, args.fTransformsIn, args.fTransformsOut); const char* textureSizeUniName = nullptr; - fTextureSizeUni = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "TextureSize", &textureSizeUniName); + fTextureSizeUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "TextureSize", &textureSizeUniName); // Use highp to work around aliasing issues fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, @@ -413,13 +391,6 @@ public: GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix); pdman.setMatrix3f(fViewMatrixUniform, viewMatrix); } - - if (dfpgp.color() != fColor) { - float c[4]; - GrColorToRGBAFloat(dfpgp.color(), c); - pdman.set4fv(fColorUniform, 1, c); - fColor = dfpgp.color(); - } } static inline void GenKey(const GrGeometryProcessor& gp, @@ -429,17 +400,14 @@ public: uint32_t key = dfTexEffect.getFlags(); key |= dfTexEffect.colorIgnored() << 16; - key |= dfTexEffect.hasVertexColor() << 17; key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25; b->add32(key); } private: - UniformHandle fColorUniform; UniformHandle fTextureSizeUni; UniformHandle fViewMatrixUniform; SkMatrix fViewMatrix; - GrColor fColor; SkISize fTextureSize; typedef GrGLSLGeometryProcessor INHERITED; @@ -464,9 +432,7 @@ GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc( this->initClassID(); fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision)); - if (flags & kColorAttr_DistanceFieldEffectFlag) { - fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType)); - } + fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType)); fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords", kVec2f_GrVertexAttribType)); this->addTextureAccess(&fTextureAccess); @@ -514,17 +480,17 @@ const GrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTes class GrGLDistanceFieldLCDTextGeoProc : public GrGLSLGeometryProcessor { public: GrGLDistanceFieldLCDTextGeoProc() - : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor_ILLEGAL) { + : fViewMatrix(SkMatrix::InvalidMatrix()) { fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.0f, 1.0f, 1.0f); } void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldLCDTextGeoProc& dfTexEffect = args.fGP.cast(); - GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(dfTexEffect); @@ -533,21 +499,21 @@ public: // setup pass through color if (!dfTexEffect.colorIgnored()) { - this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); + varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); } // Setup position - this->setupPosition(pb, - vertBuilder, + this->setupPosition(vertBuilder, + uniformHandler, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(), &fViewMatrixUniform); // emit transforms - this->emitTransforms(pb, - vertBuilder, + this->emitTransforms(vertBuilder, varyingHandler, + uniformHandler, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, args.fTransformsIn, @@ -628,9 +594,9 @@ public: // adjust width based on gamma const char* distanceAdjustUniName = nullptr; - fDistanceAdjustUni = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "DistanceAdjust", &distanceAdjustUniName); + fDistanceAdjustUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec3f_GrSLType, kDefault_GrSLPrecision, + "DistanceAdjust", &distanceAdjustUniName); fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); // To be strictly correct, we should compute the anti-aliasing factor separately @@ -693,13 +659,6 @@ public: GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix); pdman.setMatrix3f(fViewMatrixUniform, viewMatrix); } - - if (dflcd.color() != fColor) { - float c[4]; - GrColorToRGBAFloat(dflcd.color(), c); - pdman.set4fv(fColorUniform, 1, c); - fColor = dflcd.color(); - } } static inline void GenKey(const GrGeometryProcessor& gp, @@ -722,7 +681,6 @@ public: private: SkMatrix fViewMatrix; - GrColor fColor; UniformHandle fViewMatrixUniform; UniformHandle fColorUniform; GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust; @@ -748,6 +706,7 @@ GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc( this->initClassID(); fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision)); + fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType)); fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords", kVec2s_GrVertexAttribType)); this->addTextureAccess(&fTextureAccess); diff --git a/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.h b/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.h index e17a0ce7819..46d39f0123c 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.h +++ b/gfx/skia/skia/src/gpu/effects/GrDistanceFieldGeoProc.h @@ -22,15 +22,13 @@ enum GrDistanceFieldEffectFlags { kUseLCD_DistanceFieldEffectFlag = 0x04, // use lcd text kBGR_DistanceFieldEffectFlag = 0x08, // lcd display has bgr order kPortrait_DistanceFieldEffectFlag = 0x10, // lcd display is in portrait mode (not used yet) - kColorAttr_DistanceFieldEffectFlag = 0x20, // color vertex attribute kInvalid_DistanceFieldEffectFlag = 0x80, // invalid state (for initialization) kUniformScale_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag | kRectToRect_DistanceFieldEffectFlag, // The subset of the flags relevant to GrDistanceFieldA8TextGeoProc - kNonLCD_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag | - kColorAttr_DistanceFieldEffectFlag, + kNonLCD_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag, // The subset of the flags relevant to GrDistanceFieldLCDTextGeoProc kLCD_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag | kRectToRect_DistanceFieldEffectFlag | @@ -71,7 +69,6 @@ public: const Attribute* inTextureCoords() const { return fInTextureCoords; } GrColor color() const { return fColor; } bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } - bool hasVertexColor() const { return SkToBool(fInColor); } const SkMatrix& viewMatrix() const { return fViewMatrix; } bool usesLocalCoords() const { return fUsesLocalCoords; } #ifdef SK_GAMMA_APPLY_TO_A8 @@ -133,7 +130,6 @@ public: const Attribute* inTextureCoords() const { return fInTextureCoords; } GrColor color() const { return fColor; } bool colorIgnored() const { return GrColor_ILLEGAL == fColor; } - bool hasVertexColor() const { return SkToBool(fInColor); } const SkMatrix& viewMatrix() const { return fViewMatrix; } uint32_t getFlags() const { return fFlags; } bool usesLocalCoords() const { return fUsesLocalCoords; } @@ -197,6 +193,7 @@ public: const char* name() const override { return "DistanceFieldLCDTexture"; } const Attribute* inPosition() const { return fInPosition; } + const Attribute* inColor() const { return fInColor; } const Attribute* inTextureCoords() const { return fInTextureCoords; } DistanceAdjust getDistanceAdjust() const { return fDistanceAdjust; } GrColor color() const { return fColor; } @@ -221,6 +218,7 @@ private: DistanceAdjust fDistanceAdjust; uint32_t fFlags; const Attribute* fInPosition; + const Attribute* fInColor; const Attribute* fInTextureCoords; bool fUsesLocalCoords; diff --git a/gfx/skia/skia/src/gpu/effects/GrDitherEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrDitherEffect.cpp index 37cc1ae5701..44aacfccab8 100644 --- a/gfx/skia/skia/src/gpu/effects/GrDitherEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrDitherEffect.cpp @@ -11,7 +11,6 @@ #include "SkRect.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" ////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp index 5fb694b0d75..8867ab9dba8 100644 --- a/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp @@ -6,8 +6,9 @@ */ #include "GrMatrixConvolutionEffect.h" #include "glsl/GrGLSLFragmentProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" class GrGLMatrixConvolutionEffect : public GrGLSLFragmentProcessor { public: @@ -42,25 +43,27 @@ GrGLMatrixConvolutionEffect::GrGLMatrixConvolutionEffect(const GrProcessor& proc void GrGLMatrixConvolutionEffect::emitCode(EmitArgs& args) { const GrTextureDomain& domain = args.fFp.cast().domain(); - fImageIncrementUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "ImageIncrement"); - fKernelUni = args.fBuilder->addUniformArray(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "Kernel", - fKernelSize.width() * fKernelSize.height()); - fKernelOffsetUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kDefault_GrSLPrecision, "KernelOffset"); - fGainUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, "Gain"); - fBiasUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, "Bias"); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fImageIncrementUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "ImageIncrement"); + fKernelUni = uniformHandler->addUniformArray(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + "Kernel", + fKernelSize.width() * fKernelSize.height()); + fKernelOffsetUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "KernelOffset"); + fGainUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, "Gain"); + fBiasUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, "Bias"); - const char* kernelOffset = args.fBuilder->getUniformCStr(fKernelOffsetUni); - const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni); - const char* kernel = args.fBuilder->getUniformCStr(fKernelUni); - const char* gain = args.fBuilder->getUniformCStr(fGainUni); - const char* bias = args.fBuilder->getUniformCStr(fBiasUni); + const char* kernelOffset = uniformHandler->getUniformCStr(fKernelOffsetUni); + const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); + const char* kernel = uniformHandler->getUniformCStr(fKernelUni); + const char* gain = uniformHandler->getUniformCStr(fGainUni); + const char* bias = uniformHandler->getUniformCStr(fBiasUni); int kWidth = fKernelSize.width(); int kHeight = fKernelSize.height(); @@ -77,6 +80,7 @@ void GrGLMatrixConvolutionEffect::emitCode(EmitArgs& args) { SkString coord; coord.printf("coord + vec2(%d, %d) * %s", x, y, imgInc); fDomain.sampleTexture(fragBuilder, + uniformHandler, args.fGLSLCaps, domain, "c", @@ -95,6 +99,7 @@ void GrGLMatrixConvolutionEffect::emitCode(EmitArgs& args) { args.fOutputColor, args.fOutputColor, args.fOutputColor); } else { fDomain.sampleTexture(fragBuilder, + uniformHandler, args.fGLSLCaps, domain, "c", diff --git a/gfx/skia/skia/src/gpu/effects/GrOvalEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrOvalEffect.cpp index 94c5acd9494..c7e685f9022 100644 --- a/gfx/skia/skia/src/gpu/effects/GrOvalEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrOvalEffect.cpp @@ -12,8 +12,8 @@ #include "SkRect.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" ////////////////////////////////////////////////////////////////////////////// @@ -119,10 +119,10 @@ void GLCircleEffect::emitCode(EmitArgs& args) { const char *circleName; // The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills. - fCircleUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "circle", - &circleName); + fCircleUniform = args.fUniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "circle", + &circleName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* fragmentPos = fragBuilder->fragmentPosition(); @@ -133,19 +133,19 @@ void GLCircleEffect::emitCode(EmitArgs& args) { // mediump. It'd be nice to only to this on mediump devices but we currently don't have the // caps here. if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) { - fragBuilder->codeAppendf("\t\tfloat d = (length((%s.xy - %s.xy) * %s.w) - 1.0) * %s.z;\n", + fragBuilder->codeAppendf("float d = (length((%s.xy - %s.xy) * %s.w) - 1.0) * %s.z;", circleName, fragmentPos, circleName, circleName); } else { - fragBuilder->codeAppendf("\t\tfloat d = (1.0 - length((%s.xy - %s.xy) * %s.w)) * %s.z;\n", + fragBuilder->codeAppendf("float d = (1.0 - length((%s.xy - %s.xy) * %s.w)) * %s.z;", circleName, fragmentPos, circleName, circleName); } if (GrProcessorEdgeTypeIsAA(ce.getEdgeType())) { - fragBuilder->codeAppend("\t\td = clamp(d, 0.0, 1.0);\n"); + fragBuilder->codeAppend("d = clamp(d, 0.0, 1.0);"); } else { - fragBuilder->codeAppend("\t\td = d > 0.5 ? 1.0 : 0.0;\n"); + fragBuilder->codeAppend("d = d > 0.5 ? 1.0 : 0.0;"); } - fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("d")).c_str()); } @@ -276,6 +276,7 @@ protected: private: GrGLSLProgramDataManager::UniformHandle fEllipseUniform; + GrGLSLProgramDataManager::UniformHandle fScaleUniform; SkPoint fPrevCenter; SkVector fPrevRadii; @@ -291,43 +292,59 @@ void GLEllipseEffect::emitCode(EmitArgs& args) { const char *ellipseName; // The ellipse uniform is (center.x, center.y, 1 / rx^2, 1 / ry^2) // The last two terms can underflow on mediump, so we use highp. - fEllipseUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kHigh_GrSLPrecision, - "ellipse", - &ellipseName); + fEllipseUniform = args.fUniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kHigh_GrSLPrecision, + "ellipse", + &ellipseName); + // If we're on a device with a "real" mediump then we'll do the distance computation in a space + // that is normalized by the larger radius. The scale uniform will be scale, 1/scale. The + // inverse squared radii uniform values are already in this normalized space. The center is + // not. + const char* scaleName = nullptr; + if (args.fGLSLCaps->floatPrecisionVaries()) { + fScaleUniform = args.fUniformHandler->addUniform( + GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, + "scale", &scaleName); + } GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* fragmentPos = fragBuilder->fragmentPosition(); // d is the offset to the ellipse center - fragBuilder->codeAppendf("\t\tvec2 d = %s.xy - %s.xy;\n", fragmentPos, ellipseName); - fragBuilder->codeAppendf("\t\tvec2 Z = d * %s.zw;\n", ellipseName); + fragBuilder->codeAppendf("vec2 d = %s.xy - %s.xy;", fragmentPos, ellipseName); + if (scaleName) { + fragBuilder->codeAppendf("d *= %s.y;", scaleName); + } + fragBuilder->codeAppendf("vec2 Z = d * %s.zw;", ellipseName); // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1. - fragBuilder->codeAppend("\t\tfloat implicit = dot(Z, d) - 1.0;\n"); + fragBuilder->codeAppend("float implicit = dot(Z, d) - 1.0;"); // grad_dot is the squared length of the gradient of the implicit. - fragBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n"); - // avoid calling inversesqrt on zero. - fragBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n"); - fragBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n"); + fragBuilder->codeAppendf("float grad_dot = 4.0 * dot(Z, Z);"); + // Avoid calling inversesqrt on zero. + fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);"); + fragBuilder->codeAppendf("float approx_dist = implicit * inversesqrt(grad_dot);"); + if (scaleName) { + fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName); + } switch (ee.getEdgeType()) { case kFillAA_GrProcessorEdgeType: - fragBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n"); + fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);"); break; case kInverseFillAA_GrProcessorEdgeType: - fragBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n"); + fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);"); break; case kFillBW_GrProcessorEdgeType: - fragBuilder->codeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 0.0 : 1.0;\n"); + fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 0.0 : 1.0;"); break; case kInverseFillBW_GrProcessorEdgeType: - fragBuilder->codeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 1.0 : 0.0;\n"); + fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 1.0 : 0.0;"); break; case kHairlineAA_GrProcessorEdgeType: SkFAIL("Hairline not expected here."); } - fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); } @@ -341,8 +358,26 @@ void GLEllipseEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& effect) { const EllipseEffect& ee = effect.cast(); if (ee.getRadii() != fPrevRadii || ee.getCenter() != fPrevCenter) { - SkScalar invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX); - SkScalar invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY); + float invRXSqd; + float invRYSqd; + // If we're using a scale factor to work around precision issues, choose the larger radius + // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. + if (fScaleUniform.isValid()) { + if (ee.getRadii().fX > ee.getRadii().fY) { + invRXSqd = 1.f; + invRYSqd = (ee.getRadii().fX * ee.getRadii().fX) / + (ee.getRadii().fY * ee.getRadii().fY); + pdman.set2f(fScaleUniform, ee.getRadii().fX, 1.f / ee.getRadii().fX); + } else { + invRXSqd = (ee.getRadii().fY * ee.getRadii().fY) / + (ee.getRadii().fX * ee.getRadii().fX); + invRYSqd = 1.f; + pdman.set2f(fScaleUniform, ee.getRadii().fY, 1.f / ee.getRadii().fY); + } + } else { + invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX); + invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY); + } pdman.set4f(fEllipseUniform, ee.getCenter().fX, ee.getCenter().fY, invRXSqd, invRYSqd); fPrevCenter = ee.getCenter(); fPrevRadii = ee.getRadii(); diff --git a/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp index 42a96319769..94d3dd67a93 100644 --- a/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -16,9 +16,10 @@ #include "GrXferProcessor.h" #include "glsl/GrGLSLBlend.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLXferProcessor.h" +#include /** * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage. @@ -71,7 +72,7 @@ public: */ template - struct get_properties : skstd::integral_constant( + struct get_properties : std::integral_constant( (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ? kModifiesDst_Property : 0) | @@ -545,8 +546,8 @@ public: } private: - void emitBlendCodeForDstRead(GrGLSLXPBuilder* pb, - GrGLSLXPFragmentBuilder* fragBuilder, + void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, + GrGLSLUniformHandler* uniformHandler, const char* srcColor, const char* srcCoverage, const char* dstColor, @@ -850,6 +851,12 @@ void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp, //////////////////////////////////////////////////////////////////////////////////////////////// // SrcOver Global functions //////////////////////////////////////////////////////////////////////////////////////////////// +const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() { + static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff, + kISA_GrBlendCoeff); + static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula); + return gSrcOverXP; +} GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor( const GrCaps& caps, @@ -860,12 +867,11 @@ GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor( !(optimizations.fCoveragePOI.isSolidWhite() && !hasMixedSamples && optimizations.fColorPOI.isOpaque())) { - static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff, - kISA_GrBlendCoeff); - static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula); - SkASSERT(!dstTexture || !dstTexture->texture()); - gSrcOverXP.ref(); - return &gSrcOverXP; + // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP". + // We don't simply return the address of that XP here because our caller would have to unref + // it and since it is a global object and GrProgramElement's ref-cnting system is not thread + // safe. + return nullptr; } BlendFormula blendFormula; diff --git a/gfx/skia/skia/src/gpu/effects/GrRRectEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrRRectEffect.cpp index c45f5f309c2..0b492762c2c 100644 --- a/gfx/skia/skia/src/gpu/effects/GrRRectEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrRRectEffect.cpp @@ -12,10 +12,11 @@ #include "GrInvariantOutput.h" #include "GrOvalEffect.h" #include "SkRRect.h" +#include "SkTLazy.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" // The effects defined here only handle rrect radii >= kRadiusMin. static const SkScalar kRadiusMin = SK_ScalarHalf; @@ -150,20 +151,31 @@ GLCircularRRectEffect::GLCircularRRectEffect(const GrProcessor& ) { void GLCircularRRectEffect::emitCode(EmitArgs& args) { const CircularRRectEffect& crre = args.fFp.cast(); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; const char *rectName; const char *radiusPlusHalfName; // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has // only rectangular corners, that side's value corresponds to the rect edge's value outset by // half a pixel. - fInnerRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "innerRect", - &rectName); - fRadiusPlusHalfUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, - "radiusPlusHalf", - &radiusPlusHalfName); + fInnerRectUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "innerRect", + &rectName); + // x is (r + .5) and y is 1/(r + .5) + fRadiusPlusHalfUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "radiusPlusHalf", + &radiusPlusHalfName); + + // If we're on a device with a "real" mediump then the length calculation could overflow. + SkString clampedCircleDistance; + if (args.fGLSLCaps->floatPrecisionVaries()) { + clampedCircleDistance.printf("clamp(%s.x * (1.0 - length(dxy * %s.y)), 0.0, 1.0);", + radiusPlusHalfName, radiusPlusHalfName); + } else { + clampedCircleDistance.printf("clamp(%s.x - length(dxy), 0.0, 1.0);", radiusPlusHalfName); + } GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* fragmentPos = fragBuilder->fragmentPosition(); @@ -184,103 +196,94 @@ void GLCircularRRectEffect::emitCode(EmitArgs& args) { // alphas together. switch (crre.getCircularCornerFlags()) { case CircularRRectEffect::kAll_CornerFlags: - fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); - fragBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); - fragBuilder->codeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n", - radiusPlusHalfName); + fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos); + fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName); + fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);"); + fragBuilder->codeAppendf("float alpha = %s;", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kTopLeft_CornerFlag: - fragBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n", + fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - %s.xy, 0.0);", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", + fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", + fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);", rectName, fragmentPos); - fragBuilder->codeAppendf( - "\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", - radiusPlusHalfName); + fragBuilder->codeAppendf("float alpha = bottomAlpha * rightAlpha * %s;", + clampedCircleDistance.c_str()); break; case CircularRRectEffect::kTopRight_CornerFlag: - fragBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n", + fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);", fragmentPos, rectName, rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", + fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);", fragmentPos, rectName); - fragBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", + fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);", rectName, fragmentPos); - fragBuilder->codeAppendf( - "\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", - radiusPlusHalfName); + fragBuilder->codeAppendf("float alpha = bottomAlpha * leftAlpha * %s;", + clampedCircleDistance.c_str()); break; case CircularRRectEffect::kBottomRight_CornerFlag: - fragBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n", + fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - %s.zw, 0.0);", fragmentPos, rectName); - fragBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", + fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);", fragmentPos, rectName); - fragBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", + fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);", fragmentPos, rectName); - fragBuilder->codeAppendf( - "\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", - radiusPlusHalfName); + fragBuilder->codeAppendf("float alpha = topAlpha * leftAlpha * %s;", + clampedCircleDistance.c_str()); break; case CircularRRectEffect::kBottomLeft_CornerFlag: - fragBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n", + fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);", rectName, fragmentPos, fragmentPos, rectName); - fragBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", + fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", + fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);", fragmentPos, rectName); - fragBuilder->codeAppendf( - "\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", - radiusPlusHalfName); + fragBuilder->codeAppendf("float alpha = topAlpha * rightAlpha * %s;", + clampedCircleDistance.c_str()); break; case CircularRRectEffect::kLeft_CornerFlags: - fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName); - fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n"); - fragBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", + fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos); + fragBuilder->codeAppendf("float dy1 = %s.y - %s.w;", fragmentPos, rectName); + fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);"); + fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);", rectName, fragmentPos); - fragBuilder->codeAppendf( - "\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", - radiusPlusHalfName); + fragBuilder->codeAppendf("float alpha = rightAlpha * %s;", + clampedCircleDistance.c_str()); break; case CircularRRectEffect::kTop_CornerFlags: - fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName); - fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n"); - fragBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", + fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos); + fragBuilder->codeAppendf("float dx1 = %s.x - %s.z;", fragmentPos, rectName); + fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);"); + fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);", rectName, fragmentPos); - fragBuilder->codeAppendf( - "\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", - radiusPlusHalfName); + fragBuilder->codeAppendf("float alpha = bottomAlpha * %s;", + clampedCircleDistance.c_str()); break; case CircularRRectEffect::kRight_CornerFlags: - fragBuilder->codeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); - fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n"); - fragBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", + fragBuilder->codeAppendf("float dy0 = %s.y - %s.y;", rectName, fragmentPos); + fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName); + fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);"); + fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);", fragmentPos, rectName); - fragBuilder->codeAppendf( - "\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", - radiusPlusHalfName); + fragBuilder->codeAppendf("float alpha = leftAlpha * %s;", + clampedCircleDistance.c_str()); break; case CircularRRectEffect::kBottom_CornerFlags: - fragBuilder->codeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); - fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n"); - fragBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", + fragBuilder->codeAppendf("float dx0 = %s.x - %s.x;", rectName, fragmentPos); + fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName); + fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);"); + fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);", fragmentPos, rectName); - fragBuilder->codeAppendf( - "\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", - radiusPlusHalfName); + fragBuilder->codeAppendf("float alpha = topAlpha * %s;", + clampedCircleDistance.c_str()); break; } if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) { - fragBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n"); + fragBuilder->codeAppend("alpha = 1.0 - alpha;"); } - fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); } @@ -365,7 +368,8 @@ void GLCircularRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, SkFAIL("Should have been one of the above cases."); } pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); - pdman.set1f(fRadiusPlusHalfUniform, radius + 0.5f); + radius += 0.5f; + pdman.set2f(fRadiusPlusHalfUniform, radius, 1.f / radius); fPrevRRect = rrect; } } @@ -494,7 +498,8 @@ protected: private: GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; GrGLSLProgramDataManager::UniformHandle fInvRadiiSqdUniform; - SkRRect fPrevRRect; + GrGLSLProgramDataManager::UniformHandle fScaleUniform; + SkRRect fPrevRRect; typedef GrGLSLFragmentProcessor INHERITED; }; @@ -504,12 +509,13 @@ GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrProcessor& effect) { void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { const EllipticalRRectEffect& erre = args.fFp.cast(); + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; const char *rectName; // The inner rect is the rrect bounds inset by the x/y radii - fInnerRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "innerRect", - &rectName); + fInnerRectUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "innerRect", + &rectName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* fragmentPos = fragBuilder->fragmentPosition(); @@ -525,55 +531,77 @@ void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { // The code below is a simplified version of the above that performs maxs on the vector // components before computing distances and alpha values so that only one distance computation // need be computed to determine the min alpha. - fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); - fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); + fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos); + fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName); + + // If we're on a device with a "real" mediump then we'll do the distance computation in a space + // that is normalized by the largest radius. The scale uniform will be scale, 1/scale. The + // radii uniform values are already in this normalized space. + const char* scaleName = nullptr; + if (args.fGLSLCaps->floatPrecisionVaries()) { + fScaleUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, + "scale", &scaleName); + } + // The uniforms with the inv squared radii are highp to prevent underflow. switch (erre.getRRect().getType()) { case SkRRect::kSimple_Type: { const char *invRadiiXYSqdName; - fInvRadiiSqdUniform = args.fBuilder->addUniform( - GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, kHigh_GrSLPrecision, + fInvRadiiSqdUniform = uniformHandler->addUniform( + GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, kDefault_GrSLPrecision, "invRadiiXY", &invRadiiXYSqdName); - fragBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); + fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);"); + if (scaleName) { + fragBuilder->codeAppendf("dxy *= %s.y;", scaleName); + } // Z is the x/y offsets divided by squared radii. - fragBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName); + fragBuilder->codeAppendf("vec2 Z = dxy * %s.xy;", invRadiiXYSqdName); break; } case SkRRect::kNinePatch_Type: { const char *invRadiiLTRBSqdName; - fInvRadiiSqdUniform = args.fBuilder->addUniform( - GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kHigh_GrSLPrecision, + fInvRadiiSqdUniform = uniformHandler->addUniform( + GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, "invRadiiLTRB", &invRadiiLTRBSqdName); - fragBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); + if (scaleName) { + fragBuilder->codeAppendf("dxy0 *= %s.y;", scaleName); + fragBuilder->codeAppendf("dxy1 *= %s.y;", scaleName); + } + fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);"); // Z is the x/y offsets divided by squared radii. We only care about the (at most) one // corner where both the x and y offsets are positive, hence the maxes. (The inverse // squared radii will always be positive.) - fragBuilder->codeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n", + fragBuilder->codeAppendf("vec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);", invRadiiLTRBSqdName, invRadiiLTRBSqdName); + break; } default: SkFAIL("RRect should always be simple or nine-patch."); } // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1. - fragBuilder->codeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n"); + fragBuilder->codeAppend("float implicit = dot(Z, dxy) - 1.0;"); // grad_dot is the squared length of the gradient of the implicit. - fragBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n"); + fragBuilder->codeAppend("float grad_dot = 4.0 * dot(Z, Z);"); // avoid calling inversesqrt on zero. - fragBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n"); - fragBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n"); - - if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) { - fragBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n"); - } else { - fragBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n"); + fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);"); + fragBuilder->codeAppend("float approx_dist = implicit * inversesqrt(grad_dot);"); + if (scaleName) { + fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName); } - fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, + if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) { + fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);"); + } else { + fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);"); + } + + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); } @@ -588,6 +616,8 @@ void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& effect) { const EllipticalRRectEffect& erre = effect.cast(); const SkRRect& rrect = erre.getRRect(); + // If we're using a scale factor to work around precision issues, choose the largest radius + // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. if (rrect != fPrevRRect) { SkRect rect = rrect.getBounds(); const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); @@ -596,8 +626,18 @@ void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, switch (erre.getRRect().getType()) { case SkRRect::kSimple_Type: rect.inset(r0.fX, r0.fY); - pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), - 1.f / (r0.fY * r0.fY)); + if (fScaleUniform.isValid()) { + if (r0.fX > r0.fY) { + pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) / (r0.fY * r0.fY)); + pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX); + } else { + pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.fX * r0.fX), 1.f); + pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY); + } + } else { + pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), + 1.f / (r0.fY * r0.fY)); + } break; case SkRRect::kNinePatch_Type: { const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); @@ -607,10 +647,20 @@ void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, rect.fTop += r0.fY; rect.fRight -= r1.fX; rect.fBottom -= r1.fY; - pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), - 1.f / (r0.fY * r0.fY), - 1.f / (r1.fX * r1.fX), - 1.f / (r1.fY * r1.fY)); + if (fScaleUniform.isValid()) { + float scale = SkTMax(SkTMax(r0.fX, r0.fY), SkTMax(r1.fX, r1.fY)); + float scaleSqd = scale * scale; + pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX), + scaleSqd / (r0.fY * r0.fY), + scaleSqd / (r1.fX * r1.fX), + scaleSqd / (r1.fY * r1.fY)); + pdman.set2f(fScaleUniform, scale, 1.f / scale); + } else { + pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), + 1.f / (r0.fY * r0.fY), + 1.f / (r1.fX * r1.fX), + 1.f / (r1.fY * r1.fY)); + } break; } default: diff --git a/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.cpp index 4db6f2c5098..74e86249b05 100644 --- a/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrSimpleTextureEffect.cpp @@ -10,7 +10,6 @@ #include "GrTexture.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" class GrGLSimpleTextureEffect : public GrGLSLFragmentProcessor { public: diff --git a/gfx/skia/skia/src/gpu/effects/GrTextureDomain.cpp b/gfx/skia/skia/src/gpu/effects/GrTextureDomain.cpp index c0902c61760..00e8e82c8eb 100644 --- a/gfx/skia/skia/src/gpu/effects/GrTextureDomain.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrTextureDomain.cpp @@ -10,9 +10,11 @@ #include "GrSimpleTextureEffect.h" #include "SkFloatingPoint.h" #include "glsl/GrGLSLFragmentProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLShaderBuilder.h" #include "glsl/GrGLSLTextureSampler.h" +#include "glsl/GrGLSLUniformHandler.h" GrTextureDomain::GrTextureDomain(const SkRect& domain, Mode mode, int index) : fIndex(index) { @@ -42,6 +44,7 @@ GrTextureDomain::GrTextureDomain(const SkRect& domain, Mode mode, int index) ////////////////////////////////////////////////////////////////////////////// void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, + GrGLSLUniformHandler* uniformHandler, const GrGLSLCaps* glslCaps, const GrTextureDomain& textureDomain, const char* outColor, @@ -51,17 +54,15 @@ void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder, SkASSERT((Mode)-1 == fMode || textureDomain.mode() == fMode); SkDEBUGCODE(fMode = textureDomain.mode();) - GrGLSLProgramBuilder* program = builder->getProgramBuilder(); - if (textureDomain.mode() != kIgnore_Mode && !fDomainUni.isValid()) { const char* name; SkString uniName("TexDom"); if (textureDomain.fIndex >= 0) { uniName.appendS32(textureDomain.fIndex); } - fDomainUni = program->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - uniName.c_str(), &name); + fDomainUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + uniName.c_str(), &name); fDomainName = name; } @@ -199,6 +200,7 @@ void GrGLTextureDomainEffect::emitCode(EmitArgs& args) { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); fGLDomain.sampleTexture(fragBuilder, + args.fUniformHandler, args.fGLSLCaps, domain, args.fOutputColor, diff --git a/gfx/skia/skia/src/gpu/effects/GrTextureDomain.h b/gfx/skia/skia/src/gpu/effects/GrTextureDomain.h index 49e557d18ab..891ce10b38d 100644 --- a/gfx/skia/skia/src/gpu/effects/GrTextureDomain.h +++ b/gfx/skia/skia/src/gpu/effects/GrTextureDomain.h @@ -16,6 +16,7 @@ class GrGLProgramBuilder; class GrGLSLShaderBuilder; class GrInvariantOutput; class GrGLSLTextureSampler; +class GrGLSLUniformHandler; struct SkRect; /** @@ -114,6 +115,7 @@ public: * expression before being written to outColor. */ void sampleTexture(GrGLSLShaderBuilder* builder, + GrGLSLUniformHandler* uniformHandler, const GrGLSLCaps* glslCaps, const GrTextureDomain& textureDomain, const char* outColor, diff --git a/gfx/skia/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/gfx/skia/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp index 6ff4d32f067..c83d6bee55a 100644 --- a/gfx/skia/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp @@ -8,11 +8,11 @@ #include "effects/GrXfermodeFragmentProcessor.h" #include "GrFragmentProcessor.h" +#include "GrInvariantOutput.h" #include "effects/GrConstColorProcessor.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLBlend.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "SkGrPriv.h" class ComposeTwoFragmentProcessor : public GrFragmentProcessor { diff --git a/gfx/skia/skia/src/gpu/effects/GrYUVtoRGBEffect.cpp b/gfx/skia/skia/src/gpu/effects/GrYUVtoRGBEffect.cpp index 6d1c864b82c..16dad8635c8 100644 --- a/gfx/skia/skia/src/gpu/effects/GrYUVtoRGBEffect.cpp +++ b/gfx/skia/skia/src/gpu/effects/GrYUVtoRGBEffect.cpp @@ -8,12 +8,13 @@ #include "GrYUVtoRGBEffect.h" #include "GrCoordTransform.h" +#include "GrFragmentProcessor.h" #include "GrInvariantOutput.h" #include "GrProcessor.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" namespace { @@ -67,9 +68,10 @@ public: GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* yuvMatrix = nullptr; - fMatrixUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kMat44f_GrSLType, kDefault_GrSLPrecision, - "YUVMatrix", &yuvMatrix); + fMatrixUni = args.fUniformHandler->addUniform( + GrGLSLUniformHandler::kFragment_Visibility, + kMat44f_GrSLType, kDefault_GrSLPrecision, + "YUVMatrix", &yuvMatrix); fragBuilder->codeAppendf("\t%s = vec4(\n\t\t", args.fOutputColor); fragBuilder->appendTextureLookup(args.fSamplers[0], args.fCoords[0].c_str(), args.fCoords[0].getType()); diff --git a/gfx/skia/skia/src/gpu/gl/GrGLAssembleInterface.cpp b/gfx/skia/skia/src/gpu/gl/GrGLAssembleInterface.cpp index dbc54adbe49..6b578f34fc7 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLAssembleInterface.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLAssembleInterface.cpp @@ -745,17 +745,52 @@ const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) { GET_PROC_SUFFIX(ProgramPathFragmentInputGen, NV); } + if (extensions.has("GL_CHROMIUM_path_rendering")) { + GET_PROC_SUFFIX(MatrixLoadf, CHROMIUM); + GET_PROC_SUFFIX(MatrixLoadIdentity, CHROMIUM); + GET_PROC_SUFFIX(PathCommands, CHROMIUM); + GET_PROC_SUFFIX(PathParameteri, CHROMIUM); + GET_PROC_SUFFIX(PathParameterf, CHROMIUM); + GET_PROC_SUFFIX(GenPaths, CHROMIUM); + GET_PROC_SUFFIX(DeletePaths, CHROMIUM); + GET_PROC_SUFFIX(IsPath, CHROMIUM); + GET_PROC_SUFFIX(PathStencilFunc, CHROMIUM); + GET_PROC_SUFFIX(StencilFillPath, CHROMIUM); + GET_PROC_SUFFIX(StencilStrokePath, CHROMIUM); + GET_PROC_SUFFIX(StencilFillPathInstanced, CHROMIUM); + GET_PROC_SUFFIX(StencilStrokePathInstanced, CHROMIUM); + GET_PROC_SUFFIX(CoverFillPath, CHROMIUM); + GET_PROC_SUFFIX(CoverStrokePath, CHROMIUM); + GET_PROC_SUFFIX(CoverFillPathInstanced, CHROMIUM); + GET_PROC_SUFFIX(CoverStrokePathInstanced, CHROMIUM); + GET_PROC_SUFFIX(StencilThenCoverFillPath, CHROMIUM); + GET_PROC_SUFFIX(StencilThenCoverStrokePath, CHROMIUM); + GET_PROC_SUFFIX(StencilThenCoverFillPathInstanced, CHROMIUM); + GET_PROC_SUFFIX(StencilThenCoverStrokePathInstanced, CHROMIUM); + GET_PROC_SUFFIX(ProgramPathFragmentInputGen, CHROMIUM); + // GL_CHROMIUM_path_rendering additions: + GET_PROC_SUFFIX(BindFragmentInputLocation, CHROMIUM); + } + if (extensions.has("GL_NV_framebuffer_mixed_samples")) { GET_PROC_SUFFIX(CoverageModulation, NV); } - - if (version >= GR_GL_VER(3,0) || extensions.has("GL_EXT_draw_instanced")) { - GET_PROC(DrawArraysInstanced); - GET_PROC(DrawElementsInstanced); + if (extensions.has("GL_CHROMIUM_framebuffer_mixed_samples")) { + GET_PROC_SUFFIX(CoverageModulation, CHROMIUM); } - if (version >= GR_GL_VER(3,0) || extensions.has("GL_EXT_instanced_arrays")) { + if (version >= GR_GL_VER(3,0)) { + GET_PROC(DrawArraysInstanced); + GET_PROC(DrawElementsInstanced); + } else if (extensions.has("GL_EXT_draw_instanced")) { + GET_PROC_SUFFIX(DrawArraysInstanced, EXT); + GET_PROC_SUFFIX(DrawElementsInstanced, EXT); + } + + if (version >= GR_GL_VER(3,0)) { GET_PROC(VertexAttribDivisor); + } else if (extensions.has("GL_EXT_instanced_arrays")) { + GET_PROC_SUFFIX(VertexAttribDivisor, EXT); } if (extensions.has("GL_NV_bindless_texture")) { diff --git a/gfx/skia/skia/src/gpu/gl/GrGLBufferImpl.cpp b/gfx/skia/skia/src/gpu/gl/GrGLBufferImpl.cpp index 6cbf4e0d0ec..2babce80285 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLBufferImpl.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLBufferImpl.cpp @@ -65,7 +65,7 @@ void* GrGLBufferImpl::map(GrGLGpu* gpu) { if (0 == fDesc.fID) { fMapPtr = fCPUData; } else { - fMapPtr = gpu->mapBuffer(fDesc.fID, fBufferType, fDesc.fDynamic, fGLSizeInBytes, + fMapPtr = gpu->mapBuffer(fDesc.fID, fBufferType, fDesc.fUsage, fGLSizeInBytes, fDesc.fSizeInBytes); fGLSizeInBytes = fDesc.fSizeInBytes; } @@ -89,6 +89,7 @@ bool GrGLBufferImpl::isMapped() const { bool GrGLBufferImpl::updateData(GrGLGpu* gpu, const void* src, size_t srcSizeInBytes) { SkASSERT(!this->isMapped()); + SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); VALIDATE(); if (srcSizeInBytes > fDesc.fSizeInBytes) { return false; @@ -97,7 +98,7 @@ bool GrGLBufferImpl::updateData(GrGLGpu* gpu, const void* src, size_t srcSizeInB memcpy(fCPUData, src, srcSizeInBytes); return true; } - gpu->bufferData(fDesc.fID, fBufferType, fDesc.fDynamic, fDesc.fSizeInBytes, src, + gpu->bufferData(fDesc.fID, fBufferType, fDesc.fUsage, fDesc.fSizeInBytes, src, srcSizeInBytes); #if GR_GL_USE_BUFFER_DATA_NULL_HINT fGLSizeInBytes = fDesc.fSizeInBytes; @@ -109,7 +110,10 @@ bool GrGLBufferImpl::updateData(GrGLGpu* gpu, const void* src, size_t srcSizeInB } void GrGLBufferImpl::validate() const { - SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); + SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType || + GR_GL_PIXEL_PACK_BUFFER == fBufferType || GR_GL_PIXEL_UNPACK_BUFFER == fBufferType || + GR_GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM == fBufferType || + GR_GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM == fBufferType); // The following assert isn't valid when the buffer has been abandoned: // SkASSERT((0 == fDesc.fID) == (fCPUData)); SkASSERT(nullptr == fCPUData || 0 == fGLSizeInBytes); diff --git a/gfx/skia/skia/src/gpu/gl/GrGLBufferImpl.h b/gfx/skia/skia/src/gpu/gl/GrGLBufferImpl.h index 15d2f48efe4..a8f2cced372 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLBufferImpl.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLBufferImpl.h @@ -19,10 +19,20 @@ class GrGLGpu; */ class GrGLBufferImpl : SkNoncopyable { public: + enum Usage { + kStaticDraw_Usage = 0, + kDynamicDraw_Usage, + kStreamDraw_Usage, + kStreamRead_Usage, + + kLast_Usage = kStreamRead_Usage + }; + static const int kUsageCount = kLast_Usage + 1; + struct Desc { GrGLuint fID; // set to 0 to indicate buffer is CPU-backed and not a VBO. size_t fSizeInBytes; - bool fDynamic; + Usage fUsage; }; GrGLBufferImpl(GrGLGpu*, const Desc&, GrGLenum bufferType); @@ -36,6 +46,7 @@ public: GrGLuint bufferID() const { return fDesc.fID; } size_t baseOffset() const { return reinterpret_cast(fCPUData); } + GrGLenum bufferType() const { return fBufferType; } void* map(GrGLGpu* gpu); void unmap(GrGLGpu* gpu); @@ -46,7 +57,7 @@ private: void validate() const; Desc fDesc; - GrGLenum fBufferType; // GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER + GrGLenum fBufferType; // GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER, e.g. void* fCPUData; void* fMapPtr; size_t fGLSizeInBytes; // In certain cases we make the size of the GL buffer object diff --git a/gfx/skia/skia/src/gpu/gl/GrGLCaps.cpp b/gfx/skia/skia/src/gpu/gl/GrGLCaps.cpp index a768b371059..ddc52cc3781 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLCaps.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLCaps.cpp @@ -17,17 +17,14 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, const GrGLContextInfo& ctxInfo, const GrGLInterface* glInterface) : INHERITED(contextOptions) { - fVerifiedColorConfigs.reset(); fStencilFormats.reset(); fMSFBOType = kNone_MSFBOType; fInvalidateFBType = kNone_InvalidateFBType; - fLATCAlias = kLATC_LATCAlias; fMapBufferType = kNone_MapBufferType; + fTransferBufferType = kNone_TransferBufferType; fMaxFragmentUniformVectors = 0; fMaxVertexAttributes = 0; fMaxFragmentTextureUnits = 0; - fRGBA8RenderbufferSupport = false; - fBGRAIsInternalFormat = false; fUnpackRowLengthSupport = false; fUnpackFlipYSupport = false; fPackRowLengthSupport = false; @@ -36,9 +33,7 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, fTexStorageSupport = false; fTextureRedSupport = false; fImagingSupport = false; - fTwoFormatLimit = false; fVertexArrayObjectSupport = false; - fInstancedDrawingSupport = false; fDirectStateAccessSupport = false; fDebugSupport = false; fES2CompatibilitySupport = false; @@ -47,12 +42,12 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, fIsCoreProfile = false; fBindFragDataLocationSupport = false; fExternalTextureSupport = false; + fRectangleTextureSupport = false; + fTextureSwizzleSupport = false; fSRGBWriteControl = false; fRGBA8888PixelsOpsAreSlow = false; fPartialFBOReadIsSlow = false; - fReadPixelsSupportedCache.reset(); - fShaderCaps.reset(new GrGLSLCaps(contextOptions)); this->init(contextOptions, ctxInfo, glInterface); @@ -85,14 +80,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, GR_GL_GetIntegerv(gli, GR_GL_MAX_VERTEX_ATTRIBS, &fMaxVertexAttributes); GR_GL_GetIntegerv(gli, GR_GL_MAX_TEXTURE_IMAGE_UNITS, &fMaxFragmentTextureUnits); - if (kGL_GrGLStandard == standard) { - fRGBA8RenderbufferSupport = true; - } else { - fRGBA8RenderbufferSupport = version >= GR_GL_VER(3,0) || - ctxInfo.hasExtension("GL_OES_rgb8_rgba8") || - ctxInfo.hasExtension("GL_ARM_rgba8"); - } - if (kGL_GrGLStandard == standard) { fUnpackRowLengthSupport = true; fUnpackFlipYSupport = false; @@ -145,33 +132,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fImagingSupport = kGL_GrGLStandard == standard && ctxInfo.hasExtension("GL_ARB_imaging"); - // ES 2 only guarantees RGBA/uchar + one other format/type combo for - // ReadPixels. The other format has to checked at run-time since it - // can change based on which render target is bound - fTwoFormatLimit = kGLES_GrGLStandard == standard; - - // We only enable srgb support if both textures and FBOs support srgb. - bool srgbSupport = false; - if (kGL_GrGLStandard == standard) { - if (ctxInfo.version() >= GR_GL_VER(3,0)) { - srgbSupport = true; - } else if (ctxInfo.hasExtension("GL_EXT_texture_sRGB")) { - if (ctxInfo.hasExtension("GL_ARB_framebuffer_sRGB") || - ctxInfo.hasExtension("GL_EXT_framebuffer_sRGB")) { - srgbSupport = true; - } - } - // All the above srgb extensions support toggling srgb writes - fSRGBWriteControl = srgbSupport; - } else { - // See https://bug.skia.org/4148 for PowerVR issue. - srgbSupport = kPowerVRRogue_GrGLRenderer != ctxInfo.renderer() && - (ctxInfo.version() >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_EXT_sRGB")); - // ES through 3.1 requires EXT_srgb_write_control to support toggling - // sRGB writing for destinations. - fSRGBWriteControl = ctxInfo.hasExtension("GL_EXT_sRGB_write_control"); - } - // SGX and Mali GPUs that are based on a tiled-deferred architecture that have trouble with // frequently changing VBOs. We've measured a performance increase using non-VBO vertex // data for dynamic content on these GPUs. Perhaps we should read the renderer string and @@ -209,16 +169,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, ctxInfo.hasExtension("GL_OES_vertex_array_object"); } - if ((kGL_GrGLStandard == standard && version >= GR_GL_VER(3,2)) || - (kGLES_GrGLStandard == standard && version >= GR_GL_VER(3,0))) { - fInstancedDrawingSupport = true; - } else { - fInstancedDrawingSupport = (ctxInfo.hasExtension("GL_ARB_draw_instanced") || - ctxInfo.hasExtension("GL_EXT_draw_instanced")) && - (ctxInfo.hasExtension("GL_ARB_instanced_arrays") || - ctxInfo.hasExtension("GL_EXT_instanced_arrays")); - } - if (kGL_GrGLStandard == standard) { fDirectStateAccessSupport = ctxInfo.hasExtension("GL_EXT_direct_state_access"); } else { @@ -270,6 +220,21 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, } } + if ((kGL_GrGLStandard == standard && version >= GR_GL_VER(3, 2)) || + ctxInfo.hasExtension("GL_ARB_texture_rectangle")) { + fRectangleTextureSupport = true; + } + + if (kGL_GrGLStandard == standard) { + if (version >= GR_GL_VER(3,3) || ctxInfo.hasExtension("GL_ARB_texture_swizzle")) { + fTextureSwizzleSupport = true; + } + } else { + if (version >= GR_GL_VER(3,0)) { + fTextureSwizzleSupport = true; + } + } + #ifdef SK_BUILD_FOR_WIN // We're assuming that on Windows Chromium we're using ANGLE. bool isANGLE = kANGLE_GrGLDriver == ctxInfo.driver() || @@ -319,7 +284,8 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, // We need dual source blending and the ability to disable multisample in order to support mixed // samples in every corner case. if (fMultisampleDisableSupport && glslCaps->dualSourceBlendingSupport()) { - fMixedSamplesSupport = ctxInfo.hasExtension("GL_NV_framebuffer_mixed_samples"); + fMixedSamplesSupport = ctxInfo.hasExtension("GL_NV_framebuffer_mixed_samples") || + ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_mixed_samples"); // Workaround NVIDIA bug related to glInvalidateFramebuffer and mixed samples. if (fMixedSamplesSupport && kNVIDIA_GrGLDriver == ctxInfo.driver()) { fDiscardRenderTargetSupport = false; @@ -370,6 +336,18 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, } } + if (kGL_GrGLStandard == standard) { + if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_pixel_buffer_object")) { + fTransferBufferType = kPBO_TransferBufferType; + } + } else { + if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_NV_pixel_buffer_object")) { + fTransferBufferType = kPBO_TransferBufferType; + } else if (ctxInfo.hasExtension("GL_CHROMIUM_pixel_transfer_buffer_object")) { + fTransferBufferType = kChromium_TransferBufferType; + } + } + // On many GPUs, map memory is very expensive, so we effectively disable it here by setting the // threshold to the maximum unless the client gives us a hint that map memory is cheap. if (fGeometryBufferMapThreshold < 0) { @@ -475,11 +453,15 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, ctxInfo.hasExtension("GL_EXT_instanced_arrays")); } - this->initConfigTexturableTable(ctxInfo, gli, srgbSupport); - this->initConfigRenderableTable(ctxInfo, srgbSupport); this->initShaderPrecisionTable(ctxInfo, gli, glslCaps); - // Requires fTexutreSwizzleSupport and fTextureRedSupport to be set before this point. - this->initConfigSwizzleTable(ctxInfo, glslCaps); + + if (contextOptions.fUseShaderSwizzling) { + fTextureSwizzleSupport = false; + } + + // Requires fTextureRedSupport, fTextureSwizzleSupport, msaa support, ES compatibility have + // already been detected. + this->initConfigTable(ctxInfo, gli, glslCaps); this->applyOptionsOverrides(contextOptions); glslCaps->applyOptionsOverrides(contextOptions); @@ -575,9 +557,6 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo) { // from our GrTextureDomain processor. glslCaps->fCanUseAnyFunctionInShader = kImagination_GrGLVendor != ctxInfo.vendor(); - glslCaps->fForceHighPrecisionNDSTransform = kARM_GrGLVendor == ctxInfo.vendor() || - kPowerVR54x_GrGLRenderer == ctxInfo.renderer(); - glslCaps->fVersionDeclString = get_glsl_version_decl_string(standard, glslCaps->fGLSLGeneration, fIsCoreProfile); @@ -652,345 +631,47 @@ bool GrGLCaps::hasPathRenderingSupport(const GrGLContextInfo& ctxInfo, const GrG } return true; } - -void GrGLCaps::initConfigRenderableTable(const GrGLContextInfo& ctxInfo, bool srgbSupport) { - // OpenGL < 3.0 - // no support for render targets unless the GL_ARB_framebuffer_object - // extension is supported (in which case we get ALPHA, RED, RG, RGB, - // RGBA (ALPHA8, RGBA4, RGBA8) for OpenGL > 1.1). Note that we - // probably don't get R8 in this case. - - // OpenGL 3.0 - // base color renderable: ALPHA, RED, RG, RGB, and RGBA - // sized derivatives: ALPHA8, R8, RGBA4, RGBA8 - - // >= OpenGL 3.1 - // base color renderable: RED, RG, RGB, and RGBA - // sized derivatives: R8, RGBA4, RGBA8 - // if the GL_ARB_compatibility extension is supported then we get back - // support for GL_ALPHA and ALPHA8 - - // GL_EXT_bgra adds BGRA render targets to any version - - // ES 2.0 - // color renderable: RGBA4, RGB5_A1, RGB565 - // GL_EXT_texture_rg adds support for R8 as a color render target - // GL_OES_rgb8_rgba8 and/or GL_ARM_rgba8 adds support for RGBA8 - // GL_EXT_texture_format_BGRA8888 and/or GL_APPLE_texture_format_BGRA8888 added BGRA support - - // ES 3.0 - // Same as ES 2.0 except R8 and RGBA8 are supported without extensions (the functions called - // below already account for this). - - GrGLStandard standard = ctxInfo.standard(); - - enum { - kNo_MSAA = 0, - kYes_MSAA = 1, - }; - - if (kGL_GrGLStandard == standard) { - // Post 3.0 we will get R8 - // Prior to 3.0 we will get ALPHA8 (with GL_ARB_framebuffer_object) - if (ctxInfo.version() >= GR_GL_VER(3,0) || - ctxInfo.hasExtension("GL_ARB_framebuffer_object")) { - fConfigRenderSupport[kAlpha_8_GrPixelConfig][kNo_MSAA] = true; - fConfigRenderSupport[kAlpha_8_GrPixelConfig][kYes_MSAA] = true; - } - } else { - // On ES we can only hope for R8 - fConfigRenderSupport[kAlpha_8_GrPixelConfig][kNo_MSAA] = fTextureRedSupport; - fConfigRenderSupport[kAlpha_8_GrPixelConfig][kYes_MSAA] = fTextureRedSupport; - } - - if (kGL_GrGLStandard != standard) { - // only available in ES - fConfigRenderSupport[kRGB_565_GrPixelConfig][kNo_MSAA] = true; - fConfigRenderSupport[kRGB_565_GrPixelConfig][kYes_MSAA] = true; - } - - // we no longer support 444 as a render target - fConfigRenderSupport[kRGBA_4444_GrPixelConfig][kNo_MSAA] = false; - fConfigRenderSupport[kRGBA_4444_GrPixelConfig][kYes_MSAA] = false; - - if (this->fRGBA8RenderbufferSupport) { - fConfigRenderSupport[kRGBA_8888_GrPixelConfig][kNo_MSAA] = true; - fConfigRenderSupport[kRGBA_8888_GrPixelConfig][kYes_MSAA] = true; - } - - if (this->isConfigTexturable(kBGRA_8888_GrPixelConfig)) { - fConfigRenderSupport[kBGRA_8888_GrPixelConfig][kNo_MSAA] = true; - // The GL_EXT_texture_format_BGRA8888 extension does not add BGRA to the list of - // configs that are color-renderable and can be passed to glRenderBufferStorageMultisample. - // Chromium may have an extension to allow BGRA renderbuffers to work on desktop platforms. - if (ctxInfo.hasExtension("GL_CHROMIUM_renderbuffer_format_BGRA8888")) { - fConfigRenderSupport[kBGRA_8888_GrPixelConfig][kYes_MSAA] = true; - } else { - fConfigRenderSupport[kBGRA_8888_GrPixelConfig][kYes_MSAA] = - !fBGRAIsInternalFormat || !this->usesMSAARenderBuffers(); - } - } - - if (this->fRGBA8RenderbufferSupport && srgbSupport) { - fConfigRenderSupport[kSRGBA_8888_GrPixelConfig][kNo_MSAA] = true; - fConfigRenderSupport[kSRGBA_8888_GrPixelConfig][kYes_MSAA] = true; - } - - if (this->isConfigTexturable(kRGBA_float_GrPixelConfig)) { - if (kGL_GrGLStandard == standard) { - fConfigRenderSupport[kRGBA_float_GrPixelConfig][kNo_MSAA] = true; - fConfigRenderSupport[kRGBA_float_GrPixelConfig][kYes_MSAA] = true; - } else { - // for now we only enable this on desktop, because on ES we'd have to solve many - // precision issues and no clients actually want this yet - /* - if (ctxInfo.hasExtension("GL_EXT_color_buffer_float")) { - fConfigRenderSupport[kRGBA_float_GrPixelConfig][kNo_MSAA] = true; - } else { - fConfigRenderSupport[kRGBA_float_GrPixelConfig][kNo_MSAA] = false; - } - // for now we don't support floating point MSAA on ES - fConfigRenderSupport[kRGBA_float_GrPixelConfig][kYes_MSAA] = false;*/ - fConfigRenderSupport[kRGBA_float_GrPixelConfig][kNo_MSAA] = false; - fConfigRenderSupport[kRGBA_float_GrPixelConfig][kYes_MSAA] = false; - } - } - - if (this->isConfigTexturable(kAlpha_half_GrPixelConfig)) { - if (kGL_GrGLStandard == standard) { - fConfigRenderSupport[kAlpha_half_GrPixelConfig][kNo_MSAA] = true; - fConfigRenderSupport[kAlpha_half_GrPixelConfig][kYes_MSAA] = true; - } else if (ctxInfo.version() >= GR_GL_VER(3,0)) { - fConfigRenderSupport[kAlpha_half_GrPixelConfig][kNo_MSAA] = true; - // for now we don't support floating point MSAA on ES - fConfigRenderSupport[kAlpha_half_GrPixelConfig][kYes_MSAA] = false; - } else { - if (ctxInfo.hasExtension("GL_EXT_color_buffer_half_float") && fTextureRedSupport) { - fConfigRenderSupport[kAlpha_half_GrPixelConfig][kNo_MSAA] = true; - } else { - fConfigRenderSupport[kAlpha_half_GrPixelConfig][kNo_MSAA] = false; - } - // for now we don't support floating point MSAA on ES - fConfigRenderSupport[kAlpha_half_GrPixelConfig][kYes_MSAA] = false; - } - } - - if (this->isConfigTexturable(kRGBA_half_GrPixelConfig)) { - if (kGL_GrGLStandard == standard) { - fConfigRenderSupport[kRGBA_half_GrPixelConfig][kNo_MSAA] = true; - fConfigRenderSupport[kRGBA_half_GrPixelConfig][kYes_MSAA] = true; - } else if (ctxInfo.version() >= GR_GL_VER(3, 0)) { - fConfigRenderSupport[kRGBA_half_GrPixelConfig][kNo_MSAA] = true; - // for now we don't support floating point MSAA on ES - fConfigRenderSupport[kRGBA_half_GrPixelConfig][kYes_MSAA] = false; - } else { - if (ctxInfo.hasExtension("GL_EXT_color_buffer_half_float")) { - fConfigRenderSupport[kRGBA_half_GrPixelConfig][kNo_MSAA] = true; - } else { - fConfigRenderSupport[kRGBA_half_GrPixelConfig][kNo_MSAA] = false; - } - // for now we don't support floating point MSAA on ES - fConfigRenderSupport[kRGBA_half_GrPixelConfig][kYes_MSAA] = false; - } - } - - // If we don't support MSAA then undo any places above where we set a config as renderable with - // msaa. - if (kNone_MSFBOType == fMSFBOType) { - for (int i = 0; i < kGrPixelConfigCnt; ++i) { - fConfigRenderSupport[i][kYes_MSAA] = false; - } - } -} - -void GrGLCaps::initConfigTexturableTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli, - bool srgbSupport) { - GrGLStandard standard = ctxInfo.standard(); - GrGLVersion version = ctxInfo.version(); - - // Base texture support - fConfigTextureSupport[kAlpha_8_GrPixelConfig] = true; - fConfigTextureSupport[kRGB_565_GrPixelConfig] = true; - fConfigTextureSupport[kRGBA_4444_GrPixelConfig] = true; - fConfigTextureSupport[kRGBA_8888_GrPixelConfig] = true; - - // Disable this for now, while we investigate https://bug.skia.org/4333 - if (false) { - // Check for 8-bit palette.. - GrGLint numFormats; - GR_GL_GetIntegerv(gli, GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats); - if (numFormats) { - SkAutoSTMalloc<10, GrGLint> formats(numFormats); - GR_GL_GetIntegerv(gli, GR_GL_COMPRESSED_TEXTURE_FORMATS, formats); - for (int i = 0; i < numFormats; ++i) { - if (GR_GL_PALETTE8_RGBA8 == formats[i]) { - fConfigTextureSupport[kIndex_8_GrPixelConfig] = true; - break; - } - } - } - } - - // Check for BGRA - if (kGL_GrGLStandard == standard) { - fConfigTextureSupport[kBGRA_8888_GrPixelConfig] = - version >= GR_GL_VER(1,2) || ctxInfo.hasExtension("GL_EXT_bgra"); - } else { - if (ctxInfo.hasExtension("GL_APPLE_texture_format_BGRA8888")) { - fConfigTextureSupport[kBGRA_8888_GrPixelConfig] = true; - } else if (ctxInfo.hasExtension("GL_EXT_texture_format_BGRA8888")) { - fConfigTextureSupport[kBGRA_8888_GrPixelConfig] = true; - fBGRAIsInternalFormat = true; - } - SkASSERT(fConfigTextureSupport[kBGRA_8888_GrPixelConfig] || - kSkia8888_GrPixelConfig != kBGRA_8888_GrPixelConfig); - } - - fConfigTextureSupport[kSRGBA_8888_GrPixelConfig] = srgbSupport; - - // Compressed texture support - - // glCompressedTexImage2D is available on all OpenGL ES devices... - // however, it is only available on standard OpenGL after version 1.3 - bool hasCompressTex2D = (kGL_GrGLStandard != standard || version >= GR_GL_VER(1, 3)); - - fCompressedTexSubImageSupport = - hasCompressTex2D && (gli->fFunctions.fCompressedTexSubImage2D); - - // Check for ETC1 - bool hasETC1 = false; - - // First check version for support - if (kGL_GrGLStandard == standard) { - hasETC1 = hasCompressTex2D && - (version >= GR_GL_VER(4, 3) || - ctxInfo.hasExtension("GL_ARB_ES3_compatibility")); - } else { - hasETC1 = hasCompressTex2D && - (version >= GR_GL_VER(3, 0) || - ctxInfo.hasExtension("GL_OES_compressed_ETC1_RGB8_texture") || - // ETC2 is a superset of ETC1, so we can just check for that, too. - (ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGB8_texture") && - ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGBA8_texture"))); - } - fConfigTextureSupport[kETC1_GrPixelConfig] = hasETC1; - - // Check for LATC under its various forms - LATCAlias alias = kLATC_LATCAlias; - bool hasLATC = hasCompressTex2D && - (ctxInfo.hasExtension("GL_EXT_texture_compression_latc") || - ctxInfo.hasExtension("GL_NV_texture_compression_latc")); - - // Check for RGTC - if (!hasLATC) { - // If we're using OpenGL 3.0 or later, then we have RGTC, an identical compression format. - if (kGL_GrGLStandard == standard) { - hasLATC = version >= GR_GL_VER(3, 0); - } - - if (!hasLATC) { - hasLATC = - ctxInfo.hasExtension("GL_EXT_texture_compression_rgtc") || - ctxInfo.hasExtension("GL_ARB_texture_compression_rgtc"); - } - - if (hasLATC) { - alias = kRGTC_LATCAlias; - } - } - - // Check for 3DC - if (!hasLATC) { - hasLATC = ctxInfo.hasExtension("GL_AMD_compressed_3DC_texture"); - if (hasLATC) { - alias = k3DC_LATCAlias; - } - } - - fConfigTextureSupport[kLATC_GrPixelConfig] = hasLATC; - fLATCAlias = alias; - - // Check for R11_EAC ... We don't support R11_EAC on desktop, as most - // cards default to decompressing the textures in the driver, and is - // generally slower. - if (kGL_GrGLStandard != standard) { - fConfigTextureSupport[kR11_EAC_GrPixelConfig] = version >= GR_GL_VER(3, 0); - } - - // Check for ASTC - fConfigTextureSupport[kASTC_12x12_GrPixelConfig] = - ctxInfo.hasExtension("GL_KHR_texture_compression_astc_hdr") || - ctxInfo.hasExtension("GL_KHR_texture_compression_astc_ldr") || - ctxInfo.hasExtension("GL_OES_texture_compression_astc"); - - // Check for floating point texture support - // NOTE: We disallow floating point textures on ES devices if linear - // filtering modes are not supported. This is for simplicity, but a more - // granular approach is possible. Coincidentally, floating point textures became part of - // the standard in ES3.1 / OGL 3.1, hence the shorthand - bool hasFPTextures = version >= GR_GL_VER(3, 1); - if (!hasFPTextures) { - hasFPTextures = ctxInfo.hasExtension("GL_ARB_texture_float") || - (ctxInfo.hasExtension("GL_OES_texture_float_linear") && - ctxInfo.hasExtension("GL_OES_texture_float")); - } - fConfigTextureSupport[kRGBA_float_GrPixelConfig] = hasFPTextures; - - // Check for fp16 texture support - // NOTE: We disallow floating point textures on ES devices if linear - // filtering modes are not supported. This is for simplicity, but a more - // granular approach is possible. Coincidentally, 16-bit floating point textures became part of - // the standard in ES3.1 / OGL 3.1, hence the shorthand - bool hasHalfFPTextures = version >= GR_GL_VER(3, 1); - if (!hasHalfFPTextures) { - hasHalfFPTextures = ctxInfo.hasExtension("GL_ARB_texture_float") || - (ctxInfo.hasExtension("GL_OES_texture_half_float_linear") && - ctxInfo.hasExtension("GL_OES_texture_half_float")); - } - fConfigTextureSupport[kAlpha_half_GrPixelConfig] = hasHalfFPTextures; - fConfigTextureSupport[kRGBA_half_GrPixelConfig] = hasHalfFPTextures; -} - -bool GrGLCaps::doReadPixelsSupported(const GrGLInterface* intf, - GrGLenum format, - GrGLenum type) const { - if (GR_GL_RGBA == format && GR_GL_UNSIGNED_BYTE == type) { - // ES 2 guarantees this format is supported - return true; - } - - if (!fTwoFormatLimit) { - // not limited by ES 2's constraints - return true; - } - - GrGLint otherFormat = GR_GL_RGBA; - GrGLint otherType = GR_GL_UNSIGNED_BYTE; - - // The other supported format/type combo supported for ReadPixels - // can change based on which render target is bound - GR_GL_GetIntegerv(intf, - GR_GL_IMPLEMENTATION_COLOR_READ_FORMAT, - &otherFormat); - - GR_GL_GetIntegerv(intf, - GR_GL_IMPLEMENTATION_COLOR_READ_TYPE, - &otherType); - - return (GrGLenum)otherFormat == format && (GrGLenum)otherType == type; -} - bool GrGLCaps::readPixelsSupported(const GrGLInterface* intf, - GrGLenum format, - GrGLenum type, - GrGLenum currFboFormat) const { - ReadPixelsSupportedFormat key = {format, type, currFboFormat}; - if (const bool* supported = fReadPixelsSupportedCache.find(key)) { - return *supported; + GrPixelConfig readConfig, + GrPixelConfig currFBOConfig) const { + SkASSERT(this->isConfigRenderable(currFBOConfig, false)); + + GrGLenum readFormat; + GrGLenum readType; + if (!this->getReadPixelsFormat(currFBOConfig, readConfig, &readFormat, &readType)) { + return false; } - bool supported = this->doReadPixelsSupported(intf, format, type); - fReadPixelsSupportedCache.set(key, supported); - return supported; + + if (kGL_GrGLStandard == intf->fStandard) { + // All of our renderable configs can be converted to each other by glReadPixels in OpenGL. + return true; + } + + // See Section 16.1.2 in the ES 3.2 specification. + + if (kNormalizedFixedPoint_FormatType == fConfigTable[currFBOConfig].fFormatType) { + if (GR_GL_RGBA == readFormat && GR_GL_UNSIGNED_BYTE == readType) { + return true; + } + } else { + SkASSERT(kFloat_FormatType == fConfigTable[currFBOConfig].fFormatType); + if (GR_GL_RGBA == readFormat && GR_GL_FLOAT == readType) { + return true; + } + } + + if (0 == fConfigTable[currFBOConfig].fSecondReadPixelsFormat.fFormat) { + ReadPixelsFormat* rpFormat = + const_cast(&fConfigTable[currFBOConfig].fSecondReadPixelsFormat); + GrGLint format = 0, type = 0; + GR_GL_GetIntegerv(intf, GR_GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format); + GR_GL_GetIntegerv(intf, GR_GL_IMPLEMENTATION_COLOR_READ_TYPE, &type); + rpFormat->fFormat = format; + rpFormat->fType = type; + } + + return fConfigTable[currFBOConfig].fSecondReadPixelsFormat.fFormat == readFormat && + fConfigTable[currFBOConfig].fSecondReadPixelsFormat.fType == readType; } void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { @@ -1190,8 +871,6 @@ SkString GrGLCaps::dump() const { r.appendf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors); r.appendf("Max FS Texture Units: %d\n", fMaxFragmentTextureUnits); r.appendf("Max Vertex Attributes: %d\n", fMaxVertexAttributes); - r.appendf("Support RGBA8 Render Buffer: %s\n", (fRGBA8RenderbufferSupport ? "YES": "NO")); - r.appendf("BGRA is an internal format: %s\n", (fBGRAIsInternalFormat ? "YES": "NO")); r.appendf("Unpack Row length support: %s\n", (fUnpackRowLengthSupport ? "YES": "NO")); r.appendf("Unpack Flip Y support: %s\n", (fUnpackFlipYSupport ? "YES": "NO")); r.appendf("Pack Row length support: %s\n", (fPackRowLengthSupport ? "YES": "NO")); @@ -1201,9 +880,7 @@ SkString GrGLCaps::dump() const { r.appendf("Texture Storage support: %s\n", (fTexStorageSupport ? "YES": "NO")); r.appendf("GL_R support: %s\n", (fTextureRedSupport ? "YES": "NO")); r.appendf("GL_ARB_imaging support: %s\n", (fImagingSupport ? "YES": "NO")); - r.appendf("Two Format Limit: %s\n", (fTwoFormatLimit ? "YES": "NO")); r.appendf("Vertex array object support: %s\n", (fVertexArrayObjectSupport ? "YES": "NO")); - r.appendf("Instanced drawing support: %s\n", (fInstancedDrawingSupport ? "YES": "NO")); r.appendf("Direct state access support: %s\n", (fDirectStateAccessSupport ? "YES": "NO")); r.appendf("Debug support: %s\n", (fDebugSupport ? "YES": "NO")); r.appendf("Multisample disable support: %s\n", (fMultisampleDisableSupport ? "YES" : "NO")); @@ -1213,6 +890,26 @@ SkString GrGLCaps::dump() const { r.appendf("RGBA 8888 pixel ops are slow: %s\n", (fRGBA8888PixelsOpsAreSlow ? "YES" : "NO")); r.appendf("Partial FBO read is slow: %s\n", (fPartialFBOReadIsSlow ? "YES" : "NO")); r.appendf("Bind uniform location support: %s\n", (fBindUniformLocationSupport ? "YES" : "NO")); + r.appendf("External texture support: %s\n", (fExternalTextureSupport ? "YES" : "NO")); + r.appendf("Rectangle texture support: %s\n", (fRectangleTextureSupport? "YES" : "NO")); + r.appendf("Texture swizzle support: %s\n", (fTextureSwizzleSupport ? "YES" : "NO")); + + r.append("Configs\n-------\n"); + for (int i = 0; i < kGrPixelConfigCnt; ++i) { + r.appendf(" cfg: %d flags: 0x%04x, b_internal: 0x%08x s_internal: 0x%08x, e_format: " + "0x%08x, e_format_teximage: 0x%08x, e_type: 0x%08x, i_for_teximage: 0x%08x, " + "i_for_renderbuffer: 0x%08x\n", + i, + fConfigTable[i].fFlags, + fConfigTable[i].fFormats.fBaseInternalFormat, + fConfigTable[i].fFormats.fSizedInternalFormat, + fConfigTable[i].fFormats.fExternalFormat[kOther_ExternalFormatUsage], + fConfigTable[i].fFormats.fExternalFormat[kTexImage_ExternalFormatUsage], + fConfigTable[i].fFormats.fExternalType, + fConfigTable[i].fFormats.fInternalFormatTexImage, + fConfigTable[i].fFormats.fInternalFormatRenderbuffer); + } + return r; } @@ -1300,44 +997,592 @@ void GrGLCaps::initShaderPrecisionTable(const GrGLContextInfo& ctxInfo, } } -void GrGLCaps::initConfigSwizzleTable(const GrGLContextInfo& ctxInfo, GrGLSLCaps* glslCaps) { +bool GrGLCaps::bgraIsInternalFormat() const { + return fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fBaseInternalFormat == GR_GL_BGRA; +} + +bool GrGLCaps::getTexImageFormats(GrPixelConfig surfaceConfig, GrPixelConfig externalConfig, + GrGLenum* internalFormat, GrGLenum* externalFormat, + GrGLenum* externalType) const { + if (!this->getExternalFormat(surfaceConfig, externalConfig, kTexImage_ExternalFormatUsage, + externalFormat, externalType)) { + return false; + } + *internalFormat = fConfigTable[surfaceConfig].fFormats.fInternalFormatTexImage; + return true; +} + +bool GrGLCaps::getCompressedTexImageFormats(GrPixelConfig surfaceConfig, + GrGLenum* internalFormat) const { + if (!GrPixelConfigIsCompressed(surfaceConfig)) { + return false; + } + *internalFormat = fConfigTable[surfaceConfig].fFormats.fInternalFormatTexImage; + return true; +} + +bool GrGLCaps::getReadPixelsFormat(GrPixelConfig surfaceConfig, GrPixelConfig externalConfig, + GrGLenum* externalFormat, GrGLenum* externalType) const { + if (!this->getExternalFormat(surfaceConfig, externalConfig, kOther_ExternalFormatUsage, + externalFormat, externalType)) { + return false; + } + return true; +} + +bool GrGLCaps::getRenderbufferFormat(GrPixelConfig config, GrGLenum* internalFormat) const { + if (GrPixelConfigIsCompressed(config)) { + return false; + } + *internalFormat = fConfigTable[config].fFormats.fInternalFormatRenderbuffer; + return true; +} + +bool GrGLCaps::getExternalFormat(GrPixelConfig surfaceConfig, GrPixelConfig memoryConfig, + ExternalFormatUsage usage, GrGLenum* externalFormat, + GrGLenum* externalType) const { + SkASSERT(externalFormat && externalType); + if (GrPixelConfigIsCompressed(memoryConfig) || GrPixelConfigIsCompressed(memoryConfig)) { + return false; + } + + bool surfaceIsAlphaOnly = GrPixelConfigIsAlphaOnly(surfaceConfig); + bool memoryIsAlphaOnly = GrPixelConfigIsAlphaOnly(memoryConfig); + + // We don't currently support moving RGBA data into and out of ALPHA surfaces. It could be + // made to work in many cases using glPixelStore and what not but is not needed currently. + if (surfaceIsAlphaOnly && !memoryIsAlphaOnly) { + return false; + } + + *externalFormat = fConfigTable[memoryConfig].fFormats.fExternalFormat[usage]; + *externalType = fConfigTable[memoryConfig].fFormats.fExternalType; + + return true; +} + +void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli, + GrGLSLCaps* glslCaps) { + /* + Comments on renderability of configs on various GL versions. + OpenGL < 3.0: + no built in support for render targets. + GL_EXT_framebuffer_object adds possible support for any sized format with base internal + format RGB, RGBA and NV float formats we don't use. + This is the following: + R3_G3_B2, RGB4, RGB5, RGB8, RGB10, RGB12, RGB16, RGBA2, RGBA4, RGB5_A1, RGBA8 + RGB10_A2, RGBA12,RGBA16 + Though, it is hard to believe the more obscure formats such as RGBA12 would work + since they aren't required by later standards and the driver can simply return + FRAMEBUFFER_UNSUPPORTED for anything it doesn't allow. + GL_ARB_framebuffer_object adds everything added by the EXT extension and additionally + any sized internal format with a base internal format of ALPHA, LUMINANCE, + LUMINANCE_ALPHA, INTENSITY, RED, and RG. + This adds a lot of additional renderable sized formats, including ALPHA8. + The GL_ARB_texture_rg brings in the RED and RG formats (8, 8I, 8UI, 16, 16I, 16UI, + 16F, 32I, 32UI, and 32F variants). + Again, the driver has an escape hatch via FRAMEBUFFER_UNSUPPORTED. + + For both the above extensions we limit ourselves to those that are also required by + OpenGL 3.0. + + OpenGL 3.0: + Any format with base internal format ALPHA, RED, RG, RGB or RGBA is "color-renderable" + but are not required to be supported as renderable textures/renderbuffer. + Required renderable color formats: + - RGBA32F, RGBA32I, RGBA32UI, RGBA16, RGBA16F, RGBA16I, + RGBA16UI, RGBA8, RGBA8I, RGBA8UI, SRGB8_ALPHA8, and + RGB10_A2. + - R11F_G11F_B10F. + - RG32F, RG32I, RG32UI, RG16, RG16F, RG16I, RG16UI, RG8, RG8I, + and RG8UI. + - R32F, R32I, R32UI, R16F, R16I, R16UI, R16, R8, R8I, and R8UI. + - ALPHA8 + + OpenGL 3.1, 3.2, 3.3 + Same as 3.0 except ALPHA8 requires GL_ARB_compatibility/compatibility profile. + OpengGL 3.3, 4.0, 4.1 + Adds RGB10_A2UI. + OpengGL 4.2 + Adds + - RGB5_A1, RGBA4 + - RGB565 + OpenGL 4.4 + Does away with the separate list and adds a column to the sized internal color format + table. However, no new formats become required color renderable. + + ES 2.0 + color renderable: RGBA4, RGB5_A1, RGB565 + GL_EXT_texture_rg adds support for R8, RG5 as a color render target + GL_OES_rgb8_rgba8 adds support for RGB8 and RGBA8 + GL_ARM_rgba8 adds support for RGBA8 (but not RGB8) + GL_EXT_texture_format_BGRA8888 does not add renderbuffer support + GL_CHROMIUM_renderbuffer_format_BGRA8888 adds BGRA8 as color-renderable + GL_APPLE_texture_format_BGRA8888 does not add renderbuffer support + + ES 3.0 + - RGBA32I, RGBA32UI, RGBA16I, RGBA16UI, RGBA8, RGBA8I, + RGBA8UI, SRGB8_ALPHA8, RGB10_A2, RGB10_A2UI, RGBA4, and + RGB5_A1. + - RGB8 and RGB565. + - RG32I, RG32UI, RG16I, RG16UI, RG8, RG8I, and RG8UI. + - R32I, R32UI, R16I, R16UI, R8, R8I, and R8UI + ES 3.1 + Adds RGB10_A2, RGB10_A2UI, + ES 3.2 + Adds R16F, RG16F, RGBA16F, R32F, RG32F, RGBA32F, R11F_G11F_B10F. + */ + uint32_t allRenderFlags = ConfigInfo::kRenderable_Flag; + if (kNone_MSFBOType != fMSFBOType) { + allRenderFlags |= ConfigInfo::kRenderableWithMSAA_Flag; + } + GrGLStandard standard = ctxInfo.standard(); GrGLVersion version = ctxInfo.version(); - glslCaps->fMustSwizzleInShader = true; + fConfigTable[kUnknown_GrPixelConfig].fFormats.fBaseInternalFormat = 0; + fConfigTable[kUnknown_GrPixelConfig].fFormats.fSizedInternalFormat = 0; + fConfigTable[kUnknown_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; + fConfigTable[kUnknown_GrPixelConfig].fFormats.fExternalType = 0; + fConfigTable[kUnknown_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + fConfigTable[kUnknown_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + + fConfigTable[kRGBA_8888_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA; + fConfigTable[kRGBA_8888_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA8; + fConfigTable[kRGBA_8888_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_RGBA; + fConfigTable[kRGBA_8888_GrPixelConfig].fFormats.fExternalType = GR_GL_UNSIGNED_BYTE; + fConfigTable[kRGBA_8888_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + fConfigTable[kRGBA_8888_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; if (kGL_GrGLStandard == standard) { - if (version >= GR_GL_VER(3,3) || ctxInfo.hasExtension("GL_ARB_texture_swizzle")) { - glslCaps->fMustSwizzleInShader = false; + // We require some form of FBO support and all GLs with FBO support can render to RGBA8 + fConfigTable[kRGBA_8888_GrPixelConfig].fFlags |= allRenderFlags; + } else { + if (version >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_OES_rgb8_rgba8") || + ctxInfo.hasExtension("GL_ARM_rgba8")) { + fConfigTable[kRGBA_8888_GrPixelConfig].fFlags |= allRenderFlags; + } + } + fConfigTable[kRGBA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + + fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_BGRA; + fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fExternalType = GR_GL_UNSIGNED_BYTE; + fConfigTable[kBGRA_8888_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + if (kGL_GrGLStandard == standard) { + fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA; + fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA8; + if (version >= GR_GL_VER(1, 2) || ctxInfo.hasExtension("GL_EXT_bgra")) { + // Since the internal format is RGBA8, it is also renderable. + fConfigTable[kBGRA_8888_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag | + allRenderFlags; } } else { - if (version >= GR_GL_VER(3,0)) { - glslCaps->fMustSwizzleInShader = false; + fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_BGRA; + fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_BGRA8; + if (ctxInfo.hasExtension("GL_APPLE_texture_format_BGRA8888")) { + // The APPLE extension doesn't make this renderable. + fConfigTable[kBGRA_8888_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + if (version < GR_GL_VER(3,0) && !ctxInfo.hasExtension("GL_EXT_texture_storage")) { + // On ES2 the internal format of a BGRA texture is RGBA with the APPLE extension. + // Though, that seems to not be the case if the texture storage extension is + // present. The specs don't exactly make that clear. + fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA; + fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA8; + } + } else if (ctxInfo.hasExtension("GL_EXT_texture_format_BGRA8888")) { + fConfigTable[kBGRA_8888_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag | + ConfigInfo::kRenderable_Flag; + if (ctxInfo.hasExtension("GL_CHROMIUM_renderbuffer_format_BGRA8888") && + this->usesMSAARenderBuffers()) { + fConfigTable[kBGRA_8888_GrPixelConfig].fFlags |= + ConfigInfo::kRenderableWithMSAA_Flag; + } + } + } + fConfigTable[kBGRA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + + // We only enable srgb support if both textures and FBOs support srgb. + bool srgbSupport = false; + if (kGL_GrGLStandard == standard) { + if (ctxInfo.version() >= GR_GL_VER(3,0)) { + srgbSupport = true; + } else if (ctxInfo.hasExtension("GL_EXT_texture_sRGB")) { + if (ctxInfo.hasExtension("GL_ARB_framebuffer_sRGB") || + ctxInfo.hasExtension("GL_EXT_framebuffer_sRGB")) { + srgbSupport = true; + } + } + // All the above srgb extensions support toggling srgb writes + fSRGBWriteControl = srgbSupport; + } else { + // See https://bug.skia.org/4148 for PowerVR issue. + srgbSupport = kPowerVRRogue_GrGLRenderer != ctxInfo.renderer() && + (ctxInfo.version() >= GR_GL_VER(3,0) || ctxInfo.hasExtension("GL_EXT_sRGB")); + // ES through 3.1 requires EXT_srgb_write_control to support toggling + // sRGB writing for destinations. + fSRGBWriteControl = ctxInfo.hasExtension("GL_EXT_sRGB_write_control"); + } + fConfigTable[kSRGBA_8888_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_SRGB_ALPHA; + fConfigTable[kSRGBA_8888_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_SRGB8_ALPHA8; + // GL does not do srgb<->rgb conversions when transferring between cpu and gpu. Thus, the + // external format is GL_RGBA. See below for note about ES2.0 and glTex[Sub]Image. + fConfigTable[kSRGBA_8888_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_RGBA; + fConfigTable[kSRGBA_8888_GrPixelConfig].fFormats.fExternalType = GR_GL_UNSIGNED_BYTE; + fConfigTable[kSRGBA_8888_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + if (srgbSupport) { + fConfigTable[kSRGBA_8888_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag | + allRenderFlags; + } + fConfigTable[kSRGBA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + + fConfigTable[kRGB_565_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGB; + if (this->ES2CompatibilitySupport()) { + fConfigTable[kRGB_565_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGB565; + } else { + fConfigTable[kRGB_565_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGB5; + } + fConfigTable[kRGB_565_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_RGB; + fConfigTable[kRGB_565_GrPixelConfig].fFormats.fExternalType = GR_GL_UNSIGNED_SHORT_5_6_5; + fConfigTable[kRGB_565_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + fConfigTable[kRGB_565_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + if (kGL_GrGLStandard == standard) { + if (version >= GR_GL_VER(4, 2) || ctxInfo.hasExtension("GL_ES2_compatibility")) { + fConfigTable[kRGB_565_GrPixelConfig].fFlags |= allRenderFlags; + } + } else { + fConfigTable[kRGB_565_GrPixelConfig].fFlags |= allRenderFlags; + } + fConfigTable[kRGB_565_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + + fConfigTable[kRGBA_4444_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA; + fConfigTable[kRGBA_4444_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA4; + fConfigTable[kRGBA_4444_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_RGBA; + fConfigTable[kRGBA_4444_GrPixelConfig].fFormats.fExternalType = GR_GL_UNSIGNED_SHORT_4_4_4_4; + fConfigTable[kRGBA_4444_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + fConfigTable[kRGBA_4444_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + if (kGL_GrGLStandard == standard) { + if (version >= GR_GL_VER(4, 2)) { + fConfigTable[kRGBA_4444_GrPixelConfig].fFlags |= allRenderFlags; + } + } else { + fConfigTable[kRGBA_4444_GrPixelConfig].fFlags |= allRenderFlags; + } + fConfigTable[kRGBA_4444_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + + if (this->textureRedSupport()) { + fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RED; + fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_R8; + fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_RED; + fConfigTable[kAlpha_8_GrPixelConfig].fSwizzle = GrSwizzle::RRRR(); + } else { + fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_ALPHA; + fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_ALPHA8; + fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_ALPHA; + fConfigTable[kAlpha_8_GrPixelConfig].fSwizzle = GrSwizzle::AAAA(); + } + fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fExternalType = GR_GL_UNSIGNED_BYTE; + fConfigTable[kAlpha_8_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + fConfigTable[kAlpha_8_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + if (this->textureRedSupport() || kDesktop_ARB_MSFBOType == this->msFBOType()) { + // desktop ARB extension/3.0+ supports ALPHA8 as renderable. + // Core profile removes ALPHA8 support, but we should have chosen R8 in that case. + fConfigTable[kAlpha_8_GrPixelConfig].fFlags |= allRenderFlags; + } + + // Check for [half] floating point texture support + // NOTE: We disallow floating point textures on ES devices if linear filtering modes are not + // supported. This is for simplicity, but a more granular approach is possible. Coincidentally, + // [half] floating point textures became part of the standard in ES3.1 / OGL 3.0. + bool hasFPTextures = false; + bool hasHalfFPTextures = false; + // for now we don't support floating point MSAA on ES + uint32_t fpRenderFlags = (kGL_GrGLStandard == standard) ? + allRenderFlags : (uint32_t)ConfigInfo::kRenderable_Flag; + + if (kGL_GrGLStandard == standard) { + if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_texture_float")) { + hasFPTextures = true; + hasHalfFPTextures = true; + } + } else { + if (version >= GR_GL_VER(3, 1)) { + hasFPTextures = true; + hasHalfFPTextures = true; + } else { + if (ctxInfo.hasExtension("GL_OES_texture_float_linear") && + ctxInfo.hasExtension("GL_OES_texture_float")) { + hasFPTextures = true; + } + if (ctxInfo.hasExtension("GL_OES_texture_half_float_linear") && + ctxInfo.hasExtension("GL_OES_texture_half_float")) { + hasHalfFPTextures = true; + } } } - glslCaps->fConfigSwizzle[kUnknown_GrPixelConfig] = nullptr; - if (fTextureRedSupport) { - glslCaps->fConfigSwizzle[kAlpha_8_GrPixelConfig] = "rrrr"; - glslCaps->fConfigSwizzle[kAlpha_half_GrPixelConfig] = "rrrr"; - } else { - glslCaps->fConfigSwizzle[kAlpha_8_GrPixelConfig] = "aaaa"; - glslCaps->fConfigSwizzle[kAlpha_half_GrPixelConfig] = "aaaa"; + fConfigTable[kRGBA_float_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA; + fConfigTable[kRGBA_float_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA32F; + fConfigTable[kRGBA_float_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_RGBA; + fConfigTable[kRGBA_float_GrPixelConfig].fFormats.fExternalType = GR_GL_FLOAT; + fConfigTable[kRGBA_float_GrPixelConfig].fFormatType = kFloat_FormatType; + if (hasFPTextures) { + fConfigTable[kRGBA_float_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + // For now we only enable rendering to float on desktop, because on ES we'd have to solve + // many precision issues and no clients actually want this yet. + if (kGL_GrGLStandard == standard /* || version >= GR_GL_VER(3,2) || + ctxInfo.hasExtension("GL_EXT_color_buffer_float")*/) { + fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= fpRenderFlags; + } } - glslCaps->fConfigSwizzle[kIndex_8_GrPixelConfig] = "rgba"; - glslCaps->fConfigSwizzle[kRGB_565_GrPixelConfig] = "rgba"; - glslCaps->fConfigSwizzle[kRGBA_4444_GrPixelConfig] = "rgba"; - glslCaps->fConfigSwizzle[kRGBA_8888_GrPixelConfig] = "rgba"; - glslCaps->fConfigSwizzle[kBGRA_8888_GrPixelConfig] = "rgba"; - glslCaps->fConfigSwizzle[kSRGBA_8888_GrPixelConfig] = "rgba"; - glslCaps->fConfigSwizzle[kETC1_GrPixelConfig] = "rgba"; - glslCaps->fConfigSwizzle[kLATC_GrPixelConfig] = "rrrr"; - glslCaps->fConfigSwizzle[kR11_EAC_GrPixelConfig] = "rrrr"; - glslCaps->fConfigSwizzle[kASTC_12x12_GrPixelConfig] = "rgba"; - glslCaps->fConfigSwizzle[kRGBA_float_GrPixelConfig] = "rgba"; - glslCaps->fConfigSwizzle[kRGBA_half_GrPixelConfig] = "rgba"; + fConfigTable[kRGBA_float_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + if (this->textureRedSupport()) { + fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RED; + fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_R16F; + fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] + = GR_GL_RED; + fConfigTable[kAlpha_half_GrPixelConfig].fSwizzle = GrSwizzle::RRRR(); + } else { + fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_ALPHA; + fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_ALPHA16F; + fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] + = GR_GL_ALPHA; + fConfigTable[kAlpha_half_GrPixelConfig].fSwizzle = GrSwizzle::AAAA(); + } + if (kGL_GrGLStandard == ctxInfo.standard() || ctxInfo.version() >= GR_GL_VER(3, 0)) { + fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalType = GR_GL_HALF_FLOAT; + } else { + fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalType = GR_GL_HALF_FLOAT_OES; + } + fConfigTable[kAlpha_half_GrPixelConfig].fFormatType = kFloat_FormatType; + if (hasHalfFPTextures) { + fConfigTable[kAlpha_half_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + // ES requires either 3.2 or the combination of EXT_color_buffer_half_float and support for + // GL_RED internal format. + if (kGL_GrGLStandard == standard || version >= GR_GL_VER(3,2) || + (this->textureRedSupport() && + ctxInfo.hasExtension("GL_EXT_color_buffer_half_float"))) { + fConfigTable[kAlpha_half_GrPixelConfig].fFlags |= fpRenderFlags; + } + } + + fConfigTable[kRGBA_half_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA; + fConfigTable[kRGBA_half_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA16F; + fConfigTable[kRGBA_half_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + GR_GL_RGBA; + if (kGL_GrGLStandard == ctxInfo.standard() || ctxInfo.version() >= GR_GL_VER(3, 0)) { + fConfigTable[kRGBA_half_GrPixelConfig].fFormats.fExternalType = GR_GL_HALF_FLOAT; + } else { + fConfigTable[kRGBA_half_GrPixelConfig].fFormats.fExternalType = GR_GL_HALF_FLOAT_OES; + } + fConfigTable[kRGBA_half_GrPixelConfig].fFormatType = kFloat_FormatType; + if (hasHalfFPTextures) { + fConfigTable[kRGBA_half_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + // ES requires 3.2 or EXT_color_buffer_half_float. + if (kGL_GrGLStandard == standard || version >= GR_GL_VER(3,2) || + ctxInfo.hasExtension("GL_EXT_color_buffer_half_float")) { + fConfigTable[kRGBA_half_GrPixelConfig].fFlags |= fpRenderFlags; + } + } + fConfigTable[kRGBA_half_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + + // Compressed texture support + + // glCompressedTexImage2D is available on all OpenGL ES devices. It is available on standard + // OpenGL after version 1.3. We'll assume at least that level of OpenGL support. + + // TODO: Fix command buffer bindings and remove this. + fCompressedTexSubImageSupport = SkToBool(gli->fFunctions.fCompressedTexSubImage2D); + + // No sized/unsized internal format distinction for compressed formats, no external format. + // Below we set the external formats and types to 0. + + fConfigTable[kIndex_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_PALETTE8_RGBA8; + fConfigTable[kIndex_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_PALETTE8_RGBA8; + fConfigTable[kIndex_8_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; + fConfigTable[kIndex_8_GrPixelConfig].fFormats.fExternalType = 0; + fConfigTable[kIndex_8_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + // Disable this for now, while we investigate https://bug.skia.org/4333 + if (false) { + // Check for 8-bit palette.. + GrGLint numFormats; + GR_GL_GetIntegerv(gli, GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats); + if (numFormats) { + SkAutoSTMalloc<10, GrGLint> formats(numFormats); + GR_GL_GetIntegerv(gli, GR_GL_COMPRESSED_TEXTURE_FORMATS, formats); + for (int i = 0; i < numFormats; ++i) { + if (GR_GL_PALETTE8_RGBA8 == formats[i]) { + fConfigTable[kIndex_8_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + break; + } + } + } + } + fConfigTable[kIndex_8_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + + // May change the internal format based on extensions. + fConfigTable[kLATC_GrPixelConfig].fFormats.fBaseInternalFormat = + GR_GL_COMPRESSED_LUMINANCE_LATC1; + fConfigTable[kLATC_GrPixelConfig].fFormats.fSizedInternalFormat = + GR_GL_COMPRESSED_LUMINANCE_LATC1; + if (ctxInfo.hasExtension("GL_EXT_texture_compression_latc") || + ctxInfo.hasExtension("GL_NV_texture_compression_latc")) { + fConfigTable[kLATC_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + } else if ((kGL_GrGLStandard == standard && version >= GR_GL_VER(3, 0)) || + ctxInfo.hasExtension("GL_EXT_texture_compression_rgtc") || + ctxInfo.hasExtension("GL_ARB_texture_compression_rgtc")) { + // RGTC is identical and available on OpenGL 3.0+ as well as with extensions + fConfigTable[kLATC_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + fConfigTable[kLATC_GrPixelConfig].fFormats.fBaseInternalFormat = + GR_GL_COMPRESSED_RED_RGTC1; + fConfigTable[kLATC_GrPixelConfig].fFormats.fSizedInternalFormat = + GR_GL_COMPRESSED_RED_RGTC1; + } else if (ctxInfo.hasExtension("GL_AMD_compressed_3DC_texture")) { + fConfigTable[kLATC_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + fConfigTable[kLATC_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_COMPRESSED_3DC_X; + fConfigTable[kLATC_GrPixelConfig].fFormats.fSizedInternalFormat = + GR_GL_COMPRESSED_3DC_X; + + } + fConfigTable[kLATC_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; + fConfigTable[kLATC_GrPixelConfig].fFormats.fExternalType = 0; + fConfigTable[kLATC_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + fConfigTable[kLATC_GrPixelConfig].fSwizzle = GrSwizzle::RRRR(); + + fConfigTable[kETC1_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_COMPRESSED_ETC1_RGB8; + fConfigTable[kETC1_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_COMPRESSED_ETC1_RGB8; + fConfigTable[kETC1_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; + fConfigTable[kETC1_GrPixelConfig].fFormats.fExternalType = 0; + fConfigTable[kETC1_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + if (kGL_GrGLStandard == standard) { + if (version >= GR_GL_VER(4, 3) || ctxInfo.hasExtension("GL_ARB_ES3_compatibility")) { + fConfigTable[kETC1_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + } + } else { + if (version >= GR_GL_VER(3, 0) || + ctxInfo.hasExtension("GL_OES_compressed_ETC1_RGB8_texture") || + // ETC2 is a superset of ETC1, so we can just check for that, too. + (ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGB8_texture") && + ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGBA8_texture"))) { + fConfigTable[kETC1_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + } + } + fConfigTable[kETC1_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + + fConfigTable[kR11_EAC_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_COMPRESSED_R11_EAC; + fConfigTable[kR11_EAC_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_COMPRESSED_R11_EAC; + fConfigTable[kR11_EAC_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; + fConfigTable[kR11_EAC_GrPixelConfig].fFormats.fExternalType = 0; + fConfigTable[kR11_EAC_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + // Check for R11_EAC. We don't support R11_EAC on desktop, as most cards default to + // decompressing the textures in the driver, and is generally slower. + if (kGLES_GrGLStandard == standard && version >= GR_GL_VER(3,0)) { + fConfigTable[kR11_EAC_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + } + fConfigTable[kR11_EAC_GrPixelConfig].fSwizzle = GrSwizzle::RRRR(); + + fConfigTable[kASTC_12x12_GrPixelConfig].fFormats.fBaseInternalFormat = + GR_GL_COMPRESSED_RGBA_ASTC_12x12; + fConfigTable[kASTC_12x12_GrPixelConfig].fFormats.fSizedInternalFormat = + GR_GL_COMPRESSED_RGBA_ASTC_12x12; + fConfigTable[kASTC_12x12_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = + 0; + fConfigTable[kASTC_12x12_GrPixelConfig].fFormats.fExternalType = 0; + fConfigTable[kASTC_12x12_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + if (ctxInfo.hasExtension("GL_KHR_texture_compression_astc_hdr") || + ctxInfo.hasExtension("GL_KHR_texture_compression_astc_ldr") || + ctxInfo.hasExtension("GL_OES_texture_compression_astc")) { + fConfigTable[kASTC_12x12_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + } + fConfigTable[kASTC_12x12_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + + // Bulk populate the texture internal/external formats here and then deal with exceptions below. + + // ES 2.0 requires that the internal/external formats match. + bool useSizedTexFormats = (kGL_GrGLStandard == ctxInfo.standard() || + ctxInfo.version() >= GR_GL_VER(3,0)); + // All ES versions (thus far) require sized internal formats for render buffers. + // TODO: Always use sized internal format? + bool useSizedRbFormats = kGLES_GrGLStandard == ctxInfo.standard(); + + for (int i = 0; i < kGrPixelConfigCnt; ++i) { + // Almost always we want to pass fExternalFormat[kOther_ExternalFormatUsage] as the + // param to glTex[Sub]Image. + fConfigTable[i].fFormats.fExternalFormat[kTexImage_ExternalFormatUsage] = + fConfigTable[i].fFormats.fExternalFormat[kOther_ExternalFormatUsage]; + fConfigTable[i].fFormats.fInternalFormatTexImage = useSizedTexFormats ? + fConfigTable[i].fFormats.fSizedInternalFormat : + fConfigTable[i].fFormats.fBaseInternalFormat; + fConfigTable[i].fFormats.fInternalFormatRenderbuffer = useSizedRbFormats ? + fConfigTable[i].fFormats.fSizedInternalFormat : + fConfigTable[i].fFormats.fBaseInternalFormat; + } + // OpenGL ES 2.0 + GL_EXT_sRGB allows GL_SRGB_ALPHA to be specified as the + // param to Tex(Sub)Image. ES 2.0 requires the and params to match. + // Thus, on ES 2.0 we will use GL_SRGB_ALPHA as the param. + // On OpenGL and ES 3.0+ GL_SRGB_ALPHA does not work for the param to glTexImage. + if (ctxInfo.standard() == kGLES_GrGLStandard && ctxInfo.version() == GR_GL_VER(2,0)) { + fConfigTable[kSRGBA_8888_GrPixelConfig].fFormats.fExternalFormat[kTexImage_ExternalFormatUsage] = + GR_GL_SRGB_ALPHA; + } + + // If BGRA is supported as an internal format it must always be specified to glTex[Sub]Image + // as a base format. + // GL_EXT_texture_format_BGRA8888: + // This extension GL_BGRA as an unsized internal format. However, it is written against ES + // 2.0 and therefore doesn't define a value for GL_BGRA8 as ES 2.0 uses unsized internal + // formats. + // GL_APPLE_texture_format_BGRA8888: + // ES 2.0: the extension makes BGRA an external format but not an internal format. + // ES 3.0: the extension explicitly states GL_BGRA8 is not a valid internal format for + // glTexImage (just for glTexStorage). + if (useSizedTexFormats && this->bgraIsInternalFormat()) { + fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fInternalFormatTexImage = GR_GL_BGRA; + } + + // If we don't have texture swizzle support then the shader generator must insert the + // swizzle into shader code. + if (!this->textureSwizzleSupport()) { + for (int i = 0; i < kGrPixelConfigCnt; ++i) { + glslCaps->fConfigTextureSwizzle[i] = fConfigTable[i].fSwizzle; + } + } + + // Shader output swizzles will default to RGBA. When we've use GL_RED instead of GL_ALPHA to + // implement kAlpha_8_GrPixelConfig we need to swizzle the shader outputs so the alpha channel + // gets written to the single component. + if (this->textureRedSupport()) { + for (int i = 0; i < kGrPixelConfigCnt; ++i) { + GrPixelConfig config = static_cast(i); + if (GrPixelConfigIsAlphaOnly(config) && + fConfigTable[i].fFormats.fBaseInternalFormat == GR_GL_RED) { + glslCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA(); + } + } + } + +#ifdef SK_DEBUG + // Make sure we initialized everything. + ConfigInfo defaultEntry; + for (int i = 0; i < kGrPixelConfigCnt; ++i) { + SkASSERT(defaultEntry.fFormats.fBaseInternalFormat != + fConfigTable[i].fFormats.fBaseInternalFormat); + SkASSERT(defaultEntry.fFormats.fSizedInternalFormat != + fConfigTable[i].fFormats.fSizedInternalFormat); + for (int j = 0; j < kExternalFormatUsageCnt; ++j) { + SkASSERT(defaultEntry.fFormats.fExternalFormat[j] != + fConfigTable[i].fFormats.fExternalFormat[j]); + } + SkASSERT(defaultEntry.fFormats.fExternalType != fConfigTable[i].fFormats.fExternalType); + } +#endif } void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {} - - diff --git a/gfx/skia/skia/src/gpu/gl/GrGLCaps.h b/gfx/skia/skia/src/gpu/gl/GrGLCaps.h index 0ec6c85b47e..c4f42701f11 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLCaps.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLCaps.h @@ -9,9 +9,10 @@ #ifndef GrGLCaps_DEFINED #define GrGLCaps_DEFINED -#include "GrCaps.h" #include "glsl/GrGLSL.h" +#include "GrCaps.h" #include "GrGLStencilAttachment.h" +#include "GrSwizzle.h" #include "SkChecksum.h" #include "SkTHash.h" #include "SkTArray.h" @@ -90,6 +91,14 @@ public: kLast_MapBufferType = kChromium_MapBufferType, }; + enum TransferBufferType { + kNone_TransferBufferType, + kPBO_TransferBufferType, // ARB_pixel_buffer_object + kChromium_TransferBufferType, // CHROMIUM_pixel_transfer_buffer_object + + kLast_TransferBufferType = kChromium_TransferBufferType, + }; + /** * Initializes the GrGLCaps to the set of features supported in the current * OpenGL context accessible via ctxInfo. @@ -97,13 +106,83 @@ public: GrGLCaps(const GrContextOptions& contextOptions, const GrGLContextInfo& ctxInfo, const GrGLInterface* glInterface); + bool isConfigTexturable(GrPixelConfig config) const override { + SkASSERT(kGrPixelConfigCnt > config); + return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kTextureable_Flag); + } + + bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { + SkASSERT(kGrPixelConfigCnt > config); + if (withMSAA) { + return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderableWithMSAA_Flag); + } else { + return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag); + } + } + + /** Returns the mapping between GrPixelConfig components and GL internal format components. */ + const GrSwizzle& configSwizzle(GrPixelConfig config) const { + return fConfigTable[config].fSwizzle; + } + + bool getTexImageFormats(GrPixelConfig surfaceConfig, GrPixelConfig externalConfig, + GrGLenum* internalFormat, GrGLenum* externalFormat, + GrGLenum* externalType) const; + + bool getCompressedTexImageFormats(GrPixelConfig surfaceConfig, GrGLenum* internalFormat) const; + + bool getReadPixelsFormat(GrPixelConfig surfaceConfig, GrPixelConfig externalConfig, + GrGLenum* externalFormat, GrGLenum* externalType) const; + + bool getRenderbufferFormat(GrPixelConfig config, GrGLenum* internalFormat) const; + + /** + * Gets an array of legal stencil formats. These formats are not guaranteed + * to be supported by the driver but are legal GLenum names given the GL + * version and extensions supported. + */ + const SkTArray& stencilFormats() const { + return fStencilFormats; + } + + /** + * Has a stencil format index been found for the config (or we've found that no format works). + */ + bool hasStencilFormatBeenDeterminedForConfig(GrPixelConfig config) const { + return fConfigTable[config].fStencilFormatIndex != ConfigInfo::kUnknown_StencilIndex; + } + + /** + * Gets the stencil format index for the config. This assumes + * hasStencilFormatBeenDeterminedForConfig has already been checked. Returns a value < 0 if + * no stencil format is supported with the config. Otherwise, returned index refers to the array + * returned by stencilFormats(). + */ + int getStencilFormatIndexForConfig(GrPixelConfig config) const { + SkASSERT(this->hasStencilFormatBeenDeterminedForConfig(config)); + return fConfigTable[config].fStencilFormatIndex; + } + + /** + * If index is >= 0 this records an index into stencilFormats() as the best stencil format for + * the config. If < 0 it records that the config has no supported stencil format index. + */ + void setStencilFormatIndexForConfig(GrPixelConfig config, int index) { + SkASSERT(!this->hasStencilFormatBeenDeterminedForConfig(config)); + if (index < 0) { + fConfigTable[config].fStencilFormatIndex = ConfigInfo::kUnsupported_StencilFormatIndex; + } else { + fConfigTable[config].fStencilFormatIndex = index; + } + } + /** * Call to note that a color config has been verified as a valid color * attachment. This may save future calls to glCheckFramebufferStatus * using isConfigVerifiedColorAttachment(). */ void markConfigAsValidColorAttachment(GrPixelConfig config) { - fVerifiedColorConfigs.markVerified(config); + fConfigTable[config].fFlags |= ConfigInfo::kVerifiedColorAttachment_Flag; } /** @@ -111,7 +190,7 @@ public: * attachment. */ bool isConfigVerifiedColorAttachment(GrPixelConfig config) const { - return fVerifiedColorConfigs.isVerified(config); + return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kVerifiedColorAttachment_Flag); } /** @@ -143,14 +222,8 @@ public: /// What type of buffer mapping is supported? MapBufferType mapBufferType() const { return fMapBufferType; } - /** - * Gets an array of legal stencil formats. These formats are not guaranteed - * to be supported by the driver but are legal GLenum names given the GL - * version and extensions supported. - */ - const SkTArray& stencilFormats() const { - return fStencilFormats; - } + /// What type of transfer buffer is supported? + TransferBufferType transferBufferType() const { return fTransferBufferType; } /// The maximum number of fragment uniform vectors (GLES has min. 16). int maxFragmentUniformVectors() const { return fMaxFragmentUniformVectors; } @@ -161,15 +234,12 @@ public: /// maximum number of texture units accessible in the fragment shader. int maxFragmentTextureUnits() const { return fMaxFragmentTextureUnits; } - /// ES requires an extension to support RGBA8 in RenderBufferStorage - bool rgba8RenderbufferSupport() const { return fRGBA8RenderbufferSupport; } - /** * Depending on the ES extensions present the BGRA external format may - * correspond either a BGRA or RGBA internalFormat. On desktop GL it is + * correspond to either a BGRA or RGBA internalFormat. On desktop GL it is * RGBA. */ - bool bgraIsInternalFormat() const { return fBGRAIsInternalFormat; } + bool bgraIsInternalFormat() const; /// Is there support for GL_UNPACK_ROW_LENGTH bool unpackRowLengthSupport() const { return fUnpackRowLengthSupport; } @@ -198,9 +268,6 @@ public: /// Is there support for Vertex Array Objects? bool vertexArrayObjectSupport() const { return fVertexArrayObjectSupport; } - /// Is there support for glDraw*Instanced and glVertexAttribDivisor? - bool instancedDrawingSupport() const { return fInstancedDrawingSupport; } - /// Is there support for GL_EXT_direct_state_access? bool directStateAccessSupport() const { return fDirectStateAccessSupport; } @@ -211,20 +278,15 @@ public: bool ES2CompatibilitySupport() const { return fES2CompatibilitySupport; } /// Can we call glDisable(GL_MULTISAMPLE)? - bool multisampleDisableSupport() const { - return fMultisampleDisableSupport; - } + bool multisampleDisableSupport() const { return fMultisampleDisableSupport; } /// Use indices or vertices in CPU arrays rather than VBOs for dynamic content. - bool useNonVBOVertexAndIndexDynamicData() const { - return fUseNonVBOVertexAndIndexDynamicData; - } + bool useNonVBOVertexAndIndexDynamicData() const { return fUseNonVBOVertexAndIndexDynamicData; } /// Does ReadPixels support the provided format/type combo? bool readPixelsSupported(const GrGLInterface* intf, - GrGLenum format, - GrGLenum type, - GrGLenum currFboFormat) const; + GrPixelConfig readConfig, + GrPixelConfig currFBOConfig) const; bool isCoreProfile() const { return fIsCoreProfile; } @@ -235,6 +297,12 @@ public: /// Are textures with GL_TEXTURE_EXTERNAL_OES type supported. bool externalTextureSupport() const { return fExternalTextureSupport; } + /// Are textures with GL_TEXTURE_RECTANGLE type supported. + bool rectangleTextureSupport() const { return fRectangleTextureSupport; } + + /// GL_ARB_texture_swizzle + bool textureSwizzleSupport() const { return fTextureSwizzleSupport; } + /** * Is there support for enabling/disabling sRGB writes for sRGB-capable color attachments? * If false this does not mean sRGB is not supported but rather that if it is supported @@ -247,87 +315,39 @@ public: */ SkString dump() const override; - /** - * LATC can appear under one of three possible names. In order to know - * which GL internal format to use, we need to keep track of which name - * we found LATC under. The default is LATC. - */ - enum LATCAlias { - kLATC_LATCAlias, - kRGTC_LATCAlias, - k3DC_LATCAlias - }; - - LATCAlias latcAlias() const { return fLATCAlias; } - bool rgba8888PixelsOpsAreSlow() const { return fRGBA8888PixelsOpsAreSlow; } bool partialFBOReadIsSlow() const { return fPartialFBOReadIsSlow; } const GrGLSLCaps* glslCaps() const { return reinterpret_cast(fShaderCaps.get()); } private: + enum ExternalFormatUsage { + kTexImage_ExternalFormatUsage, + kOther_ExternalFormatUsage, + + kLast_ExternalFormatUsage = kOther_ExternalFormatUsage + }; + static const int kExternalFormatUsageCnt = kLast_ExternalFormatUsage + 1; + bool getExternalFormat(GrPixelConfig surfaceConfig, GrPixelConfig memoryConfig, + ExternalFormatUsage usage, GrGLenum* externalFormat, + GrGLenum* externalType) const; + void init(const GrContextOptions&, const GrGLContextInfo&, const GrGLInterface*); void initGLSL(const GrGLContextInfo&); bool hasPathRenderingSupport(const GrGLContextInfo&, const GrGLInterface*); void onApplyOptionsOverrides(const GrContextOptions& options) override; - /** - * Maintains a bit per GrPixelConfig. It is used to avoid redundantly - * performing glCheckFrameBufferStatus for the same config. - */ - struct VerifiedColorConfigs { - VerifiedColorConfigs() { - this->reset(); - } - - void reset() { - for (int i = 0; i < kNumUints; ++i) { - fVerifiedColorConfigs[i] = 0; - } - } - - static const int kNumUints = (kGrPixelConfigCnt + 31) / 32; - uint32_t fVerifiedColorConfigs[kNumUints]; - - void markVerified(GrPixelConfig config) { -#if !GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT - return; -#endif - int u32Idx = config / 32; - int bitIdx = config % 32; - fVerifiedColorConfigs[u32Idx] |= 1 << bitIdx; - } - - bool isVerified(GrPixelConfig config) const { -#if !GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT - return false; -#endif - int u32Idx = config / 32; - int bitIdx = config % 32; - return SkToBool(fVerifiedColorConfigs[u32Idx] & (1 << bitIdx)); - } - }; - void initFSAASupport(const GrGLContextInfo&, const GrGLInterface*); void initBlendEqationSupport(const GrGLContextInfo&); void initStencilFormats(const GrGLContextInfo&); // This must be called after initFSAASupport(). - void initConfigRenderableTable(const GrGLContextInfo&, bool srgbSupport); - void initConfigTexturableTable(const GrGLContextInfo&, const GrGLInterface*, bool srgbSupport); - - bool doReadPixelsSupported(const GrGLInterface* intf, GrGLenum format, GrGLenum type) const; + void initConfigTable(const GrGLContextInfo&, const GrGLInterface* gli, GrGLSLCaps* glslCaps); void initShaderPrecisionTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* intf, GrGLSLCaps* glslCaps); - void initConfigSwizzleTable(const GrGLContextInfo& ctxInfo, GrGLSLCaps* glslCaps); - - // tracks configs that have been verified to pass the FBO completeness when - // used as a color attachment - VerifiedColorConfigs fVerifiedColorConfigs; - SkTArray fStencilFormats; int fMaxFragmentUniformVectors; @@ -337,10 +357,8 @@ private: MSFBOType fMSFBOType; InvalidateFBType fInvalidateFBType; MapBufferType fMapBufferType; - LATCAlias fLATCAlias; + TransferBufferType fTransferBufferType; - bool fRGBA8RenderbufferSupport : 1; - bool fBGRAIsInternalFormat : 1; bool fUnpackRowLengthSupport : 1; bool fUnpackFlipYSupport : 1; bool fPackRowLengthSupport : 1; @@ -349,9 +367,7 @@ private: bool fTexStorageSupport : 1; bool fTextureRedSupport : 1; bool fImagingSupport : 1; - bool fTwoFormatLimit : 1; bool fVertexArrayObjectSupport : 1; - bool fInstancedDrawingSupport : 1; bool fDirectStateAccessSupport : 1; bool fDebugSupport : 1; bool fES2CompatibilitySupport : 1; @@ -364,19 +380,78 @@ private: bool fPartialFBOReadIsSlow : 1; bool fBindUniformLocationSupport : 1; bool fExternalTextureSupport : 1; + bool fRectangleTextureSupport : 1; + bool fTextureSwizzleSupport : 1; - struct ReadPixelsSupportedFormat { + /** Number type of the components (with out considering number of bits.) */ + enum FormatType { + kNormalizedFixedPoint_FormatType, + kFloat_FormatType, + }; + + struct ReadPixelsFormat { + ReadPixelsFormat() : fFormat(0), fType(0) {} GrGLenum fFormat; GrGLenum fType; - GrGLenum fFboFormat; - - bool operator==(const ReadPixelsSupportedFormat& rhs) const { - return fFormat == rhs.fFormat - && fType == rhs.fType - && fFboFormat == rhs.fFboFormat; - } }; - mutable SkTHashMap fReadPixelsSupportedCache; + + struct ConfigFormats { + ConfigFormats() { + // Inits to known bad GL enum values. + memset(this, 0xAB, sizeof(ConfigFormats)); + } + GrGLenum fBaseInternalFormat; + GrGLenum fSizedInternalFormat; + + /** The external format and type are to be used when uploading/downloading data using this + config where both the CPU data and GrSurface are the same config. To get the external + format and type when converting between configs while copying to/from memory use + getExternalFormat(). + The kTexImage external format is usually the same as kOther except for kSRGBA on some + GL contexts. */ + GrGLenum fExternalFormat[kExternalFormatUsageCnt]; + GrGLenum fExternalType; + + + // Either the base or sized internal format depending on the GL and config. + GrGLenum fInternalFormatTexImage; + GrGLenum fInternalFormatRenderbuffer; + }; + + struct ConfigInfo { + ConfigInfo() : fStencilFormatIndex(kUnknown_StencilIndex), fFlags(0) {} + + ConfigFormats fFormats; + + FormatType fFormatType; + + // On ES contexts there are restrictions on type type/format that may be used for + // ReadPixels. One is implicitly specified by the current FBO's format. The other is + // queryable. This stores the queried option (lazily). + ReadPixelsFormat fSecondReadPixelsFormat; + + enum { + // This indicates that a stencil format has not yet been determined for the config. + kUnknown_StencilIndex = -1, + // This indicates that there is no supported stencil format for the config. + kUnsupported_StencilFormatIndex = -2 + }; + + // Index fStencilFormats. + int fStencilFormatIndex; + + enum { + kVerifiedColorAttachment_Flag = 0x1, + kTextureable_Flag = 0x2, + kRenderable_Flag = 0x4, + kRenderableWithMSAA_Flag = 0x8, + }; + uint32_t fFlags; + + GrSwizzle fSwizzle; + }; + + ConfigInfo fConfigTable[kGrPixelConfigCnt]; typedef GrCaps INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLDefines.h b/gfx/skia/skia/src/gpu/gl/GrGLDefines.h index dfab5e7e13a..318fcd4d536 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLDefines.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLDefines.h @@ -110,8 +110,14 @@ #define GR_GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GR_GL_ARRAY_BUFFER_BINDING 0x8894 #define GR_GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GR_GL_PIXEL_PACK_BUFFER 0x88EB +#define GR_GL_PIXEL_UNPACK_BUFFER 0x88EC + +#define GR_GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM 0x78EC +#define GR_GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM 0x78ED #define GR_GL_STREAM_DRAW 0x88E0 +#define GR_GL_STREAM_READ 0x88E1 #define GR_GL_STATIC_DRAW 0x88E4 #define GR_GL_DYNAMIC_DRAW 0x88E8 @@ -279,35 +285,35 @@ #define GR_GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define GR_GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F -#define GR_GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 -#define GR_GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 -#define GR_GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 -#define GR_GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 -#define GR_GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 -#define GR_GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 -#define GR_GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 -#define GR_GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 -#define GR_GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 -#define GR_GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 -#define GR_GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA -#define GR_GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB -#define GR_GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC -#define GR_GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define GR_GL_COMPRESSED_RGBA_ASTC_4x4 0x93B0 +#define GR_GL_COMPRESSED_RGBA_ASTC_5x4 0x93B1 +#define GR_GL_COMPRESSED_RGBA_ASTC_5x5 0x93B2 +#define GR_GL_COMPRESSED_RGBA_ASTC_6x5 0x93B3 +#define GR_GL_COMPRESSED_RGBA_ASTC_6x6 0x93B4 +#define GR_GL_COMPRESSED_RGBA_ASTC_8x5 0x93B5 +#define GR_GL_COMPRESSED_RGBA_ASTC_8x6 0x93B6 +#define GR_GL_COMPRESSED_RGBA_ASTC_8x8 0x93B7 +#define GR_GL_COMPRESSED_RGBA_ASTC_10x5 0x93B8 +#define GR_GL_COMPRESSED_RGBA_ASTC_10x6 0x93B9 +#define GR_GL_COMPRESSED_RGBA_ASTC_10x8 0x93BA +#define GR_GL_COMPRESSED_RGBA_ASTC_10x10 0x93BB +#define GR_GL_COMPRESSED_RGBA_ASTC_12x10 0x93BC +#define GR_GL_COMPRESSED_RGBA_ASTC_12x12 0x93BD -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC -#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 0x93D0 +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 0x93D1 +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 0x93D2 +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 0x93D3 +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 0x93D4 +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 0x93D5 +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 0x93D6 +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 0x93D7 +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 0x93D8 +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 0x93D9 +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 0x93DA +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 0x93DB +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 0x93DC +#define GR_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 0x93DD /* HintMode */ #define GR_GL_DONT_CARE 0x1100 @@ -702,7 +708,8 @@ #define GR_GL_T2F_C4F_N3F_V3F 0x2A2C #define GR_GL_T4F_C4F_N3F_V4F 0x2A2D -/* Vertex Buffer Object */ +/* Buffer Object */ +#define GR_GL_READ_ONLY 0x88B8 #define GR_GL_WRITE_ONLY 0x88B9 #define GR_GL_BUFFER_MAPPED 0x88BC @@ -813,6 +820,7 @@ #define GR_GL_STENCIL 0x1802 #define GR_GL_NONE 0 +#define GR_GL_FRAMEBUFFER_DEFAULT 0x8218 #define GR_GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GR_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 @@ -931,6 +939,9 @@ /* GL_OES_EGL_image_external */ #define GR_GL_TEXTURE_EXTERNAL 0x8D65 +/* GL_ARB_texture_rectangle */ +#define GR_GL_TEXTURE_RECTANGLE 0x84F5 + /* EGL Defines */ #define GR_EGL_NO_DISPLAY ((GrEGLDisplay)0) #define GR_EGL_EXTENSIONS 0x3055 diff --git a/gfx/skia/skia/src/gpu/gl/GrGLGpu.cpp b/gfx/skia/skia/src/gpu/gl/GrGLGpu.cpp index c0581377f10..cbba3d8d946 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLGpu.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLGpu.cpp @@ -160,14 +160,6 @@ bool GrGLGpu::BlendCoeffReferencesConstant(GrBlendCoeff coeff) { /////////////////////////////////////////////////////////////////////////////// -// Used in the map of pixel configs to stencil format indices. This value is used to -// indicate that a stencil format has not yet been set for the given config. -static const int kUnknownStencilIndex = -1; -// This value is used as the stencil index when no stencil configs are supported with the -// given pixel config. -static const int kUnsupportedStencilIndex = -2; - -/////////////////////////////////////////////////////////////////////////////// GrGpu* GrGLGpu::Create(GrBackendContext backendContext, const GrContextOptions& options, GrContext* context) { @@ -221,9 +213,6 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) SkASSERT(this->glCaps().maxVertexAttributes() >= GrGeometryProcessor::kMaxVertexAttribs); - for (int i = 0; i < kGrPixelConfigCnt; ++i) { - fPixelConfigToStencilIndex[i] = kUnknownStencilIndex; - } fHWProgramID = 0; fTempSrcFBOID = 0; fTempDstFBOID = 0; @@ -232,11 +221,16 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) if (this->glCaps().shaderCaps()->pathRenderingSupport()) { fPathRendering.reset(new GrGLPathRendering(this)); } - this->createCopyPrograms(); + fWireRectProgram.fProgram = 0; + fWireRectArrayBuffer = 0; } GrGLGpu::~GrGLGpu() { + // Delete the path rendering explicitly, since it will need working gpu object to release the + // resources the object itself holds. + fPathRendering.reset(); + if (0 != fHWProgramID) { // detach the current program so there is no confusion on OpenGL's part // that we want it to be deleted @@ -258,10 +252,19 @@ GrGLGpu::~GrGLGpu() { GL_CALL(DeleteProgram(fCopyPrograms[i].fProgram)); } } + if (0 != fCopyProgramArrayBuffer) { GL_CALL(DeleteBuffers(1, &fCopyProgramArrayBuffer)); } + if (0 != fWireRectProgram.fProgram) { + GL_CALL(DeleteProgram(fWireRectProgram.fProgram)); + } + + if (0 != fWireRectArrayBuffer) { + GL_CALL(DeleteBuffers(1, &fWireRectArrayBuffer)); + } + delete fProgramCache; } @@ -276,6 +279,8 @@ void GrGLGpu::contextAbandoned() { for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) { fCopyPrograms[i].fProgram = 0; } + fWireRectProgram.fProgram = 0; + fWireRectArrayBuffer = 0; if (this->glCaps().shaderCaps()->pathRenderingSupport()) { this->glPathRendering()->abandonGpuResources(); } @@ -413,9 +418,6 @@ static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin, bool renderTarget) GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, GrWrapOwnership ownership) { - if (!this->configToGLFormats(desc.fConfig, false, nullptr, nullptr, nullptr)) { - return nullptr; - } #ifdef SK_IGNORE_GL_TEXTURE_TARGET if (!desc.fTextureHandle) { return nullptr; @@ -445,6 +447,7 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, #else idDesc.fInfo = *info; #endif + if (GR_GL_TEXTURE_EXTERNAL == idDesc.fInfo.fTarget) { if (renderTarget) { // This combination is not supported. @@ -453,8 +456,15 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, if (!this->glCaps().externalTextureSupport()) { return nullptr; } + } else if (GR_GL_TEXTURE_RECTANGLE == idDesc.fInfo.fTarget) { + if (!this->glCaps().rectangleTextureSupport()) { + return nullptr; + } + } else if (GR_GL_TEXTURE_2D != idDesc.fInfo.fTarget) { + return nullptr; } - // Sample count is interpretted to mean the number of samples that Gr code should allocate + + // Sample count is interpreted to mean the number of samples that Gr code should allocate // for a render buffer that resolves to the texture. We don't support MSAA textures. if (desc.fSampleCnt && !renderTarget) { return nullptr; @@ -467,7 +477,7 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc, case kBorrow_GrWrapOwnership: idDesc.fLifeCycle = GrGpuResource::kBorrowed_LifeCycle; break; - } + } surfDesc.fFlags = (GrSurfaceFlags) desc.fFlags; surfDesc.fWidth = desc.fWidth; @@ -544,8 +554,8 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height, ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); } else { GrGLTexture* texture = static_cast(dstSurface->asTexture()); - if (GR_GL_TEXTURE_2D != texture->target()) { - // We don't currently support writing pixels to non-TEXTURE_2D textures. + if (GR_GL_TEXTURE_EXTERNAL == texture->target()) { + // We don't currently support writing pixels to EXTERNAL textures. return false; } } @@ -595,11 +605,8 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height, return true; } -bool GrGLGpu::onWritePixels(GrSurface* surface, - int left, int top, int width, int height, - GrPixelConfig config, const void* buffer, - size_t rowBytes) { - GrGLTexture* glTex = static_cast(surface->asTexture()); +static bool check_write_and_transfer_input(GrGLTexture* glTex, GrSurface* surface, + GrPixelConfig config) { if (!glTex) { return false; } @@ -609,8 +616,21 @@ bool GrGLGpu::onWritePixels(GrSurface* surface, return false; } - // Write pixels is only implemented for TEXTURE_2D textures - if (GR_GL_TEXTURE_2D != glTex->target()) { + // Write or transfer of pixels is not implemented for TEXTURE_EXTERNAL textures + if (GR_GL_TEXTURE_EXTERNAL == glTex->target()) { + return false; + } + + return true; +} + +bool GrGLGpu::onWritePixels(GrSurface* surface, + int left, int top, int width, int height, + GrPixelConfig config, const void* buffer, + size_t rowBytes) { + GrGLTexture* glTex = static_cast(surface->asTexture()); + + if (!check_write_and_transfer_input(glTex, surface, config)) { return false; } @@ -621,11 +641,11 @@ bool GrGLGpu::onWritePixels(GrSurface* surface, if (GrPixelConfigIsCompressed(glTex->desc().fConfig)) { // We check that config == desc.fConfig in GrGLGpu::canWriteTexturePixels() SkASSERT(config == glTex->desc().fConfig); - success = this->uploadCompressedTexData(glTex->desc(), glTex->target(), buffer, false, left, - top, width, height); + success = this->uploadCompressedTexData(glTex->desc(), glTex->target(), buffer, + kWrite_UploadType, left, top, width, height); } else { - success = this->uploadTexData(glTex->desc(), glTex->target(), false, left, top, width, - height, config, buffer, rowBytes); + success = this->uploadTexData(glTex->desc(), glTex->target(), kWrite_UploadType, + left, top, width, height, config, buffer, rowBytes); } if (success) { @@ -636,6 +656,64 @@ bool GrGLGpu::onWritePixels(GrSurface* surface, return false; } +bool GrGLGpu::onTransferPixels(GrSurface* surface, + int left, int top, int width, int height, + GrPixelConfig config, GrTransferBuffer* buffer, + size_t offset, size_t rowBytes) { + GrGLTexture* glTex = static_cast(surface->asTexture()); + + if (!check_write_and_transfer_input(glTex, surface, config)) { + return false; + } + + // For the moment, can't transfer compressed data + if (GrPixelConfigIsCompressed(glTex->desc().fConfig)) { + return false; + } + + this->setScratchTextureUnit(); + GL_CALL(BindTexture(glTex->target(), glTex->textureID())); + + SkASSERT(!buffer->isMapped()); + GrGLTransferBuffer* glBuffer = reinterpret_cast(buffer); + // bind the transfer buffer + SkASSERT(GR_GL_PIXEL_UNPACK_BUFFER == glBuffer->bufferType() || + GR_GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM == glBuffer->bufferType()); + GL_CALL(BindBuffer(glBuffer->bufferType(), glBuffer->bufferID())); + + bool success = false; + success = this->uploadTexData(glTex->desc(), glTex->target(), kTransfer_UploadType, + left, top, width, height, config, buffer, rowBytes); + + if (success) { + glTex->texturePriv().dirtyMipMaps(true); + return true; + } + + return false; +} + +// For GL_[UN]PACK_ALIGNMENT. +static inline GrGLint config_alignment(GrPixelConfig config) { + SkASSERT(!GrPixelConfigIsCompressed(config)); + switch (config) { + case kAlpha_8_GrPixelConfig: + return 1; + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kRGBA_half_GrPixelConfig: + return 2; + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + return 4; + default: + return 0; + } +} + static inline GrGLenum check_alloc_error(const GrSurfaceDesc& desc, const GrGLInterface* interface) { if (SkToBool(desc.fFlags & kCheckAllocation_GrSurfaceFlag)) { @@ -647,19 +725,22 @@ static inline GrGLenum check_alloc_error(const GrSurfaceDesc& desc, bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, GrGLenum target, - bool isNewTexture, + UploadType uploadType, int left, int top, int width, int height, GrPixelConfig dataConfig, - const void* data, + const void* dataOrOffset, size_t rowBytes) { - SkASSERT(data || isNewTexture); + SkASSERT(dataOrOffset || kNewTexture_UploadType == uploadType || + kTransfer_UploadType == uploadType); // If we're uploading compressed data then we should be using uploadCompressedTexData SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); + SkASSERT(this->caps()->isConfigTexturable(desc.fConfig)); + size_t bpp = GrBytesPerPixel(dataConfig); if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bpp, &left, &top, - &width, &height, &data, &rowBytes)) { + &width, &height, &dataOrOffset, &rowBytes)) { return false; } size_t trimRowBytes = width * bpp; @@ -667,43 +748,17 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, // in case we need a temporary, trimmed copy of the src pixels SkAutoMalloc tempStorage; - // We currently lazily create MIPMAPs when the we see a draw with - // GrTextureParams::kMipMap_FilterMode. Using texture storage requires that the - // MIP levels are all created when the texture is created. So for now we don't use - // texture storage. - bool useTexStorage = false && - isNewTexture && - this->glCaps().texStorageSupport(); - - if (useTexStorage && kGL_GrGLStandard == this->glStandard()) { - // 565 is not a sized internal format on desktop GL. So on desktop with - // 565 we always use an unsized internal format to let the system pick - // the best sized format to convert the 565 data to. Since TexStorage - // only allows sized internal formats we will instead use TexImage2D. - useTexStorage = desc.fConfig != kRGB_565_GrPixelConfig; - } - - GrGLenum internalFormat = 0x0; // suppress warning - GrGLenum externalFormat = 0x0; // suppress warning - GrGLenum externalType = 0x0; // suppress warning - - // glTexStorage requires sized internal formats on both desktop and ES. ES2 requires an unsized - // format for glTexImage, unlike ES3 and desktop. - bool useSizedFormat = useTexStorage; - if (kGL_GrGLStandard == this->glStandard() || - (this->glVersion() >= GR_GL_VER(3, 0) && - // ES3 only works with sized BGRA8 format if "GL_APPLE_texture_format_BGRA8888" enabled - (kBGRA_8888_GrPixelConfig != dataConfig || !this->glCaps().bgraIsInternalFormat()))) { - useSizedFormat = true; - } - - if (!this->configToGLFormats(dataConfig, useSizedFormat, &internalFormat, - &externalFormat, &externalType)) { + // Internal format comes from the texture desc. + GrGLenum internalFormat; + // External format and type come from the upload data. + GrGLenum externalFormat; + GrGLenum externalType; + if (!this->glCaps().getTexImageFormats(desc.fConfig, dataConfig, &internalFormat, + &externalFormat, &externalType)) { return false; } - /* - * check whether to allocate a temporary buffer for flipping y or + * Check whether to allocate a temporary buffer for flipping y or * because our srcData has extra bytes past each row. If so, we need * to trim those off here, since GL ES may not let us specify * GL_UNPACK_ROW_LENGTH. @@ -711,7 +766,7 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, bool restoreGLRowLength = false; bool swFlipY = false; bool glFlipY = false; - if (data) { + if (dataOrOffset) { if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { if (this->glCaps().unpackFlipYSupport()) { glFlipY = true; @@ -726,11 +781,11 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength)); restoreGLRowLength = true; } - } else { + } else if (kTransfer_UploadType != uploadType) { if (trimRowBytes != rowBytes || swFlipY) { // copy data into our new storage, skipping the trailing bytes size_t trimSize = height * trimRowBytes; - const char* src = (const char*)data; + const char* src = (const char*)dataOrOffset; if (swFlipY) { src += (height - 1) * rowBytes; } @@ -745,50 +800,29 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, dst += trimRowBytes; } // now point data to our copied version - data = tempStorage.get(); + dataOrOffset = tempStorage.get(); } + } else { + return false; } if (glFlipY) { GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_TRUE)); } - GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, - static_cast(GrUnpackAlignment(dataConfig)))); + GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, config_alignment(dataConfig))); } bool succeeded = true; - if (isNewTexture && - 0 == left && 0 == top && - desc.fWidth == width && desc.fHeight == height) { - CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); - if (useTexStorage) { - // We never resize or change formats of textures. - GL_ALLOC_CALL(this->glInterface(), - TexStorage2D(target, - 1, // levels - internalFormat, - desc.fWidth, desc.fHeight)); - } else { - GL_ALLOC_CALL(this->glInterface(), - TexImage2D(target, - 0, // level - internalFormat, - desc.fWidth, desc.fHeight, - 0, // border - externalFormat, externalType, - data)); - } - GrGLenum error = check_alloc_error(desc, this->glInterface()); - if (error != GR_GL_NO_ERROR) { + if (kNewTexture_UploadType == uploadType) { + if (dataOrOffset && + !(0 == left && 0 == top && desc.fWidth == width && desc.fHeight == height)) { succeeded = false; } else { - // if we have data and we used TexStorage to create the texture, we - // now upload with TexSubImage. - if (data && useTexStorage) { - GL_CALL(TexSubImage2D(target, - 0, // level - left, top, - width, height, - externalFormat, externalType, - data)); + CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); + GL_ALLOC_CALL(this->glInterface(), TexImage2D(target, 0, internalFormat, desc.fWidth, + desc.fHeight, 0, externalFormat, + externalType, dataOrOffset)); + GrGLenum error = check_alloc_error(desc, this->glInterface()); + if (error != GR_GL_NO_ERROR) { + succeeded = false; } } } else { @@ -799,7 +833,7 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, 0, // level left, top, width, height, - externalFormat, externalType, data)); + externalFormat, externalType, dataOrOffset)); } if (restoreGLRowLength) { @@ -820,9 +854,11 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc, GrGLenum target, const void* data, - bool isNewTexture, + UploadType uploadType, int left, int top, int width, int height) { - SkASSERT(data || isNewTexture); + SkASSERT(this->caps()->isConfigTexturable(desc.fConfig)); + SkASSERT(kTransfer_UploadType != uploadType && + (data || kNewTexture_UploadType != uploadType)); // No support for software flip y, yet... SkASSERT(kBottomLeft_GrSurfaceOrigin != desc.fOrigin); @@ -850,12 +886,12 @@ bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc, size_t dataSize = GrCompressedFormatDataSize(desc.fConfig, width, height); // We only need the internal format for compressed 2D textures. - GrGLenum internalFormat = 0; - if (!this->configToGLFormats(desc.fConfig, false, &internalFormat, nullptr, nullptr)) { + GrGLenum internalFormat; + if (!this->glCaps().getCompressedTexImageFormats(desc.fConfig, &internalFormat)) { return false; } - if (isNewTexture) { + if (kNewTexture_UploadType == uploadType) { CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); GL_ALLOC_CALL(this->glInterface(), CompressedTexImage2D(target, @@ -939,7 +975,7 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, GrGLenum status; - GrGLenum msColorFormat = 0; // suppress warning + GrGLenum colorRenderbufferFormat = 0; // suppress warning if (desc.fSampleCnt > 0 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) { goto FAILED; @@ -950,7 +986,6 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, goto FAILED; } - // If we are using multisampling we will create two FBOS. We render to one and then resolve to // the texture bound to the other. The exception is the IMG multisample extension. With this // extension the texture is multisampled when rendered to and then auto-resolves it when it is @@ -959,15 +994,12 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, GL_CALL(GenFramebuffers(1, &idDesc->fRTFBOID)); GL_CALL(GenRenderbuffers(1, &idDesc->fMSColorRenderbufferID)); if (!idDesc->fRTFBOID || - !idDesc->fMSColorRenderbufferID || - !this->configToGLFormats(desc.fConfig, - // ES2 and ES3 require sized internal formats for rb storage. - kGLES_GrGLStandard == this->glStandard(), - &msColorFormat, - nullptr, - nullptr)) { + !idDesc->fMSColorRenderbufferID) { goto FAILED; } + if (!this->glCaps().getRenderbufferFormat(desc.fConfig, &colorRenderbufferFormat)) { + return false; + } } else { idDesc->fRTFBOID = idDesc->fTexFBOID; } @@ -979,7 +1011,7 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID)); if (!renderbuffer_storage_msaa(*fGLContext, desc.fSampleCnt, - msColorFormat, + colorRenderbufferFormat, desc.fWidth, desc.fHeight)) { goto FAILED; } @@ -1060,6 +1092,7 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); GrGLTexture::IDDesc idDesc; + idDesc.fInfo.fID = 0; GL_CALL(GenTextures(1, &idDesc.fInfo.fID)); idDesc.fLifeCycle = lifeCycle; // We only support GL_TEXTURE_2D at the moment. @@ -1101,7 +1134,7 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, GL_CALL(TexParameteri(idDesc.fInfo.fTarget, GR_GL_TEXTURE_WRAP_T, initialTexParams.fWrapT)); - if (!this->uploadTexData(desc, idDesc.fInfo.fTarget, true, 0, 0, + if (!this->uploadTexData(desc, idDesc.fInfo.fTarget, kNewTexture_UploadType, 0, 0, desc.fWidth, desc.fHeight, desc.fConfig, srcData, rowBytes)) { GL_CALL(DeleteTextures(1, &idDesc.fInfo.fID)); @@ -1139,6 +1172,7 @@ GrTexture* GrGLGpu::onCreateCompressedTexture(const GrSurfaceDesc& desc, } GrGLTexture::IDDesc idDesc; + idDesc.fInfo.fID = 0; GL_CALL(GenTextures(1, &idDesc.fInfo.fID)); idDesc.fLifeCycle = lifeCycle; // We only support GL_TEXTURE_2D at the moment. @@ -1217,11 +1251,12 @@ void inline get_stencil_rb_sizes(const GrGLInterface* gl, int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { static const int kSize = 16; - if (kUnknownStencilIndex == fPixelConfigToStencilIndex[config]) { - // Default to unsupported - fPixelConfigToStencilIndex[config] = kUnsupportedStencilIndex; + SkASSERT(this->caps()->isConfigRenderable(config, false)); + if (!this->glCaps().hasStencilFormatBeenDeterminedForConfig(config)) { + // Default to unsupported, set this if we find a stencil format that works. + int firstWorkingStencilFormatIndex = -1; // Create color texture - GrGLuint colorID; + GrGLuint colorID = 0; GL_CALL(GenTextures(1, &colorID)); this->setScratchTextureUnit(); GL_CALL(BindTexture(GR_GL_TEXTURE_2D, colorID)); @@ -1238,43 +1273,33 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE)); - GrGLenum internalFormat = 0x0; // suppress warning - GrGLenum externalFormat = 0x0; // suppress warning - GrGLenum externalType = 0x0; // suppress warning - bool useSizedFormat = false; - if (kGL_GrGLStandard == this->glStandard() || - (this->glVersion() >= GR_GL_VER(3, 0) && - // ES3 only works with sized BGRA8 format if "GL_APPLE_texture_format_BGRA8888" enabled - (kBGRA_8888_GrPixelConfig != config || !this->glCaps().bgraIsInternalFormat()))) { - useSizedFormat = true; + GrGLenum internalFormat; + GrGLenum externalFormat; + GrGLenum externalType; + if (!this->glCaps().getTexImageFormats(config, config, &internalFormat, &externalFormat, + &externalType)) { + return false; } - if (!this->configToGLFormats(config, useSizedFormat, &internalFormat, - &externalFormat, &externalType)) { - GL_CALL(DeleteTextures(1, &colorID)); - fPixelConfigToStencilIndex[config] = kUnsupportedStencilIndex; - return kUnsupportedStencilIndex; - } - CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); GL_ALLOC_CALL(this->glInterface(), TexImage2D(GR_GL_TEXTURE_2D, - 0, internalFormat, + 0, + internalFormat, kSize, kSize, 0, externalFormat, externalType, NULL)); - if (GR_GL_NO_ERROR != GR_GL_GET_ERROR(this->glInterface())) { + if (GR_GL_NO_ERROR != CHECK_ALLOC_ERROR(this->glInterface())) { GL_CALL(DeleteTextures(1, &colorID)); - fPixelConfigToStencilIndex[config] = kUnsupportedStencilIndex; - return kUnsupportedStencilIndex; + return -1; } // unbind the texture from the texture unit before binding it to the frame buffer GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0)); // Create Framebuffer - GrGLuint fb; + GrGLuint fb = 0; GL_CALL(GenFramebuffers(1, &fb)); GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fb)); fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; @@ -1283,38 +1308,38 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { GR_GL_TEXTURE_2D, colorID, 0)); + GrGLuint sbRBID = 0; + GL_CALL(GenRenderbuffers(1, &sbRBID)); // look over formats till I find a compatible one int stencilFmtCnt = this->glCaps().stencilFormats().count(); - GrGLuint sbRBID = 0; - for (int i = 0; i < stencilFmtCnt; ++i) { - const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats()[i]; - - GL_CALL(GenRenderbuffers(1, &sbRBID)); - if (!sbRBID) { - break; - } + if (sbRBID) { GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbRBID)); - CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); - GL_ALLOC_CALL(this->glInterface(), RenderbufferStorage(GR_GL_RENDERBUFFER, - sFmt.fInternalFormat, - kSize, kSize)); - if (GR_GL_NO_ERROR == GR_GL_GET_ERROR(this->glInterface())) { - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_STENCIL_ATTACHMENT, - GR_GL_RENDERBUFFER, sbRBID)); - if (sFmt.fPacked) { + for (int i = 0; i < stencilFmtCnt && sbRBID; ++i) { + const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats()[i]; + CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); + GL_ALLOC_CALL(this->glInterface(), RenderbufferStorage(GR_GL_RENDERBUFFER, + sFmt.fInternalFormat, + kSize, kSize)); + if (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(this->glInterface())) { GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_DEPTH_ATTACHMENT, + GR_GL_STENCIL_ATTACHMENT, GR_GL_RENDERBUFFER, sbRBID)); - } else { - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, - GR_GL_DEPTH_ATTACHMENT, - GR_GL_RENDERBUFFER, 0)); - } - GrGLenum status; - GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); - if (status != GR_GL_FRAMEBUFFER_COMPLETE) { + if (sFmt.fPacked) { + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, + GR_GL_DEPTH_ATTACHMENT, + GR_GL_RENDERBUFFER, sbRBID)); + } else { + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, + GR_GL_DEPTH_ATTACHMENT, + GR_GL_RENDERBUFFER, 0)); + } + GrGLenum status; + GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); + if (status == GR_GL_FRAMEBUFFER_COMPLETE) { + firstWorkingStencilFormatIndex = i; + break; + } GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT, GR_GL_RENDERBUFFER, 0)); @@ -1323,20 +1348,16 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { GR_GL_DEPTH_ATTACHMENT, GR_GL_RENDERBUFFER, 0)); } - } else { - fPixelConfigToStencilIndex[config] = i; - break; } } - sbRBID = 0; + GL_CALL(DeleteRenderbuffers(1, &sbRBID)); } GL_CALL(DeleteTextures(1, &colorID)); - GL_CALL(DeleteRenderbuffers(1, &sbRBID)); GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, 0)); GL_CALL(DeleteFramebuffers(1, &fb)); + fGLContext->caps()->setStencilFormatIndexForConfig(config, firstWorkingStencilFormatIndex); } - SkASSERT(kUnknownStencilIndex != fPixelConfigToStencilIndex[config]); - return fPixelConfigToStencilIndex[config]; + return this->glCaps().getStencilFormatIndexForConfig(config); } GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt, @@ -1352,7 +1373,7 @@ GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRen GrGLStencilAttachment::IDDesc sbDesc; int sIdx = this->getCompatibleStencilIndex(rt->config()); - if (sIdx == kUnsupportedStencilIndex) { + if (sIdx < 0) { return nullptr; } @@ -1394,16 +1415,21 @@ GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRen //////////////////////////////////////////////////////////////////////////////// +// GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a client's vertex buffer +// objects are implemented as client-side-arrays on tile-deferred architectures. +#define DYNAMIC_USAGE_PARAM GR_GL_STREAM_DRAW + GrVertexBuffer* GrGLGpu::onCreateVertexBuffer(size_t size, bool dynamic) { GrGLVertexBuffer::Desc desc; - desc.fDynamic = dynamic; + desc.fUsage = dynamic ? GrGLBufferImpl::kDynamicDraw_Usage : GrGLBufferImpl::kStaticDraw_Usage; desc.fSizeInBytes = size; - if (this->glCaps().useNonVBOVertexAndIndexDynamicData() && desc.fDynamic) { + if (this->glCaps().useNonVBOVertexAndIndexDynamicData() && dynamic) { desc.fID = 0; GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(this, desc); return vertexBuffer; } else { + desc.fID = 0; GL_CALL(GenBuffers(1, &desc.fID)); if (desc.fID) { fHWGeometryState.setVertexBufferID(this, desc.fID); @@ -1413,7 +1439,7 @@ GrVertexBuffer* GrGLGpu::onCreateVertexBuffer(size_t size, bool dynamic) { BufferData(GR_GL_ARRAY_BUFFER, (GrGLsizeiptr) desc.fSizeInBytes, nullptr, // data ptr - desc.fDynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW)); + dynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW)); if (CHECK_ALLOC_ERROR(this->glInterface()) != GR_GL_NO_ERROR) { GL_CALL(DeleteBuffers(1, &desc.fID)); this->notifyVertexBufferDelete(desc.fID); @@ -1428,14 +1454,15 @@ GrVertexBuffer* GrGLGpu::onCreateVertexBuffer(size_t size, bool dynamic) { GrIndexBuffer* GrGLGpu::onCreateIndexBuffer(size_t size, bool dynamic) { GrGLIndexBuffer::Desc desc; - desc.fDynamic = dynamic; + desc.fUsage = dynamic ? GrGLBufferImpl::kDynamicDraw_Usage : GrGLBufferImpl::kStaticDraw_Usage; desc.fSizeInBytes = size; - if (this->glCaps().useNonVBOVertexAndIndexDynamicData() && desc.fDynamic) { + if (this->glCaps().useNonVBOVertexAndIndexDynamicData() && dynamic) { desc.fID = 0; GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(this, desc); return indexBuffer; } else { + desc.fID = 0; GL_CALL(GenBuffers(1, &desc.fID)); if (desc.fID) { fHWGeometryState.setIndexBufferIDOnDefaultVertexArray(this, desc.fID); @@ -1445,7 +1472,7 @@ GrIndexBuffer* GrGLGpu::onCreateIndexBuffer(size_t size, bool dynamic) { BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, (GrGLsizeiptr) desc.fSizeInBytes, nullptr, // data ptr - desc.fDynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW)); + dynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW)); if (CHECK_ALLOC_ERROR(this->glInterface()) != GR_GL_NO_ERROR) { GL_CALL(DeleteBuffers(1, &desc.fID)); this->notifyIndexBufferDelete(desc.fID); @@ -1458,6 +1485,47 @@ GrIndexBuffer* GrGLGpu::onCreateIndexBuffer(size_t size, bool dynamic) { } } +GrTransferBuffer* GrGLGpu::onCreateTransferBuffer(size_t size, TransferType xferType) { + GrGLCaps::TransferBufferType xferBufferType = this->ctxInfo().caps()->transferBufferType(); + if (GrGLCaps::kNone_TransferBufferType == xferBufferType) { + return nullptr; + } + + GrGLTransferBuffer::Desc desc; + bool toGpu = (kCpuToGpu_TransferType == xferType); + desc.fUsage = toGpu ? GrGLBufferImpl::kStreamDraw_Usage : GrGLBufferImpl::kStreamRead_Usage; + + desc.fSizeInBytes = size; + desc.fID = 0; + GL_CALL(GenBuffers(1, &desc.fID)); + if (desc.fID) { + CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); + // make sure driver can allocate memory for this bmapuffer + GrGLenum target; + if (GrGLCaps::kChromium_TransferBufferType == xferBufferType) { + target = toGpu ? GR_GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM + : GR_GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM; + } else { + SkASSERT(GrGLCaps::kPBO_TransferBufferType == xferBufferType); + target = toGpu ? GR_GL_PIXEL_UNPACK_BUFFER : GR_GL_PIXEL_PACK_BUFFER; + } + GL_CALL(BindBuffer(target, desc.fID)); + GL_ALLOC_CALL(this->glInterface(), + BufferData(target, + (GrGLsizeiptr) desc.fSizeInBytes, + nullptr, // data ptr + (toGpu ? GR_GL_STREAM_DRAW : GR_GL_STREAM_READ))); + if (CHECK_ALLOC_ERROR(this->glInterface()) != GR_GL_NO_ERROR) { + GL_CALL(DeleteBuffers(1, &desc.fID)); + return nullptr; + } + GrTransferBuffer* transferBuffer = new GrGLTransferBuffer(this, desc, target); + return transferBuffer; + } + + return nullptr; +} + void GrGLGpu::flushScissor(const GrScissorState& scissorState, const GrGLIRect& rtViewport, GrSurfaceOrigin rtOrigin) { @@ -1491,7 +1559,7 @@ void GrGLGpu::flushScissor(const GrScissorState& scissorState, bool GrGLGpu::flushGLState(const DrawArgs& args) { GrXferProcessor::BlendInfo blendInfo; const GrPipeline& pipeline = *args.fPipeline; - args.fPipeline->getXferProcessor()->getBlendInfo(&blendInfo); + args.fPipeline->getXferProcessor().getBlendInfo(&blendInfo); this->flushColorWrite(blendInfo.fWriteColor); this->flushDrawFace(pipeline.getDrawFace()); @@ -1509,7 +1577,10 @@ bool GrGLGpu::flushGLState(const DrawArgs& args) { } if (blendInfo.fWriteColor) { - this->flushBlend(blendInfo); + // Swizzle the blend to match what the shader will output. + const GrSwizzle& swizzle = this->glCaps().glslCaps()->configOutputSwizzle( + args.fPipeline->getRenderTarget()->config()); + this->flushBlend(blendInfo, swizzle); } SkSTArray<8, const GrTextureAccess*> textureAccesses; @@ -1589,7 +1660,7 @@ void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc, void GrGLGpu::buildProgramDesc(GrProgramDesc* desc, const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline) const { - if (!GrGLProgramDescBuilder::Build(desc, primProc, pipeline, this)) { + if (!GrGLProgramDescBuilder::Build(desc, primProc, pipeline, *this->glCaps().glslCaps())) { SkDEBUGFAIL("Failed to generate GL program descriptor"); } } @@ -1598,9 +1669,10 @@ void GrGLGpu::bindBuffer(GrGLuint id, GrGLenum type) { this->handleDirtyContext(); if (GR_GL_ARRAY_BUFFER == type) { this->bindVertexBuffer(id); - } else { - SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == type); + } else if (GR_GL_ELEMENT_ARRAY_BUFFER == type) { this->bindIndexBufferAndDefaultVertexArray(id); + } else { + GR_GL_CALL(this->glInterface(), BindBuffer(type, id)); } } @@ -1609,19 +1681,29 @@ void GrGLGpu::releaseBuffer(GrGLuint id, GrGLenum type) { GL_CALL(DeleteBuffers(1, &id)); if (GR_GL_ARRAY_BUFFER == type) { this->notifyVertexBufferDelete(id); - } else { - SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == type); + } else if (GR_GL_ELEMENT_ARRAY_BUFFER == type) { this->notifyIndexBufferDelete(id); } } -// GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a client's vertex buffer -// objects are implemented as client-side-arrays on tile-deferred architectures. -#define DYNAMIC_USAGE_PARAM GR_GL_STREAM_DRAW +static GrGLenum get_gl_usage(GrGLBufferImpl::Usage usage) { + static const GrGLenum grToGL[] = { + GR_GL_STATIC_DRAW, // GrGLBufferImpl::kStaticDraw_Usage + DYNAMIC_USAGE_PARAM, // GrGLBufferImpl::kDynamicDraw_Usage + GR_GL_STREAM_DRAW, // GrGLBufferImpl::kStreamDraw_Usage + GR_GL_STREAM_READ, // GrGLBufferImpl::kStreamRead_Usage + }; + static_assert(SK_ARRAY_COUNT(grToGL) == GrGLBufferImpl::kUsageCount, "array_size_mismatch"); -void* GrGLGpu::mapBuffer(GrGLuint id, GrGLenum type, bool dynamic, size_t currentSize, - size_t requestedSize) { + return grToGL[usage]; +} + +void* GrGLGpu::mapBuffer(GrGLuint id, GrGLenum type, GrGLBufferImpl::Usage usage, + size_t currentSize, size_t requestedSize) { void* mapPtr = nullptr; + GrGLenum glUsage = get_gl_usage(usage); + bool readOnly = (GrGLBufferImpl::kStreamRead_Usage == usage); + // Handling dirty context is done in the bindBuffer call switch (this->glCaps().mapBufferType()) { case GrGLCaps::kNone_MapBufferType: @@ -1630,46 +1712,50 @@ void* GrGLGpu::mapBuffer(GrGLuint id, GrGLenum type, bool dynamic, size_t curren this->bindBuffer(id, type); // Let driver know it can discard the old data if (GR_GL_USE_BUFFER_DATA_NULL_HINT || currentSize != requestedSize) { - GL_CALL(BufferData(type, requestedSize, nullptr, - dynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW)); + GL_CALL(BufferData(type, requestedSize, nullptr, glUsage)); } - GL_CALL_RET(mapPtr, MapBuffer(type, GR_GL_WRITE_ONLY)); + GL_CALL_RET(mapPtr, MapBuffer(type, readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY)); break; case GrGLCaps::kMapBufferRange_MapBufferType: { this->bindBuffer(id, type); // Make sure the GL buffer size agrees with fDesc before mapping. if (currentSize != requestedSize) { - GL_CALL(BufferData(type, requestedSize, nullptr, - dynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW)); + GL_CALL(BufferData(type, requestedSize, nullptr, glUsage)); } - static const GrGLbitfield kAccess = GR_GL_MAP_INVALIDATE_BUFFER_BIT | - GR_GL_MAP_WRITE_BIT; - GL_CALL_RET(mapPtr, MapBufferRange(type, 0, requestedSize, kAccess)); + GrGLbitfield writeAccess = GR_GL_MAP_WRITE_BIT; + // TODO: allow the client to specify invalidation in the stream draw case + if (GrGLBufferImpl::kStreamDraw_Usage != usage) { + writeAccess |= GR_GL_MAP_INVALIDATE_BUFFER_BIT; + } + GL_CALL_RET(mapPtr, MapBufferRange(type, 0, requestedSize, readOnly ? + GR_GL_MAP_READ_BIT : + writeAccess)); break; } case GrGLCaps::kChromium_MapBufferType: this->bindBuffer(id, type); // Make sure the GL buffer size agrees with fDesc before mapping. if (currentSize != requestedSize) { - GL_CALL(BufferData(type, requestedSize, nullptr, - dynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW)); + GL_CALL(BufferData(type, requestedSize, nullptr, glUsage)); } - GL_CALL_RET(mapPtr, MapBufferSubData(type, 0, requestedSize, GR_GL_WRITE_ONLY)); + GL_CALL_RET(mapPtr, MapBufferSubData(type, 0, requestedSize, readOnly ? + GR_GL_READ_ONLY : + GR_GL_WRITE_ONLY)); break; } return mapPtr; } -void GrGLGpu::bufferData(GrGLuint id, GrGLenum type, bool dynamic, size_t currentSize, - const void* src, size_t srcSizeInBytes) { +void GrGLGpu::bufferData(GrGLuint id, GrGLenum type, GrGLBufferImpl::Usage usage, + size_t currentSize, const void* src, size_t srcSizeInBytes) { SkASSERT(srcSizeInBytes <= currentSize); // bindbuffer handles dirty context this->bindBuffer(id, type); - GrGLenum usage = dynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW; + GrGLenum glUsage = get_gl_usage(usage); #if GR_GL_USE_BUFFER_DATA_NULL_HINT if (currentSize == srcSizeInBytes) { - GL_CALL(BufferData(type, (GrGLsizeiptr) srcSizeInBytes, src, usage)); + GL_CALL(BufferData(type, (GrGLsizeiptr) srcSizeInBytes, src, glUsage)); } else { // Before we call glBufferSubData we give the driver a hint using // glBufferData with nullptr. This makes the old buffer contents @@ -1678,14 +1764,14 @@ void GrGLGpu::bufferData(GrGLuint id, GrGLenum type, bool dynamic, size_t curren // assign a different allocation for the new contents to avoid // flushing the gpu past draws consuming the old contents. // TODO I think we actually want to try calling bufferData here - GL_CALL(BufferData(type, currentSize, nullptr, usage)); + GL_CALL(BufferData(type, currentSize, nullptr, glUsage)); GL_CALL(BufferSubData(type, 0, (GrGLsizeiptr) srcSizeInBytes, src)); } #else // Note that we're cheating on the size here. Currently no methods // allow a partial update that preserves contents of non-updated // portions of the buffer (map() does a glBufferData(..size, nullptr..)) - GL_CALL(BufferData(type, srcSizeInBytes, src, usage)); + GL_CALL(BufferData(type, srcSizeInBytes, src, glUsage)); #endif } @@ -1909,8 +1995,7 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, tempDrawInfo->fSwapRAndB = true; ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference); } else if (readConfig == kBGRA_8888_GrPixelConfig && - !this->glCaps().readPixelsSupported(this->glInterface(), GR_GL_BGRA, - GR_GL_UNSIGNED_BYTE, srcConfig)) { + !this->glCaps().readPixelsSupported(this->glInterface(), readConfig, srcConfig)) { tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig; tempDrawInfo->fSwapRAndB = true; ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); @@ -1945,18 +2030,13 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, return false; } - GrGLenum format = 0; - GrGLenum type = 0; - bool flipY = kBottomLeft_GrSurfaceOrigin == surface->origin(); - if (!this->configToGLFormats(config, false, nullptr, &format, &type)) { + GrGLenum externalFormat; + GrGLenum externalType; + if (!this->glCaps().getReadPixelsFormat(surface->config(), config, &externalFormat, + &externalType)) { return false; } - - // glReadPixels does not allow GL_SRGB_ALPHA. Instead use GL_RGBA. This will not trigger a - // conversion when the src is srgb. - if (GR_GL_SRGB_ALPHA == format) { - format = GR_GL_RGBA; - } + bool flipY = kBottomLeft_GrSurfaceOrigin == surface->origin(); // resolve the render target if necessary switch (tgt->getResolveType()) { @@ -2004,9 +2084,11 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, if (flipY && this->glCaps().packFlipYSupport()) { GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, 1)); } + GL_CALL(PixelStorei(GR_GL_PACK_ALIGNMENT, config_alignment(config))); + GL_CALL(ReadPixels(readRect.fLeft, readRect.fBottom, readRect.fWidth, readRect.fHeight, - format, type, readDst)); + externalFormat, externalType, readDst)); if (readDstRowBytes != tightRowBytes) { SkASSERT(this->glCaps().packRowLengthSupport()); GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0)); @@ -2323,7 +2405,7 @@ void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA) { } } -void GrGLGpu::flushBlend(const GrXferProcessor::BlendInfo& blendInfo) { +void GrGLGpu::flushBlend(const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle& swizzle) { // Any optimization to disable blending should have already been applied and // tweaked the equation to "add" or "subtract", and the coeffs to (1, 0). @@ -2376,16 +2458,16 @@ void GrGLGpu::flushBlend(const GrXferProcessor::BlendInfo& blendInfo) { fHWBlendState.fDstCoeff = dstCoeff; } - GrColor blendConst = blendInfo.fBlendConstant; - if ((BlendCoeffReferencesConstant(srcCoeff) || - BlendCoeffReferencesConstant(dstCoeff)) && - (!fHWBlendState.fConstColorValid || - fHWBlendState.fConstColor != blendConst)) { - GrGLfloat c[4]; - GrColorToRGBAFloat(blendConst, c); - GL_CALL(BlendColor(c[0], c[1], c[2], c[3])); - fHWBlendState.fConstColor = blendConst; - fHWBlendState.fConstColorValid = true; + if ((BlendCoeffReferencesConstant(srcCoeff) || BlendCoeffReferencesConstant(dstCoeff))) { + GrColor blendConst = blendInfo.fBlendConstant; + blendConst = swizzle.applyTo(blendConst); + if (!fHWBlendState.fConstColorValid || fHWBlendState.fConstColor != blendConst) { + GrGLfloat c[4]; + GrColorToRGBAFloat(blendConst, c); + GL_CALL(BlendColor(c[0], c[1], c[2], c[3])); + fHWBlendState.fConstColor = blendConst; + fHWBlendState.fConstColorValid = true; + } } } @@ -2421,11 +2503,11 @@ static GrGLenum get_component_enum_from_char(char component) { /** If texture swizzling is available using tex parameters then it is preferred over mangling the generated shader code. This potentially allows greater reuse of cached shaders. */ static void get_tex_param_swizzle(GrPixelConfig config, - const GrGLSLCaps& caps, + const GrGLCaps& caps, GrGLenum* glSwizzle) { - const char* swizzle = caps.getSwizzleMap(config); + const GrSwizzle& swizzle = caps.configSwizzle(config); for (int i = 0; i < 4; ++i) { - glSwizzle[i] = get_component_enum_from_char(swizzle[i]); + glSwizzle[i] = get_component_enum_from_char(swizzle.c_str()[i]); } } @@ -2494,7 +2576,7 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTextur newTexParams.fWrapS = tile_to_gl_wrap(params.getTileModeX()); newTexParams.fWrapT = tile_to_gl_wrap(params.getTileModeY()); - get_tex_param_swizzle(texture->config(), *this->glCaps().glslCaps(), newTexParams.fSwizzleRGBA); + get_tex_param_swizzle(texture->config(), this->glCaps(), newTexParams.fSwizzleRGBA); if (setAll || newTexParams.fMagFilter != oldTexParams.fMagFilter) { this->setTextureUnit(unitIdx); GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, newTexParams.fMagFilter)); @@ -2511,7 +2593,7 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTextur this->setTextureUnit(unitIdx); GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_T, newTexParams.fWrapT)); } - if (!this->glCaps().glslCaps()->mustSwizzleInShader() && + if (this->glCaps().textureSwizzleSupport() && (setAll || memcmp(newTexParams.fSwizzleRGBA, oldTexParams.fSwizzleRGBA, sizeof(newTexParams.fSwizzleRGBA)))) { @@ -2568,194 +2650,6 @@ void GrGLGpu::flushDrawFace(GrPipelineBuilder::DrawFace face) { } } -bool GrGLGpu::configToGLFormats(GrPixelConfig config, - bool getSizedInternalFormat, - GrGLenum* internalFormat, - GrGLenum* externalFormat, - GrGLenum* externalType) const { - GrGLenum dontCare; - if (nullptr == internalFormat) { - internalFormat = &dontCare; - } - if (nullptr == externalFormat) { - externalFormat = &dontCare; - } - if (nullptr == externalType) { - externalType = &dontCare; - } - - if(!this->glCaps().isConfigTexturable(config)) { - return false; - } - - switch (config) { - case kRGBA_8888_GrPixelConfig: - *internalFormat = GR_GL_RGBA; - *externalFormat = GR_GL_RGBA; - if (getSizedInternalFormat) { - *internalFormat = GR_GL_RGBA8; - } else { - *internalFormat = GR_GL_RGBA; - } - *externalType = GR_GL_UNSIGNED_BYTE; - break; - case kBGRA_8888_GrPixelConfig: - if (this->glCaps().bgraIsInternalFormat()) { - if (getSizedInternalFormat) { - *internalFormat = GR_GL_BGRA8; - } else { - *internalFormat = GR_GL_BGRA; - } - } else { - if (getSizedInternalFormat) { - *internalFormat = GR_GL_RGBA8; - } else { - *internalFormat = GR_GL_RGBA; - } - } - *externalFormat = GR_GL_BGRA; - *externalType = GR_GL_UNSIGNED_BYTE; - break; - case kSRGBA_8888_GrPixelConfig: - if (getSizedInternalFormat) { - *internalFormat = GR_GL_SRGB8_ALPHA8; - } else { - *internalFormat = GR_GL_SRGB_ALPHA; - } - // OpenGL ES 2.0 + GL_EXT_sRGB allows GL_SRGB_ALPHA to be specified as the - // param to Tex(Sub)Image2D. ES 2.0 requires the internalFormat and format to match. - // Thus, on ES 2.0 we will use GL_SRGB_ALPHA as the externalFormat. However, - // onReadPixels needs code to override that because GL_SRGB_ALPHA is not allowed as a - // glReadPixels format. - // On OpenGL and ES 3.0 GL_SRGB_ALPHA does not work for the param to - // glReadPixels nor does it work with Tex(Sub)Image2D So we always set the externalFormat - // return to GL_RGBA. - if (this->glStandard() == kGLES_GrGLStandard && - this->glVersion() == GR_GL_VER(2,0)) { - *externalFormat = GR_GL_SRGB_ALPHA; - } else { - *externalFormat = GR_GL_RGBA; - } - *externalType = GR_GL_UNSIGNED_BYTE; - break; - case kRGB_565_GrPixelConfig: - *internalFormat = GR_GL_RGB; - *externalFormat = GR_GL_RGB; - if (getSizedInternalFormat) { - if (!this->glCaps().ES2CompatibilitySupport()) { - *internalFormat = GR_GL_RGB5; - } else { - *internalFormat = GR_GL_RGB565; - } - } else { - *internalFormat = GR_GL_RGB; - } - *externalType = GR_GL_UNSIGNED_SHORT_5_6_5; - break; - case kRGBA_4444_GrPixelConfig: - *internalFormat = GR_GL_RGBA; - *externalFormat = GR_GL_RGBA; - if (getSizedInternalFormat) { - *internalFormat = GR_GL_RGBA4; - } else { - *internalFormat = GR_GL_RGBA; - } - *externalType = GR_GL_UNSIGNED_SHORT_4_4_4_4; - break; - case kIndex_8_GrPixelConfig: - // no sized/unsized internal format distinction here - *internalFormat = GR_GL_PALETTE8_RGBA8; - break; - case kAlpha_8_GrPixelConfig: - if (this->glCaps().textureRedSupport()) { - *internalFormat = GR_GL_RED; - *externalFormat = GR_GL_RED; - if (getSizedInternalFormat) { - *internalFormat = GR_GL_R8; - } else { - *internalFormat = GR_GL_RED; - } - *externalType = GR_GL_UNSIGNED_BYTE; - } else { - *internalFormat = GR_GL_ALPHA; - *externalFormat = GR_GL_ALPHA; - if (getSizedInternalFormat) { - *internalFormat = GR_GL_ALPHA8; - } else { - *internalFormat = GR_GL_ALPHA; - } - *externalType = GR_GL_UNSIGNED_BYTE; - } - break; - case kETC1_GrPixelConfig: - *internalFormat = GR_GL_COMPRESSED_ETC1_RGB8; - break; - case kLATC_GrPixelConfig: - switch(this->glCaps().latcAlias()) { - case GrGLCaps::kLATC_LATCAlias: - *internalFormat = GR_GL_COMPRESSED_LUMINANCE_LATC1; - break; - case GrGLCaps::kRGTC_LATCAlias: - *internalFormat = GR_GL_COMPRESSED_RED_RGTC1; - break; - case GrGLCaps::k3DC_LATCAlias: - *internalFormat = GR_GL_COMPRESSED_3DC_X; - break; - } - break; - case kR11_EAC_GrPixelConfig: - *internalFormat = GR_GL_COMPRESSED_R11_EAC; - break; - - case kASTC_12x12_GrPixelConfig: - *internalFormat = GR_GL_COMPRESSED_RGBA_ASTC_12x12_KHR; - break; - - case kRGBA_float_GrPixelConfig: - *internalFormat = GR_GL_RGBA32F; - *externalFormat = GR_GL_RGBA; - *externalType = GR_GL_FLOAT; - break; - - case kAlpha_half_GrPixelConfig: - if (this->glCaps().textureRedSupport()) { - if (getSizedInternalFormat) { - *internalFormat = GR_GL_R16F; - } else { - *internalFormat = GR_GL_RED; - } - *externalFormat = GR_GL_RED; - } else { - if (getSizedInternalFormat) { - *internalFormat = GR_GL_ALPHA16F; - } else { - *internalFormat = GR_GL_ALPHA; - } - *externalFormat = GR_GL_ALPHA; - } - if (kGL_GrGLStandard == this->glStandard() || this->glVersion() >= GR_GL_VER(3, 0)) { - *externalType = GR_GL_HALF_FLOAT; - } else { - *externalType = GR_GL_HALF_FLOAT_OES; - } - break; - - case kRGBA_half_GrPixelConfig: - *internalFormat = GR_GL_RGBA16F; - *externalFormat = GR_GL_RGBA; - if (kGL_GrGLStandard == this->glStandard() || this->glVersion() >= GR_GL_VER(3, 0)) { - *externalType = GR_GL_HALF_FLOAT; - } else { - *externalType = GR_GL_HALF_FLOAT_OES; - } - break; - - default: - return false; - } - return true; -} - void GrGLGpu::setTextureUnit(int unit) { SkASSERT(unit >= 0 && unit < fHWBoundTextureUniqueIDs.count()); if (unit != fHWActiveTextureUnitIdx) { @@ -2957,6 +2851,12 @@ bool GrGLGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { + // None of our copy methods can handle a swizzle. TODO: Make copySurfaceAsDraw handle the + // swizzle. + if (this->glCaps().glslCaps()->configOutputSwizzle(src->config()) != + this->glCaps().glslCaps()->configOutputSwizzle(dst->config())) { + return false; + } if (src->asTexture() && dst->asRenderTarget()) { this->copySurfaceAsDraw(dst, src, srcRect, dstPoint); return true; @@ -2974,16 +2874,23 @@ bool GrGLGpu::onCopySurface(GrSurface* dst, return false; } - void GrGLGpu::createCopyPrograms() { for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) { fCopyPrograms[i].fProgram = 0; } const char* version = this->glCaps().glslCaps()->versionDeclString(); - static const GrSLType kSamplerTypes[2] = { kSampler2D_GrSLType, kSamplerExternal_GrSLType }; - SkASSERT(2 == SK_ARRAY_COUNT(fCopyPrograms)); - int programCount = this->glCaps().externalTextureSupport() ? 2 : 1; - for (int i = 0; i < programCount; ++i) { + static const GrSLType kSamplerTypes[3] = { kSampler2D_GrSLType, kSamplerExternal_GrSLType, + kSampler2DRect_GrSLType }; + SkASSERT(3 == SK_ARRAY_COUNT(fCopyPrograms)); + for (int i = 0; i < 3; ++i) { + if (kSamplerExternal_GrSLType == kSamplerTypes[i] && + !this->glCaps().externalTextureSupport()) { + continue; + } + if (kSampler2DRect_GrSLType == kSamplerTypes[i] && + !this->glCaps().rectangleTextureSupport()) { + continue; + } GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier); GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); @@ -2995,7 +2902,7 @@ void GrGLGpu::createCopyPrograms() { GrShaderVar::kVaryingOut_TypeModifier); GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier); - + SkString vshaderTxt(version); aVertex.appendDecl(this->glCaps().glslCaps(), &vshaderTxt); vshaderTxt.append(";"); @@ -3042,7 +2949,7 @@ void GrGLGpu::createCopyPrograms() { " %s = %s(u_texture, v_texCoord);" "}", fsOutName, - GrGLSLTexture2DFunctionName(kVec2f_GrSLType, this->glslGeneration()) + GrGLSLTexture2DFunctionName(kVec2f_GrSLType, kSamplerTypes[i], this->glslGeneration()) ); GL_CALL_RET(fCopyPrograms[i].fProgram, CreateProgram()); @@ -3075,7 +2982,7 @@ void GrGLGpu::createCopyPrograms() { GL_CALL(DeleteShader(vshader)); GL_CALL(DeleteShader(fshader)); } - + fCopyProgramArrayBuffer = 0; GL_CALL(GenBuffers(1, &fCopyProgramArrayBuffer)); fHWGeometryState.setVertexBufferID(this, fCopyProgramArrayBuffer); static const GrGLfloat vdata[] = { @@ -3091,6 +2998,163 @@ void GrGLGpu::createCopyPrograms() { GR_GL_STATIC_DRAW)); } +void GrGLGpu::createWireRectProgram() { + SkASSERT(!fWireRectProgram.fProgram); + GrGLSLShaderVar uColor("u_color", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); + GrGLSLShaderVar uRect("u_rect", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); + GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier); + const char* version = this->glCaps().glslCaps()->versionDeclString(); + + // The rect uniform specifies the rectangle in NDC space as a vec4 (left,top,right,bottom). The + // program is used with a vbo containing the unit square. Vertices are computed from the rect + // uniform using the 4 vbo vertices. + SkString vshaderTxt(version); + aVertex.appendDecl(this->glCaps().glslCaps(), &vshaderTxt); + vshaderTxt.append(";"); + uRect.appendDecl(this->glCaps().glslCaps(), &vshaderTxt); + vshaderTxt.append(";"); + vshaderTxt.append( + "// Wire Rect Program VS\n" + "void main() {" + " gl_Position.x = u_rect.x + a_vertex.x * (u_rect.z - u_rect.x);" + " gl_Position.y = u_rect.y + a_vertex.y * (u_rect.w - u_rect.y);" + " gl_Position.zw = vec2(0, 1);" + "}" + ); + + GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier); + + SkString fshaderTxt(version); + GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, + *this->glCaps().glslCaps(), + &fshaderTxt); + uColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt); + fshaderTxt.append(";"); + const char* fsOutName; + if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) { + oFragColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt); + fshaderTxt.append(";"); + fsOutName = oFragColor.c_str(); + } else { + fsOutName = "gl_FragColor"; + } + fshaderTxt.appendf( + "// Write Rect Program FS\n" + "void main() {" + " %s = %s;" + "}", + fsOutName, + uColor.c_str() + ); + + GL_CALL_RET(fWireRectProgram.fProgram, CreateProgram()); + const char* str; + GrGLint length; + + str = vshaderTxt.c_str(); + length = SkToInt(vshaderTxt.size()); + GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fWireRectProgram.fProgram, + GR_GL_VERTEX_SHADER, &str, &length, 1, + &fStats); + + str = fshaderTxt.c_str(); + length = SkToInt(fshaderTxt.size()); + GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fWireRectProgram.fProgram, + GR_GL_FRAGMENT_SHADER, &str, &length, 1, + &fStats); + + GL_CALL(LinkProgram(fWireRectProgram.fProgram)); + + GL_CALL_RET(fWireRectProgram.fColorUniform, + GetUniformLocation(fWireRectProgram.fProgram, "u_color")); + GL_CALL_RET(fWireRectProgram.fRectUniform, + GetUniformLocation(fWireRectProgram.fProgram, "u_rect")); + GL_CALL(BindAttribLocation(fWireRectProgram.fProgram, 0, "a_vertex")); + + GL_CALL(DeleteShader(vshader)); + GL_CALL(DeleteShader(fshader)); + GL_CALL(GenBuffers(1, &fWireRectArrayBuffer)); + fHWGeometryState.setVertexBufferID(this, fWireRectArrayBuffer); + static const GrGLfloat vdata[] = { + 0, 0, + 0, 1, + 1, 1, + 1, 0, + }; + GL_ALLOC_CALL(this->glInterface(), + BufferData(GR_GL_ARRAY_BUFFER, + (GrGLsizeiptr) sizeof(vdata), + vdata, // data ptr + GR_GL_STATIC_DRAW)); +} + +void GrGLGpu::drawDebugWireRect(GrRenderTarget* rt, const SkIRect& rect, GrColor color) { + // TODO: This should swizzle the output to match dst's config, though it is a debugging + // visualization. + + this->handleDirtyContext(); + if (!fWireRectProgram.fProgram) { + this->createWireRectProgram(); + } + + int w = rt->width(); + int h = rt->height(); + + // Compute the edges of the rectangle (top,left,right,bottom) in NDC space. Must consider + // whether the render target is flipped or not. + GrGLfloat edges[4]; + edges[0] = SkIntToScalar(rect.fLeft) + 0.5f; + edges[2] = SkIntToScalar(rect.fRight) - 0.5f; + if (kBottomLeft_GrSurfaceOrigin == rt->origin()) { + edges[1] = h - (SkIntToScalar(rect.fTop) + 0.5f); + edges[3] = h - (SkIntToScalar(rect.fBottom) - 0.5f); + } else { + edges[1] = SkIntToScalar(rect.fTop) + 0.5f; + edges[3] = SkIntToScalar(rect.fBottom) - 0.5f; + } + edges[0] = 2 * edges[0] / w - 1.0f; + edges[1] = 2 * edges[1] / h - 1.0f; + edges[2] = 2 * edges[2] / w - 1.0f; + edges[3] = 2 * edges[3] / h - 1.0f; + + GrGLfloat channels[4]; + static const GrGLfloat scale255 = 1.f / 255.f; + channels[0] = GrColorUnpackR(color) * scale255; + channels[1] = GrColorUnpackG(color) * scale255; + channels[2] = GrColorUnpackB(color) * scale255; + channels[3] = GrColorUnpackA(color) * scale255; + + GrGLRenderTarget* glRT = static_cast(rt->asRenderTarget()); + this->flushRenderTarget(glRT, &rect); + + GL_CALL(UseProgram(fWireRectProgram.fProgram)); + fHWProgramID = fWireRectProgram.fProgram; + + fHWGeometryState.setVertexArrayID(this, 0); + + GrGLAttribArrayState* attribs = + fHWGeometryState.bindArrayAndBufferToDraw(this, fWireRectArrayBuffer); + attribs->set(this, 0, fWireRectArrayBuffer, 2, GR_GL_FLOAT, false, 2 * sizeof(GrGLfloat), 0); + attribs->disableUnusedArrays(this, 0x1); + + GL_CALL(Uniform4fv(fWireRectProgram.fRectUniform, 1, edges)); + GL_CALL(Uniform4fv(fWireRectProgram.fColorUniform, 1, channels)); + + GrXferProcessor::BlendInfo blendInfo; + blendInfo.reset(); + this->flushBlend(blendInfo, GrSwizzle::RGBA()); + this->flushColorWrite(true); + this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace); + this->flushHWAAState(glRT, false); + this->disableScissor(); + GrStencilSettings stencil; + stencil.setDisabled(); + this->flushStencil(stencil); + + GL_CALL(DrawArrays(GR_GL_LINE_LOOP, 0, 4)); +} + + void GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, @@ -3115,8 +3179,7 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrGLAttribArrayState* attribs = fHWGeometryState.bindArrayAndBufferToDraw(this, fCopyProgramArrayBuffer); - attribs->set(this, 0, fCopyProgramArrayBuffer, 2, GR_GL_FLOAT, false, - 2 * sizeof(GrGLfloat), 0); + attribs->set(this, 0, fCopyProgramArrayBuffer, 2, GR_GL_FLOAT, false, 2 * sizeof(GrGLfloat), 0); attribs->disableUnusedArrays(this, 0x1); // dst rect edges in NDC (-1 to 1) @@ -3131,16 +3194,23 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst, dy1 = -dy1; } - // src rect edges in normalized texture space (0 to 1) - int sw = src->width(); + GrGLfloat sx0 = (GrGLfloat)srcRect.fLeft; + GrGLfloat sx1 = (GrGLfloat)(srcRect.fLeft + w); + GrGLfloat sy0 = (GrGLfloat)srcRect.fTop; + GrGLfloat sy1 = (GrGLfloat)(srcRect.fTop + h); int sh = src->height(); - GrGLfloat sx0 = (GrGLfloat)srcRect.fLeft / sw; - GrGLfloat sx1 = (GrGLfloat)(srcRect.fLeft + w) / sw; - GrGLfloat sy0 = (GrGLfloat)srcRect.fTop / sh; - GrGLfloat sy1 = (GrGLfloat)(srcRect.fTop + h) / sh; if (kBottomLeft_GrSurfaceOrigin == src->origin()) { - sy0 = 1.f - sy0; - sy1 = 1.f - sy1; + sy0 = sh - sy0; + sy1 = sh - sy1; + } + // src rect edges in normalized texture space (0 to 1) unless we're using a RECTANGLE texture. + GrGLenum srcTarget = srcTex->target(); + if (GR_GL_TEXTURE_RECTANGLE != srcTarget) { + int sw = src->width(); + sx0 /= sw; + sx1 /= sw; + sy0 /= sh; + sy1 /= sh; } GL_CALL(Uniform4f(fCopyPrograms[progIdx].fPosXformUniform, dx1 - dx0, dy1 - dy0, dx0, dy0)); @@ -3150,7 +3220,7 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrXferProcessor::BlendInfo blendInfo; blendInfo.reset(); - this->flushBlend(blendInfo); + this->flushBlend(blendInfo, GrSwizzle::RGBA()); this->flushColorWrite(true); this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace); this->flushHWAAState(dstRT, false); @@ -3283,8 +3353,12 @@ void GrGLGpu::xferBarrier(GrRenderTarget* rt, GrXferBarrierType type) { GrBackendObject GrGLGpu::createTestingOnlyBackendTexture(void* pixels, int w, int h, GrPixelConfig config) const { + if (!this->caps()->isConfigTexturable(config)) { + return false; + } GrGLTextureInfo* info = new GrGLTextureInfo; info->fTarget = GR_GL_TEXTURE_2D; + info->fID = 0; GL_CALL(GenTextures(1, &info->fID)); GL_CALL(ActiveTexture(GR_GL_TEXTURE0)); GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1)); @@ -3294,11 +3368,19 @@ GrBackendObject GrGLGpu::createTestingOnlyBackendTexture(void* pixels, int w, in GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE)); GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE)); - GrGLenum internalFormat = 0x0; // suppress warning - GrGLenum externalFormat = 0x0; // suppress warning - GrGLenum externalType = 0x0; // suppress warning + GrGLenum internalFormat; + GrGLenum externalFormat; + GrGLenum externalType; - this->configToGLFormats(config, false, &internalFormat, &externalFormat, &externalType); + if (!this->glCaps().getTexImageFormats(config, config, &internalFormat, &externalFormat, + &externalType)) { + delete info; +#ifdef SK_IGNORE_GL_TEXTURE_TARGET + return 0; +#else + return reinterpret_cast(nullptr); +#endif + } GL_CALL(TexImage2D(info->fTarget, 0, internalFormat, w, h, 0, externalFormat, externalType, pixels)); diff --git a/gfx/skia/skia/src/gpu/gl/GrGLGpu.h b/gfx/skia/skia/src/gpu/gl/GrGLGpu.h index 2d05396f87c..b2eec458358 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLGpu.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLGpu.h @@ -16,6 +16,7 @@ #include "GrGLRenderTarget.h" #include "GrGLStencilAttachment.h" #include "GrGLTexture.h" +#include "GrGLTransferBuffer.h" #include "GrGLVertexArray.h" #include "GrGLVertexBuffer.h" #include "GrGpu.h" @@ -25,6 +26,7 @@ class GrPipeline; class GrNonInstancedVertices; +class GrSwizzle; #ifdef SK_DEVELOPER #define PROGRAM_CACHE_STATS @@ -101,12 +103,12 @@ public: void releaseBuffer(GrGLuint id, GrGLenum type); // sizes are in bytes - void* mapBuffer(GrGLuint id, GrGLenum type, bool dynamic, size_t currentSize, + void* mapBuffer(GrGLuint id, GrGLenum type, GrGLBufferImpl::Usage usage, size_t currentSize, size_t requestedSize); void unmapBuffer(GrGLuint id, GrGLenum type, void* mapPtr); - void bufferData(GrGLuint id, GrGLenum type, bool dynamic, size_t currentSize, + void bufferData(GrGLuint id, GrGLenum type, GrGLBufferImpl::Usage usage, size_t currentSize, const void* src, size_t srcSizeInBytes); const GrGLContext* glContextForTesting() const override { @@ -130,6 +132,8 @@ public: void resetShaderCacheForTesting() const override; + void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override; + private: GrGLGpu(GrGLContext* ctx, GrContext* context); @@ -145,11 +149,12 @@ private: const void* srcData) override; GrVertexBuffer* onCreateVertexBuffer(size_t size, bool dynamic) override; GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) override; + GrTransferBuffer* onCreateTransferBuffer(size_t size, TransferType type) override; GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) override; GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&, GrWrapOwnership) override; // Given a GrPixelConfig return the index into the stencil format array on GrGLCaps to a - // compatible stencil format. + // compatible stencil format, or negative if there is no compatible stencil format. int getCompatibleStencilIndex(GrPixelConfig config); void onClear(GrRenderTarget*, const SkIRect& rect, GrColor color) override; @@ -168,6 +173,11 @@ private: GrPixelConfig config, const void* buffer, size_t rowBytes) override; + bool onTransferPixels(GrSurface*, + int left, int top, int width, int height, + GrPixelConfig config, GrTransferBuffer* buffer, + size_t offset, size_t rowBytes) override; + void onResolveRenderTarget(GrRenderTarget* target) override; void onDraw(const DrawArgs&, const GrNonInstancedVertices&) override; @@ -190,8 +200,7 @@ private: const GrNonInstancedVertices& vertices, size_t* indexOffsetInBytes); - // Subclasses should call this to flush the blend state. - void flushBlend(const GrXferProcessor::BlendInfo& blendInfo); + void flushBlend(const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle&); bool hasExtension(const char* ext) const { return fGLContext->hasExtension(ext); } @@ -279,15 +288,15 @@ private: void flushStencil(const GrStencilSettings&); void flushHWAAState(GrRenderTarget* rt, bool useHWAA); - bool configToGLFormats(GrPixelConfig config, - bool getSizedInternal, - GrGLenum* internalFormat, - GrGLenum* externalFormat, - GrGLenum* externalType) const; // helper for onCreateTexture and writeTexturePixels + enum UploadType { + kNewTexture_UploadType, // we are creating a new texture + kWrite_UploadType, // we are using TexSubImage2D to copy data to an existing texture + kTransfer_UploadType, // we are using a transfer buffer to copy data + }; bool uploadTexData(const GrSurfaceDesc& desc, GrGLenum target, - bool isNewTexture, + UploadType uploadType, int left, int top, int width, int height, GrPixelConfig dataConfig, const void* data, @@ -302,7 +311,7 @@ private: bool uploadCompressedTexData(const GrSurfaceDesc& desc, GrGLenum target, const void* data, - bool isNewTexture = true, + UploadType uploadType = kNewTexture_UploadType, int left = 0, int top = 0, int width = -1, int height = -1); @@ -326,6 +335,8 @@ private: SkAutoTUnref fGLContext; void createCopyPrograms(); + void createWireRectProgram(); + void createUnitRectBuffer(); // GL program-related state ProgramCache* fProgramCache; @@ -494,24 +505,6 @@ private: } } fHWBlendState; - /** IDs for copy surface program. */ - struct { - GrGLuint fProgram; - GrGLint fTextureUniform; - GrGLint fTexCoordXformUniform; - GrGLint fPosXformUniform; - } fCopyPrograms[2]; - GrGLuint fCopyProgramArrayBuffer; - - static int TextureTargetToCopyProgramIdx(GrGLenum target) { - if (target == GR_GL_TEXTURE_2D) { - return 0; - } else { - SkASSERT(target == GR_GL_TEXTURE_EXTERNAL); - return 1; - } - } - TriState fMSAAEnabled; GrStencilSettings fHWStencilSettings; @@ -523,12 +516,37 @@ private: uint32_t fHWBoundRenderTargetUniqueID; TriState fHWSRGBFramebuffer; SkTArray fHWBoundTextureUniqueIDs; - ///@} - // Mapping of pixel configs to known supported stencil formats to be used - // when adding a stencil buffer to a framebuffer. - int fPixelConfigToStencilIndex[kGrPixelConfigCnt]; + /** IDs for copy surface program. */ + struct { + GrGLuint fProgram; + GrGLint fTextureUniform; + GrGLint fTexCoordXformUniform; + GrGLint fPosXformUniform; + } fCopyPrograms[3]; + GrGLuint fCopyProgramArrayBuffer; + + struct { + GrGLuint fProgram; + GrGLint fColorUniform; + GrGLint fRectUniform; + } fWireRectProgram; + GrGLuint fWireRectArrayBuffer; + + static int TextureTargetToCopyProgramIdx(GrGLenum target) { + switch (target) { + case GR_GL_TEXTURE_2D: + return 0; + case GR_GL_TEXTURE_EXTERNAL: + return 1; + case GR_GL_TEXTURE_RECTANGLE: + return 2; + default: + SkFAIL("Unexpected texture target type."); + return 0; + } + } typedef GrGpu INHERITED; friend class GrGLPathRendering; // For accessing setTextureUnit. diff --git a/gfx/skia/skia/src/gpu/gl/GrGLIndexBuffer.cpp b/gfx/skia/skia/src/gpu/gl/GrGLIndexBuffer.cpp index 230d9a46933..5a794ad8240 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLIndexBuffer.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLIndexBuffer.cpp @@ -10,7 +10,8 @@ #include "SkTraceMemoryDump.h" GrGLIndexBuffer::GrGLIndexBuffer(GrGLGpu* gpu, const Desc& desc) - : INHERITED(gpu, desc.fSizeInBytes, desc.fDynamic, 0 == desc.fID) + : INHERITED(gpu, desc.fSizeInBytes, GrGLBufferImpl::kDynamicDraw_Usage == desc.fUsage, + 0 == desc.fID) , fImpl(gpu, desc, GR_GL_ELEMENT_ARRAY_BUFFER) { this->registerWithCache(); } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLInterface.cpp b/gfx/skia/skia/src/gpu/gl/GrGLInterface.cpp index da3c656c18c..b8d7db6b2e5 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLInterface.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLInterface.cpp @@ -39,6 +39,9 @@ const GrGLInterface* GrGLInterfaceRemoveNVPR(const GrGLInterface* interface) { GrGLInterface* newInterface = GrGLInterface::NewClone(interface); newInterface->fExtensions.remove("GL_NV_path_rendering"); + newInterface->fExtensions.remove("GL_CHROMIUM_path_rendering"); + newInterface->fFunctions.fMatrixLoadf = nullptr; + newInterface->fFunctions.fMatrixLoadIdentity = nullptr; newInterface->fFunctions.fPathCommands = nullptr; newInterface->fFunctions.fPathParameteri = nullptr; newInterface->fFunctions.fPathParameterf = nullptr; @@ -538,7 +541,8 @@ bool GrGLInterface::validate() const { } } - if (fExtensions.has("GL_NV_framebuffer_mixed_samples")) { + if (fExtensions.has("GL_NV_framebuffer_mixed_samples") || + fExtensions.has("GL_CHROMIUM_framebuffer_mixed_samples")) { if (nullptr == fFunctions.fCoverageModulation) { RETURN_FALSE_INTERFACE } diff --git a/gfx/skia/skia/src/gpu/gl/GrGLNameAllocator.cpp b/gfx/skia/skia/src/gpu/gl/GrGLNameAllocator.cpp deleted file mode 100644 index 03123a6d86e..00000000000 --- a/gfx/skia/skia/src/gpu/gl/GrGLNameAllocator.cpp +++ /dev/null @@ -1,370 +0,0 @@ - -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrGLNameAllocator.h" - -/** - * This is the abstract base class for a nonempty AVL tree that tracks allocated - * names within the half-open range [fFirst, fEnd). The inner nodes can be - * sparse (meaning not every name within the range is necessarily allocated), - * but the bounds are tight, so fFirst *is* guaranteed to be allocated, and so - * is fEnd - 1. - */ -class GrGLNameAllocator::SparseNameRange : public SkRefCnt { -public: - virtual ~SparseNameRange() {} - - /** - * Return the beginning of the range. first() is guaranteed to be allocated. - * - * @return The first name in the range. - */ - GrGLuint first() const { return fFirst; } - - /** - * Return the end of the range. end() - 1 is guaranteed to be allocated. - * - * @return One plus the final name in the range. - */ - GrGLuint end() const { return fEnd; } - - /** - * Return the height of the tree. This can only be nonzero at an inner node. - * - * @return 0 if the implementation is a leaf node, - * The nonzero height of the tree otherwise. - */ - GrGLuint height() const { return fHeight; } - - /** - * Allocate a name from strictly inside this range. The call will fail if - * there is not a free name within. - * - * @param outName A pointer that receives the allocated name. outName will - * be set to zero if there were no free names within the - * range [fFirst, fEnd). - * @return The resulting SparseNameRange after the allocation. Note that - * this call is destructive, so the original SparseNameRange will no - * longer be valid afterward. The caller must always update its - * pointer with the new SparseNameRange. - */ - virtual SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* outName) = 0; - - /** - * Remove the leftmost leaf node from this range (or the entire thing if it - * *is* a leaf node). This is an internal helper method that is used after - * an allocation if one contiguous range became adjacent to another. (The - * range gets removed so the one immediately before can be extended, - * collapsing the two into one.) - * - * @param removedCount A pointer that receives the size of the contiguous - range that was removed. - * @return The resulting SparseNameRange after the removal (or nullptr if it - * became empty). Note that this call is destructive, so the - * original SparseNameRange will no longer be valid afterward. The - * caller must always update its pointer with the new - * SparseNameRange. - */ - virtual SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange(GrGLuint* removedCount) = 0; - - /** - * Append adjacent allocated names to the end of this range. This operation - * does not affect the structure of the tree. The caller is responsible for - * ensuring the new names won't overlap sibling ranges, if any. - * - * @param count The number of adjacent names to append. - * @return The first name appended. - */ - virtual GrGLuint appendNames(GrGLuint count) = 0; - - /** - * Prepend adjacent allocated names behind the beginning of this range. This - * operation does not affect the structure of the tree. The caller is - * responsible for ensuring the new names won't overlap sibling ranges, if - * any. - * - * @param count The number of adjacent names to prepend. - * @return The final name prepended (the one with the lowest value). - */ - virtual GrGLuint prependNames(GrGLuint count) = 0; - - /** - * Free a name so it is no longer tracked as allocated. If the name is at - * the very beginning or very end of the range, the boundaries [fFirst, fEnd) - * will be tightened. - * - * @param name The name to free. Not-allocated names are silently ignored - * the same way they are in the OpenGL spec. - * @return The resulting SparseNameRange after the free (or nullptr if it - * became empty). Note that this call is destructive, so the - * original SparseNameRange will no longer be valid afterward. The - * caller must always update its pointer with the new - * SparseNameRange. - */ - virtual SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) = 0; - -protected: - SparseNameRange* takeRef() { - this->ref(); - return this; - } - - GrGLuint fFirst; - GrGLuint fEnd; - GrGLuint fHeight; -}; - -/** - * This class is the SparseNameRange implementation for an inner node. It is an - * AVL tree with non-null, non-adjacent left and right children. - */ -class GrGLNameAllocator::SparseNameTree : public SparseNameRange { -public: - SparseNameTree(SparseNameRange* left, SparseNameRange* right) - : fLeft(left), - fRight(right) { - SkASSERT(fLeft.get()); - SkASSERT(fRight.get()); - this->updateStats(); - } - - SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* outName) override { - // Try allocating the range inside fLeft's internal gaps. - fLeft.reset(fLeft->internalAllocate(outName)); - if (0 != *outName) { - this->updateStats(); - return this->rebalance(); - } - - if (fLeft->end() + 1 == fRight->first()) { - // It closed the gap between fLeft and fRight; merge. - GrGLuint removedCount; - fRight.reset(fRight->removeLeftmostContiguousRange(&removedCount)); - *outName = fLeft->appendNames(1 + removedCount); - if (nullptr == fRight.get()) { - return fLeft.detach(); - } - this->updateStats(); - return this->rebalance(); - } - - // There is guaranteed to be a gap between fLeft and fRight, and the - // "size 1" case has already been covered. - SkASSERT(fLeft->end() + 1 < fRight->first()); - *outName = fLeft->appendNames(1); - return this->takeRef(); - } - - SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange(GrGLuint* removedCount) override { - fLeft.reset(fLeft->removeLeftmostContiguousRange(removedCount)); - if (nullptr == fLeft) { - return fRight.detach(); - } - this->updateStats(); - return this->rebalance(); - } - - GrGLuint appendNames(GrGLuint count) override { - SkASSERT(fEnd + count > fEnd); // Check for integer wrap. - GrGLuint name = fRight->appendNames(count); - SkASSERT(fRight->end() == fEnd + count); - this->updateStats(); - return name; - } - - GrGLuint prependNames(GrGLuint count) override { - SkASSERT(fFirst > count); // We can't allocate at or below 0. - GrGLuint name = fLeft->prependNames(count); - SkASSERT(fLeft->first() == fFirst - count); - this->updateStats(); - return name; - } - - SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) override { - if (name < fLeft->end()) { - fLeft.reset(fLeft->free(name)); - if (nullptr == fLeft) { - // fLeft became empty after the free. - return fRight.detach(); - } - this->updateStats(); - return this->rebalance(); - } else { - fRight.reset(fRight->free(name)); - if (nullptr == fRight) { - // fRight became empty after the free. - return fLeft.detach(); - } - this->updateStats(); - return this->rebalance(); - } - } - -private: - typedef SkAutoTUnref SparseNameTree::* ChildRange; - - SparseNameRange* SK_WARN_UNUSED_RESULT rebalance() { - if (fLeft->height() > fRight->height() + 1) { - return this->rebalanceImpl<&SparseNameTree::fLeft, &SparseNameTree::fRight>(); - } - if (fRight->height() > fLeft->height() + 1) { - return this->rebalanceImpl<&SparseNameTree::fRight, &SparseNameTree::fLeft>(); - } - return this->takeRef(); - } - - /** - * Rebalance the tree using rotations, as described in the AVL algorithm: - * http://en.wikipedia.org/wiki/AVL_tree#Insertion - */ - template - SparseNameRange* SK_WARN_UNUSED_RESULT rebalanceImpl() { - // We should be calling rebalance() enough that the tree never gets more - // than one rotation off balance. - SkASSERT(2 == (this->*Tall)->height() - (this->*Short)->height()); - - // Ensure we are in the 'Left Left' or 'Right Right' case: - // http://en.wikipedia.org/wiki/AVL_tree#Insertion - SparseNameTree* tallChild = static_cast((this->*Tall).get()); - if ((tallChild->*Tall)->height() < (tallChild->*Short)->height()) { - (this->*Tall).reset(tallChild->rotate()); - } - - // Perform a rotation to balance the tree. - return this->rotate(); - } - - /** - * Perform a node rotation, as described in the AVL algorithm: - * http://en.wikipedia.org/wiki/AVL_tree#Insertion - */ - template - SparseNameRange* SK_WARN_UNUSED_RESULT rotate() { - SparseNameTree* newRoot = static_cast((this->*Tall).detach()); - - (this->*Tall).reset((newRoot->*Short).detach()); - this->updateStats(); - - (newRoot->*Short).reset(this->takeRef()); - newRoot->updateStats(); - - return newRoot; - } - - void updateStats() { - SkASSERT(fLeft->end() < fRight->first()); // There must be a gap between left and right. - fFirst = fLeft->first(); - fEnd = fRight->end(); - fHeight = 1 + SkMax32(fLeft->height(), fRight->height()); - } - - SkAutoTUnref fLeft; - SkAutoTUnref fRight; -}; - -/** - * This class is the SparseNameRange implementation for a leaf node. It just a - * contiguous range of allocated names. - */ -class GrGLNameAllocator::ContiguousNameRange : public SparseNameRange { -public: - ContiguousNameRange(GrGLuint first, GrGLuint end) { - SkASSERT(first < end); - fFirst = first; - fEnd = end; - fHeight = 0; - } - - SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* outName) override { - *outName = 0; // No internal gaps, we are contiguous. - return this->takeRef(); - } - - SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange(GrGLuint* removedCount) override { - *removedCount = fEnd - fFirst; - return nullptr; - } - - GrGLuint appendNames(GrGLuint count) override { - SkASSERT(fEnd + count > fEnd); // Check for integer wrap. - GrGLuint name = fEnd; - fEnd += count; - return name; - } - - GrGLuint prependNames(GrGLuint count) override { - SkASSERT(fFirst > count); // We can't allocate at or below 0. - fFirst -= count; - return fFirst; - } - - SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) override { - if (name < fFirst || name >= fEnd) { - // Not-allocated names are silently ignored. - return this->takeRef(); - } - - if (fFirst == name) { - ++fFirst; - return (fEnd == fFirst) ? nullptr : this->takeRef(); - } - - if (fEnd == name + 1) { - --fEnd; - return this->takeRef(); - } - - SparseNameRange* left = new ContiguousNameRange(fFirst, name); - SparseNameRange* right = this->takeRef(); - fFirst = name + 1; - return new SparseNameTree(left, right); - } -}; - -GrGLNameAllocator::GrGLNameAllocator(GrGLuint firstName, GrGLuint endName) - : fFirstName(firstName), - fEndName(endName) { - SkASSERT(firstName > 0); - SkASSERT(endName > firstName); -} - -GrGLNameAllocator::~GrGLNameAllocator() { -} - -GrGLuint GrGLNameAllocator::allocateName() { - if (nullptr == fAllocatedNames.get()) { - fAllocatedNames.reset(new ContiguousNameRange(fFirstName, fFirstName + 1)); - return fFirstName; - } - - if (fAllocatedNames->first() > fFirstName) { - return fAllocatedNames->prependNames(1); - } - - GrGLuint name; - fAllocatedNames.reset(fAllocatedNames->internalAllocate(&name)); - if (0 != name) { - return name; - } - - if (fAllocatedNames->end() < fEndName) { - return fAllocatedNames->appendNames(1); - } - - // Out of names. - return 0; -} - -void GrGLNameAllocator::free(GrGLuint name) { - if (!fAllocatedNames.get()) { - // Not-allocated names are silently ignored. - return; - } - - fAllocatedNames.reset(fAllocatedNames->free(name)); -} diff --git a/gfx/skia/skia/src/gpu/gl/GrGLNameAllocator.h b/gfx/skia/skia/src/gpu/gl/GrGLNameAllocator.h deleted file mode 100644 index 8b0b2a244ab..00000000000 --- a/gfx/skia/skia/src/gpu/gl/GrGLNameAllocator.h +++ /dev/null @@ -1,86 +0,0 @@ - -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrGLNameAllocator_DEFINED -#define GrGLNameAllocator_DEFINED - -#include "SkRefCnt.h" -#include "gl/GrGLTypes.h" - -/** - * This class assumes ownership of an explicit range of OpenGL object names and - * manages allocations within that range. This allows the app to generate new - * objects on the client side without making round trips to the GL server. - */ -class GrGLNameAllocator { -public: - /** - * Constructs a name allocator that produces names within the explicit - * half-open range [firstName, end). Note that the caller will most likely - * need to call glGen* beforehand to reserve a range within the GL driver, - * and then invoke this constructor with that range. - * - * @param firstName The first name in the range owned by this class. Must be - greater than zero. - * @param endName The first past-the-end name beyond the range owned by - this class. Must be >= firstName. - */ - GrGLNameAllocator(GrGLuint firstName, GrGLuint endName); - - /** - * Destructs the name allocator. The caller is responsible for calling the - * appropriate glDelete* on the range if necessary. - */ - ~GrGLNameAllocator(); - - /** - * Return the beginning of this class's range. - * - * @return The first name in the range owned by this class. - */ - GrGLuint firstName() const { return fFirstName; } - - /** - * Return the end of this class's range. Note that endName() is not owned by - * this class. - * - * @return One plus the final name in the range owned by this class. - */ - GrGLuint endName() const { return fEndName; } - - /** - * Allocate an OpenGL object name from within this class's range. - * - * @return The name if one was available, - 0 if all the names in the range were already in use. - */ - GrGLuint allocateName(); - - /** - * Free an OpenGL object name, allowing it to be returned by a future call - * to allocateName(). Note that the caller should most likely redefine the - * object as empty to deallocate any underlying GPU memory before calling - * this method (but not call glDelete*, since that would free up the name - * within the driver itself). - * - * @param name The object name to free. Not-allocated names are silently - * ignored the same way they are in the OpenGL spec. - */ - void free(GrGLuint name); - -private: - class SparseNameRange; - class SparseNameTree; - class ContiguousNameRange; - - const GrGLuint fFirstName; - const GrGLuint fEndName; - SkAutoTUnref fAllocatedNames; -}; - -#endif diff --git a/gfx/skia/skia/src/gpu/gl/GrGLPath.cpp b/gfx/skia/skia/src/gpu/gl/GrGLPath.cpp index d1fc39dffcc..067b74e1549 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLPath.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLPath.cpp @@ -179,6 +179,23 @@ inline bool init_path_object_for_general_path(GrGLGpu* gpu, GrGLuint pathID, pathCoords.count(), GR_GL_FLOAT, &pathCoords[0])); return true; } + +/* + * For now paths only natively support winding and even odd fill types + */ +static GrPathRendering::FillType convert_skpath_filltype(SkPath::FillType fill) { + switch (fill) { + default: + SkFAIL("Incomplete Switch\n"); + case SkPath::kWinding_FillType: + case SkPath::kInverseWinding_FillType: + return GrPathRendering::kWinding_FillType; + case SkPath::kEvenOdd_FillType: + case SkPath::kInverseEvenOdd_FillType: + return GrPathRendering::kEvenOdd_FillType; + } +} + } // namespace bool GrGLPath::InitPathObjectPathDataCheckingDegenerates(GrGLGpu* gpu, GrGLuint pathID, @@ -292,6 +309,9 @@ GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& o fShouldFill = stroke->isFillStyle() || stroke->getStyle() == SkStrokeRec::kStrokeAndFill_Style; + fFillType = convert_skpath_filltype(skPath->getFillType()); + fBounds = skPath->getBounds(); + if (fShouldStroke) { InitPathObjectStroke(gpu, fPathID, *stroke); diff --git a/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.cpp b/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.cpp index 4c9ef867867..3cfec749acb 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.cpp @@ -6,7 +6,6 @@ */ #include "gl/GrGLPathRendering.h" -#include "gl/GrGLNameAllocator.h" #include "gl/GrGLUtil.h" #include "gl/GrGLGpu.h" @@ -20,6 +19,9 @@ #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) #define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->gpu()->glInterface(), RET, X) +// Number of paths to allocate per glGenPaths call. The call can be overly slow on command buffer GL +// implementation. The call has a result value, and thus waiting for the call completion is needed. +static const GrGLsizei kPathIDPreallocationAmount = 65536; static const GrGLenum gIndexType2GLType[] = { GR_GL_UNSIGNED_BYTE, @@ -60,17 +62,21 @@ static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) { } GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu) - : GrPathRendering(gpu) { + : GrPathRendering(gpu) + , fPreallocatedPathCount(0) { const GrGLInterface* glInterface = gpu->glInterface(); fCaps.bindFragmentInputSupport = nullptr != glInterface->fFunctions.fBindFragmentInputLocation; } GrGLPathRendering::~GrGLPathRendering() { + if (fPreallocatedPathCount > 0) { + this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount); + } } void GrGLPathRendering::abandonGpuResources() { - fPathNameAllocator.reset(nullptr); + fPreallocatedPathCount = 0; } void GrGLPathRendering::resetContext() { @@ -230,54 +236,57 @@ void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix, } GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) { - if (range > 1) { - GrGLuint name; - GL_CALL_RET(name, GenPaths(range)); - return name; + SkASSERT(range > 0); + GrGLuint firstID; + if (fPreallocatedPathCount >= range) { + firstID = fFirstPreallocatedPathID; + fPreallocatedPathCount -= range; + fFirstPreallocatedPathID += range; + return firstID; + } + // Allocate range + the amount to fill up preallocation amount. If succeed, either join with + // the existing preallocation range or delete the existing and use the new (potentially partial) + // preallocation range. + GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount); + if (allocAmount >= range) { + GL_CALL_RET(firstID, GenPaths(allocAmount)); + + if (firstID != 0) { + if (fPreallocatedPathCount > 0 && + firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) { + firstID = fFirstPreallocatedPathID; + fPreallocatedPathCount += allocAmount - range; + fFirstPreallocatedPathID += range; + return firstID; + } + + if (allocAmount > range) { + if (fPreallocatedPathCount > 0) { + this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount); + } + fFirstPreallocatedPathID = firstID + range; + fPreallocatedPathCount = allocAmount - range; + } + // Special case: if allocAmount == range, we have full preallocated range. + return firstID; + } + } + // Failed to allocate with preallocation. Remove existing preallocation and try to allocate just + // the range. + if (fPreallocatedPathCount > 0) { + this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount); + fPreallocatedPathCount = 0; } - if (nullptr == fPathNameAllocator.get()) { - static const int range = 65536; - GrGLuint firstName; - GL_CALL_RET(firstName, GenPaths(range)); - fPathNameAllocator.reset(new GrGLNameAllocator(firstName, firstName + range)); + GL_CALL_RET(firstID, GenPaths(range)); + if (firstID == 0) { + SkDebugf("Warning: Failed to allocate path\n"); } - - // When allocating names one at a time, pull from a client-side pool of - // available names in order to save a round trip to the GL server. - GrGLuint name = fPathNameAllocator->allocateName(); - - if (0 == name) { - // Our reserved path names are all in use. Fall back on GenPaths. - GL_CALL_RET(name, GenPaths(1)); - } - - return name; + return firstID; } void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) { - if (range > 1) { - // It is not supported to delete names in ranges that were allocated - // individually using GrGLPathNameAllocator. - SkASSERT(nullptr == fPathNameAllocator.get() || - path + range <= fPathNameAllocator->firstName() || - path >= fPathNameAllocator->endName()); - GL_CALL(DeletePaths(path, range)); - return; - } - - if (nullptr == fPathNameAllocator.get() || - path < fPathNameAllocator->firstName() || - path >= fPathNameAllocator->endName()) { - // If we aren't inside fPathNameAllocator's range then this name was - // generated by the GenPaths fallback (or else was never allocated). - GL_CALL(DeletePaths(path, 1)); - return; - } - - // Make the path empty to save memory, but don't free the name in the driver. - GL_CALL(PathCommands(path, 0, nullptr, 0, GR_GL_FLOAT, nullptr)); - fPathNameAllocator->free(path); + GL_CALL(DeletePaths(path, range)); } void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) { diff --git a/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.h b/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.h index 57209fddc11..c3e53178084 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLPathRendering.h @@ -111,7 +111,8 @@ private: }; GrGLGpu* gpu(); - SkAutoTDelete fPathNameAllocator; + GrGLuint fFirstPreallocatedPathID; + GrGLsizei fPreallocatedPathCount; MatrixState fHWProjectionMatrixState; GrStencilSettings fHWPathStencilSettings; Caps fCaps; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLProgram.cpp b/gfx/skia/skia/src/gpu/gl/GrGLProgram.cpp index 3cf9e4dd7c6..007d9670bc5 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLProgram.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLProgram.cpp @@ -31,15 +31,15 @@ GrGLProgram::GrGLProgram(GrGLGpu* gpu, GrGLuint programID, const UniformInfoArray& uniforms, const VaryingInfoArray& pathProcVaryings, - GrGLInstalledGeoProc* geometryProcessor, - GrGLInstalledXferProc* xferProcessor, - GrGLInstalledFragProcs* fragmentProcessors, + GrGLSLPrimitiveProcessor* geometryProcessor, + GrGLSLXferProcessor* xferProcessor, + const GrGLSLFragProcs& fragmentProcessors, SkTArray* passSamplerUniforms) : fBuiltinUniformHandles(builtinUniforms) , fProgramID(programID) , fGeometryProcessor(geometryProcessor) , fXferProcessor(xferProcessor) - , fFragmentProcessors(SkRef(fragmentProcessors)) + , fFragmentProcessors(fragmentProcessors) , fDesc(desc) , fGpu(gpu) , fProgramDataManager(gpu, programID, uniforms, pathProcVaryings) { @@ -55,6 +55,9 @@ GrGLProgram::~GrGLProgram() { if (fProgramID) { GL_CALL(DeleteProgram(fProgramID)); } + for (int i = 0; i < fFragmentProcessors.count(); ++i) { + delete fFragmentProcessors[i]; + } } void GrGLProgram::abandon() { @@ -63,12 +66,9 @@ void GrGLProgram::abandon() { /////////////////////////////////////////////////////////////////////////////// -template -static void append_texture_bindings(const Proc* ip, - const GrProcessor& processor, +static void append_texture_bindings(const GrProcessor& processor, SkTArray* textureBindings) { if (int numTextures = processor.numTextures()) { - SkASSERT(textureBindings->count() == ip->fSamplersIdx); const GrTextureAccess** bindings = textureBindings->push_back_n(numTextures); int i = 0; do { @@ -84,37 +84,32 @@ void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, // we set the textures, and uniforms for installed processors in a generic way, but subclasses // of GLProgram determine how to set coord transforms - fGeometryProcessor->fGLProc->setData(fProgramDataManager, primProc); - append_texture_bindings(fGeometryProcessor.get(), primProc, textureBindings); + fGeometryProcessor->setData(fProgramDataManager, primProc); + append_texture_bindings(primProc, textureBindings); this->setFragmentData(primProc, pipeline, textureBindings); - const GrXferProcessor& xp = *pipeline.getXferProcessor(); - fXferProcessor->fGLProc->setData(fProgramDataManager, xp); - append_texture_bindings(fXferProcessor.get(), xp, textureBindings); + const GrXferProcessor& xp = pipeline.getXferProcessor(); + fXferProcessor->setData(fProgramDataManager, xp); + append_texture_bindings(xp, textureBindings); } void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, SkTArray* textureBindings) { - int numProcessors = fFragmentProcessors->fProcs.count(); + int numProcessors = fFragmentProcessors.count(); for (int i = 0; i < numProcessors; ++i) { const GrFragmentProcessor& processor = pipeline.getFragmentProcessor(i); - fFragmentProcessors->fProcs[i]->fGLProc->setData(fProgramDataManager, processor); - this->setTransformData(primProc, - processor, - i, - fFragmentProcessors->fProcs[i]); - append_texture_bindings(fFragmentProcessors->fProcs[i], processor, textureBindings); + fFragmentProcessors[i]->setData(fProgramDataManager, processor); + this->setTransformData(primProc, processor, i); + append_texture_bindings(processor, textureBindings); } } void GrGLProgram::setTransformData(const GrPrimitiveProcessor& primProc, const GrFragmentProcessor& processor, - int index, - GrGLInstalledFragProc* ip) { - GrGLSLPrimitiveProcessor* gp = fGeometryProcessor.get()->fGLProc.get(); - gp->setTransformData(primProc, fProgramDataManager, index, - processor.coordTransforms()); + int index) { + fGeometryProcessor->setTransformData(primProc, fProgramDataManager, index, + processor.coordTransforms()); } void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc, diff --git a/gfx/skia/skia/src/gpu/gl/GrGLProgram.h b/gfx/skia/skia/src/gpu/gl/GrGLProgram.h index 72fa9b01a01..22678cb6a38 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLProgram.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLProgram.h @@ -14,6 +14,7 @@ #include "GrGLTexture.h" #include "GrGLProgramDataManager.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" #include "SkString.h" #include "SkXfermode.h" @@ -35,7 +36,7 @@ class GrPipeline; */ class GrGLProgram : public SkRefCnt { public: - typedef GrGLProgramBuilder::BuiltinUniformHandles BuiltinUniformHandles; + typedef GrGLSLProgramBuilder::BuiltinUniformHandles BuiltinUniformHandles; ~GrGLProgram(); @@ -107,9 +108,9 @@ protected: GrGLuint programID, const UniformInfoArray&, const VaryingInfoArray&, // used for NVPR only currently - GrGLInstalledGeoProc* geometryProcessor, - GrGLInstalledXferProc* xferProcessor, - GrGLInstalledFragProcs* fragmentProcessors, + GrGLSLPrimitiveProcessor* geometryProcessor, + GrGLSLXferProcessor* xferProcessor, + const GrGLSLFragProcs& fragmentProcessors, SkTArray* passSamplerUniforms); // A templated helper to loop over effects, set the transforms(via subclass) and bind textures @@ -117,8 +118,7 @@ protected: SkTArray* textureBindings); void setTransformData(const GrPrimitiveProcessor&, const GrFragmentProcessor&, - int index, - GrGLInstalledFragProc*); + int index); // Helper for setData() that sets the view matrix and loads the render target height uniform void setRenderTargetState(const GrPrimitiveProcessor&, const GrPipeline&); @@ -129,9 +129,9 @@ protected: GrGLuint fProgramID; // the installed effects - SkAutoTDelete fGeometryProcessor; - SkAutoTDelete fXferProcessor; - SkAutoTUnref fFragmentProcessors; + SkAutoTDelete fGeometryProcessor; + SkAutoTDelete fXferProcessor; + GrGLSLFragProcs fFragmentProcessors; GrProgramDesc fDesc; GrGLGpu* fGpu; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.cpp b/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.cpp index f0aba497201..06f568ee264 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.cpp @@ -8,6 +8,7 @@ #include "SkMatrix.h" #include "gl/GrGLProgramDataManager.h" #include "gl/GrGLGpu.h" +#include "glsl/GrGLSLUniformHandler.h" #define ASSERT_ARRAY_UPLOAD_IN_BOUNDS(UNI, COUNT) \ SkASSERT(arrayCount <= uni.fArrayCount || \ @@ -31,12 +32,12 @@ GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID, ); // TODO: Move the Xoom uniform array in both FS and VS bug workaround here. - if (GrGLProgramBuilder::kVertex_Visibility & builderUniform.fVisibility) { + if (GrGLSLUniformHandler::kVertex_Visibility & builderUniform.fVisibility) { uniform.fVSLocation = builderUniform.fLocation; } else { uniform.fVSLocation = kUnusedUniform; } - if (GrGLProgramBuilder::kFragment_Visibility & builderUniform.fVisibility) { + if (GrGLSLUniformHandler::kFragment_Visibility & builderUniform.fVisibility) { uniform.fFSLocation = builderUniform.fLocation; } else { uniform.fFSLocation = kUnusedUniform; @@ -62,7 +63,8 @@ GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID, void GrGLProgramDataManager::setSampler(UniformHandle u, int texUnit) const { const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kSampler2D_GrSLType || uni.fType == kSamplerExternal_GrSLType); + SkASSERT(uni.fType == kSampler2D_GrSLType || uni.fType == kSamplerExternal_GrSLType || + uni.fType == kSampler2DRect_GrSLType); SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); // FIXME: We still insert a single sampler uniform for every stage. If the shader does not // reference the sampler then the compiler may have optimized it out. Uncomment this assert diff --git a/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.h b/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.h index d47745334d4..1fce6ed62d0 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLProgramDataManager.h @@ -19,7 +19,6 @@ class GrGLGpu; class SkMatrix; class GrGLProgram; -class GrGLProgramBuilder; /** Manages the resources used by a shader program. * The resources are objects the program uses to communicate with the diff --git a/gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.cpp b/gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.cpp index e3d292c062a..5edacf57218 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.cpp @@ -7,42 +7,39 @@ #include "GrGLProgramDesc.h" #include "GrProcessor.h" -#include "GrGLGpu.h" #include "GrPipeline.h" #include "SkChecksum.h" +#include "gl/GrGLDefines.h" +#include "gl/GrGLTexture.h" +#include "gl/GrGLTypes.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLCaps.h" -/** - * Do we need to either map r,g,b->a or a->r. configComponentMask indicates which channels are - * present in the texture's config. swizzleComponentMask indicates the channels present in the - * shader swizzle. - */ -static bool swizzle_requires_alpha_remapping(const GrGLSLCaps& caps, GrPixelConfig config) { - if (!caps.mustSwizzleInShader()) { - // Any remapping is handled using texture swizzling not shader modifications. - return false; - } - const char* swizzleMap = caps.getSwizzleMap(config); - - return SkToBool(memcmp(swizzleMap, "rgba", 4)); +static uint16_t texture_target_key(GrGLenum target) { + SkASSERT((uint32_t)target < SK_MaxU16); + return target; } -static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) { - uint32_t key = 0; +static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc, + const GrGLSLCaps& caps) { int numTextures = proc.numTextures(); - int shift = 0; - for (int t = 0; t < numTextures; ++t) { - const GrTextureAccess& access = proc.textureAccess(t); - if (swizzle_requires_alpha_remapping(*caps.glslCaps(), access.getTexture()->config())) { - key |= 1 << shift; - } - if (GR_GL_TEXTURE_EXTERNAL == static_cast(access.getTexture())->target()) { - key |= 2 << shift; - } - shift += 2; + // Need two bytes per key (swizzle and target). + int word32Count = (proc.numTextures() + 1) / 2; + if (0 == word32Count) { + return; + } + uint16_t* k16 = SkTCast(b->add32n(word32Count)); + for (int i = 0; i < numTextures; ++i) { + const GrTextureAccess& access = proc.textureAccess(i); + GrGLTexture* texture = static_cast(access.getTexture()); + k16[i] = caps.configTextureSwizzle(texture->config()).asKey() | + (texture_target_key(texture->target()) << 16); + } + // zero the last 16 bits if the number of textures is odd. + if (numTextures & 0x1) { + k16[numTextures] = 0; } - return key; } /** @@ -51,15 +48,14 @@ static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) { * in its key (e.g. the pixel format of textures used). So we create a meta-key for * every effect using this function. It is also responsible for inserting the effect's class ID * which must be different for every GrProcessor subclass. It can fail if an effect uses too many - * textures, transforms, etc, for the space allotted in the meta-key. NOTE, both FPs and GPs share - * this function because it is hairy, though FPs do not have attribs, and GPs do not have transforms + * transforms, etc, for the space allotted in the meta-key. NOTE, both FPs and GPs share this + * function because it is hairy, though FPs do not have attribs, and GPs do not have transforms */ static bool gen_meta_key(const GrProcessor& proc, - const GrGLCaps& caps, + const GrGLSLCaps& glslCaps, uint32_t transformKey, GrProcessorKeyBuilder* b) { size_t processorKeySize = b->size(); - uint32_t textureKey = gen_texture_key(proc, caps); uint32_t classID = proc.classID(); // Currently we allow 16 bits for the class id and the overall processor key size. @@ -68,34 +64,34 @@ static bool gen_meta_key(const GrProcessor& proc, return false; } - uint32_t* key = b->add32n(3); + add_texture_key(b, proc, glslCaps); + + uint32_t* key = b->add32n(2); key[0] = (classID << 16) | SkToU32(processorKeySize); - key[1] = textureKey; - key[2] = transformKey; + key[1] = transformKey; return true; } static bool gen_frag_proc_and_meta_keys(const GrPrimitiveProcessor& primProc, const GrFragmentProcessor& fp, - const GrGLCaps& caps, + const GrGLSLCaps& glslCaps, GrProcessorKeyBuilder* b) { for (int i = 0; i < fp.numChildProcessors(); ++i) { - if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), caps, b)) { + if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), glslCaps, b)) { return false; } } - fp.getGLSLProcessorKey(*caps.glslCaps(), b); + fp.getGLSLProcessorKey(glslCaps, b); - //**** use glslCaps here? - return gen_meta_key(fp, caps, primProc.getTransformKey(fp.coordTransforms(), - fp.numTransformsExclChildren()), b); + return gen_meta_key(fp, glslCaps, primProc.getTransformKey(fp.coordTransforms(), + fp.numTransformsExclChildren()), b); } bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc, const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, - const GrGLGpu* gpu) { + const GrGLSLCaps& glslCaps) { // The descriptor is used as a cache key. Thus when a field of the // descriptor will not affect program generation (because of the attribute // bindings in use or other descriptor field settings) it should be set @@ -110,25 +106,23 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc, GrProcessorKeyBuilder b(&glDesc->key()); - primProc.getGLSLProcessorKey(*gpu->glCaps().glslCaps(), &b); - //**** use glslCaps here? - if (!gen_meta_key(primProc, gpu->glCaps(), 0, &b)) { + primProc.getGLSLProcessorKey(glslCaps, &b); + if (!gen_meta_key(primProc, glslCaps, 0, &b)) { glDesc->key().reset(); return false; } for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) { const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i); - if (!gen_frag_proc_and_meta_keys(primProc, fp, gpu->glCaps(), &b)) { + if (!gen_frag_proc_and_meta_keys(primProc, fp, glslCaps, &b)) { glDesc->key().reset(); return false; } } - const GrXferProcessor& xp = *pipeline.getXferProcessor(); - xp.getGLSLProcessorKey(*gpu->glCaps().glslCaps(), &b); - //**** use glslCaps here? - if (!gen_meta_key(xp, gpu->glCaps(), 0, &b)) { + const GrXferProcessor& xp = pipeline.getXferProcessor(); + xp.getGLSLProcessorKey(glslCaps, &b); + if (!gen_meta_key(xp, glslCaps, 0, &b)) { glDesc->key().reset(); return false; } @@ -148,6 +142,9 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc, header->fFragPosKey = 0; } + header->fOutputSwizzle = + glslCaps.configOutputSwizzle(pipeline.getRenderTarget()->config()).asKey(); + if (pipeline.ignoresCoverage()) { header->fIgnoresCoverage = 1; } else { diff --git a/gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.h b/gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.h index 7ce79ecae9e..0ebf6a228ec 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.h @@ -52,14 +52,13 @@ public: * general draw information, as well as the specific color, geometry, * and coverage stages which will be used to generate the GL Program for * this optstate. - * @param GrGLGpu A GL Gpu, the caps and Gpu object are used to output processor specific - * parts of the descriptor. + * @param GrGLSLCaps Capabilities of the GLSL backend. * @param GrProgramDesc The built and finalized descriptor **/ static bool Build(GrProgramDesc*, const GrPrimitiveProcessor&, const GrPipeline&, - const GrGLGpu*); + const GrGLSLCaps&); }; #endif diff --git a/gfx/skia/skia/src/gpu/gl/GrGLTransferBuffer.cpp b/gfx/skia/skia/src/gpu/gl/GrGLTransferBuffer.cpp new file mode 100755 index 00000000000..b7ee766d928 --- /dev/null +++ b/gfx/skia/skia/src/gpu/gl/GrGLTransferBuffer.cpp @@ -0,0 +1,51 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrGLTransferBuffer.h" +#include "GrGLGpu.h" +#include "SkTraceMemoryDump.h" + +GrGLTransferBuffer::GrGLTransferBuffer(GrGLGpu* gpu, const Desc& desc, GrGLenum type) + : INHERITED(gpu, desc.fSizeInBytes) + , fImpl(gpu, desc, type) { + this->registerWithCache(); +} + +void GrGLTransferBuffer::onRelease() { + if (!this->wasDestroyed()) { + fImpl.release(this->getGpuGL()); + } + + INHERITED::onRelease(); +} + +void GrGLTransferBuffer::onAbandon() { + fImpl.abandon(); + INHERITED::onAbandon(); +} + +void* GrGLTransferBuffer::onMap() { + if (!this->wasDestroyed()) { + return fImpl.map(this->getGpuGL()); + } else { + return nullptr; + } +} + +void GrGLTransferBuffer::onUnmap() { + if (!this->wasDestroyed()) { + fImpl.unmap(this->getGpuGL()); + } +} + +void GrGLTransferBuffer::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump, + const SkString& dumpName) const { + SkString buffer_id; + buffer_id.appendU32(this->bufferID()); + traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_buffer", + buffer_id.c_str()); +} diff --git a/gfx/skia/skia/src/gpu/gl/GrGLTransferBuffer.h b/gfx/skia/skia/src/gpu/gl/GrGLTransferBuffer.h new file mode 100755 index 00000000000..e01d4447df2 --- /dev/null +++ b/gfx/skia/skia/src/gpu/gl/GrGLTransferBuffer.h @@ -0,0 +1,48 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLTransferBuffer_DEFINED +#define GrGLTransferBuffer_DEFINED + +#include "GrTransferBuffer.h" +#include "GrGLBufferImpl.h" +#include "gl/GrGLInterface.h" + +class GrGLGpu; + +class GrGLTransferBuffer : public GrTransferBuffer { + +public: + typedef GrGLBufferImpl::Desc Desc; + + GrGLTransferBuffer(GrGLGpu* gpu, const Desc& desc, GrGLenum type); + + GrGLuint bufferID() const { return fImpl.bufferID(); } + size_t baseOffset() const { return fImpl.baseOffset(); } + GrGLenum bufferType() const { return fImpl.bufferType(); } + +protected: + void onAbandon() override; + void onRelease() override; + void setMemoryBacking(SkTraceMemoryDump* traceMemoryDump, + const SkString& dumpName) const override; + +private: + void* onMap() override; + void onUnmap() override; + + GrGLGpu* getGpuGL() const { + SkASSERT(!this->wasDestroyed()); + return (GrGLGpu*)(this->getGpu()); + } + + GrGLBufferImpl fImpl; + + typedef GrTransferBuffer INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.cpp b/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.cpp new file mode 100644 index 00000000000..1ddb789668e --- /dev/null +++ b/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gl/GrGLUniformHandler.h" + +#include "gl/GrGLCaps.h" +#include "gl/GrGLGpu.h" +#include "gl/builders/GrGLProgramBuilder.h" + +#define GL_CALL(X) GR_GL_CALL(this->glGpu()->glInterface(), X) +#define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->glGpu()->glInterface(), R, X) + +GrGLSLUniformHandler::UniformHandle GrGLUniformHandler::internalAddUniformArray( + uint32_t visibility, + GrSLType type, + GrSLPrecision precision, + const char* name, + bool mangleName, + int arrayCount, + const char** outName) { + SkASSERT(name && strlen(name)); + SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility); + SkASSERT(0 == (~kVisibilityMask & visibility)); + SkASSERT(0 != visibility); + SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type)); + + UniformInfo& uni = fUniforms.push_back(); + uni.fVariable.setType(type); + uni.fVariable.setTypeModifier(GrGLSLShaderVar::kUniform_TypeModifier); + // TODO this is a bit hacky, lets think of a better way. Basically we need to be able to use + // the uniform view matrix name in the GP, and the GP is immutable so it has to tell the PB + // exactly what name it wants to use for the uniform view matrix. If we prefix anythings, then + // the names will mismatch. I think the correct solution is to have all GPs which need the + // uniform view matrix, they should upload the view matrix in their setData along with regular + // uniforms. + char prefix = 'u'; + if ('u' == name[0]) { + prefix = '\0'; + } + fProgramBuilder->nameVariable(uni.fVariable.accessName(), prefix, name, mangleName); + uni.fVariable.setArrayCount(arrayCount); + uni.fVisibility = visibility; + uni.fVariable.setPrecision(precision); + + if (outName) { + *outName = uni.fVariable.c_str(); + } + return GrGLSLUniformHandler::UniformHandle(fUniforms.count() - 1); +} + +void GrGLUniformHandler::appendUniformDecls(ShaderVisibility visibility, SkString* out) const { + for (int i = 0; i < fUniforms.count(); ++i) { + if (fUniforms[i].fVisibility & visibility) { + fUniforms[i].fVariable.appendDecl(fProgramBuilder->glslCaps(), out); + out->append(";\n"); + } + } +} + +void GrGLUniformHandler::bindUniformLocations(GrGLuint programID, const GrGLCaps& caps) { + if (caps.bindUniformLocationSupport()) { + int count = fUniforms.count(); + for (int i = 0; i < count; ++i) { + GL_CALL(BindUniformLocation(programID, i, fUniforms[i].fVariable.c_str())); + fUniforms[i].fLocation = i; + } + } +} + +void GrGLUniformHandler::getUniformLocations(GrGLuint programID, const GrGLCaps& caps) { + if (!caps.bindUniformLocationSupport()) { + int count = fUniforms.count(); + for (int i = 0; i < count; ++i) { + GrGLint location; + GL_CALL_RET(location, GetUniformLocation(programID, fUniforms[i].fVariable.c_str())); + fUniforms[i].fLocation = location; + } + } +} + +const GrGLGpu* GrGLUniformHandler::glGpu() const { + GrGLProgramBuilder* glPB = (GrGLProgramBuilder*) fProgramBuilder; + return glPB->gpu(); +} + + diff --git a/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.h b/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.h new file mode 100644 index 00000000000..a782bcb1c3d --- /dev/null +++ b/gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.h @@ -0,0 +1,61 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLUniformHandler_DEFINED +#define GrGLUniformHandler_DEFINED + +#include "glsl/GrGLSLUniformHandler.h" + +#include "gl/GrGLProgramDataManager.h" + +class GrGLCaps; + +static const int kUniformsPerBlock = 8; + +class GrGLUniformHandler : public GrGLSLUniformHandler { +public: + const GrGLSLShaderVar& getUniformVariable(UniformHandle u) const override { + return fUniforms[u.toIndex()].fVariable; + } + + const char* getUniformCStr(UniformHandle u) const override { + return this->getUniformVariable(u).c_str(); + } +private: + explicit GrGLUniformHandler(GrGLSLProgramBuilder* program) + : INHERITED(program) + , fUniforms(kUniformsPerBlock) {} + + UniformHandle internalAddUniformArray(uint32_t visibility, + GrSLType type, + GrSLPrecision precision, + const char* name, + bool mangleName, + int arrayCount, + const char** outName) override; + + void appendUniformDecls(ShaderVisibility, SkString*) const override; + + // Manually set uniform locations for all our uniforms. + void bindUniformLocations(GrGLuint programID, const GrGLCaps& caps); + + // Updates the loction of the Uniforms if we cannot bind uniform locations manually + void getUniformLocations(GrGLuint programID, const GrGLCaps& caps); + + const GrGLGpu* glGpu() const; + + typedef GrGLProgramDataManager::UniformInfo UniformInfo; + typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray; + + UniformInfoArray fUniforms; + + friend class GrGLProgramBuilder; + + typedef GrGLSLUniformHandler INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/gl/GrGLUtil.cpp b/gfx/skia/skia/src/gpu/gl/GrGLUtil.cpp index 71d54c35c06..b5e58554018 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLUtil.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLUtil.cpp @@ -261,9 +261,27 @@ GrGLRenderer GrGLGetRendererFromString(const char* rendererString) { if (1 == n && lastDigit >= 0 && lastDigit <= 9) { return kPowerVR54x_GrGLRenderer; } + // certain iOS devices also use PowerVR54x GPUs + static const char kAppleA4Str[] = "Apple A4"; + static const char kAppleA5Str[] = "Apple A5"; + static const char kAppleA6Str[] = "Apple A6"; + if (0 == strncmp(rendererString, kAppleA4Str, + SK_ARRAY_COUNT(kAppleA4Str)-1) || + 0 == strncmp(rendererString, kAppleA5Str, + SK_ARRAY_COUNT(kAppleA5Str)-1) || + 0 == strncmp(rendererString, kAppleA6Str, + SK_ARRAY_COUNT(kAppleA6Str)-1)) { + return kPowerVR54x_GrGLRenderer; + } static const char kPowerVRRogueStr[] = "PowerVR Rogue"; + static const char kAppleA7Str[] = "Apple A7"; + static const char kAppleA8Str[] = "Apple A8"; if (0 == strncmp(rendererString, kPowerVRRogueStr, - SK_ARRAY_COUNT(kPowerVRRogueStr)-1)) { + SK_ARRAY_COUNT(kPowerVRRogueStr)-1) || + 0 == strncmp(rendererString, kAppleA7Str, + SK_ARRAY_COUNT(kAppleA7Str)-1) || + 0 == strncmp(rendererString, kAppleA8Str, + SK_ARRAY_COUNT(kAppleA8Str)-1)) { return kPowerVRRogue_GrGLRenderer; } int adrenoNumber; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLUtil.h b/gfx/skia/skia/src/gpu/gl/GrGLUtil.h index 70af3a36f41..8a3021cd571 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLUtil.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLUtil.h @@ -81,6 +81,12 @@ enum GrGLDriver { GR_GL_CALL(gl, GetFramebufferAttachmentParameteriv(t, a, pname, p)); \ } while (0) +#define GR_GL_GetNamedFramebufferAttachmentParameteriv(gl, fb, a, pname, p) \ + do { \ + *(p) = GR_GL_INIT_ZERO; \ + GR_GL_CALL(gl, GetNamedFramebufferAttachmentParameteriv(fb, a, pname, p)); \ + } while (0) + #define GR_GL_GetRenderbufferParameteriv(gl, t, pname, p) \ do { \ *(p) = GR_GL_INIT_ZERO; \ diff --git a/gfx/skia/skia/src/gpu/gl/GrGLVaryingHandler.h b/gfx/skia/skia/src/gpu/gl/GrGLVaryingHandler.h index ab931debd7c..50a87adc033 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLVaryingHandler.h +++ b/gfx/skia/skia/src/gpu/gl/GrGLVaryingHandler.h @@ -21,7 +21,7 @@ public: // This function is used by the NVPR PathProcessor to add a varying directly into the fragment // shader since there is no vertex shader. VaryingHandle addPathProcessingVarying(const char* name, GrGLSLVertToFrag*, - GrSLPrecision fsPrecision = kDefault_GrSLPrecision); + GrSLPrecision fsPrecision = kDefault_GrSLPrecision); private: typedef GrGLProgramDataManager::VaryingInfo VaryingInfo; diff --git a/gfx/skia/skia/src/gpu/gl/GrGLVertexBuffer.cpp b/gfx/skia/skia/src/gpu/gl/GrGLVertexBuffer.cpp index 1f8951654f9..2294844fc42 100644 --- a/gfx/skia/skia/src/gpu/gl/GrGLVertexBuffer.cpp +++ b/gfx/skia/skia/src/gpu/gl/GrGLVertexBuffer.cpp @@ -10,7 +10,8 @@ #include "SkTraceMemoryDump.h" GrGLVertexBuffer::GrGLVertexBuffer(GrGLGpu* gpu, const Desc& desc) - : INHERITED(gpu, desc.fSizeInBytes, desc.fDynamic, 0 == desc.fID) + : INHERITED(gpu, desc.fSizeInBytes, GrGLBufferImpl::kDynamicDraw_Usage == desc.fUsage, + 0 == desc.fID) , fImpl(gpu, desc, GR_GL_ARRAY_BUFFER) { this->registerWithCache(); } diff --git a/gfx/skia/skia/src/gpu/gl/SkGLContext.cpp b/gfx/skia/skia/src/gpu/gl/SkGLContext.cpp index ec318cb80d9..07c61f7aa00 100644 --- a/gfx/skia/skia/src/gpu/gl/SkGLContext.cpp +++ b/gfx/skia/skia/src/gpu/gl/SkGLContext.cpp @@ -152,3 +152,26 @@ void SkGLContext::GLFenceSync::deleteFence(SkPlatformGpuFence fence) const { GLsync glsync = static_cast(fence); fGLDeleteSync(glsync); } + +GrGLint SkGLContext::createTextureRectangle(int width, int height, GrGLenum internalFormat, + GrGLenum externalFormat, GrGLenum externalType, + GrGLvoid* data) { + if (!(kGL_GrGLStandard == fGL->fStandard && GrGLGetVersion(fGL) >= GR_GL_VER(3, 2)) && + !fGL->fExtensions.has("GL_ARB_texture_rectangle")) { + return 0; + } + GrGLuint id; + GR_GL_CALL(fGL, GenTextures(1, &id)); + GR_GL_CALL(fGL, BindTexture(GR_GL_TEXTURE_RECTANGLE, id)); + GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MAG_FILTER, + GR_GL_NEAREST)); + GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MIN_FILTER, + GR_GL_NEAREST)); + GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_S, + GR_GL_CLAMP_TO_EDGE)); + GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_T, + GR_GL_CLAMP_TO_EDGE)); + GR_GL_CALL(fGL, TexImage2D(GR_GL_TEXTURE_RECTANGLE, 0, internalFormat, width, height, 0, + externalFormat, externalType, data)); + return id; +} diff --git a/gfx/skia/skia/src/gpu/gl/SkNullGLContext.cpp b/gfx/skia/skia/src/gpu/gl/SkNullGLContext.cpp index e2a80ce2b37..dafa1ef0bc2 100644 --- a/gfx/skia/skia/src/gpu/gl/SkNullGLContext.cpp +++ b/gfx/skia/skia/src/gpu/gl/SkNullGLContext.cpp @@ -122,6 +122,8 @@ public: BufferManager fBufferManager; GrGLuint fCurrArrayBuffer; GrGLuint fCurrElementArrayBuffer; + GrGLuint fCurrPixelPackBuffer; + GrGLuint fCurrPixelUnpackBuffer; GrGLuint fCurrProgramID; GrGLuint fCurrShaderID; @@ -129,6 +131,8 @@ public: ContextState() : fCurrArrayBuffer(0) , fCurrElementArrayBuffer(0) + , fCurrPixelPackBuffer(0) + , fCurrPixelUnpackBuffer(0) , fCurrProgramID(0) , fCurrShaderID(0) {} @@ -172,6 +176,12 @@ GrGLvoid GR_GL_FUNCTION_TYPE nullGLBufferData(GrGLenum target, case GR_GL_ELEMENT_ARRAY_BUFFER: id = state->fCurrElementArrayBuffer; break; + case GR_GL_PIXEL_PACK_BUFFER: + id = state->fCurrPixelPackBuffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + id = state->fCurrPixelUnpackBuffer; + break; default: SkFAIL("Unexpected target to nullGLBufferData"); break; @@ -215,6 +225,12 @@ GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindBuffer(GrGLenum target, GrGLuint buffer) case GR_GL_ELEMENT_ARRAY_BUFFER: state->fCurrElementArrayBuffer = buffer; break; + case GR_GL_PIXEL_PACK_BUFFER: + state->fCurrPixelPackBuffer = buffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + state->fCurrPixelUnpackBuffer = buffer; + break; } } @@ -228,6 +244,12 @@ GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteBuffers(GrGLsizei n, const GrGLuint* id if (ids[i] == state->fCurrElementArrayBuffer) { state->fCurrElementArrayBuffer = 0; } + if (ids[i] == state->fCurrPixelPackBuffer) { + state->fCurrPixelPackBuffer = 0; + } + if (ids[i] == state->fCurrPixelUnpackBuffer) { + state->fCurrPixelUnpackBuffer = 0; + } BufferObj* buffer = state->fBufferManager.lookUp(ids[i]); state->fBufferManager.free(buffer); @@ -245,6 +267,12 @@ GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBufferRange(GrGLenum target, GrGLintptr o case GR_GL_ELEMENT_ARRAY_BUFFER: id = state->fCurrElementArrayBuffer; break; + case GR_GL_PIXEL_PACK_BUFFER: + id = state->fCurrPixelPackBuffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + id = state->fCurrPixelUnpackBuffer; + break; } if (id > 0) { @@ -267,6 +295,12 @@ GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBuffer(GrGLenum target, GrGLenum access) case GR_GL_ELEMENT_ARRAY_BUFFER: id = state->fCurrElementArrayBuffer; break; + case GR_GL_PIXEL_PACK_BUFFER: + id = state->fCurrPixelPackBuffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + id = state->fCurrPixelUnpackBuffer; + break; } if (id > 0) { @@ -295,6 +329,12 @@ GrGLboolean GR_GL_FUNCTION_TYPE nullGLUnmapBuffer(GrGLenum target) { case GR_GL_ELEMENT_ARRAY_BUFFER: id = state->fCurrElementArrayBuffer; break; + case GR_GL_PIXEL_PACK_BUFFER: + id = state->fCurrPixelPackBuffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + id = state->fCurrPixelUnpackBuffer; + break; } if (id > 0) { BufferObj* buffer = state->fBufferManager.lookUp(id); @@ -320,6 +360,12 @@ GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetBufferParameteriv(GrGLenum target, GrGLenu case GR_GL_ELEMENT_ARRAY_BUFFER: id = state->fCurrElementArrayBuffer; break; + case GR_GL_PIXEL_PACK_BUFFER: + id = state->fCurrPixelPackBuffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + id = state->fCurrPixelUnpackBuffer; + break; } if (id > 0) { BufferObj* buffer = state->fBufferManager.lookUp(id); @@ -532,10 +578,7 @@ static void set_current_context_from_interface(const GrGLInterface* interface) { } #endif -SkNullGLContext* SkNullGLContext::Create(GrGLStandard forcedGpuAPI) { - if (kGLES_GrGLStandard == forcedGpuAPI) { - return nullptr; - } +SkNullGLContext* SkNullGLContext::Create() { SkNullGLContext* ctx = new SkNullGLContext; if (!ctx->isValid()) { delete ctx; diff --git a/gfx/skia/skia/src/gpu/gl/angle/GrGLCreateANGLEInterface.cpp b/gfx/skia/skia/src/gpu/gl/angle/GrGLCreateANGLEInterface.cpp index 05afb2cb1c2..d7ba2cd82a2 100644 --- a/gfx/skia/skia/src/gpu/gl/angle/GrGLCreateANGLEInterface.cpp +++ b/gfx/skia/skia/src/gpu/gl/angle/GrGLCreateANGLEInterface.cpp @@ -45,7 +45,7 @@ const GrGLInterface* GrGLCreateANGLEInterface() { gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dylib"); #else gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.so"); - gLibs.fGLLib = DynamicLoadLibrary("libEGL.so"); + gLibs.fEGLLib = DynamicLoadLibrary("libEGL.so"); #endif } diff --git a/gfx/skia/skia/src/gpu/gl/angle/SkANGLEGLContext.cpp b/gfx/skia/skia/src/gpu/gl/angle/SkANGLEGLContext.cpp index 54ef02d4924..2c9f38e1d94 100644 --- a/gfx/skia/skia/src/gpu/gl/angle/SkANGLEGLContext.cpp +++ b/gfx/skia/skia/src/gpu/gl/angle/SkANGLEGLContext.cpp @@ -180,7 +180,12 @@ GrGLuint SkANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const { } SkGLContext* SkANGLEGLContext::createNew() const { - SkGLContext* ctx = SkANGLEGLContext::Create(this->gl()->fStandard, fIsGLBackend); +#ifdef SK_BUILD_FOR_WIN + SkGLContext* ctx = fIsGLBackend ? SkANGLEGLContext::CreateOpenGL() + : SkANGLEGLContext::CreateDirectX(); +#else + SkGLContext* ctx = SkANGLEGLContext::CreateOpenGL(); +#endif if (ctx) { ctx->makeCurrent(); } diff --git a/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 86264c02de9..4a1b2e9ac5a 100644 --- a/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -10,6 +10,7 @@ #include "GrAutoLocaleSetter.h" #include "GrCoordTransform.h" #include "GrGLProgramBuilder.h" +#include "GrSwizzle.h" #include "GrTexture.h" #include "SkRTConf.h" #include "SkTraceEvent.h" @@ -41,7 +42,10 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gp GrGLSLExpr4 inputColor; GrGLSLExpr4 inputCoverage; - if (!pb->emitAndInstallProcs(&inputColor, &inputCoverage)) { + if (!pb->emitAndInstallProcs(&inputColor, + &inputCoverage, + gpu->glCaps().maxFragmentTextureUnits())) { + pb->cleanupFragmentProcessors(); return nullptr; } @@ -52,299 +56,44 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gp GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args) : INHERITED(args) - , fGeometryProcessor(nullptr) - , fXferProcessor(nullptr) , fGpu(gpu) - , fUniforms(kVarsPerBlock) , fSamplerUniforms(4) - , fVaryingHandler(this) { + , fVaryingHandler(this) + , fUniformHandler(this) { } -GrGLSLProgramDataManager::UniformHandle GrGLProgramBuilder::internalAddUniformArray( - uint32_t visibility, - GrSLType type, - GrSLPrecision precision, - const char* name, - bool mangleName, - int count, - const char** outName) { - SkASSERT(name && strlen(name)); - SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility); - SkASSERT(0 == (~kVisibilityMask & visibility)); - SkASSERT(0 != visibility); - SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type)); - - UniformInfo& uni = fUniforms.push_back(); - uni.fVariable.setType(type); - uni.fVariable.setTypeModifier(GrGLSLShaderVar::kUniform_TypeModifier); - // TODO this is a bit hacky, lets think of a better way. Basically we need to be able to use - // the uniform view matrix name in the GP, and the GP is immutable so it has to tell the PB - // exactly what name it wants to use for the uniform view matrix. If we prefix anythings, then - // the names will mismatch. I think the correct solution is to have all GPs which need the - // uniform view matrix, they should upload the view matrix in their setData along with regular - // uniforms. - char prefix = 'u'; - if ('u' == name[0]) { - prefix = '\0'; - } - this->nameVariable(uni.fVariable.accessName(), prefix, name, mangleName); - uni.fVariable.setArrayCount(count); - uni.fVisibility = visibility; - uni.fVariable.setPrecision(precision); - - if (outName) { - *outName = uni.fVariable.c_str(); - } - return GrGLSLProgramDataManager::UniformHandle(fUniforms.count() - 1); -} - -void GrGLProgramBuilder::onAppendUniformDecls(ShaderVisibility visibility, SkString* out) const { - for (int i = 0; i < fUniforms.count(); ++i) { - if (fUniforms[i].fVisibility & visibility) { - fUniforms[i].fVariable.appendDecl(this->glslCaps(), out); - out->append(";\n"); - } - } +const GrCaps* GrGLProgramBuilder::caps() const { + return fGpu->caps(); } const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const { - return this->fGpu->ctxInfo().caps()->glslCaps(); -} - -bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage) { - // First we loop over all of the installed processors and collect coord transforms. These will - // be sent to the GrGLSLPrimitiveProcessor in its emitCode function - const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); - int totalTextures = primProc.numTextures(); - const int maxTextureUnits = fGpu->glCaps().maxFragmentTextureUnits(); - - for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) { - const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i); - - if (!primProc.hasTransformedLocalCoords()) { - SkTArray& procCoords = fCoordTransforms.push_back(); - processor.gatherCoordTransforms(&procCoords); - } - - totalTextures += processor.numTextures(); - if (totalTextures >= maxTextureUnits) { - GrCapsDebugf(fGpu->caps(), "Program would use too many texture units\n"); - return false; - } - } - - this->emitAndInstallProc(primProc, inputColor, inputCoverage); - - fFragmentProcessors.reset(new GrGLInstalledFragProcs); - int numProcs = this->pipeline().numFragmentProcessors(); - this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor); - this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs, - inputCoverage); - this->emitAndInstallXferProc(*this->pipeline().getXferProcessor(), *inputColor, *inputCoverage, - this->pipeline().ignoresCoverage()); - return true; -} - -void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset, - int numProcs, - GrGLSLExpr4* inOut) { - for (int i = procOffset; i < numProcs; ++i) { - GrGLSLExpr4 output; - const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i); - this->emitAndInstallProc(fp, i, *inOut, &output); - *inOut = output; - } -} - -void GrGLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) { - // create var to hold stage result. If we already have a valid output name, just use that - // otherwise create a new mangled one. This name is only valid if we are reordering stages - // and have to tell stage exactly where to put its output. - SkString outName; - if (output->isValid()) { - outName = output->c_str(); - } else { - this->nameVariable(&outName, '\0', baseName); - } - fFS.codeAppendf("vec4 %s;", outName.c_str()); - *output = outName; -} - -// TODO Processors cannot output zeros because an empty string is all 1s -// the fix is to allow effects to take the GrGLSLExpr4 directly -void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp, - int index, - const GrGLSLExpr4& input, - GrGLSLExpr4* output) { - // Program builders have a bit of state we need to clear with each effect - AutoStageAdvance adv(this); - this->nameExpression(output, "output"); - - // Enclose custom code in a block to avoid namespace conflicts - SkString openBrace; - openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name()); - fFS.codeAppend(openBrace.c_str()); - - this->emitAndInstallProc(fp, index, output->c_str(), input.isOnes() ? nullptr : input.c_str()); - - fFS.codeAppend("}"); -} - -void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc, - GrGLSLExpr4* outputColor, - GrGLSLExpr4* outputCoverage) { - // Program builders have a bit of state we need to clear with each effect - AutoStageAdvance adv(this); - this->nameExpression(outputColor, "outputColor"); - this->nameExpression(outputCoverage, "outputCoverage"); - - // Enclose custom code in a block to avoid namespace conflicts - SkString openBrace; - openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name()); - fFS.codeAppend(openBrace.c_str()); - fVS.codeAppendf("// Primitive Processor %s\n", proc.name()); - - this->emitAndInstallProc(proc, outputColor->c_str(), outputCoverage->c_str()); - - fFS.codeAppend("}"); -} - -void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp, - int index, - const char* outColor, - const char* inColor) { - GrGLInstalledFragProc* ifp = new GrGLInstalledFragProc; - - ifp->fGLProc.reset(fp.createGLSLInstance()); - - SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures()); - this->emitSamplers(fp, &samplers, ifp); - - GrGLSLFragmentProcessor::EmitArgs args(this, - &fFS, - this->glslCaps(), - fp, - outColor, - inColor, - fOutCoords[index], - samplers); - ifp->fGLProc->emitCode(args); - - // We have to check that effects and the code they emit are consistent, ie if an effect - // asks for dst color, then the emit code needs to follow suit - verify(fp); - fFragmentProcessors->fProcs.push_back(ifp); -} - -void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp, - const char* outColor, - const char* outCoverage) { - SkASSERT(!fGeometryProcessor); - fGeometryProcessor = new GrGLInstalledGeoProc; - - fGeometryProcessor->fGLProc.reset(gp.createGLSLInstance(*fGpu->glCaps().glslCaps())); - - SkSTArray<4, GrGLSLTextureSampler> samplers(gp.numTextures()); - this->emitSamplers(gp, &samplers, fGeometryProcessor); - - GrGLSLGeometryProcessor::EmitArgs args(this, - &fVS, - &fFS, - &fVaryingHandler, - this->glslCaps(), - gp, - outColor, - outCoverage, - samplers, - fCoordTransforms, - &fOutCoords); - fGeometryProcessor->fGLProc->emitCode(args); - - // We have to check that effects and the code they emit are consistent, ie if an effect - // asks for dst color, then the emit code needs to follow suit - verify(gp); -} - -void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, - const GrGLSLExpr4& colorIn, - const GrGLSLExpr4& coverageIn, - bool ignoresCoverage) { - // Program builders have a bit of state we need to clear with each effect - AutoStageAdvance adv(this); - - SkASSERT(!fXferProcessor); - fXferProcessor = new GrGLInstalledXferProc; - - fXferProcessor->fGLProc.reset(xp.createGLSLInstance()); - - // Enable dual source secondary output if we have one - if (xp.hasSecondaryOutput()) { - fFS.enableSecondaryOutput(); - } - - if (this->glslCaps()->mustDeclareFragmentShaderOutput()) { - fFS.enableCustomOutput(); - } - - SkString openBrace; - openBrace.printf("{ // Xfer Processor: %s\n", xp.name()); - fFS.codeAppend(openBrace.c_str()); - - SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures()); - this->emitSamplers(xp, &samplers, fXferProcessor); - - GrGLSLXferProcessor::EmitArgs args(this, - &fFS, - this->glslCaps(), - xp, colorIn.c_str(), - ignoresCoverage ? nullptr : coverageIn.c_str(), - fFS.getPrimaryColorOutputName(), - fFS.getSecondaryColorOutputName(), - samplers); - fXferProcessor->fGLProc->emitCode(args); - - // We have to check that effects and the code they emit are consistent, ie if an effect - // asks for dst color, then the emit code needs to follow suit - verify(xp); - fFS.codeAppend("}"); -} - -void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { - SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); -} - -void GrGLProgramBuilder::verify(const GrXferProcessor& xp) { - SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor()); -} - -void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) { - SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); + return fGpu->ctxInfo().caps()->glslCaps(); } static GrSLType get_sampler_type(const GrTextureAccess& access) { GrGLTexture* glTexture = static_cast(access.getTexture()); if (glTexture->target() == GR_GL_TEXTURE_EXTERNAL) { return kSamplerExternal_GrSLType; + } else if (glTexture->target() == GR_GL_TEXTURE_RECTANGLE) { + return kSampler2DRect_GrSLType; } else { SkASSERT(glTexture->target() == GR_GL_TEXTURE_2D); return kSampler2D_GrSLType; } } -template void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor, - GrGLSLTextureSampler::TextureSamplerArray* outSamplers, - GrGLInstalledProc* ip) { - SkDEBUGCODE(ip->fSamplersIdx = fSamplerUniforms.count();) + 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] = this->addUniform(GrGLProgramBuilder::kFragment_Visibility, - samplerType, kDefault_GrSLPrecision, - name.c_str()); + 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) { @@ -384,12 +133,13 @@ GrGLProgram* GrGLProgramBuilder::finalize() { GrGLuint programID; GL_CALL_RET(programID, CreateProgram()); if (0 == programID) { + this->cleanupFragmentProcessors(); return nullptr; } // compile shaders and bind attributes / uniforms SkTDArray shadersToDelete; - fVS.finalize(kVertex_Visibility); + fVS.finalize(GrGLSLUniformHandler::kVertex_Visibility); if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete)) { this->cleanupProgram(programID, shadersToDelete); return nullptr; @@ -406,7 +156,7 @@ GrGLProgram* GrGLProgramBuilder::finalize() { } } - fFS.finalize(kFragment_Visibility); + fFS.finalize(GrGLSLUniformHandler::kFragment_Visibility); if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete)) { this->cleanupProgram(programID, shadersToDelete); return nullptr; @@ -432,13 +182,7 @@ GrGLProgram* GrGLProgramBuilder::finalize() { } void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) { - if (fGpu->glCaps().bindUniformLocationSupport()) { - int count = fUniforms.count(); - for (int i = 0; i < count; ++i) { - GL_CALL(BindUniformLocation(programID, i, fUniforms[i].fVariable.c_str())); - fUniforms[i].fLocation = i; - } - } + fUniformHandler.bindUniformLocations(programID, fGpu->glCaps()); const GrGLCaps& caps = this->gpu()->glCaps(); if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) { @@ -488,14 +232,7 @@ bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) { } void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) { - if (!fGpu->glCaps().bindUniformLocationSupport()) { - int count = fUniforms.count(); - for (int i = 0; i < count; ++i) { - GrGLint location; - GL_CALL_RET(location, GetUniformLocation(programID, fUniforms[i].fVariable.c_str())); - fUniforms[i].fLocation = location; - } - } + fUniformHandler.getUniformLocations(programID, fGpu->glCaps()); // handle NVPR separable varyings if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() || @@ -515,7 +252,8 @@ void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) { void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray& shaderIDs) { GL_CALL(DeleteProgram(programID)); - cleanupShaders(shaderIDs); + this->cleanupShaders(shaderIDs); + this->cleanupFragmentProcessors(); } void GrGLProgramBuilder::cleanupShaders(const SkTDArray& shaderIDs) { for (int i = 0; i < shaderIDs.count(); ++i) { @@ -524,17 +262,15 @@ void GrGLProgramBuilder::cleanupShaders(const SkTDArray& shaderIDs) { } GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) { - return new GrGLProgram(fGpu, this->desc(), fUniformHandles, programID, fUniforms, + return new GrGLProgram(fGpu, + this->desc(), + fUniformHandles, + programID, + fUniformHandler.fUniforms, fVaryingHandler.fPathProcVaryingInfos, - fGeometryProcessor, fXferProcessor, fFragmentProcessors.get(), + fGeometryProcessor, + fXferProcessor, + fFragmentProcessors, &fSamplerUniforms); } -/////////////////////////////////////////////////////////////////////////////////////////////////// - -GrGLInstalledFragProcs::~GrGLInstalledFragProcs() { - int numProcs = fProcs.count(); - for (int i = 0; i < numProcs; ++i) { - delete fProcs[i]; - } -} diff --git a/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.h b/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.h index 329e5d7d081..20879253cae 100644 --- a/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.h +++ b/gfx/skia/skia/src/gpu/gl/builders/GrGLProgramBuilder.h @@ -10,43 +10,16 @@ #include "GrPipeline.h" #include "gl/GrGLProgramDataManager.h" +#include "gl/GrGLUniformHandler.h" #include "gl/GrGLVaryingHandler.h" -#include "glsl/GrGLSLPrimitiveProcessor.h" #include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLTextureSampler.h" -#include "glsl/GrGLSLXferProcessor.h" class GrFragmentProcessor; class GrGLContextInfo; class GrGLSLShaderBuilder; class GrGLSLCaps; -/** - * The below struct represent processors installed in programs. - */ -template -struct GrGLInstalledProc { - SkDEBUGCODE(int fSamplersIdx;) - SkAutoTDelete fGLProc; -}; - -typedef GrGLInstalledProc GrGLInstalledGeoProc; -typedef GrGLInstalledProc GrGLInstalledXferProc; -typedef GrGLInstalledProc GrGLInstalledFragProc; - -struct GrGLInstalledFragProcs : public SkRefCnt { - virtual ~GrGLInstalledFragProcs(); - SkSTArray<8, GrGLInstalledFragProc*, true> fProcs; -}; - -/* - * Please note - no diamond problems because of virtual inheritance. Also, both base classes - * are pure virtual with no data members. This is the base class for program building. - * Subclasses are nearly identical but each has their own way of emitting transforms. State for - * each of the elements of the shader pipeline, ie vertex, fragment, geometry, etc, lives in those - * respective builders -*/ class GrGLProgramBuilder : public GrGLSLProgramBuilder { public: /** Generates a shader program. @@ -58,66 +31,16 @@ public: */ static GrGLProgram* CreateProgram(const DrawArgs&, GrGLGpu*); - const GrGLSLShaderVar& getUniformVariable(UniformHandle u) const override { - return fUniforms[u.toIndex()].fVariable; - } - - const char* getUniformCStr(UniformHandle u) const override { - return this->getUniformVariable(u).c_str(); - } - + const GrCaps* caps() const override; const GrGLSLCaps* glslCaps() const override; GrGLGpu* gpu() const { return fGpu; } private: - typedef GrGLProgramDataManager::UniformInfo UniformInfo; - typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray; - GrGLProgramBuilder(GrGLGpu*, const DrawArgs&); - UniformHandle internalAddUniformArray(uint32_t visibility, - GrSLType type, - GrSLPrecision precision, - const char* name, - bool mangleName, - int arrayCount, - const char** outName) override; - - // Generates a possibly mangled name for a stage variable and writes it to the fragment shader. - // If GrGLSLExpr4 has a valid name then it will use that instead - void nameExpression(GrGLSLExpr4*, const char* baseName); - bool emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage); - void emitAndInstallFragProcs(int procOffset, int numProcs, GrGLSLExpr4* inOut); - void emitAndInstallProc(const GrFragmentProcessor&, - int index, - const GrGLSLExpr4& input, - GrGLSLExpr4* output); - - void emitAndInstallProc(const GrPrimitiveProcessor&, - GrGLSLExpr4* outputColor, - GrGLSLExpr4* outputCoverage); - - // these emit functions help to keep the createAndEmitProcessors template general - void emitAndInstallProc(const GrFragmentProcessor&, - int index, - const char* outColor, - const char* inColor); - void emitAndInstallProc(const GrPrimitiveProcessor&, - const char* outColor, - const char* outCoverage); - void emitAndInstallXferProc(const GrXferProcessor&, - const GrGLSLExpr4& colorIn, - const GrGLSLExpr4& coverageIn, - bool ignoresCoverage); - - void verify(const GrPrimitiveProcessor&); - void verify(const GrXferProcessor&); - void verify(const GrFragmentProcessor&); - template void emitSamplers(const GrProcessor&, - GrGLSLTextureSampler::TextureSamplerArray* outSamplers, - GrGLInstalledProc*); + GrGLSLTextureSampler::TextureSamplerArray* outSamplers) override; bool compileAndAttachShaders(GrGLSLShaderBuilder& shader, GrGLuint programId, @@ -133,45 +56,17 @@ private: // Subclasses create different programs GrGLProgram* createProgram(GrGLuint programID); - void onAppendUniformDecls(ShaderVisibility visibility, SkString* out) const override; - + GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; } + const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; } GrGLSLVaryingHandler* varyingHandler() override { return &fVaryingHandler; } - // reset is called by program creator between each processor's emit code. It increments the - // stage offset for variable name mangling, and also ensures verfication variables in the - // fragment shader are cleared. - void reset() { - this->addStage(); - fFS.reset(); - } - void addStage() { fStageIndex++; } - - class AutoStageAdvance { - public: - AutoStageAdvance(GrGLProgramBuilder* pb) - : fPB(pb) { - fPB->reset(); - // Each output to the fragment processor gets its own code section - fPB->fFS.nextStage(); - } - ~AutoStageAdvance() {} - private: - GrGLProgramBuilder* fPB; - }; - - GrGLInstalledGeoProc* fGeometryProcessor; - GrGLInstalledXferProc* fXferProcessor; - SkAutoTUnref fFragmentProcessors; GrGLGpu* fGpu; - UniformInfoArray fUniforms; - GrGLSLPrimitiveProcessor::TransformsIn fCoordTransforms; - GrGLSLPrimitiveProcessor::TransformsOut fOutCoords; + typedef GrGLSLUniformHandler::UniformHandle UniformHandle; SkTArray fSamplerUniforms; GrGLVaryingHandler fVaryingHandler; - - friend class GrGLVaryingHandler; + GrGLUniformHandler fUniformHandler; typedef GrGLSLProgramBuilder INHERITED; }; diff --git a/gfx/skia/skia/src/gpu/gl/command_buffer/SkCommandBufferGLContext.cpp b/gfx/skia/skia/src/gpu/gl/command_buffer/SkCommandBufferGLContext.cpp index 585f1d079eb..cf9da9365b1 100644 --- a/gfx/skia/skia/src/gpu/gl/command_buffer/SkCommandBufferGLContext.cpp +++ b/gfx/skia/skia/src/gpu/gl/command_buffer/SkCommandBufferGLContext.cpp @@ -9,6 +9,7 @@ #include "gl/GrGLInterface.h" #include "gl/GrGLAssembleInterface.h" #include "gl/command_buffer/SkCommandBufferGLContext.h" +#include "../ports/SkOSEnvironment.h" #include "../ports/SkOSLibrary.h" #if defined SK_BUILD_FOR_MAC @@ -185,46 +186,75 @@ void SkCommandBufferGLContext::initializeGLContext(void* nativeWindow, const int const int* surfaceAttribs) { LoadCommandBufferOnce(); if (!gfFunctionsLoadedSuccessfully) { + SkDebugf("Command Buffer: Could not load EGL functions.\n"); return; } - fDisplay = gfGetDisplay(static_cast(EGL_DEFAULT_DISPLAY)); + // Make sure CHROMIUM_path_rendering is enabled for NVPR support. + sk_setenv("CHROME_COMMAND_BUFFER_GLES2_ARGS", "--enable-gl-path-rendering"); + fDisplay = gfGetDisplay(EGL_DEFAULT_DISPLAY); if (EGL_NO_DISPLAY == fDisplay) { - SkDebugf("Could not create EGL display!"); + SkDebugf("Command Buffer: Could not create EGL display.\n"); return; } EGLint majorVersion; EGLint minorVersion; - gfInitialize(fDisplay, &majorVersion, &minorVersion); + if (!gfInitialize(fDisplay, &majorVersion, &minorVersion)) { + SkDebugf("Command Buffer: Could not initialize EGL display.\n"); + this->destroyGLContext(); + return; + } - EGLConfig surfaceConfig = static_cast(fConfig); EGLint numConfigs; - gfChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs); + if (!gfChooseConfig(fDisplay, configAttribs, static_cast(&fConfig), 1, + &numConfigs) || numConfigs != 1) { + SkDebugf("Command Buffer: Could not choose EGL config.\n"); + this->destroyGLContext(); + return; + } if (nativeWindow) { - fSurface = gfCreateWindowSurface(fDisplay, surfaceConfig, - (EGLNativeWindowType)nativeWindow, surfaceAttribs); + fSurface = gfCreateWindowSurface(fDisplay, + static_cast(fConfig), + (EGLNativeWindowType)nativeWindow, + surfaceAttribs); } else { - fSurface = gfCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs); + fSurface = gfCreatePbufferSurface(fDisplay, + static_cast(fConfig), + surfaceAttribs); + } + if (EGL_NO_SURFACE == fSurface) { + SkDebugf("Command Buffer: Could not create EGL surface.\n"); + this->destroyGLContext(); + return; } static const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - fContext = gfCreateContext(fDisplay, surfaceConfig, nullptr, contextAttribs); + fContext = gfCreateContext(fDisplay, static_cast(fConfig), nullptr, contextAttribs); + if (EGL_NO_CONTEXT == fContext) { + SkDebugf("Command Buffer: Could not create EGL context.\n"); + this->destroyGLContext(); + return; + } - gfMakeCurrent(fDisplay, fSurface, fSurface, fContext); + if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { + SkDebugf("Command Buffer: Could not make EGL context current.\n"); + this->destroyGLContext(); + return; + } SkAutoTUnref gl(GrGLCreateCommandBufferInterface()); if (nullptr == gl.get()) { - SkDebugf("Could not create CommandBuffer GL interface!\n"); + SkDebugf("Command Buffer: Could not create CommandBuffer GL interface.\n"); this->destroyGLContext(); return; } if (!gl->validate()) { - SkDebugf("Could not validate CommandBuffer GL interface!\n"); + SkDebugf("Command Buffer: Could not validate CommandBuffer GL interface.\n"); this->destroyGLContext(); return; } @@ -264,7 +294,7 @@ void SkCommandBufferGLContext::onPlatformMakeCurrent() const { return; } if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { - SkDebugf("Could not set the context.\n"); + SkDebugf("Command Buffer: Could not make EGL context current.\n"); } } @@ -273,7 +303,7 @@ void SkCommandBufferGLContext::onPlatformSwapBuffers() const { return; } if (!gfSwapBuffers(fDisplay, fSurface)) { - SkDebugf("Could not complete gfSwapBuffers.\n"); + SkDebugf("Command Buffer: Could not complete gfSwapBuffers.\n"); } } @@ -298,14 +328,12 @@ bool SkCommandBufferGLContext::makeCurrent() { int SkCommandBufferGLContext::getStencilBits() { EGLint result = 0; - EGLConfig surfaceConfig = static_cast(fConfig); - gfGetConfigAttrib(fDisplay, surfaceConfig, EGL_STENCIL_SIZE, &result); + gfGetConfigAttrib(fDisplay, static_cast(fConfig), EGL_STENCIL_SIZE, &result); return result; } int SkCommandBufferGLContext::getSampleCount() { EGLint result = 0; - EGLConfig surfaceConfig = static_cast(fConfig); - gfGetConfigAttrib(fDisplay, surfaceConfig, EGL_SAMPLES, &result); + gfGetConfigAttrib(fDisplay, static_cast(fConfig), EGL_SAMPLES, &result); return result; } diff --git a/gfx/skia/skia/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp b/gfx/skia/skia/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp index f5440fe3137..bcc30076509 100644 --- a/gfx/skia/skia/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp +++ b/gfx/skia/skia/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp @@ -513,9 +513,10 @@ GrGLvoid debugGenObjs(GrDebugGL::GrObjTypes type, GrGLuint* ids) { for (int i = 0; i < n; ++i) { - GrFakeRefObj *obj = GrDebugGL::getInstance()->createObj(type); - GrAlwaysAssert(obj); - ids[i] = obj->getID(); + GrAlwaysAssert(ids[i] == 0); + GrFakeRefObj *obj = GrDebugGL::getInstance()->createObj(type); + GrAlwaysAssert(obj); + ids[i] = obj->getID(); } } diff --git a/gfx/skia/skia/src/gpu/gl/debug/SkDebugGLContext.h b/gfx/skia/skia/src/gpu/gl/debug/SkDebugGLContext.h index abbcf559c58..113a254e0b7 100644 --- a/gfx/skia/skia/src/gpu/gl/debug/SkDebugGLContext.h +++ b/gfx/skia/skia/src/gpu/gl/debug/SkDebugGLContext.h @@ -14,10 +14,7 @@ class SkDebugGLContext : public SkGLContext { public: ~SkDebugGLContext() override; - static SkDebugGLContext* Create(GrGLStandard forcedGpuAPI) { - if (kGLES_GrGLStandard == forcedGpuAPI) { - return nullptr; - } + static SkDebugGLContext* Create() { return new SkDebugGLContext; } private: diff --git a/gfx/skia/skia/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp b/gfx/skia/skia/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp index 591cae349c0..3b2488dfc6e 100644 --- a/gfx/skia/skia/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp +++ b/gfx/skia/skia/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp @@ -277,7 +277,7 @@ GrGLFuncPtr EGLGLContext::onPlatformGetProcAddress(const char* procName) const { } static bool supports_egl_extension(EGLDisplay display, const char* extension) { - int extensionLength = strlen(extension); + size_t extensionLength = strlen(extension); const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS); while (const char* match = strstr(extensionsStr, extension)) { // Ensure the string we found is its own extension, not a substring of a larger extension diff --git a/gfx/skia/skia/src/gpu/gl/mesa/SkMesaGLContext.h b/gfx/skia/skia/src/gpu/gl/mesa/SkMesaGLContext.h index a58f1c890ee..a9c77a81da4 100644 --- a/gfx/skia/skia/src/gpu/gl/mesa/SkMesaGLContext.h +++ b/gfx/skia/skia/src/gpu/gl/mesa/SkMesaGLContext.h @@ -19,10 +19,7 @@ private: public: ~SkMesaGLContext() override; - static SkMesaGLContext* Create(GrGLStandard forcedGpuAPI) { - if (kGLES_GrGLStandard == forcedGpuAPI) { - return nullptr; - } + static SkMesaGLContext* Create() { SkMesaGLContext* ctx = new SkMesaGLContext; if (!ctx->isValid()) { delete ctx; diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSL.h b/gfx/skia/skia/src/gpu/glsl/GrGLSL.h index ac38522ca14..f2accc54e95 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSL.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSL.h @@ -48,12 +48,23 @@ bool GrGLSLSupportsNamedFragmentShaderOutputs(GrGLSLGeneration); * Gets the name of the function that should be used to sample a 2D texture. Coord type is used * to indicate whether the texture is sampled using projective textured (kVec3f) or not (kVec2f). */ -inline const char* GrGLSLTexture2DFunctionName(GrSLType coordType, GrGLSLGeneration glslGen) { +inline const char* GrGLSLTexture2DFunctionName(GrSLType coordType, GrSLType samplerType, + GrGLSLGeneration glslGen) { + SkASSERT(GrSLTypeIsSamplerType(samplerType)); + SkASSERT(kVec2f_GrSLType == coordType || kVec3f_GrSLType == coordType); + // GL_TEXTURE_RECTANGLE_ARB is written against OpenGL 2.0/GLSL 1.10. At that time there were + // separate texture*() functions. In OpenGL 3.0/GLSL 1.30 the different texture*() functions + // were deprecated in favor or the unified texture() function. RECTANGLE textures became + // standard in OpenGL 3.2/GLSL 1.50 and use texture(). It isn't completely clear what function + // should be used for RECTANGLE textures in GLSL versions >= 1.30 && < 1.50. We're going with + // using texture(). + if (glslGen >= k130_GrGLSLGeneration) { + return (kVec2f_GrSLType == coordType) ? "texture" : "textureProj"; + } if (kVec2f_GrSLType == coordType) { - return glslGen >= k130_GrGLSLGeneration ? "texture" : "texture2D"; + return (samplerType == kSampler2DRect_GrSLType) ? "texture2DRect" : "texture2D"; } else { - SkASSERT(kVec3f_GrSLType == coordType); - return glslGen >= k130_GrGLSLGeneration ? "textureProj" : "texture2DProj"; + return (samplerType == kSampler2DRect_GrSLType) ? "texture2DRectProj" : "texture2DProj"; } } @@ -87,6 +98,8 @@ static inline const char* GrGLSLTypeString(GrSLType t) { return "sampler2D"; case kSamplerExternal_GrSLType: return "samplerExternalOES"; + case kSampler2DRect_GrSLType: + return "sampler2DRect"; default: SkFAIL("Unknown shader var type."); return ""; // suppress warning diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.cpp index 191fb567e6d..c82d8333dff 100755 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.cpp @@ -21,7 +21,6 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) { fBindlessTextureSupport = false; fUsesPrecisionModifiers = false; fCanUseAnyFunctionInShader = true; - fForceHighPrecisionNDSTransform = false; fCanUseMinAndAbsTogether = true; fMustForceNegatedAtanParamToFloat = false; fVersionDeclString = nullptr; @@ -32,9 +31,6 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) { fFBFetchColorName = nullptr; fFBFetchExtensionString = nullptr; fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction; - - fMustSwizzleInShader = false; - memset(fConfigSwizzle, 0, sizeof(fConfigSwizzle)); } SkString GrGLSLCaps::dump() const { @@ -59,8 +55,6 @@ SkString GrGLSLCaps::dump() const { r.appendf("Bindless texture support: %s\n", (fBindlessTextureSupport ? "YES" : "NO")); r.appendf("Uses precision modifiers: %s\n", (fUsesPrecisionModifiers ? "YES" : "NO")); r.appendf("Can use any() function: %s\n", (fCanUseAnyFunctionInShader ? "YES" : "NO")); - r.appendf("Force high precision on NDS transform: %s\n", (fForceHighPrecisionNDSTransform ? - "YES" : "NO")); r.appendf("Can use min() and abs() together: %s\n", (fCanUseMinAndAbsTogether ? "YES" : "NO")); r.appendf("Must force negated atan param to float: %s\n", (fMustForceNegatedAtanParamToFloat ? "YES" : "NO")); @@ -70,8 +64,5 @@ SkString GrGLSLCaps::dump() const { } void GrGLSLCaps::onApplyOptionsOverrides(const GrContextOptions& options) { - if (options.fUseShaderSwizzling) { - fMustSwizzleInShader = true; - } } diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.h index 9924773139c..060539645e2 100755 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.h @@ -11,6 +11,7 @@ #include "GrCaps.h" #include "GrGLSL.h" +#include "GrSwizzle.h" class GrGLSLCaps : public GrShaderCaps { public: @@ -72,8 +73,6 @@ public: // Returns whether we can use the glsl funciton any() in our shader code. bool canUseAnyFunctionInShader() const { return fCanUseAnyFunctionInShader; } - bool forceHighPrecisionNDSTransform() const { return fForceHighPrecisionNDSTransform; } - bool canUseMinAndAbsTogether() const { return fCanUseMinAndAbsTogether; } bool mustForceNegatedAtanParamToFloat() const { return fMustForceNegatedAtanParamToFloat; } @@ -106,14 +105,19 @@ public: return fExternalTextureExtensionString; } - bool mustSwizzleInShader() const { return fMustSwizzleInShader; } - /** - * Returns a string which represents how to map from an internal GLFormat to a given - * GrPixelConfig. The function mustSwizzleInShader determines whether this swizzle is applied - * in the generated shader code or using sample state in the 3D API. + * Given a texture's config, this determines what swizzle must be appended to accesses to the + * texture in generated shader code. Swizzling may be implemented in texture parameters or a + * sampler rather than in the shader. In this case the returned swizzle will always be "rgba". */ - const char* getSwizzleMap(GrPixelConfig config) const { return fConfigSwizzle[config]; } + const GrSwizzle& configTextureSwizzle(GrPixelConfig config) const { + return fConfigTextureSwizzle[config]; + } + + /** Swizzle that should occur on the fragment shader outputs for a given config. */ + const GrSwizzle& configOutputSwizzle(GrPixelConfig config) const { + return fConfigOutputSwizzle[config]; + } GrGLSLGeneration generation() const { return fGLSLGeneration; } @@ -133,7 +137,6 @@ private: bool fBindlessTextureSupport : 1; bool fUsesPrecisionModifiers : 1; bool fCanUseAnyFunctionInShader : 1; - bool fForceHighPrecisionNDSTransform : 1; // Used for specific driver bug work arounds bool fCanUseMinAndAbsTogether : 1; @@ -151,13 +154,13 @@ private: AdvBlendEqInteraction fAdvBlendEqInteraction; - bool fMustSwizzleInShader; - const char* fConfigSwizzle[kGrPixelConfigCnt]; + GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt]; + GrSwizzle fConfigOutputSwizzle[kGrPixelConfigCnt]; friend class GrGLCaps; // For initialization. + friend class GrVkCaps; typedef GrShaderCaps INHERITED; }; - #endif diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp index a0019669f21..649bd99deab 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp @@ -9,7 +9,7 @@ #include "GrFragmentProcessor.h" #include "GrProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" +#include "glsl/GrGLSLUniformHandler.h" void GrGLSLFragmentProcessor::setData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { @@ -93,8 +93,8 @@ void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inpu fragBuilder->codeAppend("{\n"); fragBuilder->codeAppendf("// Child Index %d (mangle: %s): %s\n", childIndex, fragBuilder->getMangleString().c_str(), childProc.name()); - EmitArgs childArgs(args.fBuilder, - fragBuilder, + EmitArgs childArgs(fragBuilder, + args.fUniformHandler, args.fGLSLCaps, childProc, outputColor, diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.h index 0fd1ae3c32f..ca72a9c415b 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentProcessor.h @@ -14,9 +14,10 @@ class GrProcessor; class GrProcessorKeyBuilder; +class GrGLSLCaps; class GrGLSLFPBuilder; class GrGLSLFragmentBuilder; -class GrGLSLCaps; +class GrGLSLUniformHandler; class GrGLSLFragmentProcessor { public: @@ -51,24 +52,24 @@ public: */ struct EmitArgs { - EmitArgs(GrGLSLFPBuilder* builder, - GrGLSLFragmentBuilder* fragBuilder, + EmitArgs(GrGLSLFragmentBuilder* fragBuilder, + GrGLSLUniformHandler* uniformHandler, const GrGLSLCaps* caps, const GrFragmentProcessor& fp, const char* outputColor, const char* inputColor, const GrGLSLTransformedCoordsArray& coords, const TextureSamplerArray& samplers) - : fBuilder(builder) - , fFragBuilder(fragBuilder) + : fFragBuilder(fragBuilder) + , fUniformHandler(uniformHandler) , fGLSLCaps(caps) , fFp(fp) , fOutputColor(outputColor) , fInputColor(inputColor) , fCoords(coords) , fSamplers(samplers) {} - GrGLSLFPBuilder* fBuilder; GrGLSLFragmentBuilder* fFragBuilder; + GrGLSLUniformHandler* fUniformHandler; const GrGLSLCaps* fGLSLCaps; const GrFragmentProcessor& fFp; const char* fOutputColor; diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp index 122db10ec99..54e0b7f9561 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp @@ -10,6 +10,7 @@ #include "glsl/GrGLSL.h" #include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLProgramBuilder.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" const char* GrGLSLFragmentShaderBuilder::kDstTextureColorName = "_dstColor"; @@ -136,24 +137,19 @@ const char* GrGLSLFragmentShaderBuilder::fragmentPosition() { static const char* kTempName = "tmpXYFragCoord"; static const char* kCoordName = "fragCoordYDown"; if (!fSetupFragPosition) { - SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); const char* rtHeightName; - fProgramBuilder->fUniformHandles.fRTHeightUni = - fProgramBuilder->addFragPosUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, - kDefault_GrSLPrecision, - "RTHeight", - &rtHeightName); + fProgramBuilder->addRTHeightUniform("RTHeight", &rtHeightName); // The Adreno compiler seems to be very touchy about access to "gl_FragCoord". // Accessing glFragCoord.zw can cause a program to fail to link. Additionally, // depending on the surrounding code, accessing .xy with a uniform involved can // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand // (and only accessing .xy) seems to "fix" things. - this->codePrependf("\tvec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n", - kCoordName, kTempName, rtHeightName, kTempName); - this->codePrependf("vec2 %s = gl_FragCoord.xy;", kTempName); + const char* precision = glslCaps->usesPrecisionModifiers() ? "highp " : ""; + this->codePrependf("\t%svec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n", + precision, kCoordName, kTempName, rtHeightName, kTempName); + this->codePrependf("%svec2 %s = gl_FragCoord.xy;", precision, kTempName); fSetupFragPosition = true; } SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h index a55fdd2860a..820cf17ae4f 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h @@ -194,6 +194,7 @@ private: bool fHasReadDstColor; bool fHasReadFragmentPosition; + friend class GrGLSLProgramBuilder; friend class GrGLProgramBuilder; typedef GrGLSLXPFragmentBuilder INHERITED; diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp index 8a1e81a1f8e..a8bd8ac4f82 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp @@ -7,9 +7,10 @@ #include "GrGLSLGeometryProcessor.h" +#include "GrCoordTransform.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProcessorTypes.h" -#include "glsl/GrGLSLProgramBuilder.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" #include "glsl/GrGLSLVertexShaderBuilder.h" @@ -20,9 +21,9 @@ void GrGLSLGeometryProcessor::emitCode(EmitArgs& args) { vBuilder->transformToNormalizedDeviceSpace(gpArgs.fPositionVar); } -void GrGLSLGeometryProcessor::emitTransforms(GrGLSLGPBuilder* pb, - GrGLSLVertexBuilder* vb, +void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb, GrGLSLVaryingHandler* varyingHandler, + GrGLSLUniformHandler* uniformHandler, const GrShaderVar& posVar, const char* localCoords, const SkMatrix& localMatrix, @@ -49,10 +50,10 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLGPBuilder* pb, const char* uniName; fInstalledTransforms[i][t].fHandle = - pb->addUniform(GrGLSLProgramBuilder::kVertex_Visibility, - kMat33f_GrSLType, precision, - strUniName.c_str(), - &uniName).toIndex(); + uniformHandler->addUniform(GrGLSLUniformHandler::kVertex_Visibility, + kMat33f_GrSLType, precision, + strUniName.c_str(), + &uniName).toIndex(); SkString strVaryingName("MatrixCoord"); strVaryingName.appendf("_%i_%i", i, t); @@ -94,8 +95,7 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLGPBuilder* pb, } } -void GrGLSLGeometryProcessor::emitTransforms(GrGLSLGPBuilder* pb, - GrGLSLVertexBuilder* vb, +void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb, GrGLSLVaryingHandler* varyingHandler, const char* localCoords, const TransformsIn& tin, @@ -124,16 +124,15 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLGPBuilder* pb, } } -void GrGLSLGeometryProcessor::setupPosition(GrGLSLGPBuilder* pb, - GrGLSLVertexBuilder* vertBuilder, +void GrGLSLGeometryProcessor::setupPosition(GrGLSLVertexBuilder* vertBuilder, GrGPArgs* gpArgs, const char* posName) { gpArgs->fPositionVar.set(kVec2f_GrSLType, "pos2"); vertBuilder->codeAppendf("vec2 %s = %s;", gpArgs->fPositionVar.c_str(), posName); } -void GrGLSLGeometryProcessor::setupPosition(GrGLSLGPBuilder* pb, - GrGLSLVertexBuilder* vertBuilder, +void GrGLSLGeometryProcessor::setupPosition(GrGLSLVertexBuilder* vertBuilder, + GrGLSLUniformHandler* uniformHandler, GrGPArgs* gpArgs, const char* posName, const SkMatrix& mat, @@ -143,10 +142,10 @@ void GrGLSLGeometryProcessor::setupPosition(GrGLSLGPBuilder* pb, vertBuilder->codeAppendf("vec2 %s = %s;", gpArgs->fPositionVar.c_str(), posName); } else { const char* viewMatrixName; - *viewMatrixUniform = pb->addUniform(GrGLSLProgramBuilder::kVertex_Visibility, - kMat33f_GrSLType, kHigh_GrSLPrecision, - "uViewM", - &viewMatrixName); + *viewMatrixUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kVertex_Visibility, + kMat33f_GrSLType, kHigh_GrSLPrecision, + "uViewM", + &viewMatrixName); if (!mat.hasPerspective()) { gpArgs->fPositionVar.set(kVec2f_GrSLType, "pos2"); vertBuilder->codeAppendf("vec2 %s = vec2(%s * vec3(%s, 1));", diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.h index 4c586a79000..84a8f8b9636 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLGeometryProcessor.h @@ -42,20 +42,21 @@ public: protected: // Emit a uniform matrix for each coord transform. - void emitTransforms(GrGLSLGPBuilder* gp, - GrGLSLVertexBuilder* vb, + void emitTransforms(GrGLSLVertexBuilder* vb, GrGLSLVaryingHandler* varyingHandler, + GrGLSLUniformHandler* uniformHandler, const GrShaderVar& posVar, const char* localCoords, const TransformsIn& tin, TransformsOut* tout) { - this->emitTransforms(gp, vb, varyingHandler, posVar, localCoords, SkMatrix::I(), tin, tout); + this->emitTransforms(vb, varyingHandler, uniformHandler, + posVar, localCoords, SkMatrix::I(), tin, tout); } // Emit pre-transformed coords as a vertex attribute per coord-transform. - void emitTransforms(GrGLSLGPBuilder*, - GrGLSLVertexBuilder*, + void emitTransforms(GrGLSLVertexBuilder*, GrGLSLVaryingHandler*, + GrGLSLUniformHandler*, const GrShaderVar& posVar, const char* localCoords, const SkMatrix& localMatrix, @@ -63,8 +64,7 @@ protected: TransformsOut*); // caller has emitted transforms via attributes - void emitTransforms(GrGLSLGPBuilder*, - GrGLSLVertexBuilder*, + void emitTransforms(GrGLSLVertexBuilder*, GrGLSLVaryingHandler*, const char* localCoords, const TransformsIn& tin, @@ -77,9 +77,9 @@ protected: }; // Create the correct type of position variable given the CTM - void setupPosition(GrGLSLGPBuilder*, GrGLSLVertexBuilder*, GrGPArgs*, const char* posName); - void setupPosition(GrGLSLGPBuilder*, - GrGLSLVertexBuilder*, + void setupPosition(GrGLSLVertexBuilder*, GrGPArgs*, const char* posName); + void setupPosition(GrGLSLVertexBuilder*, + GrGLSLUniformHandler* uniformHandler, GrGPArgs*, const char* posName, const SkMatrix& mat, diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp index 70b58cda94f..23bb249af7a 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp @@ -7,8 +7,10 @@ #include "GrGLSLPrimitiveProcessor.h" -#include "glsl/GrGLSLProgramBuilder.h" +#include "GrCoordTransform.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLUniformHandler.h" +#include "glsl/GrGLSLVertexShaderBuilder.h" SkMatrix GrGLSLPrimitiveProcessor::GetTransformMatrix(const SkMatrix& localMatrix, const GrCoordTransform& coordTransform) { @@ -32,16 +34,16 @@ SkMatrix GrGLSLPrimitiveProcessor::GetTransformMatrix(const SkMatrix& localMatri return combined; } -void GrGLSLPrimitiveProcessor::setupUniformColor(GrGLSLGPBuilder* pb, - GrGLSLFragmentBuilder* fragBuilder, +void GrGLSLPrimitiveProcessor::setupUniformColor(GrGLSLFragmentBuilder* fragBuilder, + GrGLSLUniformHandler* uniformHandler, const char* outputName, UniformHandle* colorUniform) { SkASSERT(colorUniform); const char* stagedLocalVarName; - *colorUniform = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, - kDefault_GrSLPrecision, - "Color", - &stagedLocalVarName); + *colorUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec4f_GrSLType, + kDefault_GrSLPrecision, + "Color", + &stagedLocalVarName); fragBuilder->codeAppendf("%s = %s;", outputName, stagedLocalVarName); } diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.h index d164bbe53e0..9fa5150e828 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.h @@ -18,6 +18,7 @@ class GrPrimitiveProcessor; class GrGLSLCaps; class GrGLSLFragmentBuilder; class GrGLSLGPBuilder; +class GrGLSLUniformHandler; class GrGLSLVaryingHandler; class GrGLSLVertexBuilder; @@ -33,10 +34,10 @@ public: typedef SkSTArray<8, GrGLSLTransformedCoordsArray> TransformsOut; struct EmitArgs { - EmitArgs(GrGLSLGPBuilder* pb, - GrGLSLVertexBuilder* vertBuilder, + EmitArgs(GrGLSLVertexBuilder* vertBuilder, GrGLSLFragmentBuilder* fragBuilder, GrGLSLVaryingHandler* varyingHandler, + GrGLSLUniformHandler* uniformHandler, const GrGLSLCaps* caps, const GrPrimitiveProcessor& gp, const char* outputColor, @@ -44,10 +45,10 @@ public: const TextureSamplerArray& samplers, const TransformsIn& transformsIn, TransformsOut* transformsOut) - : fPB(pb) - , fVertBuilder(vertBuilder) + : fVertBuilder(vertBuilder) , fFragBuilder(fragBuilder) , fVaryingHandler(varyingHandler) + , fUniformHandler(uniformHandler) , fGLSLCaps(caps) , fGP(gp) , fOutputColor(outputColor) @@ -55,10 +56,10 @@ public: , fSamplers(samplers) , fTransformsIn(transformsIn) , fTransformsOut(transformsOut) {} - GrGLSLGPBuilder* fPB; GrGLSLVertexBuilder* fVertBuilder; GrGLSLFragmentBuilder* fFragBuilder; GrGLSLVaryingHandler* fVaryingHandler; + GrGLSLUniformHandler* fUniformHandler; const GrGLSLCaps* fGLSLCaps; const GrPrimitiveProcessor& fGP; const char* fOutputColor; @@ -91,8 +92,8 @@ public: const SkTArray& transforms) = 0; protected: - void setupUniformColor(GrGLSLGPBuilder* pb, - GrGLSLFragmentBuilder* fragBuilder, + void setupUniformColor(GrGLSLFragmentBuilder* fragBuilder, + GrGLSLUniformHandler* uniformHandler, const char* outputName, UniformHandle* colorUniform); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp index 54e82b30c0a..6e0e95f16ab 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp @@ -7,6 +7,11 @@ #include "glsl/GrGLSLProgramBuilder.h" +#include "GrPipeline.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLGeometryProcessor.h" +#include "glsl/GrGLSLXferProcessor.h" + const int GrGLSLProgramBuilder::kVarsPerBlock = 8; GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args) @@ -14,7 +19,203 @@ GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args) , fGS(this) , fFS(this, args.fDesc->header().fFragPosKey) , fStageIndex(-1) - , fArgs(args) { + , fArgs(args) + , fGeometryProcessor(nullptr) + , fXferProcessor(nullptr) { +} + +bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, + GrGLSLExpr4* inputCoverage, + int maxTextures) { + // First we loop over all of the installed processors and collect coord transforms. These will + // be sent to the GrGLSLPrimitiveProcessor in its emitCode function + const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); + int totalTextures = primProc.numTextures(); + + for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) { + const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i); + + if (!primProc.hasTransformedLocalCoords()) { + SkTArray& procCoords = fCoordTransforms.push_back(); + processor.gatherCoordTransforms(&procCoords); + } + + totalTextures += processor.numTextures(); + if (totalTextures >= maxTextures) { + GrCapsDebugf(this->caps(), "Program would use too many texture units\n"); + return false; + } + } + + this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage); + + int numProcs = this->pipeline().numFragmentProcessors(); + this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor); + this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs, + inputCoverage); + this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, *inputCoverage, + this->pipeline().ignoresCoverage()); + this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput()); + return true; +} + +void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc, + GrGLSLExpr4* outputColor, + GrGLSLExpr4* outputCoverage) { + // Program builders have a bit of state we need to clear with each effect + AutoStageAdvance adv(this); + this->nameExpression(outputColor, "outputColor"); + this->nameExpression(outputCoverage, "outputCoverage"); + + // Enclose custom code in a block to avoid namespace conflicts + SkString openBrace; + openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name()); + fFS.codeAppend(openBrace.c_str()); + fVS.codeAppendf("// Primitive Processor %s\n", proc.name()); + + SkASSERT(!fGeometryProcessor); + fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps()); + + SkSTArray<4, GrGLSLTextureSampler> samplers(proc.numTextures()); + this->emitSamplers(proc, &samplers); + + GrGLSLGeometryProcessor::EmitArgs args(&fVS, + &fFS, + this->varyingHandler(), + this->uniformHandler(), + this->glslCaps(), + proc, + outputColor->c_str(), + outputCoverage->c_str(), + samplers, + fCoordTransforms, + &fOutCoords); + fGeometryProcessor->emitCode(args); + + // We have to check that effects and the code they emit are consistent, ie if an effect + // asks for dst color, then the emit code needs to follow suit + verify(proc); + + fFS.codeAppend("}"); +} + +void GrGLSLProgramBuilder::emitAndInstallFragProcs(int procOffset, + int numProcs, + GrGLSLExpr4* inOut) { + for (int i = procOffset; i < numProcs; ++i) { + GrGLSLExpr4 output; + const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i); + this->emitAndInstallFragProc(fp, i, *inOut, &output); + *inOut = output; + } +} + +// TODO Processors cannot output zeros because an empty string is all 1s +// the fix is to allow effects to take the GrGLSLExpr4 directly +void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, + int index, + const GrGLSLExpr4& input, + GrGLSLExpr4* output) { + // Program builders have a bit of state we need to clear with each effect + AutoStageAdvance adv(this); + this->nameExpression(output, "output"); + + // Enclose custom code in a block to avoid namespace conflicts + SkString openBrace; + openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name()); + fFS.codeAppend(openBrace.c_str()); + + GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance(); + + SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures()); + this->emitSamplers(fp, &samplers); + + GrGLSLFragmentProcessor::EmitArgs args(&fFS, + this->uniformHandler(), + this->glslCaps(), + fp, + output->c_str(), + input.isOnes() ? nullptr : input.c_str(), + fOutCoords[index], + samplers); + fragProc->emitCode(args); + + // We have to check that effects and the code they emit are consistent, ie if an effect + // asks for dst color, then the emit code needs to follow suit + verify(fp); + fFragmentProcessors.push_back(fragProc); + + fFS.codeAppend("}"); +} + +void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, + const GrGLSLExpr4& colorIn, + const GrGLSLExpr4& coverageIn, + bool ignoresCoverage) { + // Program builders have a bit of state we need to clear with each effect + AutoStageAdvance adv(this); + + SkASSERT(!fXferProcessor); + fXferProcessor = xp.createGLSLInstance(); + + // Enable dual source secondary output if we have one + if (xp.hasSecondaryOutput()) { + fFS.enableSecondaryOutput(); + } + + if (this->glslCaps()->mustDeclareFragmentShaderOutput()) { + fFS.enableCustomOutput(); + } + + SkString openBrace; + openBrace.printf("{ // Xfer Processor: %s\n", xp.name()); + fFS.codeAppend(openBrace.c_str()); + + SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures()); + this->emitSamplers(xp, &samplers); + + GrGLSLXferProcessor::EmitArgs args(&fFS, + this->uniformHandler(), + this->glslCaps(), + xp, colorIn.c_str(), + ignoresCoverage ? nullptr : coverageIn.c_str(), + fFS.getPrimaryColorOutputName(), + fFS.getSecondaryColorOutputName(), + samplers); + fXferProcessor->emitCode(args); + + // We have to check that effects and the code they emit are consistent, ie if an effect + // asks for dst color, then the emit code needs to follow suit + verify(xp); + fFS.codeAppend("}"); +} + +void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) { + // Swizzle the fragment shader outputs if necessary. + GrSwizzle swizzle; + swizzle.setFromKey(this->desc().header().fOutputSwizzle); + if (swizzle != GrSwizzle::RGBA()) { + fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(), + fFS.getPrimaryColorOutputName(), + swizzle.c_str()); + if (hasSecondaryOutput) { + fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(), + fFS.getSecondaryColorOutputName(), + swizzle.c_str()); + } + } +} + +void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { + SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); +} + +void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) { + SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor()); +} + +void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) { + SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); } void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) { @@ -32,8 +233,49 @@ void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* } } -void GrGLSLProgramBuilder::appendUniformDecls(ShaderVisibility visibility, - SkString* out) const { - this->onAppendUniformDecls(visibility, out); +void GrGLSLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) { + // create var to hold stage result. If we already have a valid output name, just use that + // otherwise create a new mangled one. This name is only valid if we are reordering stages + // and have to tell stage exactly where to put its output. + SkString outName; + if (output->isValid()) { + outName = output->c_str(); + } else { + this->nameVariable(&outName, '\0', baseName); + } + fFS.codeAppendf("vec4 %s;", outName.c_str()); + *output = outName; +} + +void GrGLSLProgramBuilder::appendUniformDecls(ShaderVisibility visibility, + SkString* out) const { + this->uniformHandler()->appendUniformDecls(visibility, out); +} + +void GrGLSLProgramBuilder::addRTAdjustmentUniform(GrSLPrecision precision, + const char* name, + const char** outName) { + SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid()); + fUniformHandles.fRTAdjustmentUni = + this->uniformHandler()->addUniform(GrGLSLUniformHandler::kVertex_Visibility, + kVec4f_GrSLType, + precision, + name, + outName); +} + +void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** outName) { + SkASSERT(!fUniformHandles.fRTHeightUni.isValid()); + GrGLSLUniformHandler* uniformHandler = this->uniformHandler(); + fUniformHandles.fRTHeightUni = + uniformHandler->internalAddUniformArray(GrGLSLUniformHandler::kFragment_Visibility, + kFloat_GrSLType, kDefault_GrSLPrecision, + name, false, 0, outName); +} + +void GrGLSLProgramBuilder::cleanupFragmentProcessors() { + for (int i = 0; i < fFragmentProcessors.count(); ++i) { + delete fFragmentProcessors[i]; + } } diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.h index 81037084e98..964d320298f 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLProgramBuilder.h @@ -12,106 +12,37 @@ #include "GrGpu.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryShaderBuilder.h" +#include "glsl/GrGLSLPrimitiveProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" +#include "glsl/GrGLSLTextureSampler.h" #include "glsl/GrGLSLVertexShaderBuilder.h" +#include "glsl/GrGLSLXferProcessor.h" class GrGLSLCaps; class GrGLSLShaderVar; class GrGLSLVaryingHandler; -// Enough precision to represent 1 / 2048 accurately in printf -#define GR_SIGNIFICANT_POW2_DECIMAL_DIG 11 +typedef SkSTArray<8, GrGLSLFragmentProcessor*, true> GrGLSLFragProcs; -class GrGLSLUniformBuilder { -public: - enum ShaderVisibility { - kVertex_Visibility = 1 << kVertex_GrShaderType, - kGeometry_Visibility = 1 << kGeometry_GrShaderType, - kFragment_Visibility = 1 << kFragment_GrShaderType, - }; - - virtual ~GrGLSLUniformBuilder() {} - - typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; - - /** Add a uniform variable to the current program, that has visibility in one or more shaders. - visibility is a bitfield of ShaderVisibility values indicating from which shaders the - uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not - supported at this time. The actual uniform name will be mangled. If outName is not nullptr - then it will refer to the final uniform name after return. Use the addUniformArray variant - to add an array of uniforms. */ - UniformHandle addUniform(uint32_t visibility, - GrSLType type, - GrSLPrecision precision, - const char* name, - const char** outName = nullptr) { - return this->addUniformArray(visibility, type, precision, name, 0, outName); - } - - UniformHandle addUniformArray(uint32_t visibility, - GrSLType type, - GrSLPrecision precision, - const char* name, - int arrayCount, - const char** outName = nullptr) { - return this->internalAddUniformArray(visibility, type, precision, name, true, arrayCount, - outName); - } - - virtual const GrGLSLShaderVar& getUniformVariable(UniformHandle u) const = 0; - - /** - * Shortcut for getUniformVariable(u).c_str() - */ - virtual const char* getUniformCStr(UniformHandle u) const = 0; - - /* - * *NOTE* NO MEMBERS ALLOWED, MULTIPLE INHERITANCE - */ -protected: - virtual UniformHandle internalAddUniformArray( - uint32_t visibility, - GrSLType type, - GrSLPrecision precision, - const char* name, - bool mangleName, - int arrayCount, - const char** outName) = 0; -}; - -/* a specialization of the above for GPs. Lets the user add uniforms, varyings, and VS / FS code */ -class GrGLSLGPBuilder : public virtual GrGLSLUniformBuilder { -public: - /* - * *NOTE* NO MEMBERS ALLOWED, MULTIPLE INHERITANCE - */ -}; - - -/* a specializations for FPs. Lets the user add uniforms and FS code */ -class GrGLSLFPBuilder : public virtual GrGLSLUniformBuilder { -public: - /* - * *NOTE* NO MEMBERS ALLOWED, MULTIPLE INHERITANCE - */ -}; - -/* a specializations for XPs. Lets the user add uniforms and FS code */ -class GrGLSLXPBuilder : public virtual GrGLSLUniformBuilder { -public: - /* - * *NOTE* NO MEMBERS ALLOWED, MULTIPLE INHERITANCE - */ -}; - -class GrGLSLProgramBuilder : public GrGLSLGPBuilder, - public GrGLSLFPBuilder, - public GrGLSLXPBuilder { +class GrGLSLProgramBuilder { public: typedef GrGpu::DrawArgs DrawArgs; + typedef GrGLSLUniformHandler::ShaderVisibility ShaderVisibility; + typedef GrGLSLUniformHandler::UniformHandle UniformHandle; + virtual ~GrGLSLProgramBuilder() {} + + virtual const GrCaps* caps() const = 0; virtual const GrGLSLCaps* glslCaps() const = 0; + const GrPrimitiveProcessor& primitiveProcessor() const { return *fArgs.fPrimitiveProcessor; } + const GrPipeline& pipeline() const { return *fArgs.fPipeline; } + const GrProgramDesc& desc() const { return *fArgs.fDesc; } + const GrProgramDesc::KeyHeader& header() const { return fArgs.fDesc->header(); } + + void appendUniformDecls(ShaderVisibility, SkString*) const; + // Handles for program uniforms (other than per-effect uniforms) struct BuiltinUniformHandles { UniformHandle fRTAdjustmentUni; @@ -121,33 +52,21 @@ public: UniformHandle fRTHeightUni; }; -protected: - explicit GrGLSLProgramBuilder(const DrawArgs& args); - - const GrPrimitiveProcessor& primitiveProcessor() const { return *fArgs.fPrimitiveProcessor; } - const GrPipeline& pipeline() const { return *fArgs.fPipeline; } - const GrProgramDesc& desc() const { return *fArgs.fDesc; } - const GrProgramDesc::KeyHeader& header() const { return fArgs.fDesc->header(); } - - void appendUniformDecls(ShaderVisibility, SkString*) const; - - // Used to add a uniform for frag position without mangling the name of the uniform inside of a - // stage. - UniformHandle addFragPosUniform(uint32_t visibility, - GrSLType type, - GrSLPrecision precision, - const char* name, - const char** outName) { - return this->internalAddUniformArray(visibility, type, precision, name, false, 0, outName); - } - + // Used to add a uniform in the vertex shader for transforming into normalized device space. + void addRTAdjustmentUniform(GrSLPrecision precision, const char* name, const char** outName); const char* rtAdjustment() const { return "rtAdjustment"; } + + // Used to add a uniform for the RenderTarget height (used for frag position) without mangling + // the name of the uniform inside of a stage. + void addRTHeightUniform(const char* name, const char** outName); // Generates a name for a variable. The generated string will be name prefixed by the prefix // char (unless the prefix is '\0'). It also will mangle the name to be stage-specific unless // explicitly asked not to. void nameVariable(SkString* out, char prefix, const char* name, bool mangle = true); + virtual GrGLSLUniformHandler* uniformHandler() = 0; + virtual const GrGLSLUniformHandler* uniformHandler() const = 0; virtual GrGLSLVaryingHandler* varyingHandler() = 0; // number of each input/output type in a single allocation block, used by many builders @@ -159,18 +78,71 @@ protected: int fStageIndex; - BuiltinUniformHandles fUniformHandles; - const DrawArgs& fArgs; -private: - virtual void onAppendUniformDecls(ShaderVisibility visibility, SkString* out) const = 0; + BuiltinUniformHandles fUniformHandles; - friend class GrGLSLShaderBuilder; - friend class GrGLSLVertexBuilder; - friend class GrGLSLFragmentShaderBuilder; - friend class GrGLSLGeometryBuilder; - friend class GrGLSLVaryingHandler; + GrGLSLPrimitiveProcessor* fGeometryProcessor; + GrGLSLXferProcessor* fXferProcessor; + GrGLSLFragProcs fFragmentProcessors; + +protected: + explicit GrGLSLProgramBuilder(const DrawArgs& args); + + bool emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage, int maxTextures); + + void cleanupFragmentProcessors(); + +private: + // reset is called by program creator between each processor's emit code. It increments the + // stage offset for variable name mangling, and also ensures verfication variables in the + // fragment shader are cleared. + void reset() { + this->addStage(); + fFS.reset(); + } + void addStage() { fStageIndex++; } + + class AutoStageAdvance { + public: + AutoStageAdvance(GrGLSLProgramBuilder* pb) + : fPB(pb) { + fPB->reset(); + // Each output to the fragment processor gets its own code section + fPB->fFS.nextStage(); + } + ~AutoStageAdvance() {} + private: + GrGLSLProgramBuilder* fPB; + }; + + // Generates a possibly mangled name for a stage variable and writes it to the fragment shader. + // If GrGLSLExpr4 has a valid name then it will use that instead + void nameExpression(GrGLSLExpr4*, const char* baseName); + + void emitAndInstallPrimProc(const GrPrimitiveProcessor&, + GrGLSLExpr4* outputColor, + GrGLSLExpr4* outputCoverage); + void emitAndInstallFragProcs(int procOffset, int numProcs, GrGLSLExpr4* inOut); + void emitAndInstallFragProc(const GrFragmentProcessor&, + int index, + const GrGLSLExpr4& input, + GrGLSLExpr4* output); + void emitAndInstallXferProc(const GrXferProcessor&, + const GrGLSLExpr4& colorIn, + const GrGLSLExpr4& coverageIn, + bool ignoresCoverage); + void emitFSOutputSwizzle(bool hasSecondaryOutput); + + void verify(const GrPrimitiveProcessor&); + void verify(const GrXferProcessor&); + void verify(const GrFragmentProcessor&); + + virtual void emitSamplers(const GrProcessor& processor, + GrGLSLTextureSampler::TextureSamplerArray* outSamplers) = 0; + + GrGLSLPrimitiveProcessor::TransformsIn fCoordTransforms; + GrGLSLPrimitiveProcessor::TransformsOut fOutCoords; }; #endif diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp index 1fc15ecb3c4..f1ede1decd7 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp @@ -5,70 +5,13 @@ * found in the LICENSE file. */ +#include "GrSwizzle.h" #include "glsl/GrGLSLShaderBuilder.h" #include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLShaderVar.h" #include "glsl/GrGLSLTextureSampler.h" #include "glsl/GrGLSLProgramBuilder.h" -static void map_swizzle(const char* swizzleMap, const char* swizzle, char* mangledSwizzle) { - int i; - for (i = 0; '\0' != swizzle[i]; ++i) { - switch (swizzle[i]) { - case 'r': - mangledSwizzle[i] = swizzleMap[0]; - break; - case 'g': - mangledSwizzle[i] = swizzleMap[1]; - break; - case 'b': - mangledSwizzle[i] = swizzleMap[2]; - break; - case 'a': - mangledSwizzle[i] = swizzleMap[3]; - break; - default: - SkFAIL("Unsupported swizzle"); - } - } - mangledSwizzle[i] ='\0'; -} - -static void append_texture_lookup(SkString* out, - const GrGLSLCaps* glslCaps, - const char* samplerName, - const char* coordName, - GrPixelConfig config, - const char* swizzle, - GrSLType varyingType = kVec2f_GrSLType) { - SkASSERT(coordName); - - out->appendf("%s(%s, %s)", - GrGLSLTexture2DFunctionName(varyingType, glslCaps->generation()), - samplerName, - coordName); - - char mangledSwizzle[5]; - - // This refers to any swizzling we may need to get from some backend internal format to the - // format used in GrPixelConfig. Some backends will automatically do the sizzling for us. - if (glslCaps->mustSwizzleInShader()) { - const char* swizzleMap = glslCaps->getSwizzleMap(config); - // if the map is simply 'rgba' then we don't need to do any manual swizzling to get us to - // a GrPixelConfig format. - if (memcmp(swizzleMap, "rgba", 4)) { - // Manually 'swizzle' the swizzle using our mapping - map_swizzle(swizzleMap, swizzle, mangledSwizzle); - swizzle = mangledSwizzle; - } - } - - // For shader prettiness we omit the swizzle rather than appending ".rgba". - if (memcmp(swizzle, "rgba", 4)) { - out->appendf(".%s", swizzle); - } -} - GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program) : fProgramBuilder(program) , fInputs(GrGLSLProgramBuilder::kVarsPerBlock) @@ -117,13 +60,22 @@ void GrGLSLShaderBuilder::appendTextureLookup(SkString* out, const GrGLSLTextureSampler& sampler, const char* coordName, GrSLType varyingType) const { - append_texture_lookup(out, - fProgramBuilder->glslCaps(), - fProgramBuilder->getUniformCStr(sampler.fSamplerUniform), - coordName, - sampler.config(), - sampler.swizzle(), - varyingType); + const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps(); + GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler(); + GrSLType samplerType = uniformHandler->getUniformVariable(sampler.fSamplerUniform).getType(); + out->appendf("%s(%s, %s)", + GrGLSLTexture2DFunctionName(varyingType, samplerType, glslCaps->generation()), + uniformHandler->getUniformCStr(sampler.fSamplerUniform), + coordName); + + // This refers to any swizzling we may need to get from some backend internal format to the + // format used in GrPixelConfig. If this is implemented by the GrGpu object, then swizzle will + // be rgba. For shader prettiness we omit the swizzle rather than appending ".rgba". + const GrSwizzle& configSwizzle = glslCaps->configTextureSwizzle(sampler.config()); + + if (configSwizzle != GrSwizzle::RGBA()) { + out->appendf(".%s", configSwizzle.c_str()); + } } void GrGLSLShaderBuilder::appendTextureLookup(const GrGLSLTextureSampler& sampler, @@ -187,7 +139,7 @@ void GrGLSLShaderBuilder::finalize(uint32_t visibility) { this->versionDecl() = fProgramBuilder->glslCaps()->versionDeclString(); this->compileAndAppendLayoutQualifiers(); SkASSERT(visibility); - fProgramBuilder->appendUniformDecls((GrGLSLProgramBuilder::ShaderVisibility) visibility, + fProgramBuilder->appendUniformDecls((GrGLSLUniformHandler::ShaderVisibility) visibility, &this->uniforms()); this->appendDecls(fInputs, &this->inputs()); this->appendDecls(fOutputs, &this->outputs()); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.h index 1a8255dbb46..16a07563060 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLShaderBuilder.h @@ -191,7 +191,9 @@ protected: int fCodeIndex; bool fFinalized; + friend class GrGLSLProgramBuilder; friend class GrGLProgramBuilder; friend class GrGLPathProgramBuilder; // to access fInputs. + friend class GrVkProgramBuilder; }; #endif diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLTextureSampler.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLTextureSampler.h index a4fbf550f25..fd8bcb26e90 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLTextureSampler.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLTextureSampler.h @@ -21,17 +21,13 @@ public: : fSamplerUniform(uniform) , fConfig(access.getTexture()->config()) { SkASSERT(kUnknown_GrPixelConfig != fConfig); - memcpy(fSwizzle, access.getSwizzle(), 5); } GrPixelConfig config() const { return fConfig; } - // this is .abcd - const char* swizzle() const { return fSwizzle; } private: UniformHandle fSamplerUniform; GrPixelConfig fConfig; - char fSwizzle[5]; friend class GrGLSLShaderBuilder; }; diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLUniformHandler.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLUniformHandler.h new file mode 100644 index 00000000000..e72716d04e4 --- /dev/null +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLUniformHandler.h @@ -0,0 +1,79 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLSLUniformHandler_DEFINED +#define GrGLSLUniformHandler_DEFINED + +#include "GrGLSLProgramDataManager.h" +#include "GrGLSLShaderVar.h" + +class GrGLSLProgramBuilder; + +class GrGLSLUniformHandler { +public: + enum ShaderVisibility { + kVertex_Visibility = 1 << kVertex_GrShaderType, + kGeometry_Visibility = 1 << kGeometry_GrShaderType, + kFragment_Visibility = 1 << kFragment_GrShaderType, + }; + + virtual ~GrGLSLUniformHandler() {} + + typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; + + /** Add a uniform variable to the current program, that has visibility in one or more shaders. + visibility is a bitfield of ShaderVisibility values indicating from which shaders the + uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not + supported at this time. The actual uniform name will be mangled. If outName is not nullptr + then it will refer to the final uniform name after return. Use the addUniformArray variant + to add an array of uniforms. */ + UniformHandle addUniform(uint32_t visibility, + GrSLType type, + GrSLPrecision precision, + const char* name, + const char** outName = nullptr) { + return this->addUniformArray(visibility, type, precision, name, 0, outName); + } + + UniformHandle addUniformArray(uint32_t visibility, + GrSLType type, + GrSLPrecision precision, + const char* name, + int arrayCount, + const char** outName = nullptr) { + return this->internalAddUniformArray(visibility, type, precision, name, true, arrayCount, + outName); + } + + virtual const GrGLSLShaderVar& getUniformVariable(UniformHandle u) const = 0; + + /** + * Shortcut for getUniformVariable(u).c_str() + */ + virtual const char* getUniformCStr(UniformHandle u) const = 0; +protected: + explicit GrGLSLUniformHandler(GrGLSLProgramBuilder* program) : fProgramBuilder(program) {} + + // This is not owned by the class + GrGLSLProgramBuilder* fProgramBuilder; + +private: + virtual UniformHandle internalAddUniformArray(uint32_t visibility, + GrSLType type, + GrSLPrecision precision, + const char* name, + bool mangleName, + int arrayCount, + const char** outName) = 0; + + virtual void appendUniformDecls(ShaderVisibility, SkString*) const = 0; + + friend class GrGLSLProgramBuilder; +}; + +#endif + diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp index 73c0fcd81e1..005b2725fff 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp @@ -7,6 +7,7 @@ #include "GrGLSLVertexShaderBuilder.h" #include "glsl/GrGLSLProgramBuilder.h" +#include "glsl/GrGLSLUniformHandler.h" #include "glsl/GrGLSLVarying.h" GrGLSLVertexBuilder::GrGLSLVertexBuilder(GrGLSLProgramBuilder* program) @@ -17,17 +18,10 @@ GrGLSLVertexBuilder::GrGLSLVertexBuilder(GrGLSLProgramBuilder* program) void GrGLSLVertexBuilder::transformToNormalizedDeviceSpace(const GrShaderVar& posVar) { SkASSERT(!fRtAdjustName); - GrSLPrecision precision = kDefault_GrSLPrecision; - if (fProgramBuilder->glslCaps()->forceHighPrecisionNDSTransform()) { - precision = kHigh_GrSLPrecision; - } - // setup RT Uniform - fProgramBuilder->fUniformHandles.fRTAdjustmentUni = - fProgramBuilder->addUniform(GrGLSLProgramBuilder::kVertex_Visibility, - kVec4f_GrSLType, precision, - fProgramBuilder->rtAdjustment(), - &fRtAdjustName); + fProgramBuilder->addRTAdjustmentUniform(kHigh_GrSLPrecision, + fProgramBuilder->rtAdjustment(), + &fRtAdjustName); if (this->getProgramBuilder()->desc().header().fSnapVerticesToPixelCenters) { if (kVec3f_GrSLType == posVar.getType()) { const char* p = posVar.c_str(); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.h index b76721fd00b..7c624cee654 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.h @@ -13,6 +13,9 @@ class GrGLSLVarying; +// Enough precision to represent 1 / 2048 accurately in printf +#define GR_SIGNIFICANT_POW2_DECIMAL_DIG 11 + class GrGLSLVertexBuilder : public GrGLSLShaderBuilder { public: GrGLSLVertexBuilder(GrGLSLProgramBuilder* program); diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.cpp b/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.cpp index b6af968651a..81bd015718c 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.cpp +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.cpp @@ -9,8 +9,8 @@ #include "GrXferProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" +#include "glsl/GrGLSLUniformHandler.h" void GrGLSLXferProcessor::emitCode(const EmitArgs& args) { if (!args.fXP.willReadDstColor()) { @@ -19,6 +19,7 @@ void GrGLSLXferProcessor::emitCode(const EmitArgs& args) { } GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder; + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; const char* dstColor = fragBuilder->dstColor(); if (args.fXP.getDstTexture()) { @@ -35,16 +36,16 @@ void GrGLSLXferProcessor::emitCode(const EmitArgs& args) { const char* dstTopLeftName; const char* dstCoordScaleName; - fDstTopLeftUni = args.fPB->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, - kDefault_GrSLPrecision, - "DstTextureUpperLeft", - &dstTopLeftName); - fDstScaleUni = args.fPB->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, - kVec2f_GrSLType, - kDefault_GrSLPrecision, - "DstTextureCoordScale", - &dstCoordScaleName); + fDstTopLeftUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, + kDefault_GrSLPrecision, + "DstTextureUpperLeft", + &dstTopLeftName); + fDstScaleUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, + kVec2f_GrSLType, + kDefault_GrSLPrecision, + "DstTextureCoordScale", + &dstCoordScaleName); const char* fragPos = fragBuilder->fragmentPosition(); fragBuilder->codeAppend("// Read color from copy of the destination.\n"); @@ -60,8 +61,8 @@ void GrGLSLXferProcessor::emitCode(const EmitArgs& args) { fragBuilder->codeAppend(";"); } - this->emitBlendCodeForDstRead(args.fPB, - fragBuilder, + this->emitBlendCodeForDstRead(fragBuilder, + uniformHandler, args.fInputColor, args.fInputCoverage, dstColor, diff --git a/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.h b/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.h index 3707d934592..ed8099b6f30 100644 --- a/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.h +++ b/gfx/skia/skia/src/gpu/glsl/GrGLSLXferProcessor.h @@ -12,9 +12,10 @@ #include "glsl/GrGLSLTextureSampler.h" class GrXferProcessor; +class GrGLSLCaps; +class GrGLSLUniformHandler; class GrGLSLXPBuilder; class GrGLSLXPFragmentBuilder; -class GrGLSLCaps; class GrGLSLXferProcessor { public: @@ -23,8 +24,8 @@ public: typedef GrGLSLTextureSampler::TextureSamplerArray TextureSamplerArray; struct EmitArgs { - EmitArgs(GrGLSLXPBuilder* pb, - GrGLSLXPFragmentBuilder* fragBuilder, + EmitArgs(GrGLSLXPFragmentBuilder* fragBuilder, + GrGLSLUniformHandler* uniformHandler, const GrGLSLCaps* caps, const GrXferProcessor& xp, const char* inputColor, @@ -32,8 +33,8 @@ public: const char* outputPrimary, const char* outputSecondary, const TextureSamplerArray& samplers) - : fPB(pb) - , fXPFragBuilder(fragBuilder) + : fXPFragBuilder(fragBuilder) + , fUniformHandler(uniformHandler) , fGLSLCaps(caps) , fXP(xp) , fInputColor(inputColor) @@ -42,8 +43,8 @@ public: , fOutputSecondary(outputSecondary) , fSamplers(samplers) {} - GrGLSLXPBuilder* fPB; GrGLSLXPFragmentBuilder* fXPFragBuilder; + GrGLSLUniformHandler* fUniformHandler; const GrGLSLCaps* fGLSLCaps; const GrXferProcessor& fXP; const char* fInputColor; @@ -82,8 +83,8 @@ private: * the blending logic. The base class applies coverage. A subclass only needs to implement this * method if it can construct a GrXferProcessor that reads the dst color. */ - virtual void emitBlendCodeForDstRead(GrGLSLXPBuilder*, - GrGLSLXPFragmentBuilder*, + virtual void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder*, + GrGLSLUniformHandler*, const char* srcColor, const char* srcCoverage, const char* dstColor, diff --git a/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.cpp b/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.cpp new file mode 100644 index 00000000000..f79f82598f6 --- /dev/null +++ b/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.cpp @@ -0,0 +1,516 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrAtlasTextBlob.h" + +#include "GrBlurUtils.h" +#include "GrContext.h" +#include "GrDrawContext.h" +#include "GrTextUtils.h" +#include "SkColorFilter.h" +#include "SkDrawFilter.h" +#include "SkGlyphCache.h" +#include "SkTextBlobRunIterator.h" +#include "batches/GrAtlasTextBatch.h" + +SkGlyphCache* GrAtlasTextBlob::setupCache(int runIndex, + const SkSurfaceProps& props, + const SkPaint& skPaint, + const SkMatrix* viewMatrix, + bool noGamma) { + GrAtlasTextBlob::Run* run = &fRuns[runIndex]; + + // if we have an override descriptor for the run, then we should use that + SkAutoDescriptor* desc = run->fOverrideDescriptor.get() ? run->fOverrideDescriptor.get() : + &run->fDescriptor; + skPaint.getScalerContextDescriptor(desc, props, viewMatrix, noGamma); + run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); + return SkGlyphCache::DetachCache(run->fTypeface, desc->getDesc()); +} + +void GrAtlasTextBlob::appendGlyph(int runIndex, + const SkRect& positions, + GrColor color, + GrBatchTextStrike* strike, + GrGlyph* glyph, + GrFontScaler* scaler, const SkGlyph& skGlyph, + SkScalar x, SkScalar y, SkScalar scale, bool applyVM) { + + // If the glyph is too large we fall back to paths + if (glyph->fTooLargeForAtlas) { + this->appendLargeGlyph(glyph, scaler, skGlyph, x, y, scale, applyVM); + return; + } + + Run& run = fRuns[runIndex]; + GrMaskFormat format = glyph->fMaskFormat; + + Run::SubRunInfo* subRun = &run.fSubRunInfo.back(); + if (run.fInitialized && subRun->maskFormat() != format) { + subRun = &run.push_back(); + subRun->setStrike(strike); + } else if (!run.fInitialized) { + subRun->setStrike(strike); + } + + run.fInitialized = true; + + size_t vertexStride = GetVertexStride(format); + + subRun->setMaskFormat(format); + + run.fVertexBounds.joinNonEmptyArg(positions); + subRun->setColor(color); + + intptr_t vertex = reinterpret_cast(this->fVertices + subRun->vertexEndIndex()); + + if (kARGB_GrMaskFormat != glyph->fMaskFormat) { + // V0 + SkPoint* position = reinterpret_cast(vertex); + position->set(positions.fLeft, positions.fTop); + SkColor* colorPtr = reinterpret_cast(vertex + sizeof(SkPoint)); + *colorPtr = color; + vertex += vertexStride; + + // V1 + position = reinterpret_cast(vertex); + position->set(positions.fLeft, positions.fBottom); + colorPtr = reinterpret_cast(vertex + sizeof(SkPoint)); + *colorPtr = color; + vertex += vertexStride; + + // V2 + position = reinterpret_cast(vertex); + position->set(positions.fRight, positions.fBottom); + colorPtr = reinterpret_cast(vertex + sizeof(SkPoint)); + *colorPtr = color; + vertex += vertexStride; + + // V3 + position = reinterpret_cast(vertex); + position->set(positions.fRight, positions.fTop); + colorPtr = reinterpret_cast(vertex + sizeof(SkPoint)); + *colorPtr = color; + } else { + // V0 + SkPoint* position = reinterpret_cast(vertex); + position->set(positions.fLeft, positions.fTop); + vertex += vertexStride; + + // V1 + position = reinterpret_cast(vertex); + position->set(positions.fLeft, positions.fBottom); + vertex += vertexStride; + + // V2 + position = reinterpret_cast(vertex); + position->set(positions.fRight, positions.fBottom); + vertex += vertexStride; + + // V3 + position = reinterpret_cast(vertex); + position->set(positions.fRight, positions.fTop); + } + subRun->appendVertices(vertexStride); + fGlyphs[subRun->glyphEndIndex()] = glyph; + subRun->glyphAppended(); +} + +void GrAtlasTextBlob::appendLargeGlyph(GrGlyph* glyph, GrFontScaler* scaler, const SkGlyph& skGlyph, + SkScalar x, SkScalar y, SkScalar scale, bool applyVM) { + if (nullptr == glyph->fPath) { + const SkPath* glyphPath = scaler->getGlyphPath(skGlyph); + if (!glyphPath) { + return; + } + + glyph->fPath = new SkPath(*glyphPath); + } + fBigGlyphs.push_back(GrAtlasTextBlob::BigGlyph(*glyph->fPath, x, y, scale, applyVM)); +} + +bool GrAtlasTextBlob::mustRegenerate(SkScalar* outTransX, SkScalar* outTransY, + const SkPaint& paint, + GrColor color, const SkMaskFilter::BlurRec& blurRec, + const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { + // If we have LCD text then our canonical color will be set to transparent, in this case we have + // to regenerate the blob on any color change + // We use the grPaint to get any color filter effects + if (fKey.fCanonicalColor == SK_ColorTRANSPARENT && + fPaintColor != color) { + return true; + } + + if (fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) { + return true; + } + + if (fViewMatrix.hasPerspective() && !fViewMatrix.cheapEqualTo(viewMatrix)) { + return true; + } + + // We only cache one masked version + if (fKey.fHasBlur && + (fBlurRec.fSigma != blurRec.fSigma || + fBlurRec.fStyle != blurRec.fStyle || + fBlurRec.fQuality != blurRec.fQuality)) { + return true; + } + + // Similarly, we only cache one version for each style + if (fKey.fStyle != SkPaint::kFill_Style && + (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() || + fStrokeInfo.fMiterLimit != paint.getStrokeMiter() || + fStrokeInfo.fJoin != paint.getStrokeJoin())) { + return true; + } + + // Mixed blobs must be regenerated. We could probably figure out a way to do integer scrolls + // for mixed blobs if this becomes an issue. + if (this->hasBitmap() && this->hasDistanceField()) { + // Identical viewmatrices and we can reuse in all cases + if (fViewMatrix.cheapEqualTo(viewMatrix) && x == fX && y == fY) { + return false; + } + return true; + } + + if (this->hasBitmap()) { + if (fViewMatrix.getScaleX() != viewMatrix.getScaleX() || + fViewMatrix.getScaleY() != viewMatrix.getScaleY() || + fViewMatrix.getSkewX() != viewMatrix.getSkewX() || + fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { + return true; + } + + // We can update the positions in the cachedtextblobs without regenerating the whole blob, + // but only for integer translations. + // This cool bit of math will determine the necessary translation to apply to the already + // generated vertex coordinates to move them to the correct position + SkScalar transX = viewMatrix.getTranslateX() + + viewMatrix.getScaleX() * (x - fX) + + viewMatrix.getSkewX() * (y - fY) - + fViewMatrix.getTranslateX(); + SkScalar transY = viewMatrix.getTranslateY() + + viewMatrix.getSkewY() * (x - fX) + + viewMatrix.getScaleY() * (y - fY) - + fViewMatrix.getTranslateY(); + if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY) ) { + return true; + } + + (*outTransX) = transX; + (*outTransY) = transY; + } else if (this->hasDistanceField()) { + // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different + // distance field being generated, so we have to regenerate in those cases + SkScalar newMaxScale = viewMatrix.getMaxScale(); + SkScalar oldMaxScale = fViewMatrix.getMaxScale(); + SkScalar scaleAdjust = newMaxScale / oldMaxScale; + if (scaleAdjust < fMaxMinScale || scaleAdjust > fMinMaxScale) { + return true; + } + + (*outTransX) = x - fX; + (*outTransY) = y - fY; + } + + + // If we can reuse the blob, then make sure we update the blob's viewmatrix, and x/y + // offsets. Note, we offset the vertex bounds right before flushing + fViewMatrix = viewMatrix; + fX = x; + fY = y; + + // It is possible that a blob has neither distanceField nor bitmaptext. This is in the case + // when all of the runs inside the blob are drawn as paths. In this case, we always regenerate + // the blob anyways at flush time, so no need to regenerate explicitly + return false; +} + +GrDrawBatch* GrAtlasTextBlob::createBatch(const Run::SubRunInfo& info, + int glyphCount, int run, int subRun, + GrColor color, SkScalar transX, SkScalar transY, + const SkPaint& skPaint, const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + GrBatchFontCache* cache) { + GrMaskFormat format = info.maskFormat(); + GrColor subRunColor; + if (kARGB_GrMaskFormat == format) { + uint8_t paintAlpha = skPaint.getAlpha(); + subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha); + } else { + subRunColor = color; + } + + GrAtlasTextBatch* batch; + if (info.drawAsDistanceFields()) { + SkColor filteredColor; + SkColorFilter* colorFilter = skPaint.getColorFilter(); + if (colorFilter) { + filteredColor = colorFilter->filterColor(skPaint.getColor()); + } else { + filteredColor = skPaint.getColor(); + } + bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry()); + batch = GrAtlasTextBatch::CreateDistanceField(glyphCount, cache, + distanceAdjustTable, filteredColor, + info.hasUseLCDText(), useBGR); + } else { + batch = GrAtlasTextBatch::CreateBitmap(format, glyphCount, cache); + } + GrAtlasTextBatch::Geometry& geometry = batch->geometry(); + geometry.fBlob = SkRef(this); + geometry.fRun = run; + geometry.fSubRun = subRun; + geometry.fColor = subRunColor; + geometry.fTransX = transX; + geometry.fTransY = transY; + batch->init(); + + return batch; +} + +inline +void GrAtlasTextBlob::flushRun(GrDrawContext* dc, GrPipelineBuilder* pipelineBuilder, + int run, GrColor color, + SkScalar transX, SkScalar transY, + const SkPaint& skPaint, const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + GrBatchFontCache* cache) { + for (int subRun = 0; subRun < fRuns[run].fSubRunInfo.count(); subRun++) { + const Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun]; + int glyphCount = info.glyphCount(); + if (0 == glyphCount) { + continue; + } + + SkAutoTUnref batch(this->createBatch(info, glyphCount, run, + subRun, color, transX, transY, + skPaint, props, + distanceAdjustTable, cache)); + dc->drawBatch(pipelineBuilder, batch); + } +} + +void GrAtlasTextBlob::flushBigGlyphs(GrContext* context, GrDrawContext* dc, + const GrClip& clip, const SkPaint& skPaint, + SkScalar transX, SkScalar transY, + const SkIRect& clipBounds) { + for (int i = 0; i < fBigGlyphs.count(); i++) { + GrAtlasTextBlob::BigGlyph& bigGlyph = fBigGlyphs[i]; + bigGlyph.fVx += transX; + bigGlyph.fVy += transY; + SkMatrix ctm; + ctm.setScale(bigGlyph.fScale, bigGlyph.fScale); + ctm.postTranslate(bigGlyph.fVx, bigGlyph.fVy); + if (bigGlyph.fApplyVM) { + ctm.postConcat(fViewMatrix); + } + + GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, bigGlyph.fPath, + skPaint, ctm, nullptr, clipBounds, false); + } +} + +void GrAtlasTextBlob::flushRunAsPaths(GrContext* context, GrDrawContext* dc, + const SkSurfaceProps& props, + const SkTextBlobRunIterator& it, + const GrClip& clip, const SkPaint& skPaint, + SkDrawFilter* drawFilter, const SkMatrix& viewMatrix, + const SkIRect& clipBounds, SkScalar x, SkScalar y) { + SkPaint runPaint = skPaint; + + size_t textLen = it.glyphCount() * sizeof(uint16_t); + const SkPoint& offset = it.offset(); + + it.applyFontToPaint(&runPaint); + + if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) { + return; + } + + runPaint.setFlags(GrTextContext::FilterTextFlags(props, runPaint)); + + switch (it.positioning()) { + case SkTextBlob::kDefault_Positioning: + GrTextUtils::DrawTextAsPath(context, dc, clip, runPaint, viewMatrix, + (const char *)it.glyphs(), + textLen, x + offset.x(), y + offset.y(), clipBounds); + break; + case SkTextBlob::kHorizontal_Positioning: + GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, runPaint, viewMatrix, + (const char*)it.glyphs(), + textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), + clipBounds); + break; + case SkTextBlob::kFull_Positioning: + GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, runPaint, viewMatrix, + (const char*)it.glyphs(), + textLen, it.pos(), 2, SkPoint::Make(x, y), clipBounds); + break; + } +} + +void GrAtlasTextBlob::flushCached(GrContext* context, + GrDrawContext* dc, + const SkTextBlob* blob, + const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + const SkPaint& skPaint, + const GrPaint& grPaint, + SkDrawFilter* drawFilter, + const GrClip& clip, + const SkMatrix& viewMatrix, + const SkIRect& clipBounds, + SkScalar x, SkScalar y, + SkScalar transX, SkScalar transY) { + // We loop through the runs of the blob, flushing each. If any run is too large, then we flush + // it as paths + GrPipelineBuilder pipelineBuilder(grPaint, dc->accessRenderTarget(), clip); + + GrColor color = grPaint.getColor(); + + SkTextBlobRunIterator it(blob); + for (int run = 0; !it.done(); it.next(), run++) { + if (fRuns[run].fDrawAsPaths) { + this->flushRunAsPaths(context, dc, props, it, clip, skPaint, + drawFilter, viewMatrix, clipBounds, x, y); + continue; + } + fRuns[run].fVertexBounds.offset(transX, transY); + this->flushRun(dc, &pipelineBuilder, run, color, + transX, transY, skPaint, props, + distanceAdjustTable, context->getBatchFontCache()); + } + + // Now flush big glyphs + this->flushBigGlyphs(context, dc, clip, skPaint, transX, transY, clipBounds); +} + +void GrAtlasTextBlob::flushThrowaway(GrContext* context, + GrDrawContext* dc, + const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + const SkPaint& skPaint, + const GrPaint& grPaint, + const GrClip& clip, + const SkIRect& clipBounds) { + GrPipelineBuilder pipelineBuilder(grPaint, dc->accessRenderTarget(), clip); + + GrColor color = grPaint.getColor(); + for (int run = 0; run < fRunCount; run++) { + this->flushRun(dc, &pipelineBuilder, run, color, 0, 0, skPaint, props, + distanceAdjustTable, context->getBatchFontCache()); + } + + // Now flush big glyphs + this->flushBigGlyphs(context, dc, clip, skPaint, 0, 0, clipBounds); +} + + +// TODO get this code building again +#ifdef CACHE_SANITY_CHECK +void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlob& r) { + SkASSERT(l.fSize == r.fSize); + SkASSERT(l.fPool == r.fPool); + + SkASSERT(l.fBlurRec.fSigma == r.fBlurRec.fSigma); + SkASSERT(l.fBlurRec.fStyle == r.fBlurRec.fStyle); + SkASSERT(l.fBlurRec.fQuality == r.fBlurRec.fQuality); + + SkASSERT(l.fStrokeInfo.fFrameWidth == r.fStrokeInfo.fFrameWidth); + SkASSERT(l.fStrokeInfo.fMiterLimit == r.fStrokeInfo.fMiterLimit); + SkASSERT(l.fStrokeInfo.fJoin == r.fStrokeInfo.fJoin); + + SkASSERT(l.fBigGlyphs.count() == r.fBigGlyphs.count()); + for (int i = 0; i < l.fBigGlyphs.count(); i++) { + const BigGlyph& lBigGlyph = l.fBigGlyphs[i]; + const BigGlyph& rBigGlyph = r.fBigGlyphs[i]; + + SkASSERT(lBigGlyph.fPath == rBigGlyph.fPath); + // We can't assert that these have the same translations + } + + SkASSERT(l.fKey == r.fKey); + SkASSERT(l.fViewMatrix.cheapEqualTo(r.fViewMatrix)); + SkASSERT(l.fPaintColor == r.fPaintColor); + SkASSERT(l.fMaxMinScale == r.fMaxMinScale); + SkASSERT(l.fMinMaxScale == r.fMinMaxScale); + SkASSERT(l.fTextType == r.fTextType); + + SkASSERT(l.fRunCount == r.fRunCount); + for (int i = 0; i < l.fRunCount; i++) { + const Run& lRun = l.fRuns[i]; + const Run& rRun = r.fRuns[i]; + + if (lRun.fStrike.get()) { + SkASSERT(rRun.fStrike.get()); + SkASSERT(GrBatchTextStrike::GetKey(*lRun.fStrike) == + GrBatchTextStrike::GetKey(*rRun.fStrike)); + + } else { + SkASSERT(!rRun.fStrike.get()); + } + + if (lRun.fTypeface.get()) { + SkASSERT(rRun.fTypeface.get()); + SkASSERT(SkTypeface::Equal(lRun.fTypeface, rRun.fTypeface)); + } else { + SkASSERT(!rRun.fTypeface.get()); + } + + // We offset bounds right before flush time so they will not be correct here + //SkASSERT(lRun.fVertexBounds == rRun.fVertexBounds); + + SkASSERT(lRun.fDescriptor.getDesc()); + SkASSERT(rRun.fDescriptor.getDesc()); + SkASSERT(lRun.fDescriptor.getDesc()->equals(*rRun.fDescriptor.getDesc())); + + if (lRun.fOverrideDescriptor.get()) { + SkASSERT(lRun.fOverrideDescriptor->getDesc()); + SkASSERT(rRun.fOverrideDescriptor.get() && rRun.fOverrideDescriptor->getDesc());; + SkASSERT(lRun.fOverrideDescriptor->getDesc()->equals( + *rRun.fOverrideDescriptor->getDesc())); + } else { + SkASSERT(!rRun.fOverrideDescriptor.get()); + } + + // color can be changed + //SkASSERT(lRun.fColor == rRun.fColor); + SkASSERT(lRun.fInitialized == rRun.fInitialized); + SkASSERT(lRun.fDrawAsPaths == rRun.fDrawAsPaths); + + SkASSERT(lRun.fSubRunInfo.count() == rRun.fSubRunInfo.count()); + for(int j = 0; j < lRun.fSubRunInfo.count(); j++) { + const Run::SubRunInfo& lSubRun = lRun.fSubRunInfo[j]; + const Run::SubRunInfo& rSubRun = rRun.fSubRunInfo[j]; + + SkASSERT(lSubRun.fVertexStartIndex == rSubRun.fVertexStartIndex); + SkASSERT(lSubRun.fVertexEndIndex == rSubRun.fVertexEndIndex); + SkASSERT(lSubRun.fGlyphStartIndex == rSubRun.fGlyphStartIndex); + SkASSERT(lSubRun.fGlyphEndIndex == rSubRun.fGlyphEndIndex); + SkASSERT(lSubRun.fTextRatio == rSubRun.fTextRatio); + SkASSERT(lSubRun.fMaskFormat == rSubRun.fMaskFormat); + SkASSERT(lSubRun.fDrawAsDistanceFields == rSubRun.fDrawAsDistanceFields); + SkASSERT(lSubRun.fUseLCDText == rSubRun.fUseLCDText); + + //We can't compare the bulk use tokens with this method + /* + SkASSERT(lSubRun.fBulkUseToken.fPlotsToUpdate.count() == + rSubRun.fBulkUseToken.fPlotsToUpdate.count()); + SkASSERT(lSubRun.fBulkUseToken.fPlotAlreadyUpdated == + rSubRun.fBulkUseToken.fPlotAlreadyUpdated); + for (int k = 0; k < lSubRun.fBulkUseToken.fPlotsToUpdate.count(); k++) { + SkASSERT(lSubRun.fBulkUseToken.fPlotsToUpdate[k] == + rSubRun.fBulkUseToken.fPlotsToUpdate[k]); + }*/ + } + } +} + +#endif diff --git a/gfx/skia/skia/src/gpu/GrAtlasTextBlob.h b/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.h similarity index 52% rename from gfx/skia/skia/src/gpu/GrAtlasTextBlob.h rename to gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.h index 6ea86627001..c24dabd010c 100644 --- a/gfx/skia/skia/src/gpu/GrAtlasTextBlob.h +++ b/gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.h @@ -11,12 +11,18 @@ #include "GrBatchAtlas.h" #include "GrBatchFontCache.h" #include "GrColor.h" +#include "GrMemoryPool.h" #include "SkDescriptor.h" #include "SkMaskFilter.h" -#include "GrMemoryPool.h" #include "SkSurfaceProps.h" #include "SkTInternalLList.h" +struct GrDistanceFieldAdjustTable; +class GrTextContext; +class SkDrawFilter; +class SkTextBlob; +class SkTextBlobRunIterator; + // With this flag enabled, the GrAtlasTextContext will, as a sanity check, regenerate every blob // that comes in to verify the integrity of its cache //#define CACHE_SANITY_CHECK // VERY SLOW @@ -35,7 +41,8 @@ * * *WARNING* If you add new fields to this struct, then you may need to to update AssertEqual */ -struct GrAtlasTextBlob : public SkRefCnt { +class GrAtlasTextBlob : public SkNVRefCnt { +public: SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob); /* @@ -63,8 +70,7 @@ struct GrAtlasTextBlob : public SkRefCnt { */ struct Run { Run() - : fColor(GrColor_ILLEGAL) - , fInitialized(false) + : fInitialized(false) , fDrawAsPaths(false) { fVertexBounds.setLargestInverted(); // To ensure we always have one subrun, we push back a fresh run here @@ -77,7 +83,7 @@ struct GrAtlasTextBlob : public SkRefCnt { , fVertexEndIndex(0) , fGlyphStartIndex(0) , fGlyphEndIndex(0) - , fTextRatio(1.0f) + , fColor(GrColor_ILLEGAL) , fMaskFormat(kA8_GrMaskFormat) , fDrawAsDistanceFields(false) , fUseLCDText(false) {} @@ -89,18 +95,52 @@ struct GrAtlasTextBlob : public SkRefCnt { , fVertexEndIndex(that.fVertexEndIndex) , fGlyphStartIndex(that.fGlyphStartIndex) , fGlyphEndIndex(that.fGlyphEndIndex) - , fTextRatio(that.fTextRatio) + , fColor(that.fColor) , fMaskFormat(that.fMaskFormat) , fDrawAsDistanceFields(that.fDrawAsDistanceFields) , fUseLCDText(that.fUseLCDText) { } - // Distance field text cannot draw coloremoji, and so has to fall back. However, - // though the distance field text and the coloremoji may share the same run, they - // will have different descriptors. If fOverrideDescriptor is non-nullptr, then it - // will be used in place of the run's descriptor to regen texture coords - // TODO we could have a descriptor cache, it would reduce the size of these blobs - // significantly, and then the subrun could just have a refed pointer to the - // correct descriptor. + + // TODO when this object is more internal, drop the privacy + void resetBulkUseToken() { fBulkUseToken.reset(); } + GrBatchAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; } + void setStrike(GrBatchTextStrike* strike) { fStrike.reset(SkRef(strike)); } + GrBatchTextStrike* strike() const { return fStrike.get(); } + + void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;} + uint64_t atlasGeneration() const { return fAtlasGeneration; } + + size_t byteCount() const { return fVertexEndIndex - fVertexStartIndex; } + size_t vertexStartIndex() const { return fVertexStartIndex; } + size_t vertexEndIndex() const { return fVertexEndIndex; } + void appendVertices(size_t vertexStride) { + fVertexEndIndex += vertexStride * kVerticesPerGlyph; + } + + uint32_t glyphCount() const { return fGlyphEndIndex - fGlyphStartIndex; } + uint32_t glyphStartIndex() const { return fGlyphStartIndex; } + uint32_t glyphEndIndex() const { return fGlyphEndIndex; } + void glyphAppended() { fGlyphEndIndex++; } + void setColor(GrColor color) { fColor = color; } + GrColor color() const { return fColor; } + void setMaskFormat(GrMaskFormat format) { fMaskFormat = format; } + GrMaskFormat maskFormat() const { return fMaskFormat; } + + void setAsSuccessor(const SubRunInfo& prev) { + fGlyphStartIndex = prev.glyphEndIndex(); + fGlyphEndIndex = prev.glyphEndIndex(); + + fVertexStartIndex = prev.vertexEndIndex(); + fVertexEndIndex = prev.vertexEndIndex(); + } + + // df properties + void setUseLCDText(bool useLCDText) { fUseLCDText = useLCDText; } + bool hasUseLCDText() const { return fUseLCDText; } + void setDrawAsDistanceFields() { fDrawAsDistanceFields = true; } + bool drawAsDistanceFields() const { return fDrawAsDistanceFields; } + + private: GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken; SkAutoTUnref fStrike; uint64_t fAtlasGeneration; @@ -108,7 +148,7 @@ struct GrAtlasTextBlob : public SkRefCnt { size_t fVertexEndIndex; uint32_t fGlyphStartIndex; uint32_t fGlyphEndIndex; - SkScalar fTextRatio; // df property + GrColor fColor; GrMaskFormat fMaskFormat; bool fDrawAsDistanceFields; // df property bool fUseLCDText; // df property @@ -117,13 +157,9 @@ struct GrAtlasTextBlob : public SkRefCnt { SubRunInfo& push_back() { // Forward glyph / vertex information to seed the new sub run SubRunInfo& newSubRun = fSubRunInfo.push_back(); - SubRunInfo& prevSubRun = fSubRunInfo.fromBack(1); + const SubRunInfo& prevSubRun = fSubRunInfo.fromBack(1); - newSubRun.fGlyphStartIndex = prevSubRun.fGlyphEndIndex; - newSubRun.fGlyphEndIndex = prevSubRun.fGlyphEndIndex; - - newSubRun.fVertexStartIndex = prevSubRun.fVertexEndIndex; - newSubRun.fVertexEndIndex = prevSubRun.fVertexEndIndex; + newSubRun.setAsSuccessor(prevSubRun); return newSubRun; } static const int kMinSubRuns = 1; @@ -131,8 +167,12 @@ struct GrAtlasTextBlob : public SkRefCnt { SkRect fVertexBounds; SkSTArray fSubRunInfo; SkAutoDescriptor fDescriptor; + + // Distance field text cannot draw coloremoji, and so has to fall back. However, + // though the distance field text and the coloremoji may share the same run, they + // will have different descriptors. If fOverrideDescriptor is non-nullptr, then it + // will be used in place of the run's descriptor to regen texture coords SkAutoTDelete fOverrideDescriptor; // df properties - GrColor fColor; bool fInitialized; bool fDrawAsPaths; }; @@ -208,7 +248,7 @@ struct GrAtlasTextBlob : public SkRefCnt { , fMinMaxScale(SK_ScalarMax) , fTextType(0) {} - ~GrAtlasTextBlob() override { + ~GrAtlasTextBlob() { for (int i = 0; i < fRunCount; i++) { fRuns[i].~Run(); } @@ -241,10 +281,114 @@ struct GrAtlasTextBlob : public SkRefCnt { void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; } void setHasBitmap() { fTextType |= kHasBitmap_TextType; } + void push_back_run(int currRun) { + SkASSERT(currRun < fRunCount); + if (currRun > 0) { + Run::SubRunInfo& newRun = fRuns[currRun].fSubRunInfo.back(); + Run::SubRunInfo& lastRun = fRuns[currRun - 1].fSubRunInfo.back(); + newRun.setAsSuccessor(lastRun); + } + } + + SkGlyphCache* setupCache(int runIndex, + const SkSurfaceProps& props, + const SkPaint& skPaint, + const SkMatrix* viewMatrix, + bool noGamma); + + // Appends a glyph to the blob. If the glyph is too large, the glyph will be appended + // as a path. + void appendGlyph(int runIndex, + const SkRect& positions, + GrColor color, + GrBatchTextStrike* strike, + GrGlyph* glyph, + GrFontScaler* scaler, const SkGlyph& skGlyph, + SkScalar x, SkScalar y, SkScalar scale, bool applyVM); + + static size_t GetVertexStride(GrMaskFormat maskFormat) { + switch (maskFormat) { + case kA8_GrMaskFormat: + return kGrayTextVASize; + case kARGB_GrMaskFormat: + return kColorTextVASize; + default: + return kLCDTextVASize; + } + } + + bool mustRegenerate(SkScalar* outTransX, SkScalar* outTransY, const SkPaint& paint, + GrColor color, const SkMaskFilter::BlurRec& blurRec, + const SkMatrix& viewMatrix, SkScalar x, SkScalar y); + + // flush a GrAtlasTextBlob associated with a SkTextBlob + void flushCached(GrContext* context, + GrDrawContext* dc, + const SkTextBlob* blob, + const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + const SkPaint& skPaint, + const GrPaint& grPaint, + SkDrawFilter* drawFilter, + const GrClip& clip, + const SkMatrix& viewMatrix, + const SkIRect& clipBounds, + SkScalar x, SkScalar y, + SkScalar transX, SkScalar transY); + + // flush a throwaway GrAtlasTextBlob *not* associated with an SkTextBlob + void flushThrowaway(GrContext* context, + GrDrawContext* dc, + const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + const SkPaint& skPaint, + const GrPaint& grPaint, + const GrClip& clip, + const SkIRect& clipBounds); + + // position + local coord + static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); + static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16); + static const size_t kLCDTextVASize = kGrayTextVASize; + static const int kVerticesPerGlyph = 4; + #ifdef CACHE_SANITY_CHECK static void AssertEqual(const GrAtlasTextBlob&, const GrAtlasTextBlob&); size_t fSize; #endif + + // We'd like to inline this and make it private, but there is some test code which calls it. + // TODO refactor this + GrDrawBatch* createBatch(const Run::SubRunInfo& info, + int glyphCount, int run, int subRun, + GrColor color, SkScalar transX, SkScalar transY, + const SkPaint& skPaint, const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + GrBatchFontCache* cache); + +private: + void appendLargeGlyph(GrGlyph* glyph, GrFontScaler* scaler, const SkGlyph& skGlyph, + SkScalar x, SkScalar y, SkScalar scale, bool applyVM); + + inline void flushRun(GrDrawContext* dc, GrPipelineBuilder* pipelineBuilder, + int run, GrColor color, + SkScalar transX, SkScalar transY, + const SkPaint& skPaint, const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + GrBatchFontCache* cache); + + void flushBigGlyphs(GrContext* context, GrDrawContext* dc, + const GrClip& clip, const SkPaint& skPaint, + SkScalar transX, SkScalar transY, + const SkIRect& clipBounds); + + void flushRunAsPaths(GrContext* context, + GrDrawContext* dc, + const SkSurfaceProps& props, + const SkTextBlobRunIterator& it, + const GrClip& clip, const SkPaint& skPaint, + SkDrawFilter* drawFilter, const SkMatrix& viewMatrix, + const SkIRect& clipBounds, SkScalar x, SkScalar y); }; #endif diff --git a/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.cpp b/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.cpp new file mode 100644 index 00000000000..37cd53d0806 --- /dev/null +++ b/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.cpp @@ -0,0 +1,774 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "GrAtlasTextContext.h" + +#include "GrDrawContext.h" +#include "GrDrawTarget.h" +#include "GrFontScaler.h" +#include "GrStrokeInfo.h" +#include "GrTextBlobCache.h" +#include "GrTexturePriv.h" +#include "GrTextUtils.h" +#include "GrVertexBuffer.h" + +#include "SkAutoKern.h" +#include "SkColorPriv.h" +#include "SkColorFilter.h" +#include "SkDistanceFieldGen.h" +#include "SkDraw.h" +#include "SkDrawFilter.h" +#include "SkDrawProcs.h" +#include "SkFindAndPlaceGlyph.h" +#include "SkGlyphCache.h" +#include "SkGpuDevice.h" +#include "SkGrPriv.h" +#include "SkPath.h" +#include "SkRTConf.h" +#include "SkStrokeRec.h" +#include "SkTextBlob.h" +#include "SkTextMapStateProc.h" + +#include "batches/GrAtlasTextBatch.h" + +namespace { +static const int kMinDFFontSize = 18; +static const int kSmallDFFontSize = 32; +static const int kSmallDFFontLimit = 32; +static const int kMediumDFFontSize = 72; +static const int kMediumDFFontLimit = 72; +static const int kLargeDFFontSize = 162; +#ifdef SK_BUILD_FOR_ANDROID +static const int kLargeDFFontLimit = 384; +#else +static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; +#endif +}; + +GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps& surfaceProps) + : INHERITED(context, surfaceProps) + , fDistanceAdjustTable(new GrDistanceFieldAdjustTable) { + // We overallocate vertices in our textblobs based on the assumption that A8 has the greatest + // vertexStride + static_assert(GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kColorTextVASize && + GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kLCDTextVASize, + "vertex_attribute_changed"); + fCurrStrike = nullptr; + fCache = context->getTextBlobCache(); +} + + +GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, + const SkSurfaceProps& surfaceProps) { + return new GrAtlasTextContext(context, surfaceProps); +} + +bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, const SkMatrix& viewMatrix) { + return this->canDrawAsDistanceFields(skPaint, viewMatrix) || + !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); +} + +GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd) { + GrColor canonicalColor = paint.computeLuminanceColor(); + if (lcd) { + // This is the correct computation, but there are tons of cases where LCD can be overridden. + // For now we just regenerate if any run in a textblob has LCD. + // TODO figure out where all of these overrides are and see if we can incorporate that logic + // at a higher level *OR* use sRGB + SkASSERT(false); + //canonicalColor = SkMaskGamma::CanonicalColor(canonicalColor); + } else { + // A8, though can have mixed BMP text but it shouldn't matter because BMP text won't have + // gamma corrected masks anyways, nor color + U8CPU lum = SkComputeLuminance(SkColorGetR(canonicalColor), + SkColorGetG(canonicalColor), + SkColorGetB(canonicalColor)); + // reduce to our finite number of bits + canonicalColor = SkMaskGamma::CanonicalColor(SkColorSetRGB(lum, lum, lum)); + } + return canonicalColor; +} + +// TODO if this function ever shows up in profiling, then we can compute this value when the +// textblob is being built and cache it. However, for the time being textblobs mostly only have 1 +// run so this is not a big deal to compute here. +bool GrAtlasTextContext::HasLCD(const SkTextBlob* blob) { + SkTextBlobRunIterator it(blob); + for (; !it.done(); it.next()) { + if (it.isLCD()) { + return true; + } + } + return false; +} + +void GrAtlasTextContext::drawTextBlob(GrDrawContext* dc, + const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, const SkTextBlob* blob, + SkScalar x, SkScalar y, + SkDrawFilter* drawFilter, const SkIRect& clipBounds) { + // If we have been abandoned, then don't draw + if (fContext->abandoned()) { + return; + } + + SkAutoTUnref cacheBlob; + SkMaskFilter::BlurRec blurRec; + GrAtlasTextBlob::Key key; + // It might be worth caching these things, but its not clear at this time + // TODO for animated mask filters, this will fill up our cache. We need a safeguard here + const SkMaskFilter* mf = skPaint.getMaskFilter(); + bool canCache = !(skPaint.getPathEffect() || + (mf && !mf->asABlur(&blurRec)) || + drawFilter); + + if (canCache) { + bool hasLCD = HasLCD(blob); + + // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry + SkPixelGeometry pixelGeometry = hasLCD ? fSurfaceProps.pixelGeometry() : + kUnknown_SkPixelGeometry; + + // TODO we want to figure out a way to be able to use the canonical color on LCD text, + // see the note on ComputeCanonicalColor above. We pick a dummy value for LCD text to + // ensure we always match the same key + GrColor canonicalColor = hasLCD ? SK_ColorTRANSPARENT : + ComputeCanonicalColor(skPaint, hasLCD); + + key.fPixelGeometry = pixelGeometry; + key.fUniqueID = blob->uniqueID(); + key.fStyle = skPaint.getStyle(); + key.fHasBlur = SkToBool(mf); + key.fCanonicalColor = canonicalColor; + cacheBlob.reset(SkSafeRef(fCache->find(key))); + } + + SkScalar transX = 0.f; + SkScalar transY = 0.f; + + // Though for the time being runs in the textblob can override the paint, they only touch font + // info. + GrPaint grPaint; + if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &grPaint)) { + return; + } + + if (cacheBlob) { + if (cacheBlob->mustRegenerate(&transX, &transY, skPaint, grPaint.getColor(), blurRec, + viewMatrix, x, y)) { + // We have to remake the blob because changes may invalidate our masks. + // TODO we could probably get away reuse most of the time if the pointer is unique, + // but we'd have to clear the subrun information + fCache->remove(cacheBlob); + cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint, + GrAtlasTextBlob::kGrayTextVASize))); + this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, + blob, x, y, drawFilter, clip); + } else { + fCache->makeMRU(cacheBlob); +#ifdef CACHE_SANITY_CHECK + { + int glyphCount = 0; + int runCount = 0; + GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob); + SkAutoTUnref sanityBlob(fCache->createBlob(glyphCount, runCount, + kGrayTextVASize)); + GrTextBlobCache::SetupCacheBlobKey(sanityBlob, key, blurRec, skPaint); + this->regenerateTextBlob(sanityBlob, skPaint, grPaint.getColor(), viewMatrix, + blob, x, y, drawFilter, clip); + GrAtlasTextBlob::AssertEqual(*sanityBlob, *cacheBlob); + } + +#endif + } + } else { + if (canCache) { + cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint, + GrAtlasTextBlob::kGrayTextVASize))); + } else { + cacheBlob.reset(fCache->createBlob(blob, GrAtlasTextBlob::kGrayTextVASize)); + } + this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, + blob, x, y, drawFilter, clip); + } + + cacheBlob->flushCached(fContext, dc, blob, fSurfaceProps, fDistanceAdjustTable, skPaint, + grPaint, drawFilter, clip, viewMatrix, clipBounds, x, y, transX, transY); +} + +inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, + const SkMatrix& viewMatrix) { + // TODO: support perspective (need getMaxScale replacement) + if (viewMatrix.hasPerspective()) { + return false; + } + + SkScalar maxScale = viewMatrix.getMaxScale(); + SkScalar scaledTextSize = maxScale*skPaint.getTextSize(); + // Hinted text looks far better at small resolutions + // Scaling up beyond 2x yields undesireable artifacts + if (scaledTextSize < kMinDFFontSize || scaledTextSize > kLargeDFFontLimit) { + return false; + } + + bool useDFT = fSurfaceProps.isUseDeviceIndependentFonts(); +#if SK_FORCE_DISTANCE_FIELD_TEXT + useDFT = true; +#endif + + if (!useDFT && scaledTextSize < kLargeDFFontSize) { + return false; + } + + // rasterizers and mask filters modify alpha, which doesn't + // translate well to distance + if (skPaint.getRasterizer() || skPaint.getMaskFilter() || + !fContext->caps()->shaderCaps()->shaderDerivativeSupport()) { + return false; + } + + // TODO: add some stroking support + if (skPaint.getStyle() != SkPaint::kFill_Style) { + return false; + } + + return true; +} + +void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, + const SkPaint& skPaint, GrColor color, + const SkMatrix& viewMatrix, + const SkTextBlob* blob, SkScalar x, SkScalar y, + SkDrawFilter* drawFilter, + const GrClip& clip) { + // The color here is the GrPaint color, and it is used to determine whether we + // have to regenerate LCD text blobs. + // We use this color vs the SkPaint color because it has the colorfilter applied. + cacheBlob->fPaintColor = color; + cacheBlob->fViewMatrix = viewMatrix; + cacheBlob->fX = x; + cacheBlob->fY = y; + + // Regenerate textblob + SkPaint runPaint = skPaint; + SkTextBlobRunIterator it(blob); + for (int run = 0; !it.done(); it.next(), run++) { + int glyphCount = it.glyphCount(); + size_t textLen = glyphCount * sizeof(uint16_t); + const SkPoint& offset = it.offset(); + // applyFontToPaint() always overwrites the exact same attributes, + // so it is safe to not re-seed the paint for this reason. + it.applyFontToPaint(&runPaint); + + if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) { + // A false return from filter() means we should abort the current draw. + runPaint = skPaint; + continue; + } + + runPaint.setFlags(FilterTextFlags(fSurfaceProps, runPaint)); + + cacheBlob->push_back_run(run); + + if (this->canDrawAsDistanceFields(runPaint, viewMatrix)) { + cacheBlob->setHasDistanceField(); + SkPaint dfPaint = runPaint; + SkScalar textRatio; + this->initDistanceFieldPaint(cacheBlob, &dfPaint, &textRatio, viewMatrix); + Run& runIdx = cacheBlob->fRuns[run]; + PerSubRunInfo& subRun = runIdx.fSubRunInfo.back(); + subRun.setUseLCDText(runPaint.isLCDRenderText()); + subRun.setDrawAsDistanceFields(); + + switch (it.positioning()) { + case SkTextBlob::kDefault_Positioning: { + this->internalDrawDFText(cacheBlob, run, dfPaint, color, viewMatrix, + (const char *)it.glyphs(), textLen, + x + offset.x(), y + offset.y(), textRatio, runPaint); + break; + } + case SkTextBlob::kHorizontal_Positioning: { + SkPoint dfOffset = SkPoint::Make(x, y + offset.y()); + this->internalDrawDFPosText(cacheBlob, run, dfPaint, color, viewMatrix, + (const char*)it.glyphs(), textLen, it.pos(), + 1, dfOffset, textRatio, + runPaint); + break; + } + case SkTextBlob::kFull_Positioning: { + SkPoint dfOffset = SkPoint::Make(x, y); + this->internalDrawDFPosText(cacheBlob, run, dfPaint, color, viewMatrix, + (const char*)it.glyphs(), textLen, it.pos(), + 2, dfOffset, textRatio, runPaint); + break; + } + } + } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { + cacheBlob->fRuns[run].fDrawAsPaths = true; + } else { + cacheBlob->setHasBitmap(); + switch (it.positioning()) { + case SkTextBlob::kDefault_Positioning: + GrTextUtils::DrawBmpText(cacheBlob, run, fContext->getBatchFontCache(), + fSurfaceProps, runPaint, color, viewMatrix, + (const char *)it.glyphs(), textLen, + x + offset.x(), y + offset.y()); + break; + case SkTextBlob::kHorizontal_Positioning: + GrTextUtils::DrawBmpPosText(cacheBlob, run, fContext->getBatchFontCache(), + fSurfaceProps, runPaint, color, viewMatrix, + (const char*)it.glyphs(), textLen, it.pos(), 1, + SkPoint::Make(x, y + offset.y())); + break; + case SkTextBlob::kFull_Positioning: + GrTextUtils::DrawBmpPosText(cacheBlob, run, fContext->getBatchFontCache(), + fSurfaceProps, runPaint, color, viewMatrix, + (const char*)it.glyphs(), textLen, it.pos(), 2, + SkPoint::Make(x, y)); + break; + } + } + + if (drawFilter) { + // A draw filter may change the paint arbitrarily, so we must re-seed in this case. + runPaint = skPaint; + } + } +} + +inline void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob, + SkPaint* skPaint, + SkScalar* textRatio, + const SkMatrix& viewMatrix) { + // getMaxScale doesn't support perspective, so neither do we at the moment + SkASSERT(!viewMatrix.hasPerspective()); + SkScalar maxScale = viewMatrix.getMaxScale(); + SkScalar textSize = skPaint->getTextSize(); + SkScalar scaledTextSize = textSize; + // if we have non-unity scale, we need to choose our base text size + // based on the SkPaint's text size multiplied by the max scale factor + // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? + if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { + scaledTextSize *= maxScale; + } + + // We have three sizes of distance field text, and within each size 'bucket' there is a floor + // and ceiling. A scale outside of this range would require regenerating the distance fields + SkScalar dfMaskScaleFloor; + SkScalar dfMaskScaleCeil; + if (scaledTextSize <= kSmallDFFontLimit) { + dfMaskScaleFloor = kMinDFFontSize; + dfMaskScaleCeil = kSmallDFFontLimit; + *textRatio = textSize / kSmallDFFontSize; + skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize)); + } else if (scaledTextSize <= kMediumDFFontLimit) { + dfMaskScaleFloor = kSmallDFFontLimit; + dfMaskScaleCeil = kMediumDFFontLimit; + *textRatio = textSize / kMediumDFFontSize; + skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize)); + } else { + dfMaskScaleFloor = kMediumDFFontLimit; + dfMaskScaleCeil = kLargeDFFontLimit; + *textRatio = textSize / kLargeDFFontSize; + skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize)); + } + + // Because there can be multiple runs in the blob, we want the overall maxMinScale, and + // minMaxScale to make regeneration decisions. Specifically, we want the maximum minimum scale + // we can tolerate before we'd drop to a lower mip size, and the minimum maximum scale we can + // tolerate before we'd have to move to a large mip size. When we actually test these values + // we look at the delta in scale between the new viewmatrix and the old viewmatrix, and test + // against these values to decide if we can reuse or not(ie, will a given scale change our mip + // level) + SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScaleCeil); + blob->fMaxMinScale = SkMaxScalar(dfMaskScaleFloor / scaledTextSize, blob->fMaxMinScale); + blob->fMinMaxScale = SkMinScalar(dfMaskScaleCeil / scaledTextSize, blob->fMinMaxScale); + + skPaint->setLCDRenderText(false); + skPaint->setAutohinted(false); + skPaint->setHinting(SkPaint::kNormal_Hinting); + skPaint->setSubpixelText(true); +} + +inline void GrAtlasTextContext::fallbackDrawPosText(GrAtlasTextBlob* blob, + int runIndex, + GrColor color, + const SkPaint& skPaint, + const SkMatrix& viewMatrix, + const SkTDArray& fallbackTxt, + const SkTDArray& fallbackPos, + int scalarsPerPosition, + const SkPoint& offset) { + SkASSERT(fallbackTxt.count()); + blob->setHasBitmap(); + Run& run = blob->fRuns[runIndex]; + // Push back a new subrun to fill and set the override descriptor + run.push_back(); + run.fOverrideDescriptor.reset(new SkAutoDescriptor); + GrTextUtils::DrawBmpPosText(blob, runIndex, fContext->getBatchFontCache(), fSurfaceProps, + skPaint, color, viewMatrix, fallbackTxt.begin(), fallbackTxt.count(), + fallbackPos.begin(), scalarsPerPosition, offset); +} + +inline GrAtlasTextBlob* +GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, + const SkMatrix& viewMatrix, SkPaint* dfPaint, + SkScalar* textRatio) { + GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::kGrayTextVASize); + + *dfPaint = origPaint; + this->initDistanceFieldPaint(blob, dfPaint, textRatio, viewMatrix); + blob->fViewMatrix = viewMatrix; + Run& run = blob->fRuns[0]; + PerSubRunInfo& subRun = run.fSubRunInfo.back(); + subRun.setUseLCDText(origPaint.isLCDRenderText()); + subRun.setDrawAsDistanceFields(); + + return blob; +} + +inline GrAtlasTextBlob* +GrAtlasTextContext::createDrawTextBlob(const GrPaint& paint, const SkPaint& skPaint, + const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + SkScalar x, SkScalar y) { + int glyphCount = skPaint.countText(text, byteLength); + + GrAtlasTextBlob* blob; + if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { + SkPaint dfPaint; + SkScalar textRatio; + blob = this->setupDFBlob(glyphCount, skPaint, viewMatrix, &dfPaint, &textRatio); + + this->internalDrawDFText(blob, 0, dfPaint, paint.getColor(), viewMatrix, text, + byteLength, x, y, textRatio, skPaint); + } else { + blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::kGrayTextVASize); + blob->fViewMatrix = viewMatrix; + + GrTextUtils::DrawBmpText(blob, 0, fContext->getBatchFontCache(), fSurfaceProps, skPaint, + paint.getColor(), viewMatrix, text, byteLength, x, y); + } + return blob; +} + +inline GrAtlasTextBlob* +GrAtlasTextContext::createDrawPosTextBlob(const GrPaint& paint, const SkPaint& skPaint, + const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset) { + int glyphCount = skPaint.countText(text, byteLength); + + GrAtlasTextBlob* blob; + if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { + SkPaint dfPaint; + SkScalar textRatio; + blob = this->setupDFBlob(glyphCount, skPaint, viewMatrix, &dfPaint, &textRatio); + + this->internalDrawDFPosText(blob, 0, dfPaint, paint.getColor(), viewMatrix, text, + byteLength, pos, scalarsPerPosition, offset, textRatio, + skPaint); + } else { + blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::kGrayTextVASize); + blob->fViewMatrix = viewMatrix; + GrTextUtils::DrawBmpPosText(blob, 0, fContext->getBatchFontCache(), fSurfaceProps, skPaint, + paint.getColor(), viewMatrix, text, + byteLength, pos, scalarsPerPosition, offset); + } + return blob; +} + +void GrAtlasTextContext::onDrawText(GrDrawContext* dc, + const GrClip& clip, + const GrPaint& paint, const SkPaint& skPaint, + const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + SkScalar x, SkScalar y, const SkIRect& regionClipBounds) { + SkAutoTUnref blob( + this->createDrawTextBlob(paint, skPaint, viewMatrix, text, byteLength, x, y)); + blob->flushThrowaway(fContext, dc, fSurfaceProps, fDistanceAdjustTable, skPaint, paint, + clip, regionClipBounds); +} + +void GrAtlasTextContext::onDrawPosText(GrDrawContext* dc, + const GrClip& clip, + const GrPaint& paint, const SkPaint& skPaint, + const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset, const SkIRect& regionClipBounds) { + SkAutoTUnref blob( + this->createDrawPosTextBlob(paint, skPaint, viewMatrix, + text, byteLength, + pos, scalarsPerPosition, + offset)); + + blob->flushThrowaway(fContext, dc, fSurfaceProps, fDistanceAdjustTable, skPaint, paint, clip, + regionClipBounds); +} + +void GrAtlasTextContext::internalDrawDFText(GrAtlasTextBlob* blob, int runIndex, + const SkPaint& skPaint, GrColor color, + const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + SkScalar x, SkScalar y, + SkScalar textRatio, + const SkPaint& origPaint) { + SkASSERT(byteLength == 0 || text != nullptr); + + // nothing to draw + if (text == nullptr || byteLength == 0) { + return; + } + + SkDrawCacheProc glyphCacheProc = origPaint.getDrawCacheProc(); + SkAutoDescriptor desc; + origPaint.getScalerContextDescriptor(&desc, fSurfaceProps, nullptr, true); + SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(origPaint.getTypeface(), + desc.getDesc()); + + SkTArray positions; + + const char* textPtr = text; + SkFixed stopX = 0; + SkFixed stopY = 0; + SkFixed origin = 0; + switch (origPaint.getTextAlign()) { + case SkPaint::kRight_Align: origin = SK_Fixed1; break; + case SkPaint::kCenter_Align: origin = SK_FixedHalf; break; + case SkPaint::kLeft_Align: origin = 0; break; + } + + SkAutoKern autokern; + const char* stop = text + byteLength; + while (textPtr < stop) { + // don't need x, y here, since all subpixel variants will have the + // same advance + const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr, 0, 0); + + SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph); + positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width))); + + SkFixed height = glyph.fAdvanceY; + positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height))); + + stopX += width; + stopY += height; + } + SkASSERT(textPtr == stop); + + SkGlyphCache::AttachCache(origPaintCache); + + // now adjust starting point depending on alignment + SkScalar alignX = SkFixedToScalar(stopX); + SkScalar alignY = SkFixedToScalar(stopY); + if (origPaint.getTextAlign() == SkPaint::kCenter_Align) { + alignX = SkScalarHalf(alignX); + alignY = SkScalarHalf(alignY); + } else if (origPaint.getTextAlign() == SkPaint::kLeft_Align) { + alignX = 0; + alignY = 0; + } + x -= alignX; + y -= alignY; + SkPoint offset = SkPoint::Make(x, y); + + this->internalDrawDFPosText(blob, runIndex, skPaint, color, viewMatrix, text, byteLength, + positions.begin(), 2, offset, textRatio, origPaint); +} + +void GrAtlasTextContext::internalDrawDFPosText(GrAtlasTextBlob* blob, int runIndex, + const SkPaint& skPaint, + GrColor color, + const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset, + SkScalar textRatio, + const SkPaint& origPaint) { + + SkASSERT(byteLength == 0 || text != nullptr); + SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); + + // nothing to draw + if (text == nullptr || byteLength == 0) { + return; + } + + SkTDArray fallbackTxt; + SkTDArray fallbackPos; + + fCurrStrike = nullptr; + + SkGlyphCache* cache = blob->setupCache(runIndex, fSurfaceProps, skPaint, nullptr, true); + SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); + GrFontScaler* fontScaler = GetGrFontScaler(cache); + + const char* stop = text + byteLength; + + if (SkPaint::kLeft_Align == skPaint.getTextAlign()) { + while (text < stop) { + const char* lastText = text; + // the last 2 parameters are ignored + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); + + if (glyph.fWidth) { + SkScalar x = offset.x() + pos[0]; + SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0); + + if (!this->dfAppendGlyph(blob, + runIndex, + glyph, + x, y, color, fontScaler, + textRatio, viewMatrix)) { + // couldn't append, send to fallback + fallbackTxt.append(SkToInt(text-lastText), lastText); + *fallbackPos.append() = pos[0]; + if (2 == scalarsPerPosition) { + *fallbackPos.append() = pos[1]; + } + } + } + pos += scalarsPerPosition; + } + } else { + SkScalar alignMul = SkPaint::kCenter_Align == skPaint.getTextAlign() ? SK_ScalarHalf + : SK_Scalar1; + while (text < stop) { + const char* lastText = text; + // the last 2 parameters are ignored + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); + + if (glyph.fWidth) { + SkScalar x = offset.x() + pos[0]; + SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0); + + SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul * textRatio; + SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul * textRatio; + + if (!this->dfAppendGlyph(blob, + runIndex, + glyph, + x - advanceX, y - advanceY, color, + fontScaler, + textRatio, + viewMatrix)) { + // couldn't append, send to fallback + fallbackTxt.append(SkToInt(text-lastText), lastText); + *fallbackPos.append() = pos[0]; + if (2 == scalarsPerPosition) { + *fallbackPos.append() = pos[1]; + } + } + } + pos += scalarsPerPosition; + } + } + + SkGlyphCache::AttachCache(cache); + if (fallbackTxt.count()) { + this->fallbackDrawPosText(blob, runIndex, origPaint.getColor(), origPaint, viewMatrix, + fallbackTxt, fallbackPos, scalarsPerPosition, offset); + } +} + +bool GrAtlasTextContext::dfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, + const SkGlyph& skGlyph, + SkScalar sx, SkScalar sy, GrColor color, + GrFontScaler* scaler, + SkScalar textRatio, const SkMatrix& viewMatrix) { + if (!fCurrStrike) { + fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); + } + + GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), + skGlyph.getSubXFixed(), + skGlyph.getSubYFixed(), + GrGlyph::kDistance_MaskStyle); + GrGlyph* glyph = fCurrStrike->getGlyph(skGlyph, id, scaler); + if (!glyph) { + return true; + } + + // fallback to color glyph support + if (kA8_GrMaskFormat != glyph->fMaskFormat) { + return false; + } + + SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); + SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); + SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceFieldInset); + SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFieldInset); + + SkScalar scale = textRatio; + dx *= scale; + dy *= scale; + width *= scale; + height *= scale; + sx += dx; + sy += dy; + SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); + + blob->appendGlyph(runIndex, glyphRect, color, fCurrStrike, glyph, scaler, skGlyph, + sx - dx, sy - dy, scale, true); + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef GR_TEST_UTILS + +DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { + static uint32_t gContextID = SK_InvalidGenID; + static GrAtlasTextContext* gTextContext = nullptr; + static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType); + + if (context->uniqueID() != gContextID) { + gContextID = context->uniqueID(); + delete gTextContext; + + // We don't yet test the fall back to paths in the GrTextContext base class. This is mostly + // because we don't really want to have a gpu device here. + // We enable distance fields by twiddling a knob on the paint + gTextContext = GrAtlasTextContext::Create(context, gSurfaceProps); + } + + // Setup dummy SkPaint / GrPaint + GrColor color = GrRandomColor(random); + SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); + SkPaint skPaint; + skPaint.setColor(color); + skPaint.setLCDRenderText(random->nextBool()); + skPaint.setAntiAlias(skPaint.isLCDRenderText() ? true : random->nextBool()); + skPaint.setSubpixelText(random->nextBool()); + + GrPaint grPaint; + if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &grPaint)) { + SkFAIL("couldn't convert paint\n"); + } + + const char* text = "The quick brown fox jumps over the lazy dog."; + int textLen = (int)strlen(text); + + // Setup clip + GrClip clip; + + // right now we don't handle textblobs, nor do we handle drawPosText. Since we only + // intend to test the batch with this unit test, that is okay. + SkAutoTUnref blob( + gTextContext->createDrawTextBlob(grPaint, skPaint, viewMatrix, text, + static_cast(textLen), 0, 0)); + + SkScalar transX = static_cast(random->nextU()); + SkScalar transY = static_cast(random->nextU()); + const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]; + return blob->createBatch(info, textLen, 0, 0, color, transX, transY, skPaint, + gSurfaceProps, gTextContext->dfAdjustTable(), + context->getBatchFontCache()); +} + +#endif diff --git a/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.h b/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.h new file mode 100644 index 00000000000..3971352e96d --- /dev/null +++ b/gfx/skia/skia/src/gpu/text/GrAtlasTextContext.h @@ -0,0 +1,126 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrAtlasTextContext_DEFINED +#define GrAtlasTextContext_DEFINED + +#include "GrTextContext.h" + +#include "GrAtlasTextBlob.h" +#include "GrDistanceFieldAdjustTable.h" +#include "GrGeometryProcessor.h" +#include "SkTextBlobRunIterator.h" + +#ifdef GR_TEST_UTILS +#include "GrBatchTest.h" +#endif + +class GrDrawBatch; +class GrDrawContext; +class GrDrawTarget; +class GrPipelineBuilder; +class GrTextBlobCache; +class SkGlyph; + +/* + * This class implements GrTextContext using standard bitmap fonts, and can also process textblobs. + */ +class GrAtlasTextContext : public GrTextContext { +public: + static GrAtlasTextContext* Create(GrContext*, const SkSurfaceProps&); + +private: + GrAtlasTextContext(GrContext*, const SkSurfaceProps&); + ~GrAtlasTextContext() override {} + + bool canDraw(const SkPaint&, const SkMatrix& viewMatrix) override; + + void onDrawText(GrDrawContext*, const GrClip&, const GrPaint&, const SkPaint&, + const SkMatrix& viewMatrix, const char text[], size_t byteLength, + SkScalar x, SkScalar y, const SkIRect& regionClipBounds) override; + void onDrawPosText(GrDrawContext*, const GrClip&, const GrPaint&, + const SkPaint&, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset, const SkIRect& regionClipBounds) override; + void drawTextBlob(GrDrawContext*, const GrClip&, const SkPaint&, + const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y, + SkDrawFilter*, const SkIRect& clipBounds) override; + + typedef GrAtlasTextBlob::Run Run; + typedef Run::SubRunInfo PerSubRunInfo; + + inline bool canDrawAsDistanceFields(const SkPaint&, const SkMatrix& viewMatrix); + GrAtlasTextBlob* setupDFBlob(int glyphCount, const SkPaint& origPaint, + const SkMatrix& viewMatrix, SkPaint* dfPaint, + SkScalar* textRatio); + void bmpAppendGlyph(GrAtlasTextBlob*, int runIndex, const SkGlyph&, int left, int top, + GrColor color, GrFontScaler*); + bool dfAppendGlyph(GrAtlasTextBlob*, int runIndex, const SkGlyph&, SkScalar sx, SkScalar sy, + GrColor color, GrFontScaler*, SkScalar textRatio, + const SkMatrix& viewMatrix); + + // A helper for drawing BitmapText in a run of distance fields + inline void fallbackDrawPosText(GrAtlasTextBlob*, int runIndex, + GrColor color, + const SkPaint&, const SkMatrix& viewMatrix, + const SkTDArray& fallbackTxt, + const SkTDArray& fallbackPos, + int scalarsPerPosition, + const SkPoint& offset); + + void internalDrawDFText(GrAtlasTextBlob*, int runIndex, + const SkPaint&, + GrColor color, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + SkScalar x, SkScalar y, + SkScalar textRatio, const SkPaint& origPaint); + void internalDrawDFPosText(GrAtlasTextBlob*, int runIndex, + const SkPaint&, + GrColor color, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset, + SkScalar textRatio, + const SkPaint& origPaint); + + // sets up the descriptor on the blob and returns a detached cache. Client must attach + inline static GrColor ComputeCanonicalColor(const SkPaint&, bool lcd); + void regenerateTextBlob(GrAtlasTextBlob* bmp, const SkPaint& skPaint, GrColor, + const SkMatrix& viewMatrix, + const SkTextBlob* blob, SkScalar x, SkScalar y, + SkDrawFilter* drawFilter, + const GrClip&); + inline static bool HasLCD(const SkTextBlob*); + inline void initDistanceFieldPaint(GrAtlasTextBlob*, SkPaint*, SkScalar* textRatio, + const SkMatrix&); + + // Test methods + // TODO this is really ugly. It'd be much nicer if positioning could be moved to batch + inline GrAtlasTextBlob* createDrawTextBlob(const GrPaint&, + const SkPaint&, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + SkScalar x, SkScalar y); + inline GrAtlasTextBlob* createDrawPosTextBlob(const GrPaint&, + const SkPaint&, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset); + const GrDistanceFieldAdjustTable* dfAdjustTable() const { return fDistanceAdjustTable; } + + GrBatchTextStrike* fCurrStrike; + GrTextBlobCache* fCache; + SkAutoTUnref fDistanceAdjustTable; + +#ifdef GR_TEST_UTILS + DRAW_BATCH_TEST_FRIEND(TextBlobBatch); +#endif + + typedef GrTextContext INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrBatchFontCache.cpp b/gfx/skia/skia/src/gpu/text/GrBatchFontCache.cpp similarity index 100% rename from gfx/skia/skia/src/gpu/GrBatchFontCache.cpp rename to gfx/skia/skia/src/gpu/text/GrBatchFontCache.cpp diff --git a/gfx/skia/skia/src/gpu/GrBatchFontCache.h b/gfx/skia/skia/src/gpu/text/GrBatchFontCache.h similarity index 100% rename from gfx/skia/skia/src/gpu/GrBatchFontCache.h rename to gfx/skia/skia/src/gpu/text/GrBatchFontCache.h diff --git a/gfx/skia/skia/src/gpu/text/GrDistanceFieldAdjustTable.cpp b/gfx/skia/skia/src/gpu/text/GrDistanceFieldAdjustTable.cpp new file mode 100644 index 00000000000..1c5aeceb801 --- /dev/null +++ b/gfx/skia/skia/src/gpu/text/GrDistanceFieldAdjustTable.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrDistanceFieldAdjustTable.h" + +#include "SkScalerContext.h" + +SkDEBUGCODE(static const int kExpectedDistanceAdjustTableSize = 8;) + +void GrDistanceFieldAdjustTable::buildDistanceAdjustTable() { + // This is used for an approximation of the mask gamma hack, used by raster and bitmap + // text. The mask gamma hack is based off of guessing what the blend color is going to + // be, and adjusting the mask so that when run through the linear blend will + // produce the value closest to the desired result. However, in practice this means + // that the 'adjusted' mask is just increasing or decreasing the coverage of + // the mask depending on what it is thought it will blit against. For black (on + // assumed white) this means that coverages are decreased (on a curve). For white (on + // assumed black) this means that coverages are increased (on a a curve). At + // middle (perceptual) gray (which could be blit against anything) the coverages + // remain the same. + // + // The idea here is that instead of determining the initial (real) coverage and + // then adjusting that coverage, we determine an adjusted coverage directly by + // essentially manipulating the geometry (in this case, the distance to the glyph + // edge). So for black (on assumed white) this thins a bit; for white (on + // assumed black) this fake bolds the geometry a bit. + // + // The distance adjustment is calculated by determining the actual coverage value which + // when fed into in the mask gamma table gives us an 'adjusted coverage' value of 0.5. This + // actual coverage value (assuming it's between 0 and 1) corresponds to a distance from the + // actual edge. So by subtracting this distance adjustment and computing without the + // the coverage adjustment we should get 0.5 coverage at the same point. + // + // This has several implications: + // For non-gray lcd smoothed text, each subpixel essentially is using a + // slightly different geometry. + // + // For black (on assumed white) this may not cover some pixels which were + // previously covered; however those pixels would have been only slightly + // covered and that slight coverage would have been decreased anyway. Also, some pixels + // which were previously fully covered may no longer be fully covered. + // + // For white (on assumed black) this may cover some pixels which weren't + // previously covered at all. + + int width, height; + size_t size; + +#ifdef SK_GAMMA_CONTRAST + SkScalar contrast = SK_GAMMA_CONTRAST; +#else + SkScalar contrast = 0.5f; +#endif + SkScalar paintGamma = SK_GAMMA_EXPONENT; + SkScalar deviceGamma = SK_GAMMA_EXPONENT; + + size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma, + &width, &height); + + SkASSERT(kExpectedDistanceAdjustTableSize == height); + fTable = new SkScalar[height]; + + SkAutoTArray data((int)size); + SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get()); + + // find the inverse points where we cross 0.5 + // binsearch might be better, but we only need to do this once on creation + for (int row = 0; row < height; ++row) { + uint8_t* rowPtr = data.get() + row*width; + for (int col = 0; col < width - 1; ++col) { + if (rowPtr[col] <= 127 && rowPtr[col + 1] >= 128) { + // compute point where a mask value will give us a result of 0.5 + float interp = (127.5f - rowPtr[col]) / (rowPtr[col + 1] - rowPtr[col]); + float borderAlpha = (col + interp) / 255.f; + + // compute t value for that alpha + // this is an approximate inverse for smoothstep() + float t = borderAlpha*(borderAlpha*(4.0f*borderAlpha - 6.0f) + 5.0f) / 3.0f; + + // compute distance which gives us that t value + const float kDistanceFieldAAFactor = 0.65f; // should match SK_DistanceFieldAAFactor + float d = 2.0f*kDistanceFieldAAFactor*t - kDistanceFieldAAFactor; + + fTable[row] = d; + break; + } + } + } +} diff --git a/gfx/skia/skia/src/gpu/text/GrDistanceFieldAdjustTable.h b/gfx/skia/skia/src/gpu/text/GrDistanceFieldAdjustTable.h new file mode 100644 index 00000000000..f7d8bee0897 --- /dev/null +++ b/gfx/skia/skia/src/gpu/text/GrDistanceFieldAdjustTable.h @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrDistanceFieldAdjustTable_DEFINED +#define GrDistanceFieldAdjustTable_DEFINED + +#include "SkRefCnt.h" +#include "SkScalar.h" + +// Distance field text needs this table to compute a value for use in the fragment shader. +// Because the GrAtlasTextContext can go out of scope before the final flush, this needs to be +// refcnted and malloced +struct GrDistanceFieldAdjustTable : public SkNVRefCnt { + GrDistanceFieldAdjustTable() { this->buildDistanceAdjustTable(); } + ~GrDistanceFieldAdjustTable() { delete[] fTable; } + + const SkScalar& operator[] (int i) const { + return fTable[i]; + } + +private: + void buildDistanceAdjustTable(); + + SkScalar* fTable; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/GrFontScaler.cpp b/gfx/skia/skia/src/gpu/text/GrFontScaler.cpp similarity index 100% rename from gfx/skia/skia/src/gpu/GrFontScaler.cpp rename to gfx/skia/skia/src/gpu/text/GrFontScaler.cpp diff --git a/gfx/skia/skia/src/gpu/GrFontScaler.h b/gfx/skia/skia/src/gpu/text/GrFontScaler.h similarity index 100% rename from gfx/skia/skia/src/gpu/GrFontScaler.h rename to gfx/skia/skia/src/gpu/text/GrFontScaler.h diff --git a/gfx/skia/skia/src/gpu/GrStencilAndCoverTextContext.cpp b/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.cpp similarity index 90% rename from gfx/skia/skia/src/gpu/GrStencilAndCoverTextContext.cpp rename to gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.cpp index bab0b32ce6a..d28f1a803a0 100644 --- a/gfx/skia/skia/src/gpu/GrStencilAndCoverTextContext.cpp +++ b/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.cpp @@ -71,7 +71,7 @@ bool GrStencilAndCoverTextContext::internalCanDraw(const SkPaint& skPaint) { return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrokeWidth(); } -void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* rt, +void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, @@ -81,13 +81,13 @@ void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* SkScalar x, SkScalar y, const SkIRect& clipBounds) { TextRun run(skPaint); - GrPipelineBuilder pipelineBuilder(paint, rt, clip); + GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); run.setText(text, byteLength, x, y); run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds, fFallbackTextContext, skPaint); } -void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarget* rt, +void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, @@ -99,27 +99,27 @@ void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg const SkPoint& offset, const SkIRect& clipBounds) { TextRun run(skPaint); - GrPipelineBuilder pipelineBuilder(paint, rt, clip); + GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); run.setPosText(text, byteLength, pos, scalarsPerPosition, offset); run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds, fFallbackTextContext, skPaint); } -void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarget* rt, +void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkTextBlob* skBlob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { if (!this->internalCanDraw(skPaint)) { - fFallbackTextContext->drawTextBlob(dc, rt, clip, skPaint, viewMatrix, skBlob, x, y, + fFallbackTextContext->drawTextBlob(dc, clip, skPaint, viewMatrix, skBlob, x, y, drawFilter, clipBounds); return; } if (drawFilter || skPaint.getPathEffect()) { // This draw can't be cached. - INHERITED::drawTextBlob(dc, rt, clip, skPaint, viewMatrix, skBlob, x, y, drawFilter, + INHERITED::drawTextBlob(dc, clip, skPaint, viewMatrix, skBlob, x, y, drawFilter, clipBounds); return; } @@ -134,7 +134,7 @@ void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarge } const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); - GrPipelineBuilder pipelineBuilder(paint, rt, clip); + GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); TextBlob::Iter iter(blob); for (TextRun* run = iter.get(); run; run = iter.next()) { @@ -233,7 +233,7 @@ void GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob, class GrStencilAndCoverTextContext::FallbackBlobBuilder { public: - FallbackBlobBuilder() : fBuffIdx(0) {} + FallbackBlobBuilder() : fBuffIdx(0), fCount(0) {} bool isInitialized() const { return SkToBool(fBuilder); } @@ -241,7 +241,7 @@ public: void appendGlyph(uint16_t glyphId, const SkPoint& pos); - const SkTextBlob* buildIfInitialized(); + const SkTextBlob* buildIfNeeded(int* count); private: enum { kWriteBufferSize = 1024 }; @@ -251,6 +251,7 @@ private: SkAutoTDelete fBuilder; SkPaint fFont; int fBuffIdx; + int fCount; uint16_t fGlyphIds[kWriteBufferSize]; SkPoint fPositions[kWriteBufferSize]; }; @@ -261,6 +262,7 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) : fStroke(fontAndStroke), fFont(fontAndStroke), fTotalGlyphCount(0), + fFallbackGlyphCount(0), fDetachedGlyphCache(nullptr), fLastDrawnGlyphsID(SK_InvalidUniqueID) { SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. @@ -339,9 +341,6 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) memcpy(&builder[2 + strokeDataCount], desc, desc->getLength()); } } - - // When drawing from canonically sized paths, the actual local coords are fTextRatio * coords. - fLocalMatrixTemplate.setScale(fTextRatio, fTextRatio); } GrStencilAndCoverTextContext::TextRun::~TextRun() { @@ -355,8 +354,9 @@ void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t by SkGlyphCache* glyphCache = this->getGlyphCache(); SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); - fDraw.reset(GrPathRangeDraw::Create(GrPathRendering::kTranslate_PathTransformType, - fTotalGlyphCount = fFont.countText(text, byteLength))); + fTotalGlyphCount = fFont.countText(text, byteLength); + fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTransformType, + fTotalGlyphCount)); const char* stop = text + byteLength; @@ -407,7 +407,7 @@ void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t by fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); } - fFallbackTextBlob.reset(fallback.buildIfInitialized()); + fFallbackTextBlob.reset(fallback.buildIfNeeded(&fFallbackGlyphCount)); } void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t byteLength, @@ -419,8 +419,9 @@ void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t SkGlyphCache* glyphCache = this->getGlyphCache(); SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); - fDraw.reset(GrPathRangeDraw::Create(GrPathRendering::kTranslate_PathTransformType, - fTotalGlyphCount = fFont.countText(text, byteLength))); + fTotalGlyphCount = fFont.countText(text, byteLength); + fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTransformType, + fTotalGlyphCount)); const char* stop = text + byteLength; @@ -440,7 +441,7 @@ void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t pos += scalarsPerPosition; } - fFallbackTextBlob.reset(fallback.buildIfInitialized()); + fFallbackTextBlob.reset(fallback.buildIfNeeded(&fFallbackGlyphCount)); } GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx) const { @@ -470,8 +471,8 @@ inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& gl } fallback->appendGlyph(glyph.getGlyphID(), pos); } else { - float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * pos.y() }; - fDraw->append(glyph.getGlyphID(), translate); + fInstanceData->append(glyph.getGlyphID(), fTextInverseRatio * pos.x(), + fTextInverseRatio * pos.y()); } } @@ -484,11 +485,10 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, const SkIRect& clipBounds, GrTextContext* fallbackTextContext, const SkPaint& originalSkPaint) const { - SkASSERT(fDraw); - SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled() || - !fFont.isAntiAlias()); + SkASSERT(fInstanceData); + SkASSERT(dc->accessRenderTarget()->isStencilBufferMultisampled() || !fFont.isAntiAlias()); - if (fDraw->count()) { + if (fInstanceData->count()) { pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.isAntiAlias()); GR_STATIC_CONST_SAME_STENCIL(kStencilPass, @@ -504,18 +504,10 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, SkAutoTUnref glyphs(this->createGlyphs(ctx)); if (fLastDrawnGlyphsID != glyphs->getUniqueID()) { // Either this is the first draw or the glyphs object was purged since last draw. - glyphs->loadPathsIfNeeded(fDraw->indices(), fDraw->count()); + glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count()); fLastDrawnGlyphsID = glyphs->getUniqueID(); } - SkMatrix drawMatrix(viewMatrix); - drawMatrix.preTranslate(x, y); - drawMatrix.preScale(fTextRatio, fTextRatio); - - SkMatrix& localMatrix = fLocalMatrixTemplate; - localMatrix.setTranslateX(x); - localMatrix.setTranslateY(y); - // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy // the entire dst. Realistically this is a moot point, because any context that supports // NV_path_rendering will also support NV_blend_equation_advanced. @@ -524,8 +516,13 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, SkRect bounds = SkRect::MakeIWH(pipelineBuilder->getRenderTarget()->width(), pipelineBuilder->getRenderTarget()->height()); - dc->drawPathsFromRange(pipelineBuilder, drawMatrix, localMatrix, color, glyphs, fDraw, - GrPathRendering::kWinding_FillType, bounds); + SkAutoTUnref batch( + GrDrawPathRangeBatch::Create(viewMatrix, fTextRatio, fTextInverseRatio * x, + fTextInverseRatio * y, color, + GrPathRendering::kWinding_FillType, glyphs, fInstanceData, + bounds)); + + dc->drawPathBatch(*pipelineBuilder, batch); } if (fFallbackTextBlob) { @@ -535,8 +532,7 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); } - fallbackTextContext->drawTextBlob(dc, pipelineBuilder->getRenderTarget(), - pipelineBuilder->clip(), fallbackSkPaint, viewMatrix, + fallbackTextContext->drawTextBlob(dc, pipelineBuilder->clip(), fallbackSkPaint, viewMatrix, fFallbackTextBlob, x, y, nullptr, clipBounds); } } @@ -557,11 +553,11 @@ void GrStencilAndCoverTextContext::TextRun::releaseGlyphCache() const { } size_t GrStencilAndCoverTextContext::TextRun::computeSizeInCache() const { - size_t size = sizeof(TextRun) + - fGlyphPathsKey.size() + - fTotalGlyphCount * (sizeof(uint16_t) + 2 * sizeof(float)); - if (fDraw) { - size += sizeof(GrPathRangeDraw); + size_t size = sizeof(TextRun) + fGlyphPathsKey.size(); + // The instance data always reserves enough space for every glyph. + size += (fTotalGlyphCount + fFallbackGlyphCount) * (sizeof(uint16_t) + 2 * sizeof(float)); + if (fInstanceData) { + size += sizeof(InstanceData); } if (fFallbackTextBlob) { size += sizeof(SkTextBlob); @@ -594,6 +590,7 @@ void GrStencilAndCoverTextContext::FallbackBlobBuilder::appendGlyph(uint16_t gly fGlyphIds[fBuffIdx] = glyphId; fPositions[fBuffIdx] = pos; fBuffIdx++; + fCount++; } void GrStencilAndCoverTextContext::FallbackBlobBuilder::flush() { @@ -609,10 +606,11 @@ void GrStencilAndCoverTextContext::FallbackBlobBuilder::flush() { fBuffIdx = 0; } -const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfInitialized() { - if (!this->isInitialized()) { - return nullptr; +const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfNeeded(int *count) { + *count = fCount; + if (fCount) { + this->flush(); + return fBuilder->build(); } - this->flush(); - return fBuilder->build(); + return nullptr; } diff --git a/gfx/skia/skia/src/gpu/GrStencilAndCoverTextContext.h b/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.h similarity index 92% rename from gfx/skia/skia/src/gpu/GrStencilAndCoverTextContext.h rename to gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.h index af1403825ab..dab71e05785 100644 --- a/gfx/skia/skia/src/gpu/GrStencilAndCoverTextContext.h +++ b/gfx/skia/skia/src/gpu/text/GrStencilAndCoverTextContext.h @@ -14,6 +14,7 @@ #include "SkTHash.h" #include "SkTInternalLList.h" #include "SkTLList.h" +#include "batches/GrDrawPathBatch.h" class GrTextStrike; class GrPath; @@ -39,17 +40,17 @@ private: bool internalCanDraw(const SkPaint&); - void onDrawText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, + void onDrawText(GrDrawContext*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds) override; - void onDrawPosText(GrDrawContext*, GrRenderTarget*, + void onDrawPosText(GrDrawContext*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds) override; - void drawTextBlob(GrDrawContext*, GrRenderTarget*, const GrClip&, const SkPaint&, + void drawTextBlob(GrDrawContext*, const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y, SkDrawFilter*, const SkIRect& clipBounds) override; @@ -74,6 +75,8 @@ private: size_t computeSizeInCache() const; private: + typedef GrDrawPathRangeBatch::InstanceData InstanceData; + SkGlyphCache* getGlyphCache() const; GrPathRange* createGlyphs(GrContext*) const; void appendGlyph(const SkGlyph&, const SkPoint&, FallbackBlobBuilder*); @@ -85,11 +88,11 @@ private: bool fUsingRawGlyphPaths; GrUniqueKey fGlyphPathsKey; int fTotalGlyphCount; - SkAutoTUnref fDraw; + SkAutoTUnref fInstanceData; + int fFallbackGlyphCount; SkAutoTUnref fFallbackTextBlob; mutable SkGlyphCache* fDetachedGlyphCache; mutable uint32_t fLastDrawnGlyphsID; - mutable SkMatrix fLocalMatrixTemplate; }; // Text blobs/caches. diff --git a/gfx/skia/skia/src/gpu/GrTextBlobCache.cpp b/gfx/skia/skia/src/gpu/text/GrTextBlobCache.cpp similarity index 94% rename from gfx/skia/skia/src/gpu/GrTextBlobCache.cpp rename to gfx/skia/skia/src/gpu/text/GrTextBlobCache.cpp index f11b7c60cbd..685284bee5c 100644 --- a/gfx/skia/skia/src/gpu/GrTextBlobCache.cpp +++ b/gfx/skia/skia/src/gpu/text/GrTextBlobCache.cpp @@ -55,4 +55,7 @@ void GrTextBlobCache::freeAll() { ++iter; } fCache.rewind(); + + // There should be no allocations in the memory pool at this point + SkASSERT(fPool.isEmpty()); } diff --git a/gfx/skia/skia/src/gpu/GrTextBlobCache.h b/gfx/skia/skia/src/gpu/text/GrTextBlobCache.h similarity index 100% rename from gfx/skia/skia/src/gpu/GrTextBlobCache.h rename to gfx/skia/skia/src/gpu/text/GrTextBlobCache.h diff --git a/gfx/skia/skia/src/gpu/GrTextContext.cpp b/gfx/skia/skia/src/gpu/text/GrTextContext.cpp similarity index 51% rename from gfx/skia/skia/src/gpu/GrTextContext.cpp rename to gfx/skia/skia/src/gpu/text/GrTextContext.cpp index b1bae56ed5a..8ff2523a73b 100644 --- a/gfx/skia/skia/src/gpu/GrTextContext.cpp +++ b/gfx/skia/skia/src/gpu/text/GrTextContext.cpp @@ -6,20 +6,14 @@ */ #include "GrTextContext.h" -#include "GrBlurUtils.h" #include "GrContext.h" -#include "GrDrawContext.h" #include "GrFontScaler.h" +#include "GrTextUtils.h" -#include "SkAutoKern.h" #include "SkDrawFilter.h" -#include "SkDrawProcs.h" #include "SkGlyphCache.h" -#include "SkGpuDevice.h" #include "SkGrPriv.h" #include "SkTextBlobRunIterator.h" -#include "SkTextMapStateProc.h" -#include "SkTextToPathIter.h" GrTextContext::GrTextContext(GrContext* context, const SkSurfaceProps& surfaceProps) : fFallbackTextContext(nullptr) @@ -31,7 +25,7 @@ GrTextContext::~GrTextContext() { delete fFallbackTextContext; } -void GrTextContext::drawText(GrDrawContext* dc, GrRenderTarget* rt, +void GrTextContext::drawText(GrDrawContext* dc, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, @@ -43,7 +37,7 @@ void GrTextContext::drawText(GrDrawContext* dc, GrRenderTarget* rt, GrTextContext* textContext = this; do { if (textContext->canDraw(skPaint, viewMatrix)) { - textContext->onDrawText(dc, rt, clip, paint, skPaint, viewMatrix, + textContext->onDrawText(dc, clip, paint, skPaint, viewMatrix, text, byteLength, x, y, clipBounds); return; } @@ -51,10 +45,11 @@ void GrTextContext::drawText(GrDrawContext* dc, GrRenderTarget* rt, } while (textContext); // fall back to drawing as a path - this->drawTextAsPath(dc, clip, skPaint, viewMatrix, text, byteLength, x, y, clipBounds); + GrTextUtils::DrawTextAsPath(fContext, dc, clip, skPaint, viewMatrix, text, byteLength, x, y, + clipBounds); } -void GrTextContext::drawPosText(GrDrawContext* dc, GrRenderTarget* rt, +void GrTextContext::drawPosText(GrDrawContext* dc, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, @@ -67,7 +62,7 @@ void GrTextContext::drawPosText(GrDrawContext* dc, GrRenderTarget* rt, GrTextContext* textContext = this; do { if (textContext->canDraw(skPaint, viewMatrix)) { - textContext->onDrawPosText(dc, rt, clip, paint, skPaint, viewMatrix, + textContext->onDrawPosText(dc, clip, paint, skPaint, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset, clipBounds); return; @@ -76,8 +71,8 @@ void GrTextContext::drawPosText(GrDrawContext* dc, GrRenderTarget* rt, } while (textContext); // fall back to drawing as a path - this->drawPosTextAsPath(dc, clip, skPaint, viewMatrix, text, byteLength, pos, - scalarsPerPosition, offset, clipBounds); + GrTextUtils::DrawPosTextAsPath(fContext, dc, fSurfaceProps, clip, skPaint, viewMatrix, text, + byteLength, pos, scalarsPerPosition, offset, clipBounds); } bool GrTextContext::ShouldDisableLCD(const SkPaint& paint) { @@ -108,7 +103,7 @@ uint32_t GrTextContext::FilterTextFlags(const SkSurfaceProps& surfaceProps, cons return flags; } -void GrTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarget* rt, +void GrTextContext::drawTextBlob(GrDrawContext* dc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, @@ -138,15 +133,15 @@ void GrTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarget* rt, switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: - this->drawText(dc, rt, clip, grPaint, runPaint, viewMatrix, (const char *)it.glyphs(), + this->drawText(dc, clip, grPaint, runPaint, viewMatrix, (const char *)it.glyphs(), textLen, x + offset.x(), y + offset.y(), clipBounds); break; case SkTextBlob::kHorizontal_Positioning: - this->drawPosText(dc, rt, clip, grPaint, runPaint, viewMatrix, (const char*)it.glyphs(), + this->drawPosText(dc, clip, grPaint, runPaint, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), clipBounds); break; case SkTextBlob::kFull_Positioning: - this->drawPosText(dc, rt, clip, grPaint, runPaint, viewMatrix, (const char*)it.glyphs(), + this->drawPosText(dc, clip, grPaint, runPaint, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2, SkPoint::Make(x, y), clipBounds); break; default: @@ -160,105 +155,6 @@ void GrTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarget* rt, } } -void GrTextContext::drawTextAsPath(GrDrawContext* dc, - const GrClip& clip, - const SkPaint& skPaint, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, SkScalar x, SkScalar y, - const SkIRect& clipBounds) { - SkTextToPathIter iter(text, byteLength, skPaint, true); - - SkMatrix matrix; - matrix.setScale(iter.getPathScale(), iter.getPathScale()); - matrix.postTranslate(x, y); - - const SkPath* iterPath; - SkScalar xpos, prevXPos = 0; - - while (iter.next(&iterPath, &xpos)) { - matrix.postTranslate(xpos - prevXPos, 0); - if (iterPath) { - const SkPaint& pnt = iter.getPaint(); - GrBlurUtils::drawPathWithMaskFilter(fContext, dc, clip, *iterPath, - pnt, viewMatrix, &matrix, clipBounds, false); - } - prevXPos = xpos; - } -} - -void GrTextContext::drawPosTextAsPath(GrDrawContext* dc, - const GrClip& clip, - const SkPaint& origPaint, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkIRect& clipBounds) { - // setup our std paint, in hopes of getting hits in the cache - SkPaint paint(origPaint); - SkScalar matrixScale = paint.setupForAsPaths(); - - SkMatrix matrix; - matrix.setScale(matrixScale, matrixScale); - - // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. - paint.setStyle(SkPaint::kFill_Style); - paint.setPathEffect(nullptr); - - SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); - SkAutoGlyphCache autoCache(paint, &fSurfaceProps, nullptr); - SkGlyphCache* cache = autoCache.getCache(); - - const char* stop = text + byteLength; - SkTextAlignProc alignProc(paint.getTextAlign()); - SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); - - // Now restore the original settings, so we "draw" with whatever style/stroking. - paint.setStyle(origPaint.getStyle()); - paint.setPathEffect(origPaint.getPathEffect()); - - while (text < stop) { - const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); - if (glyph.fWidth) { - const SkPath* path = cache->findPath(glyph); - if (path) { - SkPoint tmsLoc; - tmsProc(pos, &tmsLoc); - SkPoint loc; - alignProc(tmsLoc, glyph, &loc); - - matrix[SkMatrix::kMTransX] = loc.fX; - matrix[SkMatrix::kMTransY] = loc.fY; - GrBlurUtils::drawPathWithMaskFilter(fContext, dc, clip, *path, paint, - viewMatrix, &matrix, clipBounds, false); - } - } - pos += scalarsPerPosition; - } -} - -// *** change to output positions? -int GrTextContext::MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc, - const char text[], size_t byteLength, SkVector* stopVector) { - SkFixed x = 0, y = 0; - const char* stop = text + byteLength; - - SkAutoKern autokern; - - int numGlyphs = 0; - while (text < stop) { - // don't need x, y here, since all subpixel variants will have the - // same advance - const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); - - x += autokern.adjust(glyph) + glyph.fAdvanceX; - y += glyph.fAdvanceY; - ++numGlyphs; - } - stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y)); - - SkASSERT(text == stop); - - return numGlyphs; -} - static void GlyphCacheAuxProc(void* data) { GrFontScaler* scaler = (GrFontScaler*)data; SkSafeUnref(scaler); diff --git a/gfx/skia/skia/src/gpu/GrTextContext.h b/gfx/skia/skia/src/gpu/text/GrTextContext.h similarity index 66% rename from gfx/skia/skia/src/gpu/GrTextContext.h rename to gfx/skia/skia/src/gpu/text/GrTextContext.h index f50bf8586a1..206b34a4036 100644 --- a/gfx/skia/skia/src/gpu/GrTextContext.h +++ b/gfx/skia/skia/src/gpu/text/GrTextContext.h @@ -28,17 +28,17 @@ class GrTextContext { public: virtual ~GrTextContext(); - void drawText(GrDrawContext* dc, GrRenderTarget* rt, + void drawText(GrDrawContext* dc, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds); - void drawPosText(GrDrawContext* dc, GrRenderTarget* rt, + void drawPosText(GrDrawContext* dc, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds); - virtual void drawTextBlob(GrDrawContext* dc, GrRenderTarget*, const GrClip&, const SkPaint&, + virtual void drawTextBlob(GrDrawContext* dc, const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y, SkDrawFilter*, const SkIRect& clipBounds); @@ -54,34 +54,23 @@ protected: virtual bool canDraw(const SkPaint&, const SkMatrix& viewMatrix) = 0; - virtual void onDrawText(GrDrawContext*, GrRenderTarget*, const GrClip&, + virtual void onDrawText(GrDrawContext*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds) = 0; - virtual void onDrawPosText(GrDrawContext*, GrRenderTarget*, const GrClip&, + virtual void onDrawPosText(GrDrawContext*, const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds) = 0; - void drawTextAsPath(GrDrawContext*, const GrClip& clip, - const SkPaint& origPaint, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, SkScalar x, SkScalar y, - const SkIRect& clipBounds); - void drawPosTextAsPath(GrDrawContext*, const GrClip& clip, - const SkPaint& origPaint, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, - const SkScalar pos[], int scalarsPerPosition, - const SkPoint& offset, const SkIRect& clipBounds); - static GrFontScaler* GetGrFontScaler(SkGlyphCache* cache); - // sets extent in stopVector and returns glyph count - static int MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc, - const char text[], size_t byteLength, SkVector* stopVector); static uint32_t FilterTextFlags(const SkSurfaceProps& surfaceProps, const SkPaint& paint); friend class GrAtlasTextBatch; + friend class GrAtlasTextBlob; // for FilterTextFlags + friend class GrTextUtils; // for some static functions }; #endif diff --git a/gfx/skia/skia/src/gpu/text/GrTextUtils.cpp b/gfx/skia/skia/src/gpu/text/GrTextUtils.cpp new file mode 100644 index 00000000000..9d6bb2c857d --- /dev/null +++ b/gfx/skia/skia/src/gpu/text/GrTextUtils.cpp @@ -0,0 +1,206 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrTextUtils.h" + +#include "GrAtlasTextBlob.h" +#include "GrBatchFontCache.h" +#include "GrBlurUtils.h" +#include "GrContext.h" +#include "GrDrawContext.h" +#include "GrTextContext.h" +#include "SkDrawProcs.h" +#include "SkFindAndPlaceGlyph.h" +#include "SkGlyphCache.h" +#include "SkPaint.h" +#include "SkRect.h" +#include "SkTextMapStateProc.h" +#include "SkTextToPathIter.h" + +void GrTextUtils::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, + GrBatchFontCache* fontCache, + const SkSurfaceProps& props, const SkPaint& skPaint, + GrColor color, + const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + SkScalar x, SkScalar y) { + SkASSERT(byteLength == 0 || text != nullptr); + + // nothing to draw + if (text == nullptr || byteLength == 0) { + return; + } + + GrBatchTextStrike* currStrike = nullptr; + + // Get GrFontScaler from cache + SkGlyphCache* cache = blob->setupCache(runIndex, props, skPaint, &viewMatrix, false); + GrFontScaler* fontScaler = GrTextContext::GetGrFontScaler(cache); + + SkFindAndPlaceGlyph::ProcessText( + skPaint.getTextEncoding(), text, byteLength, + {x, y}, viewMatrix, skPaint.getTextAlign(), + cache, + [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { + position += rounding; + BmpAppendGlyph( + blob, runIndex, fontCache, &currStrike, glyph, + SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY), + color, fontScaler); + } + ); + + SkGlyphCache::AttachCache(cache); +} + +void GrTextUtils::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, + GrBatchFontCache* fontCache, + const SkSurfaceProps& props, const SkPaint& skPaint, + GrColor color, + const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset) { + SkASSERT(byteLength == 0 || text != nullptr); + SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); + + // nothing to draw + if (text == nullptr || byteLength == 0) { + return; + } + + GrBatchTextStrike* currStrike = nullptr; + + // Get GrFontScaler from cache + SkGlyphCache* cache = blob->setupCache(runIndex, props, skPaint, &viewMatrix, false); + GrFontScaler* fontScaler = GrTextContext::GetGrFontScaler(cache); + + SkFindAndPlaceGlyph::ProcessPosText( + skPaint.getTextEncoding(), text, byteLength, + offset, viewMatrix, pos, scalarsPerPosition, + skPaint.getTextAlign(), cache, + [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { + position += rounding; + BmpAppendGlyph( + blob, runIndex, fontCache, &currStrike, glyph, + SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY), + color, fontScaler); + } + ); + + SkGlyphCache::AttachCache(cache); +} + +void GrTextUtils::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, + GrBatchFontCache* fontCache, + GrBatchTextStrike** strike, const SkGlyph& skGlyph, + int vx, int vy, GrColor color, GrFontScaler* scaler) { + if (!*strike) { + *strike = fontCache->getStrike(scaler); + } + + GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), + skGlyph.getSubXFixed(), + skGlyph.getSubYFixed(), + GrGlyph::kCoverage_MaskStyle); + GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, scaler); + if (!glyph) { + return; + } + + int x = vx + glyph->fBounds.fLeft; + int y = vy + glyph->fBounds.fTop; + + // keep them as ints until we've done the clip-test + int width = glyph->fBounds.width(); + int height = glyph->fBounds.height(); + + SkRect r; + r.fLeft = SkIntToScalar(x); + r.fTop = SkIntToScalar(y); + r.fRight = r.fLeft + SkIntToScalar(width); + r.fBottom = r.fTop + SkIntToScalar(height); + + blob->appendGlyph(runIndex, r, color, *strike, glyph, scaler, skGlyph, + SkIntToScalar(vx), SkIntToScalar(vy), 1.0f, false); +} + +void GrTextUtils::DrawTextAsPath(GrContext* context, GrDrawContext* dc, + const GrClip& clip, + const SkPaint& skPaint, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, SkScalar x, SkScalar y, + const SkIRect& clipBounds) { + SkTextToPathIter iter(text, byteLength, skPaint, true); + + SkMatrix matrix; + matrix.setScale(iter.getPathScale(), iter.getPathScale()); + matrix.postTranslate(x, y); + + const SkPath* iterPath; + SkScalar xpos, prevXPos = 0; + + while (iter.next(&iterPath, &xpos)) { + matrix.postTranslate(xpos - prevXPos, 0); + if (iterPath) { + const SkPaint& pnt = iter.getPaint(); + GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, *iterPath, + pnt, viewMatrix, &matrix, clipBounds, false); + } + prevXPos = xpos; + } +} + +void GrTextUtils::DrawPosTextAsPath(GrContext* context, + GrDrawContext* dc, + const SkSurfaceProps& props, + const GrClip& clip, + const SkPaint& origPaint, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset, const SkIRect& clipBounds) { + // setup our std paint, in hopes of getting hits in the cache + SkPaint paint(origPaint); + SkScalar matrixScale = paint.setupForAsPaths(); + + SkMatrix matrix; + matrix.setScale(matrixScale, matrixScale); + + // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. + paint.setStyle(SkPaint::kFill_Style); + paint.setPathEffect(nullptr); + + SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); + SkAutoGlyphCache autoCache(paint, &props, nullptr); + SkGlyphCache* cache = autoCache.getCache(); + + const char* stop = text + byteLength; + SkTextAlignProc alignProc(paint.getTextAlign()); + SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); + + // Now restore the original settings, so we "draw" with whatever style/stroking. + paint.setStyle(origPaint.getStyle()); + paint.setPathEffect(origPaint.getPathEffect()); + + while (text < stop) { + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); + if (glyph.fWidth) { + const SkPath* path = cache->findPath(glyph); + if (path) { + SkPoint tmsLoc; + tmsProc(pos, &tmsLoc); + SkPoint loc; + alignProc(tmsLoc, glyph, &loc); + + matrix[SkMatrix::kMTransX] = loc.fX; + matrix[SkMatrix::kMTransY] = loc.fY; + GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, *path, paint, + viewMatrix, &matrix, clipBounds, false); + } + } + pos += scalarsPerPosition; + } +} diff --git a/gfx/skia/skia/src/gpu/text/GrTextUtils.h b/gfx/skia/skia/src/gpu/text/GrTextUtils.h new file mode 100644 index 00000000000..0996f655a37 --- /dev/null +++ b/gfx/skia/skia/src/gpu/text/GrTextUtils.h @@ -0,0 +1,71 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTextUtils_DEFINED +#define GrTextUtils_DEFINED + +#include "GrColor.h" +#include "SkScalar.h" + +class GrAtlasTextBlob; +class GrBatchFontCache; +class GrBatchTextStrike; +class GrClip; +class GrContext; +class GrDrawContext; +class GrFontScaler; +class SkGlyph; +class SkMatrix; +struct SkIRect; +class SkPaint; +struct SkPoint; +class SkGlyphCache; +class SkSurfaceProps; + +/* + * A class to house a bunch of common text utilities. This class should *ONLY* have static + * functions. It is not a namespace only because we wish to friend SkPaint + * + */ +class GrTextUtils { +public: + // Functions for appending BMP text to GrAtlasTextBlob + static void DrawBmpText(GrAtlasTextBlob*, int runIndex, + GrBatchFontCache*, const SkSurfaceProps&, + const SkPaint&, + GrColor, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + SkScalar x, SkScalar y); + + static void DrawBmpPosText(GrAtlasTextBlob*, int runIndex, + GrBatchFontCache*, const SkSurfaceProps&, const SkPaint&, + GrColor, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset); + + // Functions for drawing text as paths + static void DrawTextAsPath(GrContext*, GrDrawContext*, const GrClip& clip, + const SkPaint& origPaint, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, SkScalar x, SkScalar y, + const SkIRect& clipBounds); + + static void DrawPosTextAsPath(GrContext* context, + GrDrawContext* dc, + const SkSurfaceProps& props, + const GrClip& clip, + const SkPaint& origPaint, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset, const SkIRect& clipBounds); +private: + static void BmpAppendGlyph(GrAtlasTextBlob*, int runIndex, GrBatchFontCache*, + GrBatchTextStrike**, const SkGlyph&, int left, int top, + GrColor color, GrFontScaler*); +}; + +#endif diff --git a/gfx/skia/skia/src/image/SkImage.cpp b/gfx/skia/skia/src/image/SkImage.cpp index be837f28a8f..25370bcff15 100644 --- a/gfx/skia/skia/src/image/SkImage.cpp +++ b/gfx/skia/skia/src/image/SkImage.cpp @@ -9,6 +9,7 @@ #include "SkBitmapCache.h" #include "SkCanvas.h" #include "SkData.h" +#include "SkImageEncoder.h" #include "SkImageGenerator.h" #include "SkImagePriv.h" #include "SkImageShader.h" @@ -88,80 +89,6 @@ void SkImage::preroll(GrContext* ctx) const { } } -SkImage* SkImage::applyFilter(SkImageFilter* filter, SkIPoint* offset, - bool forceResultToOriginalSize) const { - if (!filter) { - return nullptr; - } - - SkIPoint offsetStorage; - if (!offset) { - offset = &offsetStorage; - } - return as_IB(this)->onApplyFilter(filter, offset, forceResultToOriginalSize); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#include "SkImageFilter.h" -#include "SkBitmapDevice.h" - -static SkIRect compute_fast_ibounds(SkImageFilter* filter, const SkIRect& srcBounds) { - SkRect fastBounds; - fastBounds.set(srcBounds); - filter->computeFastBounds(fastBounds, &fastBounds); - return fastBounds.roundOut(); -} - -class SkRasterImageFilterProxy : public SkImageFilter::Proxy { -public: - SkBaseDevice* createDevice(int width, int height) override { - return SkBitmapDevice::Create(SkImageInfo::MakeN32Premul(width, height)); - } - - bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&, - SkBitmap*, SkIPoint*) override { - return false; - } -}; - -SkImage* SkImage_Base::onApplyFilter(SkImageFilter* filter, SkIPoint* offsetResult, - bool forceResultToOriginalSize) const { - SkBitmap src; - if (!this->getROPixels(&src)) { - return nullptr; - } - - const SkIRect srcBounds = SkIRect::MakeWH(this->width(), this->height()); - - if (forceResultToOriginalSize) { - const SkIRect clipBounds = srcBounds; - SkRasterImageFilterProxy proxy; - SkImageFilter::Context ctx(SkMatrix::I(), clipBounds, SkImageFilter::Cache::Get(), - SkImageFilter::kExact_SizeConstraint); - - SkBitmap dst; - if (filter->filterImage(&proxy, src, ctx, &dst, offsetResult)) { - dst.setImmutable(); - return SkImage::NewFromBitmap(dst); - } - } else { - const SkIRect dstR = compute_fast_ibounds(filter, srcBounds); - - SkImageInfo info = SkImageInfo::MakeN32Premul(dstR.width(), dstR.height()); - SkAutoTUnref surface(this->onNewSurface(info)); - - SkPaint paint; - paint.setImageFilter(filter); - surface->getCanvas()->drawImage(this, SkIntToScalar(-dstR.x()), SkIntToScalar(-dstR.y()), - &paint); - - offsetResult->set(dstR.x(), dstR.y()); - return surface->newImageSnapshot(); - } - return nullptr; -} - /////////////////////////////////////////////////////////////////////////////////////////////////// SkShader* SkImage::newShader(SkShader::TileMode tileX, @@ -178,25 +105,14 @@ SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const { return nullptr; } -namespace { - -class DefaultSerializer : public SkPixelSerializer { -protected: - bool onUseEncodedData(const void *data, size_t len) override { - return true; - } - - SkData* onEncodePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes) override { - return SkImageEncoder::EncodeData(info, pixels, rowBytes, SkImageEncoder::kPNG_Type, 100); - } -}; - -} // anonymous namespace - SkData* SkImage::encode(SkPixelSerializer* serializer) const { - DefaultSerializer defaultSerializer; - SkPixelSerializer* effectiveSerializer = serializer ? serializer : &defaultSerializer; - + SkAutoTUnref defaultSerializer; + SkPixelSerializer* effectiveSerializer = serializer; + if (!effectiveSerializer) { + defaultSerializer.reset(SkImageEncoder::CreatePixelSerializer()); + SkASSERT(defaultSerializer.get()); + effectiveSerializer = defaultSerializer.get(); + } SkAutoTUnref encoded(this->refEncoded()); if (encoded && effectiveSerializer->useEncodedData(encoded->data(), encoded->size())) { return encoded.detach(); @@ -205,15 +121,15 @@ SkData* SkImage::encode(SkPixelSerializer* serializer) const { SkBitmap bm; SkAutoPixmapUnlock apu; if (as_IB(this)->getROPixels(&bm) && bm.requestLock(&apu)) { - const SkPixmap& pmap = apu.pixmap(); - return effectiveSerializer->encodePixels(pmap.info(), pmap.addr(), pmap.rowBytes()); + return effectiveSerializer->encode(apu.pixmap()); } return nullptr; } SkData* SkImage::refEncoded() const { - return as_IB(this)->onRefEncoded(); + GrContext* ctx = nullptr; // should we allow the caller to pass in a ctx? + return as_IB(this)->onRefEncoded(ctx); } SkImage* SkImage::NewFromEncoded(SkData* encoded, const SkIRect* subset) { diff --git a/gfx/skia/skia/src/image/SkImagePriv.h b/gfx/skia/skia/src/image/SkImagePriv.h index b8f177905dc..7518bbe8088 100644 --- a/gfx/skia/skia/src/image/SkImagePriv.h +++ b/gfx/skia/skia/src/image/SkImagePriv.h @@ -40,14 +40,6 @@ enum ForceCopyMode { }; extern SkImage* SkNewImageFromRasterBitmap(const SkBitmap&, ForceCopyMode = kNo_ForceCopyMode); -static inline size_t SkImageMinRowBytes(const SkImageInfo& info) { - size_t minRB = info.minRowBytes(); - if (kIndex_8_SkColorType != info.colorType()) { - minRB = SkAlign4(minRB); - } - return minRB; -} - // Given an image created from SkNewImageFromBitmap, return its pixelref. This // may be called to see if the surface and the image share the same pixelref, // in which case the surface may need to perform a copy-on-write. diff --git a/gfx/skia/skia/src/image/SkImage_Base.h b/gfx/skia/skia/src/image/SkImage_Base.h index c91430e5bd4..83e51a58b7c 100644 --- a/gfx/skia/skia/src/image/SkImage_Base.h +++ b/gfx/skia/skia/src/image/SkImage_Base.h @@ -15,6 +15,7 @@ #include class GrTextureParams; +class SkImageCacherator; enum { kNeedNewImageUniqueID = 0 @@ -32,14 +33,12 @@ public: int srcX, int srcY, CachingHint) const; virtual GrTexture* peekTexture() const { return nullptr; } + virtual SkImageCacherator* peekCacherator() const { return nullptr; } // return a read-only copy of the pixels. We promise to not modify them, // but only inspect them (or encode them). virtual bool getROPixels(SkBitmap*, CachingHint = kAllow_CachingHint) const = 0; - virtual SkImage* onApplyFilter(SkImageFilter*, SkIPoint* offset, - bool forceResultToOriginalSize) const; - virtual SkSurface* onNewSurface(const SkImageInfo& info) const { return SkSurface::NewRaster(info); } @@ -49,12 +48,19 @@ public: virtual SkImage* onNewSubset(const SkIRect&) const = 0; - virtual SkData* onRefEncoded() const { return nullptr; } + // If a ctx is specified, then only gpu-specific formats are requested. + virtual SkData* onRefEncoded(GrContext*) const { return nullptr; } virtual bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const; virtual bool onIsLazyGenerated() const { return false; } + // Return a bitmap suitable for passing to image-filters + // For now, that means wrapping textures into SkGrPixelRefs... + virtual bool asBitmapForImageFilters(SkBitmap* bitmap) const { + return this->getROPixels(bitmap, kAllow_CachingHint); + } + // Call when this image is part of the key to a resourcecache entry. This allows the cache // to know automatically those entries can be purged when this SkImage deleted. void notifyAddedToCache() const { diff --git a/gfx/skia/skia/src/image/SkImage_Generator.cpp b/gfx/skia/skia/src/image/SkImage_Generator.cpp index fbde92da663..688b4ffe3ba 100644 --- a/gfx/skia/skia/src/image/SkImage_Generator.cpp +++ b/gfx/skia/skia/src/image/SkImage_Generator.cpp @@ -23,7 +23,8 @@ public: bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override; const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const override; - SkData* onRefEncoded() const override; + SkImageCacherator* peekCacherator() const override { return fCache; } + SkData* onRefEncoded(GrContext*) const override; bool isOpaque() const override { return fCache->info().isOpaque(); } SkImage* onNewSubset(const SkIRect&) const override; bool getROPixels(SkBitmap*, CachingHint) const override; @@ -65,8 +66,8 @@ const void* SkImage_Generator::onPeekPixels(SkImageInfo* infoPtr, size_t* rowByt return NULL; } -SkData* SkImage_Generator::onRefEncoded() const { - return fCache->refEncoded(); +SkData* SkImage_Generator::onRefEncoded(GrContext* ctx) const { + return fCache->refEncoded(ctx); } bool SkImage_Generator::getROPixels(SkBitmap* bitmap, CachingHint chint) const { diff --git a/gfx/skia/skia/src/image/SkImage_Gpu.cpp b/gfx/skia/skia/src/image/SkImage_Gpu.cpp index 346f7983b71..1d25635e870 100644 --- a/gfx/skia/skia/src/image/SkImage_Gpu.cpp +++ b/gfx/skia/skia/src/image/SkImage_Gpu.cpp @@ -5,16 +5,18 @@ * found in the LICENSE file. */ -#include "SkBitmapCache.h" -#include "SkImage_Gpu.h" #include "GrCaps.h" #include "GrContext.h" #include "GrDrawContext.h" -#include "GrTextureParamsAdjuster.h" +#include "GrImageIDTextureAdjuster.h" #include "effects/GrYUVtoRGBEffect.h" #include "SkCanvas.h" +#include "SkBitmapCache.h" #include "SkGpuDevice.h" +#include "SkGrPixelRef.h" #include "SkGrPriv.h" +#include "SkImageFilter.h" +#include "SkImage_Gpu.h" #include "SkPixelRef.h" SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrTexture* tex, @@ -69,31 +71,15 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const { return true; } -class GpuImage_GrTextureAdjuster : public GrTextureAdjuster { -public: - GpuImage_GrTextureAdjuster(const SkImage_Gpu* image) - : INHERITED(image->peekTexture()) - , fImage(image) - {} - -protected: - void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) override { - GrUniqueKey baseKey; - GrMakeKeyFromImageID(&baseKey, fImage->uniqueID(), - SkIRect::MakeWH(fImage->width(), fImage->height())); - MakeCopyKeyFromOrigKey(baseKey, params, copyKey); - } - - void didCacheCopy(const GrUniqueKey& copyKey) override { as_IB(fImage)->notifyAddedToCache(); } - -private: - const SkImage* fImage; - - typedef GrTextureAdjuster INHERITED; -}; +bool SkImage_Gpu::asBitmapForImageFilters(SkBitmap* bitmap) const { + bitmap->setInfo(make_info(this->width(), this->height(), this->isOpaque())); + bitmap->setPixelRef(new SkGrPixelRef(bitmap->info(), fTexture))->unref(); + bitmap->pixelRef()->setImmutableWithID(this->uniqueID()); + return true; +} GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& params) const { - return GpuImage_GrTextureAdjuster(this).refTextureSafeForParams(params, nullptr); + return GrImageTextureAdjuster(as_IB(this)).refTextureSafeForParams(params, nullptr); } bool SkImage_Gpu::isOpaque() const { @@ -166,85 +152,6 @@ SkImage* SkImage_Gpu::onNewSubset(const SkIRect& subset) const { /////////////////////////////////////////////////////////////////////////////////////////////////// -#include "SkGrPixelRef.h" -#include "SkImageFilter.h" - -class SkGpuImageFilterProxy : public SkImageFilter::Proxy { - GrContext* fCtx; - -public: - SkGpuImageFilterProxy(GrContext* ctx) : fCtx(ctx) {} - - SkBaseDevice* createDevice(int width, int height) override { - GrSurfaceDesc desc; - desc.fConfig = kSkia8888_GrPixelConfig; - desc.fFlags = kRenderTarget_GrSurfaceFlag; - desc.fWidth = width; - desc.fHeight = height; - desc.fSampleCnt = 0; - - SkAutoTUnref texture(fCtx->textureProvider()->createTexture(desc, true)); - - if (texture) { - SkSurfaceProps props(0, kUnknown_SkPixelGeometry); - return SkGpuDevice::Create(texture->asRenderTarget(), width, height, &props, - SkGpuDevice::kClear_InitContents); - } else { - return nullptr; - } - } - - bool filterImage(const SkImageFilter* filter, const SkBitmap& src, - const SkImageFilter::Context& ctx, SkBitmap* dst, SkIPoint* offset) override { - return filter->canFilterImageGPU() && - filter->filterImageGPU(this, src, ctx, dst, offset); - } -}; - -static SkIRect compute_fast_ibounds(SkImageFilter* filter, const SkIRect& srcBounds) { - SkRect fastBounds; - fastBounds.set(srcBounds); - filter->computeFastBounds(fastBounds, &fastBounds); - return fastBounds.roundOut(); -} - -SkImage* SkImage_Gpu::onApplyFilter(SkImageFilter* filter, SkIPoint* offsetResult, - bool forceResultToOriginalSize) const { - const SkIRect srcBounds = SkIRect::MakeWH(this->width(), this->height()); - - if (forceResultToOriginalSize) { - SkBitmap src; - GrWrapTextureInBitmap(fTexture, this->width(), this->height(), this->isOpaque(), &src); - - const SkIRect clipBounds = srcBounds; - SkGpuImageFilterProxy proxy(fTexture->getContext()); - SkAutoTUnref cache(SkGpuDevice::NewImageFilterCache()); - SkImageFilter::Context ctx(SkMatrix::I(), clipBounds, cache, SkImageFilter::kExact_SizeConstraint); - - SkBitmap dst; - if (!filter->filterImage(&proxy, src, ctx, &dst, offsetResult)) { - return nullptr; - } - return new SkImage_Gpu(dst.width(), dst.height(), kNeedNewImageUniqueID, dst.alphaType(), - dst.getTexture(), SkSurface::kNo_Budgeted); - } - - const SkIRect dstR = compute_fast_ibounds(filter, srcBounds); - - SkImageInfo info = SkImageInfo::MakeN32Premul(dstR.width(), dstR.height()); - SkAutoTUnref surface(this->onNewSurface(info)); - - SkPaint paint; - paint.setImageFilter(filter); - surface->getCanvas()->drawImage(this, SkIntToScalar(-dstR.x()), SkIntToScalar(-dstR.y()), - &paint); - - offsetResult->set(dstR.x(), dstR.y()); - return surface->newImageSnapshot(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - static SkImage* new_wrapped_texture_common(GrContext* ctx, const GrBackendTextureDesc& desc, SkAlphaType at, GrWrapOwnership ownership, SkImage::TextureReleaseProc releaseProc, diff --git a/gfx/skia/skia/src/image/SkImage_Gpu.h b/gfx/skia/skia/src/image/SkImage_Gpu.h index ff3b12e668d..a36c8ebc135 100644 --- a/gfx/skia/skia/src/image/SkImage_Gpu.h +++ b/gfx/skia/skia/src/image/SkImage_Gpu.h @@ -43,13 +43,13 @@ public: bool isOpaque() const override; bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint) const override; - SkImage* onApplyFilter(SkImageFilter*, SkIPoint* offset, - bool forceResultToOriginalSize) const override; SkSurface* onNewSurface(const SkImageInfo& info) const override { return SkSurface::NewRenderTarget(fTexture->getContext(), SkSurface::kNo_Budgeted, info); } + bool asBitmapForImageFilters(SkBitmap* bitmap) const override; + private: SkAutoTUnref fTexture; const SkAlphaType fAlphaType; diff --git a/gfx/skia/skia/src/image/SkImage_Raster.cpp b/gfx/skia/skia/src/image/SkImage_Raster.cpp index 977dc01c4bb..d4debdf807e 100644 --- a/gfx/skia/skia/src/image/SkImage_Raster.cpp +++ b/gfx/skia/skia/src/image/SkImage_Raster.cpp @@ -48,7 +48,7 @@ public: return false; } - if (rowBytes < SkImageMinRowBytes(info)) { + if (rowBytes < info.minRowBytes()) { return false; } @@ -68,7 +68,7 @@ public: bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override; const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const override; - SkData* onRefEncoded() const override; + SkData* onRefEncoded(GrContext*) const override; bool getROPixels(SkBitmap*, CachingHint) const override; GrTexture* asTextureRef(GrContext*, const GrTextureParams&) const override; SkImage* onNewSubset(const SkIRect&) const override; @@ -150,7 +150,7 @@ const void* SkImage_Raster::onPeekPixels(SkImageInfo* infoPtr, size_t* rowBytesP return fBitmap.getPixels(); } -SkData* SkImage_Raster::onRefEncoded() const { +SkData* SkImage_Raster::onRefEncoded(GrContext*) const { SkPixelRef* pr = fBitmap.pixelRef(); const SkImageInfo prInfo = pr->info(); const SkImageInfo bmInfo = fBitmap.info(); diff --git a/gfx/skia/skia/src/image/SkSurface_Raster.cpp b/gfx/skia/skia/src/image/SkSurface_Raster.cpp index d5593eb1d7d..a6066567094 100644 --- a/gfx/skia/skia/src/image/SkSurface_Raster.cpp +++ b/gfx/skia/skia/src/image/SkSurface_Raster.cpp @@ -99,10 +99,6 @@ SkSurface_Raster::SkSurface_Raster(SkPixelRef* pr, const SkSurfaceProps* props) fBitmap.setInfo(info, info.minRowBytes()); fBitmap.setPixelRef(pr); fWeOwnThePixels = true; - - if (!info.isOpaque()) { - fBitmap.eraseColor(SK_ColorTRANSPARENT); - } } SkCanvas* SkSurface_Raster::onNewCanvas() { return new SkCanvas(fBitmap, this->props()); } @@ -185,7 +181,7 @@ SkSurface* SkSurface::NewRaster(const SkImageInfo& info, const SkSurfaceProps* p return nullptr; } - SkAutoTUnref pr(SkMallocPixelRef::NewAllocate(info, 0, nullptr)); + SkAutoTUnref pr(SkMallocPixelRef::NewZeroed(info, 0, nullptr)); if (nullptr == pr.get()) { return nullptr; } diff --git a/gfx/skia/skia/src/images/SkDecodingImageGenerator.cpp b/gfx/skia/skia/src/images/SkDecodingImageGenerator.cpp index 8cfacc3fba1..8d55bd36c7b 100644 --- a/gfx/skia/skia/src/images/SkDecodingImageGenerator.cpp +++ b/gfx/skia/skia/src/images/SkDecodingImageGenerator.cpp @@ -37,7 +37,7 @@ public: bool ditherImage); protected: - SkData* onRefEncodedData() override; + SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) override; bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) override; bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], @@ -126,7 +126,7 @@ DecodingImageGenerator::~DecodingImageGenerator() { SkSafeUnref(fData); } -SkData* DecodingImageGenerator::onRefEncodedData() { +SkData* DecodingImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { // This functionality is used in `gm --serialize` // Does not encode options. if (nullptr == fData) { diff --git a/gfx/skia/skia/src/images/SkImageDecoder_libgif.cpp b/gfx/skia/skia/src/images/SkImageDecoder_libgif.cpp index ef55a8f2e0c..2677b130736 100644 --- a/gfx/skia/skia/src/images/SkImageDecoder_libgif.cpp +++ b/gfx/skia/skia/src/images/SkImageDecoder_libgif.cpp @@ -378,8 +378,8 @@ SkImageDecoder::Result SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap SkAutoLockPixels alp(*bm); - SkAutoMalloc storage(innerWidth); - uint8_t* scanline = (uint8_t*) storage.get(); + SkAutoTMalloc storage(innerWidth); + uint8_t* scanline = storage.get(); // GIF has an option to store the scanlines of an image, plus a larger background, // filled by a fill color. In this case, we will use a subset of the larger bitmap diff --git a/gfx/skia/skia/src/images/SkImageDecoder_libico.cpp b/gfx/skia/skia/src/images/SkImageDecoder_libico.cpp index e8b4bc5c316..cb21b6906e9 100644 --- a/gfx/skia/skia/src/images/SkImageDecoder_libico.cpp +++ b/gfx/skia/skia/src/images/SkImageDecoder_libico.cpp @@ -32,8 +32,8 @@ private: //read in Intel order, and return an integer #define readByte(buffer,begin) buffer[begin] -#define read2Bytes(buffer,begin) buffer[begin]+(buffer[begin+1]<<8) -#define read4Bytes(buffer,begin) buffer[begin]+(buffer[begin+1]<<8)+(buffer[begin+2]<<16)+(buffer[begin+3]<<24) +#define read2Bytes(buffer,begin) buffer[begin]+SkLeftShift(buffer[begin+1],8) +#define read4Bytes(buffer,begin) buffer[begin]+SkLeftShift(buffer[begin+1],8)+SkLeftShift(buffer[begin+2],16)+SkLeftShift(buffer[begin+3],24) ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/images/SkImageDecoder_libjpeg.cpp b/gfx/skia/skia/src/images/SkImageDecoder_libjpeg.cpp index 58eff75dc94..0d02a658f29 100644 --- a/gfx/skia/skia/src/images/SkImageDecoder_libjpeg.cpp +++ b/gfx/skia/skia/src/images/SkImageDecoder_libjpeg.cpp @@ -37,13 +37,8 @@ extern "C" { // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. -#if defined(SK_DEBUG) -#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS false -#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS false -#else // !defined(SK_DEBUG) #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true -#endif // defined(SK_DEBUG) SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings, "images.jpeg.suppressDecoderWarnings", DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS, @@ -501,8 +496,8 @@ SkImageDecoder::Result SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* return return_failure(cinfo, *bm, "sampler.begin"); } - SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); - uint8_t* srcRow = (uint8_t*)srcStorage.get(); + SkAutoTMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); + uint8_t* srcRow = srcStorage.get(); // Possibly skip initial rows [sampler.srcY0] if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { @@ -936,7 +931,7 @@ protected: skjpeg_destination_mgr sk_wstream(stream); // allocate these before set call setjmp - SkAutoMalloc oneRow; + SkAutoTMalloc oneRow; cinfo.err = jpeg_std_error(&sk_err); sk_err.error_exit = skjpeg_error_exit; @@ -971,7 +966,7 @@ protected: jpeg_start_compress(&cinfo, TRUE); const int width = bm.width(); - uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); + uint8_t* oneRowP = oneRow.reset(width * 3); const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readColors() : nullptr; const void* srcRow = bm.getPixels(); diff --git a/gfx/skia/skia/src/images/SkImageDecoder_libpng.cpp b/gfx/skia/skia/src/images/SkImageDecoder_libpng.cpp index a03ed10453f..cd8152a36bb 100644 --- a/gfx/skia/skia/src/images/SkImageDecoder_libpng.cpp +++ b/gfx/skia/skia/src/images/SkImageDecoder_libpng.cpp @@ -37,11 +37,7 @@ #define png_flush_ptr_NULL nullptr #endif -#if defined(SK_DEBUG) -#define DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS false -#else // !defined(SK_DEBUG) #define DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS true -#endif // defined(SK_DEBUG) SK_CONF_DECLARE(bool, c_suppressPNGImageDecoderWarnings, "images.png.suppressDecoderWarnings", DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS, @@ -132,7 +128,9 @@ static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { #endif static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { - SkDEBUGF(("------ png error %s\n", msg)); + if (!c_suppressPNGImageDecoderWarnings) { + SkDEBUGF(("------ png error %s\n", msg)); + } longjmp(png_jmpbuf(png_ptr), 1); } @@ -403,8 +401,8 @@ SkImageDecoder::Result SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap const int height = decodedBitmap->height(); if (number_passes > 1) { - SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); - uint8_t* base = (uint8_t*)storage.get(); + SkAutoTMalloc storage(origWidth * origHeight * srcBytesPerPixel); + uint8_t* base = storage.get(); size_t rowBytes = origWidth * srcBytesPerPixel; for (int i = 0; i < number_passes; i++) { @@ -422,8 +420,8 @@ SkImageDecoder::Result SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap base += sampler.srcDY() * rowBytes; } } else { - SkAutoMalloc storage(origWidth * srcBytesPerPixel); - uint8_t* srcRow = (uint8_t*)storage.get(); + SkAutoTMalloc storage(origWidth * srcBytesPerPixel); + uint8_t* srcRow = storage.get(); skip_src_rows(png_ptr, srcRow, sampler.srcY0()); for (int y = 0; y < height; y++) { @@ -827,10 +825,28 @@ private: typedef SkImageEncoder INHERITED; }; -bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int /*quality*/) { - SkColorType ct = bitmap.colorType(); +bool SkPNGImageEncoder::onEncode(SkWStream* stream, + const SkBitmap& originalBitmap, + int /*quality*/) { + SkBitmap copy; + const SkBitmap* bitmap = &originalBitmap; + switch (originalBitmap.colorType()) { + case kIndex_8_SkColorType: + case kN32_SkColorType: + case kARGB_4444_SkColorType: + case kRGB_565_SkColorType: + break; + default: + // TODO(scroggo): support 8888-but-not-N32 natively. + // TODO(scroggo): support kGray_8 directly. + // TODO(scroggo): support Alpha_8 as Grayscale(black)+Alpha + if (originalBitmap.copyTo(©, kN32_SkColorType)) { + bitmap = © + } + } + SkColorType ct = bitmap->colorType(); - const bool hasAlpha = !bitmap.isOpaque(); + const bool hasAlpha = !bitmap->isOpaque(); int colorType = PNG_COLOR_MASK_COLOR; int bitDepth = 8; // default for color png_color_8 sig_bit; @@ -870,14 +886,14 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int sig_bit.alpha = 0; } - SkAutoLockPixels alp(bitmap); + SkAutoLockPixels alp(*bitmap); // readyToDraw checks for pixels (and colortable if that is required) - if (!bitmap.readyToDraw()) { + if (!bitmap->readyToDraw()) { return false; } // we must do this after we have locked the pixels - SkColorTable* ctable = bitmap.getColorTable(); + SkColorTable* ctable = bitmap->getColorTable(); if (ctable) { if (ctable->count() == 0) { return false; @@ -886,7 +902,7 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int bitDepth = computeBitDepth(ctable->count()); } - return doEncode(stream, bitmap, hasAlpha, colorType, bitDepth, ct, sig_bit); + return doEncode(stream, *bitmap, hasAlpha, colorType, bitDepth, ct, sig_bit); } bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, @@ -950,8 +966,8 @@ bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, png_write_info(png_ptr, info_ptr); const char* srcImage = (const char*)bitmap.getPixels(); - SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2); - char* storage = (char*)rowStorage.get(); + SkAutoSTMalloc<1024, char> rowStorage(bitmap.width() << 2); + char* storage = rowStorage.get(); transform_scanline_proc proc = choose_proc(ct, hasAlpha); for (int y = 0; y < bitmap.height(); y++) { diff --git a/gfx/skia/skia/src/images/SkImageDecoder_libwebp.cpp b/gfx/skia/skia/src/images/SkImageDecoder_libwebp.cpp index 07ff83de9bb..52535779fa0 100644 --- a/gfx/skia/skia/src/images/SkImageDecoder_libwebp.cpp +++ b/gfx/skia/skia/src/images/SkImageDecoder_libwebp.cpp @@ -201,8 +201,8 @@ static bool webp_idecode(SkStream* stream, WebPDecoderConfig* config) { } const size_t readBufferSize = stream->hasLength() ? SkTMin(stream->getLength(), WEBP_IDECODE_BUFFER_SZ) : WEBP_IDECODE_BUFFER_SZ; - SkAutoMalloc srcStorage(readBufferSize); - unsigned char* input = (uint8_t*)srcStorage.get(); + SkAutoTMalloc srcStorage(readBufferSize); + unsigned char* input = srcStorage.get(); if (nullptr == input) { WebPIDelete(idec); WebPFreeDecBuffer(&config->output); diff --git a/gfx/skia/skia/src/images/SkImageEncoder.cpp b/gfx/skia/skia/src/images/SkImageEncoder.cpp index cc1b73baa52..22bbc57c2f5 100644 --- a/gfx/skia/skia/src/images/SkImageEncoder.cpp +++ b/gfx/skia/skia/src/images/SkImageEncoder.cpp @@ -7,6 +7,8 @@ #include "SkImageEncoder.h" #include "SkBitmap.h" +#include "SkPixelSerializer.h" +#include "SkPixmap.h" #include "SkStream.h" #include "SkTemplates.h" @@ -57,6 +59,30 @@ SkData* SkImageEncoder::EncodeData(const SkImageInfo& info, const void* pixels, if (!bm.installPixels(info, const_cast(pixels), rowBytes)) { return nullptr; } - SkAutoTDelete enc(SkImageEncoder::Create(t)); - return enc.get() ? enc.get()->encodeData(bm, quality) : nullptr; + bm.setImmutable(); + return SkImageEncoder::EncodeData(bm, t, quality); +} + +SkData* SkImageEncoder::EncodeData(const SkPixmap& pixmap, + Type t, int quality) { + SkBitmap bm; + if (!bm.installPixels(pixmap)) { + return nullptr; + } + bm.setImmutable(); + return SkImageEncoder::EncodeData(bm, t, quality); +} + +namespace { +class ImageEncoderPixelSerializer final : public SkPixelSerializer { +protected: + bool onUseEncodedData(const void*, size_t) override { return true; } + SkData* onEncode(const SkPixmap& pmap) override { + return SkImageEncoder::EncodeData(pmap, SkImageEncoder::kPNG_Type, 100); + } +}; +} // namespace + +SkPixelSerializer* SkImageEncoder::CreatePixelSerializer() { + return new ImageEncoderPixelSerializer; } diff --git a/gfx/skia/skia/src/opts/Sk4px_NEON.h b/gfx/skia/skia/src/opts/Sk4px_NEON.h index c27bb13764f..62f1deb4ac2 100644 --- a/gfx/skia/skia/src/opts/Sk4px_NEON.h +++ b/gfx/skia/skia/src/opts/Sk4px_NEON.h @@ -58,9 +58,9 @@ inline Sk4px Sk4px::Wide::addNarrowHi(const Sk16h& other) const { } inline Sk4px Sk4px::Wide::div255() const { - // Calculated as ((x+128) + ((x+128)>>8)) >> 8. - auto v = *this + Sk16h(128); - return v.addNarrowHi(v>>8); + // Calculated as (x + (x+128)>>8 +128) >> 8. The 'r' in each instruction provides each +128. + return Sk16b(vcombine_u8(vraddhn_u16(this->fLo.fVec, vrshrq_n_u16(this->fLo.fVec, 8)), + vraddhn_u16(this->fHi.fVec, vrshrq_n_u16(this->fHi.fVec, 8)))); } inline Sk4px Sk4px::alphas() const { @@ -95,76 +95,5 @@ inline Sk4px Sk4px::zeroAlphas() const { return Sk16b(vbicq_u8(this->fVec, (uint8x16_t)vdupq_n_u32(0xFF << SK_A32_SHIFT))); } -static inline uint8x16_t widen_to_8888(uint16x4_t v) { - // RGB565 format: |R....|G.....|B....| - // Bit: 16 11 5 0 - - // First get each pixel into its own 32-bit lane. - // v == rgb3 rgb2 rgb1 rgb0 - // spread == 0000 rgb3 0000 rgb2 0000 rgb1 0000 rgb0 - uint32x4_t spread = vmovl_u16(v); - - // Get each color independently, still in 565 precison but down at bit 0. - auto r5 = vshrq_n_u32(spread, 11), - g6 = vandq_u32(vdupq_n_u32(63), vshrq_n_u32(spread, 5)), - b5 = vandq_u32(vdupq_n_u32(31), spread); - - // Scale 565 precision up to 8-bit each, filling low 323 bits with high bits of each component. - auto r8 = vorrq_u32(vshlq_n_u32(r5, 3), vshrq_n_u32(r5, 2)), - g8 = vorrq_u32(vshlq_n_u32(g6, 2), vshrq_n_u32(g6, 4)), - b8 = vorrq_u32(vshlq_n_u32(b5, 3), vshrq_n_u32(b5, 2)); - - // Now put all the 8-bit components into SkPMColor order. - return (uint8x16_t)vorrq_u32(vshlq_n_u32(r8, SK_R32_SHIFT), // TODO: one shift is zero... - vorrq_u32(vshlq_n_u32(g8, SK_G32_SHIFT), - vorrq_u32(vshlq_n_u32(b8, SK_B32_SHIFT), - vdupq_n_u32(0xFF << SK_A32_SHIFT)))); -} - -static inline uint16x4_t narrow_to_565(uint8x16_t w8x16) { - uint32x4_t w = (uint32x4_t)w8x16; - - // Extract out top RGB 565 bits of each pixel, with no rounding. - auto r5 = vandq_u32(vdupq_n_u32(31), vshrq_n_u32(w, SK_R32_SHIFT + 3)), - g6 = vandq_u32(vdupq_n_u32(63), vshrq_n_u32(w, SK_G32_SHIFT + 2)), - b5 = vandq_u32(vdupq_n_u32(31), vshrq_n_u32(w, SK_B32_SHIFT + 3)); - - // Now put the bits in place in the low 16-bits of each 32-bit lane. - auto spread = vorrq_u32(vshlq_n_u32(r5, 11), - vorrq_u32(vshlq_n_u32(g6, 5), - b5)); - - // Pack the low 16-bits of our 128-bit register down into a 64-bit register. - // spread == 0000 rgb3 0000 rgb2 0000 rgb1 0000 rgb0 - // v == rgb3 rgb2 rgb1 rgb0 - auto v = vmovn_u32(spread); - return v; -} - - -inline Sk4px Sk4px::Load4(const SkPMColor16 src[4]) { - return Sk16b(widen_to_8888(vld1_u16(src))); -} -inline Sk4px Sk4px::Load2(const SkPMColor16 src[2]) { - auto src2 = ((uint32_t)src[0] ) - | ((uint32_t)src[1] << 16); - return Sk16b(widen_to_8888(vcreate_u16(src2))); -} -inline Sk4px Sk4px::Load1(const SkPMColor16 src[1]) { - return Sk16b(widen_to_8888(vcreate_u16(src[0]))); -} - -inline void Sk4px::store4(SkPMColor16 dst[4]) const { - vst1_u16(dst, narrow_to_565(this->fVec)); -} -inline void Sk4px::store2(SkPMColor16 dst[2]) const { - auto v = narrow_to_565(this->fVec); - dst[0] = vget_lane_u16(v, 0); - dst[1] = vget_lane_u16(v, 1); -} -inline void Sk4px::store1(SkPMColor16 dst[1]) const { - dst[0] = vget_lane_u16(narrow_to_565(this->fVec), 0); -} - } // namespace diff --git a/gfx/skia/skia/src/opts/Sk4px_SSE2.h b/gfx/skia/skia/src/opts/Sk4px_SSE2.h index 96f21db3991..dc0c8ace70b 100644 --- a/gfx/skia/skia/src/opts/Sk4px_SSE2.h +++ b/gfx/skia/skia/src/opts/Sk4px_SSE2.h @@ -101,79 +101,4 @@ inline Sk4px Sk4px::zeroAlphas() const { return Sk16b(_mm_andnot_si128(_mm_set1_epi32(0xFF << SK_A32_SHIFT), this->fVec)); } -static inline __m128i widen_low_half_to_8888(__m128i v) { - // RGB565 format: |R....|G.....|B....| - // Bit: 16 11 5 0 - - // First get each pixel into its own 32-bit lane. - // v == ____ ____ ____ ____ rgb3 rgb2 rgb1 rgb0 - // spread == 0000 rgb3 0000 rgb2 0000 rgb1 0000 rgb0 - auto spread = _mm_unpacklo_epi16(v, _mm_setzero_si128()); - - // Get each color independently, still in 565 precison but down at bit 0. - auto r5 = _mm_srli_epi32(spread, 11), - g6 = _mm_and_si128(_mm_set1_epi32(63), _mm_srli_epi32(spread, 5)), - b5 = _mm_and_si128(_mm_set1_epi32(31), spread); - - // Scale 565 precision up to 8-bit each, filling low 323 bits with high bits of each component. - auto r8 = _mm_or_si128(_mm_slli_epi32(r5, 3), _mm_srli_epi32(r5, 2)), - g8 = _mm_or_si128(_mm_slli_epi32(g6, 2), _mm_srli_epi32(g6, 4)), - b8 = _mm_or_si128(_mm_slli_epi32(b5, 3), _mm_srli_epi32(b5, 2)); - - // Now put all the 8-bit components into SkPMColor order. - return _mm_or_si128(_mm_slli_epi32(r8, SK_R32_SHIFT), // TODO: one of these shifts is zero... - _mm_or_si128(_mm_slli_epi32(g8, SK_G32_SHIFT), - _mm_or_si128(_mm_slli_epi32(b8, SK_B32_SHIFT), - _mm_set1_epi32(0xFF << SK_A32_SHIFT)))); -} - -static inline __m128i narrow_to_565(__m128i w) { - // Extract out top RGB 565 bits of each pixel, with no rounding. - auto r5 = _mm_and_si128(_mm_set1_epi32(31), _mm_srli_epi32(w, SK_R32_SHIFT + 3)), - g6 = _mm_and_si128(_mm_set1_epi32(63), _mm_srli_epi32(w, SK_G32_SHIFT + 2)), - b5 = _mm_and_si128(_mm_set1_epi32(31), _mm_srli_epi32(w, SK_B32_SHIFT + 3)); - - // Now put the bits in place in the low 16-bits of each 32-bit lane. - auto spread = _mm_or_si128(_mm_slli_epi32(r5, 11), - _mm_or_si128(_mm_slli_epi32(g6, 5), - b5)); - - // We want to pack the bottom 16-bits of spread down into the low half of the register, v. - // spread == 0000 rgb3 0000 rgb2 0000 rgb1 0000 rgb0 - // v == ____ ____ ____ ____ rgb3 rgb2 rgb1 rgb0 - - // Ideally now we'd use _mm_packus_epi32(spread, ) to pack v. But that's from SSE4. - // With only SSE2, we need to use _mm_packs_epi32. That does signed saturation, and - // we need to preserve all 16 bits. So we pretend our data is signed by sign-extending first. - // TODO: is it faster to just _mm_shuffle_epi8 this when we have SSSE3? - auto signExtended = _mm_srai_epi32(_mm_slli_epi32(spread, 16), 16); - auto v = _mm_packs_epi32(signExtended, signExtended); - return v; -} - -inline Sk4px Sk4px::Load4(const SkPMColor16 src[4]) { - return Sk16b(widen_low_half_to_8888(_mm_loadl_epi64((const __m128i*)src))); -} -inline Sk4px Sk4px::Load2(const SkPMColor16 src[2]) { - auto src2 = ((uint32_t)src[0] ) - | ((uint32_t)src[1] << 16); - return Sk16b(widen_low_half_to_8888(_mm_cvtsi32_si128(src2))); -} -inline Sk4px Sk4px::Load1(const SkPMColor16 src[1]) { - return Sk16b(widen_low_half_to_8888(_mm_insert_epi16(_mm_setzero_si128(), src[0], 0))); -} - -inline void Sk4px::store4(SkPMColor16 dst[4]) const { - _mm_storel_epi64((__m128i*)dst, narrow_to_565(this->fVec)); -} -inline void Sk4px::store2(SkPMColor16 dst[2]) const { - uint32_t dst2 = _mm_cvtsi128_si32(narrow_to_565(this->fVec)); - dst[0] = dst2; - dst[1] = dst2 >> 16; -} -inline void Sk4px::store1(SkPMColor16 dst[1]) const { - uint32_t dst2 = _mm_cvtsi128_si32(narrow_to_565(this->fVec)); - dst[0] = dst2; -} - } // namespace diff --git a/gfx/skia/skia/src/opts/Sk4px_none.h b/gfx/skia/skia/src/opts/Sk4px_none.h index efbd780c9fc..b43ee875b25 100644 --- a/gfx/skia/skia/src/opts/Sk4px_none.h +++ b/gfx/skia/skia/src/opts/Sk4px_none.h @@ -106,35 +106,4 @@ inline Sk4px Sk4px::zeroColors() const { 0,0,0, this->kth<15>()); } -inline Sk4px Sk4px::Load4(const SkPMColor16 src[4]) { - SkPMColor src32[4]; - for (int i = 0; i < 4; i++) { src32[i] = SkPixel16ToPixel32(src[i]); } - return Load4(src32); -} -inline Sk4px Sk4px::Load2(const SkPMColor16 src[2]) { - SkPMColor src32[2]; - for (int i = 0; i < 2; i++) { src32[i] = SkPixel16ToPixel32(src[i]); } - return Load2(src32); -} -inline Sk4px Sk4px::Load1(const SkPMColor16 src[1]) { - SkPMColor src32 = SkPixel16ToPixel32(src[0]); - return Load1(&src32); -} - -inline void Sk4px::store4(SkPMColor16 dst[4]) const { - SkPMColor dst32[4]; - this->store4(dst32); - for (int i = 0; i < 4; i++) { dst[i] = SkPixel32ToPixel16(dst32[i]); } -} -inline void Sk4px::store2(SkPMColor16 dst[2]) const { - SkPMColor dst32[2]; - this->store2(dst32); - for (int i = 0; i < 2; i++) { dst[i] = SkPixel32ToPixel16(dst32[i]); } -} -inline void Sk4px::store1(SkPMColor16 dst[1]) const { - SkPMColor dst32; - this->store1(&dst32); - dst[0] = SkPixel32ToPixel16(dst32); -} - } // namespace diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_arm_neon.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_arm_neon.cpp index d1f71c270ce..ce2656da654 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_arm_neon.cpp +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_arm_neon.cpp @@ -15,7 +15,6 @@ // Required to ensure the table is part of the final binary. extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; -extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[]; #define NAME_WRAP(x) x ## _neon #include "SkBitmapProcState_filter_neon.h" @@ -79,30 +78,6 @@ const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[] = { SG8_alpha_D32_filter_DX_neon, }; -const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[] = { - S32_D16_nofilter_DXDY_neon, - S32_D16_nofilter_DX_neon, - S32_D16_filter_DXDY_neon, - S32_D16_filter_DX_neon, - - S16_D16_nofilter_DXDY_neon, - S16_D16_nofilter_DX_neon, - S16_D16_filter_DXDY_neon, - S16_D16_filter_DX_neon, - - SI8_D16_nofilter_DXDY_neon, - SI8_D16_nofilter_DX_neon, - SI8_D16_filter_DXDY_neon, - SI8_D16_filter_DX_neon, - - // Don't support 4444 -> 565 - nullptr, nullptr, nullptr, nullptr, - // Don't support A8 -> 565 - nullptr, nullptr, nullptr, nullptr, - // Don't support G8 -> 565 (but we could) - nullptr, nullptr, nullptr, nullptr, -}; - /////////////////////////////////////////////////////////////////////////////// #include diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.cpp index 68d920d8d81..cffe9625e50 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.cpp +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.cpp @@ -632,117 +632,3 @@ void ClampX_ClampY_nofilter_affine_SSE2(const SkBitmapProcState& s, fy += dy; } } - -/* SSE version of S32_D16_filter_DX_SSE2 - * Definition is in section of "D16 functions for SRC == 8888" in SkBitmapProcState.cpp - * It combines S32_opaque_D32_filter_DX_SSE2 and SkPixel32ToPixel16 - */ -void S32_D16_filter_DX_SSE2(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint16_t* colors) { - SkASSERT(count > 0 && colors != nullptr); - SkASSERT(s.fFilterLevel != kNone_SkFilterQuality); - SkASSERT(kN32_SkColorType == s.fPixmap.colorType()); - SkASSERT(s.fPixmap.isOpaque()); - - SkPMColor dstColor; - const char* srcAddr = static_cast(s.fPixmap.addr()); - size_t rb = s.fPixmap.rowBytes(); - uint32_t XY = *xy++; - unsigned y0 = XY >> 14; - const uint32_t* row0 = reinterpret_cast(srcAddr + (y0 >> 4) * rb); - const uint32_t* row1 = reinterpret_cast(srcAddr + (XY & 0x3FFF) * rb); - unsigned subY = y0 & 0xF; - - // ( 0, 0, 0, 0, 0, 0, 0, 16) - __m128i sixteen = _mm_cvtsi32_si128(16); - - // ( 0, 0, 0, 0, 16, 16, 16, 16) - sixteen = _mm_shufflelo_epi16(sixteen, 0); - - // ( 0, 0, 0, 0, 0, 0, 0, y) - __m128i allY = _mm_cvtsi32_si128(subY); - - // ( 0, 0, 0, 0, y, y, y, y) - allY = _mm_shufflelo_epi16(allY, 0); - - // ( 0, 0, 0, 0, 16-y, 16-y, 16-y, 16-y) - __m128i negY = _mm_sub_epi16(sixteen, allY); - - // (16-y, 16-y, 16-y, 16-y, y, y, y, y) - allY = _mm_unpacklo_epi64(allY, negY); - - // (16, 16, 16, 16, 16, 16, 16, 16 ) - sixteen = _mm_shuffle_epi32(sixteen, 0); - - // ( 0, 0, 0, 0, 0, 0, 0, 0) - __m128i zero = _mm_setzero_si128(); - - do { - uint32_t XX = *xy++; // x0:14 | 4 | x1:14 - unsigned x0 = XX >> 18; - unsigned x1 = XX & 0x3FFF; - - // (0, 0, 0, 0, 0, 0, 0, x) - __m128i allX = _mm_cvtsi32_si128((XX >> 14) & 0x0F); - - // (0, 0, 0, 0, x, x, x, x) - allX = _mm_shufflelo_epi16(allX, 0); - - // (x, x, x, x, x, x, x, x) - allX = _mm_shuffle_epi32(allX, 0); - - // (16-x, 16-x, 16-x, 16-x, 16-x, 16-x, 16-x) - __m128i negX = _mm_sub_epi16(sixteen, allX); - - // Load 4 samples (pixels). - __m128i a00 = _mm_cvtsi32_si128(row0[x0]); - __m128i a01 = _mm_cvtsi32_si128(row0[x1]); - __m128i a10 = _mm_cvtsi32_si128(row1[x0]); - __m128i a11 = _mm_cvtsi32_si128(row1[x1]); - - // (0, 0, a00, a10) - __m128i a00a10 = _mm_unpacklo_epi32(a10, a00); - - // Expand to 16 bits per component. - a00a10 = _mm_unpacklo_epi8(a00a10, zero); - - // ((a00 * (16-y)), (a10 * y)). - a00a10 = _mm_mullo_epi16(a00a10, allY); - - // (a00 * (16-y) * (16-x), a10 * y * (16-x)). - a00a10 = _mm_mullo_epi16(a00a10, negX); - - // (0, 0, a01, a10) - __m128i a01a11 = _mm_unpacklo_epi32(a11, a01); - - // Expand to 16 bits per component. - a01a11 = _mm_unpacklo_epi8(a01a11, zero); - - // (a01 * (16-y)), (a11 * y) - a01a11 = _mm_mullo_epi16(a01a11, allY); - - // (a01 * (16-y) * x), (a11 * y * x) - a01a11 = _mm_mullo_epi16(a01a11, allX); - - // (a00*w00 + a01*w01, a10*w10 + a11*w11) - __m128i sum = _mm_add_epi16(a00a10, a01a11); - - // (DC, a00*w00 + a01*w01) - __m128i shifted = _mm_shuffle_epi32(sum, 0xEE); - - // (DC, a00*w00 + a01*w01 + a10*w10 + a11*w11) - sum = _mm_add_epi16(sum, shifted); - - // Divide each 16 bit component by 256. - sum = _mm_srli_epi16(sum, 8); - - // Pack lower 4 16 bit values of sum into lower 4 bytes. - sum = _mm_packus_epi16(sum, zero); - - // Extract low int and store. - dstColor = _mm_cvtsi128_si32(sum); - - *colors++ = SkPixel32ToPixel16(dstColor); - } while (--count > 0); -} diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.h b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.h index 82bf2cdae17..d14f282dee1 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.h +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSE2.h @@ -24,8 +24,5 @@ void ClampX_ClampY_filter_affine_SSE2(const SkBitmapProcState& s, uint32_t xy[], int count, int x, int y); void ClampX_ClampY_nofilter_affine_SSE2(const SkBitmapProcState& s, uint32_t xy[], int count, int x, int y); -void S32_D16_filter_DX_SSE2(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint16_t* colors); #endif diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp index 8e381eb3c27..2de8e4049a9 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp @@ -732,28 +732,6 @@ void S32_alpha_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s, S32_generic_D32_filter_DXDY_SSSE3(s, xy, count, colors); } -void S32_D16_filter_DX_SSSE3(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint16_t* colors) { - SkASSERT(254 >= count); - SkAutoSTMalloc<254, uint32_t> colors32(count); - S32_generic_D32_filter_DX_SSSE3(s, xy, count, colors32); - for(int i = 0; i < count; i++) { - *colors++ = SkPixel32ToPixel16(colors32[i]); - } -} - -void S32_D16_filter_DXDY_SSSE3(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint16_t* colors) { - SkASSERT(64 >= count); - SkAutoSTMalloc<64, uint32_t> colors32(count); - S32_generic_D32_filter_DXDY_SSSE3(s, xy, count, colors32); - for(int i = 0; i < count; i++) { - *colors++ = SkPixel32ToPixel16(colors32[i]); - } -} - #else // SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 void S32_opaque_D32_filter_DX_SSSE3(const SkBitmapProcState& s, @@ -780,16 +758,4 @@ void S32_alpha_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s, sk_throw(); } -void S32_D16_filter_DX_SSSE3(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint16_t* colors) { - sk_throw(); -} - -void S32_D16_filter_DXDY_SSSE3(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint16_t* colors) { - sk_throw(); -} - #endif diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.h b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.h index c7a9a899236..e7799fa2c71 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.h +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_SSSE3.h @@ -22,12 +22,4 @@ void S32_opaque_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s, void S32_alpha_D32_filter_DXDY_SSSE3(const SkBitmapProcState& s, const uint32_t* xy, int count, uint32_t* colors); - -void S32_D16_filter_DX_SSSE3(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint16_t* colors); -void S32_D16_filter_DXDY_SSSE3(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint16_t* colors); - #endif diff --git a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_mips_dsp.cpp b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_mips_dsp.cpp index dac4e20381f..a80e955aeb2 100644 --- a/gfx/skia/skia/src/opts/SkBitmapProcState_opts_mips_dsp.cpp +++ b/gfx/skia/skia/src/opts/SkBitmapProcState_opts_mips_dsp.cpp @@ -12,138 +12,6 @@ #include "SkPaint.h" #include "SkUtils.h" -static void SI8_D16_nofilter_DX_mips_dsp(const SkBitmapProcState& s, - const uint32_t* SK_RESTRICT xy, - int count, uint16_t* SK_RESTRICT colors) { - SkASSERT(count > 0 && colors != nullptr); - SkASSERT(s.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)); - SkASSERT(kNone_SkFilterQuality == s.fFilterLevel); - const uint16_t* SK_RESTRICT table = s.fPixmap.ctable()->read16BitCache(); - const uint8_t* SK_RESTRICT srcAddr = (const uint8_t*)s.fPixmap.addr(); - SkASSERT((unsigned)xy[0] < (unsigned)s.fPixmap.height()); - srcAddr = (const uint8_t*)((const char*)srcAddr + xy[0] * s.fPixmap.rowBytes()); - uint8_t src; - - if (1 == s.fPixmap.width()) { - src = srcAddr[0]; - uint16_t dstValue = table[src]; - sk_memset16(colors, dstValue, count); - } else { - int count8; - const uint16_t* SK_RESTRICT xx = (const uint16_t*)(xy + 1); - - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - ".set noat \n\t" - "sra %[count8], %[count], 3 \n\t" - "beqz %[count8], 3f \n\t" - " addiu %[count8], %[count8], -1 \n\t" - "1: \n\t" - "beqz %[count8], 2f \n\t" - " addiu %[count8], %[count8], -1 \n\t" - "pref 0, 16(%[xx]) \n\t" - "lhu $t0, 0(%[xx]) \n\t" - "lhu $t1, 2(%[xx]) \n\t" - "lhu $t2, 4(%[xx]) \n\t" - "lhu $t3, 6(%[xx]) \n\t" - "lhu $t4, 8(%[xx]) \n\t" - "lhu $t5, 10(%[xx]) \n\t" - "lhu $t6, 12(%[xx]) \n\t" - "lhu $t7, 14(%[xx]) \n\t" - "pref 0, 8(%[srcAddr]) \n\t" - "lbux $t0, $t0(%[srcAddr]) \n\t" - "lbux $t1, $t1(%[srcAddr]) \n\t" - "lbux $t2, $t2(%[srcAddr]) \n\t" - "lbux $t3, $t3(%[srcAddr]) \n\t" - "lbux $t4, $t4(%[srcAddr]) \n\t" - "lbux $t5, $t5(%[srcAddr]) \n\t" - "lbux $t6, $t6(%[srcAddr]) \n\t" - "lbux $t7, $t7(%[srcAddr]) \n\t" - "addu $t0, $t0, $t0 \n\t" - "addu $t1, $t1, $t1 \n\t" - "addu $t2, $t2, $t2 \n\t" - "addu $t3, $t3, $t3 \n\t" - "addu $t4, $t4, $t4 \n\t" - "addu $t5, $t5, $t5 \n\t" - "addu $t6, $t6, $t6 \n\t" - "addu $t7, $t7, $t7 \n\t" - "pref 0, 16(%[table]) \n\t" - "lhx $t0, $t0(%[table]) \n\t" - "lhx $t1, $t1(%[table]) \n\t" - "lhx $t2, $t2(%[table]) \n\t" - "lhx $t3, $t3(%[table]) \n\t" - "lhx $t4, $t4(%[table]) \n\t" - "lhx $t5, $t5(%[table]) \n\t" - "lhx $t6, $t6(%[table]) \n\t" - "lhx $t7, $t7(%[table]) \n\t" - "sh $t0, 0(%[colors]) \n\t" - "sh $t1, 2(%[colors]) \n\t" - "sh $t2, 4(%[colors]) \n\t" - "sh $t3, 6(%[colors]) \n\t" - "sh $t4, 8(%[colors]) \n\t" - "sh $t5, 10(%[colors]) \n\t" - "sh $t6, 12(%[colors]) \n\t" - "sh $t7, 14(%[colors]) \n\t" - "addiu %[xx], %[xx], 16 \n\t" - "bgtz %[count8], 1b \n\t" - " addiu %[colors], %[colors], 16 \n\t" - "2: \n\t" - "lhu $t0, 0(%[xx]) \n\t" - "lhu $t1, 2(%[xx]) \n\t" - "lhu $t2, 4(%[xx]) \n\t" - "lhu $t3, 6(%[xx]) \n\t" - "lhu $t4, 8(%[xx]) \n\t" - "lhu $t5, 10(%[xx]) \n\t" - "lhu $t6, 12(%[xx]) \n\t" - "lhu $t7, 14(%[xx]) \n\t" - "lbux $t0, $t0(%[srcAddr]) \n\t" - "lbux $t1, $t1(%[srcAddr]) \n\t" - "lbux $t2, $t2(%[srcAddr]) \n\t" - "lbux $t3, $t3(%[srcAddr]) \n\t" - "lbux $t4, $t4(%[srcAddr]) \n\t" - "lbux $t5, $t5(%[srcAddr]) \n\t" - "lbux $t6, $t6(%[srcAddr]) \n\t" - "lbux $t7, $t7(%[srcAddr]) \n\t" - "addu $t0, $t0, $t0 \n\t" - "addu $t1, $t1, $t1 \n\t" - "addu $t2, $t2, $t2 \n\t" - "addu $t3, $t3, $t3 \n\t" - "addu $t4, $t4, $t4 \n\t" - "addu $t5, $t5, $t5 \n\t" - "addu $t6, $t6, $t6 \n\t" - "addu $t7, $t7, $t7 \n\t" - "lhx $t0, $t0(%[table]) \n\t" - "lhx $t1, $t1(%[table]) \n\t" - "lhx $t2, $t2(%[table]) \n\t" - "lhx $t3, $t3(%[table]) \n\t" - "lhx $t4, $t4(%[table]) \n\t" - "lhx $t5, $t5(%[table]) \n\t" - "lhx $t6, $t6(%[table]) \n\t" - "lhx $t7, $t7(%[table]) \n\t" - "sh $t0, 0(%[colors]) \n\t" - "sh $t1, 2(%[colors]) \n\t" - "sh $t2, 4(%[colors]) \n\t" - "sh $t3, 6(%[colors]) \n\t" - "sh $t4, 8(%[colors]) \n\t" - "sh $t5, 10(%[colors]) \n\t" - "sh $t6, 12(%[colors]) \n\t" - "sh $t7, 14(%[colors]) \n\t" - "addiu %[xx], %[xx], 16 \n\t" - "addiu %[colors], %[colors], 16 \n\t" - "3: \n\t" - ".set pop \n\t" - : [xx]"+r"(xx), [count8]"=&r"(count8), [colors]"+r"(colors) - : [table]"r"(table), [srcAddr]"r"(srcAddr), [count]"r"(count) - : "memory","t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7" - ); - - for (int i = (count & 7); i > 0; --i) { - src = srcAddr[*xx++]; *colors++ = table[src]; - } - } -} - static void SI8_opaque_D32_nofilter_DX_mips_dsp(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, int count, SkPMColor* SK_RESTRICT colors) { @@ -379,8 +247,6 @@ void SkBitmapProcState::platformProcs() { switch (fPixmap.colorType()) { case kIndex_8_SkColorType: if (justDx && kNone_SkFilterQuality == fFilterLevel) { - fSampleProc16 = SI8_D16_nofilter_DX_mips_dsp; - fShaderProc16 = nullptr; if (isOpaque) { fSampleProc32 = SI8_opaque_D32_nofilter_DX_mips_dsp; fShaderProc32 = nullptr; diff --git a/gfx/skia/skia/src/opts/SkBlitRow_opts_arm_neon.cpp b/gfx/skia/skia/src/opts/SkBlitRow_opts_arm_neon.cpp index 1f97971ee48..95bd2294862 100644 --- a/gfx/skia/skia/src/opts/SkBlitRow_opts_arm_neon.cpp +++ b/gfx/skia/skia/src/opts/SkBlitRow_opts_arm_neon.cpp @@ -390,7 +390,7 @@ void S32A_D565_Opaque_neon(uint16_t* SK_RESTRICT dst, "movi v4.8h, #0x80 \t\n" "1: \t\n" - "sub %[count], %[count], #16 \t\n" + "sub %w[count], %w[count], #16 \t\n" "ld1 {v16.8h-v17.8h}, [%[dst]] \t\n" "ld4 {v0.16b-v3.16b}, [%[src]], #64 \t\n" "prfm pldl1keep, [%[src],#512] \t\n" @@ -416,7 +416,7 @@ void S32A_D565_Opaque_neon(uint16_t* SK_RESTRICT dst, "umlal v22.8h, v3.8b, v18.8b \t\n" "ushr v20.8h, v22.8h, #5 \t\n" "addhn v20.8b, v22.8h, v20.8h \t\n" - "cmp %[count], #16 \t\n" + "cmp %w[count], #16 \t\n" "mov v6.16b, v4.16b \t\n" "mov v5.16b, v4.16b \t\n" "umlal v6.8h, v3.8b, v16.8b \t\n" diff --git a/gfx/skia/skia/src/opts/SkColorCubeFilter_opts.h b/gfx/skia/skia/src/opts/SkColorCubeFilter_opts.h index 4c394051bba..ab8d1d4c9bf 100644 --- a/gfx/skia/skia/src/opts/SkColorCubeFilter_opts.h +++ b/gfx/skia/skia/src/opts/SkColorCubeFilter_opts.h @@ -59,10 +59,10 @@ void color_cube_filter_span(const SkPMColor src[], const SkColor lutColor10 = colorCube[ix + i10]; const SkColor lutColor11 = colorCube[ix + i11]; - Sk4f sum = Sk4f::FromBytes((const uint8_t*)&lutColor00) * g0b0; - sum = sum + Sk4f::FromBytes((const uint8_t*)&lutColor01) * g0b1; - sum = sum + Sk4f::FromBytes((const uint8_t*)&lutColor10) * g1b0; - sum = sum + Sk4f::FromBytes((const uint8_t*)&lutColor11) * g1b1; + Sk4f sum = SkNx_cast(Sk4b::Load((const uint8_t*)&lutColor00)) * g0b0; + sum = sum + SkNx_cast(Sk4b::Load((const uint8_t*)&lutColor01)) * g0b1; + sum = sum + SkNx_cast(Sk4b::Load((const uint8_t*)&lutColor10)) * g1b0; + sum = sum + SkNx_cast(Sk4b::Load((const uint8_t*)&lutColor11)) * g1b1; color = color + sum * Sk4f((float)colorToFactors[x][r]); } if (a != 255) { @@ -74,7 +74,7 @@ void color_cube_filter_span(const SkPMColor src[], color = SkNx_shuffle<2,1,0,3>(color); #endif uint8_t* dstBytes = (uint8_t*)(dst+i); - color.toBytes(dstBytes); + SkNx_cast(color).store(dstBytes); dstBytes[SK_A32_SHIFT/8] = a; } } diff --git a/gfx/skia/skia/src/opts/SkNx_avx.h b/gfx/skia/skia/src/opts/SkNx_avx.h index 9697303e37b..f635181a926 100644 --- a/gfx/skia/skia/src/opts/SkNx_avx.h +++ b/gfx/skia/skia/src/opts/SkNx_avx.h @@ -13,6 +13,8 @@ // All the SSE specializations are still good ideas. We'll just add Sk8f. #include "SkNx_sse.h" +// SkNx_sse.h defines SKNX_IS_FAST. + namespace { // See SkNx.h template <> @@ -24,27 +26,10 @@ public: SkNx(float val) : fVec(_mm256_set1_ps(val)) {} static SkNx Load(const float vals[8]) { return _mm256_loadu_ps(vals); } - static SkNx FromBytes(const uint8_t bytes[8]) { - __m128i fix8 = _mm_loadl_epi64((const __m128i*)bytes), - fix16 = _mm_unpacklo_epi8 (fix8 , _mm_setzero_si128()), - lo32 = _mm_unpacklo_epi16(fix16, _mm_setzero_si128()), - hi32 = _mm_unpackhi_epi16(fix16, _mm_setzero_si128()); - __m256i fix32 = _mm256_insertf128_si256(_mm256_castsi128_si256(lo32), hi32, 1); - return _mm256_cvtepi32_ps(fix32); - } - SkNx(float a, float b, float c, float d, float e, float f, float g, float h) : fVec(_mm256_setr_ps(a,b,c,d,e,f,g,h)) {} void store(float vals[8]) const { _mm256_storeu_ps(vals, fVec); } - void toBytes(uint8_t bytes[8]) const { - __m256i fix32 = _mm256_cvttps_epi32(fVec); - __m128i lo32 = _mm256_extractf128_si256(fix32, 0), - hi32 = _mm256_extractf128_si256(fix32, 1), - fix16 = _mm_packus_epi32(lo32, hi32), - fix8 = _mm_packus_epi16(fix16, fix16); - _mm_storel_epi64((__m128i*)bytes, fix8); - } SkNx operator + (const SkNx& o) const { return _mm256_add_ps(fVec, o.fVec); } SkNx operator - (const SkNx& o) const { return _mm256_sub_ps(fVec, o.fVec); } @@ -85,6 +70,25 @@ public: __m256 fVec; }; +template<> inline Sk8b SkNx_cast(const Sk8f& src) { + __m256i _32 = _mm256_cvttps_epi32(src.fVec); + __m128i lo = _mm256_extractf128_si256(_32, 0), + hi = _mm256_extractf128_si256(_32, 1), + _16 = _mm_packus_epi32(lo, hi); + return _mm_packus_epi16(_16, _16); +} + +template<> inline Sk8f SkNx_cast(const Sk8b& src) { + /* TODO lo = _mm_cvtepu8_epi32(src.fVec), + * hi = _mm_cvtepu8_epi32(_mm_srli_si128(src.fVec, 4)) + */ + __m128i _16 = _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128()), + lo = _mm_unpacklo_epi16(_16, _mm_setzero_si128()), + hi = _mm_unpackhi_epi16(_16, _mm_setzero_si128()); + __m256i _32 = _mm256_insertf128_si256(_mm256_castsi128_si256(lo), hi, 1); + return _mm256_cvtepi32_ps(_32); +} + } // namespace #endif//SkNx_avx_DEFINED diff --git a/gfx/skia/skia/src/opts/SkNx_neon.h b/gfx/skia/skia/src/opts/SkNx_neon.h index 6fe6137e5fe..0955cb2b5b6 100644 --- a/gfx/skia/skia/src/opts/SkNx_neon.h +++ b/gfx/skia/skia/src/opts/SkNx_neon.h @@ -8,6 +8,8 @@ #ifndef SkNx_neon_DEFINED #define SkNx_neon_DEFINED +#define SKNX_IS_FAST + namespace { // See SkNx.h // Well, this is absurd. The shifts require compile-time constant arguments. @@ -148,31 +150,9 @@ public: SkNx() {} SkNx(float val) : fVec(vdupq_n_f32(val)) {} static SkNx Load(const float vals[4]) { return vld1q_f32(vals); } - static SkNx FromBytes(const uint8_t vals[4]) { - uint8x8_t fix8 = (uint8x8_t)vld1_dup_u32((const uint32_t*)vals); - uint16x8_t fix8_16 = vmovl_u8(fix8); - uint32x4_t fix8_32 = vmovl_u16(vget_low_u16(fix8_16)); - return SkNx(vcvtq_f32_u32(fix8_32)); - } - SkNx(float a, float b, float c, float d) { fVec = (float32x4_t) { a, b, c, d }; } void store(float vals[4]) const { vst1q_f32(vals, fVec); } - void toBytes(uint8_t bytes[4]) const { - uint32x4_t fix8_32 = vcvtq_u32_f32(fVec); - uint16x4_t fix8_16 = vqmovn_u32(fix8_32); - uint8x8_t fix8 = vqmovn_u16(vcombine_u16(fix8_16, vdup_n_u16(0))); - vst1_lane_u32((uint32_t*)bytes, (uint32x2_t)fix8, 0); - } - - static void ToBytes(uint8_t bytes[16], - const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { - vst1q_u8(bytes, vuzpq_u8(vuzpq_u8((uint8x16_t)vcvtq_u32_f32(a.fVec), - (uint8x16_t)vcvtq_u32_f32(b.fVec)).val[0], - vuzpq_u8((uint8x16_t)vcvtq_u32_f32(c.fVec), - (uint8x16_t)vcvtq_u32_f32(d.fVec)).val[0]).val[0]); - } - SkNx approxInvert() const { float32x4_t est0 = vrecpeq_f32(fVec), est1 = vmulq_f32(vrecpsq_f32(est0, fVec), est0); @@ -285,6 +265,24 @@ public: uint16x8_t fVec; }; +template <> +class SkNx<4, uint8_t> { +public: + SkNx(const uint8x8_t& vec) : fVec(vec) {} + + SkNx() {} + static SkNx Load(const uint8_t vals[4]) { + return (uint8x8_t)vld1_dup_u32((const uint32_t*)vals); + } + void store(uint8_t vals[4]) const { + return vst1_lane_u32((uint32_t*)vals, (uint32x2_t)fVec, 0); + } + + // TODO as needed + + uint8x8_t fVec; +}; + template <> class SkNx<16, uint8_t> { public: @@ -327,11 +325,30 @@ public: #undef SHIFT16 #undef SHIFT8 -template<> -inline SkNx<4, int> SkNx_cast(const SkNx<4, float>& src) { +template<> inline Sk4i SkNx_cast(const Sk4f& src) { return vcvtq_s32_f32(src.fVec); } +template<> inline Sk4b SkNx_cast(const Sk4f& src) { + uint32x4_t _32 = vcvtq_u32_f32(src.fVec); + uint16x4_t _16 = vqmovn_u32(_32); + return vqmovn_u16(vcombine_u16(_16, _16)); +} + +template<> inline Sk4f SkNx_cast(const Sk4b& src) { + uint16x8_t _16 = vmovl_u8 (src.fVec) ; + uint32x4_t _32 = vmovl_u16(vget_low_u16(_16)); + return vcvtq_f32_u32(_32); +} + +static inline void Sk4f_ToBytes(uint8_t bytes[16], + const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) { + vst1q_u8(bytes, vuzpq_u8(vuzpq_u8((uint8x16_t)vcvtq_u32_f32(a.fVec), + (uint8x16_t)vcvtq_u32_f32(b.fVec)).val[0], + vuzpq_u8((uint8x16_t)vcvtq_u32_f32(c.fVec), + (uint8x16_t)vcvtq_u32_f32(d.fVec)).val[0]).val[0]); +} + } // namespace #endif//SkNx_neon_DEFINED diff --git a/gfx/skia/skia/src/opts/SkNx_sse.h b/gfx/skia/skia/src/opts/SkNx_sse.h index a4f8656536c..b3f50914062 100644 --- a/gfx/skia/skia/src/opts/SkNx_sse.h +++ b/gfx/skia/skia/src/opts/SkNx_sse.h @@ -10,6 +10,8 @@ // This file may assume <= SSE2, but must check SK_CPU_SSE_LEVEL for anything more recent. +#define SKNX_IS_FAST + namespace { // See SkNx.h @@ -62,6 +64,52 @@ public: __m128 fVec; }; +template <> +class SkNx<2, double> { +public: + SkNx(const __m128d& vec) : fVec(vec) {} + + SkNx() {} + SkNx(double val) : fVec(_mm_set1_pd(val)) {} + static SkNx Load(const double vals[2]) { return _mm_loadu_pd(vals); } + SkNx(double a, double b) : fVec(_mm_setr_pd(a,b)) {} + + void store(double vals[2]) const { _mm_storeu_pd(vals, fVec); } + + SkNx operator + (const SkNx& o) const { return _mm_add_pd(fVec, o.fVec); } + SkNx operator - (const SkNx& o) const { return _mm_sub_pd(fVec, o.fVec); } + SkNx operator * (const SkNx& o) const { return _mm_mul_pd(fVec, o.fVec); } + SkNx operator / (const SkNx& o) const { return _mm_div_pd(fVec, o.fVec); } + + SkNx operator == (const SkNx& o) const { return _mm_cmpeq_pd (fVec, o.fVec); } + SkNx operator != (const SkNx& o) const { return _mm_cmpneq_pd(fVec, o.fVec); } + SkNx operator < (const SkNx& o) const { return _mm_cmplt_pd (fVec, o.fVec); } + SkNx operator > (const SkNx& o) const { return _mm_cmpgt_pd (fVec, o.fVec); } + SkNx operator <= (const SkNx& o) const { return _mm_cmple_pd (fVec, o.fVec); } + SkNx operator >= (const SkNx& o) const { return _mm_cmpge_pd (fVec, o.fVec); } + + static SkNx Min(const SkNx& l, const SkNx& r) { return _mm_min_pd(l.fVec, r.fVec); } + static SkNx Max(const SkNx& l, const SkNx& r) { return _mm_max_pd(l.fVec, r.fVec); } + + SkNx sqrt() const { return _mm_sqrt_pd(fVec); } + + template double kth() const { + SkASSERT(0 <= k && k < 2); + union { __m128d v; double fs[2]; } pun = {fVec}; + return pun.fs[k&1]; + } + + bool allTrue() const { return 0x3 == _mm_movemask_pd(fVec); } + bool anyTrue() const { return 0x0 != _mm_movemask_pd(fVec); } + + SkNx thenElse(const SkNx& t, const SkNx& e) const { + return _mm_or_pd(_mm_and_pd (fVec, t.fVec), + _mm_andnot_pd(fVec, e.fVec)); + } + + __m128d fVec; +}; + template <> class SkNx<4, int> { public: @@ -109,37 +157,9 @@ public: SkNx(float val) : fVec( _mm_set1_ps(val) ) {} static SkNx Load(const float vals[4]) { return _mm_loadu_ps(vals); } - static SkNx FromBytes(const uint8_t bytes[4]) { - __m128i fix8 = _mm_cvtsi32_si128(*(const int*)bytes); - #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 - const char _ = ~0; // Zero these bytes. - __m128i fix8_32 = _mm_shuffle_epi8(fix8, _mm_setr_epi8(0,_,_,_, 1,_,_,_, 2,_,_,_, 3,_,_,_)); - #else - __m128i fix8_16 = _mm_unpacklo_epi8 (fix8, _mm_setzero_si128()), - fix8_32 = _mm_unpacklo_epi16(fix8_16, _mm_setzero_si128()); - #endif - return SkNx(_mm_cvtepi32_ps(fix8_32)); - // TODO: use _mm_cvtepu8_epi32 w/SSE4.1? - } - SkNx(float a, float b, float c, float d) : fVec(_mm_setr_ps(a,b,c,d)) {} void store(float vals[4]) const { _mm_storeu_ps(vals, fVec); } - void toBytes(uint8_t bytes[4]) const { - __m128i fix8_32 = _mm_cvttps_epi32(fVec), - fix8_16 = _mm_packus_epi16(fix8_32, fix8_32), - fix8 = _mm_packus_epi16(fix8_16, fix8_16); - *(int*)bytes = _mm_cvtsi128_si32(fix8); - } - - static void ToBytes(uint8_t bytes[16], - const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { - _mm_storeu_si128((__m128i*)bytes, - _mm_packus_epi16(_mm_packus_epi16(_mm_cvttps_epi32(a.fVec), - _mm_cvttps_epi32(b.fVec)), - _mm_packus_epi16(_mm_cvttps_epi32(c.fVec), - _mm_cvttps_epi32(d.fVec)))); - } SkNx operator + (const SkNx& o) const { return _mm_add_ps(fVec, o.fVec); } SkNx operator - (const SkNx& o) const { return _mm_sub_ps(fVec, o.fVec); } @@ -250,6 +270,34 @@ public: __m128i fVec; }; +template <> +class SkNx<4, uint8_t> { +public: + SkNx(const __m128i& vec) : fVec(vec) {} + + SkNx() {} + static SkNx Load(const uint8_t vals[4]) { return _mm_cvtsi32_si128(*(const int*)vals); } + void store(uint8_t vals[4]) const { *(int*)vals = _mm_cvtsi128_si32(fVec); } + + // TODO as needed + + __m128i fVec; +}; + +template <> +class SkNx<8, uint8_t> { +public: + SkNx(const __m128i& vec) : fVec(vec) {} + + SkNx() {} + static SkNx Load(const uint8_t vals[8]) { return _mm_loadl_epi64((const __m128i*)vals); } + void store(uint8_t vals[8]) const { _mm_storel_epi64((__m128i*)vals, fVec); } + + // TODO as needed + + __m128i fVec; +}; + template <> class SkNx<16, uint8_t> { public: @@ -294,11 +342,42 @@ public: }; -template<> -inline SkNx<4, int> SkNx_cast(const SkNx<4, float>& src) { +template<> inline Sk4i SkNx_cast(const Sk4f& src) { return _mm_cvttps_epi32(src.fVec); } +template<> inline Sk4b SkNx_cast(const Sk4f& src) { + auto _32 = _mm_cvttps_epi32(src.fVec); +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + const int _ = ~0; + return _mm_shuffle_epi8(_32, _mm_setr_epi8(0,4,8,12, _,_,_,_, _,_,_,_, _,_,_,_)); +#else + auto _16 = _mm_packus_epi16(_32, _32); + return _mm_packus_epi16(_16, _16); +#endif +} + +template<> inline Sk4f SkNx_cast(const Sk4b& src) { +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + const int _ = ~0; + auto _32 = _mm_shuffle_epi8(src.fVec, _mm_setr_epi8(0,_,_,_, 1,_,_,_, 2,_,_,_, 3,_,_,_)); +#else + auto _16 = _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128()), + _32 = _mm_unpacklo_epi16(_16, _mm_setzero_si128()); +#endif + return _mm_cvtepi32_ps(_32); +} + +static inline void Sk4f_ToBytes(uint8_t bytes[16], + const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) { + _mm_storeu_si128((__m128i*)bytes, + _mm_packus_epi16(_mm_packus_epi16(_mm_cvttps_epi32(a.fVec), + _mm_cvttps_epi32(b.fVec)), + _mm_packus_epi16(_mm_cvttps_epi32(c.fVec), + _mm_cvttps_epi32(d.fVec)))); +} + + } // namespace #endif//SkNx_sse_DEFINED diff --git a/gfx/skia/skia/src/opts/SkOpts_neon.cpp b/gfx/skia/skia/src/opts/SkOpts_neon.cpp index a0388b06544..3a07ebb765e 100644 --- a/gfx/skia/skia/src/opts/SkOpts_neon.cpp +++ b/gfx/skia/skia/src/opts/SkOpts_neon.cpp @@ -15,6 +15,7 @@ #include "SkFloatingPoint_opts.h" #include "SkMatrix_opts.h" #include "SkMorphologyImageFilter_opts.h" +#include "SkSwizzler_opts.h" #include "SkTextureCompressor_opts.h" #include "SkUtils_opts.h" #include "SkXfermode_opts.h" @@ -47,5 +48,9 @@ namespace SkOpts { matrix_translate = sk_neon::matrix_translate; matrix_scale_translate = sk_neon::matrix_scale_translate; matrix_affine = sk_neon::matrix_affine; + + premul_xxxa = sk_neon::premul_xxxa; + premul_swaprb_xxxa = sk_neon::premul_swaprb_xxxa; + swaprb_xxxa = sk_neon::swaprb_xxxa; } } diff --git a/gfx/skia/skia/src/opts/SkOpts_sse2.cpp b/gfx/skia/skia/src/opts/SkOpts_sse2.cpp index 8cb5bd0274d..f14b4360a95 100644 --- a/gfx/skia/skia/src/opts/SkOpts_sse2.cpp +++ b/gfx/skia/skia/src/opts/SkOpts_sse2.cpp @@ -13,6 +13,7 @@ #include "SkColorCubeFilter_opts.h" #include "SkMatrix_opts.h" #include "SkMorphologyImageFilter_opts.h" +#include "SkSwizzler_opts.h" #include "SkUtils_opts.h" #include "SkXfermode_opts.h" @@ -39,6 +40,10 @@ namespace SkOpts { matrix_translate = sk_sse2::matrix_translate; matrix_scale_translate = sk_sse2::matrix_scale_translate; matrix_affine = sk_sse2::matrix_affine; + + premul_xxxa = sk_sse2::premul_xxxa; + swaprb_xxxa = sk_sse2::swaprb_xxxa; + premul_swaprb_xxxa = sk_sse2::premul_swaprb_xxxa; } } diff --git a/gfx/skia/skia/src/opts/SkOpts_sse41.cpp b/gfx/skia/skia/src/opts/SkOpts_sse41.cpp index bbb77e3b8d5..16ba87ad87c 100644 --- a/gfx/skia/skia/src/opts/SkOpts_sse41.cpp +++ b/gfx/skia/skia/src/opts/SkOpts_sse41.cpp @@ -10,10 +10,183 @@ #define SK_OPTS_NS sk_sse41 #include "SkBlurImageFilter_opts.h" +#ifndef SK_SUPPORT_LEGACY_X86_BLITS + +// This file deals mostly with unpacked 8-bit values, +// i.e. values between 0 and 255, but in 16-bit lanes with 0 at the top. + +// So __m128i typically represents 1 or 2 pixels, and m128ix2 represents 4. +struct m128ix2 { __m128i lo, hi; }; + +// unpack{lo,hi}() get our raw pixels unpacked, from half of 4 packed pixels to 2 unpacked pixels. +static inline __m128i unpacklo(__m128i x) { return _mm_cvtepu8_epi16(x); } +static inline __m128i unpackhi(__m128i x) { return _mm_unpackhi_epi8(x, _mm_setzero_si128()); } + +// pack() converts back, from 4 unpacked pixels to 4 packed pixels. +static inline __m128i pack(__m128i lo, __m128i hi) { return _mm_packus_epi16(lo, hi); } + +// These nextN() functions abstract over the difference between iterating over +// an array of values and returning a constant value, for uint8_t and uint32_t. +// The nextN() taking pointers increment that pointer past where they read. +// +// nextN() returns N unpacked pixels or 4N unpacked coverage values. + +static inline __m128i next1(uint8_t val) { return _mm_set1_epi16(val); } +static inline __m128i next2(uint8_t val) { return _mm_set1_epi16(val); } +static inline m128ix2 next4(uint8_t val) { return { next2(val), next2(val) }; } + +static inline __m128i next1(uint32_t val) { return unpacklo(_mm_cvtsi32_si128(val)); } +static inline __m128i next2(uint32_t val) { return unpacklo(_mm_set1_epi32(val)); } +static inline m128ix2 next4(uint32_t val) { return { next2(val), next2(val) }; } + +static inline __m128i next1(const uint8_t*& ptr) { return _mm_set1_epi16(*ptr++); } +static inline __m128i next2(const uint8_t*& ptr) { + auto r = _mm_cvtsi32_si128(*(const uint16_t*)ptr); + ptr += 2; + const int _ = ~0; + return _mm_shuffle_epi8(r, _mm_setr_epi8(0,_,0,_,0,_,0,_, 1,_,1,_,1,_,1,_)); +} +static inline m128ix2 next4(const uint8_t*& ptr) { + auto r = _mm_cvtsi32_si128(*(const uint32_t*)ptr); + ptr += 4; + const int _ = ~0; + auto lo = _mm_shuffle_epi8(r, _mm_setr_epi8(0,_,0,_,0,_,0,_, 1,_,1,_,1,_,1,_)), + hi = _mm_shuffle_epi8(r, _mm_setr_epi8(2,_,2,_,2,_,2,_, 3,_,3,_,3,_,3,_)); + return { lo, hi }; +} + +static inline __m128i next1(const uint32_t*& ptr) { return unpacklo(_mm_cvtsi32_si128(*ptr++)); } +static inline __m128i next2(const uint32_t*& ptr) { + auto r = unpacklo(_mm_loadl_epi64((const __m128i*)ptr)); + ptr += 2; + return r; +} +static inline m128ix2 next4(const uint32_t*& ptr) { + auto packed = _mm_loadu_si128((const __m128i*)ptr); + ptr += 4; + return { unpacklo(packed), unpackhi(packed) }; +} + +// Divide by 255 with rounding. +// (x+127)/255 == ((x+128)*257)>>16. +// Sometimes we can be more efficient by breaking this into two parts. +static inline __m128i div255_part1(__m128i x) { return _mm_add_epi16(x, _mm_set1_epi16(128)); } +static inline __m128i div255_part2(__m128i x) { return _mm_mulhi_epu16(x, _mm_set1_epi16(257)); } +static inline __m128i div255(__m128i x) { return div255_part2(div255_part1(x)); } + +// (x*y+127)/255, a byte multiply. +static inline __m128i scale(__m128i x, __m128i y) { + return div255(_mm_mullo_epi16(x, y)); +} + +// (255 - x). +static inline __m128i inv(__m128i x) { + return _mm_xor_si128(_mm_set1_epi16(0x00ff), x); // This seems a bit faster than _mm_sub_epi16. +} + +// ARGB argb -> AAAA aaaa +static inline __m128i alphas(__m128i px) { + const int a = 2 * (SK_A32_SHIFT/8); // SK_A32_SHIFT is typically 24, so this is typically 6. + const int _ = ~0; + return _mm_shuffle_epi8(px, _mm_setr_epi8(a+0,_,a+0,_,a+0,_,a+0,_, a+8,_,a+8,_,a+8,_,a+8,_)); +} + +// For i = 0...n, tgt = fn(dst,src,cov), where Dst,Src,and Cov can be constants or arrays. +template +static inline void loop(int n, uint32_t* t, const Dst dst, const Src src, const Cov cov, Fn&& fn) { + // We don't want to muck with the callers' pointers, so we make them const and copy here. + Dst d = dst; + Src s = src; + Cov c = cov; + + // Writing this as a single while-loop helps hoist loop invariants from fn. + while (n) { + if (n >= 4) { + auto d4 = next4(d), + s4 = next4(s), + c4 = next4(c); + auto lo = fn(d4.lo, s4.lo, c4.lo), + hi = fn(d4.hi, s4.hi, c4.hi); + _mm_storeu_si128((__m128i*)t, pack(lo,hi)); + t += 4; + n -= 4; + continue; + } + if (n & 2) { + auto r = fn(next2(d), next2(s), next2(c)); + _mm_storel_epi64((__m128i*)t, pack(r,r)); + t += 2; + } + if (n & 1) { + auto r = fn(next1(d), next1(s), next1(c)); + *t = _mm_cvtsi128_si32(pack(r,r)); + } + return; + } +} + +namespace sk_sse41 { + +// SrcOver, with a constant source and full coverage. +static void blit_row_color32(SkPMColor* tgt, const SkPMColor* dst, int n, SkPMColor src) { + // We want to calculate s + (d * inv(alphas(s)) + 127)/255. + // We'd generally do that div255 as s + ((d * inv(alphas(s)) + 128)*257)>>16. + + // But we can go one step further to ((s*255 + 128 + d*inv(alphas(s)))*257)>>16. + // This lets us hoist (s*255+128) and inv(alphas(s)) out of the loop. + __m128i s = next2(src), + s_255_128 = div255_part1(_mm_mullo_epi16(s, _mm_set1_epi16(255))), + A = inv(alphas(s)); + + const uint8_t cov = 0xff; + loop(n, tgt, dst, src, cov, [=](__m128i d, __m128i, __m128i) { + return div255_part2(_mm_add_epi16(s_255_128, _mm_mullo_epi16(d, A))); + }); +} + +// SrcOver, with a constant source and variable coverage. +// If the source is opaque, SrcOver becomes Src. +static void blit_mask_d32_a8(SkPMColor* dst, size_t dstRB, + const SkAlpha* cov, size_t covRB, + SkColor color, int w, int h) { + if (SkColorGetA(color) == 0xFF) { + const SkPMColor src = SkSwizzle_BGRA_to_PMColor(color); + while (h --> 0) { + loop(w, dst, (const SkPMColor*)dst, src, cov, [](__m128i d, __m128i s, __m128i c) { + // Src blend mode: a simple lerp from d to s by c. + // TODO: try a pmaddubsw version? + return div255(_mm_add_epi16(_mm_mullo_epi16(inv(c),d), _mm_mullo_epi16(c,s))); + }); + dst += dstRB / sizeof(*dst); + cov += covRB / sizeof(*cov); + } + } else { + const SkPMColor src = SkPreMultiplyColor(color); + while (h --> 0) { + loop(w, dst, (const SkPMColor*)dst, src, cov, [](__m128i d, __m128i s, __m128i c) { + // SrcOver blend mode, with coverage folded into source alpha. + __m128i sc = scale(s,c), + AC = inv(alphas(sc)); + return _mm_add_epi16(sc, scale(d,AC)); + }); + dst += dstRB / sizeof(*dst); + cov += covRB / sizeof(*cov); + } + } +} + +} // namespace sk_sse41 +#endif + namespace SkOpts { void Init_sse41() { box_blur_xx = sk_sse41::box_blur_xx; box_blur_xy = sk_sse41::box_blur_xy; box_blur_yx = sk_sse41::box_blur_yx; + + #ifndef SK_SUPPORT_LEGACY_X86_BLITS + blit_row_color32 = sk_sse41::blit_row_color32; + blit_mask_d32_a8 = sk_sse41::blit_mask_d32_a8; + #endif } } diff --git a/gfx/skia/skia/src/opts/SkPx_neon.h b/gfx/skia/skia/src/opts/SkPx_neon.h deleted file mode 100644 index 23a0934ab26..00000000000 --- a/gfx/skia/skia/src/opts/SkPx_neon.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkPx_neon_DEFINED -#define SkPx_neon_DEFINED - -// When we have NEON, we like to work 8 pixels at a time. -// This lets us exploit vld4/vst4 and represent SkPx as planar uint8x8x4_t, -// Wide as planar uint16x8x4_t, and Alpha as a single uint8x8_t plane. - -namespace neon { - -struct SkPx { - static const int N = 8; - - uint8x8x4_t fVec; - SkPx(uint8x8x4_t vec) : fVec(vec) {} - - static SkPx Dup(uint32_t px) { return vld4_dup_u8((const uint8_t*)&px); } - static SkPx Load(const uint32_t* px) { return vld4_u8((const uint8_t*)px); } - static SkPx Load(const uint32_t* px, int n) { - SkASSERT(0 < n && n < 8); - uint8x8x4_t v = vld4_dup_u8((const uint8_t*)px); // n>=1, so start all lanes with pixel 0. - switch (n) { - case 7: v = vld4_lane_u8((const uint8_t*)(px+6), v, 6); // fall through - case 6: v = vld4_lane_u8((const uint8_t*)(px+5), v, 5); // fall through - case 5: v = vld4_lane_u8((const uint8_t*)(px+4), v, 4); // fall through - case 4: v = vld4_lane_u8((const uint8_t*)(px+3), v, 3); // fall through - case 3: v = vld4_lane_u8((const uint8_t*)(px+2), v, 2); // fall through - case 2: v = vld4_lane_u8((const uint8_t*)(px+1), v, 1); - } - return v; - } - - void store(uint32_t* px) const { vst4_u8((uint8_t*)px, fVec); } - void store(uint32_t* px, int n) const { - SkASSERT(0 < n && n < 8); - switch (n) { - case 7: vst4_lane_u8((uint8_t*)(px+6), fVec, 6); - case 6: vst4_lane_u8((uint8_t*)(px+5), fVec, 5); - case 5: vst4_lane_u8((uint8_t*)(px+4), fVec, 4); - case 4: vst4_lane_u8((uint8_t*)(px+3), fVec, 3); - case 3: vst4_lane_u8((uint8_t*)(px+2), fVec, 2); - case 2: vst4_lane_u8((uint8_t*)(px+1), fVec, 1); - case 1: vst4_lane_u8((uint8_t*)(px+0), fVec, 0); - } - } - - struct Alpha { - uint8x8_t fA; - Alpha(uint8x8_t a) : fA(a) {} - - static Alpha Dup(uint8_t a) { return vdup_n_u8(a); } - static Alpha Load(const uint8_t* a) { return vld1_u8(a); } - static Alpha Load(const uint8_t* a, int n) { - SkASSERT(0 < n && n < 8); - uint8x8_t v = vld1_dup_u8(a); // n>=1, so start all lanes with alpha 0. - switch (n) { - case 7: v = vld1_lane_u8(a+6, v, 6); // fall through - case 6: v = vld1_lane_u8(a+5, v, 5); // fall through - case 5: v = vld1_lane_u8(a+4, v, 4); // fall through - case 4: v = vld1_lane_u8(a+3, v, 3); // fall through - case 3: v = vld1_lane_u8(a+2, v, 2); // fall through - case 2: v = vld1_lane_u8(a+1, v, 1); - } - return v; - } - Alpha inv() const { return vsub_u8(vdup_n_u8(255), fA); } - }; - - struct Wide { - uint16x8x4_t fVec; - Wide(uint16x8x4_t vec) : fVec(vec) {} - - Wide operator+(const Wide& o) const { - return (uint16x8x4_t) {{ - vaddq_u16(fVec.val[0], o.fVec.val[0]), - vaddq_u16(fVec.val[1], o.fVec.val[1]), - vaddq_u16(fVec.val[2], o.fVec.val[2]), - vaddq_u16(fVec.val[3], o.fVec.val[3]), - }}; - } - Wide operator-(const Wide& o) const { - return (uint16x8x4_t) {{ - vsubq_u16(fVec.val[0], o.fVec.val[0]), - vsubq_u16(fVec.val[1], o.fVec.val[1]), - vsubq_u16(fVec.val[2], o.fVec.val[2]), - vsubq_u16(fVec.val[3], o.fVec.val[3]), - }}; - } - - template Wide shl() const { - return (uint16x8x4_t) {{ - vshlq_n_u16(fVec.val[0], bits), - vshlq_n_u16(fVec.val[1], bits), - vshlq_n_u16(fVec.val[2], bits), - vshlq_n_u16(fVec.val[3], bits), - }}; - } - template Wide shr() const { - return (uint16x8x4_t) {{ - vshrq_n_u16(fVec.val[0], bits), - vshrq_n_u16(fVec.val[1], bits), - vshrq_n_u16(fVec.val[2], bits), - vshrq_n_u16(fVec.val[3], bits), - }}; - } - - SkPx addNarrowHi(const SkPx& o) const { - return (uint8x8x4_t) {{ - vshrn_n_u16(vaddw_u8(fVec.val[0], o.fVec.val[0]), 8), - vshrn_n_u16(vaddw_u8(fVec.val[1], o.fVec.val[1]), 8), - vshrn_n_u16(vaddw_u8(fVec.val[2], o.fVec.val[2]), 8), - vshrn_n_u16(vaddw_u8(fVec.val[3], o.fVec.val[3]), 8), - }}; - } - }; - - Alpha alpha() const { return fVec.val[3]; } - - Wide widenLo() const { - return (uint16x8x4_t) {{ - vmovl_u8(fVec.val[0]), - vmovl_u8(fVec.val[1]), - vmovl_u8(fVec.val[2]), - vmovl_u8(fVec.val[3]), - }}; - } - // TODO: these two can probably be done faster. - Wide widenHi() const { return this->widenLo().shl<8>(); } - Wide widenLoHi() const { return this->widenLo() + this->widenHi(); } - - SkPx operator+(const SkPx& o) const { - return (uint8x8x4_t) {{ - vadd_u8(fVec.val[0], o.fVec.val[0]), - vadd_u8(fVec.val[1], o.fVec.val[1]), - vadd_u8(fVec.val[2], o.fVec.val[2]), - vadd_u8(fVec.val[3], o.fVec.val[3]), - }}; - } - SkPx operator-(const SkPx& o) const { - return (uint8x8x4_t) {{ - vsub_u8(fVec.val[0], o.fVec.val[0]), - vsub_u8(fVec.val[1], o.fVec.val[1]), - vsub_u8(fVec.val[2], o.fVec.val[2]), - vsub_u8(fVec.val[3], o.fVec.val[3]), - }}; - } - SkPx saturatedAdd(const SkPx& o) const { - return (uint8x8x4_t) {{ - vqadd_u8(fVec.val[0], o.fVec.val[0]), - vqadd_u8(fVec.val[1], o.fVec.val[1]), - vqadd_u8(fVec.val[2], o.fVec.val[2]), - vqadd_u8(fVec.val[3], o.fVec.val[3]), - }}; - } - - Wide operator*(const Alpha& a) const { - return (uint16x8x4_t) {{ - vmull_u8(fVec.val[0], a.fA), - vmull_u8(fVec.val[1], a.fA), - vmull_u8(fVec.val[2], a.fA), - vmull_u8(fVec.val[3], a.fA), - }}; - } - SkPx approxMulDiv255(const Alpha& a) const { - return (*this * a).addNarrowHi(*this); - } - - SkPx addAlpha(const Alpha& a) const { - return (uint8x8x4_t) {{ - fVec.val[0], - fVec.val[1], - fVec.val[2], - vadd_u8(fVec.val[3], a.fA), - }}; - } -}; - -} // namespace neon - -typedef neon::SkPx SkPx; - -#endif//SkPx_neon_DEFINED diff --git a/gfx/skia/skia/src/opts/SkPx_none.h b/gfx/skia/skia/src/opts/SkPx_none.h deleted file mode 100644 index 8217eaef3c7..00000000000 --- a/gfx/skia/skia/src/opts/SkPx_none.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkPx_none_DEFINED -#define SkPx_none_DEFINED - -// Nothing fancy here. We're the backup _none case after all. -// Our declared sweet spot is simply a single pixel at a time. - -namespace none { - -struct SkPx { - static const int N = 1; - uint8_t f8[4]; - - SkPx(uint32_t px) { memcpy(f8, &px, 4); } - SkPx(uint8_t x, uint8_t y, uint8_t z, uint8_t a) { - f8[0] = x; f8[1] = y; f8[2] = z; f8[3] = a; - } - - static SkPx Dup(uint32_t px) { return px; } - static SkPx Load(const uint32_t* px) { return *px; } - static SkPx Load(const uint32_t* px, int n) { - SkASSERT(false); // There are no 0 Wide shl() const { - return Wide(f16[0]< Wide shr() const { - return Wide(f16[0]>>bits, f16[1]>>bits, f16[2]>>bits, f16[3]>>bits); - } - - SkPx addNarrowHi(const SkPx& o) const { - Wide sum = (*this + o.widenLo()).shr<8>(); - return SkPx(sum.f16[0], sum.f16[1], sum.f16[2], sum.f16[3]); - } - }; - - Alpha alpha() const { return f8[3]; } - - Wide widenLo() const { return Wide(f8[0], f8[1], f8[2], f8[3]); } - Wide widenHi() const { return this->widenLo().shl<8>(); } - Wide widenLoHi() const { return this->widenLo() + this->widenHi(); } - - SkPx operator+(const SkPx& o) const { - return SkPx(f8[0]+o.f8[0], f8[1]+o.f8[1], f8[2]+o.f8[2], f8[3]+o.f8[3]); - } - SkPx operator-(const SkPx& o) const { - return SkPx(f8[0]-o.f8[0], f8[1]-o.f8[1], f8[2]-o.f8[2], f8[3]-o.f8[3]); - } - SkPx saturatedAdd(const SkPx& o) const { - return SkPx(SkTMax(0, SkTMin(255, f8[0]+o.f8[0])), - SkTMax(0, SkTMin(255, f8[1]+o.f8[1])), - SkTMax(0, SkTMin(255, f8[2]+o.f8[2])), - SkTMax(0, SkTMin(255, f8[3]+o.f8[3]))); - } - - Wide operator*(const Alpha& a) const { - return Wide(f8[0]*a.fA, f8[1]*a.fA, f8[2]*a.fA, f8[3]*a.fA); - } - SkPx approxMulDiv255(const Alpha& a) const { - return (*this * a).addNarrowHi(*this); - } - - SkPx addAlpha(const Alpha& a) const { - return SkPx(f8[0], f8[1], f8[2], f8[3]+a.fA); - } -}; - -} // namespace none - -typedef none::SkPx SkPx; - -#endif//SkPx_none_DEFINED diff --git a/gfx/skia/skia/src/opts/SkPx_sse.h b/gfx/skia/skia/src/opts/SkPx_sse.h deleted file mode 100644 index 2560946edb9..00000000000 --- a/gfx/skia/skia/src/opts/SkPx_sse.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkPx_sse_DEFINED -#define SkPx_sse_DEFINED - -// sse::SkPx's sweet spot is to work with 4 pixels at a time, -// stored interlaced, just as they sit in memory: rgba rgba rgba rgba. - -// sse::SkPx's best way to work with alphas is similar, -// replicating the 4 alphas 4 times each across the pixel: aaaa aaaa aaaa aaaa. - -// When working with fewer than 4 pixels, we load the pixels in the low lanes, -// usually filling the top lanes with zeros (but who cares, might be junk). - -namespace sse { - -struct SkPx { - static const int N = 4; - - __m128i fVec; - SkPx(__m128i vec) : fVec(vec) {} - - static SkPx Dup(uint32_t px) { return _mm_set1_epi32(px); } - static SkPx Load(const uint32_t* px) { return _mm_loadu_si128((const __m128i*)px); } - static SkPx Load(const uint32_t* px, int n) { - SkASSERT(n > 0 && n < 4); - switch (n) { - case 1: return _mm_cvtsi32_si128(px[0]); - case 2: return _mm_loadl_epi64((const __m128i*)px); - case 3: return _mm_or_si128(_mm_loadl_epi64((const __m128i*)px), - _mm_slli_si128(_mm_cvtsi32_si128(px[2]), 8)); - } - return _mm_setzero_si128(); // Not actually reachable. - } - - void store(uint32_t* px) const { _mm_storeu_si128((__m128i*)px, fVec); } - void store(uint32_t* px, int n) const { - SkASSERT(n > 0 && n < 4); - __m128i v = fVec; - if (n & 1) { - *px++ = _mm_cvtsi128_si32(v); - v = _mm_srli_si128(v, 4); - } - if (n & 2) { - _mm_storel_epi64((__m128i*)px, v); - } - } - - struct Alpha { - __m128i fVec; - Alpha(__m128i vec) : fVec(vec) {} - - static Alpha Dup(uint8_t a) { return _mm_set1_epi8(a); } - static Alpha Load(const uint8_t* a) { - __m128i as = _mm_cvtsi32_si128(*(const uint32_t*)a); // ____ ____ ____ 3210 - #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 - return _mm_shuffle_epi8(as, _mm_set_epi8(3,3,3,3, 2,2,2,2, 1,1,1,1, 0,0,0,0)); - #else - as = _mm_unpacklo_epi8 (as, as); // ____ ____ 3322 1100 - as = _mm_unpacklo_epi16(as, as); // 3333 2222 1111 0000 - return as; - #endif - } - static Alpha Load(const uint8_t* a, int n) { - SkASSERT(n > 0 && n < 4); - uint8_t a4[] = { 0,0,0,0 }; - switch (n) { - case 3: a4[2] = a[2]; // fall through - case 2: a4[1] = a[1]; // fall through - case 1: a4[0] = a[0]; - } - return Load(a4); - } - - Alpha inv() const { return _mm_sub_epi8(_mm_set1_epi8(~0), fVec); } - }; - - struct Wide { - __m128i fLo, fHi; - Wide(__m128i lo, __m128i hi) : fLo(lo), fHi(hi) {} - - Wide operator+(const Wide& o) const { - return Wide(_mm_add_epi16(fLo, o.fLo), _mm_add_epi16(fHi, o.fHi)); - } - Wide operator-(const Wide& o) const { - return Wide(_mm_sub_epi16(fLo, o.fLo), _mm_sub_epi16(fHi, o.fHi)); - } - template Wide shl() const { - return Wide(_mm_slli_epi16(fLo, bits), _mm_slli_epi16(fHi, bits)); - } - template Wide shr() const { - return Wide(_mm_srli_epi16(fLo, bits), _mm_srli_epi16(fHi, bits)); - } - - SkPx addNarrowHi(const SkPx& o) const { - Wide sum = (*this + o.widenLo()).shr<8>(); - return _mm_packus_epi16(sum.fLo, sum.fHi); - } - }; - - Alpha alpha() const { - #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 - return _mm_shuffle_epi8(fVec, _mm_set_epi8(15,15,15,15, 11,11,11,11, 7,7,7,7, 3,3,3,3)); - #else - // We exploit that A >= rgb for any premul pixel. - __m128i as = fVec; // 3xxx 2xxx 1xxx 0xxx - as = _mm_max_epu8(as, _mm_srli_epi32(as, 8)); // 33xx 22xx 11xx 00xx - as = _mm_max_epu8(as, _mm_srli_epi32(as, 16)); // 3333 2222 1111 0000 - return as; - #endif - } - - Wide widenLo() const { - return Wide(_mm_unpacklo_epi8(fVec, _mm_setzero_si128()), - _mm_unpackhi_epi8(fVec, _mm_setzero_si128())); - } - Wide widenHi() const { - return Wide(_mm_unpacklo_epi8(_mm_setzero_si128(), fVec), - _mm_unpackhi_epi8(_mm_setzero_si128(), fVec)); - } - Wide widenLoHi() const { - return Wide(_mm_unpacklo_epi8(fVec, fVec), - _mm_unpackhi_epi8(fVec, fVec)); - } - - SkPx operator+(const SkPx& o) const { return _mm_add_epi8(fVec, o.fVec); } - SkPx operator-(const SkPx& o) const { return _mm_sub_epi8(fVec, o.fVec); } - SkPx saturatedAdd(const SkPx& o) const { return _mm_adds_epi8(fVec, o.fVec); } - - Wide operator*(const Alpha& a) const { - __m128i pLo = _mm_unpacklo_epi8( fVec, _mm_setzero_si128()), - aLo = _mm_unpacklo_epi8(a.fVec, _mm_setzero_si128()), - pHi = _mm_unpackhi_epi8( fVec, _mm_setzero_si128()), - aHi = _mm_unpackhi_epi8(a.fVec, _mm_setzero_si128()); - return Wide(_mm_mullo_epi16(pLo, aLo), _mm_mullo_epi16(pHi, aHi)); - } - SkPx approxMulDiv255(const Alpha& a) const { - return (*this * a).addNarrowHi(*this); - } - - SkPx addAlpha(const Alpha& a) const { - return _mm_add_epi8(fVec, _mm_and_si128(a.fVec, _mm_set1_epi32(0xFF000000))); - } -}; - -} // namespace sse - -typedef sse::SkPx SkPx; - -#endif//SkPx_sse_DEFINED diff --git a/gfx/skia/skia/src/opts/SkSwizzler_opts.h b/gfx/skia/skia/src/opts/SkSwizzler_opts.h new file mode 100644 index 00000000000..467e5d19406 --- /dev/null +++ b/gfx/skia/skia/src/opts/SkSwizzler_opts.h @@ -0,0 +1,153 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSwizzler_opts_DEFINED +#define SkSwizzler_opts_DEFINED + +#include "SkColorPriv.h" + +namespace SK_OPTS_NS { + +// These variable names in these functions just pretend the input is BGRA. +// They work fine with both RGBA and BGRA. + +static void premul_xxxa_portable(uint32_t dst[], const uint32_t src[], int count) { + for (int i = 0; i < count; i++) { + uint8_t a = src[i] >> 24, + r = src[i] >> 16, + g = src[i] >> 8, + b = src[i] >> 0; + r = (r*a+127)/255; + g = (g*a+127)/255; + b = (b*a+127)/255; + dst[i] = (uint32_t)a << 24 + | (uint32_t)r << 16 + | (uint32_t)g << 8 + | (uint32_t)b << 0; + } +} + +static void premul_swaprb_xxxa_portable(uint32_t dst[], const uint32_t src[], int count) { + for (int i = 0; i < count; i++) { + uint8_t a = src[i] >> 24, + r = src[i] >> 16, + g = src[i] >> 8, + b = src[i] >> 0; + r = (r*a+127)/255; + g = (g*a+127)/255; + b = (b*a+127)/255; + dst[i] = (uint32_t)a << 24 + | (uint32_t)b << 16 + | (uint32_t)g << 8 + | (uint32_t)r << 0; + } +} + +#if defined(SK_ARM_HAS_NEON) + +// Rounded divide by 255, (x + 127) / 255 +static uint8x8_t div255_round(uint16x8_t x) { + // result = (x + 127) / 255 + // result = (x + 127) / 256 + error1 + // + // error1 = (x + 127) / (255 * 256) + // error1 = (x + 127) / (256 * 256) + error2 + // + // error2 = (x + 127) / (255 * 256 * 256) + // + // The maximum value of error2 is too small to matter. Thus: + // result = (x + 127) / 256 + (x + 127) / (256 * 256) + // result = ((x + 127) / 256 + x + 127) / 256 + // result = ((x + 127) >> 8 + x + 127) >> 8 + // + // Use >>> to represent "rounded right shift" which, conveniently, + // NEON supports in one instruction. + // result = ((x >>> 8) + x) >>> 8 + // + // Note that the second right shift is actually performed as an + // "add, round, and narrow back to 8-bits" instruction. + return vraddhn_u16(x, vrshrq_n_u16(x, 8)); +} + +// Scale a byte by another, (x * y + 127) / 255 +static uint8x8_t scale(uint8x8_t x, uint8x8_t y) { + return div255_round(vmull_u8(x, y)); +} + +template +static void premul_xxxa_should_swaprb(uint32_t dst[], const uint32_t src[], int count) { + while (count >= 8) { + // Load 8 pixels. + uint8x8x4_t bgra = vld4_u8((const uint8_t*) src); + + uint8x8_t a = bgra.val[3], + r = bgra.val[2], + g = bgra.val[1], + b = bgra.val[0]; + + // Premultiply. + r = scale(r, a); + g = scale(g, a); + b = scale(b, a); + + // Store 8 premultiplied pixels. + if (kSwapRB) { + bgra.val[2] = b; + bgra.val[1] = g; + bgra.val[0] = r; + } else { + bgra.val[2] = r; + bgra.val[1] = g; + bgra.val[0] = b; + } + vst4_u8((uint8_t*) dst, bgra); + src += 8; + dst += 8; + count -= 8; + } + + // Call portable code to finish up the tail of [0,8) pixels. + auto proc = kSwapRB ? premul_swaprb_xxxa_portable : premul_xxxa_portable; + proc(dst, src, count); +} + +static void premul_xxxa(uint32_t dst[], const uint32_t src[], int count) { + premul_xxxa_should_swaprb(dst, src, count); +} + +static void premul_swaprb_xxxa(uint32_t dst[], const uint32_t src[], int count) { + premul_xxxa_should_swaprb(dst, src, count); +} + +#else + +static void premul_xxxa(uint32_t dst[], const uint32_t src[], int count) { + premul_xxxa_portable(dst, src, count); +} + +static void premul_swaprb_xxxa(uint32_t dst[], const uint32_t src[], int count) { + premul_swaprb_xxxa_portable(dst, src, count); +} + +#endif + +static void swaprb_xxxa(uint32_t dst[], const uint32_t src[], int count) { + for (int i = 0; i < count; i++) { + uint8_t a = src[i] >> 24, + r = src[i] >> 16, + g = src[i] >> 8, + b = src[i] >> 0; + dst[i] = (uint32_t)a << 24 + | (uint32_t)b << 16 + | (uint32_t)g << 8 + | (uint32_t)r << 0; + } +} + +} + +#endif // SkSwizzler_opts_DEFINED diff --git a/gfx/skia/skia/src/opts/SkXfermode_opts.h b/gfx/skia/skia/src/opts/SkXfermode_opts.h index 5a037ceb039..7b72bc3f801 100644 --- a/gfx/skia/skia/src/opts/SkXfermode_opts.h +++ b/gfx/skia/skia/src/opts/SkXfermode_opts.h @@ -15,7 +15,9 @@ namespace { // Most xfermodes can be done most efficiently 4 pixels at a time in 8 or 16-bit fixed point. -#define XFERMODE(Name) inline Sk4px Name(const Sk4px& d, const Sk4px& s) +#define XFERMODE(Xfermode) \ + struct Xfermode { Sk4px operator()(const Sk4px&, const Sk4px&) const; }; \ + inline Sk4px Xfermode::operator()(const Sk4px& d, const Sk4px& s) const XFERMODE(Clear) { return Sk4px::DupPMColor(0); } XFERMODE(Src) { return s; } @@ -23,13 +25,13 @@ XFERMODE(Dst) { return d; } XFERMODE(SrcIn) { return s.approxMulDiv255(d.alphas() ); } XFERMODE(SrcOut) { return s.approxMulDiv255(d.alphas().inv()); } XFERMODE(SrcOver) { return s + d.approxMulDiv255(s.alphas().inv()); } -XFERMODE(DstIn) { return SrcIn (s,d); } -XFERMODE(DstOut) { return SrcOut (s,d); } -XFERMODE(DstOver) { return SrcOver(s,d); } +XFERMODE(DstIn) { return SrcIn ()(s,d); } +XFERMODE(DstOut) { return SrcOut ()(s,d); } +XFERMODE(DstOver) { return SrcOver()(s,d); } // [ S * Da + (1 - Sa) * D] XFERMODE(SrcATop) { return (s * d.alphas() + d * s.alphas().inv()).div255(); } -XFERMODE(DstATop) { return SrcATop(s,d); } +XFERMODE(DstATop) { return SrcATop()(s,d); } //[ S * (1 - Da) + (1 - Sa) * D ] XFERMODE(Xor) { return (s * d.alphas().inv() + d * s.alphas().inv()).div255(); } // [S + D ] @@ -79,7 +81,7 @@ XFERMODE(HardLight) { auto colors = (both + isLite.thenElse(lite, dark)).div255(); return alphas.zeroColors() + colors.zeroAlphas(); } -XFERMODE(Overlay) { return HardLight(s,d); } +XFERMODE(Overlay) { return HardLight()(s,d); } XFERMODE(Darken) { auto sa = s.alphas(), @@ -110,7 +112,9 @@ XFERMODE(Lighten) { #undef XFERMODE // Some xfermodes use math like divide or sqrt that's best done in floats 1 pixel at a time. -#define XFERMODE(Name) inline Sk4f Name(const Sk4f& d, const Sk4f& s) +#define XFERMODE(Xfermode) \ + struct Xfermode { Sk4f operator()(const Sk4f&, const Sk4f&) const; }; \ + inline Sk4f Xfermode::operator()(const Sk4f& d, const Sk4f& s) const static inline Sk4f a_rgb(const Sk4f& a, const Sk4f& rgb) { static_assert(SK_A32_SHIFT == 24, ""); @@ -181,15 +185,15 @@ XFERMODE(SoftLight) { // A reasonable fallback mode for doing AA is to simply apply the transfermode first, // then linearly interpolate the AA. -template -inline Sk4px xfer_aa(const Sk4px& d, const Sk4px& s, const Sk4px& aa) { - Sk4px bw = Mode(d, s); +template +static Sk4px xfer_aa(const Sk4px& d, const Sk4px& s, const Sk4px& aa) { + Sk4px bw = Xfermode()(d, s); return (bw * aa + d * aa.inv()).div255(); } // For some transfermodes we specialize AA, either for correctness or performance. -#define XFERMODE_AA(Name) \ - template <> inline Sk4px xfer_aa(const Sk4px& d, const Sk4px& s, const Sk4px& aa) +#define XFERMODE_AA(Xfermode) \ + template <> Sk4px xfer_aa(const Sk4px& d, const Sk4px& s, const Sk4px& aa) // Plus' clamp needs to happen after AA. skia:3852 XFERMODE_AA(Plus) { // [ clamp( (1-AA)D + (AA)(S+D) ) == clamp(D + AA*S) ] @@ -198,8 +202,7 @@ XFERMODE_AA(Plus) { // [ clamp( (1-AA)D + (AA)(S+D) ) == clamp(D + AA*S) ] #undef XFERMODE_AA -template +template class Sk4pxXfermode : public SkProcCoeffXfermode { public: Sk4pxXfermode(const ProcCoeff& rec, SkXfermode::Mode mode) @@ -207,17 +210,41 @@ public: void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override { if (nullptr == aa) { - Sk4px::MapDstSrc(n, dst, src, Proc4); + Sk4px::MapDstSrc(n, dst, src, Xfermode()); } else { - Sk4px::MapDstSrcAlpha(n, dst, src, aa, AAProc4); + Sk4px::MapDstSrcAlpha(n, dst, src, aa, xfer_aa); } } void xfer16(uint16_t dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override { - if (nullptr == aa) { - Sk4px::MapDstSrc(n, dst, src, Proc4); - } else { - Sk4px::MapDstSrcAlpha(n, dst, src, aa, AAProc4); + SkPMColor dst32[4]; + while (n >= 4) { + dst32[0] = SkPixel16ToPixel32(dst[0]); + dst32[1] = SkPixel16ToPixel32(dst[1]); + dst32[2] = SkPixel16ToPixel32(dst[2]); + dst32[3] = SkPixel16ToPixel32(dst[3]); + + this->xfer32(dst32, src, 4, aa); + + dst[0] = SkPixel32ToPixel16(dst32[0]); + dst[1] = SkPixel32ToPixel16(dst32[1]); + dst[2] = SkPixel32ToPixel16(dst32[2]); + dst[3] = SkPixel32ToPixel16(dst32[3]); + + dst += 4; + src += 4; + aa += aa ? 4 : 0; + n -= 4; + } + while (n) { + SkPMColor dst32 = SkPixel16ToPixel32(*dst); + this->xfer32(&dst32, src, 1, aa); + *dst = SkPixel32ToPixel16(dst32); + + dst += 1; + src += 1; + aa += aa ? 1 : 0; + n -= 1; } } @@ -225,7 +252,7 @@ private: typedef SkProcCoeffXfermode INHERITED; }; -template +template class Sk4fXfermode : public SkProcCoeffXfermode { public: Sk4fXfermode(const ProcCoeff& rec, SkXfermode::Mode mode) @@ -233,41 +260,38 @@ public: void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override { for (int i = 0; i < n; i++) { - dst[i] = aa ? this->xfer32(dst[i], src[i], aa[i]) - : this->xfer32(dst[i], src[i]); + dst[i] = Xfer32_1(dst[i], src[i], aa ? aa+i : nullptr); } } void xfer16(uint16_t dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override { for (int i = 0; i < n; i++) { SkPMColor dst32 = SkPixel16ToPixel32(dst[i]); - dst32 = aa ? this->xfer32(dst32, src[i], aa[i]) - : this->xfer32(dst32, src[i]); + dst32 = Xfer32_1(dst32, src[i], aa ? aa+i : nullptr); dst[i] = SkPixel32ToPixel16(dst32); } } private: - static Sk4f Load(SkPMColor c) { - return Sk4f::FromBytes((uint8_t*)&c) * Sk4f(1.0f/255); - } - static SkPMColor Round(const Sk4f& f) { - SkPMColor c; - (f * Sk4f(255) + Sk4f(0.5f)).toBytes((uint8_t*)&c); - return c; - } - inline SkPMColor xfer32(SkPMColor dst, SkPMColor src) const { - return Round(ProcF(Load(dst), Load(src))); + static SkPMColor Xfer32_1(SkPMColor dst, const SkPMColor src, const SkAlpha* aa) { + Sk4f d = Load(dst), + s = Load(src), + b = Xfermode()(d, s); + if (aa) { + Sk4f a = Sk4f(*aa) * Sk4f(1.0f/255); + b = b*a + d*(Sk4f(1)-a); + } + return Round(b); } - inline SkPMColor xfer32(SkPMColor dst, SkPMColor src, SkAlpha aa) const { - Sk4f s(Load(src)), - d(Load(dst)), - b(ProcF(d,s)); - // We do aa in full float precision before going back down to bytes, because we can! - Sk4f a = Sk4f(aa) * Sk4f(1.0f/255); - b = b*a + d*(Sk4f(1)-a); - return Round(b); + static Sk4f Load(SkPMColor c) { + return SkNx_cast(Sk4b::Load((uint8_t*)&c)) * Sk4f(1.0f/255); + } + + static SkPMColor Round(const Sk4f& f) { + SkPMColor c; + SkNx_cast(f * Sk4f(255) + Sk4f(0.5f)).store((uint8_t*)&c); + return c; } typedef SkProcCoeffXfermode INHERITED; @@ -279,8 +303,8 @@ namespace SK_OPTS_NS { static SkXfermode* create_xfermode(const ProcCoeff& rec, SkXfermode::Mode mode) { switch (mode) { -#define CASE(Mode) \ - case SkXfermode::k##Mode##_Mode: return new Sk4pxXfermode >(rec, mode) +#define CASE(Xfermode) \ + case SkXfermode::k##Xfermode##_Mode: return new Sk4pxXfermode(rec, mode) CASE(Clear); CASE(Src); CASE(Dst); @@ -305,8 +329,8 @@ static SkXfermode* create_xfermode(const ProcCoeff& rec, SkXfermode::Mode mode) CASE(Lighten); #undef CASE -#define CASE(Mode) \ - case SkXfermode::k##Mode##_Mode: return new Sk4fXfermode(rec, mode) +#define CASE(Xfermode) \ + case SkXfermode::k##Xfermode##_Mode: return new Sk4fXfermode(rec, mode) CASE(ColorDodge); CASE(ColorBurn); CASE(SoftLight); diff --git a/gfx/skia/skia/src/opts/opts_check_x86.cpp b/gfx/skia/skia/src/opts/opts_check_x86.cpp index 3c817e1f0a4..9983eb56a84 100644 --- a/gfx/skia/skia/src/opts/opts_check_x86.cpp +++ b/gfx/skia/skia/src/opts/opts_check_x86.cpp @@ -161,17 +161,6 @@ void SkBitmapProcState::platformProcs() { } } - /* Check fSampleProc16 */ - if (fSampleProc16 == S32_D16_filter_DX) { - if (ssse3) { - fSampleProc16 = S32_D16_filter_DX_SSSE3; - } else { - fSampleProc16 = S32_D16_filter_DX_SSE2; - } - } else if (ssse3 && fSampleProc16 == S32_D16_filter_DXDY) { - fSampleProc16 = S32_D16_filter_DXDY_SSSE3; - } - /* Check fMatrixProc */ if (fMatrixProc == ClampX_ClampY_filter_scale) { fMatrixProc = ClampX_ClampY_filter_scale_SSE2; diff --git a/gfx/skia/skia/src/pathops/SkDLineIntersection.cpp b/gfx/skia/skia/src/pathops/SkDLineIntersection.cpp index 6fbac978b6e..71e2a064d5c 100644 --- a/gfx/skia/skia/src/pathops/SkDLineIntersection.cpp +++ b/gfx/skia/skia/src/pathops/SkDLineIntersection.cpp @@ -108,7 +108,7 @@ int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) { double ayBxLen = ayLen * bxLen; // detect parallel lines the same way here and in SkOpAngle operator < // so that non-parallel means they are also sortable - bool unparallel = fAllowNear ? NotAlmostEqualUlps(axByLen, ayBxLen) + bool unparallel = fAllowNear ? NotAlmostEqualUlps_Pin(axByLen, ayBxLen) : NotAlmostDequalUlps(axByLen, ayBxLen); if (unparallel && fUsed == 0) { double ab0y = a[0].fY - b[0].fY; diff --git a/gfx/skia/skia/src/pathops/SkOpAngle.cpp b/gfx/skia/skia/src/pathops/SkOpAngle.cpp index 655df45b15f..c2eb0c93266 100644 --- a/gfx/skia/skia/src/pathops/SkOpAngle.cpp +++ b/gfx/skia/skia/src/pathops/SkOpAngle.cpp @@ -1016,7 +1016,7 @@ deferTilLater: if (!crossesZero) { fSectorMask = (unsigned) -1 >> (31 - end + start) << start; } else { - fSectorMask = (unsigned) -1 >> (31 - start) | (-1 << end); + fSectorMask = (unsigned) -1 >> (31 - start) | ((unsigned) -1 << end); } } diff --git a/gfx/skia/skia/src/pathops/SkOpCoincidence.cpp b/gfx/skia/skia/src/pathops/SkOpCoincidence.cpp index 87bb9138697..5687dd415f9 100755 --- a/gfx/skia/skia/src/pathops/SkOpCoincidence.cpp +++ b/gfx/skia/skia/src/pathops/SkOpCoincidence.cpp @@ -110,11 +110,17 @@ bool SkOpCoincidence::addExpanded(SkChunkAlloc* allocator if (startPart < oStartPart) { double newT = oStartPtT->fT + oStartRange * startPart; newPt = oStart->segment()->addT(newT, SkOpSegment::kAllowAlias, allocator); + if (!newPt) { + return false; + } newPt->fPt = test->pt(); test->ptT()->addOpp(newPt); } else { double newT = startPtT->fT + startRange * oStartPart; newPt = start->segment()->addT(newT, SkOpSegment::kAllowAlias, allocator); + if (!newPt) { + return false; + } newPt->fPt = oTest->pt(); oTest->ptT()->addOpp(newPt); } @@ -384,6 +390,9 @@ bool SkOpCoincidence::apply() { SkOpSegment* oSegment = oStart->segment(); bool operandSwap = segment->operand() != oSegment->operand(); if (flipped) { + if (oEnd->deleted()) { + continue; + } do { SkOpSpanBase* oNext = oStart->next(); if (oNext == oEnd) { diff --git a/gfx/skia/skia/src/pathops/SkOpSegment.cpp b/gfx/skia/skia/src/pathops/SkOpSegment.cpp index 3b81cf2eed1..67f172e58ad 100644 --- a/gfx/skia/skia/src/pathops/SkOpSegment.cpp +++ b/gfx/skia/skia/src/pathops/SkOpSegment.cpp @@ -362,6 +362,9 @@ SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* alloca } if (t < result->fT) { SkOpSpan* prev = result->span()->prev(); + if (!prev) { + return nullptr; + } SkOpSpan* span = insert(prev, allocator); span->init(this, prev, t, pt); this->debugValidate(); @@ -1680,7 +1683,8 @@ bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT coincident = false; SkIntersections i; SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT); - SkDLine ray = {{{midPt.fX, midPt.fY}, {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}}; + SkDLine ray = {{{midPt.fX, midPt.fY}, + {(double) midPt.fX + dxdy.fY, (double) midPt.fY - dxdy.fX}}}; (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i); // measure distance and see if it's small enough to denote coincidence for (int index = 0; index < i.used(); ++index) { diff --git a/gfx/skia/skia/src/pathops/SkPathOpsLine.cpp b/gfx/skia/skia/src/pathops/SkPathOpsLine.cpp index cad54eb263a..6fa091db8eb 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsLine.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsLine.cpp @@ -41,6 +41,9 @@ double SkDLine::nearPoint(const SkDPoint& xy, bool* unequal) const { if (!between(0, numer, denom)) { return -1; } + if (!denom) { + return 0; + } double t = numer / denom; SkDPoint realPt = ptAtT(t); double dist = realPt.distance(xy); // OPTIMIZATION: can we compare against distSq instead ? @@ -48,7 +51,7 @@ double SkDLine::nearPoint(const SkDPoint& xy, bool* unequal) const { double tiniest = SkTMin(SkTMin(SkTMin(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY); double largest = SkTMax(SkTMax(SkTMax(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY); largest = SkTMax(largest, -tiniest); - if (!AlmostEqualUlps(largest, largest + dist)) { // is the dist within ULPS tolerance? + if (!AlmostEqualUlps_Pin(largest, largest + dist)) { // is the dist within ULPS tolerance? return -1; } if (unequal) { diff --git a/gfx/skia/skia/src/pathops/SkPathOpsQuad.cpp b/gfx/skia/skia/src/pathops/SkPathOpsQuad.cpp index 12b9658ce7c..3deab211339 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsQuad.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsQuad.cpp @@ -119,7 +119,8 @@ and using the roots int SkDQuad::RootsReal(const double A, const double B, const double C, double s[2]) { const double p = B / (2 * A); const double q = C / A; - if (approximately_zero(A) && (approximately_zero_inverse(p) || approximately_zero_inverse(q))) { + if (!A || (approximately_zero(A) && (approximately_zero_inverse(p) + || approximately_zero_inverse(q)))) { if (approximately_zero(B)) { s[0] = 0; return C == 0; diff --git a/gfx/skia/skia/src/pathops/SkPathOpsTSect.h b/gfx/skia/skia/src/pathops/SkPathOpsTSect.h index bebdf40208c..074fe376549 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsTSect.h +++ b/gfx/skia/skia/src/pathops/SkPathOpsTSect.h @@ -1467,11 +1467,17 @@ int SkTSect::linesIntersect(SkTSpan* span, workT += tStep; workPt = fCurve.ptAtT(workT); coinW.setPerp(fCurve, workT, workPt, opp->fCurve); + if (coinW.perpT() < 0) { + continue; + } SkDVector perpW = workPt - coinW.perpPt(); if ((perpS.dot(perpW) >= 0) == (tStep < 0)) { tStep = -tStep; } - } while (!workPt.approximatelyEqual(coinW.perpPt())); + if (workPt.approximatelyEqual(coinW.perpPt())) { + break; + } + } while (true); double oppTTest = coinW.perpT(); if (!opp->fHead->contains(oppTTest)) { return 0; diff --git a/gfx/skia/skia/src/pathops/SkPathOpsTypes.cpp b/gfx/skia/skia/src/pathops/SkPathOpsTypes.cpp index ca84405aa78..1ed484afee4 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsTypes.cpp +++ b/gfx/skia/skia/src/pathops/SkPathOpsTypes.cpp @@ -16,6 +16,16 @@ static bool arguments_denormalized(float a, float b, int epsilon) { // from http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ // FIXME: move to SkFloatBits.h static bool equal_ulps(float a, float b, int epsilon, int depsilon) { + if (arguments_denormalized(a, b, depsilon)) { + return true; + } + int aBits = SkFloatAs2sCompliment(a); + int bBits = SkFloatAs2sCompliment(b); + // Find the difference in ULPs. + return aBits < bBits + epsilon && bBits < aBits + epsilon; +} + +static bool equal_ulps_pin(float a, float b, int epsilon, int depsilon) { if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) { return false; } @@ -29,9 +39,6 @@ static bool equal_ulps(float a, float b, int epsilon, int depsilon) { } static bool d_equal_ulps(float a, float b, int epsilon) { - if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) { - return false; - } int aBits = SkFloatAs2sCompliment(a); int bBits = SkFloatAs2sCompliment(b); // Find the difference in ULPs. @@ -39,6 +46,16 @@ static bool d_equal_ulps(float a, float b, int epsilon) { } static bool not_equal_ulps(float a, float b, int epsilon) { + if (arguments_denormalized(a, b, epsilon)) { + return false; + } + int aBits = SkFloatAs2sCompliment(a); + int bBits = SkFloatAs2sCompliment(b); + // Find the difference in ULPs. + return aBits >= bBits + epsilon || bBits >= aBits + epsilon; +} + +static bool not_equal_ulps_pin(float a, float b, int epsilon) { if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) { return false; } @@ -52,9 +69,6 @@ static bool not_equal_ulps(float a, float b, int epsilon) { } static bool d_not_equal_ulps(float a, float b, int epsilon) { - if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) { - return false; - } int aBits = SkFloatAs2sCompliment(a); int bBits = SkFloatAs2sCompliment(b); // Find the difference in ULPs. @@ -62,9 +76,6 @@ static bool d_not_equal_ulps(float a, float b, int epsilon) { } static bool less_ulps(float a, float b, int epsilon) { - if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) { - return false; - } if (arguments_denormalized(a, b, epsilon)) { return a <= b - FLT_EPSILON * epsilon; } @@ -75,9 +86,6 @@ static bool less_ulps(float a, float b, int epsilon) { } static bool less_or_equal_ulps(float a, float b, int epsilon) { - if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) { - return false; - } if (arguments_denormalized(a, b, epsilon)) { return a < b + FLT_EPSILON * epsilon; } @@ -104,10 +112,7 @@ bool AlmostDequalUlps(float a, float b) { } bool AlmostDequalUlps(double a, double b) { - if (SkScalarIsFinite(a) || SkScalarIsFinite(b)) { - return AlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b)); - } - return fabs(a - b) / SkTMax(fabs(a), fabs(b)) < FLT_EPSILON * 16; + return AlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b)); } bool AlmostEqualUlps(float a, float b) { @@ -115,11 +120,21 @@ bool AlmostEqualUlps(float a, float b) { return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon); } +bool AlmostEqualUlps_Pin(float a, float b) { + const int UlpsEpsilon = 16; + return equal_ulps_pin(a, b, UlpsEpsilon, UlpsEpsilon); +} + bool NotAlmostEqualUlps(float a, float b) { const int UlpsEpsilon = 16; return not_equal_ulps(a, b, UlpsEpsilon); } +bool NotAlmostEqualUlps_Pin(float a, float b) { + const int UlpsEpsilon = 16; + return not_equal_ulps_pin(a, b, UlpsEpsilon); +} + bool NotAlmostDequalUlps(float a, float b) { const int UlpsEpsilon = 16; return d_not_equal_ulps(a, b, UlpsEpsilon); @@ -148,9 +163,6 @@ bool AlmostLessOrEqualUlps(float a, float b) { } int UlpsDistance(float a, float b) { - if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) { - return SK_MaxS32; - } SkFloatIntUnion floatIntA, floatIntB; floatIntA.fFloat = a; floatIntB.fFloat = b; diff --git a/gfx/skia/skia/src/pathops/SkPathOpsTypes.h b/gfx/skia/skia/src/pathops/SkPathOpsTypes.h index f85c6653eb0..b35c97ef067 100644 --- a/gfx/skia/skia/src/pathops/SkPathOpsTypes.h +++ b/gfx/skia/skia/src/pathops/SkPathOpsTypes.h @@ -167,6 +167,11 @@ inline bool AlmostEqualUlps(double a, double b) { return AlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b)); } +bool AlmostEqualUlps_Pin(float a, float b); +inline bool AlmostEqualUlps_Pin(double a, double b) { + return AlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b)); +} + // Use Almost Dequal when comparing should not special case denormalized values. bool AlmostDequalUlps(float a, float b); bool AlmostDequalUlps(double a, double b); @@ -176,6 +181,11 @@ inline bool NotAlmostEqualUlps(double a, double b) { return NotAlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b)); } +bool NotAlmostEqualUlps_Pin(float a, float b); +inline bool NotAlmostEqualUlps_Pin(double a, double b) { + return NotAlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b)); +} + bool NotAlmostDequalUlps(float a, float b); inline bool NotAlmostDequalUlps(double a, double b) { return NotAlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b)); diff --git a/gfx/skia/skia/src/pathops/SkReduceOrder.cpp b/gfx/skia/skia/src/pathops/SkReduceOrder.cpp index 43a91901f76..52a19d6138a 100644 --- a/gfx/skia/skia/src/pathops/SkReduceOrder.cpp +++ b/gfx/skia/skia/src/pathops/SkReduceOrder.cpp @@ -126,7 +126,7 @@ static int check_quadratic(const SkDCubic& cubic, SkDCubic& reduction) { double sideAx = midX - cubic[3].fX; double sideBx = dx23 * 3 / 2; if (approximately_zero(sideAx) ? !approximately_equal(sideAx, sideBx) - : !AlmostEqualUlps(sideAx, sideBx)) { + : !AlmostEqualUlps_Pin(sideAx, sideBx)) { return 0; } double dy10 = cubic[1].fY - cubic[0].fY; @@ -135,7 +135,7 @@ static int check_quadratic(const SkDCubic& cubic, SkDCubic& reduction) { double sideAy = midY - cubic[3].fY; double sideBy = dy23 * 3 / 2; if (approximately_zero(sideAy) ? !approximately_equal(sideAy, sideBy) - : !AlmostEqualUlps(sideAy, sideBy)) { + : !AlmostEqualUlps_Pin(sideAy, sideBy)) { return 0; } reduction[0] = cubic[0]; diff --git a/gfx/skia/skia/src/pdf/SkPDFBitmap.cpp b/gfx/skia/skia/src/pdf/SkPDFBitmap.cpp index 0c53da69743..4e49db518d8 100644 --- a/gfx/skia/skia/src/pdf/SkPDFBitmap.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFBitmap.cpp @@ -468,7 +468,8 @@ void PDFJpegBitmap::emitObject(SkWStream* stream, //////////////////////////////////////////////////////////////////////////////// -SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image) { +SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image, + SkPixelSerializer* pixelSerializer) { SkAutoTUnref data(image->refEncoded()); SkJFIFInfo info; if (data && SkIsJFIF(data, &info)) { @@ -481,6 +482,21 @@ SkPDFObject* SkPDFCreateBitmapObject(const SkImage* image) { return new PDFJpegBitmap(info.fSize, data, yuv); } } + + if (pixelSerializer) { + SkBitmap bm; + SkAutoPixmapUnlock apu; + if (as_IB(image)->getROPixels(&bm) && bm.requestLock(&apu)) { + data.reset(pixelSerializer->encode(apu.pixmap())); + if (data && SkIsJFIF(data, &info)) { + bool yuv = info.fType == SkJFIFInfo::kYCbCr; + if (info.fSize == image->dimensions()) { // Sanity check. + return new PDFJpegBitmap(info.fSize, data, yuv); + } + } + } + } + SkPDFObject* smask = image_compute_is_opaque(image) ? nullptr : new PDFAlphaBitmap(image); #ifdef SK_PDF_IMAGE_STATS diff --git a/gfx/skia/skia/src/pdf/SkPDFBitmap.h b/gfx/skia/skia/src/pdf/SkPDFBitmap.h index d9313314311..b0254c1f551 100644 --- a/gfx/skia/skia/src/pdf/SkPDFBitmap.h +++ b/gfx/skia/skia/src/pdf/SkPDFBitmap.h @@ -16,6 +16,6 @@ class SkImage; * It is designed to use a minimal amout of memory, aside from refing * the image, and its emitObject() does not cache any data. */ -SkPDFObject* SkPDFCreateBitmapObject(const SkImage*); +SkPDFObject* SkPDFCreateBitmapObject(const SkImage*, SkPixelSerializer*); #endif // SkPDFBitmap_DEFINED diff --git a/gfx/skia/skia/src/pdf/SkPDFCanon.h b/gfx/skia/skia/src/pdf/SkPDFCanon.h index 3d2ba6a77d1..9ecb3a02d99 100644 --- a/gfx/skia/skia/src/pdf/SkPDFCanon.h +++ b/gfx/skia/skia/src/pdf/SkPDFCanon.h @@ -10,6 +10,7 @@ #include "SkBitmap.h" #include "SkPDFGraphicState.h" #include "SkPDFShader.h" +#include "SkPixelSerializer.h" #include "SkTDArray.h" #include "SkTHash.h" @@ -80,6 +81,8 @@ public: SkTHashMap fCanEmbedTypeface; + SkAutoTUnref fPixelSerializer; + private: struct FontRec { SkPDFFont* fFont; diff --git a/gfx/skia/skia/src/pdf/SkPDFDevice.cpp b/gfx/skia/skia/src/pdf/SkPDFDevice.cpp index 1c5b4da0706..83408a55be1 100644 --- a/gfx/skia/skia/src/pdf/SkPDFDevice.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFDevice.cpp @@ -5,7 +5,6 @@ * found in the LICENSE file. */ -#include #include "SkPDFDevice.h" #include "SkAnnotation.h" @@ -48,15 +47,12 @@ static bool excessive_translation(const SkMatrix& m) { || SkScalarAbs(m.getTranslateY()) > kExcessiveTranslation; } -static std::tuple untranslate(const SkDraw& d) { +static SkMatrix untranslate(const SkMatrix& matrix, SkScalar x, SkScalar y) { // https://bug.skia.org/257 If the translation is too large, // PDF can't exactly represent the float values as numbers. - SkScalar translateX = d.fMatrix->getTranslateX() / d.fMatrix->getScaleX(); - SkScalar translateY = d.fMatrix->getTranslateY() / d.fMatrix->getScaleY(); - SkMatrix mat = *d.fMatrix; - mat.preTranslate(-translateX, -translateY); - SkASSERT(SkScalarAbs(mat.getTranslateX()) <= 1.0); - return std::make_tuple(mat, SkVector::Make(translateX, translateY)); + SkMatrix result(matrix); + result.preTranslate(x, y); + return result; } // If the paint will definitely draw opaquely, replace kSrc_Mode with @@ -802,7 +798,7 @@ void SkPDFDevice::internalDrawPaint(const SkPaint& paint, &contentEntry->fContent); } -void SkPDFDevice::drawPoints(const SkDraw& d, +void SkPDFDevice::drawPoints(const SkDraw& srcDraw, SkCanvas::PointMode mode, size_t count, const SkPoint* points, @@ -815,19 +811,20 @@ void SkPDFDevice::drawPoints(const SkDraw& d, } if (SkAnnotation* annotation = passedPaint.getAnnotation()) { - if (handlePointAnnotation(points, count, *d.fMatrix, annotation)) { + if (handlePointAnnotation(points, count, *srcDraw.fMatrix, annotation)) { return; } } + SkMatrix newMatrix; + SkDraw d(srcDraw); + SkTArray pointsCopy; if (excessive_translation(*d.fMatrix)) { - SkVector translate; SkMatrix translateMatrix; - std::tie(translateMatrix, translate) = untranslate(d); - SkDraw drawCopy(d); - drawCopy.fMatrix = &translateMatrix; - SkTArray pointsCopy(points, SkToInt(count)); - SkPoint::Offset(&pointsCopy[0], SkToInt(count), translate); - this->drawPoints(drawCopy, mode, count, &pointsCopy[0], srcPaint); - return; // NOTE: shader behavior will be off. + newMatrix = untranslate(*d.fMatrix, points[0].x(), points[0].y()); + d.fMatrix = &newMatrix; + pointsCopy.reset(points, SkToInt(count)); + SkPoint::Offset(&pointsCopy[0], SkToInt(count), + -points[0].x(), -points[0].y()); + points = &pointsCopy[0]; } // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. @@ -949,7 +946,7 @@ static SkPDFDict* create_link_named_dest(const SkData* nameData, return annotation.detach(); } -void SkPDFDevice::drawRect(const SkDraw& d, +void SkPDFDevice::drawRect(const SkDraw& srcDraw, const SkRect& rect, const SkPaint& srcPaint) { SkPaint paint = srcPaint; @@ -957,15 +954,12 @@ void SkPDFDevice::drawRect(const SkDraw& d, SkRect r = rect; r.sort(); + SkMatrix newMatrix; + SkDraw d(srcDraw); if (excessive_translation(*d.fMatrix)) { - SkVector translate; SkMatrix translateMatrix; - std::tie(translateMatrix, translate) = untranslate(d); - SkDraw drawCopy(d); - drawCopy.fMatrix = &translateMatrix; - SkRect rectCopy = rect; - rectCopy.offset(translate.x(), translate.y()); - this->drawRect(drawCopy, rectCopy, srcPaint); - return; // NOTE: shader behavior will be off. + newMatrix = untranslate(*d.fMatrix, r.x(), r.y()); + d.fMatrix = &newMatrix; + r.offsetTo(0, 0); } if (paint.getPathEffect()) { @@ -1015,35 +1009,40 @@ void SkPDFDevice::drawOval(const SkDraw& draw, this->drawPath(draw, path, paint, nullptr, true); } -void SkPDFDevice::drawPath(const SkDraw& d, +void SkPDFDevice::drawPath(const SkDraw& srcDraw, const SkPath& origPath, const SkPaint& srcPaint, const SkMatrix* prePathMatrix, bool pathIsMutable) { + SkMatrix newMatrix; + SkDraw d(srcDraw); + SkPath modifiedPath; + SkPath* pathPtr = const_cast(&origPath); if (excessive_translation(*d.fMatrix)) { - SkVector translate; SkMatrix translateMatrix; - std::tie(translateMatrix, translate) = untranslate(d); - SkDraw drawCopy(d); - drawCopy.fMatrix = &translateMatrix; - SkPath pathCopy(origPath); - pathCopy.offset(translate.x(), translate.y()); - this->drawPath(drawCopy, pathCopy, srcPaint, prePathMatrix, true); - return; // NOTE: shader behavior will be off. + SkPoint firstPt; + if (origPath.getPoints(&firstPt, 1) > 0) { + newMatrix = untranslate(*d.fMatrix, firstPt.x(), firstPt.y()); + d.fMatrix = &newMatrix; + modifiedPath = origPath; + modifiedPath.offset(-firstPt.x(), -firstPt.y()); + pathPtr = &modifiedPath; // NOTE: shader behavior will be off. + pathIsMutable = true; + } } SkPaint paint = srcPaint; replace_srcmode_on_opaque_paint(&paint); - SkPath modifiedPath; - SkPath* pathPtr = const_cast(&origPath); SkMatrix matrix = *d.fMatrix; if (prePathMatrix) { if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { - if (!pathIsMutable) { + if (pathIsMutable) { + pathPtr->transform(*prePathMatrix); + } else { + pathPtr->transform(*prePathMatrix, &modifiedPath); pathPtr = &modifiedPath; pathIsMutable = true; } - origPath.transform(*prePathMatrix, pathPtr); } else { matrix.preConcat(*prePathMatrix); } @@ -1053,11 +1052,14 @@ void SkPDFDevice::drawPath(const SkDraw& d, if (d.fClip->isEmpty()) { return; } - if (!pathIsMutable) { + bool fill; + if (pathIsMutable) { + fill = paint.getFillPath(*pathPtr, pathPtr); + } else { + fill = paint.getFillPath(*pathPtr, &modifiedPath); pathPtr = &modifiedPath; pathIsMutable = true; } - bool fill = paint.getFillPath(origPath, pathPtr); SkPaint noEffectPaint(paint); noEffectPaint.setPathEffect(nullptr); @@ -1321,16 +1323,15 @@ static void draw_transparent_text(SkPDFDevice* device, } -void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, +void SkPDFDevice::drawText(const SkDraw& srcDraw, const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint& srcPaint) { + SkMatrix newMatrix; + SkDraw d(srcDraw); if (excessive_translation(*d.fMatrix)) { - SkVector translate; SkMatrix translateMatrix; - std::tie(translateMatrix, translate) = untranslate(d); - SkDraw drawCopy(d); - drawCopy.fMatrix = &translateMatrix; - this->drawText(drawCopy, text, len, x + translate.x(), - y + translate.y(), srcPaint); - return; // NOTE: shader behavior will be off. + newMatrix = untranslate(*d.fMatrix, x, y); + d.fMatrix = &newMatrix; + x = 0; + y = 0; } if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fCanon)) { @@ -1391,19 +1392,44 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, content.entry()->fContent.writeText("ET\n"); } -void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, +void SkPDFDevice::drawPosText(const SkDraw& srcDraw, const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, - const SkPoint& offset, const SkPaint& srcPaint) { + const SkPoint& srcOffset, const SkPaint& srcPaint) { + if (len == 0) { + return; + } + SkMatrix newMatrix; + SkDraw d(srcDraw); + SkPoint offset(srcOffset); + SkAutoTMalloc scalarsBuffer; if (excessive_translation(*d.fMatrix)) { - SkVector translate; SkMatrix translateMatrix; - std::tie(translateMatrix, translate) = untranslate(d); - SkDraw drawCopy(d); - drawCopy.fMatrix = &translateMatrix; - SkPoint offsetCopy = offset; - SkPoint::Offset(&offsetCopy, 1, translate.x(), translate.y()); - this->drawPosText(drawCopy, text, len, pos, scalarsPerPos, offsetCopy, - srcPaint); - return; // NOTE: shader behavior will be off. + SkPoint first; + if (scalarsPerPos != 2) { + first.set(pos[0], 0); + } else { + first.set(pos[0], pos[1]); + } + newMatrix = untranslate(*d.fMatrix, + first.x() + offset.x(), + first.y() + offset.y()); + d.fMatrix = &newMatrix; + offset.set(0, 0); // offset -= offset; + if (first.x() != 0 || first.y() != 0) { + int glyphCount = srcPaint.textToGlyphs(text, len, NULL); + if (scalarsPerPos != 2) { + scalarsBuffer.reset(glyphCount); + for (int i = 0; i < glyphCount; ++i) { + scalarsBuffer[i] = pos[i] - first.x(); + } + } else { + scalarsBuffer.reset(2 * glyphCount); + for (int i = 0; i < glyphCount; ++i) { + scalarsBuffer[2 * i] = pos[2 * i] - first.x(); + scalarsBuffer[2 * i + 1] = pos[2 * i + 1] - first.y(); + } + } + pos = &scalarsBuffer[0]; + } } if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fCanon)) { @@ -2433,7 +2459,8 @@ void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix, } SkAutoTUnref pdfimage(SkSafeRef(fCanon->findPDFBitmap(image))); if (!pdfimage) { - pdfimage.reset(SkPDFCreateBitmapObject(image)); + pdfimage.reset(SkPDFCreateBitmapObject( + image, fCanon->fPixelSerializer)); if (!pdfimage) { return; } diff --git a/gfx/skia/skia/src/pdf/SkPDFFont.cpp b/gfx/skia/skia/src/pdf/SkPDFFont.cpp index 0d6f3187995..5c06bcc5324 100644 --- a/gfx/skia/skia/src/pdf/SkPDFFont.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFFont.cpp @@ -24,14 +24,13 @@ #include "SkTypes.h" #include "SkUtils.h" -#if defined (GOOGLE3) - #if !defined (SK_BUILD_FOR_ANDROID) +#if defined (SK_SFNTLY_SUBSETTER) + #if defined (GOOGLE3) // #including #defines doesn't work with this build system. #include "typography/font/sfntly/src/sample/chromium/font_subsetter.h" - #define SK_SFNTLY_SUBSETTER // For the benefit of #ifdefs below. + #else + #include SK_SFNTLY_SUBSETTER #endif -#elif defined (SK_SFNTLY_SUBSETTER) - #include SK_SFNTLY_SUBSETTER #endif // PDF's notion of symbolic vs non-symbolic is related to the character set, not diff --git a/gfx/skia/skia/src/pdf/SkPDFMetadata.cpp b/gfx/skia/skia/src/pdf/SkPDFMetadata.cpp index 3f181f5d73b..51619c67480 100644 --- a/gfx/skia/skia/src/pdf/SkPDFMetadata.cpp +++ b/gfx/skia/skia/src/pdf/SkPDFMetadata.cpp @@ -7,6 +7,7 @@ #include "SkPDFMetadata.h" #include "SkPDFTypes.h" +#include #ifdef SK_PDF_GENERATE_PDFA #include "SkMD5.h" @@ -117,7 +118,7 @@ static SkString sk_string_printf(const char* format, ...) { va_end(args); SkASSERT(check == length); SkASSERT(string[length] == '\0'); - return skstd::move(string); + return std::move(string); #else // C99/C++11 standard vsnprintf // TODO: When all compilers support this, remove windows-specific code. va_list args; @@ -138,7 +139,7 @@ static SkString sk_string_printf(const char* format, ...) { va_end(args); SkASSERT(check == length); SkASSERT(string[length] == '\0'); - return skstd::move(string); + return std::move(string); #endif } @@ -185,7 +186,7 @@ static SkString uuid_to_string(const SkPDFMetadata::UUID& uuid) { namespace { class PDFXMLObject final : public SkPDFObject { public: - PDFXMLObject(SkString xml) : fXML(skstd::move(xml)) {} + PDFXMLObject(SkString xml) : fXML(std::move(xml)) {} void emitObject(SkWStream* stream, const SkPDFObjNumMap& omap, const SkPDFSubstituteMap& smap) const override { @@ -258,7 +259,7 @@ const SkString escape_xml(const SkString& input, // Validate that we haven't written outside of our string. SkASSERT(out == &output.writable_str()[output.size()]); *out = '\0'; - return skstd::move(output); + return std::move(output); } SkPDFObject* SkPDFMetadata::createXMPObject(const UUID& doc, diff --git a/gfx/skia/skia/src/pipe/SkGPipePriv.h b/gfx/skia/skia/src/pipe/SkGPipePriv.h deleted file mode 100644 index c4217f3bf9c..00000000000 --- a/gfx/skia/skia/src/pipe/SkGPipePriv.h +++ /dev/null @@ -1,314 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - - -#ifndef SkGPipePriv_DEFINED -#define SkGPipePriv_DEFINED - -#include "SkTypes.h" - -#define UNIMPLEMENTED - -// these must be contiguous, 0...N-1 -enum PaintFlats { - kColorFilter_PaintFlat, - kDrawLooper_PaintFlat, - kImageFilter_PaintFlat, - kMaskFilter_PaintFlat, - kPathEffect_PaintFlat, - kRasterizer_PaintFlat, - kShader_PaintFlat, - kXfermode_PaintFlat, - - kLast_PaintFlat = kXfermode_PaintFlat -}; -#define kCount_PaintFlats (kLast_PaintFlat + 1) - -enum DrawOps { - kSkip_DrawOp, // skip an addition N bytes (N == data) - - // these match Canvas apis - kClipPath_DrawOp, - kClipRegion_DrawOp, - kClipRect_DrawOp, - kClipRRect_DrawOp, - kConcat_DrawOp, - kDrawAtlas_DrawOp, - kDrawBitmap_DrawOp, - kDrawBitmapNine_DrawOp, - kDrawBitmapRect_DrawOp, - kDrawDRRect_DrawOp, - kDrawImage_DrawOp, - kDrawImageRect_DrawOp, - kDrawImageNine_DrawOp, - kDrawOval_DrawOp, - kDrawPaint_DrawOp, - kDrawPatch_DrawOp, - kDrawPath_DrawOp, - kDrawPicture_DrawOp, - kDrawPoints_DrawOp, - kDrawPosText_DrawOp, - kDrawPosTextH_DrawOp, - kDrawRect_DrawOp, - kDrawRRect_DrawOp, - kDrawSprite_DrawOp, - kDrawText_DrawOp, - kDrawTextBlob_DrawOp, - kDrawTextOnPath_DrawOp, - kDrawVertices_DrawOp, - kRestore_DrawOp, - kRotate_DrawOp, - kSave_DrawOp, - kSaveLayer_DrawOp, - kScale_DrawOp, - kSetMatrix_DrawOp, - kSkew_DrawOp, - kTranslate_DrawOp, - - kPaintOp_DrawOp, - kSetTypeface_DrawOp, - kSetAnnotation_DrawOp, - - kDef_Typeface_DrawOp, - kDef_Flattenable_DrawOp, - kDef_Bitmap_DrawOp, - kDef_Factory_DrawOp, - - // these are signals to playback, not drawing verbs - kReportFlags_DrawOp, - kShareBitmapHeap_DrawOp, - kShareImageHeap_DrawOp, - kDone_DrawOp, -}; - -/** - * DrawOp packs into a 32bit int as follows - * - * DrawOp:8 - Flags:4 - Data:20 - * - * Flags and Data are called out separately, so we can reuse Data between - * different Ops that might have different Flags. e.g. Data might be a Paint - * index for both drawRect (no flags) and saveLayer (does have flags). - * - * All Ops that take a SkPaint use their Data field to store the index to - * the paint (previously defined with kPaintOp_DrawOp). - */ - -#define DRAWOPS_OP_BITS 8 -#define DRAWOPS_FLAG_BITS 4 -#define DRAWOPS_DATA_BITS 20 - -#define DRAWOPS_OP_MASK ((1 << DRAWOPS_OP_BITS) - 1) -#define DRAWOPS_FLAG_MASK ((1 << DRAWOPS_FLAG_BITS) - 1) -#define DRAWOPS_DATA_MASK ((1 << DRAWOPS_DATA_BITS) - 1) - -static inline unsigned DrawOp_unpackOp(uint32_t op32) { - return (op32 >> (DRAWOPS_FLAG_BITS + DRAWOPS_DATA_BITS)); -} - -static inline unsigned DrawOp_unpackFlags(uint32_t op32) { - return (op32 >> DRAWOPS_DATA_BITS) & DRAWOPS_FLAG_MASK; -} - -static inline unsigned DrawOp_unpackData(uint32_t op32) { - return op32 & DRAWOPS_DATA_MASK; -} - -static inline uint32_t DrawOp_packOpFlagData(DrawOps op, unsigned flags, unsigned data) { - SkASSERT(0 == (op & ~DRAWOPS_OP_MASK)); - SkASSERT(0 == (flags & ~DRAWOPS_FLAG_MASK)); - SkASSERT(0 == (data & ~DRAWOPS_DATA_MASK)); - - return (op << (DRAWOPS_FLAG_BITS + DRAWOPS_DATA_BITS)) | - (flags << DRAWOPS_DATA_BITS) | - data; -} - -/** DrawOp specific flag bits - */ - -enum { - kSaveLayer_HasBounds_DrawOpFlag = 1 << 0, - kSaveLayer_HasPaint_DrawOpFlag = 1 << 1, -}; -enum { - kDrawTextOnPath_HasMatrix_DrawOpFlag = 1 << 0 -}; -enum { - kDrawVertices_HasTexs_DrawOpFlag = 1 << 0, - kDrawVertices_HasColors_DrawOpFlag = 1 << 1, - kDrawVertices_HasIndices_DrawOpFlag = 1 << 2, - kDrawVertices_HasXfermode_DrawOpFlag = 1 << 3, -}; -enum { - kDrawAtlas_HasPaint_DrawOpFlag = 1 << 0, - kDrawAtlas_HasColors_DrawOpFlag = 1 << 1, - kDrawAtlas_HasCull_DrawOpFlag = 1 << 2, -}; -// These are shared between drawbitmap and drawimage -enum { - kDrawBitmap_HasPaint_DrawOpFlag = 1 << 0, - // Specific to drawBitmapRect, but needs to be different from HasPaint, - // which is used for all drawBitmap calls, so include it here. - kDrawBitmap_HasSrcRect_DrawOpFlag = 1 << 1, - // SkCanvas::DrawBitmapRectFlags::kBleed_DrawBitmapRectFlag is - // converted into and out of this flag to save space - kDrawBitmap_Bleed_DrawOpFlag = 1 << 2, -}; -enum { - kClip_HasAntiAlias_DrawOpFlag = 1 << 0, -}; -/////////////////////////////////////////////////////////////////////////////// - -class BitmapInfo : SkNoncopyable { -public: - BitmapInfo(SkBitmap* bitmap, uint32_t genID, int toBeDrawnCount) - : fBitmap(bitmap) - , fGenID(genID) - , fBytesAllocated(0) - , fMoreRecentlyUsed(nullptr) - , fLessRecentlyUsed(nullptr) - , fToBeDrawnCount(toBeDrawnCount) - {} - - ~BitmapInfo() { - SkASSERT(0 == fToBeDrawnCount); - delete fBitmap; - } - - void addDraws(int drawsToAdd) { - if (0 == fToBeDrawnCount) { - // The readers will only ever decrement the count, so once the - // count is zero, the writer will be the only one modifying it, - // so it does not need to be an atomic operation. - fToBeDrawnCount = drawsToAdd; - } else { - sk_atomic_add(&fToBeDrawnCount, drawsToAdd); - } - } - - void decDraws() { - sk_atomic_dec(&fToBeDrawnCount); - } - - int drawCount() const { - return fToBeDrawnCount; - } - - SkBitmap* fBitmap; - // Store the generation ID of the original bitmap, since copying does - // not copy this field, so fBitmap's generation ID will not be useful - // for comparing. - // FIXME: Is it reasonable to make copying a bitmap/pixelref copy the - // generation ID? - uint32_t fGenID; - // Keep track of the bytes allocated for this bitmap. When replacing the - // bitmap or removing this BitmapInfo we know how much memory has been - // reclaimed. - size_t fBytesAllocated; - // TODO: Generalize the LRU caching mechanism - BitmapInfo* fMoreRecentlyUsed; - BitmapInfo* fLessRecentlyUsed; -private: - int fToBeDrawnCount; -}; - -static inline bool shouldFlattenBitmaps(uint32_t flags) { - return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag - && !(flags & SkGPipeWriter::kSharedAddressSpace_Flag)); -} - -class SkImageHeap : public SkRefCnt { -public: - SkImageHeap(); - virtual ~SkImageHeap(); - - size_t bytesInCache() const { return fBytesInCache; } - void reset(); - // slot must be "valid" -- 0 is never valid - const SkImage* get(int32_t slot) const; - // returns 0 if not found, else returns slot - int32_t find(const SkImage*) const; - // returns non-zero value for where the image was stored - int32_t insert(const SkImage*); - -private: - SkTDArray fArray; - size_t fBytesInCache; -}; - -/////////////////////////////////////////////////////////////////////////////// - -enum PaintOps { - kReset_PaintOp, // no arg - - kFlags_PaintOp, // arg inline - kColor_PaintOp, // arg 32 - kFilterLevel_PaintOp, // arg inline - kStyle_PaintOp, // arg inline - kJoin_PaintOp, // arg inline - kCap_PaintOp, // arg inline - kWidth_PaintOp, // arg scalar - kMiter_PaintOp, // arg scalar - - kEncoding_PaintOp, // arg inline - text - kHinting_PaintOp, // arg inline - text - kAlign_PaintOp, // arg inline - text - kTextSize_PaintOp, // arg scalar - text - kTextScaleX_PaintOp,// arg scalar - text - kTextSkewX_PaintOp, // arg scalar - text - kTypeface_PaintOp, // arg inline (index) - text - - kFlatIndex_PaintOp, // flags=paintflat, data=index -}; - -#define PAINTOPS_OP_BITS 8 -#define PAINTOPS_FLAG_BITS 4 -#define PAINTOPS_DATA_BITS 20 - -#define PAINTOPS_OP_MASK ((1 << PAINTOPS_OP_BITS) - 1) -#define PAINTOPS_FLAG_MASK ((1 << PAINTOPS_FLAG_BITS) - 1) -#define PAINTOPS_DATA_MASK ((1 << PAINTOPS_DATA_BITS) - 1) - -static inline unsigned PaintOp_unpackOp(uint32_t op32) { - return (op32 >> (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS)); -} - -static inline unsigned PaintOp_unpackFlags(uint32_t op32) { - return (op32 >> PAINTOPS_DATA_BITS) & PAINTOPS_FLAG_MASK; -} - -static inline unsigned PaintOp_unpackData(uint32_t op32) { - return op32 & PAINTOPS_DATA_MASK; -} - -static inline uint32_t PaintOp_packOp(PaintOps op) { - SkASSERT(0 == (op & ~PAINTOPS_OP_MASK)); - - return op << (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS); -} - -static inline uint32_t PaintOp_packOpData(PaintOps op, unsigned data) { - SkASSERT(0 == (op & ~PAINTOPS_OP_MASK)); - SkASSERT(0 == (data & ~PAINTOPS_DATA_MASK)); - - return (op << (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS)) | data; -} - -static inline uint32_t PaintOp_packOpFlagData(PaintOps op, unsigned flags, unsigned data) { - SkASSERT(0 == (op & ~PAINTOPS_OP_MASK)); - SkASSERT(0 == (flags & ~PAINTOPS_FLAG_MASK)); - SkASSERT(0 == (data & ~PAINTOPS_DATA_MASK)); - - return (op << (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS)) | - (flags << PAINTOPS_DATA_BITS) | - data; -} - -#endif diff --git a/gfx/skia/skia/src/pipe/SkGPipeRead.cpp b/gfx/skia/skia/src/pipe/SkGPipeRead.cpp deleted file mode 100644 index 4d57a6cca9d..00000000000 --- a/gfx/skia/skia/src/pipe/SkGPipeRead.cpp +++ /dev/null @@ -1,1017 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkBitmapHeap.h" -#include "SkCanvas.h" -#include "SkPaint.h" -#include "SkGPipe.h" -#include "SkGPipePriv.h" -#include "SkReader32.h" -#include "SkStream.h" - -#include "SkAnnotation.h" -#include "SkColorFilter.h" -#include "SkDrawLooper.h" -#include "SkImageFilter.h" -#include "SkMaskFilter.h" -#include "SkPatchUtils.h" -#include "SkPathEffect.h" -#include "SkRasterizer.h" -#include "SkReadBuffer.h" -#include "SkRRect.h" -#include "SkRSXform.h" -#include "SkShader.h" -#include "SkTextBlob.h" -#include "SkTypeface.h" -#include "SkXfermode.h" - -static SkFlattenable::Type paintflat_to_flattype(PaintFlats pf) { - static const uint8_t gEffectTypesInPaintFlatsOrder[] = { - SkFlattenable::kSkColorFilter_Type, - SkFlattenable::kSkDrawLooper_Type, - SkFlattenable::kSkImageFilter_Type, - SkFlattenable::kSkMaskFilter_Type, - SkFlattenable::kSkPathEffect_Type, - SkFlattenable::kSkRasterizer_Type, - SkFlattenable::kSkShader_Type, - SkFlattenable::kSkXfermode_Type, - }; - - SkASSERT((size_t)pf < SK_ARRAY_COUNT(gEffectTypesInPaintFlatsOrder)); - return (SkFlattenable::Type)gEffectTypesInPaintFlatsOrder[pf]; -} - -static void set_paintflat(SkPaint* paint, SkFlattenable* obj, unsigned paintFlat) { - SkASSERT(paintFlat < kCount_PaintFlats); - switch (paintFlat) { - case kColorFilter_PaintFlat: - paint->setColorFilter((SkColorFilter*)obj); - break; - case kDrawLooper_PaintFlat: - paint->setLooper((SkDrawLooper*)obj); - break; - case kMaskFilter_PaintFlat: - paint->setMaskFilter((SkMaskFilter*)obj); - break; - case kPathEffect_PaintFlat: - paint->setPathEffect((SkPathEffect*)obj); - break; - case kRasterizer_PaintFlat: - paint->setRasterizer((SkRasterizer*)obj); - break; - case kShader_PaintFlat: - paint->setShader((SkShader*)obj); - break; - case kImageFilter_PaintFlat: - paint->setImageFilter((SkImageFilter*)obj); - break; - case kXfermode_PaintFlat: - paint->setXfermode((SkXfermode*)obj); - break; - default: - SkDEBUGFAIL("never gets here"); - } -} - -template class SkRefCntTDArray : public SkTDArray { -public: - ~SkRefCntTDArray() { this->unrefAll(); } -}; - -class SkGPipeState : public SkBitmapHeapReader { -public: - SkGPipeState(); - ~SkGPipeState(); - - void setSilent(bool silent) { - fSilent = silent; - } - - bool shouldDraw() { - return !fSilent; - } - - void setFlags(unsigned flags) { - if (fFlags != flags) { - fFlags = flags; - this->updateReader(); - } - } - - unsigned getFlags() const { - return fFlags; - } - - void setReader(SkReadBuffer* reader) { - fReader = reader; - this->updateReader(); - } - - const SkPaint& paint() const { return fPaint; } - SkPaint* editPaint() { return &fPaint; } - - SkFlattenable* getFlat(unsigned index) const { - if (0 == index) { - return nullptr; - } - return fFlatArray[index - 1]; - } - - void defFlattenable(PaintFlats pf, int index) { - index--; - SkFlattenable* obj = fReader->readFlattenable(paintflat_to_flattype(pf)); - if (fFlatArray.count() == index) { - *fFlatArray.append() = obj; - } else { - SkSafeUnref(fFlatArray[index]); - fFlatArray[index] = obj; - } - } - - void defFactory(const char* name) { - SkFlattenable::Factory factory = SkFlattenable::NameToFactory(name); - if (factory) { - SkASSERT(fFactoryArray.find(factory) < 0); - *fFactoryArray.append() = factory; - } - } - - /** - * Add a bitmap to the array of bitmaps, or replace an existing one. - * This is only used when in cross process mode without a shared heap. - */ - void addBitmap(int index) { - SkASSERT(shouldFlattenBitmaps(fFlags)); - SkBitmap* bm; - if(fBitmaps.count() == index) { - bm = new SkBitmap; - *fBitmaps.append() = bm; - } else { - bm = fBitmaps[index]; - } - fReader->readBitmap(bm); - } - - /** - * Override of SkBitmapHeapReader, so that SkReadBuffer can use - * these SkBitmaps for bitmap shaders. Used only in cross process mode - * without a shared heap. - */ - SkBitmap* getBitmap(int32_t index) const override { - SkASSERT(shouldFlattenBitmaps(fFlags)); - return fBitmaps[index]; - } - - /** - * Needed to be a non-abstract subclass of SkBitmapHeapReader. - */ - void releaseRef(int32_t) override {} - - void setSharedHeap(SkBitmapHeap* heap) { - SkASSERT(!shouldFlattenBitmaps(fFlags) || nullptr == heap); - SkRefCnt_SafeAssign(fSharedHeap, heap); - this->updateReader(); - } - - void setImageHeap(SkImageHeap* heap) { - fImageHeap.reset(SkRef(heap)); - } - - /** - * Access the shared heap. Only used in the case when bitmaps are not - * flattened. - */ - SkBitmapHeap* getSharedHeap() const { - SkASSERT(!shouldFlattenBitmaps(fFlags)); - return fSharedHeap; - } - - void addTypeface() { - size_t size = fReader->read32(); - const void* data = fReader->skip(SkAlign4(size)); - SkMemoryStream stream(data, size, false); - *fTypefaces.append() = SkTypeface::Deserialize(&stream); - } - - SkTypeface* getTypeface(unsigned id) const { - return id ? fTypefaces[id - 1] : nullptr; - } - - const SkImage* getImage(int32_t slot) const { - return fImageHeap->get(slot); - } - -private: - void updateReader() { - if (nullptr == fReader) { - return; - } - bool crossProcess = SkToBool(fFlags & SkGPipeWriter::kCrossProcess_Flag); - fReader->setFlags(SkSetClearMask(fReader->getFlags(), crossProcess, - SkReadBuffer::kCrossProcess_Flag)); - if (crossProcess) { - fReader->setFactoryArray(&fFactoryArray); - } else { - fReader->setFactoryArray(nullptr); - } - - if (shouldFlattenBitmaps(fFlags)) { - fReader->setBitmapStorage(this); - } else { - fReader->setBitmapStorage(fSharedHeap); - } - } - SkReadBuffer* fReader; - SkPaint fPaint; - SkTDArray fFlatArray; - SkTDArray fTypefaces; - SkTDArray fFactoryArray; - SkTDArray fBitmaps; - bool fSilent; - // Only used when sharing bitmaps with the writer. - SkBitmapHeap* fSharedHeap; - SkAutoTUnref fImageHeap; - unsigned fFlags; -}; - -/////////////////////////////////////////////////////////////////////////////// - -template const T* skip(SkReader32* reader, size_t count = 1) { - size_t size = sizeof(T) * count; - SkASSERT(SkAlign4(size) == size); - return reinterpret_cast(reader->skip(size)); -} - -template const T* skipAlign(SkReader32* reader, size_t count = 1) { - size_t size = SkAlign4(sizeof(T) * count); - return reinterpret_cast(reader->skip(size)); -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -static void clipPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkPath path; - reader->readPath(&path); - bool doAA = SkToBool(DrawOp_unpackFlags(op32) & kClip_HasAntiAlias_DrawOpFlag); - canvas->clipPath(path, (SkRegion::Op)DrawOp_unpackData(op32), doAA); -} - -static void clipRegion_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkRegion rgn; - reader->readRegion(&rgn); - canvas->clipRegion(rgn, (SkRegion::Op)DrawOp_unpackData(op32)); -} - -static void clipRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - const SkRect* rect = skip(reader); - bool doAA = SkToBool(DrawOp_unpackFlags(op32) & kClip_HasAntiAlias_DrawOpFlag); - canvas->clipRect(*rect, (SkRegion::Op)DrawOp_unpackData(op32), doAA); -} - -static void clipRRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkRRect rrect; - reader->readRRect(&rrect); - bool doAA = SkToBool(DrawOp_unpackFlags(op32) & kClip_HasAntiAlias_DrawOpFlag); - canvas->clipRRect(rrect, (SkRegion::Op)DrawOp_unpackData(op32), doAA); -} - -/////////////////////////////////////////////////////////////////////////////// - -static void setMatrix_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkMatrix matrix; - reader->readMatrix(&matrix); - canvas->setMatrix(matrix); -} - -static void concat_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkMatrix matrix; - reader->readMatrix(&matrix); - canvas->concat(matrix); -} - -static void scale_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - const SkScalar* param = skip(reader, 2); - canvas->scale(param[0], param[1]); -} - -static void skew_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - const SkScalar* param = skip(reader, 2); - canvas->skew(param[0], param[1]); -} - -static void rotate_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - canvas->rotate(reader->readScalar()); -} - -static void translate_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - const SkScalar* param = skip(reader, 2); - canvas->translate(param[0], param[1]); -} - -/////////////////////////////////////////////////////////////////////////////// - -static void save_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - canvas->save(); -} - -static void saveLayer_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - unsigned flags = DrawOp_unpackFlags(op32); - SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags)DrawOp_unpackData(op32); - - const SkRect* bounds = nullptr; - if (flags & kSaveLayer_HasBounds_DrawOpFlag) { - bounds = skip(reader); - } - const SkPaint* paint = nullptr; - if (flags & kSaveLayer_HasPaint_DrawOpFlag) { - paint = &state->paint(); - } - canvas->saveLayer(bounds, paint, saveFlags); -} - -static void restore_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - canvas->restore(); -} - -/////////////////////////////////////////////////////////////////////////////// - -static void drawPaint_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - if (state->shouldDraw()) { - canvas->drawPaint(state->paint()); - } -} - -static void drawPoints_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkCanvas::PointMode mode = (SkCanvas::PointMode)DrawOp_unpackFlags(op32); - size_t count = reader->readU32(); - const SkPoint* pts = skip(reader, count); - if (state->shouldDraw()) { - canvas->drawPoints(mode, count, pts, state->paint()); - } -} - -static void drawOval_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - const SkRect* rect = skip(reader); - if (state->shouldDraw()) { - canvas->drawOval(*rect, state->paint()); - } -} - -static void drawRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - const SkRect* rect = skip(reader); - if (state->shouldDraw()) { - canvas->drawRect(*rect, state->paint()); - } -} - -static void drawRRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkRRect rrect; - reader->readRRect(&rrect); - if (state->shouldDraw()) { - canvas->drawRRect(rrect, state->paint()); - } -} - -static void drawDRRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkRRect outer, inner; - reader->readRRect(&outer); - reader->readRRect(&inner); - if (state->shouldDraw()) { - canvas->drawDRRect(outer, inner, state->paint()); - } -} - -static void drawPatch_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - - unsigned flags = DrawOp_unpackFlags(op32); - - const SkPoint* cubics = skip(reader, SkPatchUtils::kNumCtrlPts); - - const SkColor* colors = nullptr; - if (flags & kDrawVertices_HasColors_DrawOpFlag) { - colors = skip(reader, SkPatchUtils::kNumCorners); - } - const SkPoint* texCoords = nullptr; - if (flags & kDrawVertices_HasTexs_DrawOpFlag) { - texCoords = skip(reader, SkPatchUtils::kNumCorners); - } - SkAutoTUnref xfer; - if (flags & kDrawVertices_HasXfermode_DrawOpFlag) { - int mode = reader->readInt(); - if (mode < 0 || mode > SkXfermode::kLastMode) { - mode = SkXfermode::kModulate_Mode; - } - xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode)); - } - if (state->shouldDraw()) { - canvas->drawPatch(cubics, colors, texCoords, xfer, state->paint()); - } -} - -static void drawPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkPath path; - reader->readPath(&path); - if (state->shouldDraw()) { - canvas->drawPath(path, state->paint()); - } -} - -static void drawVertices_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - unsigned flags = DrawOp_unpackFlags(op32); - - SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader->readU32(); - int vertexCount = reader->readU32(); - const SkPoint* verts = skip(reader, vertexCount); - - const SkPoint* texs = nullptr; - if (flags & kDrawVertices_HasTexs_DrawOpFlag) { - texs = skip(reader, vertexCount); - } - - const SkColor* colors = nullptr; - if (flags & kDrawVertices_HasColors_DrawOpFlag) { - colors = skip(reader, vertexCount); - } - - SkAutoTUnref xfer; - if (flags & kDrawVertices_HasXfermode_DrawOpFlag) { - SkXfermode::Mode mode = (SkXfermode::Mode)reader->readU32(); - xfer.reset(SkXfermode::Create(mode)); - } - - int indexCount = 0; - const uint16_t* indices = nullptr; - if (flags & kDrawVertices_HasIndices_DrawOpFlag) { - indexCount = reader->readU32(); - indices = skipAlign(reader, indexCount); - } - if (state->shouldDraw()) { - canvas->drawVertices(vmode, vertexCount, verts, texs, colors, xfer, - indices, indexCount, state->paint()); - } -} - -static void drawAtlas_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, SkGPipeState* state) { - unsigned flags = DrawOp_unpackFlags(op32); - - const SkPaint* paint = nullptr; - if (flags & kDrawAtlas_HasPaint_DrawOpFlag) { - paint = &state->paint(); - } - const int slot = reader->readU32(); - const SkImage* atlas = state->getImage(slot); - const int count = reader->readU32(); - SkXfermode::Mode mode = (SkXfermode::Mode)reader->readU32(); - const SkRSXform* xform = skip(reader, count); - const SkRect* tex = skip(reader, count); - const SkColor* colors = nullptr; - if (flags & kDrawAtlas_HasColors_DrawOpFlag) { - colors = skip(reader, count); - } - const SkRect* cull = nullptr; - if (flags & kDrawAtlas_HasCull_DrawOpFlag) { - cull = skip(reader, 1); - } - - if (state->shouldDraw()) { - canvas->drawAtlas(atlas, xform, tex, colors, count, mode, cull, paint); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -static void drawText_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - size_t len = reader->readU32(); - const void* text = reader->skip(SkAlign4(len)); - const SkScalar* xy = skip(reader, 2); - if (state->shouldDraw()) { - canvas->drawText(text, len, xy[0], xy[1], state->paint()); - } -} - -static void drawPosText_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - size_t len = reader->readU32(); - const void* text = reader->skip(SkAlign4(len)); - size_t posCount = reader->readU32(); // compute by our writer - const SkPoint* pos = skip(reader, posCount); - if (state->shouldDraw()) { - canvas->drawPosText(text, len, pos, state->paint()); - } -} - -static void drawPosTextH_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - size_t len = reader->readU32(); - const void* text = reader->skip(SkAlign4(len)); - size_t posCount = reader->readU32(); // compute by our writer - const SkScalar* xpos = skip(reader, posCount); - SkScalar constY = reader->readScalar(); - if (state->shouldDraw()) { - canvas->drawPosTextH(text, len, xpos, constY, state->paint()); - } -} - -static void drawTextOnPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - size_t len = reader->readU32(); - const void* text = reader->skip(SkAlign4(len)); - - SkPath path; - reader->readPath(&path); - - SkMatrix matrixStorage; - const SkMatrix* matrix = nullptr; - if (DrawOp_unpackFlags(op32) & kDrawTextOnPath_HasMatrix_DrawOpFlag) { - reader->readMatrix(&matrixStorage); - matrix = &matrixStorage; - } - if (state->shouldDraw()) { - canvas->drawTextOnPath(text, len, path, matrix, state->paint()); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -class BitmapHolder : SkNoncopyable { -public: - BitmapHolder(SkReader32* reader, uint32_t op32, SkGPipeState* state); - ~BitmapHolder() { - if (fHeapEntry != nullptr) { - fHeapEntry->releaseRef(); - } - } - const SkBitmap* getBitmap() { - return fBitmap; - } -private: - SkBitmapHeapEntry* fHeapEntry; - const SkBitmap* fBitmap; - SkBitmap fBitmapStorage; -}; - -BitmapHolder::BitmapHolder(SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - const unsigned flags = state->getFlags(); - const unsigned index = DrawOp_unpackData(op32); - if (shouldFlattenBitmaps(flags)) { - fHeapEntry = nullptr; - fBitmap = state->getBitmap(index); - } else { - SkBitmapHeapEntry* entry = state->getSharedHeap()->getEntry(index); - if (SkToBool(flags & SkGPipeWriter::kSimultaneousReaders_Flag)) { - // Make a shallow copy for thread safety. Each thread will point to the same SkPixelRef, - // which is thread safe. - fBitmapStorage = *entry->getBitmap(); - fBitmap = &fBitmapStorage; - // Release the ref on the bitmap now, since we made our own copy. - entry->releaseRef(); - fHeapEntry = nullptr; - } else { - SkASSERT(!shouldFlattenBitmaps(flags)); - SkASSERT(!SkToBool(flags & SkGPipeWriter::kSimultaneousReaders_Flag)); - fHeapEntry = entry; - fBitmap = fHeapEntry->getBitmap(); - } - } -} - -static void drawBitmap_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - BitmapHolder holder(reader, op32, state); - bool hasPaint = SkToBool(DrawOp_unpackFlags(op32) & kDrawBitmap_HasPaint_DrawOpFlag); - SkScalar left = reader->readScalar(); - SkScalar top = reader->readScalar(); - const SkBitmap* bitmap = holder.getBitmap(); - if (state->shouldDraw()) { - canvas->drawBitmap(*bitmap, left, top, hasPaint ? &state->paint() : nullptr); - } -} - -static void drawBitmapNine_rp(SkCanvas* canvas, SkReader32* reader, - uint32_t op32, SkGPipeState* state) { - BitmapHolder holder(reader, op32, state); - bool hasPaint = SkToBool(DrawOp_unpackFlags(op32) & kDrawBitmap_HasPaint_DrawOpFlag); - const SkIRect* center = skip(reader); - const SkRect* dst = skip(reader); - const SkBitmap* bitmap = holder.getBitmap(); - if (state->shouldDraw()) { - canvas->drawBitmapNine(*bitmap, *center, *dst, - hasPaint ? &state->paint() : nullptr); - } -} - -static void drawBitmapRect_rp(SkCanvas* canvas, SkReader32* reader, - uint32_t op32, SkGPipeState* state) { - BitmapHolder holder(reader, op32, state); - unsigned flags = DrawOp_unpackFlags(op32); - bool hasPaint = SkToBool(flags & kDrawBitmap_HasPaint_DrawOpFlag); - bool hasSrc = SkToBool(flags & kDrawBitmap_HasSrcRect_DrawOpFlag); - const SkRect* src; - if (hasSrc) { - src = skip(reader); - } else { - src = nullptr; - } - SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint; - if (flags & kDrawBitmap_Bleed_DrawOpFlag) { - constraint = SkCanvas::kFast_SrcRectConstraint; - } - const SkRect* dst = skip(reader); - const SkBitmap* bitmap = holder.getBitmap(); - if (state->shouldDraw()) { - canvas->legacy_drawBitmapRect(*bitmap, src, *dst, hasPaint ? &state->paint() : nullptr, constraint); - } -} - -static void drawSprite_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - BitmapHolder holder(reader, op32, state); - bool hasPaint = SkToBool(DrawOp_unpackFlags(op32) & kDrawBitmap_HasPaint_DrawOpFlag); - const SkIPoint* point = skip(reader); - const SkBitmap* bitmap = holder.getBitmap(); - if (state->shouldDraw()) { - canvas->drawSprite(*bitmap, point->fX, point->fY, hasPaint ? &state->paint() : nullptr); - } -} - -static void drawImage_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, SkGPipeState* state) { - unsigned slot = DrawOp_unpackData(op32); - unsigned flags = DrawOp_unpackFlags(op32); - bool hasPaint = SkToBool(flags & kDrawBitmap_HasPaint_DrawOpFlag); - SkScalar x = reader->readScalar(); - SkScalar y = reader->readScalar(); - const SkImage* image = state->getImage(slot); - if (state->shouldDraw()) { - canvas->drawImage(image, x, y, hasPaint ? &state->paint() : nullptr); - } -} - -static void drawImageRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - unsigned slot = DrawOp_unpackData(op32); - unsigned flags = DrawOp_unpackFlags(op32); - bool hasPaint = SkToBool(flags & kDrawBitmap_HasPaint_DrawOpFlag); - bool hasSrc = SkToBool(flags & kDrawBitmap_HasSrcRect_DrawOpFlag); - const SkRect* src = nullptr; - if (hasSrc) { - src = skip(reader); - } - const SkRect* dst = skip(reader); - SkCanvas::SrcRectConstraint constraint = (SkCanvas::SrcRectConstraint)reader->readInt(); - - const SkImage* image = state->getImage(slot); - if (state->shouldDraw()) { - canvas->legacy_drawImageRect(image, src, *dst, hasPaint ? &state->paint() : nullptr, constraint); - } -} - -static void drawImageNine_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - unsigned slot = DrawOp_unpackData(op32); - unsigned flags = DrawOp_unpackFlags(op32); - bool hasPaint = SkToBool(flags & kDrawBitmap_HasPaint_DrawOpFlag); - const SkIRect* center = skip(reader); - const SkRect* dst = skip(reader); - const SkImage* image = state->getImage(slot); - if (state->shouldDraw()) { - canvas->drawImageNine(image, *center, *dst, hasPaint ? &state->paint() : nullptr); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -static void drawPicture_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - UNIMPLEMENTED -} - -static void drawTextBlob_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkScalar x = reader->readScalar(); - SkScalar y = reader->readScalar(); - - int typefaceCount = reader->readU32(); - SkAutoSTMalloc<16, SkTypeface*> typefaceArray(typefaceCount); - if (state->getFlags() & SkGPipeWriter::kCrossProcess_Flag) { - for (int i = 0; i < typefaceCount; ++i) { - typefaceArray[i] = state->getTypeface(reader->readU32()); - } - } else { - reader->read(typefaceArray.get(), typefaceCount * sizeof(SkTypeface*)); - } - - size_t blobSize = reader->readU32(); - const void* data = reader->skip(SkAlign4(blobSize)); - - if (state->shouldDraw()) { - SkReadBuffer blobBuffer(data, blobSize); - blobBuffer.setTypefaceArray(typefaceArray.get(), typefaceCount); - SkAutoTUnref blob(SkTextBlob::CreateFromBuffer(blobBuffer)); - SkASSERT(blob.get()); - - canvas->drawTextBlob(blob, x, y, state->paint()); - } -} -/////////////////////////////////////////////////////////////////////////////// - -static void paintOp_rp(SkCanvas*, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - size_t offset = reader->offset(); - size_t stop = offset + PaintOp_unpackData(op32); - SkPaint* p = state->editPaint(); - - do { - uint32_t p32 = reader->readU32(); - unsigned op = PaintOp_unpackOp(p32); - unsigned data = PaintOp_unpackData(p32); - -// SkDebugf(" read %08X op=%d flags=%d data=%d\n", p32, op, done, data); - - switch (op) { - case kReset_PaintOp: p->reset(); break; - case kFlags_PaintOp: p->setFlags(data); break; - case kColor_PaintOp: p->setColor(reader->readU32()); break; - case kFilterLevel_PaintOp: p->setFilterQuality((SkFilterQuality)data); break; - case kStyle_PaintOp: p->setStyle((SkPaint::Style)data); break; - case kJoin_PaintOp: p->setStrokeJoin((SkPaint::Join)data); break; - case kCap_PaintOp: p->setStrokeCap((SkPaint::Cap)data); break; - case kWidth_PaintOp: p->setStrokeWidth(reader->readScalar()); break; - case kMiter_PaintOp: p->setStrokeMiter(reader->readScalar()); break; - case kEncoding_PaintOp: - p->setTextEncoding((SkPaint::TextEncoding)data); - break; - case kHinting_PaintOp: p->setHinting((SkPaint::Hinting)data); break; - case kAlign_PaintOp: p->setTextAlign((SkPaint::Align)data); break; - case kTextSize_PaintOp: p->setTextSize(reader->readScalar()); break; - case kTextScaleX_PaintOp: p->setTextScaleX(reader->readScalar()); break; - case kTextSkewX_PaintOp: p->setTextSkewX(reader->readScalar()); break; - - case kFlatIndex_PaintOp: { - PaintFlats pf = (PaintFlats)PaintOp_unpackFlags(p32); - unsigned index = data; - set_paintflat(p, state->getFlat(index), pf); - break; - } - - case kTypeface_PaintOp: - SkASSERT(SkToBool(state->getFlags() & - SkGPipeWriter::kCrossProcess_Flag)); - p->setTypeface(state->getTypeface(data)); - break; - default: SkDEBUGFAIL("bad paintop"); return; - } - SkASSERT(reader->offset() <= stop); - } while (reader->offset() < stop); -} - -static void typeface_rp(SkCanvas*, SkReader32* reader, uint32_t, - SkGPipeState* state) { - SkASSERT(!SkToBool(state->getFlags() & SkGPipeWriter::kCrossProcess_Flag)); - SkPaint* p = state->editPaint(); - p->setTypeface(static_cast(reader->readPtr())); -} - -static void annotation_rp(SkCanvas*, SkReader32* reader, uint32_t op32, - SkGPipeState* state) { - SkPaint* p = state->editPaint(); - - const size_t size = DrawOp_unpackData(op32); - if (size > 0) { - SkReadBuffer buffer(reader->skip(size), size); - p->setAnnotation(SkAnnotation::Create(buffer))->unref(); - SkASSERT(buffer.offset() == size); - } else { - p->setAnnotation(nullptr); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -static void def_Typeface_rp(SkCanvas*, SkReader32*, uint32_t, SkGPipeState* state) { - state->addTypeface(); -} - -static void def_PaintFlat_rp(SkCanvas*, SkReader32*, uint32_t op32, - SkGPipeState* state) { - PaintFlats pf = (PaintFlats)DrawOp_unpackFlags(op32); - unsigned index = DrawOp_unpackData(op32); - state->defFlattenable(pf, index); -} - -static void def_Bitmap_rp(SkCanvas*, SkReader32*, uint32_t op32, - SkGPipeState* state) { - unsigned index = DrawOp_unpackData(op32); - state->addBitmap(index); -} - -static void def_Factory_rp(SkCanvas*, SkReader32* reader, uint32_t, - SkGPipeState* state) { - state->defFactory(reader->readString()); -} - -/////////////////////////////////////////////////////////////////////////////// - -static void skip_rp(SkCanvas*, SkReader32* reader, uint32_t op32, SkGPipeState*) { - size_t bytes = DrawOp_unpackData(op32); - (void)reader->skip(bytes); -} - -static void reportFlags_rp(SkCanvas*, SkReader32*, uint32_t op32, - SkGPipeState* state) { - unsigned flags = DrawOp_unpackFlags(op32); - state->setFlags(flags); -} - -static void shareBitmapHeap_rp(SkCanvas*, SkReader32* reader, uint32_t, - SkGPipeState* state) { - state->setSharedHeap(static_cast(reader->readPtr())); -} - -static void shareImageHeap_rp(SkCanvas*, SkReader32* reader, uint32_t, SkGPipeState* state) { - state->setImageHeap(static_cast(reader->readPtr())); -} - -static void done_rp(SkCanvas*, SkReader32*, uint32_t, SkGPipeState*) {} - -typedef void (*ReadProc)(SkCanvas*, SkReader32*, uint32_t op32, SkGPipeState*); - -static const ReadProc gReadTable[] = { - skip_rp, - clipPath_rp, - clipRegion_rp, - clipRect_rp, - clipRRect_rp, - concat_rp, - drawAtlas_rp, - drawBitmap_rp, - drawBitmapNine_rp, - drawBitmapRect_rp, - drawDRRect_rp, - drawImage_rp, - drawImageRect_rp, - drawImageNine_rp, - drawOval_rp, - drawPaint_rp, - drawPatch_rp, - drawPath_rp, - drawPicture_rp, - drawPoints_rp, - drawPosText_rp, - drawPosTextH_rp, - drawRect_rp, - drawRRect_rp, - drawSprite_rp, - drawText_rp, - drawTextBlob_rp, - drawTextOnPath_rp, - drawVertices_rp, - restore_rp, - rotate_rp, - save_rp, - saveLayer_rp, - scale_rp, - setMatrix_rp, - skew_rp, - translate_rp, - - paintOp_rp, - typeface_rp, - annotation_rp, - - def_Typeface_rp, - def_PaintFlat_rp, - def_Bitmap_rp, - def_Factory_rp, - - reportFlags_rp, - shareBitmapHeap_rp, - shareImageHeap_rp, - done_rp -}; - -/////////////////////////////////////////////////////////////////////////////// - -SkGPipeState::SkGPipeState() - : fReader(0) - , fSilent(false) - , fSharedHeap(nullptr) - , fFlags(0) { - -} - -SkGPipeState::~SkGPipeState() { - fTypefaces.safeUnrefAll(); - fFlatArray.safeUnrefAll(); - fBitmaps.deleteAll(); - SkSafeUnref(fSharedHeap); -} - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkGPipe.h" - -SkGPipeReader::SkGPipeReader() { - fCanvas = nullptr; - fState = nullptr; - fProc = nullptr; -} - -SkGPipeReader::SkGPipeReader(SkCanvas* target) { - fCanvas = nullptr; - this->setCanvas(target); - fState = nullptr; - fProc = nullptr; -} - -void SkGPipeReader::setCanvas(SkCanvas *target) { - SkRefCnt_SafeAssign(fCanvas, target); -} - -SkGPipeReader::~SkGPipeReader() { - SkSafeUnref(fCanvas); - delete fState; -} - -SkGPipeReader::Status SkGPipeReader::playback(const void* data, size_t length, - uint32_t playbackFlags, size_t* bytesRead) { - if (nullptr == fCanvas) { - return kError_Status; - } - - if (nullptr == fState) { - fState = new SkGPipeState; - } - - fState->setSilent(playbackFlags & kSilent_PlaybackFlag); - - SkASSERT(SK_ARRAY_COUNT(gReadTable) == (kDone_DrawOp + 1)); - - const ReadProc* table = gReadTable; - SkReadBuffer reader(data, length); - reader.setBitmapDecoder(fProc); - SkCanvas* canvas = fCanvas; - Status status = kEOF_Status; - - fState->setReader(&reader); - while (!reader.eof()) { - uint32_t op32 = reader.readUInt(); - unsigned op = DrawOp_unpackOp(op32); - // SkDEBUGCODE(DrawOps drawOp = (DrawOps)op;) - - if (op >= SK_ARRAY_COUNT(gReadTable)) { - SkDebugf("---- bad op during GPipeState::playback\n"); - status = kError_Status; - break; - } - if (kDone_DrawOp == op) { - status = kDone_Status; - break; - } - table[op](canvas, reader.getReader32(), op32, fState); - if ((playbackFlags & kReadAtom_PlaybackFlag) && - (table[op] != paintOp_rp && - table[op] != def_Typeface_rp && - table[op] != def_PaintFlat_rp && - table[op] != def_Bitmap_rp - )) { - status = kReadAtom_Status; - break; - } - } - - if (bytesRead) { - *bytesRead = reader.offset(); - } - return status; -} diff --git a/gfx/skia/skia/src/pipe/SkGPipeWrite.cpp b/gfx/skia/skia/src/pipe/SkGPipeWrite.cpp deleted file mode 100644 index 0fccb80d0a1..00000000000 --- a/gfx/skia/skia/src/pipe/SkGPipeWrite.cpp +++ /dev/null @@ -1,1495 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkAnnotation.h" -#include "SkBitmapHeap.h" -#include "SkCanvas.h" -#include "SkColorFilter.h" -#include "SkData.h" -#include "SkDrawLooper.h" -#include "SkGPipe.h" -#include "SkGPipePriv.h" -#include "SkImageFilter.h" -#include "SkMaskFilter.h" -#include "SkRSXform.h" -#include "SkWriteBuffer.h" -#include "SkPaint.h" -#include "SkPatchUtils.h" -#include "SkPathEffect.h" -#include "SkPictureFlat.h" -#include "SkPtrRecorder.h" -#include "SkRasterizer.h" -#include "SkRRect.h" -#include "SkShader.h" -#include "SkStream.h" -#include "SkTextBlob.h" -#include "SkTSearch.h" -#include "SkTypeface.h" -#include "SkWriter32.h" - -enum { - kSizeOfFlatRRect = sizeof(SkRect) + 4 * sizeof(SkVector) -}; - -static bool is_cross_process(uint32_t flags) { - return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag); -} - -static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) { - SkASSERT(paintFlat < kCount_PaintFlats); - switch (paintFlat) { - case kColorFilter_PaintFlat: return paint.getColorFilter(); - case kDrawLooper_PaintFlat: return paint.getLooper(); - case kMaskFilter_PaintFlat: return paint.getMaskFilter(); - case kPathEffect_PaintFlat: return paint.getPathEffect(); - case kRasterizer_PaintFlat: return paint.getRasterizer(); - case kShader_PaintFlat: return paint.getShader(); - case kImageFilter_PaintFlat: return paint.getImageFilter(); - case kXfermode_PaintFlat: return paint.getXfermode(); - } - SkDEBUGFAIL("never gets here"); - return nullptr; -} - -static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) { - SkASSERT(typeface); - SkDynamicMemoryWStream stream; - typeface->serialize(&stream); - size_t size = stream.getOffset(); - if (writer) { - writer->write32(SkToU32(size)); - SkAutoDataUnref data(stream.copyToData()); - writer->writePad(data->data(), size); - } - return 4 + SkAlign4(size); -} - -/////////////////////////////////////////////////////////////////////////////// - -class FlattenableHeap : public SkFlatController { -public: - FlattenableHeap(int numFlatsToKeep, SkNamedFactorySet* fset, bool isCrossProcess) - : INHERITED(isCrossProcess ? SkWriteBuffer::kCrossProcess_Flag : 0) - , fNumFlatsToKeep(numFlatsToKeep) { - SkASSERT((isCrossProcess && fset != nullptr) || (!isCrossProcess && nullptr == fset)); - if (isCrossProcess) { - this->setNamedFactorySet(fset); - } - } - - ~FlattenableHeap() { - fPointers.freeAll(); - } - - void* allocThrow(size_t bytes) override; - - void unalloc(void* ptr) override; - - void setBitmapStorage(SkBitmapHeap* heap) { - this->setBitmapHeap(heap); - } - - const SkFlatData* flatToReplace() const; - - // Mark an SkFlatData as one that should not be returned by flatToReplace. - // Takes the result of SkFlatData::index() as its parameter. - void markFlatForKeeping(int index) { - *fFlatsThatMustBeKept.append() = index; - } - - void markAllFlatsSafeToDelete() { - fFlatsThatMustBeKept.reset(); - } - -private: - // Keep track of the indices (i.e. the result of SkFlatData::index()) of - // flats that must be kept, since they are on the current paint. - SkTDArray fFlatsThatMustBeKept; - SkTDArray fPointers; - const int fNumFlatsToKeep; - - typedef SkFlatController INHERITED; -}; - -void FlattenableHeap::unalloc(void* ptr) { - int indexToRemove = fPointers.rfind(ptr); - if (indexToRemove >= 0) { - sk_free(ptr); - fPointers.remove(indexToRemove); - } -} - -void* FlattenableHeap::allocThrow(size_t bytes) { - void* ptr = sk_malloc_throw(bytes); - *fPointers.append() = ptr; - return ptr; -} - -const SkFlatData* FlattenableHeap::flatToReplace() const { - // First, determine whether we should replace one. - if (fPointers.count() > fNumFlatsToKeep) { - // Look through the flattenable heap. - // TODO: Return the LRU flat. - for (int i = 0; i < fPointers.count(); i++) { - SkFlatData* potential = (SkFlatData*)fPointers[i]; - // Make sure that it is not one that must be kept. - bool mustKeep = false; - for (int j = 0; j < fFlatsThatMustBeKept.count(); j++) { - if (potential->index() == fFlatsThatMustBeKept[j]) { - mustKeep = true; - break; - } - } - if (!mustKeep) { - return potential; - } - } - } - return nullptr; -} - -/////////////////////////////////////////////////////////////////////////////// - -struct SkFlattenableTraits { - static void Flatten(SkWriteBuffer& buffer, const SkFlattenable& flattenable) { - buffer.writeFlattenable(&flattenable); - } - // No need to define unflatten if we never call it. -}; -typedef SkFlatDictionary FlatDictionary; - -/////////////////////////////////////////////////////////////////////////////// - -/** - * If SkBitmaps are to be flattened to send to the reader, this class is - * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so. - */ -class BitmapShuttle : public SkBitmapHeap::ExternalStorage { -public: - BitmapShuttle(SkGPipeCanvas*); - - ~BitmapShuttle(); - - bool insert(const SkBitmap& bitmap, int32_t slot) override; - - /** - * Remove the SkGPipeCanvas used for insertion. After this, calls to - * insert will crash. - */ - void removeCanvas(); - -private: - SkGPipeCanvas* fCanvas; -}; - -/////////////////////////////////////////////////////////////////////////////// - -class SkGPipeCanvas : public SkCanvas { -public: - SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags, - uint32_t width, uint32_t height); - virtual ~SkGPipeCanvas(); - - /** - * Called when nothing else is to be written to the stream. Any repeated - * calls are ignored. - * - * @param notifyReaders Whether to send a message to the reader(s) that - * the writer is through sending commands. Should generally be true, - * unless there is an error which prevents further messages from - * being sent. - */ - void finish(bool notifyReaders) { - if (fDone) { - return; - } - if (notifyReaders && this->needOpBytes()) { - this->writeOp(kDone_DrawOp); - this->doNotify(); - } - if (shouldFlattenBitmaps(fFlags)) { - // The following circular references exist: - // fFlattenableHeap -> fWriteBuffer -> fBitmapStorage -> fExternalStorage -> fCanvas - // fBitmapHeap -> fExternalStorage -> fCanvas - // fFlattenableHeap -> fBitmapStorage -> fExternalStorage -> fCanvas - - // Break them all by destroying the final link to this SkGPipeCanvas. - fBitmapShuttle->removeCanvas(); - } - fDone = true; - } - - void flushRecording(bool detachCurrentBlock); - size_t freeMemoryIfPossible(size_t bytesToFree); - - size_t storageAllocatedForRecording() { - size_t bytesAllocated = 0; - if (nullptr != fBitmapHeap) { - bytesAllocated += fBitmapHeap->bytesAllocated(); - } - if (nullptr != fImageHeap) { - bytesAllocated += fImageHeap->bytesInCache(); - } - return bytesAllocated; - } - - /** - * Flatten an SkBitmap to send to the reader, where it will be referenced - * according to slot. - */ - bool shuttleBitmap(const SkBitmap&, int32_t slot); - - void resetImageHeap(); - -protected: - void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override; - void willRestore() override; - - void didConcat(const SkMatrix&) override; - void didSetMatrix(const SkMatrix&) override; - - void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; - void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, - const SkPaint&) override; - void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], - const SkPaint&) override; - void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], - SkScalar constY, const SkPaint&) override; - void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, - const SkMatrix* matrix, const SkPaint&) override; - void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, - const SkPaint& paint) override; - void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, - const SkPaint& paint) override; - void onDrawPaint(const SkPaint&) override; - void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; - void onDrawRect(const SkRect&, const SkPaint&) override; - void onDrawOval(const SkRect&, const SkPaint&) override; - void onDrawRRect(const SkRRect&, const SkPaint&) override; - void onDrawPath(const SkPath&, const SkPaint&) override; - void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; - void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, - SrcRectConstraint) override; - void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; - void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, - const SkPaint*, SrcRectConstraint) override; - void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, - const SkPaint*) override; - void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, - const SkPaint*) override; - void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; - void onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint&) override; - void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], - int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) override; - void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; - void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, SkRegion::Op) override; - - void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; - -private: - void recordTranslate(const SkMatrix&); - void recordScale(const SkMatrix&); - void recordConcat(const SkMatrix&); - - SkNamedFactorySet* fFactorySet; - SkBitmapHeap* fBitmapHeap; - SkImageHeap* fImageHeap; - SkGPipeController* fController; - SkWriter32& fWriter; - size_t fBlockSize; // amount allocated for writer - size_t fBytesNotified; - bool fDone; - const uint32_t fFlags; - - SkRefCntSet fTypefaceSet; - - uint32_t getTypefaceID(SkTypeface*); - - inline void writeOp(DrawOps op, unsigned flags, unsigned data) { - fWriter.write32(DrawOp_packOpFlagData(op, flags, data)); - } - - inline void writeOp(DrawOps op) { - fWriter.write32(DrawOp_packOpFlagData(op, 0, 0)); - } - - bool needOpBytes(size_t size = 0); - - inline void doNotify() { - if (!fDone) { - size_t bytes = fWriter.bytesWritten() - fBytesNotified; - if (bytes > 0) { - fController->notifyWritten(bytes); - fBytesNotified += bytes; - } - } - } - - typedef SkAutoSTMalloc<128, uint8_t> TypefaceBuffer; - size_t getInProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuffer*); - size_t getCrossProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuffer*); - - // Should be called after any calls to an SkFlatDictionary::findAndReplace - // if a new SkFlatData was added when in cross process mode - void flattenFactoryNames(); - - FlattenableHeap fFlattenableHeap; - FlatDictionary fFlatDictionary; - SkAutoTUnref fBitmapShuttle; - int fCurrFlatIndex[kCount_PaintFlats]; - - int flattenToIndex(SkFlattenable* obj, PaintFlats); - - // Common code used by drawBitmap*. Behaves differently depending on the - // type of SkBitmapHeap being used, which is determined by the flags used. - bool commonDrawBitmap(const SkBitmap&, DrawOps, unsigned flags, size_t bytes, const SkPaint*); - bool commonDrawImage(const SkImage*, DrawOps, unsigned flags, size_t bytes, const SkPaint*); - - SkPaint fPaint; - void writePaint(const SkPaint&); - - class AutoPipeNotify { - public: - AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {} - ~AutoPipeNotify() { fCanvas->doNotify(); } - private: - SkGPipeCanvas* fCanvas; - }; - friend class AutoPipeNotify; - - typedef SkCanvas INHERITED; -}; - -void SkGPipeCanvas::flattenFactoryNames() { - const char* name; - while ((name = fFactorySet->getNextAddedFactoryName()) != nullptr) { - size_t len = strlen(name); - if (this->needOpBytes(SkWriter32::WriteStringSize(name, len))) { - this->writeOp(kDef_Factory_DrawOp); - fWriter.writeString(name, len); - } - } -} - -bool SkGPipeCanvas::shuttleBitmap(const SkBitmap& bm, int32_t slot) { - SkASSERT(shouldFlattenBitmaps(fFlags)); - SkWriteBuffer buffer; - buffer.setNamedFactoryRecorder(fFactorySet); - buffer.writeBitmap(bm); - this->flattenFactoryNames(); - size_t size = buffer.bytesWritten(); - if (this->needOpBytes(size)) { - this->writeOp(kDef_Bitmap_DrawOp, 0, slot); - void* dst = static_cast(fWriter.reserve(size)); - buffer.writeToMemory(dst); - return true; - } - return false; -} - -// return 0 for nullptr (or unflattenable obj), or index-base-1 -// return ~(index-base-1) if an old flattenable was replaced -int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) { - SkASSERT(!fDone && fBitmapHeap != nullptr); - if (nullptr == obj) { - return 0; - } - - fBitmapHeap->deferAddingOwners(); - bool added, replaced; - const SkFlatData* flat = fFlatDictionary.findAndReplace(*obj, fFlattenableHeap.flatToReplace(), - &added, &replaced); - fBitmapHeap->endAddingOwnersDeferral(added); - int index = flat->index(); - if (added) { - if (is_cross_process(fFlags)) { - this->flattenFactoryNames(); - } - size_t flatSize = flat->flatSize(); - if (this->needOpBytes(flatSize)) { - this->writeOp(kDef_Flattenable_DrawOp, paintflat, index); - fWriter.write(flat->data(), flatSize); - } - } - if (replaced) { - index = ~index; - } - return index; -} - -/////////////////////////////////////////////////////////////////////////////// - -#define MIN_BLOCK_SIZE (16 * 1024) -#define BITMAPS_TO_KEEP 5 -#define FLATTENABLES_TO_KEEP 10 - -SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, - SkWriter32* writer, - uint32_t flags, - uint32_t width, - uint32_t height) - : SkCanvas(width, height) - , fFactorySet(is_cross_process(flags) ? new SkNamedFactorySet : nullptr) - , fWriter(*writer) - , fFlags(flags) - , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, is_cross_process(flags)) - , fFlatDictionary(&fFlattenableHeap) { - fController = controller; - fDone = false; - fBlockSize = 0; // need first block from controller - fBytesNotified = 0; - sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex)); - - // Tell the reader the appropriate flags to use. - if (this->needOpBytes()) { - this->writeOp(kReportFlags_DrawOp, fFlags, 0); - } - - if (shouldFlattenBitmaps(flags)) { - fBitmapShuttle.reset(new BitmapShuttle(this)); - fBitmapHeap = new SkBitmapHeap(fBitmapShuttle.get(), BITMAPS_TO_KEEP); - } else { - fBitmapHeap = new SkBitmapHeap(BITMAPS_TO_KEEP, controller->numberOfReaders()); - if (this->needOpBytes(sizeof(void*))) { - this->writeOp(kShareBitmapHeap_DrawOp); - fWriter.writePtr(static_cast(fBitmapHeap)); - } - } - fFlattenableHeap.setBitmapStorage(fBitmapHeap); - - fImageHeap = new SkImageHeap; - if (this->needOpBytes(sizeof(void*))) { - this->writeOp(kShareImageHeap_DrawOp); - fWriter.writePtr(static_cast(fImageHeap)); - } - - this->doNotify(); -} - -SkGPipeCanvas::~SkGPipeCanvas() { - this->finish(true); - SkSafeUnref(fFactorySet); - SkSafeUnref(fBitmapHeap); - SkSafeUnref(fImageHeap); -} - -bool SkGPipeCanvas::needOpBytes(size_t needed) { - if (fDone) { - return false; - } - - needed += 4; // size of DrawOp atom - needed = SkAlign4(needed); - if (fWriter.bytesWritten() + needed > fBlockSize) { - // Before we wipe out any data that has already been written, read it out. - this->doNotify(); - - // If we're going to allocate a new block, allocate enough to make it worthwhile. - needed = SkTMax(MIN_BLOCK_SIZE, needed); - - void* block = fController->requestBlock(needed, &fBlockSize); - if (nullptr == block) { - // Do not notify the readers, which would call this function again. - this->finish(false); - return false; - } - SkASSERT(SkIsAlign4(fBlockSize)); - fWriter.reset(block, fBlockSize); - fBytesNotified = 0; - } - return true; -} - -uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) { - uint32_t id = 0; // 0 means default/null typeface - if (face) { - id = fTypefaceSet.find(face); - if (0 == id) { - id = fTypefaceSet.add(face); - size_t size = writeTypeface(nullptr, face); - if (this->needOpBytes(size)) { - this->writeOp(kDef_Typeface_DrawOp); - writeTypeface(&fWriter, face); - } - } - } - return id; -} - -/////////////////////////////////////////////////////////////////////////////// - -#define NOTIFY_SETUP(canvas) \ - AutoPipeNotify apn(canvas) - -void SkGPipeCanvas::willSave() { - NOTIFY_SETUP(this); - if (this->needOpBytes()) { - this->writeOp(kSave_DrawOp); - } - - this->INHERITED::willSave(); -} - -SkCanvas::SaveLayerStrategy SkGPipeCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, - SaveFlags saveFlags) { - NOTIFY_SETUP(this); - size_t size = 0; - unsigned opFlags = 0; - - if (bounds) { - opFlags |= kSaveLayer_HasBounds_DrawOpFlag; - size += sizeof(SkRect); - } - if (paint) { - opFlags |= kSaveLayer_HasPaint_DrawOpFlag; - this->writePaint(*paint); - } - - if (this->needOpBytes(size)) { - this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags); - if (bounds) { - fWriter.writeRect(*bounds); - } - } - - this->INHERITED::willSaveLayer(bounds, paint, saveFlags); - // we don't create a layer - return kNoLayer_SaveLayerStrategy; -} - -void SkGPipeCanvas::willRestore() { - NOTIFY_SETUP(this); - if (this->needOpBytes()) { - this->writeOp(kRestore_DrawOp); - } - - this->INHERITED::willRestore(); -} - -void SkGPipeCanvas::recordTranslate(const SkMatrix& m) { - if (this->needOpBytes(2 * sizeof(SkScalar))) { - this->writeOp(kTranslate_DrawOp); - fWriter.writeScalar(m.getTranslateX()); - fWriter.writeScalar(m.getTranslateY()); - } -} - -void SkGPipeCanvas::recordScale(const SkMatrix& m) { - if (this->needOpBytes(2 * sizeof(SkScalar))) { - this->writeOp(kScale_DrawOp); - fWriter.writeScalar(m.getScaleX()); - fWriter.writeScalar(m.getScaleY()); - } -} - -void SkGPipeCanvas::recordConcat(const SkMatrix& m) { - if (this->needOpBytes(m.writeToMemory(nullptr))) { - this->writeOp(kConcat_DrawOp); - fWriter.writeMatrix(m); - } -} - -void SkGPipeCanvas::didConcat(const SkMatrix& matrix) { - if (!matrix.isIdentity()) { - NOTIFY_SETUP(this); - switch (matrix.getType()) { - case SkMatrix::kTranslate_Mask: - this->recordTranslate(matrix); - break; - case SkMatrix::kScale_Mask: - this->recordScale(matrix); - break; - default: - this->recordConcat(matrix); - break; - } - } - - this->INHERITED::didConcat(matrix); -} - -void SkGPipeCanvas::didSetMatrix(const SkMatrix& matrix) { - NOTIFY_SETUP(this); - if (this->needOpBytes(matrix.writeToMemory(nullptr))) { - this->writeOp(kSetMatrix_DrawOp); - fWriter.writeMatrix(matrix); - } - this->INHERITED::didSetMatrix(matrix); -} - -void SkGPipeCanvas::onClipRect(const SkRect& rect, SkRegion::Op rgnOp, - ClipEdgeStyle edgeStyle) { - NOTIFY_SETUP(this); - if (this->needOpBytes(sizeof(SkRect))) { - unsigned flags = 0; - if (kSoft_ClipEdgeStyle == edgeStyle) { - flags = kClip_HasAntiAlias_DrawOpFlag; - } - this->writeOp(kClipRect_DrawOp, flags, rgnOp); - fWriter.writeRect(rect); - } - this->INHERITED::onClipRect(rect, rgnOp, edgeStyle); -} - -void SkGPipeCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op rgnOp, - ClipEdgeStyle edgeStyle) { - NOTIFY_SETUP(this); - if (this->needOpBytes(kSizeOfFlatRRect)) { - unsigned flags = 0; - if (kSoft_ClipEdgeStyle == edgeStyle) { - flags = kClip_HasAntiAlias_DrawOpFlag; - } - this->writeOp(kClipRRect_DrawOp, flags, rgnOp); - fWriter.writeRRect(rrect); - } - this->INHERITED::onClipRRect(rrect, rgnOp, edgeStyle); -} - -void SkGPipeCanvas::onClipPath(const SkPath& path, SkRegion::Op rgnOp, - ClipEdgeStyle edgeStyle) { - NOTIFY_SETUP(this); - if (this->needOpBytes(path.writeToMemory(nullptr))) { - unsigned flags = 0; - if (kSoft_ClipEdgeStyle == edgeStyle) { - flags = kClip_HasAntiAlias_DrawOpFlag; - } - this->writeOp(kClipPath_DrawOp, flags, rgnOp); - fWriter.writePath(path); - } - // we just pass on the bounds of the path - this->INHERITED::onClipRect(path.getBounds(), rgnOp, edgeStyle); -} - -void SkGPipeCanvas::onClipRegion(const SkRegion& region, SkRegion::Op rgnOp) { - NOTIFY_SETUP(this); - if (this->needOpBytes(region.writeToMemory(nullptr))) { - this->writeOp(kClipRegion_DrawOp, 0, rgnOp); - fWriter.writeRegion(region); - } - this->INHERITED::onClipRegion(region, rgnOp); -} - -/////////////////////////////////////////////////////////////////////////////// - -void SkGPipeCanvas::onDrawPaint(const SkPaint& paint) { - NOTIFY_SETUP(this); - this->writePaint(paint); - if (this->needOpBytes()) { - this->writeOp(kDrawPaint_DrawOp); - } -} - -void SkGPipeCanvas::onDrawPoints(PointMode mode, size_t count, - const SkPoint pts[], const SkPaint& paint) { - if (count) { - NOTIFY_SETUP(this); - this->writePaint(paint); - if (this->needOpBytes(4 + count * sizeof(SkPoint))) { - this->writeOp(kDrawPoints_DrawOp, mode, 0); - fWriter.write32(SkToU32(count)); - fWriter.write(pts, count * sizeof(SkPoint)); - } - } -} - -void SkGPipeCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) { - NOTIFY_SETUP(this); - this->writePaint(paint); - if (this->needOpBytes(sizeof(SkRect))) { - this->writeOp(kDrawOval_DrawOp); - fWriter.writeRect(rect); - } -} - -void SkGPipeCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { - NOTIFY_SETUP(this); - this->writePaint(paint); - if (this->needOpBytes(sizeof(SkRect))) { - this->writeOp(kDrawRect_DrawOp); - fWriter.writeRect(rect); - } -} - -void SkGPipeCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { - NOTIFY_SETUP(this); - this->writePaint(paint); - if (this->needOpBytes(kSizeOfFlatRRect)) { - this->writeOp(kDrawRRect_DrawOp); - fWriter.writeRRect(rrect); - } -} - -void SkGPipeCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, - const SkPaint& paint) { - NOTIFY_SETUP(this); - this->writePaint(paint); - if (this->needOpBytes(kSizeOfFlatRRect * 2)) { - this->writeOp(kDrawDRRect_DrawOp); - fWriter.writeRRect(outer); - fWriter.writeRRect(inner); - } -} - -void SkGPipeCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { - NOTIFY_SETUP(this); - this->writePaint(paint); - if (this->needOpBytes(path.writeToMemory(nullptr))) { - this->writeOp(kDrawPath_DrawOp); - fWriter.writePath(path); - } -} - -bool SkGPipeCanvas::commonDrawBitmap(const SkBitmap& bm, DrawOps op, - unsigned flags, - size_t opBytesNeeded, - const SkPaint* paint) { - if (fDone) { - return false; - } - - if (paint != nullptr) { - flags |= kDrawBitmap_HasPaint_DrawOpFlag; - this->writePaint(*paint); - } - // This needs to run first so its calls to needOpBytes() and its writes - // don't interlace with the needOpBytes() and write below. - SkASSERT(fBitmapHeap != nullptr); - int32_t bitmapIndex = fBitmapHeap->insert(bm); - if (SkBitmapHeap::INVALID_SLOT == bitmapIndex) { - return false; - } - - if (this->needOpBytes(opBytesNeeded)) { - this->writeOp(op, flags, bitmapIndex); - return true; - } - return false; -} - -void SkGPipeCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top, - const SkPaint* paint) { - NOTIFY_SETUP(this); - size_t opBytesNeeded = sizeof(SkScalar) * 2; - - if (this->commonDrawBitmap(bm, kDrawBitmap_DrawOp, 0, opBytesNeeded, paint)) { - fWriter.writeScalar(left); - fWriter.writeScalar(top); - } -} - -void SkGPipeCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst, - const SkPaint* paint, SrcRectConstraint constraint) { - NOTIFY_SETUP(this); - size_t opBytesNeeded = sizeof(SkRect); - bool hasSrc = src != nullptr; - unsigned flags; - if (hasSrc) { - flags = kDrawBitmap_HasSrcRect_DrawOpFlag; - opBytesNeeded += sizeof(int32_t) * 4; - } else { - flags = 0; - } - if (kFast_SrcRectConstraint == constraint) { - flags |= kDrawBitmap_Bleed_DrawOpFlag; - } - - if (this->commonDrawBitmap(bm, kDrawBitmapRect_DrawOp, flags, opBytesNeeded, paint)) { - if (hasSrc) { - fWriter.writeRect(*src); - } - fWriter.writeRect(dst); - } -} - -void SkGPipeCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, - const SkRect& dst, const SkPaint* paint) { - NOTIFY_SETUP(this); - size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(SkRect); - - if (this->commonDrawBitmap(bm, kDrawBitmapNine_DrawOp, 0, opBytesNeeded, paint)) { - fWriter.write32(center.fLeft); - fWriter.write32(center.fTop); - fWriter.write32(center.fRight); - fWriter.write32(center.fBottom); - fWriter.writeRect(dst); - } -} - -void SkGPipeCanvas::onDrawSprite(const SkBitmap& bm, int left, int top, const SkPaint* paint) { - NOTIFY_SETUP(this); - size_t opBytesNeeded = sizeof(int32_t) * 2; - - if (this->commonDrawBitmap(bm, kDrawSprite_DrawOp, 0, opBytesNeeded, paint)) { - fWriter.write32(left); - fWriter.write32(top); - } -} - -bool SkGPipeCanvas::commonDrawImage(const SkImage* image, DrawOps op, unsigned flags, - size_t opBytesNeeded, const SkPaint* paint) { - if (fDone) { - return false; - } - - if (paint != nullptr) { - flags |= kDrawBitmap_HasPaint_DrawOpFlag; - this->writePaint(*paint); - } - // This needs to run first so its calls to needOpBytes() and its writes - // don't interlace with the needOpBytes() and write below. - int32_t slot = fImageHeap->insert(image); - SkASSERT(slot != 0); - if (this->needOpBytes(opBytesNeeded)) { - this->writeOp(op, flags, slot); - return true; - } - return false; -} - -void SkGPipeCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, - const SkPaint* paint) { - NOTIFY_SETUP(this); - if (this->commonDrawImage(image, kDrawImage_DrawOp, 0, sizeof(SkScalar) * 2, paint)) { - fWriter.writeScalar(x); - fWriter.writeScalar(y); - } -} - -void SkGPipeCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, - const SkPaint* paint, SrcRectConstraint constraint) { - NOTIFY_SETUP(this); - unsigned flags = 0; - size_t opBytesNeeded = sizeof(SkRect); // dst - if (src) { - flags |= kDrawBitmap_HasSrcRect_DrawOpFlag; - opBytesNeeded += sizeof(SkRect); // src - } - if (this->commonDrawImage(image, kDrawImageRect_DrawOp, flags, opBytesNeeded, paint)) { - if (src) { - fWriter.writeRect(*src); - } - fWriter.writeRect(dst); - fWriter.writeInt(constraint); - } -} - -void SkGPipeCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, - const SkPaint* paint) { - NOTIFY_SETUP(this); - size_t opBytesNeeded = sizeof(SkIRect) + sizeof(SkRect); // center + dst - if (this->commonDrawImage(image, kDrawImageNine_DrawOp, 0, opBytesNeeded, paint)) { - fWriter.writeIRect(center); - fWriter.writeRect(dst); - } -} - -void SkGPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, - const SkPaint& paint) { - if (byteLength) { - NOTIFY_SETUP(this); - this->writePaint(paint); - if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) { - this->writeOp(kDrawText_DrawOp); - fWriter.write32(SkToU32(byteLength)); - fWriter.writePad(text, byteLength); - fWriter.writeScalar(x); - fWriter.writeScalar(y); - } - } -} - -void SkGPipeCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], - const SkPaint& paint) { - if (byteLength) { - NOTIFY_SETUP(this); - this->writePaint(paint); - int count = paint.textToGlyphs(text, byteLength, nullptr); - if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) { - this->writeOp(kDrawPosText_DrawOp); - fWriter.write32(SkToU32(byteLength)); - fWriter.writePad(text, byteLength); - fWriter.write32(count); - fWriter.write(pos, count * sizeof(SkPoint)); - } - } -} - -void SkGPipeCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], - SkScalar constY, const SkPaint& paint) { - if (byteLength) { - NOTIFY_SETUP(this); - this->writePaint(paint); - int count = paint.textToGlyphs(text, byteLength, nullptr); - if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) { - this->writeOp(kDrawPosTextH_DrawOp); - fWriter.write32(SkToU32(byteLength)); - fWriter.writePad(text, byteLength); - fWriter.write32(count); - fWriter.write(xpos, count * sizeof(SkScalar)); - fWriter.writeScalar(constY); - } - } -} - -void SkGPipeCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, - const SkMatrix* matrix, const SkPaint& paint) { - if (byteLength) { - NOTIFY_SETUP(this); - unsigned flags = 0; - size_t size = 4 + SkAlign4(byteLength) + path.writeToMemory(nullptr); - if (matrix) { - flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag; - size += matrix->writeToMemory(nullptr); - } - this->writePaint(paint); - if (this->needOpBytes(size)) { - this->writeOp(kDrawTextOnPath_DrawOp, flags, 0); - - fWriter.write32(SkToU32(byteLength)); - fWriter.writePad(text, byteLength); - - fWriter.writePath(path); - if (matrix) { - fWriter.writeMatrix(*matrix); - } - } - } -} - -size_t SkGPipeCanvas::getInProcessTypefaces(const SkRefCntSet& typefaceSet, - TypefaceBuffer* buffer) { - // When in-process, we simply write out the typeface pointers. - size_t size = typefaceSet.count() * sizeof(SkTypeface*); - buffer->reset(size); - typefaceSet.copyToArray(reinterpret_cast(buffer->get())); - - return size; -} - -size_t SkGPipeCanvas::getCrossProcessTypefaces(const SkRefCntSet& typefaceSet, - TypefaceBuffer* buffer) { - // For cross-process we use typeface IDs. - size_t size = typefaceSet.count() * sizeof(uint32_t); - buffer->reset(size); - - uint32_t* idBuffer = reinterpret_cast(buffer->get()); - SkRefCntSet::Iter iter(typefaceSet); - int i = 0; - - for (void* setPtr = iter.next(); setPtr; setPtr = iter.next()) { - idBuffer[i++] = this->getTypefaceID(reinterpret_cast(setPtr)); - } - - SkASSERT(i == typefaceSet.count()); - - return size; -} - -void SkGPipeCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, - const SkPaint& paint) { - NOTIFY_SETUP(this); - this->writePaint(paint); - - // FIXME: this is inefficient but avoids duplicating the blob serialization logic. - SkRefCntSet typefaceSet; - SkWriteBuffer blobBuffer; - blobBuffer.setTypefaceRecorder(&typefaceSet); - blob->flatten(blobBuffer); - - // Unlike most draw ops (which only use one paint/typeface), text blobs may reference - // an arbitrary number of typefaces. Since the one-paint-per-op model is not applicable, - // we need to serialize these explicitly. - TypefaceBuffer typefaceBuffer; - size_t typefaceSize = is_cross_process(fFlags) - ? this->getCrossProcessTypefaces(typefaceSet, &typefaceBuffer) - : this->getInProcessTypefaces(typefaceSet, &typefaceBuffer); - - // blob byte count + typeface count + x + y + blob data + an index (cross-process) - // or pointer (in-process) for each typeface - size_t size = 2 * sizeof(uint32_t) - + 2 * sizeof(SkScalar) - + blobBuffer.bytesWritten() - + typefaceSize; - - if (this->needOpBytes(size)) { - this->writeOp(kDrawTextBlob_DrawOp); - SkDEBUGCODE(size_t initialOffset = fWriter.bytesWritten();) - - fWriter.writeScalar(x); - fWriter.writeScalar(y); - - fWriter.write32(typefaceSet.count()); - fWriter.write(typefaceBuffer.get(), typefaceSize); - - fWriter.write32(SkToU32(blobBuffer.bytesWritten())); - uint32_t* pad = fWriter.reservePad(blobBuffer.bytesWritten()); - blobBuffer.writeToMemory(pad); - - SkASSERT(initialOffset + size == fWriter.bytesWritten()); - } -} - -void SkGPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, - const SkPaint* paint) { - // we want to playback the picture into individual draw calls - // - // todo: do we always have to unroll? If the pipe is not cross-process, seems like - // we could just ref the picture and move on...? - // - this->INHERITED::onDrawPicture(picture, matrix, paint); -} - -void SkGPipeCanvas::onDrawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xfer, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { - if (0 == vertexCount) { - return; - } - - NOTIFY_SETUP(this); - this->writePaint(paint); - - unsigned flags = 0; // packs with the op, so needs no extra space - - size_t size = 0; - size += 4; // vmode - size += 4; // vertex count - size += vertexCount * sizeof(SkPoint); // vertices - - if (texs) { - flags |= kDrawVertices_HasTexs_DrawOpFlag; - size += vertexCount * sizeof(SkPoint); - } - if (colors) { - flags |= kDrawVertices_HasColors_DrawOpFlag; - size += vertexCount * sizeof(SkColor); - } - if (xfer && !SkXfermode::IsMode(xfer, SkXfermode::kModulate_Mode)) { - flags |= kDrawVertices_HasXfermode_DrawOpFlag; - size += sizeof(int32_t); // SkXfermode::Mode - } - if (indices && indexCount > 0) { - flags |= kDrawVertices_HasIndices_DrawOpFlag; - size += 4; // index count - size += SkAlign4(indexCount * sizeof(uint16_t)); // indices - } - - if (this->needOpBytes(size)) { - this->writeOp(kDrawVertices_DrawOp, flags, 0); - fWriter.write32(vmode); - fWriter.write32(vertexCount); - fWriter.write(vertices, vertexCount * sizeof(SkPoint)); - if (flags & kDrawVertices_HasTexs_DrawOpFlag) { - fWriter.write(texs, vertexCount * sizeof(SkPoint)); - } - if (flags & kDrawVertices_HasColors_DrawOpFlag) { - fWriter.write(colors, vertexCount * sizeof(SkColor)); - } - if (flags & kDrawVertices_HasXfermode_DrawOpFlag) { - SkXfermode::Mode mode = SkXfermode::kModulate_Mode; - SkAssertResult(xfer->asMode(&mode)); - fWriter.write32(mode); - } - if (flags & kDrawVertices_HasIndices_DrawOpFlag) { - fWriter.write32(indexCount); - fWriter.writePad(indices, indexCount * sizeof(uint16_t)); - } - } -} - -void SkGPipeCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], - const SkColor colors[], int count, SkXfermode::Mode mode, - const SkRect* cull, const SkPaint* paint) { - NOTIFY_SETUP(this); - unsigned flags = 0; // packs with the op, so needs no extra space - - if (paint) { - flags |= kDrawAtlas_HasPaint_DrawOpFlag; - this->writePaint(*paint); - } - - size_t size = 4; // image-slot - size += 4; // count - size += 4; // mode - size += count * sizeof(SkRSXform); // xform - size += count * sizeof(SkRect); // tex - if (colors) { - flags |= kDrawAtlas_HasColors_DrawOpFlag; - size += count * sizeof(SkColor); // colors - } - if (cull) { - flags |= kDrawAtlas_HasCull_DrawOpFlag; - size += sizeof(SkRect); // cull - } - - if (this->needOpBytes(size)) { - this->writeOp(kDrawAtlas_DrawOp, flags, 0); - int32_t slot = fImageHeap->insert(atlas); - fWriter.write32(slot); - fWriter.write32(count); - fWriter.write32(mode); - fWriter.write(xform, count * sizeof(SkRSXform)); - fWriter.write(tex, count * sizeof(SkRect)); - if (colors) { - fWriter.write(colors, count * sizeof(SkColor)); - } - if (cull) { - fWriter.writeRect(*cull); - } - } -} - -void SkGPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, - const SkPaint& paint) { - NOTIFY_SETUP(this); - - size_t size = SkPatchUtils::kNumCtrlPts * sizeof(SkPoint); - unsigned flags = 0; - if (colors) { - flags |= kDrawVertices_HasColors_DrawOpFlag; - size += SkPatchUtils::kNumCorners * sizeof(SkColor); - } - if (texCoords) { - flags |= kDrawVertices_HasTexs_DrawOpFlag; - size += SkPatchUtils::kNumCorners * sizeof(SkPoint); - } - if (xmode) { - SkXfermode::Mode mode; - if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) { - flags |= kDrawVertices_HasXfermode_DrawOpFlag; - size += sizeof(int32_t); - } - } - - this->writePaint(paint); - if (this->needOpBytes(size)) { - this->writeOp(kDrawPatch_DrawOp, flags, 0); - - fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint)); - - if (colors) { - fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor)); - } - - if (texCoords) { - fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint)); - } - - if (flags & kDrawVertices_HasXfermode_DrawOpFlag) { - SkXfermode::Mode mode = SkXfermode::kModulate_Mode; - SkAssertResult(xmode->asMode(&mode)); - fWriter.write32(mode); - } - } -} - -void SkGPipeCanvas::flushRecording(bool detachCurrentBlock) { - this->doNotify(); - if (detachCurrentBlock) { - // force a new block to be requested for the next recorded command - fBlockSize = 0; - } -} - -void SkGPipeCanvas::resetImageHeap() { - if (fImageHeap) { - fImageHeap->reset(); - } -} - -size_t SkGPipeCanvas::freeMemoryIfPossible(size_t bytesToFree) { - return (nullptr == fBitmapHeap) ? 0 : fBitmapHeap->freeMemoryIfPossible(bytesToFree); -} - -/////////////////////////////////////////////////////////////////////////////// - -template uint32_t castToU32(T value) { - union { - T fSrc; - uint32_t fDst; - } data; - data.fSrc = value; - return data.fDst; -} - -void SkGPipeCanvas::writePaint(const SkPaint& paint) { - if (fDone) { - return; - } - SkPaint& base = fPaint; - uint32_t storage[32]; - uint32_t* ptr = storage; - - if (base.getFlags() != paint.getFlags()) { - *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags()); - base.setFlags(paint.getFlags()); - } - if (base.getColor() != paint.getColor()) { - *ptr++ = PaintOp_packOp(kColor_PaintOp); - *ptr++ = paint.getColor(); - base.setColor(paint.getColor()); - } - if (base.getFilterQuality() != paint.getFilterQuality()) { - *ptr++ = PaintOp_packOpData(kFilterLevel_PaintOp, paint.getFilterQuality()); - base.setFilterQuality(paint.getFilterQuality()); - } - if (base.getStyle() != paint.getStyle()) { - *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle()); - base.setStyle(paint.getStyle()); - } - if (base.getStrokeJoin() != paint.getStrokeJoin()) { - *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin()); - base.setStrokeJoin(paint.getStrokeJoin()); - } - if (base.getStrokeCap() != paint.getStrokeCap()) { - *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap()); - base.setStrokeCap(paint.getStrokeCap()); - } - if (base.getStrokeWidth() != paint.getStrokeWidth()) { - *ptr++ = PaintOp_packOp(kWidth_PaintOp); - *ptr++ = castToU32(paint.getStrokeWidth()); - base.setStrokeWidth(paint.getStrokeWidth()); - } - if (base.getStrokeMiter() != paint.getStrokeMiter()) { - *ptr++ = PaintOp_packOp(kMiter_PaintOp); - *ptr++ = castToU32(paint.getStrokeMiter()); - base.setStrokeMiter(paint.getStrokeMiter()); - } - if (base.getTextEncoding() != paint.getTextEncoding()) { - *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding()); - base.setTextEncoding(paint.getTextEncoding()); - } - if (base.getHinting() != paint.getHinting()) { - *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting()); - base.setHinting(paint.getHinting()); - } - if (base.getTextAlign() != paint.getTextAlign()) { - *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign()); - base.setTextAlign(paint.getTextAlign()); - } - if (base.getTextSize() != paint.getTextSize()) { - *ptr++ = PaintOp_packOp(kTextSize_PaintOp); - *ptr++ = castToU32(paint.getTextSize()); - base.setTextSize(paint.getTextSize()); - } - if (base.getTextScaleX() != paint.getTextScaleX()) { - *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp); - *ptr++ = castToU32(paint.getTextScaleX()); - base.setTextScaleX(paint.getTextScaleX()); - } - if (base.getTextSkewX() != paint.getTextSkewX()) { - *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp); - *ptr++ = castToU32(paint.getTextSkewX()); - base.setTextSkewX(paint.getTextSkewX()); - } - - if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) { - if (is_cross_process(fFlags)) { - uint32_t id = this->getTypefaceID(paint.getTypeface()); - *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id); - } else if (this->needOpBytes(sizeof(void*))) { - // Add to the set for ref counting. - fTypefaceSet.add(paint.getTypeface()); - // It is safe to write the typeface to the stream before the rest - // of the paint unless we ever send a kReset_PaintOp, which we - // currently never do. - this->writeOp(kSetTypeface_DrawOp); - fWriter.writePtr(paint.getTypeface()); - } - base.setTypeface(paint.getTypeface()); - } - - // This is a new paint, so all old flats can be safely purged, if necessary. - fFlattenableHeap.markAllFlatsSafeToDelete(); - for (int i = 0; i < kCount_PaintFlats; i++) { - int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i); - bool replaced = index < 0; - if (replaced) { - index = ~index; - } - // Store the index of any flat that needs to be kept. 0 means no flat. - if (index > 0) { - fFlattenableHeap.markFlatForKeeping(index); - } - SkASSERT(index >= 0 && index <= fFlatDictionary.count()); - if (index != fCurrFlatIndex[i] || replaced) { - *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index); - fCurrFlatIndex[i] = index; - } - } - - size_t size = (char*)ptr - (char*)storage; - if (size && this->needOpBytes(size)) { - this->writeOp(kPaintOp_DrawOp, 0, SkToU32(size)); - fWriter.write(storage, size); - for (size_t i = 0; i < size/4; i++) { -// SkDebugf("[%d] %08X\n", i, storage[i]); - } - } - - // - // Do these after we've written kPaintOp_DrawOp - - if (base.getAnnotation() != paint.getAnnotation()) { - if (nullptr == paint.getAnnotation()) { - if (this->needOpBytes()) { - this->writeOp(kSetAnnotation_DrawOp, 0, 0); - } - } else { - SkWriteBuffer buffer; - paint.getAnnotation()->writeToBuffer(buffer); - const size_t size = buffer.bytesWritten(); - if (this->needOpBytes(size)) { - this->writeOp(kSetAnnotation_DrawOp, 0, SkToU32(size)); - buffer.writeToMemory(fWriter.reserve(size)); - } - } - base.setAnnotation(paint.getAnnotation()); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkGPipe.h" - -SkGPipeController::~SkGPipeController() { - SkSafeUnref(fCanvas); -} - -void SkGPipeController::setCanvas(SkGPipeCanvas* canvas) { - SkRefCnt_SafeAssign(fCanvas, canvas); -} - -void SkGPipeController::purgeCaches() -{ - fCanvas->resetImageHeap(); - // Other caches are self-purging with a small MRU pool - // We could purge them as well, but it is not clear whether - // that would be a win. -} - -/////////////////////////////////////////////////////////////////////////////// - -SkGPipeWriter::SkGPipeWriter() -: fWriter(0) { - fCanvas = nullptr; -} - -SkGPipeWriter::~SkGPipeWriter() { - this->endRecording(); -} - -SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags, - uint32_t width, uint32_t height) { - if (nullptr == fCanvas) { - fWriter.reset(nullptr, 0); - fCanvas = new SkGPipeCanvas(controller, &fWriter, flags, width, height); - } - controller->setCanvas(fCanvas); - return fCanvas; -} - -void SkGPipeWriter::endRecording() { - if (fCanvas) { - fCanvas->finish(true); - fCanvas->unref(); - fCanvas = nullptr; - } -} - -void SkGPipeWriter::flushRecording(bool detachCurrentBlock) { - if (fCanvas) { - fCanvas->flushRecording(detachCurrentBlock); - } -} - -size_t SkGPipeWriter::freeMemoryIfPossible(size_t bytesToFree) { - if (fCanvas) { - return fCanvas->freeMemoryIfPossible(bytesToFree); - } - return 0; -} - -size_t SkGPipeWriter::storageAllocatedForRecording() const { - return nullptr == fCanvas ? 0 : fCanvas->storageAllocatedForRecording(); -} - -/////////////////////////////////////////////////////////////////////////////// - -BitmapShuttle::BitmapShuttle(SkGPipeCanvas* canvas) { - SkASSERT(canvas != nullptr); - fCanvas = canvas; - fCanvas->ref(); -} - -BitmapShuttle::~BitmapShuttle() { - this->removeCanvas(); -} - -bool BitmapShuttle::insert(const SkBitmap& bitmap, int32_t slot) { - SkASSERT(fCanvas != nullptr); - return fCanvas->shuttleBitmap(bitmap, slot); -} - -void BitmapShuttle::removeCanvas() { - if (nullptr == fCanvas) { - return; - } - fCanvas->unref(); - fCanvas = nullptr; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -SkImageHeap::SkImageHeap() : fBytesInCache (0) {} - -SkImageHeap::~SkImageHeap() { - fArray.unrefAll(); -} - -void SkImageHeap::reset() { - fArray.unrefAll(); - fArray.rewind(); - fBytesInCache = 0; -} - -const SkImage* SkImageHeap::get(int32_t slot) const { - SkASSERT(slot > 0); - return fArray[slot - 1]; -} - -int32_t SkImageHeap::find(const SkImage* img) const { - int index = fArray.find(img); - if (index >= 0) { - return index + 1; // found - } - return 0; // not found -} - -int32_t SkImageHeap::insert(const SkImage* img) { - int32_t slot = this->find(img); - if (slot) { - return slot; - } - // TODO: SkImage does not expose bytes per pixel, 4 is just a best guess. - fBytesInCache += img->width() * img->height() * 4; - *fArray.append() = SkRef(img); - return fArray.count(); // slot is always index+1 -} - diff --git a/gfx/skia/skia/src/pipe/utils/SamplePipeControllers.cpp b/gfx/skia/skia/src/pipe/utils/SamplePipeControllers.cpp deleted file mode 100644 index fea9d6842b7..00000000000 --- a/gfx/skia/skia/src/pipe/utils/SamplePipeControllers.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SamplePipeControllers.h" - -#include "SkCanvas.h" -#include "SkGPipe.h" -#include "SkMatrix.h" - -PipeController::PipeController(SkCanvas* target, SkPicture::InstallPixelRefProc proc) -:fReader(target) { - fBlock = nullptr; - fBlockSize = fBytesWritten = 0; - fReader.setBitmapDecoder(proc); -} - -PipeController::~PipeController() { - sk_free(fBlock); -} - -void* PipeController::requestBlock(size_t minRequest, size_t *actual) { - sk_free(fBlock); - fBlockSize = minRequest; - fBlock = sk_malloc_throw(fBlockSize); - fBytesWritten = 0; - *actual = fBlockSize; - return fBlock; -} - -void PipeController::notifyWritten(size_t bytes) { - fStatus = fReader.playback(this->getData(), bytes); - SkASSERT(SkGPipeReader::kError_Status != fStatus); - fBytesWritten += bytes; -} - -//////////////////////////////////////////////////////////////////////////////// - -TiledPipeController::TiledPipeController(const SkBitmap& bitmap, - SkPicture::InstallPixelRefProc proc, - const SkMatrix* initial) -: INHERITED(nullptr, proc) { - int32_t top = 0; - int32_t bottom; - int32_t height = bitmap.height() / NumberOfTiles; - SkIRect rect; - for (int i = 0; i < NumberOfTiles; i++) { - bottom = i + 1 == NumberOfTiles ? bitmap.height() : top + height; - rect.setLTRB(0, top, bitmap.width(), bottom); - top = bottom; - - SkDEBUGCODE(bool extracted = )bitmap.extractSubset(&fBitmaps[i], rect); - SkASSERT(extracted); - SkCanvas* canvas = new SkCanvas(fBitmaps[i]); - if (initial != nullptr) { - canvas->setMatrix(*initial); - } - canvas->translate(SkIntToScalar(-rect.left()), - SkIntToScalar(-rect.top())); - if (0 == i) { - fReader.setCanvas(canvas); - } else { - fReaders[i - 1].setCanvas(canvas); - fReaders[i - 1].setBitmapDecoder(proc); - } - canvas->unref(); - } -} - -void TiledPipeController::notifyWritten(size_t bytes) { - for (int i = 0; i < NumberOfTiles - 1; i++) { - fReaders[i].playback(this->getData(), bytes); - } - this->INHERITED::notifyWritten(bytes); -} - -//////////////////////////////////////////////////////////////////////////////// - -ThreadSafePipeController::ThreadSafePipeController(int numberOfReaders) -: fAllocator(kMinBlockSize) -, fNumberOfReaders(numberOfReaders) { - fBlock = nullptr; - fBytesWritten = 0; -} - -void* ThreadSafePipeController::requestBlock(size_t minRequest, size_t *actual) { - if (fBlock) { - // Save the previous block for later - PipeBlock previousBloc(fBlock, fBytesWritten); - fBlockList.push(previousBloc); - } - int32_t blockSize = SkMax32(SkToS32(minRequest), kMinBlockSize); - fBlock = fAllocator.allocThrow(blockSize); - fBytesWritten = 0; - *actual = blockSize; - return fBlock; -} - -void ThreadSafePipeController::notifyWritten(size_t bytes) { - fBytesWritten += bytes; -} - -void ThreadSafePipeController::draw(SkCanvas* target) { - SkGPipeReader reader(target); - for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) { - reader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fBytes); - } - - if (fBlock) { - reader.playback(fBlock, fBytesWritten); - } -} diff --git a/gfx/skia/skia/src/pipe/utils/SamplePipeControllers.h b/gfx/skia/skia/src/pipe/utils/SamplePipeControllers.h deleted file mode 100644 index b3f057fa8c5..00000000000 --- a/gfx/skia/skia/src/pipe/utils/SamplePipeControllers.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBitmap.h" -#include "SkChunkAlloc.h" -#include "SkGPipe.h" -#include "SkPicture.h" -#include "SkTDArray.h" - -class SkCanvas; -class SkMatrix; - -class PipeController : public SkGPipeController { -public: - PipeController(SkCanvas* target, SkPicture::InstallPixelRefProc proc = nullptr); - virtual ~PipeController(); - void* requestBlock(size_t minRequest, size_t* actual) override; - void notifyWritten(size_t bytes) override; -protected: - const void* getData() { return (const char*) fBlock + fBytesWritten; } - SkGPipeReader fReader; -private: - void* fBlock; - size_t fBlockSize; - size_t fBytesWritten; - SkGPipeReader::Status fStatus; -}; - -//////////////////////////////////////////////////////////////////////////////// - -class TiledPipeController : public PipeController { -public: - TiledPipeController(const SkBitmap&, SkPicture::InstallPixelRefProc proc = nullptr, - const SkMatrix* initialMatrix = nullptr); - virtual ~TiledPipeController() {}; - void notifyWritten(size_t bytes) override; - int numberOfReaders() const override { return NumberOfTiles; } -private: - enum { - NumberOfTiles = 10 - }; - SkGPipeReader fReaders[NumberOfTiles - 1]; - SkBitmap fBitmaps[NumberOfTiles]; - typedef PipeController INHERITED; -}; - -//////////////////////////////////////////////////////////////////////////////// - -/** - * Borrowed (and modified) from SkDeferredCanvas.cpp::DeferredPipeController. - * Allows playing back from multiple threads, but does not do the threading itself. - */ -class ThreadSafePipeController : public SkGPipeController { -public: - ThreadSafePipeController(int numberOfReaders); - void* requestBlock(size_t minRequest, size_t* actual) override; - void notifyWritten(size_t bytes) override; - int numberOfReaders() const override { return fNumberOfReaders; } - - /** - * Play the stored drawing commands to the specified canvas. If SkGPipeWriter::startRecording - * used the flag SkGPipeWriter::kSimultaneousReaders_Flag, this can be called from different - * threads simultaneously. - */ - void draw(SkCanvas*); -private: - enum { - kMinBlockSize = 4096 - }; - struct PipeBlock { - PipeBlock(void* block, size_t bytes) { fBlock = block, fBytes = bytes; } - // Stream of draw commands written by the SkGPipeWriter. Allocated by fAllocator, which will - // handle freeing it. - void* fBlock; - // Number of bytes that were written to fBlock. - size_t fBytes; - }; - void* fBlock; - size_t fBytesWritten; - SkChunkAlloc fAllocator; - SkTDArray fBlockList; - int fNumberOfReaders; -}; diff --git a/gfx/skia/skia/src/ports/SkFontMgr_android_parser.cpp b/gfx/skia/skia/src/ports/SkFontMgr_android_parser.cpp index ba2296bffa6..1d1a3b7ddb6 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_android_parser.cpp +++ b/gfx/skia/skia/src/ports/SkFontMgr_android_parser.cpp @@ -12,6 +12,7 @@ #include "SkTDArray.h" #include "SkTSearch.h" #include "SkTemplates.h" +#include "SkTLogic.h" #include #include @@ -579,9 +580,6 @@ static const XML_Memory_Handling_Suite sk_XML_alloc = { sk_free }; -template struct remove_ptr {typedef T type;}; -template struct remove_ptr {typedef T type;}; - /** * This function parses the given filename and stores the results in the given * families array. Returns the version of the file, negative if the file does not exist. @@ -598,7 +596,7 @@ static int parse_config_file(const char* filename, SkTDArray& famil return -1; } - SkAutoTCallVProc::type, XML_ParserFree> parser( + SkAutoTCallVProc, XML_ParserFree> parser( XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr)); if (!parser) { SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "could not create XML parser\n"); @@ -665,11 +663,6 @@ static void append_fallback_font_families_for_locale(SkTDArray& fal const char* dir, const SkString& basePath) { -#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) - // The framework is beyond Android 4.2 and can therefore skip this function - return; -#endif - SkAutoTCallIProc fontDirectory(opendir(dir)); if (nullptr == fontDirectory) { return; diff --git a/gfx/skia/skia/src/ports/SkFontMgr_android_parser.h b/gfx/skia/skia/src/ports/SkFontMgr_android_parser.h index aca1573952d..b841bc6d189 100644 --- a/gfx/skia/skia/src/ports/SkFontMgr_android_parser.h +++ b/gfx/skia/skia/src/ports/SkFontMgr_android_parser.h @@ -211,7 +211,7 @@ template static bool parse_fixed(const char* s, T* value) { n = -n; frac = -frac; } - *value = (n << N) + frac; + *value = SkLeftShift(n, N) + frac; return true; } diff --git a/gfx/skia/skia/src/ports/SkGlobalInitialization_chromium.cpp b/gfx/skia/skia/src/ports/SkGlobalInitialization_chromium.cpp deleted file mode 100644 index 8ff43f78e8d..00000000000 --- a/gfx/skia/skia/src/ports/SkGlobalInitialization_chromium.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkTypes.h" - -#include "SkBitmapProcShader.h" -#include "SkMallocPixelRef.h" -#include "SkPathEffect.h" -#include "SkPixelRef.h" -#include "SkXfermode.h" - -#include "Sk1DPathEffect.h" -#include "Sk2DPathEffect.h" -#include "SkArithmeticMode.h" -#include "SkArcToPathEffect.h" -#include "SkBitmapSourceDeserializer.h" -#include "SkBlurDrawLooper.h" -#include "SkBlurImageFilter.h" -#include "SkBlurMaskFilter.h" -#include "SkColorCubeFilter.h" -#include "SkColorFilter.h" -#include "SkColorFilterImageFilter.h" -#include "SkColorMatrixFilter.h" -#include "SkColorShader.h" -#include "SkComposeImageFilter.h" -#include "SkComposeShader.h" -#include "SkCornerPathEffect.h" -#include "SkDashPathEffect.h" -#include "SkDiscretePathEffect.h" -#include "SkDisplacementMapEffect.h" -#include "SkDropShadowImageFilter.h" -#include "SkEmptyShader.h" -#include "SkEmbossMaskFilter.h" -#include "SkFlattenable.h" -#include "SkGradientShader.h" -#include "SkImageSource.h" -#include "SkLayerDrawLooper.h" -#include "SkLayerRasterizer.h" -#include "SkLerpXfermode.h" -#include "SkLightingImageFilter.h" -#include "SkLightingShader.h" -#include "SkLocalMatrixShader.h" -#include "SkLumaColorFilter.h" -#include "SkMagnifierImageFilter.h" -#include "SkMatrixConvolutionImageFilter.h" -#include "SkMergeImageFilter.h" -#include "SkModeColorFilter.h" -#include "SkMorphologyImageFilter.h" -#include "SkOffsetImageFilter.h" -#include "SkOnce.h" -#include "SkPerlinNoiseShader.h" -#include "SkPictureImageFilter.h" -#include "SkPictureShader.h" -#include "SkPixelXorXfermode.h" -#include "SkRectShaderImageFilter.h" -#include "SkTableColorFilter.h" -#include "SkTestImageFilters.h" -#include "SkTileImageFilter.h" -#include "SkMatrixImageFilter.h" -#include "SkXfermodeImageFilter.h" - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// -// Adding new classes to Init() below has security consequences in Chrome. -// -// In particular, it is important that we don't create code paths that -// deserialize untrusted data as SkImageFilters; SkImageFilters are sent from -// Chrome renderers (untrusted) to the main (trusted) process. -// -// If you add a new SkImageFilter here _or_ other effect that can be part of -// an SkImageFilter, it's a good idea to have chrome-security@google.com sign -// off on the CL, and at minimum extend SampleFilterFuzz.cpp to fuzz it. -// -// SkPictures are untrusted data. Please be extremely careful not to allow -// SkPictures created in a Chrome renderer to be deserialized in the main process. -// -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -class SkPrivateEffectInitializer { -public: - static void Init() { - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArcToPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBitmapProcShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBitmapSourceDeserializer) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurDrawLooper) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorCubeFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorMatrixFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposePathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkCornerPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDashPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDilateImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiscretePathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDisplacementMapEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDropShadowImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmbossMaskFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmptyShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkErodeImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageSource) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerDrawLooper) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerRasterizer) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLerpXfermode) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLocalMatrixShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLumaColorFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPath1DPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLine2DPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPath2DPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPictureImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPictureShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPixelXorXfermode) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRectShaderImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSumPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTileImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMatrixImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkXfermodeImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMagnifierImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMatrixConvolutionImageFilter) - - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkOffsetImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMergeImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorFilterImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDownSampleImageFilter) - - SkArithmeticMode::InitializeFlattenables(); - SkBlurMaskFilter::InitializeFlattenables(); - SkColorFilter::InitializeFlattenables(); - SkGradientShader::InitializeFlattenables(); - SkLightingImageFilter::InitializeFlattenables(); - SkLightingShader::InitializeFlattenables(); - SkTableColorFilter::InitializeFlattenables(); - SkXfermode::InitializeFlattenables(); - } -}; - -SK_DECLARE_STATIC_ONCE(once); -void SkFlattenable::InitializeFlattenablesIfNeeded() { - SkOnce(&once, SkPrivateEffectInitializer::Init); -} diff --git a/gfx/skia/skia/src/ports/SkGlobalInitialization_default.cpp b/gfx/skia/skia/src/ports/SkGlobalInitialization_default.cpp index 3038e25c5d4..9471f01c882 100644 --- a/gfx/skia/skia/src/ports/SkGlobalInitialization_default.cpp +++ b/gfx/skia/skia/src/ports/SkGlobalInitialization_default.cpp @@ -5,12 +5,9 @@ * found in the LICENSE file. */ -#include "SkBitmapProcShader.h" -#include "SkPathEffect.h" -#include "SkXfermode.h" - #include "Sk1DPathEffect.h" #include "Sk2DPathEffect.h" +#include "SkAlphaThresholdFilter.h" #include "SkArithmeticMode.h" #include "SkArcToPathEffect.h" #include "SkBitmapSourceDeserializer.h" @@ -18,20 +15,15 @@ #include "SkBlurImageFilter.h" #include "SkBlurMaskFilter.h" #include "SkColorCubeFilter.h" -#include "SkColorFilter.h" #include "SkColorFilterImageFilter.h" #include "SkColorMatrixFilter.h" -#include "SkColorShader.h" #include "SkComposeImageFilter.h" -#include "SkComposeShader.h" #include "SkCornerPathEffect.h" #include "SkDashPathEffect.h" #include "SkDiscretePathEffect.h" #include "SkDisplacementMapEffect.h" #include "SkDropShadowImageFilter.h" -#include "SkEmptyShader.h" #include "SkEmbossMaskFilter.h" -#include "SkFlattenable.h" #include "SkGradientShader.h" #include "SkImageSource.h" #include "SkLayerDrawLooper.h" @@ -39,88 +31,87 @@ #include "SkLerpXfermode.h" #include "SkLightingImageFilter.h" #include "SkLightingShader.h" -#include "SkLocalMatrixShader.h" #include "SkLumaColorFilter.h" #include "SkMagnifierImageFilter.h" #include "SkMatrixConvolutionImageFilter.h" #include "SkMergeImageFilter.h" -#include "SkModeColorFilter.h" #include "SkMorphologyImageFilter.h" #include "SkOffsetImageFilter.h" -#include "SkOnce.h" +#include "SkPaintImageFilter.h" #include "SkPerlinNoiseShader.h" #include "SkPictureImageFilter.h" -#include "SkPictureShader.h" #include "SkPixelXorXfermode.h" -#include "SkRectShaderImageFilter.h" #include "SkTableColorFilter.h" #include "SkTestImageFilters.h" #include "SkTileImageFilter.h" -#include "SkMatrixImageFilter.h" #include "SkXfermodeImageFilter.h" -class SkPrivateEffectInitializer { -public: - static void Init() { - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArcToPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBitmapProcShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBitmapSourceDeserializer) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurDrawLooper) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorCubeFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorMatrixFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposePathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkCornerPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDashPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDilateImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiscretePathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDisplacementMapEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDropShadowImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmbossMaskFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmptyShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkErodeImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageSource) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerDrawLooper) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerRasterizer) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLerpXfermode) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLocalMatrixShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLumaColorFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPath1DPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLine2DPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPath2DPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPictureImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPictureShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPixelXorXfermode) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRectShaderImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSumPathEffect) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTileImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMatrixImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkXfermodeImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMagnifierImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMatrixConvolutionImageFilter) +/* + * None of these are strictly "required" for Skia to operate. + * + * These are the bulk of our "effects" -- subclasses of various effects on SkPaint. + * + * Clients should feel free to dup this file and modify it as needed. This function "InitEffects" + * will automatically be called before any of skia's effects are asked to be deserialized. + */ +void SkFlattenable::PrivateInitializer::InitEffects() { + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBitmapSourceDeserializer) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkOffsetImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMergeImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorFilterImageFilter) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDownSampleImageFilter) + // MaskFilter + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmbossMaskFilter) + SkBlurMaskFilter::InitializeFlattenables(); - SkArithmeticMode::InitializeFlattenables(); - SkBlurMaskFilter::InitializeFlattenables(); - SkColorFilter::InitializeFlattenables(); - SkGradientShader::InitializeFlattenables(); - SkLightingImageFilter::InitializeFlattenables(); - SkLightingShader::InitializeFlattenables(); - SkTableColorFilter::InitializeFlattenables(); - SkXfermode::InitializeFlattenables(); - } -}; + // DrawLooper + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurDrawLooper) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerDrawLooper) -SK_DECLARE_STATIC_ONCE(once); -void SkFlattenable::InitializeFlattenablesIfNeeded() { - SkOnce(&once, SkPrivateEffectInitializer::Init); + // Rasterizer + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerRasterizer) + + // ColorFilter + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorCubeFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorMatrixFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLumaColorFilter) + SkAlphaThresholdFilter::InitializeFlattenables(); + SkArithmeticMode::InitializeFlattenables(); + SkTableColorFilter::InitializeFlattenables(); + + // Shader + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShader) + SkGradientShader::InitializeFlattenables(); + SkLightingShader::InitializeFlattenables(); + + // Xfermode + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLerpXfermode) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPixelXorXfermode) + + // PathEffect + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArcToPathEffect) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkCornerPathEffect) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDashPathEffect) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiscretePathEffect) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPath1DPathEffect) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLine2DPathEffect) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPath2DPathEffect) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSumPathEffect) + + // ImageFilter + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDilateImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDisplacementMapEffect) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDropShadowImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkErodeImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageSource) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPaintImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPictureImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTileImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkXfermodeImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMagnifierImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMatrixConvolutionImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkOffsetImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMergeImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorFilterImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDownSampleImageFilter) + SkLightingImageFilter::InitializeFlattenables(); } diff --git a/gfx/skia/skia/src/ports/SkImageDecoder_empty.cpp b/gfx/skia/skia/src/ports/SkImageDecoder_empty.cpp index 11c3db1afc5..f52dada73bc 100644 --- a/gfx/skia/skia/src/ports/SkImageDecoder_empty.cpp +++ b/gfx/skia/skia/src/ports/SkImageDecoder_empty.cpp @@ -11,6 +11,7 @@ #include "SkImageDecoder.h" #include "SkImageEncoder.h" #include "SkMovie.h" +#include "SkPixelSerializer.h" #include "SkStream.h" class SkColorTable; @@ -108,6 +109,10 @@ SkData* SkImageEncoder::EncodeData(const SkImageInfo&, const void* pixels, size_ return nullptr; } +SkData* SkImageEncoder::EncodeData(const SkPixmap&, Type, int) { + return nullptr; +} + bool SkImageEncoder::encodeStream(SkWStream*, const SkBitmap&, int) { return false; } @@ -119,4 +124,17 @@ SkData* SkImageEncoder::encodeData(const SkBitmap&, int) { bool SkImageEncoder::encodeFile(const char file[], const SkBitmap& bm, int quality) { return false; } + +namespace { +class ImageEncoderPixelSerializer final : public SkPixelSerializer { +protected: + bool onUseEncodedData(const void*, size_t) override { return true; } + SkData* onEncode(const SkPixmap&) override { return nullptr; } +}; +} // namespace + +SkPixelSerializer* SkImageEncoder::CreatePixelSerializer() { + return new ImageEncoderPixelSerializer; +} + ///////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/ports/SkImageGenerator_skia.cpp b/gfx/skia/skia/src/ports/SkImageGenerator_skia.cpp index afcd4b4a924..8dbad555dd1 100644 --- a/gfx/skia/skia/src/ports/SkImageGenerator_skia.cpp +++ b/gfx/skia/skia/src/ports/SkImageGenerator_skia.cpp @@ -43,7 +43,7 @@ public: {} protected: - SkData* onRefEncodedData() override { + SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) override { return SkRef(fData.get()); } bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, diff --git a/gfx/skia/skia/src/ports/SkOSEnvironment.cpp b/gfx/skia/skia/src/ports/SkOSEnvironment.cpp new file mode 100644 index 00000000000..cc7aa18cff7 --- /dev/null +++ b/gfx/skia/skia/src/ports/SkOSEnvironment.cpp @@ -0,0 +1,19 @@ + +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkOSEnvironment.h" +#include + +void sk_setenv(const char* key, const char* value) { +#ifdef SK_BUILD_FOR_WIN32 + _putenv_s(key, value); +#else + setenv(key, value, 1); +#endif +} + diff --git a/gfx/skia/skia/src/ports/SkOSEnvironment.h b/gfx/skia/skia/src/ports/SkOSEnvironment.h new file mode 100644 index 00000000000..fdbce7a826b --- /dev/null +++ b/gfx/skia/skia/src/ports/SkOSEnvironment.h @@ -0,0 +1,15 @@ + +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOSEnvironment_DEFINED +#define SkOSEnvironment_DEFINED + +void sk_setenv(const char* key, const char* value); + +#endif + diff --git a/gfx/skia/skia/src/ports/SkOSFile_stdio.cpp b/gfx/skia/skia/src/ports/SkOSFile_stdio.cpp index 3371bb7031b..ecd5a027fcd 100644 --- a/gfx/skia/skia/src/ports/SkOSFile_stdio.cpp +++ b/gfx/skia/skia/src/ports/SkOSFile_stdio.cpp @@ -143,6 +143,14 @@ void sk_fflush(FILE* f) { ::fflush(f); } +void sk_fsync(FILE* f) { +#if !defined(_WIN32) && !defined(SK_BUILD_FOR_ANDROID) && !defined(__UCLIBC__) \ + && !defined(_NEWLIB_VERSION) + int fd = ::fileno(f); + ::fsync(fd); +#endif +} + bool sk_fseek(FILE* f, size_t byteCount) { int err = ::fseek(f, (long)byteCount, SEEK_SET); return err == 0; diff --git a/gfx/skia/skia/src/ports/SkTime_Unix.cpp b/gfx/skia/skia/src/ports/SkTime_Unix.cpp index 396abc04366..2123a406192 100644 --- a/gfx/skia/skia/src/ports/SkTime_Unix.cpp +++ b/gfx/skia/skia/src/ports/SkTime_Unix.cpp @@ -5,36 +5,3 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - -#include "SkTime.h" -#include "SkTypes.h" - -#include -#include - -void SkTime::GetDateTime(DateTime* dt) -{ - if (dt) - { - tzset(); // initialize timezone variable; - time_t m_time; - time(&m_time); - struct tm* tstruct; - tstruct = localtime(&m_time); - int offset = tstruct->tm_isdst == 1 ? 60 : 0; - - // http://pubs.opengroup.org/onlinepubs/009695399/basedefs/time.h.html -#if defined(__FreeBSD__) - dt->fTimeZoneMinutes = SkToS16(offset - tstruct->tm_gmtoff / 60); -#else - dt->fTimeZoneMinutes = SkToS16(offset - timezone / 60); -#endif - dt->fYear = tstruct->tm_year + 1900; - dt->fMonth = SkToU8(tstruct->tm_mon + 1); - dt->fDayOfWeek = SkToU8(tstruct->tm_wday); - dt->fDay = SkToU8(tstruct->tm_mday); - dt->fHour = SkToU8(tstruct->tm_hour); - dt->fMinute = SkToU8(tstruct->tm_min); - dt->fSecond = SkToU8(tstruct->tm_sec); - } -} diff --git a/gfx/skia/skia/src/ports/SkTime_win.cpp b/gfx/skia/skia/src/ports/SkTime_win.cpp index 2589d43d44d..f55ff90ea30 100644 --- a/gfx/skia/skia/src/ports/SkTime_win.cpp +++ b/gfx/skia/skia/src/ports/SkTime_win.cpp @@ -5,40 +5,4 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#include "SkTypes.h" -#if defined(SK_BUILD_FOR_WIN32) - -#include "SkTime.h" - -void SkTime::GetDateTime(DateTime* dt) -{ - if (dt) - { - SYSTEMTIME st; - TIME_ZONE_INFORMATION timeZoneInfo; - int tz_bias; - GetLocalTime(&st); - // https://gist.github.com/wrl/8924636 - switch (GetTimeZoneInformation(&timeZoneInfo)) { - case TIME_ZONE_ID_STANDARD: - tz_bias = -timeZoneInfo.Bias - timeZoneInfo.StandardBias; - break; - case TIME_ZONE_ID_DAYLIGHT: - tz_bias = -timeZoneInfo.Bias - timeZoneInfo.DaylightBias; - break; - default: - tz_bias = -timeZoneInfo.Bias; - break; - } - dt->fTimeZoneMinutes = SkToS16(tz_bias); - dt->fYear = st.wYear; - dt->fMonth = SkToU8(st.wMonth); - dt->fDayOfWeek = SkToU8(st.wDayOfWeek); - dt->fDay = SkToU8(st.wDay); - dt->fHour = SkToU8(st.wHour); - dt->fMinute = SkToU8(st.wMinute); - dt->fSecond = SkToU8(st.wSecond); - } -} -#endif//defined(SK_BUILD_FOR_WIN32) diff --git a/gfx/skia/skia/src/svg/parser/SkSVG.cpp b/gfx/skia/skia/src/svg/parser/SkSVG.cpp index fdfc13a6d5b..8ee7d0286a8 100644 --- a/gfx/skia/skia/src/svg/parser/SkSVG.cpp +++ b/gfx/skia/skia/src/svg/parser/SkSVG.cpp @@ -8,7 +8,8 @@ #include "SkSVG.h" -#include 'SkSVGParser.h" +#include "SkSVGParser.h" +#include "SkTemplates.h" SkSVG::SkSVG() { } @@ -19,8 +20,8 @@ SkSVG::~SkSVG() { bool SkSVG::decodeStream(SkStream* stream); { size_t size = stream->read(nil, 0); - SkAutoMalloc storage(size); - char* data = (char*)storage.get(); + SkAutoTMalloc storage(size); + char* data = storage.get(); size_t actual = stream->read(data, size); SkASSERT(size == actual); SkSVGParser parser(*fMaker); diff --git a/gfx/skia/skia/src/utils/SkCubicInterval.cpp b/gfx/skia/skia/src/utils/SkCubicInterval.cpp deleted file mode 100644 index 566023a2447..00000000000 --- a/gfx/skia/skia/src/utils/SkCubicInterval.cpp +++ /dev/null @@ -1,67 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkCubicInterval.h" - -static SkScalar eval_cubic(SkScalar c1, SkScalar c2, SkScalar c3, - SkScalar t) { - return SkScalarMul(SkScalarMul(SkScalarMul(c3, t) + c2, t) + c1, t); -} - -static SkScalar find_cubic_t(SkScalar c1, SkScalar c2, SkScalar c3, - SkScalar targetX) { - SkScalar minT = 0; - SkScalar maxT = SK_Scalar1; - SkScalar t; - - for (;;) { - t = SkScalarAve(minT, maxT); - SkScalar x = eval_cubic(c1, c2, c3, t); - if (SkScalarNearlyZero(x - targetX)) { - break; - } - // subdivide the range and try again - if (x < targetX) { - minT = t; - } else { - maxT = t; - } - } - return t; -} - -/* - a(1-t)^3 + 3bt(1-t)^2 + 3ct^2(1-t) + dt^3 - a: [0, 0] - d: [1, 1] - - 3bt - 6bt^2 + 3bt^3 + 3ct^2 - 3ct^3 + t^3 - C1 = t^1: 3b - C2 = t^2: 3c - 6b - C3 = t^3: 3b - 3c + 1 - - ((C3*t + C2)*t + C1)*t - */ -SkScalar SkEvalCubicInterval(SkScalar x1, SkScalar y1, - SkScalar x2, SkScalar y2, - SkScalar unitX) { - x1 = SkScalarPin(x1, 0, SK_Scalar1); - x2 = SkScalarPin(x2, 0, SK_Scalar1); - unitX = SkScalarPin(unitX, 0, SK_Scalar1); - - // First compute our coefficients in X - x1 *= 3; - x2 *= 3; - - // now search for t given unitX - SkScalar t = find_cubic_t(x1, x2 - 2*x1, x1 - x2 + SK_Scalar1, unitX); - - // now evaluate the cubic in Y - y1 *= 3; - y2 *= 3; - return eval_cubic(y1, y2 - 2*y1, y1 - y2 + SK_Scalar1, t); -} diff --git a/gfx/skia/skia/src/utils/SkCullPoints.cpp b/gfx/skia/skia/src/utils/SkCullPoints.cpp deleted file mode 100644 index f77acf10238..00000000000 --- a/gfx/skia/skia/src/utils/SkCullPoints.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkCullPoints.h" - -static bool cross_product_is_neg(const SkIPoint& v, int dx, int dy) { -#if 0 - return v.fX * dy - v.fY * dx < 0; -#else - return sk_64_mul(v.fX, dy) < sk_64_mul(dx, v.fY); -#endif -} - -bool SkCullPoints::sect_test(int x0, int y0, int x1, int y1) const { - const SkIRect& r = fR; - - if ((x0 < r.fLeft && x1 < r.fLeft) || - (x0 > r.fRight && x1 > r.fRight) || - (y0 < r.fTop && y1 < r.fTop) || - (y0 > r.fBottom && y1 > r.fBottom)) { - return false; - } - - // since the crossprod test is a little expensive, check for easy-in cases first - if (r.contains(x0, y0) || r.contains(x1, y1)) { - return true; - } - - // At this point we're not sure, so we do a crossprod test - SkIPoint vec; - const SkIPoint* rAsQuad = fAsQuad; - - vec.set(x1 - x0, y1 - y0); - bool isNeg = cross_product_is_neg(vec, x0 - rAsQuad[0].fX, y0 - rAsQuad[0].fY); - for (int i = 1; i < 4; i++) { - if (cross_product_is_neg(vec, x0 - rAsQuad[i].fX, y0 - rAsQuad[i].fY) != isNeg) { - return true; - } - } - return false; // we didn't intersect -} - -static void toQuad(const SkIRect& r, SkIPoint quad[4]) { - SkASSERT(quad); - - quad[0].set(r.fLeft, r.fTop); - quad[1].set(r.fRight, r.fTop); - quad[2].set(r.fRight, r.fBottom); - quad[3].set(r.fLeft, r.fBottom); -} - -SkCullPoints::SkCullPoints() { - SkIRect r; - r.setEmpty(); - this->reset(r); -} - -SkCullPoints::SkCullPoints(const SkIRect& r) { - this->reset(r); -} - -void SkCullPoints::reset(const SkIRect& r) { - fR = r; - toQuad(fR, fAsQuad); - fPrevPt.set(0, 0); - fPrevResult = kNo_Result; -} - -void SkCullPoints::moveTo(int x, int y) { - fPrevPt.set(x, y); - fPrevResult = kNo_Result; // so we trigger a movetolineto later -} - -SkCullPoints::LineToResult SkCullPoints::lineTo(int x, int y, SkIPoint line[]) { - SkASSERT(line != nullptr); - - LineToResult result = kNo_Result; - int x0 = fPrevPt.fX; - int y0 = fPrevPt.fY; - - // need to upgrade sect_test to chop the result - // and to correctly return kLineTo_Result when the result is connected - // to the previous call-out - if (this->sect_test(x0, y0, x, y)) { - line[0].set(x0, y0); - line[1].set(x, y); - - if (fPrevResult != kNo_Result && fPrevPt.equals(x0, y0)) { - result = kLineTo_Result; - } else { - result = kMoveToLineTo_Result; - } - } - - fPrevPt.set(x, y); - fPrevResult = result; - - return result; -} - -///////////////////////////////////////////////////////////////////////////////////////////////// - -#include "SkPath.h" - -SkCullPointsPath::SkCullPointsPath() - : fCP(), fPath(nullptr) { -} - -SkCullPointsPath::SkCullPointsPath(const SkIRect& r, SkPath* dst) - : fCP(r), fPath(dst) { -} - -void SkCullPointsPath::reset(const SkIRect& r, SkPath* dst) { - fCP.reset(r); - fPath = dst; -} - -void SkCullPointsPath::moveTo(int x, int y) { - fCP.moveTo(x, y); -} - -void SkCullPointsPath::lineTo(int x, int y) { - SkIPoint pts[2]; - - switch (fCP.lineTo(x, y, pts)) { - case SkCullPoints::kMoveToLineTo_Result: - fPath->moveTo(SkIntToScalar(pts[0].fX), SkIntToScalar(pts[0].fY)); - // fall through to the lineto case - case SkCullPoints::kLineTo_Result: - fPath->lineTo(SkIntToScalar(pts[1].fX), SkIntToScalar(pts[1].fY)); - break; - default: - break; - } -} - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkMatrix.h" -#include "SkRegion.h" - -bool SkHitTestPath(const SkPath& path, SkRect& target, bool hires) { - if (target.isEmpty()) { - return false; - } - - bool isInverse = path.isInverseFillType(); - if (path.isEmpty()) { - return isInverse; - } - - SkRect bounds = path.getBounds(); - - bool sects = SkRect::Intersects(target, bounds); - if (isInverse) { - if (!sects) { - return true; - } - } else { - if (!sects) { - return false; - } - if (target.contains(bounds)) { - return true; - } - } - - SkPath devPath; - const SkPath* pathPtr; - SkRect devTarget; - - if (hires) { - const SkScalar coordLimit = SkIntToScalar(16384); - const SkRect limit = { 0, 0, coordLimit, coordLimit }; - - SkMatrix matrix; - matrix.setRectToRect(bounds, limit, SkMatrix::kFill_ScaleToFit); - - path.transform(matrix, &devPath); - matrix.mapRect(&devTarget, target); - - pathPtr = &devPath; - } else { - devTarget = target; - pathPtr = &path; - } - - SkIRect iTarget; - devTarget.round(&iTarget); - if (iTarget.isEmpty()) { - iTarget.fLeft = SkScalarFloorToInt(devTarget.fLeft); - iTarget.fTop = SkScalarFloorToInt(devTarget.fTop); - iTarget.fRight = iTarget.fLeft + 1; - iTarget.fBottom = iTarget.fTop + 1; - } - - SkRegion clip(iTarget); - SkRegion rgn; - return rgn.setPath(*pathPtr, clip) ^ isInverse; -} - -bool SkHitTestPath(const SkPath& path, SkScalar x, SkScalar y, bool hires) { - const SkScalar half = SK_ScalarHalf; - const SkScalar one = SK_Scalar1; - SkRect r = SkRect::MakeXYWH(x - half, y - half, one, one); - return SkHitTestPath(path, r, hires); -} diff --git a/gfx/skia/skia/src/utils/SkDashPath.cpp b/gfx/skia/skia/src/utils/SkDashPath.cpp index e0cbe9732d2..4e34b87eac1 100644 --- a/gfx/skia/skia/src/utils/SkDashPath.cpp +++ b/gfx/skia/skia/src/utils/SkDashPath.cpp @@ -10,7 +10,7 @@ #include "SkStrokeRec.h" static inline int is_even(int x) { - return (~x) << 31; + return !(x & 1); } static SkScalar find_first_interval(const SkScalar intervals[], SkScalar phase, diff --git a/gfx/skia/skia/src/utils/SkDumpCanvas.cpp b/gfx/skia/skia/src/utils/SkDumpCanvas.cpp index 8d0209d9642..916c32a6557 100644 --- a/gfx/skia/skia/src/utils/SkDumpCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkDumpCanvas.cpp @@ -199,14 +199,14 @@ void SkDumpCanvas::willSave() { this->INHERITED::willSave(); } -SkCanvas::SaveLayerStrategy SkDumpCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, - SaveFlags flags) { +SkCanvas::SaveLayerStrategy SkDumpCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { SkString str; - str.printf("saveLayer(0x%X)", flags); - if (bounds) { + str.printf("saveLayer(0x%X)", rec.fSaveLayerFlags); + if (rec.fBounds) { str.append(" bounds"); - toString(*bounds, &str); + toString(*rec.fBounds, &str); } + const SkPaint* paint = rec.fPaint; if (paint) { if (paint->getAlpha() != 0xFF) { str.appendf(" alpha:0x%02X", paint->getAlpha()); @@ -216,7 +216,7 @@ SkCanvas::SaveLayerStrategy SkDumpCanvas::willSaveLayer(const SkRect* bounds, co } } this->dump(kSave_Verb, paint, str.c_str()); - return this->INHERITED::willSaveLayer(bounds, paint, flags); + return this->INHERITED::getSaveLayerStrategy(rec); } void SkDumpCanvas::willRestore() { @@ -397,13 +397,6 @@ void SkDumpCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, cons bs.c_str(), rs.c_str()); } -void SkDumpCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) { - SkString str; - bitmap.toString(&str); - this->dump(kDrawBitmap_Verb, paint, "drawSprite(%s %d %d)", str.c_str(), - x, y); -} - void SkDumpCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { SkString str; diff --git a/gfx/skia/skia/src/utils/SkFrontBufferedStream.cpp b/gfx/skia/skia/src/utils/SkFrontBufferedStream.cpp index 0955cfaf712..e0b586a29d8 100644 --- a/gfx/skia/skia/src/utils/SkFrontBufferedStream.cpp +++ b/gfx/skia/skia/src/utils/SkFrontBufferedStream.cpp @@ -16,7 +16,7 @@ public: size_t read(void* buffer, size_t size) override; - bool peek(void* buffer, size_t size) const override; + size_t peek(void* buffer, size_t size) const override; bool isAtEnd() const override; @@ -157,18 +157,20 @@ size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) { return bytesReadDirectly; } -bool FrontBufferedStream::peek(void* dst, size_t size) const { +size_t FrontBufferedStream::peek(void* dst, size_t size) const { // Keep track of the offset so we can return to it. const size_t start = fOffset; - if (start + size > fBufferSize) { - // This stream is not able to buffer enough. - return false; + + if (start >= fBufferSize) { + // This stream is not able to buffer. + return 0; } + + size = SkTMin(size, fBufferSize - start); FrontBufferedStream* nonConstThis = const_cast(this); - SkDEBUGCODE(const size_t bytesRead =) nonConstThis->read(dst, size); - SkASSERT(bytesRead == size); + const size_t bytesRead = nonConstThis->read(dst, size); nonConstThis->fOffset = start; - return true; + return bytesRead; } size_t FrontBufferedStream::read(void* voidDst, size_t size) { diff --git a/gfx/skia/skia/src/utils/SkInterpolator.cpp b/gfx/skia/skia/src/utils/SkInterpolator.cpp index cd9ad3a2db4..197d977cac6 100644 --- a/gfx/skia/skia/src/utils/SkInterpolator.cpp +++ b/gfx/skia/skia/src/utils/SkInterpolator.cpp @@ -68,7 +68,7 @@ SkScalar SkInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime, } SkInterpolatorBase::Result SkInterpolatorBase::timeToT(SkMSec time, SkScalar* T, - int* indexPtr, SkBool* exactPtr) const { + int* indexPtr, bool* exactPtr) const { SkASSERT(fFrameCount > 0); Result result = kNormal_Result; if (fRepeat != SK_Scalar1) { @@ -182,7 +182,7 @@ SkInterpolator::Result SkInterpolator::timeToValues(SkMSec time, SkScalar values[]) const { SkScalar T; int index; - SkBool exact; + bool exact; Result result = timeToT(time, &T, &index, &exact); if (values) { const SkScalar* nextSrc = &fValues[index * fElemCount]; diff --git a/gfx/skia/skia/src/utils/SkLua.cpp b/gfx/skia/skia/src/utils/SkLua.cpp index 307e5f6152d..d85fb91a033 100644 --- a/gfx/skia/skia/src/utils/SkLua.cpp +++ b/gfx/skia/skia/src/utils/SkLua.cpp @@ -13,6 +13,7 @@ #include "SkBlurImageFilter.h" #include "SkCanvas.h" +#include "SkColorFilter.h" #include "SkData.h" #include "SkDocument.h" #include "SkGradientShader.h" @@ -42,6 +43,7 @@ template const char* get_mtname(); } DEF_MTNAME(SkCanvas) +DEF_MTNAME(SkColorFilter) DEF_MTNAME(SkDocument) DEF_MTNAME(SkImage) DEF_MTNAME(SkImageFilter) @@ -1079,6 +1081,22 @@ static int lpaint_getEffects(lua_State* L) { return 1; } +static int lpaint_getColorFilter(lua_State* L) { + const SkPaint* paint = get_obj(L, 1); + SkColorFilter* cf = paint->getColorFilter(); + if (cf) { + push_ref(L, cf); + return 1; + } + return 0; +} + +static int lpaint_setColorFilter(lua_State* L) { + SkPaint* paint = get_obj(L, 1); + paint->setColorFilter(get_ref(L, 2)); + return 0; +} + static int lpaint_getImageFilter(lua_State* L) { const SkPaint* paint = get_obj(L, 1); SkImageFilter* imf = paint->getImageFilter(); @@ -1170,6 +1188,8 @@ static const struct luaL_Reg gSkPaint_Methods[] = { { "measureText", lpaint_measureText }, { "getFontMetrics", lpaint_getFontMetrics }, { "getEffects", lpaint_getEffects }, + { "getColorFilter", lpaint_getColorFilter }, + { "setColorFilter", lpaint_setColorFilter }, { "getImageFilter", lpaint_getImageFilter }, { "setImageFilter", lpaint_setImageFilter }, { "getShader", lpaint_getShader }, @@ -1294,6 +1314,18 @@ static const struct luaL_Reg gSkPathEffect_Methods[] = { /////////////////////////////////////////////////////////////////////////////// +static int lpcolorfilter_gc(lua_State* L) { + get_ref(L, 1)->unref(); + return 0; +} + +static const struct luaL_Reg gSkColorFilter_Methods[] = { + { "__gc", lpcolorfilter_gc }, + { nullptr, nullptr } +}; + +/////////////////////////////////////////////////////////////////////////////// + static int lpimagefilter_gc(lua_State* L) { get_ref(L, 1)->unref(); return 0; @@ -2048,6 +2080,7 @@ static void register_Sk(lua_State* L) { void SkLua::Load(lua_State* L) { register_Sk(L); REG_CLASS(L, SkCanvas); + REG_CLASS(L, SkColorFilter); REG_CLASS(L, SkDocument); REG_CLASS(L, SkImage); REG_CLASS(L, SkImageFilter); diff --git a/gfx/skia/skia/src/utils/SkLuaCanvas.cpp b/gfx/skia/skia/src/utils/SkLuaCanvas.cpp index ada76666fe5..c51b0d8a7ce 100644 --- a/gfx/skia/skia/src/utils/SkLuaCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkLuaCanvas.cpp @@ -86,17 +86,16 @@ void SkLuaCanvas::willSave() { this->INHERITED::willSave(); } -SkCanvas::SaveLayerStrategy SkLuaCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, - SaveFlags flags) { +SkCanvas::SaveLayerStrategy SkLuaCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { AUTO_LUA("saveLayer"); - if (bounds) { - lua.pushRect(*bounds, "bounds"); + if (rec.fBounds) { + lua.pushRect(*rec.fBounds, "bounds"); } - if (paint) { - lua.pushPaint(*paint, "paint"); + if (rec.fPaint) { + lua.pushPaint(*rec.fPaint, "paint"); } - this->INHERITED::willSaveLayer(bounds, paint, flags); + (void)this->INHERITED::getSaveLayerStrategy(rec); // No need for a layer. return kNoLayer_SaveLayerStrategy; } @@ -245,13 +244,6 @@ void SkLuaCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const } } -void SkLuaCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) { - AUTO_LUA("drawSprite"); - if (paint) { - lua.pushPaint(*paint, "paint"); - } -} - void SkLuaCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { AUTO_LUA("drawText"); diff --git a/gfx/skia/skia/src/utils/SkNWayCanvas.cpp b/gfx/skia/skia/src/utils/SkNWayCanvas.cpp index fb8d0ee13eb..4f60ca33cfd 100644 --- a/gfx/skia/skia/src/utils/SkNWayCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkNWayCanvas.cpp @@ -66,14 +66,13 @@ void SkNWayCanvas::willSave() { this->INHERITED::willSave(); } -SkCanvas::SaveLayerStrategy SkNWayCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, - SaveFlags flags) { +SkCanvas::SaveLayerStrategy SkNWayCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { Iter iter(fList); while (iter.next()) { - iter->saveLayer(bounds, paint, flags); + iter->saveLayer(rec); } - this->INHERITED::willSaveLayer(bounds, paint, flags); + this->INHERITED::getSaveLayerStrategy(rec); // No need for a layer. return kNoLayer_SaveLayerStrategy; } @@ -224,13 +223,6 @@ void SkNWayCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, cons } } -void SkNWayCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) { - Iter iter(fList); - while (iter.next()) { - iter->drawSprite(bitmap, x, y, paint); - } -} - void SkNWayCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { Iter iter(fList); diff --git a/gfx/skia/skia/src/utils/SkPaintFilterCanvas.cpp b/gfx/skia/skia/src/utils/SkPaintFilterCanvas.cpp index dff1514acbf..ea94068cb6e 100644 --- a/gfx/skia/skia/src/utils/SkPaintFilterCanvas.cpp +++ b/gfx/skia/skia/src/utils/SkPaintFilterCanvas.cpp @@ -12,20 +12,21 @@ class SkPaintFilterCanvas::AutoPaintFilter { public: - AutoPaintFilter(const SkPaintFilterCanvas* canvas, Type type, const SkPaint* paint) { - if (paint) { - canvas->onFilterPaint(fLazyPaint.set(*paint), type); - } + AutoPaintFilter(const SkPaintFilterCanvas* canvas, Type type, const SkPaint* paint) + : fPaint(paint) { + fShouldDraw = canvas->onFilter(&fPaint, type); } - AutoPaintFilter(const SkPaintFilterCanvas* canvas, Type type, const SkPaint& paint) { - canvas->onFilterPaint(fLazyPaint.set(paint), type); - } + AutoPaintFilter(const SkPaintFilterCanvas* canvas, Type type, const SkPaint& paint) + : AutoPaintFilter(canvas, type, &paint) { } - const SkPaint* paint() const { return fLazyPaint.getMaybeNull(); } + const SkPaint* paint() const { return fPaint; } + + bool shouldDraw() const { return fShouldDraw; } private: - SkTLazy fLazyPaint; + SkTCopyOnFirstWrite fPaint; + bool fShouldDraw; }; SkPaintFilterCanvas::SkPaintFilterCanvas(int width, int height) : INHERITED(width, height) { } @@ -44,76 +45,102 @@ SkPaintFilterCanvas::SkPaintFilterCanvas(SkCanvas *canvas) void SkPaintFilterCanvas::onDrawPaint(const SkPaint& paint) { AutoPaintFilter apf(this, kPaint_Type, paint); - this->INHERITED::onDrawPaint(*apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawPaint(*apf.paint()); + } } void SkPaintFilterCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { AutoPaintFilter apf(this, kPoint_Type, paint); - this->INHERITED::onDrawPoints(mode, count, pts, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawPoints(mode, count, pts, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { AutoPaintFilter apf(this, kRect_Type, paint); - this->INHERITED::onDrawRect(rect, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawRect(rect, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { AutoPaintFilter apf(this, kRRect_Type, paint); - this->INHERITED::onDrawRRect(rrect, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawRRect(rrect, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { AutoPaintFilter apf(this, kDRRect_Type, paint); - this->INHERITED::onDrawDRRect(outer, inner, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawDRRect(outer, inner, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) { AutoPaintFilter apf(this, kOval_Type, paint); - this->INHERITED::onDrawOval(rect, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawOval(rect, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { AutoPaintFilter apf(this, kPath_Type, paint); - this->INHERITED::onDrawPath(path, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawPath(path, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top, const SkPaint* paint) { AutoPaintFilter apf(this, kBitmap_Type, paint); - this->INHERITED::onDrawBitmap(bm, left, top, apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawBitmap(bm, left, top, apf.paint()); + } } void SkPaintFilterCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint) { AutoPaintFilter apf(this, kBitmap_Type, paint); - this->INHERITED::onDrawBitmapRect(bm, src, dst, apf.paint(), constraint); + if (apf.shouldDraw()) { + this->INHERITED::onDrawBitmapRect(bm, src, dst, apf.paint(), constraint); + } +} + +void SkPaintFilterCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, + const SkRect& dst, const SkPaint* paint) { + AutoPaintFilter apf(this, kBitmap_Type, paint); + if (apf.shouldDraw()) { + this->INHERITED::onDrawBitmapNine(bm, center, dst, apf.paint()); + } } void SkPaintFilterCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint) { AutoPaintFilter apf(this, kBitmap_Type, paint); - this->INHERITED::onDrawImage(image, left, top, apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawImage(image, left, top, apf.paint()); + } } void SkPaintFilterCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint) { AutoPaintFilter apf(this, kBitmap_Type, paint); - this->INHERITED::onDrawImageRect(image, src, dst, apf.paint(), constraint); + if (apf.shouldDraw()) { + this->INHERITED::onDrawImageRect(image, src, dst, apf.paint(), constraint); + } } -void SkPaintFilterCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, - const SkRect& dst, const SkPaint* paint) { +void SkPaintFilterCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, + const SkRect& dst, const SkPaint* paint) { AutoPaintFilter apf(this, kBitmap_Type, paint); - this->INHERITED::onDrawBitmapNine(bm, center, dst, apf.paint()); -} - -void SkPaintFilterCanvas::onDrawSprite(const SkBitmap& bm, int left, int top, - const SkPaint* paint) { - AutoPaintFilter apf(this, kBitmap_Type, paint); - this->INHERITED::onDrawSprite(bm, left, top, apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawImageNine(image, center, dst, apf.paint()); + } } void SkPaintFilterCanvas::onDrawVertices(VertexMode vmode, int vertexCount, @@ -122,49 +149,65 @@ void SkPaintFilterCanvas::onDrawVertices(VertexMode vmode, int vertexCount, const uint16_t indices[], int indexCount, const SkPaint& paint) { AutoPaintFilter apf(this, kVertices_Type, paint); - this->INHERITED::onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode, indices, - indexCount, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode, indices, + indexCount, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawPatch(const SkPoint cubics[], const SkColor colors[], const SkPoint texCoords[], SkXfermode* xmode, const SkPaint& paint) { AutoPaintFilter apf(this, kPatch_Type, paint); - this->INHERITED::onDrawPatch(cubics, colors, texCoords, xmode, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawPatch(cubics, colors, texCoords, xmode, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* m, const SkPaint* paint) { AutoPaintFilter apf(this, kPicture_Type, paint); - this->INHERITED::onDrawPicture(picture, m, apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawPicture(picture, m, apf.paint()); + } } void SkPaintFilterCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { AutoPaintFilter apf(this, kText_Type, paint); - this->INHERITED::onDrawText(text, byteLength, x, y, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawText(text, byteLength, x, y, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) { AutoPaintFilter apf(this, kText_Type, paint); - this->INHERITED::onDrawPosText(text, byteLength, pos, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawPosText(text, byteLength, pos, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { AutoPaintFilter apf(this, kText_Type, paint); - this->INHERITED::onDrawPosTextH(text, byteLength, xpos, constY, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawPosTextH(text, byteLength, xpos, constY, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { AutoPaintFilter apf(this, kText_Type, paint); - this->INHERITED::onDrawTextOnPath(text, byteLength, path, matrix, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawTextOnPath(text, byteLength, path, matrix, *apf.paint()); + } } void SkPaintFilterCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) { AutoPaintFilter apf(this, kTextBlob_Type, paint); - this->INHERITED::onDrawTextBlob(blob, x, y, *apf.paint()); + if (apf.shouldDraw()) { + this->INHERITED::onDrawTextBlob(blob, x, y, *apf.paint()); + } } diff --git a/gfx/skia/skia/src/utils/SkParsePath.cpp b/gfx/skia/skia/src/utils/SkParsePath.cpp index 3fecb46fe60..3eb9e1ef798 100644 --- a/gfx/skia/skia/src/utils/SkParsePath.cpp +++ b/gfx/skia/skia/src/utils/SkParsePath.cpp @@ -77,6 +77,10 @@ bool SkParsePath::FromSVGString(const char data[], SkPath* result) { char previousOp = '\0'; bool relative = false; for (;;) { + if (!data) { + // Truncated data + return false; + } data = skip_ws(data); if (data[0] == '\0') { break; diff --git a/gfx/skia/skia/src/utils/SkTFitsIn.h b/gfx/skia/skia/src/utils/SkTFitsIn.h index cf92822d8fe..08f7aef5f0e 100644 --- a/gfx/skia/skia/src/utils/SkTFitsIn.h +++ b/gfx/skia/skia/src/utils/SkTFitsIn.h @@ -31,7 +31,7 @@ template struct SkTHasMoreDigits * that source values are in the range of the Destination. */ template struct SkTOutOfRange_False { - typedef skstd::false_type can_be_true; + typedef std::false_type can_be_true; typedef S source_type; static bool apply(S s) { return false; @@ -42,7 +42,7 @@ template struct SkTOutOfRange_False { * Assumes that Min(S) <= Min(D). */ template struct SkTOutOfRange_LT_MinD { - typedef skstd::true_type can_be_true; + typedef std::true_type can_be_true; typedef S source_type; static bool apply(S s) { typedef SkTHasMoreDigits precondition; @@ -54,7 +54,7 @@ template struct SkTOutOfRange_LT_MinD { /** A low side predicate which tests if the source value is less than 0. */ template struct SkTOutOfRange_LT_Zero { - typedef skstd::true_type can_be_true; + typedef std::true_type can_be_true; typedef S source_type; static bool apply(S s) { return s < static_cast(0); @@ -65,7 +65,7 @@ template struct SkTOutOfRange_LT_Zero { * Assumes that Max(S) >= Max(D). */ template struct SkTOutOfRange_GT_MaxD { - typedef skstd::true_type can_be_true; + typedef std::true_type can_be_true; typedef S source_type; static bool apply(S s) { typedef SkTHasMoreDigits precondition; @@ -79,7 +79,7 @@ template struct SkTOutOfRange_GT_MaxD { * First checks OutOfRange_Low then, if in range, OutOfRange_High. */ template struct SkTOutOfRange_Either { - typedef skstd::true_type can_be_true; + typedef std::true_type can_be_true; typedef typename OutOfRange_Low::source_type source_type; static bool apply(source_type s) { bool outOfRange = OutOfRange_Low::apply(s); diff --git a/gfx/skia/skia/src/utils/android/SkAndroidSDKCanvas.cpp b/gfx/skia/skia/src/utils/android/SkAndroidSDKCanvas.cpp deleted file mode 100644 index e6f802fc5ba..00000000000 --- a/gfx/skia/skia/src/utils/android/SkAndroidSDKCanvas.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkAndroidSDKCanvas.h" - -#include "SkColorFilter.h" -#include "SkPaint.h" -#include "SkPathEffect.h" -#include "SkShader.h" -#include "SkTLazy.h" - -namespace { - -/** Discard SkShaders not exposed by the Android Java API. */ - -void CheckShader(SkPaint* paint) { - SkShader* shader = paint->getShader(); - if (!shader) { - return; - } - - if (shader->isABitmap()) { - return; - } - if (shader->asACompose(nullptr)) { - return; - } - SkShader::GradientType gtype = shader->asAGradient(nullptr); - if (gtype == SkShader::kLinear_GradientType || - gtype == SkShader::kRadial_GradientType || - gtype == SkShader::kSweep_GradientType) { - return; - } - paint->setShader(nullptr); -} - -void Filter(SkPaint* paint) { - - uint32_t flags = paint->getFlags(); - flags &= ~SkPaint::kLCDRenderText_Flag; - paint->setFlags(flags); - - // Android doesn't support Xfermodes above kLighten_Mode - SkXfermode::Mode mode; - SkXfermode::AsMode(paint->getXfermode(), &mode); - if (mode > SkXfermode::kLighten_Mode) { - paint->setXfermode(nullptr); - } - - // Force bilinear scaling or none - if (paint->getFilterQuality() != kNone_SkFilterQuality) { - paint->setFilterQuality(kLow_SkFilterQuality); - } - - CheckShader(paint); - - // Android SDK only supports mode & matrix color filters - // (and, again, no modes above kLighten_Mode). - SkColorFilter* cf = paint->getColorFilter(); - if (cf) { - SkColor color; - SkXfermode::Mode mode; - SkScalar srcColorMatrix[20]; - bool isMode = cf->asColorMode(&color, &mode); - if (isMode && mode > SkXfermode::kLighten_Mode) { - paint->setColorFilter( - SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcOver_Mode)); - } else if (!isMode && !cf->asColorMatrix(srcColorMatrix)) { - paint->setColorFilter(nullptr); - } - } - -#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK - SkPathEffect* pe = paint->getPathEffect(); - if (pe && !pe->exposedInAndroidJavaAPI()) { - paint->setPathEffect(nullptr); - } -#endif - - // TODO: Android doesn't support all the flags that can be passed to - // blur filters; we need plumbing to get them out. - - paint->setImageFilter(nullptr); - paint->setLooper(nullptr); -}; - -} // namespace - -#define FILTER(p) \ - SkPaint filteredPaint(p); \ - Filter(&filteredPaint); - -#define FILTER_PTR(p) \ - SkTLazy lazyPaint; \ - SkPaint* filteredPaint = (SkPaint*) p; \ - if (p) { \ - filteredPaint = lazyPaint.set(*p); \ - Filter(filteredPaint); \ - } - - -SkAndroidSDKCanvas::SkAndroidSDKCanvas() : fProxyTarget(nullptr) { } - -void SkAndroidSDKCanvas::reset(SkCanvas* newTarget) { fProxyTarget = newTarget; } - -void SkAndroidSDKCanvas::onDrawPaint(const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawPaint(filteredPaint); -} -void SkAndroidSDKCanvas::onDrawPoints(PointMode pMode, - size_t count, - const SkPoint pts[], - const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawPoints(pMode, count, pts, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawOval(const SkRect& r, const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawOval(r, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawRect(r, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawRRect(const SkRRect& r, const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawRRect(r, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawPath(path, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawBitmap(const SkBitmap& bitmap, - SkScalar left, - SkScalar top, - const SkPaint* paint) { - FILTER_PTR(paint); - fProxyTarget->drawBitmap(bitmap, left, top, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawBitmapRect(const SkBitmap& bitmap, - const SkRect* src, - const SkRect& dst, - const SkPaint* paint, - SkCanvas::SrcRectConstraint constraint) { - FILTER_PTR(paint); - fProxyTarget->legacy_drawBitmapRect(bitmap, src, dst, filteredPaint, constraint); -} -void SkAndroidSDKCanvas::onDrawBitmapNine(const SkBitmap& bitmap, - const SkIRect& center, - const SkRect& dst, - const SkPaint* paint) { - FILTER_PTR(paint); - fProxyTarget->drawBitmapNine(bitmap, center, dst, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawSprite(const SkBitmap& bitmap, - int left, - int top, - const SkPaint* paint) { - FILTER_PTR(paint); - fProxyTarget->drawSprite(bitmap, left, top, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawVertices(VertexMode vMode, - int vertexCount, - const SkPoint vertices[], - const SkPoint texs[], const SkColor colors[], SkXfermode* xMode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawVertices(vMode, vertexCount, vertices, texs, colors, - xMode, indices, indexCount, filteredPaint); -} - -void SkAndroidSDKCanvas::onDrawDRRect(const SkRRect& outer, - const SkRRect& inner, - const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawDRRect(outer, inner, filteredPaint); -} - -void SkAndroidSDKCanvas::onDrawText(const void* text, - size_t byteLength, - SkScalar x, - SkScalar y, - const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawText(text, byteLength, x, y, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawPosText(const void* text, - size_t byteLength, - const SkPoint pos[], - const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawPosText(text, byteLength, pos, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawPosTextH(const void* text, - size_t byteLength, - const SkScalar xpos[], - SkScalar constY, - const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawPosTextH(text, byteLength, xpos, constY, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawTextOnPath(const void* text, - size_t byteLength, - const SkPath& path, - const SkMatrix* matrix, - const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawTextOnPath(text, byteLength, path, matrix, filteredPaint); -} -void SkAndroidSDKCanvas::onDrawTextBlob(const SkTextBlob* blob, - SkScalar x, - SkScalar y, - const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawTextBlob(blob, x, y, filteredPaint); -} - -void SkAndroidSDKCanvas::onDrawPatch(const SkPoint cubics[12], - const SkColor colors[4], - const SkPoint texCoords[4], - SkXfermode* xmode, - const SkPaint& paint) { - FILTER(paint); - fProxyTarget->drawPatch(cubics, colors, texCoords, xmode, filteredPaint); -} - - -void SkAndroidSDKCanvas::onDrawImage(const SkImage* image, - SkScalar x, - SkScalar y, - const SkPaint* paint) { - FILTER_PTR(paint); - fProxyTarget->drawImage(image, x, y, filteredPaint); -} - -void SkAndroidSDKCanvas::onDrawImageRect(const SkImage* image, - const SkRect* in, - const SkRect& out, - const SkPaint* paint, - SrcRectConstraint constraint) { - FILTER_PTR(paint); - fProxyTarget->legacy_drawImageRect(image, in, out, filteredPaint, constraint); -} - -void SkAndroidSDKCanvas::onDrawPicture(const SkPicture* picture, - const SkMatrix* matrix, - const SkPaint* paint) { - FILTER_PTR(paint); - fProxyTarget->drawPicture(picture, matrix, filteredPaint); -} - -void SkAndroidSDKCanvas::onDrawAtlas(const SkImage* atlas, - const SkRSXform xform[], - const SkRect tex[], - const SkColor colors[], - int count, - SkXfermode::Mode mode, - const SkRect* cullRect, - const SkPaint* paint) { - FILTER_PTR(paint); - fProxyTarget->drawAtlas(atlas, xform, tex, colors, count, mode, cullRect, - filteredPaint); -} - -void SkAndroidSDKCanvas::onDrawImageNine(const SkImage* image, - const SkIRect& center, - const SkRect& dst, - const SkPaint* paint) { - FILTER_PTR(paint); - fProxyTarget->drawImageNine(image, center, dst, filteredPaint); -} - - -void SkAndroidSDKCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { - fProxyTarget->drawDrawable(drawable, matrix); -} - -SkISize SkAndroidSDKCanvas::getBaseLayerSize() const { - return fProxyTarget->getBaseLayerSize(); -} -bool SkAndroidSDKCanvas::getClipBounds(SkRect* rect) const { - return fProxyTarget->getClipBounds(rect); -} -bool SkAndroidSDKCanvas::getClipDeviceBounds(SkIRect* rect) const { - return fProxyTarget->getClipDeviceBounds(rect); -} - -bool SkAndroidSDKCanvas::isClipEmpty() const { return fProxyTarget->isClipEmpty(); } -bool SkAndroidSDKCanvas::isClipRect() const { return fProxyTarget->isClipRect(); } - -SkSurface* SkAndroidSDKCanvas::onNewSurface(const SkImageInfo& info, - const SkSurfaceProps& props) { - return fProxyTarget->newSurface(info, &props); -} - -bool SkAndroidSDKCanvas::onPeekPixels(SkPixmap* pmap) { - SkASSERT(pmap); - SkImageInfo info; - size_t rowBytes; - const void* addr = fProxyTarget->peekPixels(&info, &rowBytes); - if (addr) { - pmap->reset(info, addr, rowBytes); - return true; - } - return false; -} - -bool SkAndroidSDKCanvas::onAccessTopLayerPixels(SkPixmap* pmap) { - SkASSERT(pmap); - SkImageInfo info; - size_t rowBytes; - const void* addr = fProxyTarget->accessTopLayerPixels(&info, &rowBytes, nullptr); - if (addr) { - pmap->reset(info, addr, rowBytes); - return true; - } - return false; -} - -void SkAndroidSDKCanvas::willSave() { - fProxyTarget->save(); -} - -SkCanvas::SaveLayerStrategy SkAndroidSDKCanvas::willSaveLayer(const SkRect* rect, - const SkPaint* paint, - SaveFlags flags) { - fProxyTarget->saveLayer(rect, paint, flags); - return SkCanvas::kNoLayer_SaveLayerStrategy; -} - -void SkAndroidSDKCanvas::willRestore() { - fProxyTarget->restore(); -} - -void SkAndroidSDKCanvas::didRestore() { } - -void SkAndroidSDKCanvas::didConcat(const SkMatrix& m) { - fProxyTarget->concat(m); -} - -void SkAndroidSDKCanvas::didSetMatrix(const SkMatrix& m) { - fProxyTarget->setMatrix(m); -} - -void SkAndroidSDKCanvas::onClipRect(const SkRect& rect, - SkRegion::Op op, - ClipEdgeStyle style) { - fProxyTarget->clipRect(rect, op, style); -} - -void SkAndroidSDKCanvas::onClipRRect(const SkRRect& rrect, - SkRegion::Op op, - ClipEdgeStyle style) { - fProxyTarget->clipRRect(rrect, op, style); -} - -void SkAndroidSDKCanvas::onClipPath(const SkPath& path, - SkRegion::Op op, - ClipEdgeStyle style) { - fProxyTarget->clipPath(path, op, style); -} - -void SkAndroidSDKCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) { - fProxyTarget->clipRegion(region, op); -} - -void SkAndroidSDKCanvas::onDiscard() { fProxyTarget->discard(); } - - diff --git a/gfx/skia/skia/src/utils/android/SkAndroidSDKCanvas.h b/gfx/skia/skia/src/utils/android/SkAndroidSDKCanvas.h deleted file mode 100644 index 08b73f144cd..00000000000 --- a/gfx/skia/skia/src/utils/android/SkAndroidSDKCanvas.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkAndroidSDKCanvas_DEFINED -#define SkAndroidSDKCanvas_DEFINED - -#include "SkBitmap.h" -#include "SkCanvas.h" -#include "SkPaint.h" -#include "SkPath.h" -#include "SkRect.h" - -/** SkDrawFilter is likely to be deprecated; this is a proxy - canvas that does the same thing: alter SkPaint fields. - - onDraw*() functions may have their SkPaint modified, and are then - passed on to the same function on proxyTarget. THIS BREAKS CONSTNESS! - - This still suffers one of the same architectural flaws as SkDrawFilter: - TextBlob paints are incomplete when filter is called. -*/ - -class SkAndroidSDKCanvas : public SkCanvas { -public: - SkAndroidSDKCanvas(); - void reset(SkCanvas* newTarget); - -protected: - - // FILTERING - - void onDrawPaint(const SkPaint& paint) override; - void onDrawPoints(PointMode pMode, size_t count, const SkPoint pts[], - const SkPaint& paint) override; - void onDrawOval(const SkRect& r, const SkPaint& paint) override; - void onDrawRect(const SkRect& r, const SkPaint& paint) override; - void onDrawRRect(const SkRRect& r, const SkPaint& paint) override; - void onDrawPath(const SkPath& path, const SkPaint& paint) override; - void onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, - const SkPaint* paint) override; - void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, - const SkPaint* paint, SkCanvas::SrcRectConstraint) override; - void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, - const SkRect& dst, const SkPaint* paint) override; - void onDrawSprite(const SkBitmap& bitmap, int left, int top, - const SkPaint* paint) override; - void onDrawVertices(VertexMode vMode, int vertexCount, const SkPoint vertices[], - const SkPoint texs[], const SkColor colors[], SkXfermode* xMode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) override; - - void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, - const SkPaint& paint) override; - - void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, - const SkPaint& paint) override; - void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], - const SkPaint& paint) override; - void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], - SkScalar constY, const SkPaint& paint) override; - void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, - const SkMatrix* matrix, const SkPaint& paint) override; - void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, - const SkPaint& paint) override; - - void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, - const SkPaint& paint) override; - - void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override; - void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*, - SrcRectConstraint) override; - void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*); - void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], - const SkColor[], int count, SkXfermode::Mode, - const SkRect* cull, const SkPaint*) override; - void onDrawImageNine(const SkImage*, const SkIRect& center, - const SkRect& dst, const SkPaint*) override; - - // PASS THROUGH - - void onDrawDrawable(SkDrawable*, const SkMatrix*) override; - SkISize getBaseLayerSize() const override; - bool getClipBounds(SkRect*) const override; - bool getClipDeviceBounds(SkIRect*) const override; - bool isClipEmpty() const override; - bool isClipRect() const override; - SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; - bool onPeekPixels(SkPixmap*) override; - bool onAccessTopLayerPixels(SkPixmap*) override; - void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override; - void willRestore() override; - void didRestore() override; - void didConcat(const SkMatrix&) override; - void didSetMatrix(const SkMatrix&) override; - void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; - void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, SkRegion::Op) override; - void onDiscard() override; - -protected: - SkCanvas* fProxyTarget; -}; - -#endif // SkAndroidSDKCanvas_DEFINED - diff --git a/gfx/skia/skia/src/utils/debugger/SkDebugCanvas.cpp b/gfx/skia/skia/src/utils/debugger/SkDebugCanvas.cpp index f163cc5470b..63739aee814 100644 --- a/gfx/skia/skia/src/utils/debugger/SkDebugCanvas.cpp +++ b/gfx/skia/skia/src/utils/debugger/SkDebugCanvas.cpp @@ -69,15 +69,18 @@ public: , fFilterQuality(quality) {} protected: - void onFilterPaint(SkPaint* paint, Type) const override { - if (nullptr != fOverdrawXfermode.get()) { - paint->setAntiAlias(false); - paint->setXfermode(fOverdrawXfermode.get()); - } + bool onFilter(SkTCopyOnFirstWrite* paint, Type) const override { + if (*paint) { + if (nullptr != fOverdrawXfermode.get()) { + paint->writable()->setAntiAlias(false); + paint->writable()->setXfermode(fOverdrawXfermode.get()); + } - if (fOverrideFilterQuality) { - paint->setFilterQuality(fFilterQuality); + if (fOverrideFilterQuality) { + paint->writable()->setFilterQuality(fFilterQuality); + } } + return true; } void onDrawPicture(const SkPicture* picture, @@ -484,10 +487,6 @@ void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint)); } -void SkDebugCanvas::onDrawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) { - this->addDrawCommand(new SkDrawSpriteCommand(bitmap, left, top, paint)); -} - void SkDebugCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { this->addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint)); @@ -528,10 +527,9 @@ void SkDebugCanvas::willSave() { this->INHERITED::willSave(); } -SkCanvas::SaveLayerStrategy SkDebugCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, - SaveFlags flags) { - this->addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags)); - this->INHERITED::willSaveLayer(bounds, paint, flags); +SkCanvas::SaveLayerStrategy SkDebugCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { + this->addDrawCommand(new SkSaveLayerCommand(rec)); + (void)this->INHERITED::getSaveLayerStrategy(rec); // No need for a full layer. return kNoLayer_SaveLayerStrategy; } diff --git a/gfx/skia/skia/src/utils/debugger/SkDebugCanvas.h b/gfx/skia/skia/src/utils/debugger/SkDebugCanvas.h index 612ee5756f9..217b52e3ce9 100644 --- a/gfx/skia/skia/src/utils/debugger/SkDebugCanvas.h +++ b/gfx/skia/skia/src/utils/debugger/SkDebugCanvas.h @@ -165,7 +165,7 @@ public: protected: void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; void willRestore() override; void didConcat(const SkMatrix&) override; @@ -205,7 +205,6 @@ protected: const SkPaint*, SrcRectConstraint) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; diff --git a/gfx/skia/skia/src/utils/debugger/SkDrawCommand.cpp b/gfx/skia/skia/src/utils/debugger/SkDrawCommand.cpp index 66f0c14f2d2..17c59e67a65 100644 --- a/gfx/skia/skia/src/utils/debugger/SkDrawCommand.cpp +++ b/gfx/skia/skia/src/utils/debugger/SkDrawCommand.cpp @@ -11,6 +11,7 @@ #include "SkObjectParser.h" #include "SkPicture.h" #include "SkTextBlob.h" +#include "SkTextBlobRunIterator.h" // TODO(chudy): Refactor into non subclass model. @@ -47,7 +48,6 @@ const char* SkDrawCommand::GetCommandString(OpType type) { case kDrawPosTextH_OpType: return "DrawPosTextH"; case kDrawRect_OpType: return "DrawRect"; case kDrawRRect_OpType: return "DrawRRect"; - case kDrawSprite_OpType: return "DrawSprite"; case kDrawText_OpType: return "DrawText"; case kDrawTextBlob_OpType: return "DrawTextBlob"; case kDrawTextOnPath_OpType: return "DrawTextOnPath"; @@ -675,21 +675,49 @@ void SkDrawPosTextHCommand::execute(SkCanvas* canvas) const { canvas->drawPosTextH(fText, fByteLength, fXpos, fConstY, fPaint); } +static const char* gPositioningLabels[] = { + "kDefault_Positioning", + "kHorizontal_Positioning", + "kFull_Positioning", +}; + SkDrawTextBlobCommand::SkDrawTextBlobCommand(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) : INHERITED(kDrawTextBlob_OpType) - , fBlob(blob) + , fBlob(SkRef(blob)) , fXPos(x) , fYPos(y) , fPaint(paint) { - blob->ref(); - - // FIXME: push blob info + SkAutoTDelete runsStr(new SkString); fInfo.push(SkObjectParser::ScalarToString(x, "XPOS: ")); fInfo.push(SkObjectParser::ScalarToString(y, "YPOS: ")); fInfo.push(SkObjectParser::RectToString(fBlob->bounds(), "Bounds: ")); + fInfo.push(runsStr); fInfo.push(SkObjectParser::PaintToString(paint)); + + unsigned runs = 0; + SkPaint runPaint(paint); + SkTextBlobRunIterator iter(blob); + while (!iter.done()) { + SkAutoTDelete tmpStr(new SkString); + tmpStr->printf("==== Run [%d] ====", runs++); + fInfo.push(tmpStr.release()); + + fInfo.push(SkObjectParser::IntToString(iter.glyphCount(), "GlyphCount: ")); + tmpStr.reset(new SkString("GlyphPositioning: ")); + tmpStr->append(gPositioningLabels[iter.positioning()]); + fInfo.push(tmpStr.release()); + + iter.applyFontToPaint(&runPaint); + fInfo.push(SkObjectParser::PaintToString(runPaint)); + + iter.next(); + } + + runsStr->printf("Runs: %d", runs); + // runStr is owned by fInfo at this point. + runsStr.release(); } void SkDrawTextBlobCommand::execute(SkCanvas* canvas) const { @@ -780,36 +808,6 @@ bool SkDrawDRRectCommand::render(SkCanvas* canvas) const { return true; } -SkDrawSpriteCommand::SkDrawSpriteCommand(const SkBitmap& bitmap, int left, int top, - const SkPaint* paint) - : INHERITED(kDrawSprite_OpType) { - fBitmap = bitmap; - fLeft = left; - fTop = top; - if (paint) { - fPaint = *paint; - fPaintPtr = &fPaint; - } else { - fPaintPtr = nullptr; - } - - fInfo.push(SkObjectParser::BitmapToString(bitmap)); - fInfo.push(SkObjectParser::IntToString(left, "Left: ")); - fInfo.push(SkObjectParser::IntToString(top, "Top: ")); - if (paint) { - fInfo.push(SkObjectParser::PaintToString(*paint)); - } -} - -void SkDrawSpriteCommand::execute(SkCanvas* canvas) const { - canvas->drawSprite(fBitmap, fLeft, fTop, fPaintPtr); -} - -bool SkDrawSpriteCommand::render(SkCanvas* canvas) const { - render_bitmap(canvas, fBitmap); - return true; -} - SkDrawTextCommand::SkDrawTextCommand(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) : INHERITED(kDrawText_OpType) { @@ -937,36 +935,35 @@ void SkSaveCommand::execute(SkCanvas* canvas) const { canvas->save(); } -SkSaveLayerCommand::SkSaveLayerCommand(const SkRect* bounds, const SkPaint* paint, - SkCanvas::SaveFlags flags) +SkSaveLayerCommand::SkSaveLayerCommand(const SkCanvas::SaveLayerRec& rec) : INHERITED(kSaveLayer_OpType) { - if (bounds) { - fBounds = *bounds; + if (rec.fBounds) { + fBounds = *rec.fBounds; } else { fBounds.setEmpty(); } - if (paint) { - fPaint = *paint; + if (rec.fPaint) { + fPaint = *rec.fPaint; fPaintPtr = &fPaint; } else { fPaintPtr = nullptr; } - fFlags = flags; + fSaveLayerFlags = rec.fSaveLayerFlags; - if (bounds) { - fInfo.push(SkObjectParser::RectToString(*bounds, "Bounds: ")); + if (rec.fBounds) { + fInfo.push(SkObjectParser::RectToString(*rec.fBounds, "Bounds: ")); } - if (paint) { - fInfo.push(SkObjectParser::PaintToString(*paint)); + if (rec.fPaint) { + fInfo.push(SkObjectParser::PaintToString(*rec.fPaint)); } - fInfo.push(SkObjectParser::SaveFlagsToString(flags)); + fInfo.push(SkObjectParser::SaveLayerFlagsToString(fSaveLayerFlags)); } void SkSaveLayerCommand::execute(SkCanvas* canvas) const { - canvas->saveLayer(fBounds.isEmpty() ? nullptr : &fBounds, - fPaintPtr, - fFlags); + canvas->saveLayer(SkCanvas::SaveLayerRec(fBounds.isEmpty() ? nullptr : &fBounds, + fPaintPtr, + fSaveLayerFlags)); } void SkSaveLayerCommand::vizExecute(SkCanvas* canvas) const { diff --git a/gfx/skia/skia/src/utils/debugger/SkDrawCommand.h b/gfx/skia/skia/src/utils/debugger/SkDrawCommand.h index c7e5f008a42..f67df92de7d 100644 --- a/gfx/skia/skia/src/utils/debugger/SkDrawCommand.h +++ b/gfx/skia/skia/src/utils/debugger/SkDrawCommand.h @@ -41,7 +41,6 @@ public: kDrawPosTextH_OpType, kDrawRect_OpType, kDrawRRect_OpType, - kDrawSprite_OpType, kDrawText_OpType, kDrawTextBlob_OpType, kDrawTextOnPath_OpType, @@ -518,21 +517,6 @@ private: typedef SkDrawCommand INHERITED; }; -class SkDrawSpriteCommand : public SkDrawCommand { -public: - SkDrawSpriteCommand(const SkBitmap& bitmap, int left, int top, const SkPaint* paint); - void execute(SkCanvas* canvas) const override; - bool render(SkCanvas* canvas) const override; -private: - SkBitmap fBitmap; - int fLeft; - int fTop; - SkPaint fPaint; - SkPaint* fPaintPtr; - - typedef SkDrawCommand INHERITED; -}; - class SkDrawVerticesCommand : public SkDrawCommand { public: SkDrawVerticesCommand(SkCanvas::VertexMode vmode, int vertexCount, @@ -567,8 +551,7 @@ private: class SkSaveLayerCommand : public SkDrawCommand { public: - SkSaveLayerCommand(const SkRect* bounds, const SkPaint* paint, - SkCanvas::SaveFlags flags); + SkSaveLayerCommand(const SkCanvas::SaveLayerRec&); void execute(SkCanvas* canvas) const override; void vizExecute(SkCanvas* canvas) const override; Action action() const override{ return kPushLayer_Action; } @@ -578,12 +561,12 @@ public: const SkPaint* paint() const { return fPaintPtr; } private: - SkRect fBounds; - SkPaint fPaint; - SkPaint* fPaintPtr; - SkCanvas::SaveFlags fFlags; + SkRect fBounds; + SkPaint fPaint; + SkPaint* fPaintPtr; + uint32_t fSaveLayerFlags; - bool fActive; + bool fActive; typedef SkDrawCommand INHERITED; }; diff --git a/gfx/skia/skia/src/utils/debugger/SkObjectParser.cpp b/gfx/skia/skia/src/utils/debugger/SkObjectParser.cpp index 3dbc03901fb..6d71a38b7b8 100644 --- a/gfx/skia/skia/src/utils/debugger/SkObjectParser.cpp +++ b/gfx/skia/skia/src/utils/debugger/SkObjectParser.cpp @@ -338,16 +338,13 @@ SkString* SkObjectParser::RegionToString(const SkRegion& region) { return mRegion; } -SkString* SkObjectParser::SaveFlagsToString(SkCanvas::SaveFlags flags) { +SkString* SkObjectParser::SaveLayerFlagsToString(SkCanvas::SaveLayerFlags saveLayerFlags) { SkString* mFlags = new SkString("SkCanvas::SaveFlags: "); - if (flags & SkCanvas::kHasAlphaLayer_SaveFlag) { - mFlags->append("kHasAlphaLayer_SaveFlag "); + if (saveLayerFlags & SkCanvas::kIsOpaque_SaveLayerFlag) { + mFlags->append("kIsOpaque_SaveLayerFlag "); } - if (flags & SkCanvas::kFullColorLayer_SaveFlag) { - mFlags->append("kFullColorLayer_SaveFlag "); - } - if (flags & SkCanvas::kClipToLayer_SaveFlag) { - mFlags->append("kClipToLayer_SaveFlag "); + if (saveLayerFlags & SkCanvas::kPreserveLCDText_SaveLayerFlag) { + mFlags->append("kPreserveLCDText_SaveLayerFlag "); } return mFlags; } diff --git a/gfx/skia/skia/src/utils/debugger/SkObjectParser.h b/gfx/skia/skia/src/utils/debugger/SkObjectParser.h index 4c04935257d..9bdfad5e79e 100644 --- a/gfx/skia/skia/src/utils/debugger/SkObjectParser.h +++ b/gfx/skia/skia/src/utils/debugger/SkObjectParser.h @@ -110,10 +110,10 @@ public: static SkString* RegionToString(const SkRegion& region); /** - Returns a string representation of the SkCanvas::SaveFlags enum. - @param flags SkCanvas::SaveFlags enum + Returns a string representation of the SkCanvas::SaveLayerFlags enum. + @param flags SkCanvas::SaveLayerFlags enum */ - static SkString* SaveFlagsToString(SkCanvas::SaveFlags flags); + static SkString* SaveLayerFlagsToString(uint32_t saveLayerFlags); /** Returns a string representation of an SkScalar with the text parameter diff --git a/gfx/skia/skia/src/views/SkView.cpp b/gfx/skia/skia/src/views/SkView.cpp index ec75d610aaf..9e8182b16a9 100644 --- a/gfx/skia/skia/src/views/SkView.cpp +++ b/gfx/skia/skia/src/views/SkView.cpp @@ -1,17 +1,21 @@ - /* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ + #include "SkView.h" #include "SkCanvas.h" +static inline uint32_t SkSetClearShift(uint32_t bits, bool cond, unsigned shift) { + SkASSERT((int)cond == 0 || (int)cond == 1); + return (bits & ~(1 << shift)) | ((int)cond << shift); +} + //////////////////////////////////////////////////////////////////////// -SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags)) -{ +SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags)) { fWidth = fHeight = 0; fLoc.set(0, 0); fParent = fFirstChild = fNextSibling = fPrevSibling = nullptr; @@ -19,13 +23,11 @@ SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags)) fContainsFocus = 0; } -SkView::~SkView() -{ +SkView::~SkView() { this->detachAllChildren(); } -void SkView::setFlags(uint32_t flags) -{ +void SkView::setFlags(uint32_t flags) { SkASSERT((flags & ~kAllFlagMasks) == 0); uint32_t diff = fFlags ^ flags; @@ -35,24 +37,20 @@ void SkView::setFlags(uint32_t flags) fFlags = SkToU8(flags); - if (diff & kVisible_Mask) - { + if (diff & kVisible_Mask) { this->inval(nullptr); } } -void SkView::setVisibleP(bool pred) -{ +void SkView::setVisibleP(bool pred) { this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift)); } -void SkView::setEnabledP(bool pred) -{ +void SkView::setEnabledP(bool pred) { this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift)); } -void SkView::setFocusableP(bool pred) -{ +void SkView::setFocusableP(bool pred) { this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift)); } @@ -60,8 +58,7 @@ void SkView::setClipToBounds(bool pred) { this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift)); } -void SkView::setSize(SkScalar width, SkScalar height) -{ +void SkView::setSize(SkScalar width, SkScalar height) { width = SkMaxScalar(0, width); height = SkMaxScalar(0, height); @@ -76,38 +73,31 @@ void SkView::setSize(SkScalar width, SkScalar height) } } -void SkView::setLoc(SkScalar x, SkScalar y) -{ - if (fLoc.fX != x || fLoc.fY != y) - { +void SkView::setLoc(SkScalar x, SkScalar y) { + if (fLoc.fX != x || fLoc.fY != y) { this->inval(nullptr); fLoc.set(x, y); this->inval(nullptr); } } -void SkView::offset(SkScalar dx, SkScalar dy) -{ +void SkView::offset(SkScalar dx, SkScalar dy) { if (dx || dy) this->setLoc(fLoc.fX + dx, fLoc.fY + dy); } -void SkView::setLocalMatrix(const SkMatrix& matrix) -{ +void SkView::setLocalMatrix(const SkMatrix& matrix) { this->inval(nullptr); fMatrix = matrix; this->inval(nullptr); } -void SkView::draw(SkCanvas* canvas) -{ - if (fWidth && fHeight && this->isVisible()) - { +void SkView::draw(SkCanvas* canvas) { + if (fWidth && fHeight && this->isVisible()) { SkRect r; r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight); - if (this->isClipToBounds() && - canvas->quickReject(r)) { - return; + if (this->isClipToBounds() && canvas->quickReject(r)) { + return; } SkAutoCanvasRestore as(canvas, true); @@ -178,84 +168,79 @@ void SkView::inval(SkRect* rect) { //////////////////////////////////////////////////////////////////////////// -bool SkView::setFocusView(SkView* fv) -{ +bool SkView::setFocusView(SkView* fv) { SkView* view = this; do { - if (view->onSetFocusView(fv)) + if (view->onSetFocusView(fv)) { return true; + } } while ((view = view->fParent) != nullptr); return false; } -SkView* SkView::getFocusView() const -{ - SkView* focus = nullptr; - const SkView* view = this; +SkView* SkView::getFocusView() const { + SkView* focus = nullptr; + const SkView* view = this; do { - if (view->onGetFocusView(&focus)) + if (view->onGetFocusView(&focus)) { break; + } } while ((view = view->fParent) != nullptr); return focus; } -bool SkView::hasFocus() const -{ +bool SkView::hasFocus() const { return this == this->getFocusView(); } -bool SkView::acceptFocus() -{ +bool SkView::acceptFocus() { return this->isFocusable() && this->setFocusView(this); } /* Try to give focus to this view, or its children */ -SkView* SkView::acceptFocus(FocusDirection dir) -{ - if (dir == kNext_FocusDirection) - { - if (this->acceptFocus()) +SkView* SkView::acceptFocus(FocusDirection dir) { + if (dir == kNext_FocusDirection) { + if (this->acceptFocus()) { return this; - + } B2FIter iter(this); SkView* child, *focus; - while ((child = iter.next()) != nullptr) - if ((focus = child->acceptFocus(dir)) != nullptr) + while ((child = iter.next()) != nullptr) { + if ((focus = child->acceptFocus(dir)) != nullptr) { return focus; - } - else // prev - { + } + } + } else { // prev F2BIter iter(this); SkView* child, *focus; - while ((child = iter.next()) != nullptr) - if ((focus = child->acceptFocus(dir)) != nullptr) + while ((child = iter.next()) != nullptr) { + if ((focus = child->acceptFocus(dir)) != nullptr) { return focus; - - if (this->acceptFocus()) + } + } + if (this->acceptFocus()) { return this; + } } - return nullptr; } -SkView* SkView::moveFocus(FocusDirection dir) -{ +SkView* SkView::moveFocus(FocusDirection dir) { SkView* focus = this->getFocusView(); - if (focus == nullptr) - { // start with the root + if (focus == nullptr) { // start with the root focus = this; - while (focus->fParent) + while (focus->fParent) { focus = focus->fParent; + } } - SkView* child, *parent; + SkView* child, *parent; - if (dir == kNext_FocusDirection) - { + if (dir == kNext_FocusDirection) { parent = focus; child = focus->fFirstChild; if (child) @@ -264,8 +249,7 @@ SkView* SkView::moveFocus(FocusDirection dir) goto NEXT_SIB; do { - while (child != parent->fFirstChild) - { + while (child != parent->fFirstChild) { FIRST_CHILD: if ((focus = child->acceptFocus(dir)) != nullptr) return focus; @@ -275,26 +259,22 @@ SkView* SkView::moveFocus(FocusDirection dir) child = parent->fNextSibling; parent = parent->fParent; } while (parent != nullptr); - } - else // prevfocus - { + } else { // prevfocus parent = focus->fParent; - if (parent == nullptr) // we're the root + if (parent == nullptr) { // we're the root return focus->acceptFocus(dir); - else - { + } else { child = focus; - while (parent) - { - while (child != parent->fFirstChild) - { + while (parent) { + while (child != parent->fFirstChild) { child = child->fPrevSibling; - if ((focus = child->acceptFocus(dir)) != nullptr) + if ((focus = child->acceptFocus(dir)) != nullptr) { return focus; + } } - if (parent->acceptFocus()) + if (parent->acceptFocus()) { return parent; - + } child = parent; parent = parent->fParent; } @@ -303,15 +283,13 @@ SkView* SkView::moveFocus(FocusDirection dir) return nullptr; } -void SkView::onFocusChange(bool gainFocusP) -{ +void SkView::onFocusChange(bool gainFocusP) { this->inval(nullptr); } //////////////////////////////////////////////////////////////////////////// -SkView::Click::Click(SkView* target) -{ +SkView::Click::Click(SkView* target) { SkASSERT(target); fTargetID = target->getSinkID(); fType = nullptr; @@ -319,49 +297,43 @@ SkView::Click::Click(SkView* target) fOwner = nullptr; } -SkView::Click::~Click() -{ +SkView::Click::~Click() { this->resetType(); } -void SkView::Click::resetType() -{ - if (fWeOwnTheType) - { +void SkView::Click::resetType() { + if (fWeOwnTheType) { sk_free(fType); fWeOwnTheType = false; } fType = nullptr; } -bool SkView::Click::isType(const char type[]) const -{ +bool SkView::Click::isType(const char type[]) const { const char* t = fType; - if (type == t) + if (type == t) { return true; - - if (type == nullptr) + } + if (type == nullptr) { type = ""; - if (t == nullptr) + } + if (t == nullptr) { t = ""; + } return !strcmp(t, type); } -void SkView::Click::setType(const char type[]) -{ +void SkView::Click::setType(const char type[]) { this->resetType(); fType = (char*)type; } -void SkView::Click::copyType(const char type[]) -{ - if (fType != type) - { +void SkView::Click::copyType(const char type[]) { + if (fType != type) { this->resetType(); - if (type) - { - size_t len = strlen(type) + 1; + if (type) { + size_t len = strlen(type) + 1; fType = (char*)sk_malloc_throw(len); memcpy(fType, type, len); fWeOwnTheType = true; @@ -400,8 +372,7 @@ SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y, unsigned modi) { return this->onFindClickHandler(x, y, modi); } -void SkView::DoClickDown(Click* click, int x, int y, unsigned modi) -{ +void SkView::DoClickDown(Click* click, int x, int y, unsigned modi) { SkASSERT(click); SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID); @@ -424,8 +395,7 @@ void SkView::DoClickDown(Click* click, int x, int y, unsigned modi) target->onClick(click); } -void SkView::DoClickMoved(Click* click, int x, int y, unsigned modi) -{ +void SkView::DoClickMoved(Click* click, int x, int y, unsigned modi) { SkASSERT(click); SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID); @@ -448,8 +418,7 @@ void SkView::DoClickMoved(Click* click, int x, int y, unsigned modi) target->onClick(click); } -void SkView::DoClickUp(Click* click, int x, int y, unsigned modi) -{ +void SkView::DoClickUp(Click* click, int x, int y, unsigned modi) { SkASSERT(click); SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID); @@ -637,8 +606,8 @@ void SkView::localToGlobal(SkMatrix* matrix) const { } } } -bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const -{ + +bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const { SkASSERT(this); if (local) { @@ -684,9 +653,11 @@ void SkView::onInflate(const SkDOM& dom, const SkDOM::Node* node) { bool b; uint32_t flags = this->getFlags(); - for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++) - if (dom.findBool(node, gFlagNames[i], &b)) + for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++) { + if (dom.findBool(node, gFlagNames[i], &b)) { flags = SkSetClearShift(flags, b, i); + } + } this->setFlags(flags); } @@ -788,20 +759,19 @@ void SkView::validate() const { } } -static inline void show_if_nonzero(const char name[], SkScalar value) -{ - if (value) +static inline void show_if_nonzero(const char name[], SkScalar value) { + if (value) { SkDebugf("%s=\"%g\"", name, value/65536.); + } } -static void tab(int level) -{ - for (int i = 0; i < level; i++) +static void tab(int level) { + for (int i = 0; i < level; i++) { SkDebugf(" "); + } } -static void dumpview(const SkView* view, int level, bool recurse) -{ +static void dumpview(const SkView* view, int level, bool recurse) { tab(level); SkDebugf("width()); show_if_nonzero(" height", view->height()); - if (recurse) - { + if (recurse) { SkView::B2FIter iter(view); SkView* child; bool noChildren = true; - while ((child = iter.next()) != nullptr) - { - if (noChildren) + while ((child = iter.next()) != nullptr) { + if (noChildren) { SkDebugf(">\n"); + } noChildren = false; dumpview(child, level + 1, true); } - if (!noChildren) - { + if (!noChildren) { tab(level); SkDebugf("\n"); - } - else + } else { goto ONELINER; - } - else - { + } + } else { ONELINER: SkDebugf(" />\n"); } } -void SkView::dump(bool recurse) const -{ +void SkView::dump(bool recurse) const { dumpview(this, 0, recurse); } diff --git a/gfx/skia/skia/src/views/sdl/SkOSWindow_SDL.cpp b/gfx/skia/skia/src/views/sdl/SkOSWindow_SDL.cpp index 45beaee53e8..c39a4fdfef8 100644 --- a/gfx/skia/skia/src/views/sdl/SkOSWindow_SDL.cpp +++ b/gfx/skia/skia/src/views/sdl/SkOSWindow_SDL.cpp @@ -15,72 +15,39 @@ #include #endif -const int SCREEN_WIDTH = 640; -const int SCREEN_HEIGHT = 480; +const int kInitialWindowWidth = 640; +const int kInitialWindowHeight = 480; +static SkOSWindow* gCurrentWindow; -static void handle_error() { +static void report_sdl_error(const char* failure) { const char* error = SDL_GetError(); - SkDebugf("SDL Error: %s\n", error); + SkASSERT(error); // Called only to check SDL error. + SkDebugf("%s SDL Error: %s.\n", failure, error); SDL_ClearError(); } +SkOSWindow::SkOSWindow(void*) + : fWindow(nullptr) + , fGLContext(nullptr) + , fWindowMSAASampleCount(0) { -SkOSWindow::SkOSWindow(void* screen) : fQuit(false) , fGLContext(nullptr) { -#if defined(SK_BUILD_FOR_ANDROID) - // TODO we should try and get a 3.0 context first - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - fWindowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | - SDL_WINDOW_BORDERLESS | SDL_WINDOW_FULLSCREEN_DESKTOP | - SDL_WINDOW_ALLOW_HIGHDPI; -#else - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_StartTextInput(); + SkASSERT(!gCurrentWindow); + gCurrentWindow = this; - fWindowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; -#endif - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - - SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); - - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { - handle_error(); - return; - } - - SDL_DisplayMode dm; - if (SDL_GetDesktopDisplayMode(0, &dm) != 0) { - handle_error(); - return; - } - - fWindow = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - dm.w, dm.h, fWindowFlags); - - if (!fWindow) { - handle_error(); - return; - } - this->resize(dm.w, dm.h); + this->createWindow(0); } SkOSWindow::~SkOSWindow() { - if (fGLContext) { - SDL_GL_DeleteContext(fGLContext); + this->destroyWindow(); + gCurrentWindow = nullptr; +} + +SkOSWindow* SkOSWindow::GetInstanceForWindowID(Uint32 windowID) { + if (gCurrentWindow && + gCurrentWindow->fWindow && + SDL_GetWindowID(gCurrentWindow->fWindow) == windowID) { + return gCurrentWindow; } - - //Destroy window - SDL_DestroyWindow(fWindow); - - //Quit SDL subsystems - SDL_Quit(); + return nullptr; } void SkOSWindow::detach() { @@ -88,67 +55,67 @@ void SkOSWindow::detach() { SDL_GL_DeleteContext(fGLContext); fGLContext = nullptr; } - -#if defined(SK_BUILD_FOR_ANDROID) - if (fWindow) { - // Destroy window - // Not totally sure why, but we have to do this or swapbuffers will hang - SDL_DestroyWindow(fWindow); - fWindow = nullptr; - } -#endif } bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo* info) { + this->createWindow(msaaSampleCount); if (!fWindow) { - fWindow = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - SCREEN_WIDTH, SCREEN_HEIGHT, - fWindowFlags); + return false; + } + if (!fGLContext) { + fGLContext = SDL_GL_CreateContext(fWindow); + if (!fGLContext) { + report_sdl_error("Failed to create SDL GL context."); + return false; + } + glClearColor(0, 0, 0, 0); + glClearStencil(0); + glStencilMask(0xffffffff); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } - if (msaaSampleCount > 0) { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaaSampleCount); + if (SDL_GL_MakeCurrent(fWindow, fGLContext) != 0) { + report_sdl_error("Failed to make SDL GL context current."); + this->detach(); + return false; } info->fSampleCount = msaaSampleCount; info->fStencilBits = 8; - fGLContext = SDL_GL_CreateContext(fWindow); - if (!fGLContext) { - handle_error(); - return false; - } - - int success = SDL_GL_MakeCurrent(fWindow, fGLContext); - if (success != 0) { - handle_error(); - return false; - } - - glViewport(0, 0, SkScalarFloorToInt(this->width()), SkScalarFloorToInt(this->height())); - glClearColor(1, 1, 1, 1); - glClearStencil(0); - glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - + glViewport(0, 0, SkScalarRoundToInt(this->width()), SkScalarRoundToInt(this->height())); return true; } void SkOSWindow::present() { + if (!fWindow) { + return; + } SDL_GL_SwapWindow(fWindow); } bool SkOSWindow::makeFullscreen() { - SDL_SetWindowFullscreen(fWindow, SDL_WINDOW_FULLSCREEN); + if (!fWindow) { + return false; + } + SDL_SetWindowFullscreen(fWindow, SDL_WINDOW_FULLSCREEN_DESKTOP); return true; } void SkOSWindow::setVsync(bool vsync) { + if (!fWindow) { + return; + } SDL_GL_SetSwapInterval(vsync ? 1 : 0); } void SkOSWindow::closeWindow() { - fQuit = true; + this->destroyWindow(); + + // Currently closing the window causes the app to quit. + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); } static SkKey convert_sdlkey_to_skkey(SDL_Keycode src) { @@ -194,59 +161,200 @@ static SkKey convert_sdlkey_to_skkey(SDL_Keycode src) { } } -void SkOSWindow::handleEvents() { - SkEvent::ServiceQueueTimer(); - SkEvent::ProcessEvent(); +void SkOSWindow::createWindow(int msaaSampleCount) { + if (fWindowMSAASampleCount != msaaSampleCount) { + this->destroyWindow(); + } + if (fWindow) { + return; + } + uint32_t windowFlags = +#if defined(SK_BUILD_FOR_ANDROID) + SDL_WINDOW_BORDERLESS | SDL_WINDOW_FULLSCREEN_DESKTOP | + SDL_WINDOW_ALLOW_HIGHDPI | +#endif + SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; - SDL_Event event; - while(SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_MOUSEMOTION: - if (event.motion.state == SDL_PRESSED) { - this->handleClick(event.motion.x, event.motion.y, - SkView::Click::kMoved_State, nullptr); - } - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - this->handleClick(event.button.x, event.button.y, - event.button.state == SDL_PRESSED ? - SkView::Click::kDown_State : - SkView::Click::kUp_State, nullptr); - break; - case SDL_KEYDOWN: { - SDL_Keycode key = event.key.keysym.sym; - SkKey sk = convert_sdlkey_to_skkey(key); - if (kNONE_SkKey != sk) { - if (event.key.state == SDL_PRESSED) { - this->handleKey(sk); - } else { - this->handleKeyUp(sk); - } - } else if (key == SDLK_ESCAPE) { - fQuit = true; - } - break; - } - case SDL_TEXTINPUT: { - size_t len = strlen(event.text.text); - for (size_t i = 0; i < len; i++) { - this->handleChar((SkUnichar)event.text.text[i]); - } - break; - } - case SDL_QUIT: - fQuit = true; - break; - default: - break; + // GL settings are part of SDL_WINDOW_OPENGL window creation arguments. +#if defined(SK_BUILD_FOR_ANDROID) + // TODO we should try and get a 3.0 context first + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); +#else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +#endif + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); +#if defined(SK_BUILD_FOR_UNIX) + // Apparently MSAA request matches "slow caveat". Make SDL not set anything for caveat for MSAA + // by setting -1 for ACCELERATED_VISUAL. For non-MSAA, set ACCELERATED_VISUAL to 1 just for + // compatiblity with other platforms. + SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, msaaSampleCount > 0 ? -1 : 1); +#else + SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); +#endif + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, msaaSampleCount > 0 ? 1 : 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaaSampleCount); + + // This is an approximation for sizing purposes. + bool isInitialWindow = this->width() == 0 && this->height() == 0; + SkScalar windowWidth = isInitialWindow ? kInitialWindowWidth : this->width(); + SkScalar windowHeight = isInitialWindow ? kInitialWindowHeight : this->height(); + + fWindow = SDL_CreateWindow(this->getTitle(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + windowWidth, windowHeight, windowFlags); + if (!fWindow) { + report_sdl_error("Failed to create SDL window."); + return; + } + fWindowMSAASampleCount = msaaSampleCount; +} + +void SkOSWindow::destroyWindow() { + this->detach(); + if (fWindow) { + SDL_DestroyWindow(fWindow); + fWindow = nullptr; + fWindowMSAASampleCount = 0; + } +} + +bool SkOSWindow::HasDirtyWindows() { + if (gCurrentWindow && gCurrentWindow->fWindow) { + return gCurrentWindow->isDirty(); + } + return false; +} + +void SkOSWindow::UpdateDirtyWindows() { + if (gCurrentWindow && gCurrentWindow->fWindow) { + if (gCurrentWindow->isDirty()) { + // This will call present. + gCurrentWindow->update(nullptr); } } } +void SkOSWindow::HandleEvent(const SDL_Event& event) { + switch (event.type) { + case SDL_MOUSEMOTION: + if (SkOSWindow* window = GetInstanceForWindowID(event.motion.windowID)) { + if (event.motion.state == SDL_PRESSED) { + window->handleClick(event.motion.x, event.motion.y, + SkView::Click::kMoved_State, nullptr); + } + } + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + if (SkOSWindow* window = GetInstanceForWindowID(event.button.windowID)) { + window->handleClick(event.button.x, event.button.y, + event.button.state == SDL_PRESSED ? + SkView::Click::kDown_State : + SkView::Click::kUp_State, nullptr); + } + break; + case SDL_KEYDOWN: + if (SkOSWindow* window = GetInstanceForWindowID(event.key.windowID)) { + SDL_Keycode key = event.key.keysym.sym; + SkKey sk = convert_sdlkey_to_skkey(key); + if (kNONE_SkKey != sk) { + if (event.key.state == SDL_PRESSED) { + window->handleKey(sk); + } else { + window->handleKeyUp(sk); + } + } else if (key == SDLK_ESCAPE) { + window->closeWindow(); + } + } + break; + case SDL_TEXTINPUT: + if (SkOSWindow* window = GetInstanceForWindowID(event.text.windowID)) { + size_t len = strlen(event.text.text); + for (size_t i = 0; i < len; i++) { + window->handleChar((SkUnichar)event.text.text[i]); + } + } + break; + case SDL_WINDOWEVENT: + switch (event.window.event) { + case SDL_WINDOWEVENT_SHOWN: + // For initialization purposes, we resize upon first show. + // Fallthrough. + case SDL_WINDOWEVENT_SIZE_CHANGED: + if (SkOSWindow* window = GetInstanceForWindowID(event.window.windowID)) { + int w = 0; + int h = 0; + SDL_GetWindowSize(window->fWindow, &w, &h); + window->resize(w, h); + } + break; + case SDL_WINDOWEVENT_FOCUS_GAINED: + if (GetInstanceForWindowID(event.text.windowID)) { + SDL_StartTextInput(); + } + break; + default: + break; + } + break; + default: + break; + } +} + +SkMSec gTimerDelay; + +void SkOSWindow::RunEventLoop() { + for (;;) { + SkEvent::ServiceQueueTimer(); + bool hasMoreSkEvents = SkEvent::ProcessEvent(); + + SDL_Event event; + bool hasSDLEvents = SDL_PollEvent(&event) == 1; + + // Invalidations do not post to event loop, rather we just go through the + // windows for each event loop iteration. + bool hasDirtyWindows = HasDirtyWindows(); + + if (!hasSDLEvents && !hasMoreSkEvents && !hasDirtyWindows) { + // If there is no SDL events, SkOSWindow updates or SkEvents + // to be done, wait for the SDL events. + if (gTimerDelay > 0) { + hasSDLEvents = SDL_WaitEventTimeout(&event, gTimerDelay) == 1; + } else { + hasSDLEvents = SDL_WaitEvent(&event) == 1; + } + } + while (hasSDLEvents) { + if (event.type == SDL_QUIT) { + return; + } + HandleEvent(event); + hasSDLEvents = SDL_PollEvent(&event); + } + UpdateDirtyWindows(); + } +} void SkOSWindow::onSetTitle(const char title[]) { - SDL_SetWindowTitle(fWindow, title); + if (!fWindow) { + return; + } + this->updateWindowTitle(); +} + +void SkOSWindow::updateWindowTitle() { + SDL_SetWindowTitle(fWindow, this->getTitle()); } /////////////////////////////////////////////////////////////////////////////////////// @@ -255,13 +363,7 @@ void SkEvent::SignalNonEmptyQueue() { } void SkEvent::SignalQueueTimer(SkMSec delay) { - // just need to record the delay time. We handle waking up for it in -} - -void SkOSWindow::onHandleInval(const SkIRect& rect) { -} - -void SkOSWindow::onPDFSaved(const char title[], const char desc[], const char path[]) { + gTimerDelay = delay; } ////////////////////////////////////////////////////////////////////////////////////////////// @@ -275,17 +377,24 @@ int SDL_main(int argc, char** argv) { #else int main(int argc, char** argv) { #endif + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { + report_sdl_error("Failed to init SDL."); + return -1; + } + + application_init(); + SkOSWindow* window = create_sk_window(nullptr, argc, argv); // drain any events that occurred before |window| was assigned. while (SkEvent::ProcessEvent()); - // Start normal Skia sequence - application_init(); - - window->loop(); + SkOSWindow::RunEventLoop(); delete window; application_term(); + + SDL_Quit(); + return 0; } diff --git a/gfx/skia/skia/src/xml/SkDOM.cpp b/gfx/skia/skia/src/xml/SkDOM.cpp index 68e2938d9a3..0f0b614f111 100644 --- a/gfx/skia/skia/src/xml/SkDOM.cpp +++ b/gfx/skia/skia/src/xml/SkDOM.cpp @@ -240,7 +240,7 @@ protected: } *fParentStack.push() = node; - memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr)); + sk_careful_memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr)); fAttrs.reset(); }