1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/2d/FilterProcessingScalar.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,321 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#define FILTER_PROCESSING_SCALAR 1.10 + 1.11 +#include "FilterProcessingSIMD-inl.h" 1.12 + 1.13 +namespace mozilla { 1.14 +namespace gfx { 1.15 + 1.16 +void 1.17 +FilterProcessing::ExtractAlpha_Scalar(const IntSize& size, uint8_t* sourceData, int32_t sourceStride, uint8_t* alphaData, int32_t alphaStride) 1.18 +{ 1.19 + for (int32_t y = 0; y < size.height; y++) { 1.20 + for (int32_t x = 0; x < size.width; x++) { 1.21 + int32_t sourceIndex = y * sourceStride + 4 * x; 1.22 + int32_t targetIndex = y * alphaStride + x; 1.23 + alphaData[targetIndex] = sourceData[sourceIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A]; 1.24 + } 1.25 + } 1.26 +} 1.27 + 1.28 +TemporaryRef<DataSourceSurface> 1.29 +FilterProcessing::ConvertToB8G8R8A8_Scalar(SourceSurface* aSurface) 1.30 +{ 1.31 + return ConvertToB8G8R8A8_SIMD<simd::Scalaru8x16_t>(aSurface); 1.32 +} 1.33 + 1.34 +template<BlendMode aBlendMode> 1.35 +static TemporaryRef<DataSourceSurface> 1.36 +ApplyBlending_Scalar(DataSourceSurface* aInput1, DataSourceSurface* aInput2) 1.37 +{ 1.38 + IntSize size = aInput1->GetSize(); 1.39 + RefPtr<DataSourceSurface> target = 1.40 + Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); 1.41 + if (!target) { 1.42 + return nullptr; 1.43 + } 1.44 + 1.45 + uint8_t* source1Data = aInput1->GetData(); 1.46 + uint8_t* source2Data = aInput2->GetData(); 1.47 + uint8_t* targetData = target->GetData(); 1.48 + uint32_t targetStride = target->Stride(); 1.49 + uint32_t source1Stride = aInput1->Stride(); 1.50 + uint32_t source2Stride = aInput2->Stride(); 1.51 + 1.52 + for (int32_t y = 0; y < size.height; y++) { 1.53 + for (int32_t x = 0; x < size.width; x++) { 1.54 + uint32_t targetIndex = y * targetStride + 4 * x; 1.55 + uint32_t source1Index = y * source1Stride + 4 * x; 1.56 + uint32_t source2Index = y * source2Stride + 4 * x; 1.57 + uint32_t qa = source1Data[source1Index + B8G8R8A8_COMPONENT_BYTEOFFSET_A]; 1.58 + uint32_t qb = source2Data[source2Index + B8G8R8A8_COMPONENT_BYTEOFFSET_A]; 1.59 + for (int32_t i = std::min(B8G8R8A8_COMPONENT_BYTEOFFSET_B, B8G8R8A8_COMPONENT_BYTEOFFSET_R); 1.60 + i <= std::max(B8G8R8A8_COMPONENT_BYTEOFFSET_B, B8G8R8A8_COMPONENT_BYTEOFFSET_R); i++) { 1.61 + uint32_t ca = source1Data[source1Index + i]; 1.62 + uint32_t cb = source2Data[source2Index + i]; 1.63 + uint32_t val; 1.64 + switch (aBlendMode) { 1.65 + case BLEND_MODE_MULTIPLY: 1.66 + val = ((255 - qa) * cb + (255 - qb + cb) * ca); 1.67 + break; 1.68 + case BLEND_MODE_SCREEN: 1.69 + val = 255 * (cb + ca) - ca * cb; 1.70 + break; 1.71 + case BLEND_MODE_DARKEN: 1.72 + val = umin((255 - qa) * cb + 255 * ca, 1.73 + (255 - qb) * ca + 255 * cb); 1.74 + break; 1.75 + case BLEND_MODE_LIGHTEN: 1.76 + val = umax((255 - qa) * cb + 255 * ca, 1.77 + (255 - qb) * ca + 255 * cb); 1.78 + break; 1.79 + default: 1.80 + MOZ_CRASH(); 1.81 + } 1.82 + val = umin(FilterProcessing::FastDivideBy255<unsigned>(val), 255U); 1.83 + targetData[targetIndex + i] = static_cast<uint8_t>(val); 1.84 + } 1.85 + uint32_t alpha = 255 * 255 - (255 - qa) * (255 - qb); 1.86 + targetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A] = 1.87 + FilterProcessing::FastDivideBy255<uint8_t>(alpha); 1.88 + } 1.89 + } 1.90 + 1.91 + return target; 1.92 +} 1.93 + 1.94 +TemporaryRef<DataSourceSurface> 1.95 +FilterProcessing::ApplyBlending_Scalar(DataSourceSurface* aInput1, DataSourceSurface* aInput2, 1.96 + BlendMode aBlendMode) 1.97 +{ 1.98 + switch (aBlendMode) { 1.99 + case BLEND_MODE_MULTIPLY: 1.100 + return gfx::ApplyBlending_Scalar<BLEND_MODE_MULTIPLY>(aInput1, aInput2); 1.101 + case BLEND_MODE_SCREEN: 1.102 + return gfx::ApplyBlending_Scalar<BLEND_MODE_SCREEN>(aInput1, aInput2); 1.103 + case BLEND_MODE_DARKEN: 1.104 + return gfx::ApplyBlending_Scalar<BLEND_MODE_DARKEN>(aInput1, aInput2); 1.105 + case BLEND_MODE_LIGHTEN: 1.106 + return gfx::ApplyBlending_Scalar<BLEND_MODE_LIGHTEN>(aInput1, aInput2); 1.107 + default: 1.108 + return nullptr; 1.109 + } 1.110 +} 1.111 + 1.112 +template<MorphologyOperator Operator> 1.113 +static void 1.114 +ApplyMorphologyHorizontal_Scalar(uint8_t* aSourceData, int32_t aSourceStride, 1.115 + uint8_t* aDestData, int32_t aDestStride, 1.116 + const IntRect& aDestRect, int32_t aRadius) 1.117 +{ 1.118 + static_assert(Operator == MORPHOLOGY_OPERATOR_ERODE || 1.119 + Operator == MORPHOLOGY_OPERATOR_DILATE, 1.120 + "unexpected morphology operator"); 1.121 + 1.122 + for (int32_t y = aDestRect.y; y < aDestRect.YMost(); y++) { 1.123 + int32_t startX = aDestRect.x - aRadius; 1.124 + int32_t endX = aDestRect.x + aRadius; 1.125 + for (int32_t x = aDestRect.x; x < aDestRect.XMost(); x++, startX++, endX++) { 1.126 + int32_t sourceIndex = y * aSourceStride + 4 * startX; 1.127 + uint8_t u[4]; 1.128 + for (size_t i = 0; i < 4; i++) { 1.129 + u[i] = aSourceData[sourceIndex + i]; 1.130 + } 1.131 + sourceIndex += 4; 1.132 + for (int32_t ix = startX + 1; ix <= endX; ix++, sourceIndex += 4) { 1.133 + for (size_t i = 0; i < 4; i++) { 1.134 + if (Operator == MORPHOLOGY_OPERATOR_ERODE) { 1.135 + u[i] = umin(u[i], aSourceData[sourceIndex + i]); 1.136 + } else { 1.137 + u[i] = umax(u[i], aSourceData[sourceIndex + i]); 1.138 + } 1.139 + } 1.140 + } 1.141 + 1.142 + int32_t destIndex = y * aDestStride + 4 * x; 1.143 + for (size_t i = 0; i < 4; i++) { 1.144 + aDestData[destIndex+i] = u[i]; 1.145 + } 1.146 + } 1.147 + } 1.148 +} 1.149 + 1.150 +void 1.151 +FilterProcessing::ApplyMorphologyHorizontal_Scalar(uint8_t* aSourceData, int32_t aSourceStride, 1.152 + uint8_t* aDestData, int32_t aDestStride, 1.153 + const IntRect& aDestRect, int32_t aRadius, 1.154 + MorphologyOperator aOp) 1.155 +{ 1.156 + if (aOp == MORPHOLOGY_OPERATOR_ERODE) { 1.157 + gfx::ApplyMorphologyHorizontal_Scalar<MORPHOLOGY_OPERATOR_ERODE>( 1.158 + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); 1.159 + } else { 1.160 + gfx::ApplyMorphologyHorizontal_Scalar<MORPHOLOGY_OPERATOR_DILATE>( 1.161 + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); 1.162 + } 1.163 +} 1.164 + 1.165 +template<MorphologyOperator Operator> 1.166 +static void ApplyMorphologyVertical_Scalar(uint8_t* aSourceData, int32_t aSourceStride, 1.167 + uint8_t* aDestData, int32_t aDestStride, 1.168 + const IntRect& aDestRect, int32_t aRadius) 1.169 +{ 1.170 + static_assert(Operator == MORPHOLOGY_OPERATOR_ERODE || 1.171 + Operator == MORPHOLOGY_OPERATOR_DILATE, 1.172 + "unexpected morphology operator"); 1.173 + 1.174 + int32_t startY = aDestRect.y - aRadius; 1.175 + int32_t endY = aDestRect.y + aRadius; 1.176 + for (int32_t y = aDestRect.y; y < aDestRect.YMost(); y++, startY++, endY++) { 1.177 + for (int32_t x = aDestRect.x; x < aDestRect.XMost(); x++) { 1.178 + int32_t sourceIndex = startY * aSourceStride + 4 * x; 1.179 + uint8_t u[4]; 1.180 + for (size_t i = 0; i < 4; i++) { 1.181 + u[i] = aSourceData[sourceIndex + i]; 1.182 + } 1.183 + sourceIndex += aSourceStride; 1.184 + for (int32_t iy = startY + 1; iy <= endY; iy++, sourceIndex += aSourceStride) { 1.185 + for (size_t i = 0; i < 4; i++) { 1.186 + if (Operator == MORPHOLOGY_OPERATOR_ERODE) { 1.187 + u[i] = umin(u[i], aSourceData[sourceIndex + i]); 1.188 + } else { 1.189 + u[i] = umax(u[i], aSourceData[sourceIndex + i]); 1.190 + } 1.191 + } 1.192 + } 1.193 + 1.194 + int32_t destIndex = y * aDestStride + 4 * x; 1.195 + for (size_t i = 0; i < 4; i++) { 1.196 + aDestData[destIndex+i] = u[i]; 1.197 + } 1.198 + } 1.199 + } 1.200 +} 1.201 + 1.202 +void 1.203 +FilterProcessing::ApplyMorphologyVertical_Scalar(uint8_t* aSourceData, int32_t aSourceStride, 1.204 + uint8_t* aDestData, int32_t aDestStride, 1.205 + const IntRect& aDestRect, int32_t aRadius, 1.206 + MorphologyOperator aOp) 1.207 +{ 1.208 + if (aOp == MORPHOLOGY_OPERATOR_ERODE) { 1.209 + gfx::ApplyMorphologyVertical_Scalar<MORPHOLOGY_OPERATOR_ERODE>( 1.210 + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); 1.211 + } else { 1.212 + gfx::ApplyMorphologyVertical_Scalar<MORPHOLOGY_OPERATOR_DILATE>( 1.213 + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); 1.214 + } 1.215 +} 1.216 + 1.217 +TemporaryRef<DataSourceSurface> 1.218 +FilterProcessing::ApplyColorMatrix_Scalar(DataSourceSurface* aInput, const Matrix5x4 &aMatrix) 1.219 +{ 1.220 + return ApplyColorMatrix_SIMD<simd::Scalari32x4_t,simd::Scalari16x8_t,simd::Scalaru8x16_t>(aInput, aMatrix); 1.221 +} 1.222 + 1.223 +void 1.224 +FilterProcessing::ApplyComposition_Scalar(DataSourceSurface* aSource, DataSourceSurface* aDest, 1.225 + CompositeOperator aOperator) 1.226 +{ 1.227 + return ApplyComposition_SIMD<simd::Scalari32x4_t,simd::Scalaru16x8_t,simd::Scalaru8x16_t>(aSource, aDest, aOperator); 1.228 +} 1.229 + 1.230 +void 1.231 +FilterProcessing::SeparateColorChannels_Scalar(const IntSize &size, uint8_t* sourceData, int32_t sourceStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data, int32_t channelStride) 1.232 +{ 1.233 + for (int32_t y = 0; y < size.height; y++) { 1.234 + for (int32_t x = 0; x < size.width; x++) { 1.235 + int32_t sourceIndex = y * sourceStride + 4 * x; 1.236 + int32_t targetIndex = y * channelStride + x; 1.237 + channel0Data[targetIndex] = sourceData[sourceIndex]; 1.238 + channel1Data[targetIndex] = sourceData[sourceIndex+1]; 1.239 + channel2Data[targetIndex] = sourceData[sourceIndex+2]; 1.240 + channel3Data[targetIndex] = sourceData[sourceIndex+3]; 1.241 + } 1.242 + } 1.243 +} 1.244 + 1.245 +void 1.246 +FilterProcessing::CombineColorChannels_Scalar(const IntSize &size, int32_t resultStride, uint8_t* resultData, int32_t channelStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data) 1.247 +{ 1.248 + for (int32_t y = 0; y < size.height; y++) { 1.249 + for (int32_t x = 0; x < size.width; x++) { 1.250 + int32_t resultIndex = y * resultStride + 4 * x; 1.251 + int32_t channelIndex = y * channelStride + x; 1.252 + resultData[resultIndex] = channel0Data[channelIndex]; 1.253 + resultData[resultIndex+1] = channel1Data[channelIndex]; 1.254 + resultData[resultIndex+2] = channel2Data[channelIndex]; 1.255 + resultData[resultIndex+3] = channel3Data[channelIndex]; 1.256 + } 1.257 + } 1.258 +} 1.259 + 1.260 +void 1.261 +FilterProcessing::DoPremultiplicationCalculation_Scalar(const IntSize& aSize, 1.262 + uint8_t* aTargetData, int32_t aTargetStride, 1.263 + uint8_t* aSourceData, int32_t aSourceStride) 1.264 +{ 1.265 + for (int32_t y = 0; y < aSize.height; y++) { 1.266 + for (int32_t x = 0; x < aSize.width; x++) { 1.267 + int32_t inputIndex = y * aSourceStride + 4 * x; 1.268 + int32_t targetIndex = y * aTargetStride + 4 * x; 1.269 + uint8_t alpha = aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A]; 1.270 + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_R] = 1.271 + FastDivideBy255<uint8_t>(aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_R] * alpha); 1.272 + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_G] = 1.273 + FastDivideBy255<uint8_t>(aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_G] * alpha); 1.274 + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_B] = 1.275 + FastDivideBy255<uint8_t>(aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_B] * alpha); 1.276 + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A] = alpha; 1.277 + } 1.278 + } 1.279 +} 1.280 + 1.281 +void 1.282 +FilterProcessing::DoUnpremultiplicationCalculation_Scalar( 1.283 + const IntSize& aSize, 1.284 + uint8_t* aTargetData, int32_t aTargetStride, 1.285 + uint8_t* aSourceData, int32_t aSourceStride) 1.286 +{ 1.287 + for (int32_t y = 0; y < aSize.height; y++) { 1.288 + for (int32_t x = 0; x < aSize.width; x++) { 1.289 + int32_t inputIndex = y * aSourceStride + 4 * x; 1.290 + int32_t targetIndex = y * aTargetStride + 4 * x; 1.291 + uint8_t alpha = aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A]; 1.292 + uint16_t alphaFactor = sAlphaFactors[alpha]; 1.293 + // inputColor * alphaFactor + 128 is guaranteed to fit into uint16_t 1.294 + // because the input is premultiplied and thus inputColor <= inputAlpha. 1.295 + // The maximum value this can attain is 65520 (which is less than 65535) 1.296 + // for color == alpha == 244: 1.297 + // 244 * sAlphaFactors[244] + 128 == 244 * 268 + 128 == 65520 1.298 + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_R] = 1.299 + (aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_R] * alphaFactor + 128) >> 8; 1.300 + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_G] = 1.301 + (aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_G] * alphaFactor + 128) >> 8; 1.302 + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_B] = 1.303 + (aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_B] * alphaFactor + 128) >> 8; 1.304 + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A] = alpha; 1.305 + } 1.306 + } 1.307 +} 1.308 + 1.309 +TemporaryRef<DataSourceSurface> 1.310 +FilterProcessing::RenderTurbulence_Scalar(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency, 1.311 + int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect) 1.312 +{ 1.313 + return RenderTurbulence_SIMD<simd::Scalarf32x4_t,simd::Scalari32x4_t,simd::Scalaru8x16_t>( 1.314 + aSize, aOffset, aBaseFrequency, aSeed, aNumOctaves, aType, aStitch, aTileRect); 1.315 +} 1.316 + 1.317 +TemporaryRef<DataSourceSurface> 1.318 +FilterProcessing::ApplyArithmeticCombine_Scalar(DataSourceSurface* aInput1, DataSourceSurface* aInput2, Float aK1, Float aK2, Float aK3, Float aK4) 1.319 +{ 1.320 + return ApplyArithmeticCombine_SIMD<simd::Scalari32x4_t,simd::Scalari16x8_t,simd::Scalaru8x16_t>(aInput1, aInput2, aK1, aK2, aK3, aK4); 1.321 +} 1.322 + 1.323 +} // namespace mozilla 1.324 +} // namespace gfx