From 74698b456062c01d8dbc5c53842d69b84cb36310 Mon Sep 17 00:00:00 2001 From: Jeremy Andrews Date: Mon, 11 Oct 2021 18:04:47 -0500 Subject: [PATCH 01/40] Issue #3017 - Shadow boundaries not accounted for in nsFrameManager. --- dom/base/nsINode.h | 17 ++++ layout/base/nsFrameManager.cpp | 161 +++++++++++++++++++++++---------- layout/base/nsFrameManager.h | 4 +- 3 files changed, 131 insertions(+), 51 deletions(-) diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index 1599a0094f..1d580540f8 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -1652,6 +1652,9 @@ private: ParserHasNotified, // Sets if the node is apz aware or we have apz aware listeners. MayBeApzAware, + // Set if this node has at some point (and may still have) + // display:none or display:contents children. + NodeMayHaveChildrenWithLayoutBoxesDisabled, // Guard value BooleanFlagCount }; @@ -1790,6 +1793,20 @@ public: { return GetBoolFlag(MayBeApzAware); } + + void SetMayHaveChildrenWithLayoutBoxesDisabled() + { + SetBoolFlag(NodeMayHaveChildrenWithLayoutBoxesDisabled); + } + void UnsetMayHaveChildrenWithLayoutBoxesDisabled() + { + ClearBoolFlag(NodeMayHaveChildrenWithLayoutBoxesDisabled); + } + bool MayHaveChildrenWithLayoutBoxesDisabled() const + { + return GetBoolFlag(NodeMayHaveChildrenWithLayoutBoxesDisabled); + } + protected: void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); } void SetIsInDocument() { SetBoolFlag(IsInDocument); } diff --git a/layout/base/nsFrameManager.cpp b/layout/base/nsFrameManager.cpp index be8cd7147d..d6a6cb46b5 100644 --- a/layout/base/nsFrameManager.cpp +++ b/layout/base/nsFrameManager.cpp @@ -187,6 +187,17 @@ nsFrameManager::SetStyleContextInMap(UndisplayedMap* aMap, "undisplayed content must have a parent, unless it's the root " "element"); #endif + + // We set this bit as an optimization so that we can can know when a content + // node may have |display:none| or |display:contents| children. This allows + // other parts of the code to avoid checking for such children in + // mUndisplayedMap and mDisplayContentsMap if the bit isn't present on a node + // that it's handling. + +if (parent) { + parent->SetMayHaveChildrenWithLayoutBoxesDisabled(); +} + aMap->AddNodeFor(parent, aContent, aStyleContext); } @@ -212,7 +223,10 @@ nsFrameManager::ChangeStyleContextInMap(UndisplayedMap* aMap, printf("ChangeStyleContextInMap(%d): p=%p \n", i++, (void *)aContent); #endif - for (UndisplayedNode* node = aMap->GetFirstNode(aContent->GetParent()); + nsIContent* parent = aContent->GetParentElementCrossingShadowRoot(); + MOZ_ASSERT(parent || !aContent->GetParent(), "no non-elements"); + + for (UndisplayedNode* node = aMap->GetFirstNode(parent); node; node = node->getNext()) { if (node->mContent == aContent) { node->mStyle = aStyleContext; @@ -235,9 +249,20 @@ nsFrameManager::ClearUndisplayedContentIn(nsIContent* aContent, if (!mUndisplayedMap) { return; } + + if (aParentContent && + !aParentContent->MayHaveChildrenWithLayoutBoxesDisabled()) { + MOZ_ASSERT(!mUndisplayedMap->GetFirstNode(aParentContent), + "MayHaveChildrenWithLayoutBoxesDisabled bit out of sync - " + "may fail to removenode from mUndisplayedMap"); + return; + } - for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aParentContent); - node; node = node->getNext()) { + UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aParentContent); + + const bool haveOneDisplayNoneChild = node && !node->getNext(); + + for (; node; node = node->getNext()) { if (node->mContent == aContent) { mUndisplayedMap->RemoveNodeFor(aParentContent, node); @@ -247,6 +272,22 @@ nsFrameManager::ClearUndisplayedContentIn(nsIContent* aContent, // make sure that there are no more entries for the same content MOZ_ASSERT(!GetUndisplayedContent(aContent), "Found more undisplayed content data after removal"); + + if (haveOneDisplayNoneChild) { + // There are no more children of aParentContent in mUndisplayedMap. + MOZ_ASSERT(!mUndisplayedMap->GetFirstNode(aParentContent), + "Bad UnsetMayHaveChildrenWithLayoutBoxesDisabled call"); + // If we also know that none of its children are in mDisplayContentsMap + // then we can call UnsetMayHaveChildrenWithLayoutBoxesDisabled. We + // don't want to check mDisplayContentsMap though, since that involves + // a hash table lookup in relatively hot code. Still, we know there are + // no chlildren in mDisplayContentsMap if the map is empty, so we do + // check for that. + if (aParentContent && !mDisplayContentsMap) { + aParentContent->UnsetMayHaveChildrenWithLayoutBoxesDisabled(); + } + } + return; } } @@ -257,16 +298,44 @@ nsFrameManager::ClearUndisplayedContentIn(nsIContent* aContent, } void -nsFrameManager::ClearAllUndisplayedContentIn(nsIContent* aParentContent) +nsFrameManager::ClearAllMapsFor(nsIContent* aParentContent) { -#ifdef DEBUG_UNDISPLAYED_MAP +#if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_CONTENTS_MAP) static int i = 0; - printf("ClearAllUndisplayedContentIn(%d): parent=%p \n", i++, (void*)aParentContent); + printf("ClearAllMapsFor(%d): parent=%p \n", i++, (void*)aParentContent); #endif - if (mUndisplayedMap) { - mUndisplayedMap->RemoveNodesFor(aParentContent); + if (!aParentContent || + aParentContent->MayHaveChildrenWithLayoutBoxesDisabled()) { + if (mUndisplayedMap) { + mUndisplayedMap->RemoveNodesFor(aParentContent); + } + if (mDisplayContentsMap) { + nsAutoPtr> list = + mDisplayContentsMap->UnlinkNodesFor(aParentContent); + if (list) { + while (UndisplayedNode* node = list->popFirst()) { + ClearAllMapsFor(node->mContent); + delete node; + } + } + } + if (aParentContent) { + aParentContent->UnsetMayHaveChildrenWithLayoutBoxesDisabled(); + } } +#ifdef DEBUG + else { + if (mUndisplayedMap) { + MOZ_ASSERT(!mUndisplayedMap->GetFirstNode(aParentContent), + "We failed to remove a node from mUndisplayedMap"); + } + if (mDisplayContentsMap) { + MOZ_ASSERT(!mDisplayContentsMap->GetFirstNode(aParentContent), + "We failed to remove a node from mDisplayContentsMap"); + } + } +#endif // Need to look at aParentContent's content list due to XBL insertions. // Nodes in aParentContent's content list do not have aParentContent as a @@ -274,8 +343,10 @@ nsFrameManager::ClearAllUndisplayedContentIn(nsIContent* aParentContent) // the flattened content list and just ignore any nodes we don't care about. FlattenedChildIterator iter(aParentContent); for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { - if (child->GetParent() != aParentContent) { - ClearUndisplayedContentIn(child, child->GetParent()); + auto parent = child->GetParent(); + if (parent != aParentContent) { + ClearUndisplayedContentIn(child, parent); + ClearDisplayContentsIn(child, parent); } } } @@ -311,8 +382,19 @@ nsFrameManager::ClearDisplayContentsIn(nsIContent* aContent, return; } - for (UndisplayedNode* node = mDisplayContentsMap->GetFirstNode(aParentContent); - node; node = node->getNext()) { + if (aParentContent && + !aParentContent->MayHaveChildrenWithLayoutBoxesDisabled()) { + MOZ_ASSERT(!mDisplayContentsMap->GetFirstNode(aParentContent), + "MayHaveChildrenWithLayoutBoxesDisabled bit out of sync - " + "may fail to remove node from mDisplayContentsMap"); + return; + } + + UndisplayedNode* node = mDisplayContentsMap->GetFirstNode(aParentContent); + + const bool haveOneDisplayContentsChild = node && !node->getNext(); + + for (; node; node = node->getNext()) { if (node->mContent == aContent) { mDisplayContentsMap->RemoveNodeFor(aParentContent, node); @@ -322,8 +404,23 @@ nsFrameManager::ClearDisplayContentsIn(nsIContent* aContent, // make sure that there are no more entries for the same content MOZ_ASSERT(!GetDisplayContentsStyleFor(aContent), "Found more entries for aContent after removal"); - ClearAllDisplayContentsIn(aContent); - ClearAllUndisplayedContentIn(aContent); + ClearAllMapsFor(aContent); + + if (haveOneDisplayContentsChild) { + // There are no more children of aParentContent in mDisplayContentsMap. + MOZ_ASSERT(!mDisplayContentsMap->GetFirstNode(aParentContent), + "Bad UnsetMayHaveChildrenWithLayoutBoxesDisabled call"); + // If we also know that none of its children are in mUndisplayedMap + // then we can call UnsetMayHaveChildrenWithLayoutBoxesDisabled. We + // don't want to check mUndisplayedMap though since that involves a + // hash table lookup in relatively hot code. Still, we know there are + // no children in mUndisplayedMap if the map is empty, so we do + // check for that. + if (aParentContent && !mUndisplayedMap) { + aParentContent->UnsetMayHaveChildrenWithLayoutBoxesDisabled(); + } + } + return; } } @@ -332,39 +429,6 @@ nsFrameManager::ClearDisplayContentsIn(nsIContent* aContent, #endif } -void -nsFrameManager::ClearAllDisplayContentsIn(nsIContent* aParentContent) -{ -#ifdef DEBUG_DISPLAY_CONTENTS_MAP - static int i = 0; - printf("ClearAllDisplayContentsIn(%d): parent=%p \n", i++, (void*)aParentContent); -#endif - - if (mDisplayContentsMap) { - nsAutoPtr> list = - mDisplayContentsMap->UnlinkNodesFor(aParentContent); - if (list) { - while (UndisplayedNode* node = list->popFirst()) { - ClearAllDisplayContentsIn(node->mContent); - ClearAllUndisplayedContentIn(node->mContent); - delete node; - } - } - } - - // Need to look at aParentContent's content list due to XBL insertions. - // Nodes in aParentContent's content list do not have aParentContent as a - // parent, but are treated as children of aParentContent. We iterate over - // the flattened content list and just ignore any nodes we don't care about. - FlattenedChildIterator iter(aParentContent); - for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { - if (child->GetParent() != aParentContent) { - ClearDisplayContentsIn(child, child->GetParent()); - ClearUndisplayedContentIn(child, child->GetParent()); - } - } -} - //---------------------------------------------------------------------- void nsFrameManager::AppendFrames(nsContainerFrame* aParentFrame, @@ -441,8 +505,7 @@ nsFrameManager::NotifyDestroyingFrame(nsIFrame* aFrame) { nsIContent* content = aFrame->GetContent(); if (content && content->GetPrimaryFrame() == aFrame) { - ClearAllUndisplayedContentIn(content); - ClearAllDisplayContentsIn(content); + ClearAllMapsFor(content); } } diff --git a/layout/base/nsFrameManager.h b/layout/base/nsFrameManager.h index ae7477d3d3..7537888605 100644 --- a/layout/base/nsFrameManager.h +++ b/layout/base/nsFrameManager.h @@ -99,7 +99,6 @@ public: void ClearUndisplayedContentIn(nsIContent* aContent, nsIContent* aParentContent); - void ClearAllUndisplayedContentIn(nsIContent* aParentContent); // display:contents related methods: /** @@ -139,7 +138,6 @@ public: */ void ClearDisplayContentsIn(nsIContent* aContent, nsIContent* aParentContent); - void ClearAllDisplayContentsIn(nsIContent* aParentContent); // Functions for manipulating the frame model void AppendFrames(nsContainerFrame* aParentFrame, @@ -184,6 +182,8 @@ public: void RestoreFrameStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aState); protected: + void ClearAllMapsFor(nsIContent* aParentContent); + static nsStyleContext* GetStyleContextInMap(UndisplayedMap* aMap, const nsIContent* aContent); static mozilla::UndisplayedNode* From 72d9d1a476b0f9b77b73ea410f9a338394ba0bad Mon Sep 17 00:00:00 2001 From: Moonchild Date: Tue, 26 Oct 2021 11:15:59 +0000 Subject: [PATCH 02/40] Don't rely on nsCRT from jsdate. --- js/src/jsdate.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 21d2b476a5..dfd04e1305 100755 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -20,8 +20,6 @@ #include "mozilla/FloatingPoint.h" #include "mozilla/Sprintf.h" -#include "nsCRT.h" - #include #include #include @@ -932,6 +930,10 @@ ParseISOStyleDate(const CharT* s, size_t length, ClippedTime* result) #undef NEED_NDIGITS } +static bool IsAsciiDigit(char ch) { + return (uint8_t)(ch - '0') <= 9; +} + template static bool ParseDate(const CharT* s, size_t length, ClippedTime* result) @@ -967,7 +969,7 @@ ParseDate(const CharT* s, size_t length, ClippedTime* result) // Dashes are delimiters if they're immediately followed by a number field. // If they're not followed by a number field, they're simply ignored. if (c == '-') { - if (i < length && nsCRT::IsAsciiDigit(s[i])) { + if (i < length && IsAsciiDigit(s[i])) { prevc = c; } continue; @@ -989,7 +991,7 @@ ParseDate(const CharT* s, size_t length, ClippedTime* result) } // Parse a number field. - if (nsCRT::IsAsciiDigit(c)) { + if (IsAsciiDigit(c)) { int n = c - '0'; while (i < length && '0' <= (c = s[i]) && c <= '9') { n = n * 10 + c - '0'; From be7e9c26bb889778c382c551923ba3ab70467811 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 19 Nov 2021 00:00:15 -0500 Subject: [PATCH 03/40] Issue #3038 - Update libpixman --- gfx/cairo/libpixman/src/Makefile.in | 10 - .../libpixman/src/dither/blue-noise-64x64.h | 77 + .../libpixman/src/dither/make-blue-noise.c | 679 +++++ gfx/cairo/libpixman/src/loongson-mmintrin.h | 412 +++ gfx/cairo/libpixman/src/make-combine.pl | 86 - gfx/cairo/libpixman/src/meson.build | 129 + gfx/cairo/libpixman/src/moz.build | 11 +- gfx/cairo/libpixman/src/pixman-access.c | 297 +- gfx/cairo/libpixman/src/pixman-arm-asm.h | 37 + gfx/cairo/libpixman/src/pixman-arm-common.h | 27 +- .../libpixman/src/pixman-arm-detect-win32.asm | 21 - .../src/pixman-arm-neon-asm-bilinear.S | 12 +- gfx/cairo/libpixman/src/pixman-arm-neon-asm.S | 25 +- gfx/cairo/libpixman/src/pixman-arm-neon-asm.h | 30 +- gfx/cairo/libpixman/src/pixman-arm-neon.c | 65 +- .../src/pixman-arm-simd-asm-scaled.S | 11 +- gfx/cairo/libpixman/src/pixman-arm-simd-asm.S | 566 ++++ gfx/cairo/libpixman/src/pixman-arm-simd-asm.h | 122 +- gfx/cairo/libpixman/src/pixman-arm-simd.c | 50 +- gfx/cairo/libpixman/src/pixman-arm.c | 63 +- gfx/cairo/libpixman/src/pixman-bits-image.c | 1364 +++------ .../libpixman/src/pixman-combine-float.c | 368 ++- .../libpixman/src/pixman-combine.c.template | 2461 ---------------- .../libpixman/src/pixman-combine.h.template | 226 -- gfx/cairo/libpixman/src/pixman-combine16.c | 114 - gfx/cairo/libpixman/src/pixman-combine32.c | 1957 +++---------- gfx/cairo/libpixman/src/pixman-combine32.h | 2 +- gfx/cairo/libpixman/src/pixman-combine64.c | 2465 ----------------- gfx/cairo/libpixman/src/pixman-combine64.h | 230 -- gfx/cairo/libpixman/src/pixman-compiler.h | 14 +- .../libpixman/src/pixman-conical-gradient.c | 36 +- gfx/cairo/libpixman/src/pixman-cpu.c | 765 ----- gfx/cairo/libpixman/src/pixman-dither.h | 51 - gfx/cairo/libpixman/src/pixman-edge-imp.h | 5 +- gfx/cairo/libpixman/src/pixman-fast-path.c | 1306 +++++++-- gfx/cairo/libpixman/src/pixman-fast-path.h | 1022 ------- gfx/cairo/libpixman/src/pixman-filter.c | 244 +- gfx/cairo/libpixman/src/pixman-general.c | 163 +- gfx/cairo/libpixman/src/pixman-glyph.c | 6 + .../libpixman/src/pixman-gradient-walker.c | 174 +- gfx/cairo/libpixman/src/pixman-image.c | 159 +- .../libpixman/src/pixman-implementation.c | 132 +- gfx/cairo/libpixman/src/pixman-inlines.h | 160 +- .../libpixman/src/pixman-linear-gradient.c | 204 +- gfx/cairo/libpixman/src/pixman-matrix.c | 4 +- .../libpixman/src/pixman-mips-dspr2-asm.S | 1324 +++++++-- .../libpixman/src/pixman-mips-dspr2-asm.h | 54 +- gfx/cairo/libpixman/src/pixman-mips-dspr2.c | 58 +- gfx/cairo/libpixman/src/pixman-mips-dspr2.h | 50 +- gfx/cairo/libpixman/src/pixman-mmx.c | 261 +- gfx/cairo/libpixman/src/pixman-noop.c | 189 +- gfx/cairo/libpixman/src/pixman-private.h | 196 +- .../libpixman/src/pixman-radial-gradient.c | 382 +-- gfx/cairo/libpixman/src/pixman-region.c | 22 +- gfx/cairo/libpixman/src/pixman-solid-fill.c | 8 +- gfx/cairo/libpixman/src/pixman-sse2.c | 506 ++-- gfx/cairo/libpixman/src/pixman-ssse3.c | 351 +++ gfx/cairo/libpixman/src/pixman-utils.c | 27 +- gfx/cairo/libpixman/src/pixman-version.h | 10 +- gfx/cairo/libpixman/src/pixman-version.h.in | 54 + gfx/cairo/libpixman/src/pixman-vmx.c | 1706 +++++++++++- .../libpixman/src/pixman-x64-mmx-emulation.h | 263 -- gfx/cairo/libpixman/src/pixman-x86.c | 16 +- gfx/cairo/libpixman/src/pixman.c | 42 +- gfx/cairo/libpixman/src/pixman.h | 331 ++- gfx/cairo/libpixman/src/refactor | 478 ---- gfx/cairo/libpixman/src/solaris-hwcap.mapfile | 30 + 67 files changed, 9392 insertions(+), 13328 deletions(-) delete mode 100644 gfx/cairo/libpixman/src/Makefile.in create mode 100644 gfx/cairo/libpixman/src/dither/blue-noise-64x64.h create mode 100644 gfx/cairo/libpixman/src/dither/make-blue-noise.c create mode 100644 gfx/cairo/libpixman/src/loongson-mmintrin.h delete mode 100644 gfx/cairo/libpixman/src/make-combine.pl create mode 100644 gfx/cairo/libpixman/src/meson.build create mode 100644 gfx/cairo/libpixman/src/pixman-arm-asm.h delete mode 100644 gfx/cairo/libpixman/src/pixman-arm-detect-win32.asm delete mode 100644 gfx/cairo/libpixman/src/pixman-combine.c.template delete mode 100644 gfx/cairo/libpixman/src/pixman-combine.h.template delete mode 100644 gfx/cairo/libpixman/src/pixman-combine16.c delete mode 100644 gfx/cairo/libpixman/src/pixman-combine64.c delete mode 100644 gfx/cairo/libpixman/src/pixman-combine64.h delete mode 100644 gfx/cairo/libpixman/src/pixman-cpu.c delete mode 100644 gfx/cairo/libpixman/src/pixman-dither.h delete mode 100644 gfx/cairo/libpixman/src/pixman-fast-path.h create mode 100644 gfx/cairo/libpixman/src/pixman-ssse3.c create mode 100644 gfx/cairo/libpixman/src/pixman-version.h.in delete mode 100644 gfx/cairo/libpixman/src/pixman-x64-mmx-emulation.h delete mode 100644 gfx/cairo/libpixman/src/refactor create mode 100644 gfx/cairo/libpixman/src/solaris-hwcap.mapfile diff --git a/gfx/cairo/libpixman/src/Makefile.in b/gfx/cairo/libpixman/src/Makefile.in deleted file mode 100644 index f119333b44..0000000000 --- a/gfx/cairo/libpixman/src/Makefile.in +++ /dev/null @@ -1,10 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -include $(topsrcdir)/config/rules.mk - -# The ARM asm functions here don't appreciate being called by functions -# compiled with -mapcs-frame. See bug 832752. -CXXFLAGS := $(filter-out -mapcs-frame,$(CXXFLAGS)) -CFLAGS := $(filter-out -mapcs-frame,$(CFLAGS)) diff --git a/gfx/cairo/libpixman/src/dither/blue-noise-64x64.h b/gfx/cairo/libpixman/src/dither/blue-noise-64x64.h new file mode 100644 index 0000000000..93c8805b51 --- /dev/null +++ b/gfx/cairo/libpixman/src/dither/blue-noise-64x64.h @@ -0,0 +1,77 @@ +/* WARNING: This file is generated by make-blue-noise.c + * Please edit that file instead of this one. + */ + +#ifndef BLUE_NOISE_64X64_H +#define BLUE_NOISE_64X64_H + +#include + +static const uint16_t dither_blue_noise_64x64[4096] = { + 3039, 1368, 3169, 103, 2211, 1248, 2981, 668, 2633, 37, 3963, 2903, 384, 2564, 3115, 1973, 3348, 830, 2505, 1293, 3054, 1060, 1505, 3268, 400, 1341, 593, 3802, 3384, 429, 4082, 1411, 2503, 3863, 126, 1292, 1887, 2855, 205, 2094, 2977, 1899, 3924, 356, 3088, 2500, 3942, 1409, 2293, 1734, 3732, 1291, 3227, 277, 2054, 786, 2871, 411, 2425, 1678, 3986, 455, 2879, 2288, + 388, 1972, 3851, 778, 2768, 3697, 944, 2123, 1501, 3533, 937, 1713, 1381, 3888, 156, 1242, 516, 2888, 1607, 3676, 632, 2397, 3804, 2673, 1898, 3534, 2593, 1777, 1170, 2299, 3013, 1838, 523, 3053, 1647, 3601, 3197, 959, 1520, 3633, 893, 2437, 3367, 2187, 1258, 137, 1965, 401, 3546, 643, 3087, 2498, 733, 2786, 3371, 4053, 1266, 1977, 3663, 183, 2570, 2107, 1183, 3708, + 907, 2473, 1151, 3363, 1527, 1902, 232, 3903, 3060, 496, 2486, 3206, 2165, 861, 2387, 3653, 2101, 3972, 132, 2162, 3437, 1827, 215, 895, 3114, 271, 969, 2932, 197, 1598, 878, 3696, 1140, 2120, 904, 2431, 302, 3846, 2675, 481, 3187, 66, 1440, 650, 3833, 2826, 3435, 901, 2936, 2111, 250, 1875, 3609, 1174, 1747, 162, 2346, 3420, 913, 3172, 1383, 752, 3298, 1735, + 3540, 2938, 249, 2324, 526, 3099, 2561, 1324, 2347, 1861, 1200, 3702, 257, 3442, 1514, 2999, 992, 1766, 2735, 1163, 478, 2943, 1279, 3635, 2177, 1464, 3672, 2386, 3871, 3340, 2690, 64, 3489, 2811, 3999, 633, 1948, 1243, 2269, 1807, 1143, 2750, 3729, 1790, 2363, 1053, 1537, 2636, 4065, 1076, 1476, 3869, 450, 2200, 2676, 658, 2979, 1548, 544, 1913, 2838, 3911, 116, 2698, + 517, 1295, 3997, 1739, 3665, 1083, 3509, 599, 3400, 118, 2956, 720, 2689, 1907, 567, 2523, 284, 3397, 711, 3219, 2450, 3985, 1665, 2549, 562, 3011, 1855, 729, 1355, 528, 1908, 2456, 1384, 337, 1540, 2654, 3138, 3513, 703, 4080, 3314, 2047, 855, 3037, 209, 3317, 577, 1828, 17, 2336, 3193, 2748, 962, 3441, 1450, 3246, 1075, 3878, 2615, 3497, 1033, 2310, 1442, 2183, + 1654, 3254, 2061, 738, 2832, 148, 2030, 1670, 909, 3850, 2109, 1533, 4046, 1085, 3098, 3897, 1378, 2248, 3829, 1495, 1966, 23, 797, 3427, 1124, 4057, 95, 2787, 2190, 3074, 3950, 742, 3194, 1999, 3386, 1113, 16, 1657, 2804, 201, 1543, 383, 2559, 1325, 3604, 2068, 2493, 3771, 1284, 3460, 710, 1716, 2447, 80, 3811, 2032, 347, 2227, 15, 1689, 397, 3084, 662, 3798, + 973, 43, 2608, 3143, 1459, 2423, 4066, 2770, 3191, 1283, 2630, 314, 3235, 2289, 72, 1822, 2840, 924, 350, 2653, 1057, 3715, 2235, 2775, 346, 2083, 1553, 3292, 1081, 274, 1686, 1188, 2327, 3743, 578, 2234, 3916, 2519, 1011, 3056, 2207, 3438, 3890, 537, 1617, 837, 3094, 373, 2795, 1980, 276, 3951, 1353, 3015, 844, 1724, 3651, 2923, 1316, 4092, 2504, 3627, 1936, 2854, + 2461, 3929, 1193, 421, 3746, 820, 1180, 286, 2261, 532, 3625, 1812, 802, 1327, 3527, 670, 3730, 2025, 3124, 3565, 529, 2960, 1769, 1390, 3196, 2494, 3756, 796, 3618, 2602, 3463, 2847, 166, 953, 1745, 2900, 438, 2070, 1418, 3741, 639, 1205, 1891, 2882, 2282, 4012, 1182, 1696, 3630, 951, 2904, 2170, 3530, 375, 2320, 2742, 1132, 701, 3216, 2023, 847, 1230, 310, 3431, + 770, 1961, 3531, 1702, 2181, 3370, 1877, 3072, 1571, 3389, 1071, 2415, 3782, 2803, 1610, 2454, 1211, 182, 1655, 2322, 1282, 3372, 287, 3935, 704, 1232, 415, 1910, 2286, 1399, 556, 1964, 4068, 2444, 3605, 1272, 3345, 816, 3526, 256, 2402, 2777, 955, 345, 3289, 111, 2727, 635, 2396, 1488, 3331, 600, 1032, 1575, 4026, 515, 3507, 2433, 1605, 460, 3364, 2783, 1810, 1397, + 2334, 223, 2945, 688, 2533, 99, 2705, 624, 3944, 2073, 46, 2978, 508, 2132, 269, 3173, 3453, 2631, 4076, 694, 1892, 2586, 972, 2178, 3470, 1695, 2849, 3141, 77, 3884, 994, 3029, 1536, 673, 3083, 124, 2583, 1722, 2821, 1944, 4027, 1661, 3176, 3728, 1337, 1813, 3503, 2035, 3930, 157, 2537, 1865, 3096, 2646, 1941, 3252, 1449, 135, 2836, 3758, 2139, 84, 3678, 3106, + 3862, 1545, 3307, 1320, 3955, 1031, 3664, 1306, 2460, 776, 1487, 3294, 1187, 3990, 1903, 1021, 549, 1484, 943, 3027, 97, 3853, 1499, 2880, 198, 2575, 3995, 1089, 1587, 2475, 3282, 339, 2657, 1158, 2105, 1493, 3943, 580, 3232, 1287, 846, 48, 2480, 2112, 771, 2534, 459, 3134, 850, 1298, 3790, 325, 3652, 1249, 193, 940, 2202, 3895, 1829, 911, 1366, 2577, 1069, 534, + 2104, 1009, 2667, 392, 1983, 2917, 1645, 324, 3439, 2869, 3705, 1767, 2592, 756, 2916, 3683, 2276, 2850, 2053, 3594, 2403, 3181, 634, 3699, 1933, 906, 519, 2150, 3673, 764, 1770, 2220, 3795, 3336, 502, 3547, 2339, 1110, 301, 2210, 3354, 3643, 569, 1518, 2940, 3973, 1138, 1613, 2773, 2127, 2983, 1671, 769, 2161, 3800, 2730, 3127, 1179, 533, 3259, 2284, 4014, 1651, 2820, + 3566, 653, 1839, 3455, 2399, 789, 3149, 2244, 1863, 1099, 474, 2307, 158, 3541, 1312, 1711, 0, 3902, 360, 1629, 1091, 395, 1781, 1191, 2374, 3353, 1419, 3225, 206, 2931, 3553, 1046, 54, 1646, 2470, 910, 1860, 3137, 3770, 2635, 1562, 2809, 1215, 3788, 222, 2199, 3335, 67, 3606, 524, 1001, 3309, 2410, 3473, 591, 1619, 291, 2502, 3629, 2891, 335, 741, 3378, 168, + 2384, 3129, 4051, 22, 1444, 3613, 543, 3893, 186, 2665, 4062, 933, 3058, 2142, 449, 2711, 3224, 849, 1330, 3349, 2195, 2670, 3484, 2993, 32, 3774, 2722, 1859, 2548, 1268, 583, 2027, 3165, 2807, 4029, 227, 2897, 1434, 721, 1816, 195, 905, 2066, 3258, 1754, 970, 2674, 1880, 2338, 3915, 1485, 2660, 14, 1313, 2914, 2046, 4074, 791, 1917, 1301, 1725, 2687, 2019, 1443, + 418, 1186, 1664, 2859, 1049, 2056, 2741, 1226, 1589, 3186, 2042, 1377, 3449, 1574, 3941, 1063, 1930, 2501, 3751, 2930, 671, 4031, 888, 2081, 1544, 684, 1117, 351, 4052, 1698, 2393, 3881, 1439, 785, 1277, 2013, 3488, 441, 2459, 3980, 3061, 3481, 2543, 419, 3020, 609, 3515, 1350, 799, 2878, 348, 2034, 3966, 1824, 950, 3281, 1394, 2239, 3452, 55, 3922, 3119, 892, 3785, + 3023, 2140, 782, 2492, 3817, 241, 3355, 2424, 856, 3639, 612, 2556, 245, 2858, 705, 2316, 3562, 495, 1748, 128, 1912, 1454, 280, 2552, 3905, 3130, 2274, 3472, 834, 3055, 240, 2692, 471, 2272, 3301, 2632, 1080, 3693, 2136, 1029, 1364, 590, 1611, 4067, 1190, 2360, 3827, 261, 3180, 1768, 3471, 1103, 3003, 520, 3674, 151, 2571, 555, 3033, 982, 2353, 504, 1259, 2555, + 149, 3889, 3380, 493, 3178, 1681, 663, 1924, 2990, 49, 1792, 3861, 1192, 1987, 3273, 297, 1457, 3043, 1177, 2292, 3249, 2829, 3682, 1154, 1758, 428, 2872, 1993, 1500, 3703, 1129, 3421, 1840, 3754, 163, 659, 1733, 3182, 38, 2875, 1957, 3614, 2237, 78, 1873, 2801, 1513, 2121, 1074, 2516, 667, 3710, 1429, 2430, 2088, 2830, 1072, 3557, 1531, 2733, 1955, 3286, 3590, 1826, + 2778, 1068, 1932, 1452, 2279, 1185, 3564, 3952, 1391, 2726, 3313, 2331, 870, 3709, 1674, 2772, 4085, 808, 2596, 3848, 927, 538, 2335, 3334, 773, 3597, 1347, 109, 2663, 608, 2108, 2994, 936, 1524, 2922, 3968, 2422, 1467, 845, 3870, 321, 2704, 1073, 3308, 3680, 823, 430, 3375, 4030, 112, 2171, 2695, 267, 3374, 731, 1627, 3919, 1871, 352, 3839, 1370, 234, 794, 1532, + 3245, 647, 3575, 74, 3045, 2766, 285, 2174, 498, 1059, 1551, 385, 3125, 2598, 143, 1128, 2095, 3395, 318, 1590, 3524, 1345, 1969, 242, 2759, 2092, 947, 3926, 3244, 2356, 1658, 6, 3593, 2554, 1172, 1995, 371, 2755, 3417, 2294, 1570, 3164, 748, 2517, 1401, 3111, 2420, 1662, 2910, 1276, 3276, 854, 1804, 4000, 1253, 2987, 229, 2344, 3184, 649, 2196, 2921, 4095, 2389, + 1289, 2193, 2579, 4023, 757, 1858, 986, 3199, 2514, 3475, 4021, 2154, 651, 1432, 3468, 2404, 574, 1799, 3105, 2145, 86, 2614, 3218, 1565, 4088, 2481, 3079, 1815, 323, 1212, 3837, 759, 2159, 435, 3223, 784, 3659, 1114, 1888, 550, 1221, 3786, 1803, 499, 2117, 185, 3763, 942, 589, 2001, 3838, 1483, 3154, 2256, 468, 2544, 3403, 898, 1208, 2610, 3622, 967, 1929, 378, + 3781, 220, 1656, 1115, 3347, 2428, 3822, 1577, 712, 1959, 110, 2765, 1762, 3854, 979, 2928, 3714, 1371, 746, 3969, 2884, 975, 3779, 641, 1142, 159, 1460, 702, 3485, 2866, 2495, 3330, 1305, 3937, 1635, 2229, 2962, 146, 4055, 3091, 2417, 100, 3508, 2933, 4006, 1167, 1920, 2760, 3552, 2545, 433, 2845, 142, 1056, 1886, 3616, 1435, 2099, 3803, 1749, 27, 1446, 3350, 2843, + 884, 3310, 2948, 2103, 447, 1351, 187, 2895, 3655, 1256, 3036, 932, 3325, 2257, 451, 1915, 40, 2780, 2438, 1112, 1814, 423, 2290, 1905, 2898, 3419, 2306, 3760, 1938, 486, 1019, 1791, 3010, 2628, 203, 3408, 1269, 2507, 1606, 862, 2779, 2078, 952, 1529, 2638, 708, 3332, 1413, 2, 1726, 1156, 3500, 2392, 3791, 3076, 812, 107, 2861, 501, 3050, 3487, 2455, 594, 1731, + 2685, 1498, 680, 3908, 2621, 3529, 1786, 2236, 342, 2569, 1526, 3722, 230, 1290, 3203, 3947, 1609, 3516, 467, 3267, 3685, 1461, 3140, 3569, 367, 1759, 928, 2754, 1332, 2219, 4034, 260, 655, 1984, 978, 3814, 617, 2086, 3525, 279, 3841, 1373, 3361, 319, 2251, 3066, 407, 2382, 3918, 3133, 2168, 762, 1523, 507, 2641, 1677, 4025, 2413, 1584, 793, 2049, 1109, 3962, 2218, + 1194, 3692, 266, 1687, 981, 3103, 740, 3983, 1005, 3434, 570, 2383, 1942, 2718, 676, 2462, 1007, 2089, 1308, 2222, 233, 2568, 829, 1241, 2669, 3987, 514, 3303, 69, 3142, 1603, 3560, 2295, 3288, 1497, 2696, 1764, 2865, 1058, 3271, 1914, 477, 2529, 3927, 1736, 1273, 3752, 2029, 1012, 565, 2798, 4078, 1949, 3305, 1175, 2179, 380, 3366, 1195, 3849, 2637, 416, 2959, 125, + 3396, 2467, 2036, 3234, 2340, 68, 2819, 1436, 2011, 3139, 1704, 4073, 860, 3582, 1468, 2969, 211, 3157, 4056, 866, 2935, 2000, 3923, 31, 2157, 1477, 2429, 1147, 3792, 2557, 774, 2802, 1153, 3747, 464, 3192, 42, 3904, 539, 1474, 2283, 803, 2876, 1061, 75, 3477, 747, 2893, 1538, 3626, 251, 1322, 2506, 189, 2791, 3667, 939, 2991, 1971, 175, 3195, 1416, 3648, 1857, + 3052, 454, 851, 3789, 1271, 1906, 3694, 2484, 406, 2757, 26, 1189, 2909, 296, 2215, 3784, 1864, 637, 2715, 1673, 3445, 581, 1572, 3059, 3469, 761, 2984, 1737, 2058, 440, 1414, 1921, 121, 2527, 894, 2223, 1302, 2377, 3077, 2666, 3759, 3198, 1811, 3661, 2166, 2731, 1883, 359, 3285, 2458, 1805, 3459, 926, 3834, 675, 1893, 1496, 2612, 657, 3523, 1763, 2354, 564, 961, + 1367, 3977, 1588, 2714, 322, 3446, 1088, 625, 3887, 1354, 3535, 2090, 3316, 1760, 1127, 483, 3491, 1421, 2301, 94, 1202, 3740, 2311, 1014, 1878, 3836, 180, 3412, 991, 2868, 3953, 3450, 3081, 1632, 4071, 1882, 3543, 726, 1719, 179, 1171, 364, 1420, 622, 3090, 1490, 946, 4007, 2212, 1102, 619, 2739, 2189, 1669, 2937, 3426, 39, 3940, 2191, 1264, 887, 4091, 2792, 2135, + 4, 2883, 2281, 631, 3044, 1641, 2232, 3243, 1773, 2319, 827, 2591, 629, 3938, 2426, 3222, 2629, 1044, 3879, 3293, 1952, 2749, 275, 2590, 472, 1372, 2496, 660, 3669, 2264, 208, 915, 2167, 561, 2828, 307, 3265, 1104, 3964, 2155, 3425, 1951, 4077, 2391, 283, 3387, 2581, 115, 1415, 3069, 3896, 141, 3158, 1214, 442, 2405, 1349, 3085, 425, 2528, 3002, 312, 1602, 3588, + 1137, 3323, 1963, 1002, 3578, 2521, 127, 925, 2970, 273, 3737, 1573, 167, 2863, 1509, 800, 147, 2059, 2942, 409, 921, 3151, 1451, 3909, 3333, 2844, 2096, 1512, 3136, 1210, 1798, 2709, 1331, 3586, 1034, 1521, 2441, 2926, 488, 2585, 775, 3031, 2693, 879, 3602, 1173, 2028, 3654, 2781, 841, 1975, 1507, 3646, 768, 3991, 2012, 996, 3544, 1666, 3810, 1990, 3360, 753, 2597, + 3736, 304, 1473, 3828, 485, 1334, 4008, 2072, 3495, 1136, 2806, 2004, 3236, 1010, 2130, 3819, 1750, 3567, 644, 2515, 1794, 3636, 698, 2137, 1162, 832, 3761, 326, 2613, 513, 3302, 3820, 357, 3163, 2259, 3733, 101, 1922, 1386, 3587, 1640, 28, 1286, 2141, 1761, 2918, 693, 1639, 457, 3250, 2434, 365, 2599, 1729, 3284, 2643, 306, 2793, 689, 1090, 104, 1309, 2305, 1831, + 2776, 859, 2446, 2915, 1778, 3337, 2677, 614, 1508, 2409, 469, 4033, 1321, 3563, 402, 3131, 2720, 1093, 1569, 4042, 1229, 2277, 216, 3046, 1817, 57, 3006, 1684, 4059, 2016, 795, 2440, 1652, 1960, 610, 2763, 920, 3864, 3110, 1026, 2326, 3762, 3233, 521, 3856, 173, 2457, 3939, 2138, 1262, 3572, 989, 3021, 2238, 119, 1445, 3832, 1809, 2297, 3467, 2700, 3684, 3102, 394, + 4036, 2050, 3256, 89, 2198, 1079, 248, 1845, 3805, 3104, 880, 1779, 2688, 717, 2373, 1375, 262, 2249, 3071, 13, 2813, 3429, 1600, 3984, 2416, 3603, 1299, 2298, 998, 3492, 1393, 2951, 10, 4009, 1247, 3462, 1679, 2204, 414, 2736, 316, 1894, 2816, 1050, 3373, 1462, 3107, 817, 3464, 21, 1835, 4070, 568, 1178, 3718, 875, 3168, 466, 2974, 1458, 2084, 616, 1564, 1018, + 1693, 546, 1244, 3899, 716, 3160, 3608, 2877, 1220, 334, 3443, 2270, 44, 3000, 1843, 3928, 3405, 766, 3686, 2040, 587, 993, 2647, 387, 930, 2753, 630, 3274, 150, 2808, 453, 3638, 1092, 2352, 3030, 239, 2562, 700, 3240, 1257, 4016, 730, 1515, 2203, 2551, 417, 1866, 1123, 2348, 2902, 1550, 2678, 2075, 3238, 1630, 2531, 2115, 1255, 4054, 840, 290, 3874, 2477, 3399, + 2250, 3577, 2817, 1626, 2576, 1356, 2315, 792, 2087, 2618, 1612, 3855, 1263, 3637, 1036, 494, 1535, 2553, 1198, 1715, 3867, 3170, 1359, 1954, 3483, 1539, 2069, 3886, 1772, 2487, 1534, 2045, 3242, 806, 1578, 2018, 3948, 1423, 3596, 2076, 2466, 3424, 139, 3688, 871, 4049, 2852, 3342, 547, 3719, 327, 852, 3505, 207, 2794, 542, 3600, 45, 2411, 3324, 1788, 3012, 1235, 61, + 2655, 917, 253, 1986, 3738, 313, 1706, 4072, 120, 3229, 957, 597, 2024, 3262, 2453, 2857, 2002, 3190, 210, 2784, 2206, 300, 2400, 3766, 553, 3152, 218, 1150, 2988, 883, 3753, 627, 2664, 3831, 437, 3385, 1008, 2957, 60, 1636, 891, 2899, 1776, 3062, 1315, 2026, 194, 1643, 2079, 1296, 3201, 2465, 1379, 1927, 3898, 1125, 1847, 2846, 1552, 1028, 2725, 2169, 787, 3202, + 1441, 3982, 3032, 1052, 3251, 605, 2639, 3073, 1431, 3642, 2329, 2949, 341, 1634, 833, 129, 4020, 916, 3571, 669, 1506, 3411, 821, 2856, 1207, 2337, 2683, 3448, 340, 2214, 3128, 235, 1738, 1288, 2833, 2419, 606, 1884, 2668, 552, 3765, 1176, 399, 2302, 596, 3591, 2634, 767, 3845, 2767, 995, 3967, 491, 3057, 814, 2300, 3422, 691, 3797, 254, 3645, 509, 3478, 1836, + 2119, 475, 2445, 1525, 2175, 3539, 914, 1926, 473, 1157, 1800, 3971, 2701, 3739, 2129, 3486, 1333, 1784, 2366, 2982, 1070, 4089, 1802, 73, 1642, 3958, 835, 1837, 1480, 4043, 1217, 2469, 3416, 2113, 88, 3668, 1240, 3255, 3920, 2355, 3167, 2003, 2645, 3936, 3228, 1592, 1144, 3474, 2394, 79, 1820, 2241, 1594, 3656, 2584, 153, 1448, 3034, 2005, 2511, 1692, 1335, 3913, 217, + 2822, 3391, 745, 3813, 192, 1274, 2941, 3847, 2489, 3440, 744, 161, 1422, 1086, 572, 3004, 2617, 338, 3807, 2031, 236, 2472, 3065, 2098, 3358, 362, 2163, 3574, 497, 2788, 1970, 948, 3885, 685, 3100, 1712, 2228, 292, 1408, 1016, 164, 3537, 1417, 941, 34, 2172, 3001, 358, 1491, 3147, 699, 3356, 258, 1149, 2946, 1787, 3931, 382, 1146, 3291, 818, 2890, 2379, 1096, + 3679, 1328, 1901, 3162, 2747, 1730, 2253, 5, 1556, 2818, 2093, 3166, 2522, 3410, 2287, 1701, 956, 3237, 620, 1596, 3300, 1307, 511, 3701, 1020, 2939, 1362, 2532, 3208, 749, 3641, 160, 1522, 2624, 1095, 4086, 826, 2841, 3583, 2173, 1727, 723, 2925, 1911, 2482, 3726, 863, 1962, 4028, 1111, 2835, 3773, 2449, 2022, 582, 3278, 923, 2619, 2152, 4039, 92, 1934, 3145, 677, + 2530, 53, 2303, 1003, 458, 3989, 739, 3321, 1064, 369, 3556, 877, 1900, 426, 3876, 1, 3617, 2106, 1197, 2805, 3634, 857, 2706, 1504, 2418, 682, 3868, 20, 1139, 1688, 2333, 3311, 2907, 1945, 265, 2385, 3433, 1601, 636, 2620, 3095, 4044, 386, 3382, 1184, 527, 2814, 3414, 2342, 465, 1889, 1343, 874, 3479, 1502, 2233, 3689, 1385, 559, 2745, 1463, 3465, 376, 1718, + 3217, 4045, 1580, 3612, 2525, 1228, 3018, 1958, 3725, 2358, 1361, 3996, 1581, 3063, 1224, 2737, 1475, 2442, 3946, 191, 1796, 2128, 3975, 134, 1916, 3318, 1597, 2071, 3749, 2672, 403, 1278, 602, 3745, 3220, 1374, 445, 2064, 3830, 243, 1252, 2390, 1563, 2724, 3875, 1818, 1346, 165, 1650, 3264, 2680, 117, 2998, 4081, 343, 2799, 9, 3122, 1743, 3724, 1040, 2231, 3842, 1209, + 900, 398, 2851, 697, 1797, 3482, 293, 2679, 1649, 566, 2954, 91, 2697, 714, 2060, 3211, 781, 480, 3040, 1038, 2611, 666, 2989, 3458, 1201, 2796, 548, 2975, 839, 3121, 1850, 4001, 2208, 1631, 790, 2558, 2972, 1148, 3213, 1849, 3624, 971, 2102, 108, 772, 3101, 2589, 3777, 1042, 656, 3907, 2097, 1615, 2540, 805, 1935, 1231, 3494, 2451, 268, 2995, 750, 2682, 2020, + 3024, 1392, 2124, 3279, 106, 2217, 1387, 822, 3214, 3825, 2160, 1000, 2395, 3691, 228, 4038, 1872, 3413, 1608, 2225, 3536, 303, 1653, 886, 2541, 224, 4037, 2252, 1428, 172, 3504, 958, 2848, 113, 3628, 1834, 3979, 19, 2317, 779, 2797, 518, 3174, 3549, 1482, 2266, 444, 2014, 3555, 2439, 1213, 3113, 535, 1135, 3204, 3858, 2309, 931, 623, 2009, 3359, 1566, 140, 3550, + 1808, 3872, 2488, 1152, 3764, 2892, 3960, 2412, 353, 1223, 1825, 3444, 3116, 1717, 1082, 2313, 1280, 2661, 82, 3852, 1389, 3200, 2330, 3812, 2038, 3581, 1728, 1039, 3339, 2427, 586, 2580, 1238, 3328, 2280, 1047, 595, 2662, 1363, 3338, 1620, 3934, 2497, 1881, 1054, 3954, 3215, 864, 2887, 1801, 320, 3519, 2378, 3704, 1753, 424, 2958, 1660, 4005, 2601, 1116, 3912, 2381, 573, + 2740, 200, 828, 1667, 432, 1931, 1035, 1616, 3598, 2640, 728, 264, 1437, 557, 3501, 2966, 372, 3734, 974, 1978, 758, 2719, 1145, 452, 1433, 725, 2681, 408, 3843, 1918, 1547, 3906, 1996, 503, 1456, 3019, 3493, 1700, 3742, 355, 2134, 176, 1311, 615, 2867, 315, 1680, 1314, 8, 3297, 1494, 783, 1950, 83, 2656, 1382, 3561, 138, 2834, 1404, 330, 1904, 3156, 1027, + 1357, 3381, 3041, 3666, 2729, 734, 3415, 177, 3051, 2021, 4079, 2823, 3775, 2186, 2616, 869, 1668, 3148, 2367, 3315, 393, 4075, 1870, 2920, 3343, 2362, 3188, 1303, 2782, 825, 3171, 259, 2905, 3717, 2538, 184, 2074, 838, 2860, 2407, 1024, 3496, 3008, 3706, 1985, 2349, 3623, 2582, 4058, 2184, 2694, 3873, 2964, 990, 3346, 690, 2033, 1066, 2201, 3490, 2971, 718, 3700, 2188, + 4061, 391, 1989, 2325, 1430, 3150, 2125, 2526, 592, 1403, 976, 2351, 1165, 1851, 114, 3921, 2063, 613, 1358, 2785, 1623, 2254, 25, 3542, 1045, 246, 1852, 3554, 87, 2243, 3615, 1169, 727, 1705, 968, 3957, 3185, 1251, 500, 4063, 1751, 2622, 842, 1519, 90, 3393, 819, 490, 1874, 999, 571, 1275, 2271, 1586, 4040, 2448, 3126, 3731, 436, 885, 1708, 2421, 24, 1599, + 889, 2563, 1199, 645, 70, 4013, 1237, 3723, 1694, 3499, 3, 3266, 484, 2997, 3390, 1233, 2842, 3687, 152, 3480, 1084, 3698, 881, 2490, 1542, 3992, 2209, 692, 1690, 3022, 1470, 2625, 2114, 3512, 2359, 381, 2684, 1897, 3368, 1395, 3080, 289, 2065, 3981, 2758, 1141, 3097, 1472, 2870, 3352, 3707, 225, 3159, 505, 1895, 214, 1222, 1774, 2686, 3978, 3275, 1196, 3518, 2825, + 3270, 1720, 3796, 3466, 2650, 1841, 298, 899, 2862, 2091, 2671, 1744, 3735, 801, 1560, 349, 2262, 903, 1833, 2524, 512, 3117, 1793, 2827, 476, 3038, 1216, 2550, 3826, 980, 431, 4048, 35, 2992, 1265, 1595, 765, 3675, 76, 2247, 696, 3456, 1254, 2452, 664, 1757, 2133, 3750, 145, 2332, 1554, 1981, 3580, 2712, 868, 3640, 2919, 638, 2275, 1427, 309, 2595, 2006, 492, + 2226, 178, 2911, 836, 1528, 3028, 2240, 3327, 404, 3970, 707, 1294, 2464, 2131, 4032, 2600, 3319, 1406, 2913, 3974, 2156, 1425, 221, 3877, 2017, 811, 3662, 272, 3287, 1988, 2408, 3357, 1746, 598, 3239, 3823, 2182, 2934, 1078, 2604, 3840, 1697, 2906, 413, 3210, 3880, 331, 2644, 1260, 848, 3042, 2535, 1077, 1438, 3261, 2365, 1561, 3799, 85, 3082, 1876, 674, 3932, 1101, + 3644, 1344, 1943, 2401, 390, 3835, 1048, 2572, 1541, 1133, 3075, 3584, 308, 2889, 1065, 1869, 601, 3783, 282, 1181, 736, 3312, 2368, 1126, 3383, 1675, 2734, 1426, 628, 2873, 1317, 843, 2717, 2048, 1004, 2536, 333, 1782, 3295, 1517, 219, 2153, 815, 3502, 1579, 2268, 987, 3409, 1780, 4018, 354, 665, 3914, 47, 1956, 456, 1006, 2010, 3406, 1130, 3621, 2894, 1549, 3092, + 2485, 640, 3993, 3179, 1270, 3436, 585, 1925, 3757, 2304, 136, 1976, 1486, 646, 3520, 50, 3155, 1637, 2435, 3522, 1937, 2756, 3748, 661, 2224, 58, 3230, 2357, 1830, 3892, 170, 3607, 1447, 3949, 190, 3392, 1336, 584, 4010, 918, 3016, 3670, 1155, 2406, 52, 1304, 3009, 607, 2085, 2699, 3205, 1848, 2291, 3402, 2764, 3865, 3048, 2508, 735, 2710, 443, 2341, 897, 263, + 1785, 2769, 983, 56, 2197, 1685, 2703, 202, 2944, 810, 3377, 2626, 3787, 3047, 2055, 1236, 2752, 2122, 945, 3093, 96, 1624, 439, 3014, 1388, 4015, 977, 448, 3506, 1098, 2242, 3026, 506, 2361, 2952, 1862, 3619, 2790, 1992, 2483, 525, 1868, 2652, 4093, 1998, 3595, 2478, 3816, 122, 1412, 929, 3716, 1166, 1648, 813, 1300, 199, 1489, 3998, 1771, 1310, 3808, 2052, 3423, + 434, 3712, 1625, 3558, 2955, 853, 4019, 1348, 3511, 1732, 1246, 487, 934, 1672, 2510, 3965, 788, 3711, 396, 1369, 4090, 1055, 2603, 1879, 3528, 2518, 2067, 3005, 1516, 2588, 751, 1740, 3418, 1131, 1576, 686, 2296, 1118, 18, 3263, 1365, 3401, 294, 737, 3177, 410, 867, 1633, 2963, 3579, 2375, 252, 2881, 479, 2471, 3576, 2180, 3306, 332, 2255, 3035, 41, 2648, 1396, + 2929, 2230, 1219, 2512, 446, 2008, 3189, 2388, 626, 2164, 2831, 4047, 2376, 174, 3272, 368, 1469, 3226, 2578, 1991, 2874, 2263, 3681, 876, 188, 1239, 683, 3776, 226, 3183, 4083, 2148, 63, 2649, 3859, 299, 3086, 3933, 1585, 2185, 3767, 988, 1707, 2908, 1407, 1844, 2771, 2245, 1161, 560, 1755, 3376, 2051, 4064, 3135, 1832, 652, 2853, 1051, 3649, 760, 3290, 1105, 3945, + 872, 154, 3207, 713, 3780, 1453, 281, 1087, 3695, 30, 3299, 1919, 1400, 3551, 1119, 1890, 2314, 618, 1703, 3428, 724, 295, 3146, 1557, 3341, 2896, 1683, 2723, 1974, 1017, 541, 1380, 3720, 804, 3280, 2082, 997, 2567, 777, 2961, 213, 2707, 2328, 3632, 1025, 3891, 3304, 255, 4003, 3108, 2587, 1323, 743, 1479, 105, 1013, 3901, 1618, 2044, 2627, 1465, 1846, 576, 1994, + 2560, 3521, 1742, 2118, 2800, 3404, 1783, 2609, 2968, 1582, 1022, 412, 2713, 687, 2976, 3857, 2761, 3620, 62, 1108, 3844, 1340, 2100, 540, 2345, 3925, 405, 3457, 1319, 2468, 3362, 2815, 1867, 2372, 1281, 1714, 3690, 482, 3498, 1842, 1285, 3994, 558, 2039, 81, 2499, 678, 1481, 1923, 964, 12, 3824, 2980, 2205, 2762, 3432, 2398, 181, 3247, 462, 4094, 2350, 3589, 3089, + 1555, 1094, 4041, 247, 1267, 908, 3959, 2041, 732, 3860, 2343, 3132, 3769, 2144, 1621, 237, 912, 1329, 3025, 2146, 2642, 1775, 3721, 2746, 1121, 1953, 902, 2285, 130, 3671, 1659, 278, 3153, 522, 2721, 123, 2996, 1466, 2380, 377, 3231, 873, 1510, 3476, 3123, 1250, 2147, 3650, 2839, 3451, 2323, 1122, 3545, 379, 1765, 1218, 603, 3768, 1360, 938, 2885, 133, 1245, 363, + 2364, 554, 2743, 3344, 2474, 530, 3112, 169, 1297, 3430, 536, 1741, 98, 1043, 2574, 3253, 2246, 1854, 4022, 510, 3283, 204, 858, 3398, 36, 3118, 1478, 3794, 2986, 706, 2176, 922, 3559, 1097, 3976, 3322, 2149, 1160, 2810, 3883, 2007, 2513, 2953, 328, 1721, 3793, 422, 2566, 807, 329, 1638, 1967, 648, 2520, 3727, 3109, 2116, 2927, 2491, 1939, 3365, 1709, 2728, 3815, + 2037, 3120, 831, 1405, 1896, 3592, 1622, 2369, 2864, 2151, 1107, 2542, 3532, 1410, 3917, 427, 3568, 709, 2509, 1503, 1037, 2973, 2436, 1604, 4035, 2594, 563, 1819, 2659, 1234, 4004, 2565, 1511, 2273, 1823, 336, 882, 3772, 575, 1628, 171, 3570, 1120, 2260, 2716, 935, 3064, 1806, 1342, 3144, 3900, 2744, 3296, 985, 1546, 238, 896, 1663, 305, 3660, 695, 2213, 960, 3407, + 144, 1795, 3894, 2267, 51, 2708, 1023, 3818, 366, 1821, 4087, 2985, 755, 2057, 2912, 949, 1583, 2774, 231, 3447, 2258, 3866, 1982, 672, 1225, 2077, 3320, 1062, 370, 3241, 1968, 7, 3068, 681, 3631, 2573, 1567, 3175, 2321, 1067, 3070, 722, 1856, 3744, 642, 1471, 4084, 131, 3514, 2443, 531, 1227, 155, 2265, 4024, 2658, 3326, 3910, 1168, 3078, 1530, 3956, 489, 1424, + 3647, 1203, 420, 2924, 3755, 719, 3248, 1376, 3067, 890, 196, 1559, 3269, 270, 2432, 1885, 3212, 1164, 3778, 1752, 579, 1338, 344, 3585, 3017, 288, 3658, 2371, 3882, 1691, 611, 2789, 3809, 1339, 389, 2950, 2015, 59, 3548, 2751, 2158, 4011, 1352, 29, 3388, 2370, 2812, 1946, 954, 2110, 1558, 2947, 3573, 1909, 1326, 679, 1853, 2312, 551, 2702, 33, 2414, 3209, 2824, + 2547, 2143, 3379, 966, 1492, 1979, 2479, 463, 2194, 3657, 2738, 2318, 1261, 3713, 604, 4002, 11, 2192, 2967, 919, 2607, 3369, 2837, 1676, 2539, 984, 1568, 93, 2901, 1318, 3538, 1041, 2216, 1756, 3454, 1030, 4050, 1402, 798, 1723, 311, 3277, 2546, 2886, 2043, 461, 1206, 3677, 361, 3260, 3988, 809, 2605, 470, 3007, 3517, 102, 3221, 1398, 2062, 3611, 1134, 1928, 865, + 4060, 621, 1710, 2606, 3510, 317, 4017, 1682, 3329, 1159, 1940, 654, 3461, 1789, 1015, 2691, 1455, 3599, 374, 1947, 4069, 71, 2126, 763, 3961, 2278, 3161, 1997, 824, 2623, 2080, 244, 3257, 780, 2732, 2308, 545, 3351, 2476, 3806, 1204, 588, 1591, 963, 3610, 1699, 754, 3049, 2651, 1106, 65, 2221, 1644, 3821, 1100, 2463, 1614, 3801, 965, 2965, 715, 3394, 1593, 212, +}; + +#endif /* BLUE_NOISE_64X64_H */ diff --git a/gfx/cairo/libpixman/src/dither/make-blue-noise.c b/gfx/cairo/libpixman/src/dither/make-blue-noise.c new file mode 100644 index 0000000000..f9974b4d44 --- /dev/null +++ b/gfx/cairo/libpixman/src/dither/make-blue-noise.c @@ -0,0 +1,679 @@ +/* Blue noise generation using the void-and-cluster method as described in + * + * The void-and-cluster method for dither array generation + * Ulichney, Robert A (1993) + * + * http://cv.ulichney.com/papers/1993-void-cluster.pdf + * + * Note that running with openmp (-DUSE_OPENMP) will trigger additional + * randomness due to computing reductions in parallel, and is not recommended + * unless generating very large dither arrays. + */ + +#include +#include +#include +#include +#include + +/* Booleans and utility functions */ + +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +typedef int bool_t; + +int +imin (int x, int y) +{ + return x < y ? x : y; +} + +/* Memory allocation */ +void * +malloc_abc (unsigned int a, unsigned int b, unsigned int c) +{ + if (a >= INT32_MAX / b) + return NULL; + else if (a * b >= INT32_MAX / c) + return NULL; + else + return malloc (a * b * c); +} + +/* Random number generation */ +typedef uint32_t xorwow_state_t[5]; + +uint32_t +xorwow_next (xorwow_state_t *state) +{ + uint32_t s = (*state)[0], + t = (*state)[3]; + (*state)[3] = (*state)[2]; + (*state)[2] = (*state)[1]; + (*state)[1] = s; + + t ^= t >> 2; + t ^= t << 1; + t ^= s ^ (s << 4); + + (*state)[0] = t; + (*state)[4] += 362437; + + return t + (*state)[4]; +} + +float +xorwow_float (xorwow_state_t *s) +{ + return (xorwow_next (s) >> 9) / (float)((1 << 23) - 1); +} + +/* Floating point matrices + * + * Used to cache the cluster sizes. + */ +typedef struct matrix_t { + int width; + int height; + float *buffer; +} matrix_t; + +bool_t +matrix_init (matrix_t *matrix, int width, int height) +{ + float *buffer; + + if (!matrix) + return FALSE; + + buffer = malloc_abc (width, height, sizeof (float)); + + if (!buffer) + return FALSE; + + matrix->buffer = buffer; + matrix->width = width; + matrix->height = height; + + return TRUE; +} + +bool_t +matrix_copy (matrix_t *dst, matrix_t const *src) +{ + float *srcbuf = src->buffer, + *srcend = src->buffer + src->width * src->height, + *dstbuf = dst->buffer; + + if (dst->width != src->width || dst->height != src->height) + return FALSE; + + while (srcbuf < srcend) + *dstbuf++ = *srcbuf++; + + return TRUE; +} + +float * +matrix_get (matrix_t *matrix, int x, int y) +{ + return &matrix->buffer[y * matrix->width + x]; +} + +void +matrix_destroy (matrix_t *matrix) +{ + free (matrix->buffer); +} + +/* Binary patterns */ +typedef struct pattern_t { + int width; + int height; + bool_t *buffer; +} pattern_t; + +bool_t +pattern_init (pattern_t *pattern, int width, int height) +{ + bool_t *buffer; + + if (!pattern) + return FALSE; + + buffer = malloc_abc (width, height, sizeof (bool_t)); + + if (!buffer) + return FALSE; + + pattern->buffer = buffer; + pattern->width = width; + pattern->height = height; + + return TRUE; +} + +bool_t +pattern_copy (pattern_t *dst, pattern_t const *src) +{ + bool_t *srcbuf = src->buffer, + *srcend = src->buffer + src->width * src->height, + *dstbuf = dst->buffer; + + if (dst->width != src->width || dst->height != src->height) + return FALSE; + + while (srcbuf < srcend) + *dstbuf++ = *srcbuf++; + + return TRUE; +} + +bool_t * +pattern_get (pattern_t *pattern, int x, int y) +{ + return &pattern->buffer[y * pattern->width + x]; +} + +void +pattern_fill_white_noise (pattern_t *pattern, float fraction, + xorwow_state_t *s) +{ + bool_t *buffer = pattern->buffer; + bool_t *end = buffer + (pattern->width * pattern->height); + + while (buffer < end) + *buffer++ = xorwow_float (s) < fraction; +} + +void +pattern_destroy (pattern_t *pattern) +{ + free (pattern->buffer); +} + +/* Dither arrays */ +typedef struct array_t { + int width; + int height; + uint32_t *buffer; +} array_t; + +bool_t +array_init (array_t *array, int width, int height) +{ + uint32_t *buffer; + + if (!array) + return FALSE; + + buffer = malloc_abc (width, height, sizeof (uint32_t)); + + if (!buffer) + return FALSE; + + array->buffer = buffer; + array->width = width; + array->height = height; + + return TRUE; +} + +uint32_t * +array_get (array_t *array, int x, int y) +{ + return &array->buffer[y * array->width + x]; +} + +bool_t +array_save_ppm (array_t *array, const char *filename) +{ + FILE *f = fopen(filename, "wb"); + + int i = 0; + int bpp = 2; + uint8_t buffer[1024]; + + if (!f) + return FALSE; + + if (array->width * array->height - 1 < 256) + bpp = 1; + + fprintf(f, "P5 %d %d %d\n", array->width, array->height, + array->width * array->height - 1); + while (i < array->width * array->height) + { + int j = 0; + for (; j < 1024 / bpp && j < array->width * array->height; ++j) + { + uint32_t v = array->buffer[i + j]; + if (bpp == 2) + { + buffer[2 * j] = v & 0xff; + buffer[2 * j + 1] = (v & 0xff00) >> 8; + } else { + buffer[j] = v; + } + } + + fwrite((void *)buffer, bpp, j, f); + i += j; + } + + if (fclose(f) != 0) + return FALSE; + + return TRUE; +} + +bool_t +array_save (array_t *array, const char *filename) +{ + int x, y; + FILE *f = fopen(filename, "wb"); + + if (!f) + return FALSE; + + fprintf (f, +"/* WARNING: This file is generated by make-blue-noise.c\n" +" * Please edit that file instead of this one.\n" +" */\n" +"\n" +"#ifndef BLUE_NOISE_%dX%d_H\n" +"#define BLUE_NOISE_%dX%d_H\n" +"\n" +"#include \n" +"\n", array->width, array->height, array->width, array->height); + + fprintf (f, "static const uint16_t dither_blue_noise_%dx%d[%d] = {\n", + array->width, array->height, array->width * array->height); + + for (y = 0; y < array->height; ++y) + { + fprintf (f, " "); + for (x = 0; x < array->width; ++x) + { + if (x != 0) + fprintf (f, ", "); + + fprintf (f, "%d", *array_get (array, x, y)); + } + + fprintf (f, ",\n"); + } + fprintf (f, "};\n"); + + fprintf (f, "\n#endif /* BLUE_NOISE_%dX%d_H */\n", + array->width, array->height); + + if (fclose(f) != 0) + return FALSE; + + return TRUE; +} + +void +array_destroy (array_t *array) +{ + free (array->buffer); +} + +/* Dither array generation */ +bool_t +compute_cluster_sizes (pattern_t *pattern, matrix_t *matrix) +{ + int width = pattern->width, + height = pattern->height; + + if (matrix->width != width || matrix->height != height) + return FALSE; + + int px, py, qx, qy, dx, dy; + float tsqsi = 2.f * 1.5f * 1.5f; + +#ifdef USE_OPENMP +#pragma omp parallel for default (none) \ + private (py, px, qy, qx, dx, dy) \ + shared (height, width, pattern, matrix, tsqsi) +#endif + for (py = 0; py < height; ++py) + { + for (px = 0; px < width; ++px) + { + bool_t pixel = *pattern_get (pattern, px, py); + float dist = 0.f; + + for (qx = 0; qx < width; ++qx) + { + dx = imin (abs (qx - px), width - abs (qx - px)); + dx = dx * dx; + + for (qy = 0; qy < height; ++qy) + { + dy = imin (abs (qy - py), height - abs (qy - py)); + dy = dy * dy; + + dist += (pixel == *pattern_get (pattern, qx, qy)) + * expf (- (dx + dy) / tsqsi); + } + } + + *matrix_get (matrix, px, py) = dist; + } + } + + return TRUE; +} + +bool_t +swap_pixel (pattern_t *pattern, matrix_t *matrix, int x, int y) +{ + int width = pattern->width, + height = pattern->height; + + bool_t new; + + float f, + dist = 0.f, + tsqsi = 2.f * 1.5f * 1.5f; + + int px, py, dx, dy; + bool_t b; + + new = !*pattern_get (pattern, x, y); + *pattern_get (pattern, x, y) = new; + + if (matrix->width != width || matrix->height != height) + return FALSE; + + +#ifdef USE_OPENMP +#pragma omp parallel for reduction (+:dist) default (none) \ + private (px, py, dx, dy, b, f) \ + shared (x, y, width, height, pattern, matrix, new, tsqsi) +#endif + for (py = 0; py < height; ++py) + { + dy = imin (abs (py - y), height - abs (py - y)); + dy = dy * dy; + + for (px = 0; px < width; ++px) + { + dx = imin (abs (px - x), width - abs (px - x)); + dx = dx * dx; + + b = (*pattern_get (pattern, px, py) == new); + f = expf (- (dx + dy) / tsqsi); + *matrix_get (matrix, px, py) += (2 * b - 1) * f; + + dist += b * f; + } + } + + *matrix_get (matrix, x, y) = dist; + return TRUE; +} + +void +largest_cluster (pattern_t *pattern, matrix_t *matrix, + bool_t pixel, int *xmax, int *ymax) +{ + int width = pattern->width, + height = pattern->height; + + int x, y; + + float vmax = -INFINITY; + +#ifdef USE_OPENMP +#pragma omp parallel default (none) \ + private (x, y) \ + shared (height, width, pattern, matrix, pixel, xmax, ymax, vmax) +#endif + { + int xbest = -1, + ybest = -1; + +#ifdef USE_OPENMP + float vbest = -INFINITY; + +#pragma omp for reduction (max: vmax) collapse (2) +#endif + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + if (*pattern_get (pattern, x, y) != pixel) + continue; + + if (*matrix_get (matrix, x, y) > vmax) + { + vmax = *matrix_get (matrix, x, y); +#ifdef USE_OPENMP + vbest = vmax; +#endif + xbest = x; + ybest = y; + } + } + } + +#ifdef USE_OPENMP +#pragma omp barrier +#pragma omp critical + { + if (vmax == vbest) + { + *xmax = xbest; + *ymax = ybest; + } + } +#else + *xmax = xbest; + *ymax = ybest; +#endif + } + + assert (vmax > -INFINITY); +} + +void +generate_initial_binary_pattern (pattern_t *pattern, matrix_t *matrix) +{ + int xcluster = 0, + ycluster = 0, + xvoid = 0, + yvoid = 0; + + for (;;) + { + largest_cluster (pattern, matrix, TRUE, &xcluster, &ycluster); + assert (*pattern_get (pattern, xcluster, ycluster) == TRUE); + swap_pixel (pattern, matrix, xcluster, ycluster); + + largest_cluster (pattern, matrix, FALSE, &xvoid, &yvoid); + assert (*pattern_get (pattern, xvoid, yvoid) == FALSE); + swap_pixel (pattern, matrix, xvoid, yvoid); + + if (xcluster == xvoid && ycluster == yvoid) + return; + } +} + +bool_t +generate_dither_array (array_t *array, + pattern_t const *prototype, matrix_t const *matrix, + pattern_t *temp_pattern, matrix_t *temp_matrix) +{ + int width = prototype->width, + height = prototype->height; + + int x, y, rank; + + int initial_rank = 0; + + if (array->width != width || array->height != height) + return FALSE; + + // Make copies of the prototype and associated sizes matrix since we will + // trash them + if (!pattern_copy (temp_pattern, prototype)) + return FALSE; + + if (!matrix_copy (temp_matrix, matrix)) + return FALSE; + + // Compute initial rank + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + if (*pattern_get (temp_pattern, x, y)) + initial_rank += 1; + + *array_get (array, x, y) = 0; + } + } + + // Phase 1 + for (rank = initial_rank; rank > 0; --rank) + { + largest_cluster (temp_pattern, temp_matrix, TRUE, &x, &y); + swap_pixel (temp_pattern, temp_matrix, x, y); + *array_get (array, x, y) = rank - 1; + } + + // Make copies again for phases 2 & 3 + if (!pattern_copy (temp_pattern, prototype)) + return FALSE; + + if (!matrix_copy (temp_matrix, matrix)) + return FALSE; + + // Phase 2 & 3 + for (rank = initial_rank; rank < width * height; ++rank) + { + largest_cluster (temp_pattern, temp_matrix, FALSE, &x, &y); + swap_pixel (temp_pattern, temp_matrix, x, y); + *array_get (array, x, y) = rank; + } + + return TRUE; +} + +bool_t +generate (int size, xorwow_state_t *s, + char const *c_filename, char const *ppm_filename) +{ + bool_t ok = TRUE; + + pattern_t prototype, temp_pattern; + array_t array; + matrix_t matrix, temp_matrix; + + printf ("Generating %dx%d blue noise...\n", size, size); + + if (!pattern_init (&prototype, size, size)) + return FALSE; + + if (!pattern_init (&temp_pattern, size, size)) + { + pattern_destroy (&prototype); + return FALSE; + } + + if (!matrix_init (&matrix, size, size)) + { + pattern_destroy (&temp_pattern); + pattern_destroy (&prototype); + return FALSE; + } + + if (!matrix_init (&temp_matrix, size, size)) + { + matrix_destroy (&matrix); + pattern_destroy (&temp_pattern); + pattern_destroy (&prototype); + return FALSE; + } + + if (!array_init (&array, size, size)) + { + matrix_destroy (&temp_matrix); + matrix_destroy (&matrix); + pattern_destroy (&temp_pattern); + pattern_destroy (&prototype); + return FALSE; + } + + printf("Filling initial binary pattern with white noise...\n"); + pattern_fill_white_noise (&prototype, .1, s); + + printf("Initializing cluster sizes...\n"); + if (!compute_cluster_sizes (&prototype, &matrix)) + { + fprintf (stderr, "Error while computing cluster sizes\n"); + ok = FALSE; + goto out; + } + + printf("Generating initial binary pattern...\n"); + generate_initial_binary_pattern (&prototype, &matrix); + + printf("Generating dither array...\n"); + if (!generate_dither_array (&array, &prototype, &matrix, + &temp_pattern, &temp_matrix)) + { + fprintf (stderr, "Error while generating dither array\n"); + ok = FALSE; + goto out; + } + + printf("Saving dither array...\n"); + if (!array_save (&array, c_filename)) + { + fprintf (stderr, "Error saving dither array\n"); + ok = FALSE; + goto out; + } + +#if SAVE_PPM + if (!array_save_ppm (&array, ppm_filename)) + { + fprintf (stderr, "Error saving dither array PPM\n"); + ok = FALSE; + goto out; + } +#else + (void)ppm_filename; +#endif + + printf("All done!\n"); + +out: + array_destroy (&array); + matrix_destroy (&temp_matrix); + matrix_destroy (&matrix); + pattern_destroy (&temp_pattern); + pattern_destroy (&prototype); + return ok; +} + +int +main (void) +{ + xorwow_state_t s = {1185956906, 12385940, 983948, 349208051, 901842}; + + if (!generate (64, &s, "blue-noise-64x64.h", "blue-noise-64x64.ppm")) + return -1; + + return 0; +} diff --git a/gfx/cairo/libpixman/src/loongson-mmintrin.h b/gfx/cairo/libpixman/src/loongson-mmintrin.h new file mode 100644 index 0000000000..0e79e86484 --- /dev/null +++ b/gfx/cairo/libpixman/src/loongson-mmintrin.h @@ -0,0 +1,412 @@ +/* The gcc-provided loongson intrinsic functions are way too fucking broken + * to be of any use, otherwise I'd use them. + * + * - The hardware instructions are very similar to MMX or iwMMXt. Certainly + * close enough that they could have implemented the _mm_*-style intrinsic + * interface and had a ton of optimized code available to them. Instead they + * implemented something much, much worse. + * + * - pshuf takes a dead first argument, causing extra instructions to be + * generated. + * + * - There are no 64-bit shift or logical intrinsics, which means you have + * to implement them with inline assembly, but this is a nightmare because + * gcc doesn't understand that the integer vector datatypes are actually in + * floating-point registers, so you end up with braindead code like + * + * punpcklwd $f9,$f9,$f5 + * dmtc1 v0,$f8 + * punpcklwd $f19,$f19,$f5 + * dmfc1 t9,$f9 + * dmtc1 v0,$f9 + * dmtc1 t9,$f20 + * dmfc1 s0,$f19 + * punpcklbh $f20,$f20,$f2 + * + * where crap just gets copied back and forth between integer and floating- + * point registers ad nauseum. + * + * Instead of trying to workaround the problems from these crap intrinsics, I + * just implement the _mm_* intrinsics needed for pixman-mmx.c using inline + * assembly. + */ + +#include + +/* vectors are stored in 64-bit floating-point registers */ +typedef double __m64; +/* having a 32-bit datatype allows us to use 32-bit loads in places like load8888 */ +typedef float __m32; + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_setzero_si64 (void) +{ + return 0.0; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_add_pi16 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("paddh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_add_pi32 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("paddw %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_adds_pu16 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("paddush %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_adds_pu8 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("paddusb %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_and_si64 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("and %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_cmpeq_pi32 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("pcmpeqw %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_empty (void) +{ + +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_madd_pi16 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("pmaddhw %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mulhi_pu16 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("pmulhuh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mullo_pi16 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("pmullh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_or_si64 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("or %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_packs_pu16 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("packushb %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_packs_pi32 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("packsswh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +#define _MM_SHUFFLE(fp3,fp2,fp1,fp0) \ + (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | (fp0)) +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_set_pi16 (uint16_t __w3, uint16_t __w2, uint16_t __w1, uint16_t __w0) +{ + if (__builtin_constant_p (__w3) && + __builtin_constant_p (__w2) && + __builtin_constant_p (__w1) && + __builtin_constant_p (__w0)) + { + uint64_t val = ((uint64_t)__w3 << 48) + | ((uint64_t)__w2 << 32) + | ((uint64_t)__w1 << 16) + | ((uint64_t)__w0 << 0); + return *(__m64 *)&val; + } + else if (__w3 == __w2 && __w2 == __w1 && __w1 == __w0) + { + /* TODO: handle other cases */ + uint64_t val = __w3; + uint64_t imm = _MM_SHUFFLE (0, 0, 0, 0); + __m64 ret; + asm("pshufh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (*(__m64 *)&val), "f" (*(__m64 *)&imm) + ); + return ret; + } else { + uint64_t val = ((uint64_t)__w3 << 48) + | ((uint64_t)__w2 << 32) + | ((uint64_t)__w1 << 16) + | ((uint64_t)__w0 << 0); + return *(__m64 *)&val; + } +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_set_pi32 (unsigned __i1, unsigned __i0) +{ + if (__builtin_constant_p (__i1) && + __builtin_constant_p (__i0)) + { + uint64_t val = ((uint64_t)__i1 << 32) + | ((uint64_t)__i0 << 0); + return *(__m64 *)&val; + } + else if (__i1 == __i0) + { + uint64_t imm = _MM_SHUFFLE (1, 0, 1, 0); + __m64 ret; + asm("pshufh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (*(__m32 *)&__i1), "f" (*(__m64 *)&imm) + ); + return ret; + } else { + uint64_t val = ((uint64_t)__i1 << 32) + | ((uint64_t)__i0 << 0); + return *(__m64 *)&val; + } +} +#undef _MM_SHUFFLE + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_shuffle_pi16 (__m64 __m, int64_t __n) +{ + __m64 ret; + asm("pshufh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m), "f" (*(__m64 *)&__n) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_slli_pi16 (__m64 __m, int64_t __count) +{ + __m64 ret; + asm("psllh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m), "f" (*(__m64 *)&__count) + ); + return ret; +} +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_slli_si64 (__m64 __m, int64_t __count) +{ + __m64 ret; + asm("dsll %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m), "f" (*(__m64 *)&__count) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_srli_pi16 (__m64 __m, int64_t __count) +{ + __m64 ret; + asm("psrlh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m), "f" (*(__m64 *)&__count) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_srli_pi32 (__m64 __m, int64_t __count) +{ + __m64 ret; + asm("psrlw %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m), "f" (*(__m64 *)&__count) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_srli_si64 (__m64 __m, int64_t __count) +{ + __m64 ret; + asm("dsrl %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m), "f" (*(__m64 *)&__count) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_sub_pi16 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("psubh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_unpackhi_pi8 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("punpckhbh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_unpackhi_pi16 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("punpckhhw %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_unpacklo_pi8 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("punpcklbh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +/* Since punpcklbh doesn't care about the high 32-bits, we use the __m32 datatype which + * allows load8888 to use 32-bit loads */ +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_unpacklo_pi8_f (__m32 __m1, __m64 __m2) +{ + __m64 ret; + asm("punpcklbh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_unpacklo_pi16 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("punpcklhw %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_xor_si64 (__m64 __m1, __m64 __m2) +{ + __m64 ret; + asm("xor %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +loongson_extract_pi16 (__m64 __m, int64_t __pos) +{ + __m64 ret; + asm("pextrh %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m), "f" (*(__m64 *)&__pos) + ); + return ret; +} + +extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +loongson_insert_pi16 (__m64 __m1, __m64 __m2, int64_t __pos) +{ + __m64 ret; + asm("pinsrh_%3 %0, %1, %2\n\t" + : "=f" (ret) + : "f" (__m1), "f" (__m2), "i" (__pos) + ); + return ret; +} diff --git a/gfx/cairo/libpixman/src/make-combine.pl b/gfx/cairo/libpixman/src/make-combine.pl deleted file mode 100644 index 210a5da12b..0000000000 --- a/gfx/cairo/libpixman/src/make-combine.pl +++ /dev/null @@ -1,86 +0,0 @@ -$usage = "Usage: combine.pl { 8 | 16 } < pixman-combine.c.template"; - -$#ARGV == 0 or die $usage; - -# Get the component size. -$size = int($ARGV[0]); -$size == 8 or $size == 16 or die $usage; - -$pixel_size = $size * 4; -$half_pixel_size = $size * 2; - -sub mask { - my $str = shift; - my $suffix; - $suffix = "ULL" if $size > 8; - - return "0x" . $str . $suffix; -} - -# Generate mask strings. -$nibbles = $size / 4; -$mask = "f" x $nibbles; -$zero_mask = "0" x $nibbles; -$one_half = "8" . "0" x ($nibbles - 1); - -print "/* WARNING: This file is generated by combine.pl from combine.inc.\n"; -print " Please edit one of those files rather than this one. */\n"; -print "\n"; - -print "#line 1 \"pixman-combine.c.template\"\n"; - -$mask_ = mask($mask); -$one_half_ = mask($one_half); -$g_mask = mask($mask . $zero_mask); -$b_mask = mask($mask . $zero_mask x 2); -$a_mask = mask($mask . $zero_mask x 3); -$rb_mask = mask($mask . $zero_mask . $mask); -$ag_mask = mask($mask . $zero_mask . $mask . $zero_mask); -$rb_one_half = mask($one_half . $zero_mask . $one_half); -$rb_mask_plus_one = mask("1" . $zero_mask x 2 . "1" . $zero_mask); - -while () { - # Mask and 1/2 value for a single component. - s/#define COMPONENT_SIZE\b/$& $size/; - s/#define MASK\b/$& $mask_/; - s/#define ONE_HALF\b/$& $one_half_/; - - # Shifts and masks for green, blue, and alpha. - s/#define G_SHIFT\b/$& $size/; - s/#define R_SHIFT\b/$& $size * 2/; - s/#define A_SHIFT\b/$& $size * 3/; - s/#define G_MASK\b/$& $g_mask/; - s/#define R_MASK\b/$& $b_mask/; - s/#define A_MASK\b/$& $a_mask/; - - # Special values for dealing with red + blue at the same time. - s/#define RB_MASK\b/$& $rb_mask/; - s/#define AG_MASK\b/$& $ag_mask/; - s/#define RB_ONE_HALF\b/$& $rb_one_half/; - s/#define RB_MASK_PLUS_ONE\b/$& $rb_mask_plus_one/; - - # Add 32/64 suffix to combining function types. - s/\bCombineFunc\b/CombineFunc$pixel_size/; - s/\bFbComposeFunctions\b/FbComposeFunctions$pixel_size/; - s/combine_width/combine_$pixel_size/; - s/_pixman_setup_combiner_functions_width/_pixman_setup_combiner_functions_$pixel_size/; - s/UNc/UN$size/g; - s/ALPHA_c/ALPHA_$size/g; - s/RED_c/RED_$size/g; - s/GREEN_c/GREEN_$size/g; - s/BLUE_c/BLUE_$size/g; - - # Convert comp*_t values into the appropriate real types. - s/comp1_t/uint${size}_t/g; - s/comp2_t/uint${half_pixel_size}_t/g; - s/comp4_t/uint${pixel_size}_t/g; - - # Change the function table name for the 64-bit version. - s/pixman_composeFunctions/pixman_composeFunctions64/ if $size == 16; - - # Change the header for the 64-bit version - s/pixman-combine.h/pixman-combine64.h/ if $size == 16; - s/pixman-combine.h/pixman-combine32.h/ if $size == 8; - - print; -} diff --git a/gfx/cairo/libpixman/src/meson.build b/gfx/cairo/libpixman/src/meson.build new file mode 100644 index 0000000000..f48357f261 --- /dev/null +++ b/gfx/cairo/libpixman/src/meson.build @@ -0,0 +1,129 @@ +# Copyright © 2018 Intel Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +config_h = configure_file( + configuration : config, + output : 'config.h' +) + +version_h = configure_file( + configuration : version_conf, + input : 'pixman-version.h.in', + output : 'pixman-version.h', + install_dir : join_paths(get_option('prefix'), get_option('includedir'), 'pixman-1') +) + +libpixman_extra_cargs = [] +if cc.has_function_attribute('dllexport') + libpixman_extra_cargs = ['-DPIXMAN_API=__declspec(dllexport)'] +endif + +pixman_simd_libs = [] +simds = [ + # the mmx library can be compiled with mmx on x86/x86_64, iwmmxt on + # some arm cores, or loongson mmi on loongson mips systems. The + # libraries will all have the same name, "pixman-mmx", but there is + # no chance of more than one version being built in the same build + # because no system could have mmx, iwmmxt, and mmi, and it + # simplifies the build logic to give them the same name. + ['mmx', have_mmx, mmx_flags, []], + ['mmx', have_loongson_mmi, loongson_mmi_flags, []], + ['mmx', have_iwmmxt, iwmmxt_flags, []], + + ['sse2', have_sse2, sse2_flags, []], + ['ssse3', have_ssse3, ssse3_flags, []], + ['vmx', have_vmx, vmx_flags, []], + ['arm-simd', have_armv6_simd, [], + ['pixman-arm-simd-asm.S', 'pixman-arm-simd-asm-scaled.S']], + ['arm-neon', have_neon, [], + ['pixman-arm-neon-asm.S', 'pixman-arm-neon-asm-bilinear.S']], + ['mips-dspr2', have_mips_dspr2, mips_dspr2_flags, + ['pixman-mips-dspr2-asm.S', 'pixman-mips-memcpy-asm.S']], +] + +foreach simd : simds + if simd[1] + name = 'pixman-' + simd[0] + pixman_simd_libs += static_library( + name, + [name + '.c', config_h, version_h, simd[3]], + c_args : simd[2] + ) + endif +endforeach + +pixman_files = files( + 'pixman.c', + 'pixman-access.c', + 'pixman-access-accessors.c', + 'pixman-bits-image.c', + 'pixman-combine32.c', + 'pixman-combine-float.c', + 'pixman-conical-gradient.c', + 'pixman-filter.c', + 'pixman-x86.c', + 'pixman-mips.c', + 'pixman-arm.c', + 'pixman-ppc.c', + 'pixman-edge.c', + 'pixman-edge-accessors.c', + 'pixman-fast-path.c', + 'pixman-glyph.c', + 'pixman-general.c', + 'pixman-gradient-walker.c', + 'pixman-image.c', + 'pixman-implementation.c', + 'pixman-linear-gradient.c', + 'pixman-matrix.c', + 'pixman-noop.c', + 'pixman-radial-gradient.c', + 'pixman-region16.c', + 'pixman-region32.c', + 'pixman-solid-fill.c', + 'pixman-timer.c', + 'pixman-trap.c', + 'pixman-utils.c', +) + +# We cannot use 'link_with' or 'link_whole' because meson wont do the right +# thing for static archives. +_obs = [] +foreach l : pixman_simd_libs + _obs += l.extract_all_objects() +endforeach + +libpixman = library( + 'pixman-1', + [pixman_files, config_h, version_h], + objects : _obs, + c_args : libpixman_extra_cargs, + dependencies : [dep_m, dep_threads], + version : meson.project_version(), + install : true, +) + +inc_pixman = include_directories('.') + +idep_pixman = declare_dependency( + link_with: libpixman, + include_directories : inc_pixman, +) + +install_headers('pixman.h', subdir : 'pixman-1') diff --git a/gfx/cairo/libpixman/src/moz.build b/gfx/cairo/libpixman/src/moz.build index 6bfa22dc0a..02e2582452 100644 --- a/gfx/cairo/libpixman/src/moz.build +++ b/gfx/cairo/libpixman/src/moz.build @@ -30,7 +30,6 @@ SOURCES += [ 'pixman-arm.c', 'pixman-bits-image.c', 'pixman-combine-float.c', - 'pixman-combine16.c', 'pixman-combine32.c', 'pixman-conical-gradient.c', 'pixman-edge-accessors.c', @@ -66,10 +65,7 @@ LOCAL_INCLUDES += [ ] if CONFIG['MOZ_USE_PTHREADS']: - DEFINES['HAVE_PTHREAD_SETSPECIFIC'] = True - -if CONFIG['_MSC_VER']: - DEFINES['PIXMAN_USE_XP_DLL_TLS_WORKAROUND'] = True + DEFINES['HAVE_PTHREADS'] = True DEFINES['PACKAGE'] = 'mozpixman' @@ -103,8 +99,8 @@ if use_mmx: if CONFIG['GNU_CC']: SOURCES['pixman-mmx.c'].flags += [ '-Winline', - '--param inline-unit-growth=10000', - '--param large-function-growth=10000', + '--param', 'inline-unit-growth=10000', + '--param', 'large-function-growth=10000', ] if use_sse2: @@ -135,6 +131,7 @@ if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']: '-Wno-address', '-Wno-missing-field-initializers', '-Wno-sign-compare', + '-Wno-incompatible-pointer-types', '-Wno-unused', # too many unused warnings; ignore ] if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']: diff --git a/gfx/cairo/libpixman/src/pixman-access.c b/gfx/cairo/libpixman/src/pixman-access.c index 00a02140ae..7c5ce783f9 100644 --- a/gfx/cairo/libpixman/src/pixman-access.c +++ b/gfx/cairo/libpixman/src/pixman-access.c @@ -68,14 +68,14 @@ #ifdef WORDS_BIGENDIAN #define FETCH_24(img,l,o) \ - ((READ (img, (((uint8_t *)(l)) + ((o) * 3) + 0)) << 16) | \ - (READ (img, (((uint8_t *)(l)) + ((o) * 3) + 1)) << 8) | \ - (READ (img, (((uint8_t *)(l)) + ((o) * 3) + 2)) << 0)) + ((uint32_t)(READ (img, (((uint8_t *)(l)) + ((o) * 3) + 0)) << 16) | \ + (uint32_t)(READ (img, (((uint8_t *)(l)) + ((o) * 3) + 1)) << 8) | \ + (uint32_t)(READ (img, (((uint8_t *)(l)) + ((o) * 3) + 2)) << 0)) #else #define FETCH_24(img,l,o) \ - ((READ (img, (((uint8_t *)(l)) + ((o) * 3) + 0)) << 0) | \ - (READ (img, (((uint8_t *)(l)) + ((o) * 3) + 1)) << 8) | \ - (READ (img, (((uint8_t *)(l)) + ((o) * 3) + 2)) << 16)) + ((uint32_t)(READ (img, (((uint8_t *)(l)) + ((o) * 3) + 0)) << 0) | \ + (uint32_t)(READ (img, (((uint8_t *)(l)) + ((o) * 3) + 1)) << 8) | \ + (uint32_t)(READ (img, (((uint8_t *)(l)) + ((o) * 3) + 2)) << 16)) #endif /* Store macros */ @@ -87,7 +87,7 @@ uint32_t *__d = ((uint32_t *)(l)) + ((o) >> 5); \ uint32_t __m, __v; \ \ - __m = 1 << (0x1f - ((o) & 0x1f)); \ + __m = 1U << (0x1f - ((o) & 0x1f)); \ __v = (v)? __m : 0; \ \ WRITE((img), __d, (READ((img), __d) & ~__m) | __v); \ @@ -100,7 +100,7 @@ uint32_t *__d = ((uint32_t *)(l)) + ((o) >> 5); \ uint32_t __m, __v; \ \ - __m = 1 << ((o) & 0x1f); \ + __m = 1U << ((o) & 0x1f); \ __v = (v)? __m : 0; \ \ WRITE((img), __d, (READ((img), __d) & ~__m) | __v); \ @@ -294,14 +294,14 @@ convert_pixel (pixman_format_code_t from, pixman_format_code_t to, uint32_t pixe } static force_inline uint32_t -convert_pixel_to_a8r8g8b8 (pixman_image_t *image, +convert_pixel_to_a8r8g8b8 (bits_image_t *image, pixman_format_code_t format, uint32_t pixel) { if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_GRAY || PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_COLOR) { - return image->bits.indexed->rgba[pixel]; + return image->indexed->rgba[pixel]; } else { @@ -332,7 +332,7 @@ convert_pixel_from_a8r8g8b8 (pixman_image_t *image, } static force_inline uint32_t -fetch_and_convert_pixel (pixman_image_t * image, +fetch_and_convert_pixel (bits_image_t * image, const uint8_t * bits, int offset, pixman_format_code_t format) @@ -417,7 +417,7 @@ convert_and_store_pixel (bits_image_t * image, #define MAKE_ACCESSORS(format) \ static void \ - fetch_scanline_ ## format (pixman_image_t *image, \ + fetch_scanline_ ## format (bits_image_t *image, \ int x, \ int y, \ int width, \ @@ -425,7 +425,7 @@ convert_and_store_pixel (bits_image_t * image, const uint32_t *mask) \ { \ uint8_t *bits = \ - (uint8_t *)(image->bits.bits + y * image->bits.rowstride); \ + (uint8_t *)(image->bits + y * image->rowstride); \ int i; \ \ for (i = 0; i < width; ++i) \ @@ -461,8 +461,8 @@ convert_and_store_pixel (bits_image_t * image, uint8_t *bits = \ (uint8_t *)(image->bits + line * image->rowstride); \ \ - return fetch_and_convert_pixel ((pixman_image_t *)image, \ - bits, offset, PIXMAN_ ## format); \ + return fetch_and_convert_pixel ( \ + image, bits, offset, PIXMAN_ ## format); \ } \ \ static const void *const __dummy__ ## format @@ -583,14 +583,14 @@ to_srgb (float f) } static void -fetch_scanline_a8r8g8b8_sRGB_float (pixman_image_t *image, +fetch_scanline_a8r8g8b8_sRGB_float (bits_image_t * image, int x, int y, int width, uint32_t * b, const uint32_t *mask) { - const uint32_t *bits = image->bits.bits + y * image->bits.rowstride; + const uint32_t *bits = image->bits + y * image->rowstride; const uint32_t *pixel = bits + x; const uint32_t *end = pixel + width; argb_t *buffer = (argb_t *)b; @@ -612,14 +612,14 @@ fetch_scanline_a8r8g8b8_sRGB_float (pixman_image_t *image, /* Expects a float buffer */ static void -fetch_scanline_a2r10g10b10_float (pixman_image_t *image, +fetch_scanline_a2r10g10b10_float (bits_image_t * image, int x, int y, int width, uint32_t * b, const uint32_t *mask) { - const uint32_t *bits = image->bits.bits + y * image->bits.rowstride; + const uint32_t *bits = image->bits + y * image->rowstride; const uint32_t *pixel = bits + x; const uint32_t *end = pixel + width; argb_t *buffer = (argb_t *)b; @@ -642,15 +642,57 @@ fetch_scanline_a2r10g10b10_float (pixman_image_t *image, } /* Expects a float buffer */ +#ifndef PIXMAN_FB_ACCESSORS static void -fetch_scanline_x2r10g10b10_float (pixman_image_t *image, +fetch_scanline_rgbf_float (bits_image_t *image, + int x, + int y, + int width, + uint32_t * b, + const uint32_t *mask) +{ + const float *bits = (float *)image->bits + y * image->rowstride; + const float *pixel = bits + x * 3; + argb_t *buffer = (argb_t *)b; + + for (; width--; buffer++) { + buffer->r = *pixel++; + buffer->g = *pixel++; + buffer->b = *pixel++; + buffer->a = 1.f; + } +} + +static void +fetch_scanline_rgbaf_float (bits_image_t *image, + int x, + int y, + int width, + uint32_t * b, + const uint32_t *mask) +{ + const float *bits = (float *)image->bits + y * image->rowstride; + const float *pixel = bits + x * 4; + argb_t *buffer = (argb_t *)b; + + for (; width--; buffer++) { + buffer->r = *pixel++; + buffer->g = *pixel++; + buffer->b = *pixel++; + buffer->a = *pixel++; + } +} +#endif + +static void +fetch_scanline_x2r10g10b10_float (bits_image_t *image, int x, int y, int width, uint32_t * b, const uint32_t *mask) { - const uint32_t *bits = image->bits.bits + y * image->bits.rowstride; + const uint32_t *bits = image->bits + y * image->rowstride; const uint32_t *pixel = (uint32_t *)bits + x; const uint32_t *end = pixel + width; argb_t *buffer = (argb_t *)b; @@ -673,14 +715,14 @@ fetch_scanline_x2r10g10b10_float (pixman_image_t *image, /* Expects a float buffer */ static void -fetch_scanline_a2b10g10r10_float (pixman_image_t *image, +fetch_scanline_a2b10g10r10_float (bits_image_t *image, int x, int y, int width, uint32_t * b, const uint32_t *mask) { - const uint32_t *bits = image->bits.bits + y * image->bits.rowstride; + const uint32_t *bits = image->bits + y * image->rowstride; const uint32_t *pixel = bits + x; const uint32_t *end = pixel + width; argb_t *buffer = (argb_t *)b; @@ -704,14 +746,14 @@ fetch_scanline_a2b10g10r10_float (pixman_image_t *image, /* Expects a float buffer */ static void -fetch_scanline_x2b10g10r10_float (pixman_image_t *image, +fetch_scanline_x2b10g10r10_float (bits_image_t *image, int x, int y, int width, uint32_t * b, const uint32_t *mask) { - const uint32_t *bits = image->bits.bits + y * image->bits.rowstride; + const uint32_t *bits = image->bits + y * image->rowstride; const uint32_t *pixel = (uint32_t *)bits + x; const uint32_t *end = pixel + width; argb_t *buffer = (argb_t *)b; @@ -733,14 +775,14 @@ fetch_scanline_x2b10g10r10_float (pixman_image_t *image, } static void -fetch_scanline_yuy2 (pixman_image_t *image, +fetch_scanline_yuy2 (bits_image_t *image, int x, int line, int width, uint32_t * buffer, const uint32_t *mask) { - const uint32_t *bits = image->bits.bits + image->bits.rowstride * line; + const uint32_t *bits = image->bits + image->rowstride * line; int i; for (i = 0; i < width; i++) @@ -767,7 +809,7 @@ fetch_scanline_yuy2 (pixman_image_t *image, } static void -fetch_scanline_yv12 (pixman_image_t *image, +fetch_scanline_yv12 (bits_image_t *image, int x, int line, int width, @@ -805,6 +847,40 @@ fetch_scanline_yv12 (pixman_image_t *image, /**************************** Pixel wise fetching *****************************/ +#ifndef PIXMAN_FB_ACCESSORS +static argb_t +fetch_pixel_rgbf_float (bits_image_t *image, + int offset, + int line) +{ + float *bits = (float *)image->bits + line * image->rowstride; + argb_t argb; + + argb.r = bits[offset * 3]; + argb.g = bits[offset * 3 + 1]; + argb.b = bits[offset * 3 + 2]; + argb.a = 1.f; + + return argb; +} + +static argb_t +fetch_pixel_rgbaf_float (bits_image_t *image, + int offset, + int line) +{ + float *bits = (float *)image->bits + line * image->rowstride; + argb_t argb; + + argb.r = bits[offset * 4]; + argb.g = bits[offset * 4 + 1]; + argb.b = bits[offset * 4 + 2]; + argb.a = bits[offset * 4 + 3]; + + return argb; +} +#endif + static argb_t fetch_pixel_x2r10g10b10_float (bits_image_t *image, int offset, @@ -962,6 +1038,45 @@ fetch_pixel_yv12 (bits_image_t *image, /*********************************** Store ************************************/ +#ifndef PIXMAN_FB_ACCESSORS +static void +store_scanline_rgbaf_float (bits_image_t * image, + int x, + int y, + int width, + const uint32_t *v) +{ + float *bits = (float *)image->bits + image->rowstride * y + 4 * x; + const argb_t *values = (argb_t *)v; + + for (; width; width--, values++) + { + *bits++ = values->r; + *bits++ = values->g; + *bits++ = values->b; + *bits++ = values->a; + } +} + +static void +store_scanline_rgbf_float (bits_image_t * image, + int x, + int y, + int width, + const uint32_t *v) +{ + float *bits = (float *)image->bits + image->rowstride * y + 3 * x; + const argb_t *values = (argb_t *)v; + + for (; width; width--, values++) + { + *bits++ = values->r; + *bits++ = values->g; + *bits++ = values->b; + } +} +#endif + static void store_scanline_a2r10g10b10_float (bits_image_t * image, int x, @@ -976,7 +1091,7 @@ store_scanline_a2r10g10b10_float (bits_image_t * image, for (i = 0; i < width; ++i) { - uint16_t a, r, g, b; + uint32_t a, r, g, b; a = pixman_float_to_unorm (values[i].a, 2); r = pixman_float_to_unorm (values[i].r, 10); @@ -1002,7 +1117,7 @@ store_scanline_x2r10g10b10_float (bits_image_t * image, for (i = 0; i < width; ++i) { - uint16_t r, g, b; + uint32_t r, g, b; r = pixman_float_to_unorm (values[i].r, 10); g = pixman_float_to_unorm (values[i].g, 10); @@ -1027,7 +1142,7 @@ store_scanline_a2b10g10r10_float (bits_image_t * image, for (i = 0; i < width; ++i) { - uint16_t a, r, g, b; + uint32_t a, r, g, b; a = pixman_float_to_unorm (values[i].a, 2); r = pixman_float_to_unorm (values[i].r, 10); @@ -1053,7 +1168,7 @@ store_scanline_x2b10g10r10_float (bits_image_t * image, for (i = 0; i < width; ++i) { - uint16_t r, g, b; + uint32_t r, g, b; r = pixman_float_to_unorm (values[i].r, 10); g = pixman_float_to_unorm (values[i].g, 10); @@ -1078,7 +1193,7 @@ store_scanline_a8r8g8b8_sRGB_float (bits_image_t * image, for (i = 0; i < width; ++i) { - uint8_t a, r, g, b; + uint32_t a, r, g, b; a = pixman_float_to_unorm (values[i].a, 8); r = to_srgb (values[i].r); @@ -1090,44 +1205,6 @@ store_scanline_a8r8g8b8_sRGB_float (bits_image_t * image, } } -static void -store_scanline_16 (bits_image_t * image, - int x, - int y, - int width, - const uint32_t *v) -{ - uint16_t *bits = (uint16_t*)(image->bits + image->rowstride * y); - uint16_t *values = (uint16_t *)v; - uint16_t *pixel = bits + x; - int i; - - for (i = 0; i < width; ++i) - { - WRITE (image, pixel++, values[i]); - } -} - -static void -fetch_scanline_16 (pixman_image_t *image, - int x, - int y, - int width, - uint32_t * b, - const uint32_t *mask) -{ - const uint16_t *bits = (uint16_t*)(image->bits.bits + y * image->bits.rowstride); - const uint16_t *pixel = bits + x; - int i; - uint16_t *buffer = (uint16_t *)b; - - for (i = 0; i < width; ++i) - { - *buffer++ = READ (image, pixel++); - } -} - - /* * Contracts a floating point image to 32bpp and then stores it using a * regular 32-bit store proc. Despite the type, this function expects an @@ -1159,37 +1236,37 @@ store_scanline_generic_float (bits_image_t * image, } static void -fetch_scanline_generic_float (pixman_image_t *image, +fetch_scanline_generic_float (bits_image_t * image, int x, int y, int width, uint32_t * buffer, const uint32_t *mask) { - image->bits.fetch_scanline_32 (image, x, y, width, buffer, NULL); + image->fetch_scanline_32 (image, x, y, width, buffer, NULL); - pixman_expand_to_float ((argb_t *)buffer, buffer, image->bits.format, width); + pixman_expand_to_float ((argb_t *)buffer, buffer, image->format, width); } /* The 32_sRGB paths should be deleted after narrow processing * is no longer invoked for formats that are considered wide. * (Also see fetch_pixel_generic_lossy_32) */ static void -fetch_scanline_a8r8g8b8_32_sRGB (pixman_image_t *image, +fetch_scanline_a8r8g8b8_32_sRGB (bits_image_t *image, int x, int y, int width, uint32_t *buffer, const uint32_t *mask) { - const uint32_t *bits = image->bits.bits + y * image->bits.rowstride; + const uint32_t *bits = image->bits + y * image->rowstride; const uint32_t *pixel = (uint32_t *)bits + x; const uint32_t *end = pixel + width; uint32_t tmp; while (pixel < end) { - uint8_t a, r, g, b; + uint32_t a, r, g, b; tmp = READ (image, pixel++); @@ -1213,7 +1290,7 @@ fetch_pixel_a8r8g8b8_32_sRGB (bits_image_t *image, { uint32_t *bits = image->bits + line * image->rowstride; uint32_t tmp = READ (image, bits + offset); - uint8_t a, r, g, b; + uint32_t a, r, g, b; a = (tmp >> 24) & 0xff; r = (tmp >> 16) & 0xff; @@ -1242,7 +1319,7 @@ store_scanline_a8r8g8b8_32_sRGB (bits_image_t *image, for (i = 0; i < width; ++i) { - uint8_t a, r, g, b; + uint32_t a, r, g, b; tmp = values[i]; @@ -1294,12 +1371,10 @@ fetch_pixel_generic_lossy_32 (bits_image_t *image, typedef struct { pixman_format_code_t format; - fetch_scanline_t fetch_scanline_16; fetch_scanline_t fetch_scanline_32; fetch_scanline_t fetch_scanline_float; fetch_pixel_32_t fetch_pixel_32; fetch_pixel_float_t fetch_pixel_float; - store_scanline_t store_scanline_16; store_scanline_t store_scanline_32; store_scanline_t store_scanline_float; } format_info_t; @@ -1307,28 +1382,13 @@ typedef struct #define FORMAT_INFO(format) \ { \ PIXMAN_ ## format, \ - NULL, \ fetch_scanline_ ## format, \ fetch_scanline_generic_float, \ fetch_pixel_ ## format, \ fetch_pixel_generic_float, \ - NULL, \ store_scanline_ ## format, \ store_scanline_generic_float \ } -#define FORMAT_INFO16(format) \ - { \ - PIXMAN_ ## format, \ - fetch_scanline_16, \ - fetch_scanline_ ## format, \ - fetch_scanline_generic_float, \ - fetch_pixel_ ## format, \ - fetch_pixel_generic_float, \ - store_scanline_16, \ - store_scanline_ ## format, \ - store_scanline_generic_float \ - } - static const format_info_t accessors[] = { @@ -1345,10 +1405,8 @@ static const format_info_t accessors[] = /* sRGB formats */ { PIXMAN_a8r8g8b8_sRGB, - NULL, fetch_scanline_a8r8g8b8_32_sRGB, fetch_scanline_a8r8g8b8_sRGB_float, fetch_pixel_a8r8g8b8_32_sRGB, fetch_pixel_a8r8g8b8_sRGB_float, - NULL, store_scanline_a8r8g8b8_32_sRGB, store_scanline_a8r8g8b8_sRGB_float, }, @@ -1357,8 +1415,8 @@ static const format_info_t accessors[] = FORMAT_INFO (b8g8r8), /* 16bpp formats */ - FORMAT_INFO16 (r5g6b5), - FORMAT_INFO16 (b5g6r5), + FORMAT_INFO (r5g6b5), + FORMAT_INFO (b5g6r5), FORMAT_INFO (a1r5g5b5), FORMAT_INFO (x1r5g5b5), @@ -1408,37 +1466,48 @@ static const format_info_t accessors[] = FORMAT_INFO (g1), /* Wide formats */ - +#ifndef PIXMAN_FB_ACCESSORS + { PIXMAN_rgba_float, + NULL, fetch_scanline_rgbaf_float, + fetch_pixel_generic_lossy_32, fetch_pixel_rgbaf_float, + NULL, store_scanline_rgbaf_float }, + + { PIXMAN_rgb_float, + NULL, fetch_scanline_rgbf_float, + fetch_pixel_generic_lossy_32, fetch_pixel_rgbf_float, + NULL, store_scanline_rgbf_float }, +#endif + { PIXMAN_a2r10g10b10, - NULL, NULL, fetch_scanline_a2r10g10b10_float, + NULL, fetch_scanline_a2r10g10b10_float, fetch_pixel_generic_lossy_32, fetch_pixel_a2r10g10b10_float, - NULL, NULL, store_scanline_a2r10g10b10_float }, + NULL, store_scanline_a2r10g10b10_float }, { PIXMAN_x2r10g10b10, - NULL, NULL, fetch_scanline_x2r10g10b10_float, + NULL, fetch_scanline_x2r10g10b10_float, fetch_pixel_generic_lossy_32, fetch_pixel_x2r10g10b10_float, - NULL, NULL, store_scanline_x2r10g10b10_float }, + NULL, store_scanline_x2r10g10b10_float }, { PIXMAN_a2b10g10r10, - NULL, NULL, fetch_scanline_a2b10g10r10_float, + NULL, fetch_scanline_a2b10g10r10_float, fetch_pixel_generic_lossy_32, fetch_pixel_a2b10g10r10_float, - NULL, NULL, store_scanline_a2b10g10r10_float }, + NULL, store_scanline_a2b10g10r10_float }, { PIXMAN_x2b10g10r10, - NULL, NULL, fetch_scanline_x2b10g10r10_float, + NULL, fetch_scanline_x2b10g10r10_float, fetch_pixel_generic_lossy_32, fetch_pixel_x2b10g10r10_float, - NULL, NULL, store_scanline_x2b10g10r10_float }, + NULL, store_scanline_x2b10g10r10_float }, /* YUV formats */ { PIXMAN_yuy2, - NULL, fetch_scanline_yuy2, fetch_scanline_generic_float, + fetch_scanline_yuy2, fetch_scanline_generic_float, fetch_pixel_yuy2, fetch_pixel_generic_float, - NULL, NULL, NULL }, + NULL, NULL }, { PIXMAN_yv12, - NULL, fetch_scanline_yv12, fetch_scanline_generic_float, + fetch_scanline_yv12, fetch_scanline_generic_float, fetch_pixel_yv12, fetch_pixel_generic_float, - NULL, NULL, NULL }, + NULL, NULL }, { PIXMAN_null }, }; @@ -1452,12 +1521,10 @@ setup_accessors (bits_image_t *image) { if (info->format == image->format) { - image->fetch_scanline_16 = info->fetch_scanline_16; image->fetch_scanline_32 = info->fetch_scanline_32; image->fetch_scanline_float = info->fetch_scanline_float; image->fetch_pixel_32 = info->fetch_pixel_32; image->fetch_pixel_float = info->fetch_pixel_float; - image->store_scanline_16 = info->store_scanline_16; image->store_scanline_32 = info->store_scanline_32; image->store_scanline_float = info->store_scanline_float; diff --git a/gfx/cairo/libpixman/src/pixman-arm-asm.h b/gfx/cairo/libpixman/src/pixman-arm-asm.h new file mode 100644 index 0000000000..ee78541087 --- /dev/null +++ b/gfx/cairo/libpixman/src/pixman-arm-asm.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2008 Mozilla Corporation + * Copyright © 2010 Nokia Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Mozilla Corporation not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Mozilla Corporation makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Author: Jeff Muizelaar (jeff@infidigm.net) + * + */ + +/* Supplementary macro for setting function attributes */ +.macro pixman_asm_function fname + .func fname + .global fname +#ifdef __ELF__ + .hidden fname + .type fname, %function +#endif +fname: +.endm diff --git a/gfx/cairo/libpixman/src/pixman-arm-common.h b/gfx/cairo/libpixman/src/pixman-arm-common.h index b598502bba..9537688306 100644 --- a/gfx/cairo/libpixman/src/pixman-arm-common.h +++ b/gfx/cairo/libpixman/src/pixman-arm-common.h @@ -266,13 +266,6 @@ FAST_NEAREST_MAINLOOP (cputype##_##name##_normal_##op, \ scaled_nearest_scanline_##cputype##_##name##_##op, \ src_type, dst_type, NORMAL) -/* Provide entries for the fast path table */ -#define PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH(op,s,d,func) \ - SIMPLE_NEAREST_FAST_PATH_COVER (op,s,d,func), \ - SIMPLE_NEAREST_FAST_PATH_NONE (op,s,d,func), \ - SIMPLE_NEAREST_FAST_PATH_PAD (op,s,d,func), \ - SIMPLE_NEAREST_FAST_PATH_NORMAL (op,s,d,func) - #define PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_A8_DST(flags, cputype, name, op, \ src_type, dst_type) \ void \ @@ -318,9 +311,7 @@ FAST_NEAREST_MAINLOOP_COMMON (cputype##_##name##_normal_##op, \ /* Provide entries for the fast path table */ #define PIXMAN_ARM_SIMPLE_NEAREST_A8_MASK_FAST_PATH(op,s,d,func) \ - SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER (op,s,d,func), \ - SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE (op,s,d,func), \ - SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD (op,s,d,func), \ + SIMPLE_NEAREST_A8_MASK_FAST_PATH (op,s,d,func), \ SIMPLE_NEAREST_A8_MASK_FAST_PATH_NORMAL (op,s,d,func) /*****************************************************************************/ @@ -360,16 +351,16 @@ scaled_bilinear_scanline_##cputype##_##name##_##op ( \ \ FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_cover_##op, \ scaled_bilinear_scanline_##cputype##_##name##_##op, \ - NULL, src_type, uint32_t, dst_type, COVER, FLAG_NONE) \ + src_type, uint32_t, dst_type, COVER, FLAG_NONE) \ FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_none_##op, \ scaled_bilinear_scanline_##cputype##_##name##_##op, \ - NULL, src_type, uint32_t, dst_type, NONE, FLAG_NONE) \ + src_type, uint32_t, dst_type, NONE, FLAG_NONE) \ FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_pad_##op, \ scaled_bilinear_scanline_##cputype##_##name##_##op, \ - NULL, src_type, uint32_t, dst_type, PAD, FLAG_NONE) \ + src_type, uint32_t, dst_type, PAD, FLAG_NONE) \ FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_normal_##op, \ scaled_bilinear_scanline_##cputype##_##name##_##op, \ - NULL, src_type, uint32_t, dst_type, NORMAL, \ + src_type, uint32_t, dst_type, NORMAL, \ FLAG_NONE) @@ -409,19 +400,19 @@ scaled_bilinear_scanline_##cputype##_##name##_##op ( \ \ FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_cover_##op, \ scaled_bilinear_scanline_##cputype##_##name##_##op, \ - NULL, src_type, uint8_t, dst_type, COVER, \ + src_type, uint8_t, dst_type, COVER, \ FLAG_HAVE_NON_SOLID_MASK) \ FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_none_##op, \ scaled_bilinear_scanline_##cputype##_##name##_##op, \ - NULL, src_type, uint8_t, dst_type, NONE, \ + src_type, uint8_t, dst_type, NONE, \ FLAG_HAVE_NON_SOLID_MASK) \ FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_pad_##op, \ scaled_bilinear_scanline_##cputype##_##name##_##op, \ - NULL, src_type, uint8_t, dst_type, PAD, \ + src_type, uint8_t, dst_type, PAD, \ FLAG_HAVE_NON_SOLID_MASK) \ FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_normal_##op, \ scaled_bilinear_scanline_##cputype##_##name##_##op, \ - NULL, src_type, uint8_t, dst_type, NORMAL, \ + src_type, uint8_t, dst_type, NORMAL, \ FLAG_HAVE_NON_SOLID_MASK) diff --git a/gfx/cairo/libpixman/src/pixman-arm-detect-win32.asm b/gfx/cairo/libpixman/src/pixman-arm-detect-win32.asm deleted file mode 100644 index d27bf54858..0000000000 --- a/gfx/cairo/libpixman/src/pixman-arm-detect-win32.asm +++ /dev/null @@ -1,21 +0,0 @@ - area pixman_msvc, code, readonly - - export pixman_msvc_try_arm_simd_op - -pixman_msvc_try_arm_simd_op - ;; I don't think the msvc arm asm knows how to do SIMD insns - ;; uqadd8 r3,r3,r3 - dcd 0xe6633f93 - mov pc,lr - endp - - export pixman_msvc_try_arm_neon_op - -pixman_msvc_try_arm_neon_op - ;; I don't think the msvc arm asm knows how to do NEON insns - ;; veor d0,d0,d0 - dcd 0xf3000110 - mov pc,lr - endp - - end diff --git a/gfx/cairo/libpixman/src/pixman-arm-neon-asm-bilinear.S b/gfx/cairo/libpixman/src/pixman-arm-neon-asm-bilinear.S index e37b5c298e..0fd92d61c5 100644 --- a/gfx/cairo/libpixman/src/pixman-arm-neon-asm-bilinear.S +++ b/gfx/cairo/libpixman/src/pixman-arm-neon-asm-bilinear.S @@ -65,23 +65,13 @@ .p2align 2 #include "pixman-private.h" +#include "pixman-arm-asm.h" #include "pixman-arm-neon-asm.h" /* * Bilinear macros from pixman-arm-neon-asm.S */ -/* Supplementary macro for setting function attributes */ -.macro pixman_asm_function fname - .func fname - .global fname -#ifdef __ELF__ - .hidden fname - .type fname, %function -#endif -fname: -.endm - /* * Bilinear scaling support code which tries to provide pixel fetching, color * format conversion, and interpolation as separate macros which can be used diff --git a/gfx/cairo/libpixman/src/pixman-arm-neon-asm.S b/gfx/cairo/libpixman/src/pixman-arm-neon-asm.S index d0e943d712..7e949a38fd 100644 --- a/gfx/cairo/libpixman/src/pixman-arm-neon-asm.S +++ b/gfx/cairo/libpixman/src/pixman-arm-neon-asm.S @@ -50,6 +50,7 @@ .p2align 2 #include "pixman-private.h" +#include "pixman-arm-asm.h" #include "pixman-arm-neon-asm.h" /* Global configuration options and preferences */ @@ -954,7 +955,6 @@ generate_composite_function \ */ .macro pixman_composite_over_n_8_0565_init add DUMMY, sp, #ARGS_STACK_OFFSET - .vsave {d8-d15} vpush {d8-d15} vld1.32 {d11[0]}, [DUMMY] vdup.8 d8, d11[0] @@ -982,7 +982,6 @@ generate_composite_function \ .macro pixman_composite_over_8888_n_0565_init add DUMMY, sp, #(ARGS_STACK_OFFSET + 8) - .vsave {d8-d15} vpush {d8-d15} vld1.32 {d24[0]}, [DUMMY] vdup.8 d24, d24[3] @@ -1449,7 +1448,6 @@ generate_composite_function \ .macro pixman_composite_over_n_8_8888_init add DUMMY, sp, #ARGS_STACK_OFFSET - .vsave {d8-d15} vpush {d8-d15} vld1.32 {d11[0]}, [DUMMY] vdup.8 d8, d11[0] @@ -1521,7 +1519,6 @@ generate_composite_function \ .macro pixman_composite_over_n_8_8_init add DUMMY, sp, #ARGS_STACK_OFFSET - .vsave {d8-d15} vpush {d8-d15} vld1.32 {d8[0]}, [DUMMY] vdup.8 d8, d8[3] @@ -1623,7 +1620,6 @@ generate_composite_function \ .macro pixman_composite_over_n_8888_8888_ca_init add DUMMY, sp, #ARGS_STACK_OFFSET - .vsave {d8-d15} vpush {d8-d15} vld1.32 {d11[0]}, [DUMMY] vdup.8 d8, d11[0] @@ -1793,7 +1789,6 @@ generate_composite_function \ .macro pixman_composite_over_n_8888_0565_ca_init add DUMMY, sp, #ARGS_STACK_OFFSET - .vsave {d8-d15} vpush {d8-d15} vld1.32 {d11[0]}, [DUMMY] vdup.8 d8, d11[0] @@ -1907,7 +1902,6 @@ generate_composite_function \ .macro pixman_composite_add_n_8_8_init add DUMMY, sp, #ARGS_STACK_OFFSET - .vsave {d8-d15} vpush {d8-d15} vld1.32 {d11[0]}, [DUMMY] vdup.8 d11, d11[3] @@ -2214,7 +2208,6 @@ generate_composite_function_single_scanline \ .macro pixman_composite_over_8888_n_8888_init add DUMMY, sp, #48 - .vsave {d8-d15} vpush {d8-d15} vld1.32 {d15[0]}, [DUMMY] vdup.8 d15, d15[3] @@ -2587,7 +2580,6 @@ generate_composite_function \ .macro pixman_composite_over_0565_n_0565_init add DUMMY, sp, #(ARGS_STACK_OFFSET + 8) - .vsave {d8-d15} vpush {d8-d15} vld1.32 {d15[0]}, [DUMMY] vdup.8 d15, d15[3] @@ -2839,17 +2831,6 @@ generate_composite_function_nearest_scanline \ /******************************************************************************/ -/* Supplementary macro for setting function attributes */ -.macro pixman_asm_function fname - .func fname - .global fname -#ifdef __ELF__ - .hidden fname - .type fname, %function -#endif -fname: -.endm - /* * Bilinear scaling support code which tries to provide pixel fetching, color * format conversion, and interpolation as separate macros which can be used @@ -3141,16 +3122,13 @@ pixman_asm_function fname TMP4 .req r9 STRIDE .req r2 - .fnstart mov ip, sp - .save {r4, r5, r6, r7, r8, r9} push {r4, r5, r6, r7, r8, r9} mov PF_OFFS, #prefetch_distance ldmia ip, {WB, X, UX, WIDTH} mul PF_OFFS, PF_OFFS, UX .if ((flags) & BILINEAR_FLAG_USE_ALL_NEON_REGS) != 0 - .vsave {d8-d15} vpush {d8-d15} .endif @@ -3244,7 +3222,6 @@ pixman_asm_function fname .endif pop {r4, r5, r6, r7, r8, r9} bx lr - .fnend .unreq OUT .unreq TOP diff --git a/gfx/cairo/libpixman/src/pixman-arm-neon-asm.h b/gfx/cairo/libpixman/src/pixman-arm-neon-asm.h index f50ade3ef1..bdcf6a9d47 100644 --- a/gfx/cairo/libpixman/src/pixman-arm-neon-asm.h +++ b/gfx/cairo/libpixman/src/pixman-arm-neon-asm.h @@ -385,7 +385,7 @@ * execute simultaneously with NEON and be completely shadowed by it. Thus * we get no performance overhead at all (*). This looks like a very nice * feature of Cortex-A8, if used wisely. We don't have a hardware prefetcher, - * but still can implement some rather advanced prefetch logic in sofware + * but still can implement some rather advanced prefetch logic in software * for almost zero cost! * * (*) The overhead of the prefetcher is visible when running some trivial @@ -631,16 +631,8 @@ local skip1 src_basereg_ = 0, \ mask_basereg_ = 24 - .func fname - .global fname - /* For ELF format also set function visibility to hidden */ -#ifdef __ELF__ - .hidden fname - .type fname, %function -#endif -fname: - .fnstart - .save {r4-r12, lr} + pixman_asm_function fname + push {r4-r12, lr} /* save all registers */ /* @@ -818,7 +810,6 @@ fname: init .if regs_shortage - .save {r0, r1} push {r0, r1} .endif subs H, H, #1 @@ -904,7 +895,6 @@ fname: .endif cleanup pop {r4-r12, pc} /* exit */ - .fnend .purgem fetch_src_pixblock .purgem pixld_src @@ -949,15 +939,8 @@ fname: src_basereg_ = 0, \ mask_basereg_ = 24 - .func fname - .global fname - /* For ELF format also set function visibility to hidden */ -#ifdef __ELF__ - .hidden fname - .type fname, %function -#endif -fname: - .fnstart + pixman_asm_function fname + .set PREFETCH_TYPE_CURRENT, PREFETCH_TYPE_NONE /* * Make some macro arguments globally visible and accessible @@ -992,7 +975,6 @@ fname: .endm ldr UNIT_X, [sp] - .save {r4-r8, lr} push {r4-r8, lr} ldr SRC_WIDTH_FIXED, [sp, #(24 + 4)] .if mask_bpp != 0 @@ -1108,7 +1090,6 @@ fname: .purgem fetch_src_pixblock .purgem pixld_src - .fnend .endfunc .endm @@ -1135,7 +1116,6 @@ fname: */ .macro default_init_need_all_regs - .vsave {d8-d15} vpush {d8-d15} .endm diff --git a/gfx/cairo/libpixman/src/pixman-arm-neon.c b/gfx/cairo/libpixman/src/pixman-arm-neon.c index d902193cfa..be761c9652 100644 --- a/gfx/cairo/libpixman/src/pixman-arm-neon.c +++ b/gfx/cairo/libpixman/src/pixman-arm-neon.c @@ -145,23 +145,6 @@ PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (0, neon, 0565_0565, SRC, uint16_t, uint16_t) PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (SKIP_ZERO_SRC, neon, 8888_8888, OVER, uint32_t, uint32_t) -static force_inline void -pixman_scaled_bilinear_scanline_8888_8888_SRC ( - uint32_t * dst, - const uint32_t * mask, - const uint32_t * src_top, - const uint32_t * src_bottom, - int32_t w, - int wt, - int wb, - pixman_fixed_t vx, - pixman_fixed_t unit_x, - pixman_fixed_t max_vx, - pixman_bool_t zero_src) -{ - pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon (dst, src_top, src_bottom, wt, wb, vx, unit_x, w); -} - PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (SKIP_ZERO_SRC, neon, 8888_8888, ADD, uint32_t, uint32_t) @@ -285,28 +268,6 @@ arm_neon_blt (pixman_implementation_t *imp, } } -static inline void op_bilinear_over_8888_0565(uint16_t *dst, const uint32_t *mask, const uint32_t *src, int width) -{ - pixman_composite_over_8888_0565_asm_neon (width, 1, dst, 0, src, 0); -} - -FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_0565_cover_OVER, - pixman_scaled_bilinear_scanline_8888_8888_SRC, op_bilinear_over_8888_0565, - uint32_t, uint32_t, uint16_t, - COVER, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_0565_pad_OVER, - pixman_scaled_bilinear_scanline_8888_8888_SRC, op_bilinear_over_8888_0565, - uint32_t, uint32_t, uint16_t, - PAD, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_0565_none_OVER, - pixman_scaled_bilinear_scanline_8888_8888_SRC, op_bilinear_over_8888_0565, - uint32_t, uint32_t, uint16_t, - NONE, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_0565_normal_OVER, - pixman_scaled_bilinear_scanline_8888_8888_SRC, op_bilinear_over_8888_0565, - uint32_t, uint32_t, uint16_t, - NORMAL, FLAG_NONE) - static const pixman_fast_path_t arm_neon_fast_paths[] = { PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, r5g6b5, neon_composite_src_0565_0565), @@ -401,21 +362,21 @@ static const pixman_fast_path_t arm_neon_fast_paths[] = PIXMAN_STD_FAST_PATH (OUT_REVERSE, a8, null, a8r8g8b8, neon_composite_out_reverse_8_8888), PIXMAN_STD_FAST_PATH (OUT_REVERSE, a8, null, a8b8g8r8, neon_composite_out_reverse_8_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, neon_8888_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, neon_8888_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, neon_8888_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, neon_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, neon_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, neon_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, neon_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, neon_8888_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, r5g6b5, neon_8888_0565), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, b5g6r5, neon_8888_0565), + SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, r5g6b5, neon_8888_0565), + SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, b5g6r5, neon_8888_0565), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, r5g6b5, neon_8888_0565), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, x8r8g8b8, r5g6b5, neon_8888_0565), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, b5g6r5, neon_8888_0565), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, x8b8g8r8, b5g6r5, neon_8888_0565), + SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, r5g6b5, neon_8888_0565), + SIMPLE_NEAREST_FAST_PATH (SRC, x8r8g8b8, r5g6b5, neon_8888_0565), + SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, b5g6r5, neon_8888_0565), + SIMPLE_NEAREST_FAST_PATH (SRC, x8b8g8r8, b5g6r5, neon_8888_0565), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, b5g6r5, x8b8g8r8, neon_0565_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, r5g6b5, x8r8g8b8, neon_0565_8888), + SIMPLE_NEAREST_FAST_PATH (SRC, b5g6r5, x8b8g8r8, neon_0565_8888), + SIMPLE_NEAREST_FAST_PATH (SRC, r5g6b5, x8r8g8b8, neon_0565_8888), /* Note: NONE repeat is not supported yet */ SIMPLE_NEAREST_FAST_PATH_COVER (SRC, r5g6b5, a8r8g8b8, neon_0565_8888), SIMPLE_NEAREST_FAST_PATH_COVER (SRC, b5g6r5, a8b8g8r8, neon_0565_8888), @@ -460,8 +421,6 @@ static const pixman_fast_path_t arm_neon_fast_paths[] = SIMPLE_BILINEAR_A8_MASK_FAST_PATH (ADD, a8r8g8b8, a8r8g8b8, neon_8888_8_8888), SIMPLE_BILINEAR_A8_MASK_FAST_PATH (ADD, a8r8g8b8, x8r8g8b8, neon_8888_8_8888), - SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, r5g6b5, neon_8888_0565), - { PIXMAN_OP_NONE }, }; diff --git a/gfx/cairo/libpixman/src/pixman-arm-simd-asm-scaled.S b/gfx/cairo/libpixman/src/pixman-arm-simd-asm-scaled.S index 7110995488..e050292e05 100644 --- a/gfx/cairo/libpixman/src/pixman-arm-simd-asm-scaled.S +++ b/gfx/cairo/libpixman/src/pixman-arm-simd-asm-scaled.S @@ -37,16 +37,7 @@ .altmacro .p2align 2 -/* Supplementary macro for setting function attributes */ -.macro pixman_asm_function fname - .func fname - .global fname -#ifdef __ELF__ - .hidden fname - .type fname, %function -#endif -fname: -.endm +#include "pixman-arm-asm.h" /* * Note: This code is only using armv5te instructions (not even armv6), diff --git a/gfx/cairo/libpixman/src/pixman-arm-simd-asm.S b/gfx/cairo/libpixman/src/pixman-arm-simd-asm.S index c209688790..a74a0a8f34 100644 --- a/gfx/cairo/libpixman/src/pixman-arm-simd-asm.S +++ b/gfx/cairo/libpixman/src/pixman-arm-simd-asm.S @@ -37,6 +37,7 @@ .altmacro .p2align 2 +#include "pixman-arm-asm.h" #include "pixman-arm-simd-asm.h" /* A head macro should do all processing which results in an output of up to @@ -303,6 +304,83 @@ generate_composite_function \ /******************************************************************************/ +.macro src_x888_0565_init + /* Hold loop invariant in MASK */ + ldr MASK, =0x001F001F + line_saved_regs STRIDE_S, ORIG_W +.endm + +.macro src_x888_0565_1pixel s, d + and WK&d, MASK, WK&s, lsr #3 @ 00000000000rrrrr00000000000bbbbb + and STRIDE_S, WK&s, #0xFC00 @ 0000000000000000gggggg0000000000 + orr WK&d, WK&d, WK&d, lsr #5 @ 00000000000-----rrrrr000000bbbbb + orr WK&d, WK&d, STRIDE_S, lsr #5 @ 00000000000-----rrrrrggggggbbbbb + /* Top 16 bits are discarded during the following STRH */ +.endm + +.macro src_x888_0565_2pixels slo, shi, d, tmp + and SCRATCH, WK&shi, #0xFC00 @ 0000000000000000GGGGGG0000000000 + and WK&tmp, MASK, WK&shi, lsr #3 @ 00000000000RRRRR00000000000BBBBB + and WK&shi, MASK, WK&slo, lsr #3 @ 00000000000rrrrr00000000000bbbbb + orr WK&tmp, WK&tmp, WK&tmp, lsr #5 @ 00000000000-----RRRRR000000BBBBB + orr WK&tmp, WK&tmp, SCRATCH, lsr #5 @ 00000000000-----RRRRRGGGGGGBBBBB + and SCRATCH, WK&slo, #0xFC00 @ 0000000000000000gggggg0000000000 + orr WK&shi, WK&shi, WK&shi, lsr #5 @ 00000000000-----rrrrr000000bbbbb + orr WK&shi, WK&shi, SCRATCH, lsr #5 @ 00000000000-----rrrrrggggggbbbbb + pkhbt WK&d, WK&shi, WK&tmp, lsl #16 @ RRRRRGGGGGGBBBBBrrrrrggggggbbbbb +.endm + +.macro src_x888_0565_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload + WK4 .req STRIDE_S + WK5 .req STRIDE_M + WK6 .req WK3 + WK7 .req ORIG_W + .if numbytes == 16 + pixld , 16, 4, SRC, 0 + src_x888_0565_2pixels 4, 5, 0, 0 + pixld , 8, 4, SRC, 0 + src_x888_0565_2pixels 6, 7, 1, 1 + pixld , 8, 6, SRC, 0 + .else + pixld , numbytes*2, 4, SRC, 0 + .endif +.endm + +.macro src_x888_0565_process_tail cond, numbytes, firstreg + .if numbytes == 16 + src_x888_0565_2pixels 4, 5, 2, 2 + src_x888_0565_2pixels 6, 7, 3, 4 + .elseif numbytes == 8 + src_x888_0565_2pixels 4, 5, 1, 1 + src_x888_0565_2pixels 6, 7, 2, 2 + .elseif numbytes == 4 + src_x888_0565_2pixels 4, 5, 1, 1 + .else + src_x888_0565_1pixel 4, 1 + .endif + .if numbytes == 16 + pixst , numbytes, 0, DST + .else + pixst , numbytes, 1, DST + .endif + .unreq WK4 + .unreq WK5 + .unreq WK6 + .unreq WK7 +.endm + +generate_composite_function \ + pixman_composite_src_x888_0565_asm_armv6, 32, 0, 16, \ + FLAG_DST_WRITEONLY | FLAG_BRANCH_OVER | FLAG_PROCESS_DOES_STORE | FLAG_SPILL_LINE_VARS | FLAG_PROCESS_CORRUPTS_SCRATCH, \ + 3, /* prefetch distance */ \ + src_x888_0565_init, \ + nop_macro, /* newline */ \ + nop_macro, /* cleanup */ \ + src_x888_0565_process_head, \ + src_x888_0565_process_tail + +/******************************************************************************/ + .macro add_8_8_8pixels cond, dst1, dst2 uqadd8&cond WK&dst1, WK&dst1, MASK uqadd8&cond WK&dst2, WK&dst2, STRIDE_M @@ -611,3 +689,491 @@ generate_composite_function \ /******************************************************************************/ +.macro over_reverse_n_8888_init + ldr SRC, [sp, #ARGS_STACK_OFFSET] + ldr MASK, =0x00800080 + /* Split source pixel into RB/AG parts */ + uxtb16 STRIDE_S, SRC + uxtb16 STRIDE_M, SRC, ror #8 + /* Set GE[3:0] to 0101 so SEL instructions do what we want */ + uadd8 SCRATCH, MASK, MASK + line_saved_regs STRIDE_D, ORIG_W +.endm + +.macro over_reverse_n_8888_newline + mov STRIDE_D, #0xFF +.endm + +.macro over_reverse_n_8888_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload + pixld , numbytes, firstreg, DST, 0 +.endm + +.macro over_reverse_n_8888_1pixel d, is_only + teq WK&d, #0 + beq 8f /* replace with source */ + bics ORIG_W, STRIDE_D, WK&d, lsr #24 + .if is_only == 1 + beq 49f /* skip store */ + .else + beq 9f /* write same value back */ + .endif + mla SCRATCH, STRIDE_S, ORIG_W, MASK /* red/blue */ + mla ORIG_W, STRIDE_M, ORIG_W, MASK /* alpha/green */ + uxtab16 SCRATCH, SCRATCH, SCRATCH, ror #8 + uxtab16 ORIG_W, ORIG_W, ORIG_W, ror #8 + mov SCRATCH, SCRATCH, ror #8 + sel ORIG_W, SCRATCH, ORIG_W + uqadd8 WK&d, WK&d, ORIG_W + b 9f +8: mov WK&d, SRC +9: +.endm + +.macro over_reverse_n_8888_tail numbytes, reg1, reg2, reg3, reg4 + .if numbytes == 4 + over_reverse_n_8888_1pixel reg1, 1 + .else + and SCRATCH, WK®1, WK®2 + .if numbytes == 16 + and SCRATCH, SCRATCH, WK®3 + and SCRATCH, SCRATCH, WK®4 + .endif + mvns SCRATCH, SCRATCH, asr #24 + beq 49f /* skip store if all opaque */ + over_reverse_n_8888_1pixel reg1, 0 + over_reverse_n_8888_1pixel reg2, 0 + .if numbytes == 16 + over_reverse_n_8888_1pixel reg3, 0 + over_reverse_n_8888_1pixel reg4, 0 + .endif + .endif + pixst , numbytes, reg1, DST +49: +.endm + +.macro over_reverse_n_8888_process_tail cond, numbytes, firstreg + over_reverse_n_8888_tail numbytes, firstreg, %(firstreg+1), %(firstreg+2), %(firstreg+3) +.endm + +generate_composite_function \ + pixman_composite_over_reverse_n_8888_asm_armv6, 0, 0, 32 \ + FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_CORRUPTS_PSR | FLAG_PROCESS_DOES_STORE | FLAG_SPILL_LINE_VARS | FLAG_PROCESS_CORRUPTS_SCRATCH, \ + 3, /* prefetch distance */ \ + over_reverse_n_8888_init, \ + over_reverse_n_8888_newline, \ + nop_macro, /* cleanup */ \ + over_reverse_n_8888_process_head, \ + over_reverse_n_8888_process_tail + +/******************************************************************************/ + +.macro over_white_8888_8888_ca_init + HALF .req SRC + TMP0 .req STRIDE_D + TMP1 .req STRIDE_S + TMP2 .req STRIDE_M + TMP3 .req ORIG_W + WK4 .req SCRATCH + line_saved_regs STRIDE_D, STRIDE_M, ORIG_W + ldr SCRATCH, =0x800080 + mov HALF, #0x80 + /* Set GE[3:0] to 0101 so SEL instructions do what we want */ + uadd8 SCRATCH, SCRATCH, SCRATCH + .set DST_PRELOAD_BIAS, 8 +.endm + +.macro over_white_8888_8888_ca_cleanup + .set DST_PRELOAD_BIAS, 0 + .unreq HALF + .unreq TMP0 + .unreq TMP1 + .unreq TMP2 + .unreq TMP3 + .unreq WK4 +.endm + +.macro over_white_8888_8888_ca_combine m, d + uxtb16 TMP1, TMP0 /* rb_notmask */ + uxtb16 TMP2, d /* rb_dest; 1 stall follows */ + smlatt TMP3, TMP2, TMP1, HALF /* red */ + smlabb TMP2, TMP2, TMP1, HALF /* blue */ + uxtb16 TMP0, TMP0, ror #8 /* ag_notmask */ + uxtb16 TMP1, d, ror #8 /* ag_dest; 1 stall follows */ + smlatt d, TMP1, TMP0, HALF /* alpha */ + smlabb TMP1, TMP1, TMP0, HALF /* green */ + pkhbt TMP0, TMP2, TMP3, lsl #16 /* rb; 1 stall follows */ + pkhbt TMP1, TMP1, d, lsl #16 /* ag */ + uxtab16 TMP0, TMP0, TMP0, ror #8 + uxtab16 TMP1, TMP1, TMP1, ror #8 + mov TMP0, TMP0, ror #8 + sel d, TMP0, TMP1 + uqadd8 d, d, m /* d is a late result */ +.endm + +.macro over_white_8888_8888_ca_1pixel_head + pixld , 4, 1, MASK, 0 + pixld , 4, 3, DST, 0 +.endm + +.macro over_white_8888_8888_ca_1pixel_tail + mvn TMP0, WK1 + teq WK1, WK1, asr #32 + bne 01f + bcc 03f + mov WK3, WK1 + b 02f +01: over_white_8888_8888_ca_combine WK1, WK3 +02: pixst , 4, 3, DST +03: +.endm + +.macro over_white_8888_8888_ca_2pixels_head + pixld , 8, 1, MASK, 0 +.endm + +.macro over_white_8888_8888_ca_2pixels_tail + pixld , 8, 3, DST + mvn TMP0, WK1 + teq WK1, WK1, asr #32 + bne 01f + movcs WK3, WK1 + bcs 02f + teq WK2, #0 + beq 05f + b 02f +01: over_white_8888_8888_ca_combine WK1, WK3 +02: mvn TMP0, WK2 + teq WK2, WK2, asr #32 + bne 03f + movcs WK4, WK2 + b 04f +03: over_white_8888_8888_ca_combine WK2, WK4 +04: pixst , 8, 3, DST +05: +.endm + +.macro over_white_8888_8888_ca_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload + .if numbytes == 4 + over_white_8888_8888_ca_1pixel_head + .else + .if numbytes == 16 + over_white_8888_8888_ca_2pixels_head + over_white_8888_8888_ca_2pixels_tail + .endif + over_white_8888_8888_ca_2pixels_head + .endif +.endm + +.macro over_white_8888_8888_ca_process_tail cond, numbytes, firstreg + .if numbytes == 4 + over_white_8888_8888_ca_1pixel_tail + .else + over_white_8888_8888_ca_2pixels_tail + .endif +.endm + +generate_composite_function \ + pixman_composite_over_white_8888_8888_ca_asm_armv6, 0, 32, 32 \ + FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_CORRUPTS_PSR | FLAG_PROCESS_DOES_STORE | FLAG_SPILL_LINE_VARS | FLAG_PROCESS_CORRUPTS_SCRATCH \ + 2, /* prefetch distance */ \ + over_white_8888_8888_ca_init, \ + nop_macro, /* newline */ \ + over_white_8888_8888_ca_cleanup, \ + over_white_8888_8888_ca_process_head, \ + over_white_8888_8888_ca_process_tail + + +.macro over_n_8888_8888_ca_init + /* Set up constants. RB_SRC and AG_SRC are in registers; + * RB_FLDS, A_SRC, and the two HALF values need to go on the + * stack (and the ful SRC value is already there) */ + ldr SCRATCH, [sp, #ARGS_STACK_OFFSET] + mov WK0, #0x00FF0000 + orr WK0, WK0, #0xFF /* RB_FLDS (0x00FF00FF) */ + mov WK1, #0x80 /* HALF default value */ + mov WK2, SCRATCH, lsr #24 /* A_SRC */ + orr WK3, WK1, WK1, lsl #16 /* HALF alternate value (0x00800080) */ + push {WK0-WK3} + .set ARGS_STACK_OFFSET, ARGS_STACK_OFFSET+16 + uxtb16 SRC, SCRATCH + uxtb16 STRIDE_S, SCRATCH, ror #8 + + /* Set GE[3:0] to 0101 so SEL instructions do what we want */ + uadd8 SCRATCH, WK3, WK3 + + .unreq WK0 + .unreq WK1 + .unreq WK2 + .unreq WK3 + WK0 .req Y + WK1 .req STRIDE_D + RB_SRC .req SRC + AG_SRC .req STRIDE_S + WK2 .req STRIDE_M + RB_FLDS .req r8 /* the reloaded constants have to be at consecutive registers starting at an even one */ + A_SRC .req r8 + HALF .req r9 + WK3 .req r10 + WK4 .req r11 + WK5 .req SCRATCH + WK6 .req ORIG_W + + line_saved_regs Y, STRIDE_D, STRIDE_M, ORIG_W +.endm + +.macro over_n_8888_8888_ca_cleanup + add sp, sp, #16 + .set ARGS_STACK_OFFSET, ARGS_STACK_OFFSET-16 + + .unreq WK0 + .unreq WK1 + .unreq RB_SRC + .unreq AG_SRC + .unreq WK2 + .unreq RB_FLDS + .unreq A_SRC + .unreq HALF + .unreq WK3 + .unreq WK4 + .unreq WK5 + .unreq WK6 + WK0 .req r8 + WK1 .req r9 + WK2 .req r10 + WK3 .req r11 +.endm + +.macro over_n_8888_8888_ca_1pixel_head + pixld , 4, 6, MASK, 0 + pixld , 4, 0, DST, 0 +.endm + +.macro over_n_8888_8888_ca_1pixel_tail + ldrd A_SRC, HALF, [sp, #LOCALS_STACK_OFFSET+8] + uxtb16 WK1, WK6 /* rb_mask (first step of hard case placed in what would otherwise be a stall) */ + teq WK6, WK6, asr #32 /* Zc if transparent, ZC if opaque */ + bne 20f + bcc 40f + /* Mask is fully opaque (all channels) */ + ldr WK6, [sp, #ARGS_STACK_OFFSET] /* get SRC back */ + eors A_SRC, A_SRC, #0xFF + bne 10f + /* Source is also opaque - same as src_8888_8888 */ + mov WK0, WK6 + b 30f +10: /* Same as over_8888_8888 */ + mul_8888_8 WK0, A_SRC, WK5, HALF + uqadd8 WK0, WK0, WK6 + b 30f +20: /* No simplifications possible - do it the hard way */ + uxtb16 WK2, WK6, ror #8 /* ag_mask */ + mla WK3, WK1, A_SRC, HALF /* rb_mul; 2 cycles */ + mla WK4, WK2, A_SRC, HALF /* ag_mul; 2 cycles */ + ldrd RB_FLDS, HALF, [sp, #LOCALS_STACK_OFFSET] + uxtb16 WK5, WK0 /* rb_dest */ + uxtab16 WK3, WK3, WK3, ror #8 + uxtb16 WK6, WK0, ror #8 /* ag_dest */ + uxtab16 WK4, WK4, WK4, ror #8 + smlatt WK0, RB_SRC, WK1, HALF /* red1 */ + smlabb WK1, RB_SRC, WK1, HALF /* blue1 */ + bic WK3, RB_FLDS, WK3, lsr #8 + bic WK4, RB_FLDS, WK4, lsr #8 + pkhbt WK1, WK1, WK0, lsl #16 /* rb1 */ + smlatt WK0, WK5, WK3, HALF /* red2 */ + smlabb WK3, WK5, WK3, HALF /* blue2 */ + uxtab16 WK1, WK1, WK1, ror #8 + smlatt WK5, AG_SRC, WK2, HALF /* alpha1 */ + pkhbt WK3, WK3, WK0, lsl #16 /* rb2 */ + smlabb WK0, AG_SRC, WK2, HALF /* green1 */ + smlatt WK2, WK6, WK4, HALF /* alpha2 */ + smlabb WK4, WK6, WK4, HALF /* green2 */ + pkhbt WK0, WK0, WK5, lsl #16 /* ag1 */ + uxtab16 WK3, WK3, WK3, ror #8 + pkhbt WK4, WK4, WK2, lsl #16 /* ag2 */ + uxtab16 WK0, WK0, WK0, ror #8 + uxtab16 WK4, WK4, WK4, ror #8 + mov WK1, WK1, ror #8 + mov WK3, WK3, ror #8 + sel WK2, WK1, WK0 /* recombine source*mask */ + sel WK1, WK3, WK4 /* recombine dest*(1-source_alpha*mask) */ + uqadd8 WK0, WK1, WK2 /* followed by 1 stall */ +30: /* The destination buffer is already in the L1 cache, so + * there's little point in amalgamating writes */ + pixst , 4, 0, DST +40: +.endm + +.macro over_n_8888_8888_ca_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload + .rept (numbytes / 4) - 1 + over_n_8888_8888_ca_1pixel_head + over_n_8888_8888_ca_1pixel_tail + .endr + over_n_8888_8888_ca_1pixel_head +.endm + +.macro over_n_8888_8888_ca_process_tail cond, numbytes, firstreg + over_n_8888_8888_ca_1pixel_tail +.endm + +pixman_asm_function pixman_composite_over_n_8888_8888_ca_asm_armv6 + ldr ip, [sp] + cmp ip, #-1 + beq pixman_composite_over_white_8888_8888_ca_asm_armv6 + /* else drop through... */ + .endfunc +generate_composite_function \ + pixman_composite_over_n_8888_8888_ca_asm_armv6_helper, 0, 32, 32 \ + FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_CORRUPTS_PSR | FLAG_PROCESS_DOES_STORE | FLAG_SPILL_LINE_VARS | FLAG_PROCESS_CORRUPTS_SCRATCH | FLAG_PROCESS_CORRUPTS_WK0 \ + 2, /* prefetch distance */ \ + over_n_8888_8888_ca_init, \ + nop_macro, /* newline */ \ + over_n_8888_8888_ca_cleanup, \ + over_n_8888_8888_ca_process_head, \ + over_n_8888_8888_ca_process_tail + +/******************************************************************************/ + +.macro in_reverse_8888_8888_init + /* Hold loop invariant in MASK */ + ldr MASK, =0x00800080 + /* Set GE[3:0] to 0101 so SEL instructions do what we want */ + uadd8 SCRATCH, MASK, MASK + /* Offset the source pointer: we only need the alpha bytes */ + add SRC, SRC, #3 + line_saved_regs ORIG_W +.endm + +.macro in_reverse_8888_8888_head numbytes, reg1, reg2, reg3 + ldrb ORIG_W, [SRC], #4 + .if numbytes >= 8 + ldrb WK®1, [SRC], #4 + .if numbytes == 16 + ldrb WK®2, [SRC], #4 + ldrb WK®3, [SRC], #4 + .endif + .endif + add DST, DST, #numbytes +.endm + +.macro in_reverse_8888_8888_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload + in_reverse_8888_8888_head numbytes, firstreg, %(firstreg+1), %(firstreg+2) +.endm + +.macro in_reverse_8888_8888_1pixel s, d, offset, is_only + .if is_only != 1 + movs s, ORIG_W + .if offset != 0 + ldrb ORIG_W, [SRC, #offset] + .endif + beq 01f + teq STRIDE_M, #0xFF + beq 02f + .endif + uxtb16 SCRATCH, d /* rb_dest */ + uxtb16 d, d, ror #8 /* ag_dest */ + mla SCRATCH, SCRATCH, s, MASK + mla d, d, s, MASK + uxtab16 SCRATCH, SCRATCH, SCRATCH, ror #8 + uxtab16 d, d, d, ror #8 + mov SCRATCH, SCRATCH, ror #8 + sel d, SCRATCH, d + b 02f + .if offset == 0 +48: /* Last mov d,#0 of the set - used as part of shortcut for + * source values all 0 */ + .endif +01: mov d, #0 +02: +.endm + +.macro in_reverse_8888_8888_tail numbytes, reg1, reg2, reg3, reg4 + .if numbytes == 4 + teq ORIG_W, ORIG_W, asr #32 + ldrne WK®1, [DST, #-4] + .elseif numbytes == 8 + teq ORIG_W, WK®1 + teqeq ORIG_W, ORIG_W, asr #32 /* all 0 or all -1? */ + ldmnedb DST, {WK®1-WK®2} + .else + teq ORIG_W, WK®1 + teqeq ORIG_W, WK®2 + teqeq ORIG_W, WK®3 + teqeq ORIG_W, ORIG_W, asr #32 /* all 0 or all -1? */ + ldmnedb DST, {WK®1-WK®4} + .endif + cmnne DST, #0 /* clear C if NE */ + bcs 49f /* no writes to dest if source all -1 */ + beq 48f /* set dest to all 0 if source all 0 */ + .if numbytes == 4 + in_reverse_8888_8888_1pixel ORIG_W, WK®1, 0, 1 + str WK®1, [DST, #-4] + .elseif numbytes == 8 + in_reverse_8888_8888_1pixel STRIDE_M, WK®1, -4, 0 + in_reverse_8888_8888_1pixel STRIDE_M, WK®2, 0, 0 + stmdb DST, {WK®1-WK®2} + .else + in_reverse_8888_8888_1pixel STRIDE_M, WK®1, -12, 0 + in_reverse_8888_8888_1pixel STRIDE_M, WK®2, -8, 0 + in_reverse_8888_8888_1pixel STRIDE_M, WK®3, -4, 0 + in_reverse_8888_8888_1pixel STRIDE_M, WK®4, 0, 0 + stmdb DST, {WK®1-WK®4} + .endif +49: +.endm + +.macro in_reverse_8888_8888_process_tail cond, numbytes, firstreg + in_reverse_8888_8888_tail numbytes, firstreg, %(firstreg+1), %(firstreg+2), %(firstreg+3) +.endm + +generate_composite_function \ + pixman_composite_in_reverse_8888_8888_asm_armv6, 32, 0, 32 \ + FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_CORRUPTS_PSR | FLAG_PROCESS_DOES_STORE | FLAG_SPILL_LINE_VARS | FLAG_PROCESS_CORRUPTS_SCRATCH | FLAG_NO_PRELOAD_DST \ + 2, /* prefetch distance */ \ + in_reverse_8888_8888_init, \ + nop_macro, /* newline */ \ + nop_macro, /* cleanup */ \ + in_reverse_8888_8888_process_head, \ + in_reverse_8888_8888_process_tail + +/******************************************************************************/ + +.macro over_n_8888_init + ldr SRC, [sp, #ARGS_STACK_OFFSET] + /* Hold loop invariant in MASK */ + ldr MASK, =0x00800080 + /* Hold multiplier for destination in STRIDE_M */ + mov STRIDE_M, #255 + sub STRIDE_M, STRIDE_M, SRC, lsr #24 + /* Set GE[3:0] to 0101 so SEL instructions do what we want */ + uadd8 SCRATCH, MASK, MASK +.endm + +.macro over_n_8888_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload + pixld , numbytes, firstreg, DST, 0 +.endm + +.macro over_n_8888_1pixel dst + mul_8888_8 WK&dst, STRIDE_M, SCRATCH, MASK + uqadd8 WK&dst, WK&dst, SRC +.endm + +.macro over_n_8888_process_tail cond, numbytes, firstreg + .set PROCESS_REG, firstreg + .rept numbytes / 4 + over_n_8888_1pixel %(PROCESS_REG) + .set PROCESS_REG, PROCESS_REG+1 + .endr + pixst , numbytes, firstreg, DST +.endm + +generate_composite_function \ + pixman_composite_over_n_8888_asm_armv6, 0, 0, 32 \ + FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_DOES_STORE \ + 2, /* prefetch distance */ \ + over_n_8888_init, \ + nop_macro, /* newline */ \ + nop_macro, /* cleanup */ \ + over_n_8888_process_head, \ + over_n_8888_process_tail + +/******************************************************************************/ diff --git a/gfx/cairo/libpixman/src/pixman-arm-simd-asm.h b/gfx/cairo/libpixman/src/pixman-arm-simd-asm.h index 496e37e309..da153c3f58 100644 --- a/gfx/cairo/libpixman/src/pixman-arm-simd-asm.h +++ b/gfx/cairo/libpixman/src/pixman-arm-simd-asm.h @@ -76,6 +76,16 @@ .set FLAG_SPILL_LINE_VARS, 48 .set FLAG_PROCESS_CORRUPTS_SCRATCH, 0 .set FLAG_PROCESS_PRESERVES_SCRATCH, 64 +.set FLAG_PROCESS_PRESERVES_WK0, 0 +.set FLAG_PROCESS_CORRUPTS_WK0, 128 /* if possible, use the specified register(s) instead so WK0 can hold number of leading pixels */ +.set FLAG_PRELOAD_DST, 0 +.set FLAG_NO_PRELOAD_DST, 256 + +/* + * Number of bytes by which to adjust preload offset of destination + * buffer (allows preload instruction to be moved before the load(s)) + */ +.set DST_PRELOAD_BIAS, 0 /* * Offset into stack where mask and source pointer/stride can be accessed. @@ -86,6 +96,11 @@ .set ARGS_STACK_OFFSET, (9*4) #endif +/* + * Offset into stack where space allocated during init macro can be accessed. + */ +.set LOCALS_STACK_OFFSET, 0 + /* * Constants for selecting preferable prefetch type. */ @@ -196,8 +211,8 @@ PF add, SCRATCH, base, WK0, lsl #bpp_shift-dst_bpp_shift PF and, SCRATCH, SCRATCH, #31 PF rsb, SCRATCH, SCRATCH, WK0, lsl #bpp_shift-dst_bpp_shift - PF sub, SCRATCH, SCRATCH, #1 /* so now ranges are -16..-1 / 0..31 / 32..63 */ - PF movs, SCRATCH, SCRATCH, #32-6 /* so this sets NC / nc / Nc */ + PF sub, SCRATCH, SCRATCH, #1 /* so now ranges are -16..-1 / 0..31 / 32..63 */ + PF movs, SCRATCH, SCRATCH, lsl #32-6 /* so this sets NC / nc / Nc */ PF bcs, 61f PF bpl, 60f PF pld, [ptr, #32*(prefetch_distance+2)] @@ -359,23 +374,41 @@ .macro test_bits_1_0_ptr + .if (flags) & FLAG_PROCESS_CORRUPTS_WK0 + movs SCRATCH, X, lsl #32-1 /* C,N = bits 1,0 of DST */ + .else movs SCRATCH, WK0, lsl #32-1 /* C,N = bits 1,0 of DST */ + .endif .endm .macro test_bits_3_2_ptr + .if (flags) & FLAG_PROCESS_CORRUPTS_WK0 + movs SCRATCH, X, lsl #32-3 /* C,N = bits 3, 2 of DST */ + .else movs SCRATCH, WK0, lsl #32-3 /* C,N = bits 3, 2 of DST */ + .endif .endm .macro leading_15bytes process_head, process_tail /* On entry, WK0 bits 0-3 = number of bytes until destination is 16-byte aligned */ + .set DECREMENT_X, 1 + .if (flags) & FLAG_PROCESS_CORRUPTS_WK0 + .set DECREMENT_X, 0 + sub X, X, WK0, lsr #dst_bpp_shift + str X, [sp, #LINE_SAVED_REG_COUNT*4] + mov X, WK0 + .endif /* Use unaligned loads in all cases for simplicity */ .if dst_w_bpp == 8 - conditional_process2 test_bits_1_0_ptr, mi, cs, process_head, process_tail, 1, 2, 1, 2, 1, 1, 1 + conditional_process2 test_bits_1_0_ptr, mi, cs, process_head, process_tail, 1, 2, 1, 2, 1, 1, DECREMENT_X .elseif dst_w_bpp == 16 test_bits_1_0_ptr - conditional_process1 cs, process_head, process_tail, 2, 2, 1, 1, 1 + conditional_process1 cs, process_head, process_tail, 2, 2, 1, 1, DECREMENT_X + .endif + conditional_process2 test_bits_3_2_ptr, mi, cs, process_head, process_tail, 4, 8, 1, 2, 1, 1, DECREMENT_X + .if (flags) & FLAG_PROCESS_CORRUPTS_WK0 + ldr X, [sp, #LINE_SAVED_REG_COUNT*4] .endif - conditional_process2 test_bits_3_2_ptr, mi, cs, process_head, process_tail, 4, 8, 1, 2, 1, 1, 1 .endm .macro test_bits_3_2_pix @@ -414,7 +447,7 @@ preload_middle src_bpp, SRC, 0 preload_middle mask_bpp, MASK, 0 .endif - .if (dst_r_bpp > 0) && ((SUBBLOCK % 2) == 0) + .if (dst_r_bpp > 0) && ((SUBBLOCK % 2) == 0) && (((flags) & FLAG_NO_PRELOAD_DST) == 0) /* Because we know that writes are 16-byte aligned, it's relatively easy to ensure that * destination prefetches are 32-byte aligned. It's also the easiest channel to offset * preloads for, to achieve staggered prefetches for multiple channels, because there are @@ -437,11 +470,11 @@ .if dst_r_bpp > 0 tst DST, #16 bne 111f - process_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, 16 + process_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, 16 + DST_PRELOAD_BIAS b 112f 111: .endif - process_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, 0 + process_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, 0 + DST_PRELOAD_BIAS 112: /* Just before the final (prefetch_distance+1) 32-byte blocks, deal with final preloads */ .if (src_bpp*pix_per_block > 256) || (mask_bpp*pix_per_block > 256) || (dst_r_bpp*pix_per_block > 256) @@ -449,7 +482,9 @@ .endif preload_trailing src_bpp, src_bpp_shift, SRC preload_trailing mask_bpp, mask_bpp_shift, MASK + .if ((flags) & FLAG_NO_PRELOAD_DST) == 0 preload_trailing dst_r_bpp, dst_bpp_shift, DST + .endif add X, X, #(prefetch_distance+2)*pix_per_block - 128/dst_w_bpp /* The remainder of the line is handled identically to the medium case */ medium_case_inner_loop_and_trailing_pixels process_head, process_tail,, exit_label, unaligned_src, unaligned_mask @@ -561,13 +596,7 @@ process_tail, \ process_inner_loop - .func fname - .global fname - /* For ELF format also set function visibility to hidden */ -#ifdef __ELF__ - .hidden fname - .type fname, %function -#endif + pixman_asm_function fname /* * Make some macro arguments globally visible and accessible @@ -679,16 +708,12 @@ SCRATCH .req r12 ORIG_W .req r14 /* width (pixels) */ -fname: - .fnstart - .save {r4-r11, lr} push {r4-r11, lr} /* save all registers */ subs Y, Y, #1 blo 199f #ifdef DEBUG_PARAMS - .pad #9*4 sub sp, sp, #9*4 #endif @@ -708,6 +733,13 @@ fname: #endif init + + .if (flags) & FLAG_PROCESS_CORRUPTS_WK0 + /* Reserve a word in which to store X during leading pixels */ + sub sp, sp, #4 + .set ARGS_STACK_OFFSET, ARGS_STACK_OFFSET+4 + .set LOCALS_STACK_OFFSET, LOCALS_STACK_OFFSET+4 + .endif lsl STRIDE_D, #dst_bpp_shift /* stride in bytes */ sub STRIDE_D, STRIDE_D, X, lsl #dst_bpp_shift @@ -737,42 +769,49 @@ fname: .if (flags) & FLAG_SPILL_LINE_VARS_WIDE /* This is stmdb sp!,{} */ .word 0xE92D0000 | LINE_SAVED_REGS + .set ARGS_STACK_OFFSET, ARGS_STACK_OFFSET + LINE_SAVED_REG_COUNT*4 + .set LOCALS_STACK_OFFSET, LOCALS_STACK_OFFSET + LINE_SAVED_REG_COUNT*4 .endif 151: /* New line */ newline preload_leading_step1 src_bpp, WK1, SRC preload_leading_step1 mask_bpp, WK2, MASK + .if ((flags) & FLAG_NO_PRELOAD_DST) == 0 preload_leading_step1 dst_r_bpp, WK3, DST - - tst DST, #15 - beq 154f - rsb WK0, DST, #0 /* bits 0-3 = number of leading bytes until destination aligned */ - .if (src_bpp != 0 && src_bpp != 2*dst_w_bpp) || (mask_bpp != 0 && mask_bpp != 2*dst_w_bpp) - PF and, WK0, WK0, #15 .endif + + ands WK0, DST, #15 + beq 154f + rsb WK0, WK0, #16 /* number of leading bytes until destination aligned */ preload_leading_step2 src_bpp, src_bpp_shift, WK1, SRC preload_leading_step2 mask_bpp, mask_bpp_shift, WK2, MASK + .if ((flags) & FLAG_NO_PRELOAD_DST) == 0 preload_leading_step2 dst_r_bpp, dst_bpp_shift, WK3, DST + .endif leading_15bytes process_head, process_tail 154: /* Destination now 16-byte aligned; we have at least one prefetch on each channel as well as at least one 16-byte output block */ - .if (src_bpp > 0) && (mask_bpp == 0) && ((flags) & FLAG_PROCESS_PRESERVES_SCRATCH) + .if (src_bpp > 0) && (mask_bpp == 0) && ((flags) & FLAG_PROCESS_PRESERVES_SCRATCH) and SCRATCH, SRC, #31 rsb SCRATCH, SCRATCH, #32*prefetch_distance - .elseif (src_bpp == 0) && (mask_bpp > 0) && ((flags) & FLAG_PROCESS_PRESERVES_SCRATCH) + .elseif (src_bpp == 0) && (mask_bpp > 0) && ((flags) & FLAG_PROCESS_PRESERVES_SCRATCH) and SCRATCH, MASK, #31 rsb SCRATCH, SCRATCH, #32*prefetch_distance - .endif - .ifc "process_inner_loop","" + .endif + .ifc "process_inner_loop","" switch_on_alignment wide_case_inner_loop_and_trailing_pixels, process_head, process_tail, wide_case_inner_loop, 157f - .else + .else switch_on_alignment wide_case_inner_loop_and_trailing_pixels, process_head, process_tail, process_inner_loop, 157f - .endif + .endif 157: /* Check for another line */ end_of_line 1, %((flags) & FLAG_SPILL_LINE_VARS_WIDE), 151b + .if (flags) & FLAG_SPILL_LINE_VARS_WIDE + .set ARGS_STACK_OFFSET, ARGS_STACK_OFFSET - LINE_SAVED_REG_COUNT*4 + .set LOCALS_STACK_OFFSET, LOCALS_STACK_OFFSET - LINE_SAVED_REG_COUNT*4 + .endif .endif .ltorg @@ -782,17 +821,21 @@ fname: .if (flags) & FLAG_SPILL_LINE_VARS_NON_WIDE /* This is stmdb sp!,{} */ .word 0xE92D0000 | LINE_SAVED_REGS + .set ARGS_STACK_OFFSET, ARGS_STACK_OFFSET + LINE_SAVED_REG_COUNT*4 + .set LOCALS_STACK_OFFSET, LOCALS_STACK_OFFSET + LINE_SAVED_REG_COUNT*4 .endif 161: /* New line */ newline preload_line 0, src_bpp, src_bpp_shift, SRC /* in: X, corrupts: WK0-WK1 */ preload_line 0, mask_bpp, mask_bpp_shift, MASK + .if ((flags) & FLAG_NO_PRELOAD_DST) == 0 preload_line 0, dst_r_bpp, dst_bpp_shift, DST + .endif sub X, X, #128/dst_w_bpp /* simplifies inner loop termination */ - tst DST, #15 + ands WK0, DST, #15 beq 164f - rsb WK0, DST, #0 /* bits 0-3 = number of leading bytes until destination aligned */ + rsb WK0, WK0, #16 /* number of leading bytes until destination aligned */ leading_15bytes process_head, process_tail @@ -816,7 +859,9 @@ fname: newline preload_line 1, src_bpp, src_bpp_shift, SRC /* in: X, corrupts: WK0-WK1 */ preload_line 1, mask_bpp, mask_bpp_shift, MASK + .if ((flags) & FLAG_NO_PRELOAD_DST) == 0 preload_line 1, dst_r_bpp, dst_bpp_shift, DST + .endif .if dst_w_bpp == 8 tst DST, #3 @@ -847,12 +892,22 @@ fname: 177: /* Check for another line */ end_of_line %(dst_w_bpp < 32), %((flags) & FLAG_SPILL_LINE_VARS_NON_WIDE), 171b, last_one + .if (flags) & FLAG_SPILL_LINE_VARS_NON_WIDE + .set ARGS_STACK_OFFSET, ARGS_STACK_OFFSET - LINE_SAVED_REG_COUNT*4 + .set LOCALS_STACK_OFFSET, LOCALS_STACK_OFFSET - LINE_SAVED_REG_COUNT*4 + .endif 197: .if (flags) & FLAG_SPILL_LINE_VARS add sp, sp, #LINE_SAVED_REG_COUNT*4 .endif 198: + .if (flags) & FLAG_PROCESS_CORRUPTS_WK0 + .set ARGS_STACK_OFFSET, ARGS_STACK_OFFSET-4 + .set LOCALS_STACK_OFFSET, LOCALS_STACK_OFFSET-4 + add sp, sp, #4 + .endif + cleanup #ifdef DEBUG_PARAMS @@ -860,7 +915,6 @@ fname: #endif 199: pop {r4-r11, pc} /* exit */ - .fnend .ltorg diff --git a/gfx/cairo/libpixman/src/pixman-arm-simd.c b/gfx/cairo/libpixman/src/pixman-arm-simd.c index af062e19dc..f0d14540bc 100644 --- a/gfx/cairo/libpixman/src/pixman-arm-simd.c +++ b/gfx/cairo/libpixman/src/pixman-arm-simd.c @@ -41,11 +41,20 @@ PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, src_8_8, uint8_t, 1, uint8_t, 1) PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, src_0565_8888, uint16_t, 1, uint32_t, 1) +PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, src_x888_0565, + uint32_t, 1, uint16_t, 1) PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, add_8_8, uint8_t, 1, uint8_t, 1) PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, over_8888_8888, uint32_t, 1, uint32_t, 1) +PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, in_reverse_8888_8888, + uint32_t, 1, uint32_t, 1) + +PIXMAN_ARM_BIND_FAST_PATH_N_DST (SKIP_ZERO_SRC, armv6, over_n_8888, + uint32_t, 1) +PIXMAN_ARM_BIND_FAST_PATH_N_DST (0, armv6, over_reverse_n_8888, + uint32_t, 1) PIXMAN_ARM_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, armv6, over_8888_n_8888, uint32_t, 1, uint32_t, 1) @@ -53,6 +62,9 @@ PIXMAN_ARM_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, armv6, over_8888_n_8888, PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, armv6, over_n_8_8888, uint8_t, 1, uint32_t, 1) +PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, armv6, over_n_8888_8888_ca, + uint32_t, 1, uint32_t, 1) + PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (armv6, 0565_0565, SRC, uint16_t, uint16_t) PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (armv6, 8888_8888, SRC, @@ -216,6 +228,11 @@ static const pixman_fast_path_t arm_simd_fast_paths[] = PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, a8b8g8r8, armv6_composite_src_0565_8888), PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, x8b8g8r8, armv6_composite_src_0565_8888), + PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, r5g6b5, armv6_composite_src_x888_0565), + PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, r5g6b5, armv6_composite_src_x888_0565), + PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, b5g6r5, armv6_composite_src_x888_0565), + PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, b5g6r5, armv6_composite_src_x888_0565), + PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, a8r8g8b8, armv6_composite_over_8888_8888), PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, armv6_composite_over_8888_8888), PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, armv6_composite_over_8888_8888), @@ -225,6 +242,13 @@ static const pixman_fast_path_t arm_simd_fast_paths[] = PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, a8b8g8r8, armv6_composite_over_8888_n_8888), PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, x8b8g8r8, armv6_composite_over_8888_n_8888), + PIXMAN_STD_FAST_PATH (OVER, solid, null, a8r8g8b8, armv6_composite_over_n_8888), + PIXMAN_STD_FAST_PATH (OVER, solid, null, x8r8g8b8, armv6_composite_over_n_8888), + PIXMAN_STD_FAST_PATH (OVER, solid, null, a8b8g8r8, armv6_composite_over_n_8888), + PIXMAN_STD_FAST_PATH (OVER, solid, null, x8b8g8r8, armv6_composite_over_n_8888), + PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8r8g8b8, armv6_composite_over_reverse_n_8888), + PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8b8g8r8, armv6_composite_over_reverse_n_8888), + PIXMAN_STD_FAST_PATH (ADD, a8, null, a8, armv6_composite_add_8_8), PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, armv6_composite_over_n_8_8888), @@ -232,15 +256,25 @@ static const pixman_fast_path_t arm_simd_fast_paths[] = PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, armv6_composite_over_n_8_8888), PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8b8g8r8, armv6_composite_over_n_8_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, r5g6b5, r5g6b5, armv6_0565_0565), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, b5g6r5, b5g6r5, armv6_0565_0565), + PIXMAN_STD_FAST_PATH (IN_REVERSE, a8r8g8b8, null, a8r8g8b8, armv6_composite_in_reverse_8888_8888), + PIXMAN_STD_FAST_PATH (IN_REVERSE, a8r8g8b8, null, x8r8g8b8, armv6_composite_in_reverse_8888_8888), + PIXMAN_STD_FAST_PATH (IN_REVERSE, a8b8g8r8, null, a8b8g8r8, armv6_composite_in_reverse_8888_8888), + PIXMAN_STD_FAST_PATH (IN_REVERSE, a8b8g8r8, null, x8b8g8r8, armv6_composite_in_reverse_8888_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, armv6_8888_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, armv6_8888_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, armv6_8888_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, a8b8g8r8, armv6_8888_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, x8b8g8r8, armv6_8888_8888), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, x8b8g8r8, x8b8g8r8, armv6_8888_8888), + PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, a8r8g8b8, armv6_composite_over_n_8888_8888_ca), + PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, x8r8g8b8, armv6_composite_over_n_8888_8888_ca), + PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, a8b8g8r8, armv6_composite_over_n_8888_8888_ca), + PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, x8b8g8r8, armv6_composite_over_n_8888_8888_ca), + + SIMPLE_NEAREST_FAST_PATH (SRC, r5g6b5, r5g6b5, armv6_0565_0565), + SIMPLE_NEAREST_FAST_PATH (SRC, b5g6r5, b5g6r5, armv6_0565_0565), + + SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, armv6_8888_8888), + SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, armv6_8888_8888), + SIMPLE_NEAREST_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, armv6_8888_8888), + SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, a8b8g8r8, armv6_8888_8888), + SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, x8b8g8r8, armv6_8888_8888), + SIMPLE_NEAREST_FAST_PATH (SRC, x8b8g8r8, x8b8g8r8, armv6_8888_8888), { PIXMAN_OP_NONE }, }; diff --git a/gfx/cairo/libpixman/src/pixman-arm.c b/gfx/cairo/libpixman/src/pixman-arm.c index 358372e50a..4a2ae85393 100644 --- a/gfx/cairo/libpixman/src/pixman-arm.c +++ b/gfx/cairo/libpixman/src/pixman-arm.c @@ -1,20 +1,19 @@ /* * Copyright © 2000 SuSE, Inc. * Copyright © 2007 Red Hat, Inc. - * Copyright © 2021 Moonchild Productions * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting - * documentation, and that the names of the authors not be used in advertising or + * documentation, and that the name of SuSE not be used in advertising or * publicity pertaining to distribution of the software without specific, - * written prior permission. The authors make no representations about the + * written prior permission. SuSE makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * - * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE AUTHORS + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN @@ -95,6 +94,35 @@ detect_cpu_features (void) return features; } +#elif defined(__ANDROID__) || defined(ANDROID) /* Android */ + +#include + +static arm_cpu_features_t +detect_cpu_features (void) +{ + arm_cpu_features_t features = 0; + AndroidCpuFamily cpu_family; + uint64_t cpu_features; + + cpu_family = android_getCpuFamily(); + cpu_features = android_getCpuFeatures(); + + if (cpu_family == ANDROID_CPU_FAMILY_ARM) + { + if (cpu_features & ANDROID_CPU_ARM_FEATURE_ARMv7) + features |= ARM_V7; + + if (cpu_features & ANDROID_CPU_ARM_FEATURE_VFPv3) + features |= ARM_VFP; + + if (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) + features |= ARM_NEON; + } + + return features; +} + #elif defined (__linux__) /* linux ELF */ #include @@ -148,6 +176,31 @@ detect_cpu_features (void) return features; } +#elif defined (_3DS) /* 3DS homebrew (devkitARM) */ + +static arm_cpu_features_t +detect_cpu_features (void) +{ + arm_cpu_features_t features = 0; + + features |= ARM_V6; + + return features; +} + +#elif defined (PSP2) || defined (__SWITCH__) +/* Vita (VitaSDK) or Switch (devkitA64) homebrew */ + +static arm_cpu_features_t +detect_cpu_features (void) +{ + arm_cpu_features_t features = 0; + + features |= ARM_NEON; + + return features; +} + #else /* Unknown */ static arm_cpu_features_t diff --git a/gfx/cairo/libpixman/src/pixman-bits-image.c b/gfx/cairo/libpixman/src/pixman-bits-image.c index e9d2fb69c6..4cfabe318a 100644 --- a/gfx/cairo/libpixman/src/pixman-bits-image.c +++ b/gfx/cairo/libpixman/src/pixman-bits-image.c @@ -35,44 +35,47 @@ #include "pixman-private.h" #include "pixman-combine32.h" #include "pixman-inlines.h" - -static uint32_t * -_pixman_image_get_scanline_generic_float (pixman_iter_t * iter, - const uint32_t *mask) -{ - pixman_iter_get_scanline_t fetch_32 = iter->data; - uint32_t *buffer = iter->buffer; - - fetch_32 (iter, NULL); - - pixman_expand_to_float ((argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); - - return iter->buffer; -} +#include "dither/blue-noise-64x64.h" /* Fetch functions */ -static force_inline uint32_t -fetch_pixel_no_alpha (bits_image_t *image, - int x, int y, pixman_bool_t check_bounds) +static force_inline void +fetch_pixel_no_alpha_32 (bits_image_t *image, + int x, int y, pixman_bool_t check_bounds, + void *out) { + uint32_t *ret = out; + if (check_bounds && (x < 0 || x >= image->width || y < 0 || y >= image->height)) - { - return 0; - } - - return image->fetch_pixel_32 (image, x, y); + *ret = 0; + else + *ret = image->fetch_pixel_32 (image, x, y); } -typedef uint32_t (* get_pixel_t) (bits_image_t *image, - int x, int y, pixman_bool_t check_bounds); +static force_inline void +fetch_pixel_no_alpha_float (bits_image_t *image, + int x, int y, pixman_bool_t check_bounds, + void *out) +{ + argb_t *ret = out; -static force_inline uint32_t + if (check_bounds && + (x < 0 || x >= image->width || y < 0 || y >= image->height)) + ret->a = ret->r = ret->g = ret->b = 0.f; + else + *ret = image->fetch_pixel_float (image, x, y); +} + +typedef void (* get_pixel_t) (bits_image_t *image, + int x, int y, pixman_bool_t check_bounds, void *out); + +static force_inline void bits_image_fetch_pixel_nearest (bits_image_t *image, pixman_fixed_t x, pixman_fixed_t y, - get_pixel_t get_pixel) + get_pixel_t get_pixel, + void *out) { int x0 = pixman_fixed_to_int (x - pixman_fixed_e); int y0 = pixman_fixed_to_int (y - pixman_fixed_e); @@ -82,19 +85,20 @@ bits_image_fetch_pixel_nearest (bits_image_t *image, repeat (image->common.repeat, &x0, image->width); repeat (image->common.repeat, &y0, image->height); - return get_pixel (image, x0, y0, FALSE); + get_pixel (image, x0, y0, FALSE, out); } else { - return get_pixel (image, x0, y0, TRUE); + get_pixel (image, x0, y0, TRUE, out); } } -static force_inline uint32_t -bits_image_fetch_pixel_bilinear (bits_image_t *image, - pixman_fixed_t x, - pixman_fixed_t y, - get_pixel_t get_pixel) +static force_inline void +bits_image_fetch_pixel_bilinear_32 (bits_image_t *image, + pixman_fixed_t x, + pixman_fixed_t y, + get_pixel_t get_pixel, + void *out) { pixman_repeat_t repeat_mode = image->common.repeat; int width = image->width; @@ -102,6 +106,7 @@ bits_image_fetch_pixel_bilinear (bits_image_t *image, int x1, y1, x2, y2; uint32_t tl, tr, bl, br; int32_t distx, disty; + uint32_t *ret = out; x1 = x - pixman_fixed_1 / 2; y1 = y - pixman_fixed_1 / 2; @@ -121,242 +126,142 @@ bits_image_fetch_pixel_bilinear (bits_image_t *image, repeat (repeat_mode, &x2, width); repeat (repeat_mode, &y2, height); - tl = get_pixel (image, x1, y1, FALSE); - bl = get_pixel (image, x1, y2, FALSE); - tr = get_pixel (image, x2, y1, FALSE); - br = get_pixel (image, x2, y2, FALSE); + get_pixel (image, x1, y1, FALSE, &tl); + get_pixel (image, x2, y1, FALSE, &tr); + get_pixel (image, x1, y2, FALSE, &bl); + get_pixel (image, x2, y2, FALSE, &br); } else { - tl = get_pixel (image, x1, y1, TRUE); - tr = get_pixel (image, x2, y1, TRUE); - bl = get_pixel (image, x1, y2, TRUE); - br = get_pixel (image, x2, y2, TRUE); + get_pixel (image, x1, y1, TRUE, &tl); + get_pixel (image, x2, y1, TRUE, &tr); + get_pixel (image, x1, y2, TRUE, &bl); + get_pixel (image, x2, y2, TRUE, &br); } - return bilinear_interpolation (tl, tr, bl, br, distx, disty); + *ret = bilinear_interpolation (tl, tr, bl, br, distx, disty); } -static uint32_t * -bits_image_fetch_bilinear_no_repeat_8888 (pixman_iter_t *iter, - const uint32_t *mask) +static force_inline void +bits_image_fetch_pixel_bilinear_float (bits_image_t *image, + pixman_fixed_t x, + pixman_fixed_t y, + get_pixel_t get_pixel, + void *out) { + pixman_repeat_t repeat_mode = image->common.repeat; + int width = image->width; + int height = image->height; + int x1, y1, x2, y2; + argb_t tl, tr, bl, br; + float distx, disty; + argb_t *ret = out; - pixman_image_t * ima = iter->image; - int offset = iter->x; - int line = iter->y++; - int width = iter->width; - uint32_t * buffer = iter->buffer; + x1 = x - pixman_fixed_1 / 2; + y1 = y - pixman_fixed_1 / 2; - bits_image_t *bits = &ima->bits; - pixman_fixed_t x_top, x_bottom, x; - pixman_fixed_t ux_top, ux_bottom, ux; - pixman_vector_t v; - uint32_t top_mask, bottom_mask; - uint32_t *top_row; - uint32_t *bottom_row; - uint32_t *end; - uint32_t zero[2] = { 0, 0 }; - uint32_t one = 1; - int y, y1, y2; - int disty; - int mask_inc; - int w; + distx = ((float)pixman_fixed_fraction(x1)) / 65536.f; + disty = ((float)pixman_fixed_fraction(y1)) / 65536.f; - /* reference point is the center of the pixel */ - v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; - v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; - v.vector[2] = pixman_fixed_1; - - if (!pixman_transform_point_3d (bits->common.transform, &v)) - return iter->buffer; - - ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0]; - x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2; - - y = v.vector[1] - pixman_fixed_1/2; - disty = pixman_fixed_to_bilinear_weight (y); - - /* Load the pointers to the first and second lines from the source - * image that bilinear code must read. - * - * The main trick in this code is about the check if any line are - * outside of the image; - * - * When I realize that a line (any one) is outside, I change - * the pointer to a dummy area with zeros. Once I change this, I - * must be sure the pointer will not change, so I set the - * variables to each pointer increments inside the loop. - */ - y1 = pixman_fixed_to_int (y); + x1 = pixman_fixed_to_int (x1); + y1 = pixman_fixed_to_int (y1); + x2 = x1 + 1; y2 = y1 + 1; - if (y1 < 0 || y1 >= bits->height) + if (repeat_mode != PIXMAN_REPEAT_NONE) { - top_row = zero; - x_top = 0; - ux_top = 0; + repeat (repeat_mode, &x1, width); + repeat (repeat_mode, &y1, height); + repeat (repeat_mode, &x2, width); + repeat (repeat_mode, &y2, height); + + get_pixel (image, x1, y1, FALSE, &tl); + get_pixel (image, x2, y1, FALSE, &tr); + get_pixel (image, x1, y2, FALSE, &bl); + get_pixel (image, x2, y2, FALSE, &br); } else { - top_row = bits->bits + y1 * bits->rowstride; - x_top = x; - ux_top = ux; + get_pixel (image, x1, y1, TRUE, &tl); + get_pixel (image, x2, y1, TRUE, &tr); + get_pixel (image, x1, y2, TRUE, &bl); + get_pixel (image, x2, y2, TRUE, &br); } - if (y2 < 0 || y2 >= bits->height) - { - bottom_row = zero; - x_bottom = 0; - ux_bottom = 0; - } - else - { - bottom_row = bits->bits + y2 * bits->rowstride; - x_bottom = x; - ux_bottom = ux; - } - - /* Instead of checking whether the operation uses the mast in - * each loop iteration, verify this only once and prepare the - * variables to make the code smaller inside the loop. - */ - if (!mask) - { - mask_inc = 0; - mask = &one; - } - else - { - /* If have a mask, prepare the variables to check it */ - mask_inc = 1; - } - - /* If both are zero, then the whole thing is zero */ - if (top_row == zero && bottom_row == zero) - { - memset (buffer, 0, width * sizeof (uint32_t)); - return iter->buffer; - } - else if (bits->format == PIXMAN_x8r8g8b8) - { - if (top_row == zero) - { - top_mask = 0; - bottom_mask = 0xff000000; - } - else if (bottom_row == zero) - { - top_mask = 0xff000000; - bottom_mask = 0; - } - else - { - top_mask = 0xff000000; - bottom_mask = 0xff000000; - } - } - else - { - top_mask = 0; - bottom_mask = 0; - } - - end = buffer + width; - - /* Zero fill to the left of the image */ - while (buffer < end && x < pixman_fixed_minus_1) - { - *buffer++ = 0; - x += ux; - x_top += ux_top; - x_bottom += ux_bottom; - mask += mask_inc; - } - - /* Left edge - */ - while (buffer < end && x < 0) - { - uint32_t tr, br; - int32_t distx; - - tr = top_row[pixman_fixed_to_int (x_top) + 1] | top_mask; - br = bottom_row[pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; - - distx = pixman_fixed_to_bilinear_weight (x); - - *buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty); - - x += ux; - x_top += ux_top; - x_bottom += ux_bottom; - mask += mask_inc; - } - - /* Main part */ - w = pixman_int_to_fixed (bits->width - 1); - - while (buffer < end && x < w) - { - if (*mask) - { - uint32_t tl, tr, bl, br; - int32_t distx; - - tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; - tr = top_row [pixman_fixed_to_int (x_top) + 1] | top_mask; - bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; - br = bottom_row [pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; - - distx = pixman_fixed_to_bilinear_weight (x); - - *buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty); - } - - buffer++; - x += ux; - x_top += ux_top; - x_bottom += ux_bottom; - mask += mask_inc; - } - - /* Right Edge */ - w = pixman_int_to_fixed (bits->width); - while (buffer < end && x < w) - { - if (*mask) - { - uint32_t tl, bl; - int32_t distx; - - tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; - bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; - - distx = pixman_fixed_to_bilinear_weight (x); - - *buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty); - } - - buffer++; - x += ux; - x_top += ux_top; - x_bottom += ux_bottom; - mask += mask_inc; - } - - /* Zero fill to the left of the image */ - while (buffer < end) - *buffer++ = 0; - - return iter->buffer; + *ret = bilinear_interpolation_float (tl, tr, bl, br, distx, disty); } -static force_inline uint32_t +static force_inline void accum_32(unsigned int *satot, unsigned int *srtot, + unsigned int *sgtot, unsigned int *sbtot, + const void *p, pixman_fixed_t f) +{ + uint32_t pixel = *(uint32_t *)p; + + *srtot += (int)RED_8 (pixel) * f; + *sgtot += (int)GREEN_8 (pixel) * f; + *sbtot += (int)BLUE_8 (pixel) * f; + *satot += (int)ALPHA_8 (pixel) * f; +} + +static force_inline void reduce_32(unsigned int satot, unsigned int srtot, + unsigned int sgtot, unsigned int sbtot, + void *p) +{ + uint32_t *ret = p; + + satot = (satot + 0x8000) >> 16; + srtot = (srtot + 0x8000) >> 16; + sgtot = (sgtot + 0x8000) >> 16; + sbtot = (sbtot + 0x8000) >> 16; + + satot = CLIP (satot, 0, 0xff); + srtot = CLIP (srtot, 0, 0xff); + sgtot = CLIP (sgtot, 0, 0xff); + sbtot = CLIP (sbtot, 0, 0xff); + + *ret = ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); +} + +static force_inline void accum_float(unsigned int *satot, unsigned int *srtot, + unsigned int *sgtot, unsigned int *sbtot, + const void *p, pixman_fixed_t f) +{ + const argb_t *pixel = p; + + *satot += pixel->a * f; + *srtot += pixel->r * f; + *sgtot += pixel->g * f; + *sbtot += pixel->b * f; +} + +static force_inline void reduce_float(unsigned int satot, unsigned int srtot, + unsigned int sgtot, unsigned int sbtot, + void *p) +{ + argb_t *ret = p; + + ret->a = CLIP (satot / 65536.f, 0.f, 1.f); + ret->r = CLIP (srtot / 65536.f, 0.f, 1.f); + ret->g = CLIP (sgtot / 65536.f, 0.f, 1.f); + ret->b = CLIP (sbtot / 65536.f, 0.f, 1.f); +} + +typedef void (* accumulate_pixel_t) (unsigned int *satot, unsigned int *srtot, + unsigned int *sgtot, unsigned int *sbtot, + const void *pixel, pixman_fixed_t f); + +typedef void (* reduce_pixel_t) (unsigned int satot, unsigned int srtot, + unsigned int sgtot, unsigned int sbtot, + void *out); + +static force_inline void bits_image_fetch_pixel_convolution (bits_image_t *image, pixman_fixed_t x, pixman_fixed_t y, - get_pixel_t get_pixel) + get_pixel_t get_pixel, + void *out, + accumulate_pixel_t accum, + reduce_pixel_t reduce) { pixman_fixed_t *params = image->common.filter_params; int x_off = (params[0] - pixman_fixed_1) >> 1; @@ -367,7 +272,7 @@ bits_image_fetch_pixel_convolution (bits_image_t *image, pixman_repeat_t repeat_mode = image->common.repeat; int width = image->width; int height = image->height; - int srtot, sgtot, sbtot, satot; + unsigned int srtot, sgtot, sbtot, satot; params += 2; @@ -389,48 +294,39 @@ bits_image_fetch_pixel_convolution (bits_image_t *image, if (f) { - uint32_t pixel; + /* Must be big enough to hold a argb_t */ + argb_t pixel; if (repeat_mode != PIXMAN_REPEAT_NONE) { repeat (repeat_mode, &rx, width); repeat (repeat_mode, &ry, height); - pixel = get_pixel (image, rx, ry, FALSE); + get_pixel (image, rx, ry, FALSE, &pixel); } else { - pixel = get_pixel (image, rx, ry, TRUE); + get_pixel (image, rx, ry, TRUE, &pixel); } - srtot += (int)RED_8 (pixel) * f; - sgtot += (int)GREEN_8 (pixel) * f; - sbtot += (int)BLUE_8 (pixel) * f; - satot += (int)ALPHA_8 (pixel) * f; + accum (&satot, &srtot, &sgtot, &sbtot, &pixel, f); } params++; } } - satot = (satot + 0x8000) >> 16; - srtot = (srtot + 0x8000) >> 16; - sgtot = (sgtot + 0x8000) >> 16; - sbtot = (sbtot + 0x8000) >> 16; - - satot = CLIP (satot, 0, 0xff); - srtot = CLIP (srtot, 0, 0xff); - sgtot = CLIP (sgtot, 0, 0xff); - sbtot = CLIP (sbtot, 0, 0xff); - - return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); + reduce (satot, srtot, sgtot, sbtot, out); } -static uint32_t -bits_image_fetch_pixel_separable_convolution (bits_image_t *image, - pixman_fixed_t x, - pixman_fixed_t y, - get_pixel_t get_pixel) +static void +bits_image_fetch_pixel_separable_convolution (bits_image_t *image, + pixman_fixed_t x, + pixman_fixed_t y, + get_pixel_t get_pixel, + void *out, + accumulate_pixel_t accum, + reduce_pixel_t reduce) { pixman_fixed_t *params = image->common.filter_params; pixman_repeat_t repeat_mode = image->common.repeat; @@ -445,7 +341,7 @@ bits_image_fetch_pixel_separable_convolution (bits_image_t *image, int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; pixman_fixed_t *y_params; - int srtot, sgtot, sbtot, satot; + unsigned int srtot, sgtot, sbtot, satot; int32_t x1, x2, y1, y2; int32_t px, py; int i, j; @@ -485,82 +381,100 @@ bits_image_fetch_pixel_separable_convolution (bits_image_t *image, if (fx) { + /* Must be big enough to hold a argb_t */ + argb_t pixel; pixman_fixed_t f; - uint32_t pixel; if (repeat_mode != PIXMAN_REPEAT_NONE) { repeat (repeat_mode, &rx, width); repeat (repeat_mode, &ry, height); - pixel = get_pixel (image, rx, ry, FALSE); + get_pixel (image, rx, ry, FALSE, &pixel); } else { - pixel = get_pixel (image, rx, ry, TRUE); + get_pixel (image, rx, ry, TRUE, &pixel); } f = (fy * fx + 0x8000) >> 16; - srtot += (int)RED_8 (pixel) * f; - sgtot += (int)GREEN_8 (pixel) * f; - sbtot += (int)BLUE_8 (pixel) * f; - satot += (int)ALPHA_8 (pixel) * f; + accum(&satot, &srtot, &sgtot, &sbtot, &pixel, f); } } } } - satot = (satot + 0x8000) >> 16; - srtot = (srtot + 0x8000) >> 16; - sgtot = (sgtot + 0x8000) >> 16; - sbtot = (sbtot + 0x8000) >> 16; - satot = CLIP (satot, 0, 0xff); - srtot = CLIP (srtot, 0, 0xff); - sgtot = CLIP (sgtot, 0, 0xff); - sbtot = CLIP (sbtot, 0, 0xff); - - return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); + reduce(satot, srtot, sgtot, sbtot, out); } -static force_inline uint32_t -bits_image_fetch_pixel_filtered (bits_image_t *image, +static force_inline void +bits_image_fetch_pixel_filtered (bits_image_t *image, + pixman_bool_t wide, pixman_fixed_t x, pixman_fixed_t y, - get_pixel_t get_pixel) + get_pixel_t get_pixel, + void *out) { switch (image->common.filter) { case PIXMAN_FILTER_NEAREST: case PIXMAN_FILTER_FAST: - return bits_image_fetch_pixel_nearest (image, x, y, get_pixel); + bits_image_fetch_pixel_nearest (image, x, y, get_pixel, out); break; case PIXMAN_FILTER_BILINEAR: case PIXMAN_FILTER_GOOD: case PIXMAN_FILTER_BEST: - return bits_image_fetch_pixel_bilinear (image, x, y, get_pixel); + if (wide) + bits_image_fetch_pixel_bilinear_float (image, x, y, get_pixel, out); + else + bits_image_fetch_pixel_bilinear_32 (image, x, y, get_pixel, out); break; case PIXMAN_FILTER_CONVOLUTION: - return bits_image_fetch_pixel_convolution (image, x, y, get_pixel); + if (wide) + { + bits_image_fetch_pixel_convolution (image, x, y, + get_pixel, out, + accum_float, + reduce_float); + } + else + { + bits_image_fetch_pixel_convolution (image, x, y, + get_pixel, out, + accum_32, reduce_32); + } break; case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: - return bits_image_fetch_pixel_separable_convolution (image, x, y, get_pixel); + if (wide) + { + bits_image_fetch_pixel_separable_convolution (image, x, y, + get_pixel, out, + accum_float, + reduce_float); + } + else + { + bits_image_fetch_pixel_separable_convolution (image, x, y, + get_pixel, out, + accum_32, reduce_32); + } break; default: + assert (0); break; } - - return 0; } static uint32_t * -bits_image_fetch_affine_no_alpha (pixman_iter_t * iter, - const uint32_t * mask) +__bits_image_fetch_affine_no_alpha (pixman_iter_t * iter, + pixman_bool_t wide, + const uint32_t * mask) { pixman_image_t *image = iter->image; int offset = iter->x; @@ -572,6 +486,8 @@ bits_image_fetch_affine_no_alpha (pixman_iter_t * iter, pixman_fixed_t ux, uy; pixman_vector_t v; int i; + get_pixel_t get_pixel = + wide ? fetch_pixel_no_alpha_float : fetch_pixel_no_alpha_32; /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; @@ -599,27 +515,45 @@ bits_image_fetch_affine_no_alpha (pixman_iter_t * iter, { if (!mask || mask[i]) { - buffer[i] = bits_image_fetch_pixel_filtered ( - &image->bits, x, y, fetch_pixel_no_alpha); + bits_image_fetch_pixel_filtered ( + &image->bits, wide, x, y, get_pixel, buffer); } x += ux; y += uy; + buffer += wide ? 4 : 1; } - return buffer; + return iter->buffer; +} + +static uint32_t * +bits_image_fetch_affine_no_alpha_32 (pixman_iter_t *iter, + const uint32_t *mask) +{ + return __bits_image_fetch_affine_no_alpha(iter, FALSE, mask); +} + +static uint32_t * +bits_image_fetch_affine_no_alpha_float (pixman_iter_t *iter, + const uint32_t *mask) +{ + return __bits_image_fetch_affine_no_alpha(iter, TRUE, mask); } /* General fetcher */ -static force_inline uint32_t -fetch_pixel_general (bits_image_t *image, int x, int y, pixman_bool_t check_bounds) +static force_inline void +fetch_pixel_general_32 (bits_image_t *image, + int x, int y, pixman_bool_t check_bounds, + void *out) { - uint32_t pixel; + uint32_t pixel, *ret = out; if (check_bounds && (x < 0 || x >= image->width || y < 0 || y >= image->height)) { - return 0; + *ret = 0; + return; } pixel = image->fetch_pixel_32 (image, x, y); @@ -648,18 +582,59 @@ fetch_pixel_general (bits_image_t *image, int x, int y, pixman_bool_t check_boun pixel |= (pixel_a << 24); } - return pixel; + *ret = pixel; +} + +static force_inline void +fetch_pixel_general_float (bits_image_t *image, + int x, int y, pixman_bool_t check_bounds, + void *out) +{ + argb_t *ret = out; + + if (check_bounds && + (x < 0 || x >= image->width || y < 0 || y >= image->height)) + { + ret->a = ret->r = ret->g = ret->b = 0; + return; + } + + *ret = image->fetch_pixel_float (image, x, y); + + if (image->common.alpha_map) + { + x -= image->common.alpha_origin_x; + y -= image->common.alpha_origin_y; + + if (x < 0 || x >= image->common.alpha_map->width || + y < 0 || y >= image->common.alpha_map->height) + { + ret->a = 0.f; + } + else + { + argb_t alpha; + + alpha = image->common.alpha_map->fetch_pixel_float ( + image->common.alpha_map, x, y); + + ret->a = alpha.a; + } + } } static uint32_t * -bits_image_fetch_general (pixman_iter_t *iter, - const uint32_t *mask) +__bits_image_fetch_general (pixman_iter_t *iter, + pixman_bool_t wide, + const uint32_t *mask) { pixman_image_t *image = iter->image; int offset = iter->x; int line = iter->y++; int width = iter->width; uint32_t * buffer = iter->buffer; + get_pixel_t get_pixel = + wide ? fetch_pixel_general_float : fetch_pixel_general_32; pixman_fixed_t x, y, w; pixman_fixed_t ux, uy, uw; @@ -699,8 +674,8 @@ bits_image_fetch_general (pixman_iter_t *iter, { if (w != 0) { - x0 = ((pixman_fixed_48_16_t)x << 16) / w; - y0 = ((pixman_fixed_48_16_t)y << 16) / w; + x0 = ((uint64_t)x << 16) / w; + y0 = ((uint64_t)y << 16) / w; } else { @@ -708,484 +683,33 @@ bits_image_fetch_general (pixman_iter_t *iter, y0 = 0; } - buffer[i] = bits_image_fetch_pixel_filtered ( - &image->bits, x0, y0, fetch_pixel_general); + bits_image_fetch_pixel_filtered ( + &image->bits, wide, x0, y0, get_pixel, buffer); } x += ux; y += uy; w += uw; + buffer += wide ? 4 : 1; } - return buffer; + return iter->buffer; } -typedef uint32_t (* convert_pixel_t) (const uint8_t *row, int x); - -static force_inline void -bits_image_fetch_separable_convolution_affine (pixman_image_t * image, - int offset, - int line, - int width, - uint32_t * buffer, - const uint32_t * mask, - - convert_pixel_t convert_pixel, - pixman_format_code_t format, - pixman_repeat_t repeat_mode) +static uint32_t * +bits_image_fetch_general_32 (pixman_iter_t *iter, + const uint32_t *mask) { - bits_image_t *bits = &image->bits; - pixman_fixed_t *params = image->common.filter_params; - int cwidth = pixman_fixed_to_int (params[0]); - int cheight = pixman_fixed_to_int (params[1]); - int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; - int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; - int x_phase_bits = pixman_fixed_to_int (params[2]); - int y_phase_bits = pixman_fixed_to_int (params[3]); - int x_phase_shift = 16 - x_phase_bits; - int y_phase_shift = 16 - y_phase_bits; - pixman_fixed_t vx, vy; - pixman_fixed_t ux, uy; - pixman_vector_t v; - int k; - - /* reference point is the center of the pixel */ - v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; - v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; - v.vector[2] = pixman_fixed_1; - - if (!pixman_transform_point_3d (image->common.transform, &v)) - return; - - ux = image->common.transform->matrix[0][0]; - uy = image->common.transform->matrix[1][0]; - - vx = v.vector[0]; - vy = v.vector[1]; - - for (k = 0; k < width; ++k) - { - pixman_fixed_t *y_params; - int satot, srtot, sgtot, sbtot; - pixman_fixed_t x, y; - int32_t x1, x2, y1, y2; - int32_t px, py; - int i, j; - - if (mask && !mask[k]) - goto next; - - /* Round x and y to the middle of the closest phase before continuing. This - * ensures that the convolution matrix is aligned right, since it was - * positioned relative to a particular phase (and not relative to whatever - * exact fraction we happen to get here). - */ - x = ((vx >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1); - y = ((vy >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1); - - px = (x & 0xffff) >> x_phase_shift; - py = (y & 0xffff) >> y_phase_shift; - - x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); - y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); - x2 = x1 + cwidth; - y2 = y1 + cheight; - - satot = srtot = sgtot = sbtot = 0; - - y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight; - - for (i = y1; i < y2; ++i) - { - pixman_fixed_t fy = *y_params++; - - if (fy) - { - pixman_fixed_t *x_params = params + 4 + px * cwidth; - - for (j = x1; j < x2; ++j) - { - pixman_fixed_t fx = *x_params++; - int rx = j; - int ry = i; - - if (fx) - { - pixman_fixed_t f; - uint32_t pixel, mask; - uint8_t *row; - - mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; - - if (repeat_mode != PIXMAN_REPEAT_NONE) - { - repeat (repeat_mode, &rx, bits->width); - repeat (repeat_mode, &ry, bits->height); - - row = (uint8_t *)bits->bits + bits->rowstride * 4 * ry; - pixel = convert_pixel (row, rx) | mask; - } - else - { - if (rx < 0 || ry < 0 || rx >= bits->width || ry >= bits->height) - { - pixel = 0; - } - else - { - row = (uint8_t *)bits->bits + bits->rowstride * 4 * ry; - pixel = convert_pixel (row, rx) | mask; - } - } - - f = ((pixman_fixed_32_32_t)fx * fy + 0x8000) >> 16; - srtot += (int)RED_8 (pixel) * f; - sgtot += (int)GREEN_8 (pixel) * f; - sbtot += (int)BLUE_8 (pixel) * f; - satot += (int)ALPHA_8 (pixel) * f; - } - } - } - } - - satot = (satot + 0x8000) >> 16; - srtot = (srtot + 0x8000) >> 16; - sgtot = (sgtot + 0x8000) >> 16; - sbtot = (sbtot + 0x8000) >> 16; - - satot = CLIP (satot, 0, 0xff); - srtot = CLIP (srtot, 0, 0xff); - sgtot = CLIP (sgtot, 0, 0xff); - sbtot = CLIP (sbtot, 0, 0xff); - - buffer[k] = (satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot << 0); - - next: - vx += ux; - vy += uy; - } + return __bits_image_fetch_general(iter, FALSE, mask); } -static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - -static force_inline void -bits_image_fetch_bilinear_affine (pixman_image_t * image, - int offset, - int line, - int width, - uint32_t * buffer, - const uint32_t * mask, - - convert_pixel_t convert_pixel, - pixman_format_code_t format, - pixman_repeat_t repeat_mode) +static uint32_t * +bits_image_fetch_general_float (pixman_iter_t *iter, + const uint32_t *mask) { - pixman_fixed_t x, y; - pixman_fixed_t ux, uy; - pixman_vector_t v; - bits_image_t *bits = &image->bits; - int i; - - /* reference point is the center of the pixel */ - v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; - v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; - v.vector[2] = pixman_fixed_1; - - if (!pixman_transform_point_3d (image->common.transform, &v)) - return; - - ux = image->common.transform->matrix[0][0]; - uy = image->common.transform->matrix[1][0]; - - x = v.vector[0]; - y = v.vector[1]; - - for (i = 0; i < width; ++i) - { - int x1, y1, x2, y2; - uint32_t tl, tr, bl, br; - int32_t distx, disty; - int width = image->bits.width; - int height = image->bits.height; - const uint8_t *row1; - const uint8_t *row2; - - if (mask && !mask[i]) - goto next; - - x1 = x - pixman_fixed_1 / 2; - y1 = y - pixman_fixed_1 / 2; - - distx = pixman_fixed_to_bilinear_weight (x1); - disty = pixman_fixed_to_bilinear_weight (y1); - - y1 = pixman_fixed_to_int (y1); - y2 = y1 + 1; - x1 = pixman_fixed_to_int (x1); - x2 = x1 + 1; - - if (repeat_mode != PIXMAN_REPEAT_NONE) - { - uint32_t mask; - - mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; - - repeat (repeat_mode, &x1, width); - repeat (repeat_mode, &y1, height); - repeat (repeat_mode, &x2, width); - repeat (repeat_mode, &y2, height); - - row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1; - row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2; - - tl = convert_pixel (row1, x1) | mask; - tr = convert_pixel (row1, x2) | mask; - bl = convert_pixel (row2, x1) | mask; - br = convert_pixel (row2, x2) | mask; - } - else - { - uint32_t mask1, mask2; - int bpp; - - /* Note: PIXMAN_FORMAT_BPP() returns an unsigned value, - * which means if you use it in expressions, those - * expressions become unsigned themselves. Since - * the variables below can be negative in some cases, - * that will lead to crashes on 64 bit architectures. - * - * So this line makes sure bpp is signed - */ - bpp = PIXMAN_FORMAT_BPP (format); - - if (x1 >= width || x2 < 0 || y1 >= height || y2 < 0) - { - buffer[i] = 0; - goto next; - } - - if (y2 == 0) - { - row1 = zero; - mask1 = 0; - } - else - { - row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1; - row1 += bpp / 8 * x1; - - mask1 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; - } - - if (y1 == height - 1) - { - row2 = zero; - mask2 = 0; - } - else - { - row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2; - row2 += bpp / 8 * x1; - - mask2 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; - } - - if (x2 == 0) - { - tl = 0; - bl = 0; - } - else - { - tl = convert_pixel (row1, 0) | mask1; - bl = convert_pixel (row2, 0) | mask2; - } - - if (x1 == width - 1) - { - tr = 0; - br = 0; - } - else - { - tr = convert_pixel (row1, 1) | mask1; - br = convert_pixel (row2, 1) | mask2; - } - } - - buffer[i] = bilinear_interpolation ( - tl, tr, bl, br, distx, disty); - - next: - x += ux; - y += uy; - } + return __bits_image_fetch_general(iter, TRUE, mask); } -static force_inline void -bits_image_fetch_nearest_affine (pixman_image_t * image, - int offset, - int line, - int width, - uint32_t * buffer, - const uint32_t * mask, - - convert_pixel_t convert_pixel, - pixman_format_code_t format, - pixman_repeat_t repeat_mode) -{ - pixman_fixed_t x, y; - pixman_fixed_t ux, uy; - pixman_vector_t v; - bits_image_t *bits = &image->bits; - int i; - - /* reference point is the center of the pixel */ - v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; - v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; - v.vector[2] = pixman_fixed_1; - - if (!pixman_transform_point_3d (image->common.transform, &v)) - return; - - ux = image->common.transform->matrix[0][0]; - uy = image->common.transform->matrix[1][0]; - - x = v.vector[0]; - y = v.vector[1]; - - for (i = 0; i < width; ++i) - { - int width, height, x0, y0; - const uint8_t *row; - - if (mask && !mask[i]) - goto next; - - width = image->bits.width; - height = image->bits.height; - x0 = pixman_fixed_to_int (x - pixman_fixed_e); - y0 = pixman_fixed_to_int (y - pixman_fixed_e); - - if (repeat_mode == PIXMAN_REPEAT_NONE && - (y0 < 0 || y0 >= height || x0 < 0 || x0 >= width)) - { - buffer[i] = 0; - } - else - { - uint32_t mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; - - if (repeat_mode != PIXMAN_REPEAT_NONE) - { - repeat (repeat_mode, &x0, width); - repeat (repeat_mode, &y0, height); - } - - row = (uint8_t *)bits->bits + bits->rowstride * 4 * y0; - - buffer[i] = convert_pixel (row, x0) | mask; - } - - next: - x += ux; - y += uy; - } -} - -static force_inline uint32_t -convert_a8r8g8b8 (const uint8_t *row, int x) -{ - return *(((uint32_t *)row) + x); -} - -static force_inline uint32_t -convert_x8r8g8b8 (const uint8_t *row, int x) -{ - return *(((uint32_t *)row) + x); -} - -static force_inline uint32_t -convert_a8 (const uint8_t *row, int x) -{ - return *(row + x) << 24; -} - -static force_inline uint32_t -convert_r5g6b5 (const uint8_t *row, int x) -{ - return convert_0565_to_0888 (*((uint16_t *)row + x)); -} - -#define MAKE_SEPARABLE_CONVOLUTION_FETCHER(name, format, repeat_mode) \ - static uint32_t * \ - bits_image_fetch_separable_convolution_affine_ ## name (pixman_iter_t *iter, \ - const uint32_t * mask) \ - { \ - bits_image_fetch_separable_convolution_affine ( \ - iter->image, \ - iter->x, iter->y++, \ - iter->width, \ - iter->buffer, mask, \ - convert_ ## format, \ - PIXMAN_ ## format, \ - repeat_mode); \ - \ - return iter->buffer; \ - } - -#define MAKE_BILINEAR_FETCHER(name, format, repeat_mode) \ - static uint32_t * \ - bits_image_fetch_bilinear_affine_ ## name (pixman_iter_t *iter, \ - const uint32_t * mask) \ - { \ - bits_image_fetch_bilinear_affine (iter->image, \ - iter->x, iter->y++, \ - iter->width, \ - iter->buffer, mask, \ - convert_ ## format, \ - PIXMAN_ ## format, \ - repeat_mode); \ - return iter->buffer; \ - } - -#define MAKE_NEAREST_FETCHER(name, format, repeat_mode) \ - static uint32_t * \ - bits_image_fetch_nearest_affine_ ## name (pixman_iter_t *iter, \ - const uint32_t * mask) \ - { \ - bits_image_fetch_nearest_affine (iter->image, \ - iter->x, iter->y++, \ - iter->width, \ - iter->buffer, mask, \ - convert_ ## format, \ - PIXMAN_ ## format, \ - repeat_mode); \ - return iter->buffer; \ - } - -#define MAKE_FETCHERS(name, format, repeat_mode) \ - MAKE_NEAREST_FETCHER (name, format, repeat_mode) \ - MAKE_BILINEAR_FETCHER (name, format, repeat_mode) \ - MAKE_SEPARABLE_CONVOLUTION_FETCHER (name, format, repeat_mode) - -MAKE_FETCHERS (pad_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_PAD) -MAKE_FETCHERS (none_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NONE) -MAKE_FETCHERS (reflect_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_REFLECT) -MAKE_FETCHERS (normal_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NORMAL) -MAKE_FETCHERS (pad_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_PAD) -MAKE_FETCHERS (none_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NONE) -MAKE_FETCHERS (reflect_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_REFLECT) -MAKE_FETCHERS (normal_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NORMAL) -MAKE_FETCHERS (pad_a8, a8, PIXMAN_REPEAT_PAD) -MAKE_FETCHERS (none_a8, a8, PIXMAN_REPEAT_NONE) -MAKE_FETCHERS (reflect_a8, a8, PIXMAN_REPEAT_REFLECT) -MAKE_FETCHERS (normal_a8, a8, PIXMAN_REPEAT_NORMAL) -MAKE_FETCHERS (pad_r5g6b5, r5g6b5, PIXMAN_REPEAT_PAD) -MAKE_FETCHERS (none_r5g6b5, r5g6b5, PIXMAN_REPEAT_NONE) -MAKE_FETCHERS (reflect_r5g6b5, r5g6b5, PIXMAN_REPEAT_REFLECT) -MAKE_FETCHERS (normal_r5g6b5, r5g6b5, PIXMAN_REPEAT_NORMAL) - static void replicate_pixel_32 (bits_image_t * bits, int x, @@ -1253,9 +777,9 @@ bits_image_fetch_untransformed_repeat_none (bits_image_t *image, w = MIN (width, image->width - x); if (wide) - image->fetch_scanline_float ((pixman_image_t *)image, x, y, w, buffer, NULL); + image->fetch_scanline_float (image, x, y, w, buffer, NULL); else - image->fetch_scanline_32 ((pixman_image_t *)image, x, y, w, buffer, NULL); + image->fetch_scanline_32 (image, x, y, w, buffer, NULL); width -= w; buffer += w * (wide? 4 : 1); @@ -1301,9 +825,9 @@ bits_image_fetch_untransformed_repeat_normal (bits_image_t *image, w = MIN (width, image->width - x); if (wide) - image->fetch_scanline_float ((pixman_image_t *)image, x, y, w, buffer, NULL); + image->fetch_scanline_float (image, x, y, w, buffer, NULL); else - image->fetch_scanline_32 ((pixman_image_t *)image, x, y, w, buffer, NULL); + image->fetch_scanline_32 (image, x, y, w, buffer, NULL); buffer += w * (wide? 4 : 1); x += w; @@ -1381,104 +905,18 @@ static const fetcher_info_t fetcher_info[] = bits_image_fetch_untransformed_float }, -#define FAST_BILINEAR_FLAGS \ - (FAST_PATH_NO_ALPHA_MAP | \ - FAST_PATH_NO_ACCESSORS | \ - FAST_PATH_HAS_TRANSFORM | \ - FAST_PATH_AFFINE_TRANSFORM | \ - FAST_PATH_X_UNIT_POSITIVE | \ - FAST_PATH_Y_UNIT_ZERO | \ - FAST_PATH_NONE_REPEAT | \ - FAST_PATH_BILINEAR_FILTER) - - { PIXMAN_a8r8g8b8, - FAST_BILINEAR_FLAGS, - bits_image_fetch_bilinear_no_repeat_8888, - _pixman_image_get_scanline_generic_float - }, - - { PIXMAN_x8r8g8b8, - FAST_BILINEAR_FLAGS, - bits_image_fetch_bilinear_no_repeat_8888, - _pixman_image_get_scanline_generic_float - }, - -#define GENERAL_BILINEAR_FLAGS \ - (FAST_PATH_NO_ALPHA_MAP | \ - FAST_PATH_NO_ACCESSORS | \ - FAST_PATH_HAS_TRANSFORM | \ - FAST_PATH_AFFINE_TRANSFORM | \ - FAST_PATH_BILINEAR_FILTER) - -#define GENERAL_NEAREST_FLAGS \ - (FAST_PATH_NO_ALPHA_MAP | \ - FAST_PATH_NO_ACCESSORS | \ - FAST_PATH_HAS_TRANSFORM | \ - FAST_PATH_AFFINE_TRANSFORM | \ - FAST_PATH_NEAREST_FILTER) - -#define GENERAL_SEPARABLE_CONVOLUTION_FLAGS \ - (FAST_PATH_NO_ALPHA_MAP | \ - FAST_PATH_NO_ACCESSORS | \ - FAST_PATH_HAS_TRANSFORM | \ - FAST_PATH_AFFINE_TRANSFORM | \ - FAST_PATH_SEPARABLE_CONVOLUTION_FILTER) - -#define SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \ - { PIXMAN_ ## format, \ - GENERAL_SEPARABLE_CONVOLUTION_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ - bits_image_fetch_separable_convolution_affine_ ## name, \ - _pixman_image_get_scanline_generic_float \ - }, - -#define BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \ - { PIXMAN_ ## format, \ - GENERAL_BILINEAR_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ - bits_image_fetch_bilinear_affine_ ## name, \ - _pixman_image_get_scanline_generic_float \ - }, - -#define NEAREST_AFFINE_FAST_PATH(name, format, repeat) \ - { PIXMAN_ ## format, \ - GENERAL_NEAREST_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ - bits_image_fetch_nearest_affine_ ## name, \ - _pixman_image_get_scanline_generic_float \ - }, - -#define AFFINE_FAST_PATHS(name, format, repeat) \ - SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \ - BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \ - NEAREST_AFFINE_FAST_PATH(name, format, repeat) - - AFFINE_FAST_PATHS (pad_a8r8g8b8, a8r8g8b8, PAD) - AFFINE_FAST_PATHS (none_a8r8g8b8, a8r8g8b8, NONE) - AFFINE_FAST_PATHS (reflect_a8r8g8b8, a8r8g8b8, REFLECT) - AFFINE_FAST_PATHS (normal_a8r8g8b8, a8r8g8b8, NORMAL) - AFFINE_FAST_PATHS (pad_x8r8g8b8, x8r8g8b8, PAD) - AFFINE_FAST_PATHS (none_x8r8g8b8, x8r8g8b8, NONE) - AFFINE_FAST_PATHS (reflect_x8r8g8b8, x8r8g8b8, REFLECT) - AFFINE_FAST_PATHS (normal_x8r8g8b8, x8r8g8b8, NORMAL) - AFFINE_FAST_PATHS (pad_a8, a8, PAD) - AFFINE_FAST_PATHS (none_a8, a8, NONE) - AFFINE_FAST_PATHS (reflect_a8, a8, REFLECT) - AFFINE_FAST_PATHS (normal_a8, a8, NORMAL) - AFFINE_FAST_PATHS (pad_r5g6b5, r5g6b5, PAD) - AFFINE_FAST_PATHS (none_r5g6b5, r5g6b5, NONE) - AFFINE_FAST_PATHS (reflect_r5g6b5, r5g6b5, REFLECT) - AFFINE_FAST_PATHS (normal_r5g6b5, r5g6b5, NORMAL) - /* Affine, no alpha */ { PIXMAN_any, (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_HAS_TRANSFORM | FAST_PATH_AFFINE_TRANSFORM), - bits_image_fetch_affine_no_alpha, - _pixman_image_get_scanline_generic_float + bits_image_fetch_affine_no_alpha_32, + bits_image_fetch_affine_no_alpha_float, }, /* General */ { PIXMAN_any, 0, - bits_image_fetch_general, - _pixman_image_get_scanline_generic_float + bits_image_fetch_general_32, + bits_image_fetch_general_float, }, { PIXMAN_null }, @@ -1508,7 +946,6 @@ _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter) } else { - iter->data = info->get_scanline_32; iter->get_scanline = info->get_scanline_float; } return; @@ -1519,20 +956,6 @@ _pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter) iter->get_scanline = _pixman_iter_get_scanline_noop; } -static uint32_t * -dest_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask) -{ - pixman_image_t *image = iter->image; - int x = iter->x; - int y = iter->y; - int width = iter->width; - uint32_t * buffer = iter->buffer; - - image->bits.fetch_scanline_16 (image, x, y, width, buffer, mask); - - return iter->buffer; -} - static uint32_t * dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) { @@ -1542,7 +965,7 @@ dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) int width = iter->width; uint32_t * buffer = iter->buffer; - image->bits.fetch_scanline_32 (image, x, y, width, buffer, mask); + image->bits.fetch_scanline_32 (&image->bits, x, y, width, buffer, mask); if (image->common.alpha_map) { uint32_t *alpha; @@ -1555,8 +978,7 @@ dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) y -= image->common.alpha_origin_y; image->common.alpha_map->fetch_scanline_32 ( - (pixman_image_t *)image->common.alpha_map, - x, y, width, alpha, mask); + image->common.alpha_map, x, y, width, alpha, mask); for (i = 0; i < width; ++i) { @@ -1581,7 +1003,7 @@ dest_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) argb_t * buffer = (argb_t *)iter->buffer; image->fetch_scanline_float ( - (pixman_image_t *)image, x, y, width, (uint32_t *)buffer, mask); + image, x, y, width, (uint32_t *)buffer, mask); if (image->common.alpha_map) { argb_t *alpha; @@ -1594,8 +1016,7 @@ dest_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) y -= image->common.alpha_origin_y; image->common.alpha_map->fetch_scanline_float ( - (pixman_image_t *)image->common.alpha_map, - x, y, width, (uint32_t *)alpha, mask); + image->common.alpha_map, x, y, width, (uint32_t *)alpha, mask); for (i = 0; i < width; ++i) buffer[i].a = alpha[i].a; @@ -1607,20 +1028,6 @@ dest_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) return iter->buffer; } -static void -dest_write_back_16 (pixman_iter_t *iter) -{ - bits_image_t * image = &iter->image->bits; - int x = iter->x; - int y = iter->y; - int width = iter->width; - const uint32_t *buffer = iter->buffer; - - image->store_scanline_16 (image, x, y, width, buffer); - - iter->y++; -} - static void dest_write_back_narrow (pixman_iter_t *iter) { @@ -1644,6 +1051,119 @@ dest_write_back_narrow (pixman_iter_t *iter) iter->y++; } +static const float +dither_factor_blue_noise_64 (int x, int y) +{ + float m = dither_blue_noise_64x64[((y & 0x3f) << 6) | (x & 0x3f)]; + return m * (1. / 4096.f) + (1. / 8192.f); +} + +static const float +dither_factor_bayer_8 (int x, int y) +{ + uint32_t m; + + y ^= x; + + /* Compute reverse(interleave(xor(x mod n, y mod n), x mod n)) + * Here n = 8 and `mod n` is the bottom 3 bits. + */ + m = ((y & 0x1) << 5) | ((x & 0x1) << 4) | + ((y & 0x2) << 2) | ((x & 0x2) << 1) | + ((y & 0x4) >> 1) | ((x & 0x4) >> 2); + + /* m is in range [0, 63]. We scale it to [0, 63.0f/64.0f], then + * shift it to to [1.0f/128.0f, 127.0f/128.0f] so that 0 < d < 1. + * This ensures exact values are not changed by dithering. + */ + return (float)(m) * (1 / 64.0f) + (1.0f / 128.0f); +} + +typedef float (* dither_factor_t)(int x, int y); + +static force_inline float +dither_apply_channel (float f, float d, float s) +{ + /* float_to_unorm splits the [0, 1] segment in (1 << n_bits) + * subsections of equal length; however unorm_to_float does not + * map to the center of those sections. In fact, pixel value u is + * mapped to: + * + * u u u 1 + * -------------- = ---------- + -------------- * ---------- + * 2^n_bits - 1 2^n_bits 2^n_bits - 1 2^n_bits + * + * Hence if f = u / (2^n_bits - 1) is exactly representable on a + * n_bits palette, all the numbers between + * + * u + * ---------- = f - f * 2^n_bits = f + (0 - f) * 2^n_bits + * 2^n_bits + * + * and + * + * u + 1 + * ---------- = f - (f - 1) * 2^n_bits = f + (1 - f) * 2^n_bits + * 2^n_bits + * + * are also mapped back to u. + * + * Hence the following calculation ensures that we add as much + * noise as possible without perturbing values which are exactly + * representable in the target colorspace. Note that this corresponds to + * mixing the original color with noise with a ratio of `1 / 2^n_bits`. + */ + return f + (d - f) * s; +} + +static force_inline float +dither_compute_scale (int n_bits) +{ + // No dithering for wide formats + if (n_bits == 0 || n_bits >= 32) + return 0.f; + + return 1.f / (float)(1 << n_bits); +} + +static const uint32_t * +dither_apply_ordered (pixman_iter_t *iter, dither_factor_t factor) +{ + bits_image_t *image = &iter->image->bits; + int x = iter->x + image->dither_offset_x; + int y = iter->y + image->dither_offset_y; + int width = iter->width; + argb_t *buffer = (argb_t *)iter->buffer; + + pixman_format_code_t format = image->format; + int a_size = PIXMAN_FORMAT_A (format); + int r_size = PIXMAN_FORMAT_R (format); + int g_size = PIXMAN_FORMAT_G (format); + int b_size = PIXMAN_FORMAT_B (format); + + float a_scale = dither_compute_scale (a_size); + float r_scale = dither_compute_scale (r_size); + float g_scale = dither_compute_scale (g_size); + float b_scale = dither_compute_scale (b_size); + + int i; + float d; + + for (i = 0; i < width; ++i) + { + d = factor (x + i, y); + + buffer->a = dither_apply_channel (buffer->a, d, a_scale); + buffer->r = dither_apply_channel (buffer->r, d, r_scale); + buffer->g = dither_apply_channel (buffer->g, d, g_scale); + buffer->b = dither_apply_channel (buffer->b, d, b_scale); + + buffer++; + } + + return iter->buffer; +} + static void dest_write_back_wide (pixman_iter_t *iter) { @@ -1653,6 +1173,23 @@ dest_write_back_wide (pixman_iter_t *iter) int width = iter->width; const uint32_t *buffer = iter->buffer; + switch (image->dither) + { + case PIXMAN_DITHER_NONE: + break; + + case PIXMAN_DITHER_GOOD: + case PIXMAN_DITHER_BEST: + case PIXMAN_DITHER_ORDERED_BLUE_NOISE_64: + buffer = dither_apply_ordered (iter, dither_factor_blue_noise_64); + break; + + case PIXMAN_DITHER_FAST: + case PIXMAN_DITHER_ORDERED_BAYER_8: + buffer = dither_apply_ordered (iter, dither_factor_bayer_8); + break; + } + image->store_scanline_float (image, x, y, width, buffer); if (image->common.alpha_map) @@ -1670,20 +1207,7 @@ dest_write_back_wide (pixman_iter_t *iter) void _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter) { - if (iter->iter_flags & ITER_16) - { - if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == - (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) - { - iter->get_scanline = _pixman_iter_get_scanline_noop; - } - else - { - iter->get_scanline = dest_get_scanline_16; - } - iter->write_back = dest_write_back_16; - } - else if (iter->iter_flags & ITER_NARROW) + if (iter->iter_flags & ITER_NARROW) { if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) @@ -1694,7 +1218,7 @@ _pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter) { iter->get_scanline = dest_get_scanline_narrow; } - + iter->write_back = dest_write_back_narrow; } else @@ -1758,6 +1282,9 @@ _pixman_bits_image_init (pixman_image_t * image, { uint32_t *free_me = NULL; + if (PIXMAN_FORMAT_BPP (format) == 128) + return_val_if_fail(!(rowstride % 4), FALSE); + if (!bits && width && height) { int rowstride_bytes; @@ -1778,6 +1305,9 @@ _pixman_bits_image_init (pixman_image_t * image, image->bits.height = height; image->bits.bits = bits; image->bits.free_me = free_me; + image->bits.dither = PIXMAN_DITHER_NONE; + image->bits.dither_offset_x = 0; + image->bits.dither_offset_y = 0; image->bits.read_func = NULL; image->bits.write_func = NULL; image->bits.rowstride = rowstride; diff --git a/gfx/cairo/libpixman/src/pixman-combine-float.c b/gfx/cairo/libpixman/src/pixman-combine-float.c index 06ce2037ee..f5145bc9d7 100644 --- a/gfx/cairo/libpixman/src/pixman-combine-float.c +++ b/gfx/cairo/libpixman/src/pixman-combine-float.c @@ -42,8 +42,6 @@ #define force_inline __inline__ #endif -#define IS_ZERO(f) (-FLT_MIN < (f) && (f) < FLT_MIN) - typedef float (* combine_channel_t) (float sa, float s, float da, float d); static force_inline void @@ -203,56 +201,56 @@ get_factor (combine_factor_t factor, float sa, float da) break; case SA_OVER_DA: - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) f = 1.0f; else f = CLAMP (sa / da); break; case DA_OVER_SA: - if (IS_ZERO (sa)) + if (FLOAT_IS_ZERO (sa)) f = 1.0f; else f = CLAMP (da / sa); break; case INV_SA_OVER_DA: - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) f = 1.0f; else f = CLAMP ((1.0f - sa) / da); break; case INV_DA_OVER_SA: - if (IS_ZERO (sa)) + if (FLOAT_IS_ZERO (sa)) f = 1.0f; else f = CLAMP ((1.0f - da) / sa); break; case ONE_MINUS_SA_OVER_DA: - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) f = 0.0f; else f = CLAMP (1.0f - sa / da); break; case ONE_MINUS_DA_OVER_SA: - if (IS_ZERO (sa)) + if (FLOAT_IS_ZERO (sa)) f = 0.0f; else f = CLAMP (1.0f - da / sa); break; case ONE_MINUS_INV_DA_OVER_SA: - if (IS_ZERO (sa)) + if (FLOAT_IS_ZERO (sa)) f = 0.0f; else f = CLAMP (1.0f - (1.0f - da) / sa); break; case ONE_MINUS_INV_SA_OVER_DA: - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) f = 0.0f; else f = CLAMP (1.0f - (1.0f - sa) / da); @@ -321,23 +319,44 @@ MAKE_PD_COMBINERS (conjoint_xor, ONE_MINUS_DA_OVER_SA, ONE_MINUS_SA_OVER_DA) * * The following blend modes have been taken from the PDF ISO 32000 * specification, which at this point in time is available from - * http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf - * The relevant chapters are 11.3.5 and 11.3.6. + * + * http://www.adobe.com/devnet/pdf/pdf_reference.html + * + * The specific documents of interest are the PDF spec itself: + * + * http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf + * + * chapters 11.3.5 and 11.3.6 and a later supplement for Adobe Acrobat + * 9.1 and Reader 9.1: + * + * http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/adobe_supplement_iso32000_1.pdf + * + * that clarifies the specifications for blend modes ColorDodge and + * ColorBurn. + * * The formula for computing the final pixel color given in 11.3.6 is: - * αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs) - * with B() being the blend function. - * Note that OVER is a special case of this operation, using B(Cb, Cs) = Cs * - * These blend modes should match the SVG filter draft specification, as - * it has been designed to mirror ISO 32000. Note that at the current point - * no released draft exists that shows this, as the formulas have not been - * updated yet after the release of ISO 32000. + * αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs) * - * The default implementation here uses the PDF_SEPARABLE_BLEND_MODE and - * PDF_NON_SEPARABLE_BLEND_MODE macros, which take the blend function as an - * argument. Note that this implementation operates on premultiplied colors, - * while the PDF specification does not. Therefore the code uses the formula - * ar.Cra = (1 – as) . Dca + (1 – ad) . Sca + B(Dca, ad, Sca, as) + * with B() is the blend function. When B(Cb, Cs) = Cs, this formula + * reduces to the regular OVER operator. + * + * Cs and Cb are not premultiplied, so in our implementation we instead + * use: + * + * cr = (1 – αs) × cb + (1 – αb) × cs + αb × αs × B (cb/αb, cs/αs) + * + * where cr, cs, and cb are premultiplied colors, and where the + * + * αb × αs × B(cb/αb, cs/αs) + * + * part is first arithmetically simplified under the assumption that αb + * and αs are not 0, and then updated to produce a meaningful result when + * they are. + * + * For all the blend mode operators, the alpha channel is given by + * + * αr = αs + αb + αb × αs */ #define MAKE_SEPARABLE_PDF_COMBINERS(name) \ @@ -357,18 +376,55 @@ MAKE_PD_COMBINERS (conjoint_xor, ONE_MINUS_DA_OVER_SA, ONE_MINUS_SA_OVER_DA) \ MAKE_COMBINERS (name, combine_ ## name ## _a, combine_ ## name ## _c) +/* + * Multiply + * + * ad * as * B(d / ad, s / as) + * = ad * as * d/ad * s/as + * = d * s + * + */ static force_inline float blend_multiply (float sa, float s, float da, float d) { return d * s; } +/* + * Screen + * + * ad * as * B(d/ad, s/as) + * = ad * as * (d/ad + s/as - s/as * d/ad) + * = ad * s + as * d - s * d + */ static force_inline float blend_screen (float sa, float s, float da, float d) { return d * sa + s * da - s * d; } +/* + * Overlay + * + * ad * as * B(d/ad, s/as) + * = ad * as * Hardlight (s, d) + * = if (d / ad < 0.5) + * as * ad * Multiply (s/as, 2 * d/ad) + * else + * as * ad * Screen (s/as, 2 * d / ad - 1) + * = if (d < 0.5 * ad) + * as * ad * s/as * 2 * d /ad + * else + * as * ad * (s/as + 2 * d / ad - 1 - s / as * (2 * d / ad - 1)) + * = if (2 * d < ad) + * 2 * s * d + * else + * ad * s + 2 * as * d - as * ad - ad * s * (2 * d / ad - 1) + * = if (2 * d < ad) + * 2 * s * d + * else + * as * ad - 2 * (ad - d) * (as - s) + */ static force_inline float blend_overlay (float sa, float s, float da, float d) { @@ -378,6 +434,13 @@ blend_overlay (float sa, float s, float da, float d) return sa * da - 2 * (da - d) * (sa - s); } +/* + * Darken + * + * ad * as * B(d/ad, s/as) + * = ad * as * MIN(d/ad, s/as) + * = MIN (as * d, ad * s) + */ static force_inline float blend_darken (float sa, float s, float da, float d) { @@ -390,6 +453,13 @@ blend_darken (float sa, float s, float da, float d) return s; } +/* + * Lighten + * + * ad * as * B(d/ad, s/as) + * = ad * as * MAX(d/ad, s/as) + * = MAX (as * d, ad * s) + */ static force_inline float blend_lighten (float sa, float s, float da, float d) { @@ -402,19 +472,57 @@ blend_lighten (float sa, float s, float da, float d) return d; } +/* + * Color dodge + * + * ad * as * B(d/ad, s/as) + * = if d/ad = 0 + * ad * as * 0 + * else if (d/ad >= (1 - s/as) + * ad * as * 1 + * else + * ad * as * ((d/ad) / (1 - s/as)) + * = if d = 0 + * 0 + * elif as * d >= ad * (as - s) + * ad * as + * else + * as * (as * d / (as - s)) + * + */ static force_inline float blend_color_dodge (float sa, float s, float da, float d) { - if (IS_ZERO (d)) + if (FLOAT_IS_ZERO (d)) return 0.0f; else if (d * sa >= sa * da - s * da) return sa * da; - else if (IS_ZERO (sa - s)) + else if (FLOAT_IS_ZERO (sa - s)) return sa * da; else return sa * sa * d / (sa - s); } +/* + * Color burn + * + * We modify the first clause "if d = 1" to "if d >= 1" since with + * premultiplied colors d > 1 can actually happen. + * + * ad * as * B(d/ad, s/as) + * = if d/ad >= 1 + * ad * as * 1 + * elif (1 - d/ad) >= s/as + * ad * as * 0 + * else + * ad * as * (1 - ((1 - d/ad) / (s/as))) + * = if d >= ad + * ad * as + * elif as * ad - as * d >= ad * s + * 0 + * else + * ad * as - as * as * (ad - d) / s + */ static force_inline float blend_color_burn (float sa, float s, float da, float d) { @@ -422,12 +530,29 @@ blend_color_burn (float sa, float s, float da, float d) return sa * da; else if (sa * (da - d) >= s * da) return 0.0f; - else if (IS_ZERO (s)) + else if (FLOAT_IS_ZERO (s)) return 0.0f; else return sa * (da - sa * (da - d) / s); } +/* + * Hard light + * + * ad * as * B(d/ad, s/as) + * = if (s/as <= 0.5) + * ad * as * Multiply (d/ad, 2 * s/as) + * else + * ad * as * Screen (d/ad, 2 * s/as - 1) + * = if 2 * s <= as + * ad * as * d/ad * 2 * s / as + * else + * ad * as * (d/ad + (2 * s/as - 1) + d/ad * (2 * s/as - 1)) + * = if 2 * s <= as + * 2 * s * d + * else + * as * ad - 2 * (ad - d) * (as - s) + */ static force_inline float blend_hard_light (float sa, float s, float da, float d) { @@ -437,21 +562,38 @@ blend_hard_light (float sa, float s, float da, float d) return sa * da - 2 * (da - d) * (sa - s); } +/* + * Soft light + * + * ad * as * B(d/ad, s/as) + * = if (s/as <= 0.5) + * ad * as * (d/ad - (1 - 2 * s/as) * d/ad * (1 - d/ad)) + * else if (d/ad <= 0.25) + * ad * as * (d/ad + (2 * s/as - 1) * ((((16 * d/ad - 12) * d/ad + 4) * d/ad) - d/ad)) + * else + * ad * as * (d/ad + (2 * s/as - 1) * sqrt (d/ad)) + * = if (2 * s <= as) + * d * as - d * (ad - d) * (as - 2 * s) / ad; + * else if (4 * d <= ad) + * (2 * s - as) * d * ((16 * d / ad - 12) * d / ad + 3); + * else + * d * as + (sqrt (d * ad) - d) * (2 * s - as); + */ static force_inline float blend_soft_light (float sa, float s, float da, float d) { - if (2 * s < sa) + if (2 * s <= sa) { - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) return d * sa; else return d * sa - d * (da - d) * (sa - 2 * s) / da; } else { - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) { - return 0.0f; + return d * sa; } else { @@ -463,6 +605,20 @@ blend_soft_light (float sa, float s, float da, float d) } } +/* + * Difference + * + * ad * as * B(s/as, d/ad) + * = ad * as * abs (s/as - d/ad) + * = if (s/as <= d/ad) + * ad * as * (d/ad - s/as) + * else + * ad * as * (s/as - d/ad) + * = if (ad * s <= as * d) + * as * d - ad * s + * else + * ad * s - as * d + */ static force_inline float blend_difference (float sa, float s, float da, float d) { @@ -475,6 +631,13 @@ blend_difference (float sa, float s, float da, float d) return sda - dsa; } +/* + * Exclusion + * + * ad * as * B(s/as, d/ad) + * = ad * as * (d/ad + s/as - 2 * d/ad * s/as) + * = as * d + ad * s - 2 * s * d + */ static force_inline float blend_exclusion (float sa, float s, float da, float d) { @@ -494,116 +657,79 @@ MAKE_SEPARABLE_PDF_COMBINERS (difference) MAKE_SEPARABLE_PDF_COMBINERS (exclusion) /* - * PDF nonseperable blend modes. - * - * These are implemented using the following functions to operate in Hsl - * space, with Cmax, Cmid, Cmin referring to the max, mid and min value - * of the red, green and blue components. + * PDF nonseperable blend modes are implemented using the following functions + * to operate in Hsl space, with Cmax, Cmid, Cmin referring to the max, mid + * and min value of the red, green and blue components. * * LUM (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue * * clip_color (C): - * l = LUM (C) - * min = Cmin - * max = Cmax - * if n < 0.0 - * C = l + (((C – l) × l) ⁄ (l – min)) - * if x > 1.0 - * C = l + (((C – l) × (1 – l)) (max – l)) - * return C + * l = LUM (C) + * min = Cmin + * max = Cmax + * if n < 0.0 + * C = l + (((C – l) × l) ⁄ (l – min)) + * if x > 1.0 + * C = l + (((C – l) × (1 – l) ) ⁄ (max – l)) + * return C * * set_lum (C, l): - * d = l – LUM (C) - * C += d - * return clip_color (C) + * d = l – LUM (C) + * C += d + * return clip_color (C) * * SAT (C) = CH_MAX (C) - CH_MIN (C) * * set_sat (C, s): - * if Cmax > Cmin - * Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) ) - * Cmax = s - * else - * Cmid = Cmax = 0.0 - * Cmin = 0.0 - * return C + * if Cmax > Cmin + * Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) ) + * Cmax = s + * else + * Cmid = Cmax = 0.0 + * Cmin = 0.0 + * return C */ /* For premultiplied colors, we need to know what happens when C is * multiplied by a real number. LUM and SAT are linear: * - * LUM (r × C) = r × LUM (C) SAT (r × C) = r × SAT (C) + * LUM (r × C) = r × LUM (C) SAT (r * C) = r * SAT (C) * * If we extend clip_color with an extra argument a and change * - * if x >= 1.0 + * if x >= 1.0 * * into * - * if x >= a + * if x >= a * * then clip_color is also linear: * - * r * clip_color (C, a) = clip_color (r_c, ra); + * r * clip_color (C, a) = clip_color (r * C, r * a); * * for positive r. * * Similarly, we can extend set_lum with an extra argument that is just passed * on to clip_color: * - * r × set_lum ( C, l, a) + * r * set_lum (C, l, a) * - * = r × clip_color ( C + l - LUM (C), a) + * = r × clip_color (C + l - LUM (C), a) * - * = clip_color ( r * C + r × l - LUM (r × C), r * a) + * = clip_color (r * C + r × l - r * LUM (C), r * a) * - * = set_lum ( r * C, r * l, r * a) + * = set_lum (r * C, r * l, r * a) * * Finally, set_sat: * - * r * set_sat (C, s) = set_sat (x * C, r * s) + * r * set_sat (C, s) = set_sat (x * C, r * s) * - * The above holds for all non-zero x because they x'es in the fraction for + * The above holds for all non-zero x, because the x'es in the fraction for * C_mid cancel out. Specifically, it holds for x = r: * - * r * set_sat (C, s) = set_sat (r_c, rs) - * - * - * - * - * So, for the non-separable PDF blend modes, we have (using s, d for - * non-premultiplied colors, and S, D for premultiplied: - * - * Color: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (S/a_s, LUM (D/a_d), 1) - * = set_lum (S * a_d, a_s * LUM (D), a_s * a_d) - * - * - * Luminosity: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (D/a_d, LUM(S/a_s), 1) - * = set_lum (a_s * D, a_d * LUM(S), a_s * a_d) - * - * - * Saturation: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (set_sat (D/a_d, SAT (S/a_s)), LUM (D/a_d), 1) - * = set_lum (a_s * a_d * set_sat (D/a_d, SAT (S/a_s)), - * a_s * LUM (D), a_s * a_d) - * = set_lum (set_sat (a_s * D, a_d * SAT (S), a_s * LUM (D), a_s * a_d)) - * - * Hue: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (set_sat (S/a_s, SAT (D/a_d)), LUM (D/a_d), 1) - * = set_lum (set_sat (a_d * S, a_s * SAT (D)), a_s * LUM (D), a_s * a_d) + * r * set_sat (C, s) = set_sat (r * C, r * s) * */ - typedef struct { float r; @@ -658,7 +784,7 @@ clip_color (rgb_t *color, float a) if (n < 0.0f) { t = l - n; - if (IS_ZERO (t)) + if (FLOAT_IS_ZERO (t)) { color->r = 0.0f; color->g = 0.0f; @@ -674,7 +800,7 @@ clip_color (rgb_t *color, float a) if (x > a) { t = x - l; - if (IS_ZERO (t)) + if (FLOAT_IS_ZERO (t)) { color->r = a; color->g = a; @@ -758,7 +884,7 @@ set_sat (rgb_t *src, float sat) t = *max - *min; - if (IS_ZERO (t)) + if (FLOAT_IS_ZERO (t)) { *mid = *max = 0.0f; } @@ -771,9 +897,12 @@ set_sat (rgb_t *src, float sat) *min = 0.0f; } -/* - * Hue: - * B(Cb, Cs) = set_lum (set_sat (Cs, SAT (Cb)), LUM (Cb)) +/* Hue: + * + * as * ad * B(s/as, d/as) + * = as * ad * set_lum (set_sat (s/as, SAT (d/ad)), LUM (d/ad), 1) + * = set_lum (set_sat (ad * s, as * SAT (d)), as * LUM (d), as * ad) + * */ static force_inline void blend_hsl_hue (rgb_t *res, @@ -788,9 +917,14 @@ blend_hsl_hue (rgb_t *res, set_lum (res, sa * da, get_lum (dest) * sa); } -/* - * Saturation: - * B(Cb, Cs) = set_lum (set_sat (Cb, SAT (Cs)), LUM (Cb)) +/* + * Saturation + * + * as * ad * B(s/as, d/ad) + * = as * ad * set_lum (set_sat (d/ad, SAT (s/as)), LUM (d/ad), 1) + * = set_lum (as * ad * set_sat (d/ad, SAT (s/as)), + * as * LUM (d), as * ad) + * = set_lum (set_sat (as * d, ad * SAT (s), as * LUM (d), as * ad)) */ static force_inline void blend_hsl_saturation (rgb_t *res, @@ -805,9 +939,12 @@ blend_hsl_saturation (rgb_t *res, set_lum (res, sa * da, get_lum (dest) * sa); } -/* - * Color: - * B(Cb, Cs) = set_lum (Cs, LUM (Cb)) +/* + * Color + * + * as * ad * B(s/as, d/as) + * = as * ad * set_lum (s/as, LUM (d/ad), 1) + * = set_lum (s * ad, as * LUM (d), as * ad) */ static force_inline void blend_hsl_color (rgb_t *res, @@ -822,8 +959,11 @@ blend_hsl_color (rgb_t *res, } /* - * Luminosity: - * B(Cb, Cs) = set_lum (Cb, LUM (Cs)) + * Luminosity + * + * as * ad * B(s/as, d/ad) + * = as * ad * set_lum (d/ad, LUM (s/as), 1) + * = set_lum (as * d, ad * LUM (s), as * ad) */ static force_inline void blend_hsl_luminosity (rgb_t *res, diff --git a/gfx/cairo/libpixman/src/pixman-combine.c.template b/gfx/cairo/libpixman/src/pixman-combine.c.template deleted file mode 100644 index cd008d9673..0000000000 --- a/gfx/cairo/libpixman/src/pixman-combine.c.template +++ /dev/null @@ -1,2461 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "pixman-private.h" - -#include "pixman-combine.h" - -/*** per channel helper functions ***/ - -static void -combine_mask_ca (comp4_t *src, comp4_t *mask) -{ - comp4_t a = *mask; - - comp4_t x; - comp2_t xa; - - if (!a) - { - *(src) = 0; - return; - } - - x = *(src); - if (a == ~0) - { - x = x >> A_SHIFT; - x |= x << G_SHIFT; - x |= x << R_SHIFT; - *(mask) = x; - return; - } - - xa = x >> A_SHIFT; - UNcx4_MUL_UNcx4 (x, a); - *(src) = x; - - UNcx4_MUL_UNc (a, xa); - *(mask) = a; -} - -static void -combine_mask_value_ca (comp4_t *src, const comp4_t *mask) -{ - comp4_t a = *mask; - comp4_t x; - - if (!a) - { - *(src) = 0; - return; - } - - if (a == ~0) - return; - - x = *(src); - UNcx4_MUL_UNcx4 (x, a); - *(src) = x; -} - -static void -combine_mask_alpha_ca (const comp4_t *src, comp4_t *mask) -{ - comp4_t a = *(mask); - comp4_t x; - - if (!a) - return; - - x = *(src) >> A_SHIFT; - if (x == MASK) - return; - - if (a == ~0) - { - x |= x << G_SHIFT; - x |= x << R_SHIFT; - *(mask) = x; - return; - } - - UNcx4_MUL_UNc (a, x); - *(mask) = a; -} - -/* - * There are two ways of handling alpha -- either as a single unified value or - * a separate value for each component, hence each macro must have two - * versions. The unified alpha version has a 'U' at the end of the name, - * the component version has a 'C'. Similarly, functions which deal with - * this difference will have two versions using the same convention. - */ - -/* - * All of the composing functions - */ - -static force_inline comp4_t -combine_mask (const comp4_t *src, const comp4_t *mask, int i) -{ - comp4_t s, m; - - if (mask) - { - m = *(mask + i) >> A_SHIFT; - - if (!m) - return 0; - } - - s = *(src + i); - - if (mask) - UNcx4_MUL_UNc (s, m); - - return s; -} - -static void -combine_clear (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - memset (dest, 0, width * sizeof(comp4_t)); -} - -static void -combine_dst (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - return; -} - -static void -combine_src_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - if (!mask) - memcpy (dest, src, width * sizeof (comp4_t)); - else - { - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - - *(dest + i) = s; - } - } -} - -/* if the Src is opaque, call combine_src_u */ -static void -combine_over_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp4_t ia = ALPHA_c (~s); - - UNcx4_MUL_UNc_ADD_UNcx4 (d, ia, s); - *(dest + i) = d; - } -} - -/* if the Dst is opaque, this is a noop */ -static void -combine_over_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp4_t ia = ALPHA_c (~*(dest + i)); - UNcx4_MUL_UNc_ADD_UNcx4 (s, ia, d); - *(dest + i) = s; - } -} - -/* if the Dst is opaque, call combine_src_u */ -static void -combine_in_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t a = ALPHA_c (*(dest + i)); - UNcx4_MUL_UNc (s, a); - *(dest + i) = s; - } -} - -/* if the Src is opaque, this is a noop */ -static void -combine_in_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp4_t a = ALPHA_c (s); - UNcx4_MUL_UNc (d, a); - *(dest + i) = d; - } -} - -/* if the Dst is opaque, call combine_clear */ -static void -combine_out_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t a = ALPHA_c (~*(dest + i)); - UNcx4_MUL_UNc (s, a); - *(dest + i) = s; - } -} - -/* if the Src is opaque, call combine_clear */ -static void -combine_out_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp4_t a = ALPHA_c (~s); - UNcx4_MUL_UNc (d, a); - *(dest + i) = d; - } -} - -/* if the Src is opaque, call combine_in_u */ -/* if the Dst is opaque, call combine_over_u */ -/* if both the Src and Dst are opaque, call combine_src_u */ -static void -combine_atop_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp4_t dest_a = ALPHA_c (d); - comp4_t src_ia = ALPHA_c (~s); - - UNcx4_MUL_UNc_ADD_UNcx4_MUL_UNc (s, dest_a, d, src_ia); - *(dest + i) = s; - } -} - -/* if the Src is opaque, call combine_over_reverse_u */ -/* if the Dst is opaque, call combine_in_reverse_u */ -/* if both the Src and Dst are opaque, call combine_dst_u */ -static void -combine_atop_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp4_t src_a = ALPHA_c (s); - comp4_t dest_ia = ALPHA_c (~d); - - UNcx4_MUL_UNc_ADD_UNcx4_MUL_UNc (s, dest_ia, d, src_a); - *(dest + i) = s; - } -} - -/* if the Src is opaque, call combine_over_u */ -/* if the Dst is opaque, call combine_over_reverse_u */ -/* if both the Src and Dst are opaque, call combine_clear */ -static void -combine_xor_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp4_t src_ia = ALPHA_c (~s); - comp4_t dest_ia = ALPHA_c (~d); - - UNcx4_MUL_UNc_ADD_UNcx4_MUL_UNc (s, dest_ia, d, src_ia); - *(dest + i) = s; - } -} - -static void -combine_add_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - UNcx4_ADD_UNcx4 (d, s); - *(dest + i) = d; - } -} - -/* if the Src is opaque, call combine_add_u */ -/* if the Dst is opaque, call combine_add_u */ -/* if both the Src and Dst are opaque, call combine_add_u */ -static void -combine_saturate_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp2_t sa, da; - - sa = s >> A_SHIFT; - da = ~d >> A_SHIFT; - if (sa > da) - { - sa = DIV_UNc (da, sa); - UNcx4_MUL_UNc (s, sa); - } - ; - UNcx4_ADD_UNcx4 (d, s); - *(dest + i) = d; - } -} - -/* - * PDF blend modes: - * The following blend modes have been taken from the PDF ISO 32000 - * specification, which at this point in time is available from - * http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf - * The relevant chapters are 11.3.5 and 11.3.6. - * The formula for computing the final pixel color given in 11.3.6 is: - * αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs) - * with B() being the blend function. - * Note that OVER is a special case of this operation, using B(Cb, Cs) = Cs - * - * These blend modes should match the SVG filter draft specification, as - * it has been designed to mirror ISO 32000. Note that at the current point - * no released draft exists that shows this, as the formulas have not been - * updated yet after the release of ISO 32000. - * - * The default implementation here uses the PDF_SEPARABLE_BLEND_MODE and - * PDF_NON_SEPARABLE_BLEND_MODE macros, which take the blend function as an - * argument. Note that this implementation operates on premultiplied colors, - * while the PDF specification does not. Therefore the code uses the formula - * Cra = (1 – as) . Dca + (1 – ad) . Sca + B(Dca, ad, Sca, as) - */ - -/* - * Multiply - * B(Dca, ad, Sca, as) = Dca.Sca - */ - -static void -combine_multiply_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp4_t ss = s; - comp4_t src_ia = ALPHA_c (~s); - comp4_t dest_ia = ALPHA_c (~d); - - UNcx4_MUL_UNc_ADD_UNcx4_MUL_UNc (ss, dest_ia, d, src_ia); - UNcx4_MUL_UNcx4 (d, s); - UNcx4_ADD_UNcx4 (d, ss); - - *(dest + i) = d; - } -} - -static void -combine_multiply_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t m = *(mask + i); - comp4_t s = *(src + i); - comp4_t d = *(dest + i); - comp4_t r = d; - comp4_t dest_ia = ALPHA_c (~d); - - combine_mask_value_ca (&s, &m); - - UNcx4_MUL_UNcx4_ADD_UNcx4_MUL_UNc (r, ~m, s, dest_ia); - UNcx4_MUL_UNcx4 (d, s); - UNcx4_ADD_UNcx4 (r, d); - - *(dest + i) = r; - } -} - -#define PDF_SEPARABLE_BLEND_MODE(name) \ - static void \ - combine_ ## name ## _u (pixman_implementation_t *imp, \ - pixman_op_t op, \ - comp4_t * dest, \ - const comp4_t * src, \ - const comp4_t * mask, \ - int width) \ - { \ - int i; \ - for (i = 0; i < width; ++i) { \ - comp4_t s = combine_mask (src, mask, i); \ - comp4_t d = *(dest + i); \ - comp1_t sa = ALPHA_c (s); \ - comp1_t isa = ~sa; \ - comp1_t da = ALPHA_c (d); \ - comp1_t ida = ~da; \ - comp4_t result; \ - \ - result = d; \ - UNcx4_MUL_UNc_ADD_UNcx4_MUL_UNc (result, isa, s, ida); \ - \ - *(dest + i) = result + \ - (DIV_ONE_UNc (sa * (comp4_t)da) << A_SHIFT) + \ - (blend_ ## name (RED_c (d), da, RED_c (s), sa) << R_SHIFT) + \ - (blend_ ## name (GREEN_c (d), da, GREEN_c (s), sa) << G_SHIFT) + \ - (blend_ ## name (BLUE_c (d), da, BLUE_c (s), sa)); \ - } \ - } \ - \ - static void \ - combine_ ## name ## _ca (pixman_implementation_t *imp, \ - pixman_op_t op, \ - comp4_t * dest, \ - const comp4_t * src, \ - const comp4_t * mask, \ - int width) \ - { \ - int i; \ - for (i = 0; i < width; ++i) { \ - comp4_t m = *(mask + i); \ - comp4_t s = *(src + i); \ - comp4_t d = *(dest + i); \ - comp1_t da = ALPHA_c (d); \ - comp1_t ida = ~da; \ - comp4_t result; \ - \ - combine_mask_value_ca (&s, &m); \ - \ - result = d; \ - UNcx4_MUL_UNcx4_ADD_UNcx4_MUL_UNc (result, ~m, s, ida); \ - \ - result += \ - (DIV_ONE_UNc (ALPHA_c (m) * (comp4_t)da) << A_SHIFT) + \ - (blend_ ## name (RED_c (d), da, RED_c (s), RED_c (m)) << R_SHIFT) + \ - (blend_ ## name (GREEN_c (d), da, GREEN_c (s), GREEN_c (m)) << G_SHIFT) + \ - (blend_ ## name (BLUE_c (d), da, BLUE_c (s), BLUE_c (m))); \ - \ - *(dest + i) = result; \ - } \ - } - -/* - * Screen - * B(Dca, ad, Sca, as) = Dca.sa + Sca.da - Dca.Sca - */ -static inline comp4_t -blend_screen (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) -{ - return DIV_ONE_UNc (sca * da + dca * sa - sca * dca); -} - -PDF_SEPARABLE_BLEND_MODE (screen) - -/* - * Overlay - * B(Dca, Da, Sca, Sa) = - * if 2.Dca < Da - * 2.Sca.Dca - * otherwise - * Sa.Da - 2.(Da - Dca).(Sa - Sca) - */ -static inline comp4_t -blend_overlay (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) -{ - comp4_t rca; - - if (2 * dca < da) - rca = 2 * sca * dca; - else - rca = sa * da - 2 * (da - dca) * (sa - sca); - return DIV_ONE_UNc (rca); -} - -PDF_SEPARABLE_BLEND_MODE (overlay) - -/* - * Darken - * B(Dca, Da, Sca, Sa) = min (Sca.Da, Dca.Sa) - */ -static inline comp4_t -blend_darken (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) -{ - comp4_t s, d; - - s = sca * da; - d = dca * sa; - return DIV_ONE_UNc (s > d ? d : s); -} - -PDF_SEPARABLE_BLEND_MODE (darken) - -/* - * Lighten - * B(Dca, Da, Sca, Sa) = max (Sca.Da, Dca.Sa) - */ -static inline comp4_t -blend_lighten (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) -{ - comp4_t s, d; - - s = sca * da; - d = dca * sa; - return DIV_ONE_UNc (s > d ? s : d); -} - -PDF_SEPARABLE_BLEND_MODE (lighten) - -/* - * Color dodge - * B(Dca, Da, Sca, Sa) = - * if Dca == 0 - * 0 - * if Sca == Sa - * Sa.Da - * otherwise - * Sa.Da. min (1, Dca / Da / (1 - Sca/Sa)) - */ -static inline comp4_t -blend_color_dodge (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) -{ - if (sca >= sa) - { - return dca == 0 ? 0 : DIV_ONE_UNc (sa * da); - } - else - { - comp4_t rca = dca * sa / (sa - sca); - return DIV_ONE_UNc (sa * MIN (rca, da)); - } -} - -PDF_SEPARABLE_BLEND_MODE (color_dodge) - -/* - * Color burn - * B(Dca, Da, Sca, Sa) = - * if Dca == Da - * Sa.Da - * if Sca == 0 - * 0 - * otherwise - * Sa.Da.(1 - min (1, (1 - Dca/Da).Sa / Sca)) - */ -static inline comp4_t -blend_color_burn (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) -{ - if (sca == 0) - { - return dca < da ? 0 : DIV_ONE_UNc (sa * da); - } - else - { - comp4_t rca = (da - dca) * sa / sca; - return DIV_ONE_UNc (sa * (MAX (rca, da) - rca)); - } -} - -PDF_SEPARABLE_BLEND_MODE (color_burn) - -/* - * Hard light - * B(Dca, Da, Sca, Sa) = - * if 2.Sca < Sa - * 2.Sca.Dca - * otherwise - * Sa.Da - 2.(Da - Dca).(Sa - Sca) - */ -static inline comp4_t -blend_hard_light (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) -{ - if (2 * sca < sa) - return DIV_ONE_UNc (2 * sca * dca); - else - return DIV_ONE_UNc (sa * da - 2 * (da - dca) * (sa - sca)); -} - -PDF_SEPARABLE_BLEND_MODE (hard_light) - -/* - * Soft light - * B(Dca, Da, Sca, Sa) = - * if (2.Sca <= Sa) - * Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa)) - * otherwise if Dca.4 <= Da - * Dca.(Sa + (2.Sca - Sa).((16.Dca/Da - 12).Dca/Da + 3) - * otherwise - * (Dca.Sa + (SQRT (Dca/Da).Da - Dca).(2.Sca - Sa)) - */ -static inline comp4_t -blend_soft_light (comp4_t dca_org, - comp4_t da_org, - comp4_t sca_org, - comp4_t sa_org) -{ - double dca = dca_org * (1.0 / MASK); - double da = da_org * (1.0 / MASK); - double sca = sca_org * (1.0 / MASK); - double sa = sa_org * (1.0 / MASK); - double rca; - - if (2 * sca < sa) - { - if (da == 0) - rca = dca * sa; - else - rca = dca * sa - dca * (da - dca) * (sa - 2 * sca) / da; - } - else if (da == 0) - { - rca = 0; - } - else if (4 * dca <= da) - { - rca = dca * sa + - (2 * sca - sa) * dca * ((16 * dca / da - 12) * dca / da + 3); - } - else - { - rca = dca * sa + (sqrt (dca * da) - dca) * (2 * sca - sa); - } - return rca * MASK + 0.5; -} - -PDF_SEPARABLE_BLEND_MODE (soft_light) - -/* - * Difference - * B(Dca, Da, Sca, Sa) = abs (Dca.Sa - Sca.Da) - */ -static inline comp4_t -blend_difference (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) -{ - comp4_t dcasa = dca * sa; - comp4_t scada = sca * da; - - if (scada < dcasa) - return DIV_ONE_UNc (dcasa - scada); - else - return DIV_ONE_UNc (scada - dcasa); -} - -PDF_SEPARABLE_BLEND_MODE (difference) - -/* - * Exclusion - * B(Dca, Da, Sca, Sa) = (Sca.Da + Dca.Sa - 2.Sca.Dca) - */ - -/* This can be made faster by writing it directly and not using - * PDF_SEPARABLE_BLEND_MODE, but that's a performance optimization */ - -static inline comp4_t -blend_exclusion (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) -{ - return DIV_ONE_UNc (sca * da + dca * sa - 2 * dca * sca); -} - -PDF_SEPARABLE_BLEND_MODE (exclusion) - -#undef PDF_SEPARABLE_BLEND_MODE - -/* - * PDF nonseperable blend modes are implemented using the following functions - * to operate in Hsl space, with Cmax, Cmid, Cmin referring to the max, mid - * and min value of the red, green and blue components. - * - * LUM (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue - * - * clip_color (C): - * l = LUM (C) - * min = Cmin - * max = Cmax - * if n < 0.0 - * C = l + ( ( ( C – l ) × l ) ⁄ ( l – min ) ) - * if x > 1.0 - * C = l + ( ( ( C – l ) × ( 1 – l ) ) ⁄ ( max – l ) ) - * return C - * - * set_lum (C, l): - * d = l – LUM (C) - * C += d - * return clip_color (C) - * - * SAT (C) = CH_MAX (C) - CH_MIN (C) - * - * set_sat (C, s): - * if Cmax > Cmin - * Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) ) - * Cmax = s - * else - * Cmid = Cmax = 0.0 - * Cmin = 0.0 - * return C - */ - -/* For premultiplied colors, we need to know what happens when C is - * multiplied by a real number. LUM and SAT are linear: - * - * LUM (r × C) = r × LUM (C) SAT (r * C) = r * SAT (C) - * - * If we extend clip_color with an extra argument a and change - * - * if x >= 1.0 - * - * into - * - * if x >= a - * - * then clip_color is also linear: - * - * r * clip_color (C, a) = clip_color (r_c, ra); - * - * for positive r. - * - * Similarly, we can extend set_lum with an extra argument that is just passed - * on to clip_color: - * - * r * set_lum ( C, l, a) - * - * = r × clip_color ( C + l - LUM (C), a) - * - * = clip_color ( r * C + r × l - r * LUM (C), r * a) - * - * = set_lum ( r * C, r * l, r * a) - * - * Finally, set_sat: - * - * r * set_sat (C, s) = set_sat (x * C, r * s) - * - * The above holds for all non-zero x, because the x'es in the fraction for - * C_mid cancel out. Specifically, it holds for x = r: - * - * r * set_sat (C, s) = set_sat (r_c, rs) - * - */ - -/* So, for the non-separable PDF blend modes, we have (using s, d for - * non-premultiplied colors, and S, D for premultiplied: - * - * Color: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (S/a_s, LUM (D/a_d), 1) - * = set_lum (S * a_d, a_s * LUM (D), a_s * a_d) - * - * - * Luminosity: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (D/a_d, LUM(S/a_s), 1) - * = set_lum (a_s * D, a_d * LUM(S), a_s * a_d) - * - * - * Saturation: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (set_sat (D/a_d, SAT (S/a_s)), LUM (D/a_d), 1) - * = set_lum (a_s * a_d * set_sat (D/a_d, SAT (S/a_s)), - * a_s * LUM (D), a_s * a_d) - * = set_lum (set_sat (a_s * D, a_d * SAT (S), a_s * LUM (D), a_s * a_d)) - * - * Hue: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (set_sat (S/a_s, SAT (D/a_d)), LUM (D/a_d), 1) - * = set_lum (set_sat (a_d * S, a_s * SAT (D)), a_s * LUM (D), a_s * a_d) - * - */ - -#define CH_MIN(c) (c[0] < c[1] ? (c[0] < c[2] ? c[0] : c[2]) : (c[1] < c[2] ? c[1] : c[2])) -#define CH_MAX(c) (c[0] > c[1] ? (c[0] > c[2] ? c[0] : c[2]) : (c[1] > c[2] ? c[1] : c[2])) -#define LUM(c) ((c[0] * 30 + c[1] * 59 + c[2] * 11) / 100) -#define SAT(c) (CH_MAX (c) - CH_MIN (c)) - -#define PDF_NON_SEPARABLE_BLEND_MODE(name) \ - static void \ - combine_ ## name ## _u (pixman_implementation_t *imp, \ - pixman_op_t op, \ - comp4_t *dest, \ - const comp4_t *src, \ - const comp4_t *mask, \ - int width) \ - { \ - int i; \ - for (i = 0; i < width; ++i) \ - { \ - comp4_t s = combine_mask (src, mask, i); \ - comp4_t d = *(dest + i); \ - comp1_t sa = ALPHA_c (s); \ - comp1_t isa = ~sa; \ - comp1_t da = ALPHA_c (d); \ - comp1_t ida = ~da; \ - comp4_t result; \ - comp4_t sc[3], dc[3], c[3]; \ - \ - result = d; \ - UNcx4_MUL_UNc_ADD_UNcx4_MUL_UNc (result, isa, s, ida); \ - dc[0] = RED_c (d); \ - sc[0] = RED_c (s); \ - dc[1] = GREEN_c (d); \ - sc[1] = GREEN_c (s); \ - dc[2] = BLUE_c (d); \ - sc[2] = BLUE_c (s); \ - blend_ ## name (c, dc, da, sc, sa); \ - \ - *(dest + i) = result + \ - (DIV_ONE_UNc (sa * (comp4_t)da) << A_SHIFT) + \ - (DIV_ONE_UNc (c[0]) << R_SHIFT) + \ - (DIV_ONE_UNc (c[1]) << G_SHIFT) + \ - (DIV_ONE_UNc (c[2])); \ - } \ - } - -static void -set_lum (comp4_t dest[3], comp4_t src[3], comp4_t sa, comp4_t lum) -{ - double a, l, min, max; - double tmp[3]; - - a = sa * (1.0 / MASK); - - l = lum * (1.0 / MASK); - tmp[0] = src[0] * (1.0 / MASK); - tmp[1] = src[1] * (1.0 / MASK); - tmp[2] = src[2] * (1.0 / MASK); - - l = l - LUM (tmp); - tmp[0] += l; - tmp[1] += l; - tmp[2] += l; - - /* clip_color */ - l = LUM (tmp); - min = CH_MIN (tmp); - max = CH_MAX (tmp); - - if (min < 0) - { - if (l - min == 0.0) - { - tmp[0] = 0; - tmp[1] = 0; - tmp[2] = 0; - } - else - { - tmp[0] = l + (tmp[0] - l) * l / (l - min); - tmp[1] = l + (tmp[1] - l) * l / (l - min); - tmp[2] = l + (tmp[2] - l) * l / (l - min); - } - } - if (max > a) - { - if (max - l == 0.0) - { - tmp[0] = a; - tmp[1] = a; - tmp[2] = a; - } - else - { - tmp[0] = l + (tmp[0] - l) * (a - l) / (max - l); - tmp[1] = l + (tmp[1] - l) * (a - l) / (max - l); - tmp[2] = l + (tmp[2] - l) * (a - l) / (max - l); - } - } - - dest[0] = tmp[0] * MASK + 0.5; - dest[1] = tmp[1] * MASK + 0.5; - dest[2] = tmp[2] * MASK + 0.5; -} - -static void -set_sat (comp4_t dest[3], comp4_t src[3], comp4_t sat) -{ - int id[3]; - comp4_t min, max; - - if (src[0] > src[1]) - { - if (src[0] > src[2]) - { - id[0] = 0; - if (src[1] > src[2]) - { - id[1] = 1; - id[2] = 2; - } - else - { - id[1] = 2; - id[2] = 1; - } - } - else - { - id[0] = 2; - id[1] = 0; - id[2] = 1; - } - } - else - { - if (src[0] > src[2]) - { - id[0] = 1; - id[1] = 0; - id[2] = 2; - } - else - { - id[2] = 0; - if (src[1] > src[2]) - { - id[0] = 1; - id[1] = 2; - } - else - { - id[0] = 2; - id[1] = 1; - } - } - } - - max = dest[id[0]]; - min = dest[id[2]]; - if (max > min) - { - dest[id[1]] = (dest[id[1]] - min) * sat / (max - min); - dest[id[0]] = sat; - dest[id[2]] = 0; - } - else - { - dest[0] = dest[1] = dest[2] = 0; - } -} - -/* - * Hue: - * B(Cb, Cs) = set_lum (set_sat (Cs, SAT (Cb)), LUM (Cb)) - */ -static inline void -blend_hsl_hue (comp4_t c[3], - comp4_t dc[3], - comp4_t da, - comp4_t sc[3], - comp4_t sa) -{ - c[0] = sc[0] * da; - c[1] = sc[1] * da; - c[2] = sc[2] * da; - set_sat (c, c, SAT (dc) * sa); - set_lum (c, c, sa * da, LUM (dc) * sa); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_hue) - -/* - * Saturation: - * B(Cb, Cs) = set_lum (set_sat (Cb, SAT (Cs)), LUM (Cb)) - */ -static inline void -blend_hsl_saturation (comp4_t c[3], - comp4_t dc[3], - comp4_t da, - comp4_t sc[3], - comp4_t sa) -{ - c[0] = dc[0] * sa; - c[1] = dc[1] * sa; - c[2] = dc[2] * sa; - set_sat (c, c, SAT (sc) * da); - set_lum (c, c, sa * da, LUM (dc) * sa); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_saturation) - -/* - * Color: - * B(Cb, Cs) = set_lum (Cs, LUM (Cb)) - */ -static inline void -blend_hsl_color (comp4_t c[3], - comp4_t dc[3], - comp4_t da, - comp4_t sc[3], - comp4_t sa) -{ - c[0] = sc[0] * da; - c[1] = sc[1] * da; - c[2] = sc[2] * da; - set_lum (c, c, sa * da, LUM (dc) * sa); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_color) - -/* - * Luminosity: - * B(Cb, Cs) = set_lum (Cb, LUM (Cs)) - */ -static inline void -blend_hsl_luminosity (comp4_t c[3], - comp4_t dc[3], - comp4_t da, - comp4_t sc[3], - comp4_t sa) -{ - c[0] = dc[0] * sa; - c[1] = dc[1] * sa; - c[2] = dc[2] * sa; - set_lum (c, c, sa * da, LUM (sc) * da); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_luminosity) - -#undef SAT -#undef LUM -#undef CH_MAX -#undef CH_MIN -#undef PDF_NON_SEPARABLE_BLEND_MODE - -/* All of the disjoint/conjoint composing functions - * - * The four entries in the first column indicate what source contributions - * come from each of the four areas of the picture -- areas covered by neither - * A nor B, areas covered only by A, areas covered only by B and finally - * areas covered by both A and B. - * - * Disjoint Conjoint - * Fa Fb Fa Fb - * (0,0,0,0) 0 0 0 0 - * (0,A,0,A) 1 0 1 0 - * (0,0,B,B) 0 1 0 1 - * (0,A,B,A) 1 min((1-a)/b,1) 1 max(1-a/b,0) - * (0,A,B,B) min((1-b)/a,1) 1 max(1-b/a,0) 1 - * (0,0,0,A) max(1-(1-b)/a,0) 0 min(1,b/a) 0 - * (0,0,0,B) 0 max(1-(1-a)/b,0) 0 min(a/b,1) - * (0,A,0,0) min(1,(1-b)/a) 0 max(1-b/a,0) 0 - * (0,0,B,0) 0 min(1,(1-a)/b) 0 max(1-a/b,0) - * (0,0,B,A) max(1-(1-b)/a,0) min(1,(1-a)/b) min(1,b/a) max(1-a/b,0) - * (0,A,0,B) min(1,(1-b)/a) max(1-(1-a)/b,0) max(1-b/a,0) min(1,a/b) - * (0,A,B,0) min(1,(1-b)/a) min(1,(1-a)/b) max(1-b/a,0) max(1-a/b,0) - * - * See http://marc.info/?l=xfree-render&m=99792000027857&w=2 for more - * information about these operators. - */ - -#define COMBINE_A_OUT 1 -#define COMBINE_A_IN 2 -#define COMBINE_B_OUT 4 -#define COMBINE_B_IN 8 - -#define COMBINE_CLEAR 0 -#define COMBINE_A (COMBINE_A_OUT | COMBINE_A_IN) -#define COMBINE_B (COMBINE_B_OUT | COMBINE_B_IN) -#define COMBINE_A_OVER (COMBINE_A_OUT | COMBINE_B_OUT | COMBINE_A_IN) -#define COMBINE_B_OVER (COMBINE_A_OUT | COMBINE_B_OUT | COMBINE_B_IN) -#define COMBINE_A_ATOP (COMBINE_B_OUT | COMBINE_A_IN) -#define COMBINE_B_ATOP (COMBINE_A_OUT | COMBINE_B_IN) -#define COMBINE_XOR (COMBINE_A_OUT | COMBINE_B_OUT) - -/* portion covered by a but not b */ -static comp1_t -combine_disjoint_out_part (comp1_t a, comp1_t b) -{ - /* min (1, (1-b) / a) */ - - b = ~b; /* 1 - b */ - if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */ - return MASK; /* 1 */ - return DIV_UNc (b, a); /* (1-b) / a */ -} - -/* portion covered by both a and b */ -static comp1_t -combine_disjoint_in_part (comp1_t a, comp1_t b) -{ - /* max (1-(1-b)/a,0) */ - /* = - min ((1-b)/a - 1, 0) */ - /* = 1 - min (1, (1-b)/a) */ - - b = ~b; /* 1 - b */ - if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */ - return 0; /* 1 - 1 */ - return ~DIV_UNc(b, a); /* 1 - (1-b) / a */ -} - -/* portion covered by a but not b */ -static comp1_t -combine_conjoint_out_part (comp1_t a, comp1_t b) -{ - /* max (1-b/a,0) */ - /* = 1-min(b/a,1) */ - - /* min (1, (1-b) / a) */ - - if (b >= a) /* b >= a -> b/a >= 1 */ - return 0x00; /* 0 */ - return ~DIV_UNc(b, a); /* 1 - b/a */ -} - -/* portion covered by both a and b */ -static comp1_t -combine_conjoint_in_part (comp1_t a, comp1_t b) -{ - /* min (1,b/a) */ - - if (b >= a) /* b >= a -> b/a >= 1 */ - return MASK; /* 1 */ - return DIV_UNc (b, a); /* b/a */ -} - -#define GET_COMP(v, i) ((comp2_t) (comp1_t) ((v) >> i)) - -#define ADD(x, y, i, t) \ - ((t) = GET_COMP (x, i) + GET_COMP (y, i), \ - (comp4_t) ((comp1_t) ((t) | (0 - ((t) >> G_SHIFT)))) << (i)) - -#define GENERIC(x, y, i, ax, ay, t, u, v) \ - ((t) = (MUL_UNc (GET_COMP (y, i), ay, (u)) + \ - MUL_UNc (GET_COMP (x, i), ax, (v))), \ - (comp4_t) ((comp1_t) ((t) | \ - (0 - ((t) >> G_SHIFT)))) << (i)) - -static void -combine_disjoint_general_u (comp4_t * dest, - const comp4_t *src, - const comp4_t *mask, - int width, - comp1_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp4_t m, n, o, p; - comp2_t Fa, Fb, t, u, v; - comp1_t sa = s >> A_SHIFT; - comp1_t da = d >> A_SHIFT; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - Fa = combine_disjoint_out_part (sa, da); - break; - - case COMBINE_A_IN: - Fa = combine_disjoint_in_part (sa, da); - break; - - case COMBINE_A: - Fa = MASK; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - Fb = combine_disjoint_out_part (da, sa); - break; - - case COMBINE_B_IN: - Fb = combine_disjoint_in_part (da, sa); - break; - - case COMBINE_B: - Fb = MASK; - break; - } - m = GENERIC (s, d, 0, Fa, Fb, t, u, v); - n = GENERIC (s, d, G_SHIFT, Fa, Fb, t, u, v); - o = GENERIC (s, d, R_SHIFT, Fa, Fb, t, u, v); - p = GENERIC (s, d, A_SHIFT, Fa, Fb, t, u, v); - s = m | n | o | p; - *(dest + i) = s; - } -} - -static void -combine_disjoint_over_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp2_t a = s >> A_SHIFT; - - if (s != 0x00) - { - comp4_t d = *(dest + i); - a = combine_disjoint_out_part (d >> A_SHIFT, a); - UNcx4_MUL_UNc_ADD_UNcx4 (d, a, s); - - *(dest + i) = d; - } - } -} - -static void -combine_disjoint_in_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_disjoint_in_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_disjoint_out_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_disjoint_out_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_disjoint_atop_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_disjoint_atop_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_disjoint_xor_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_XOR); -} - -static void -combine_conjoint_general_u (comp4_t * dest, - const comp4_t *src, - const comp4_t *mask, - int width, - comp1_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = combine_mask (src, mask, i); - comp4_t d = *(dest + i); - comp4_t m, n, o, p; - comp2_t Fa, Fb, t, u, v; - comp1_t sa = s >> A_SHIFT; - comp1_t da = d >> A_SHIFT; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - Fa = combine_conjoint_out_part (sa, da); - break; - - case COMBINE_A_IN: - Fa = combine_conjoint_in_part (sa, da); - break; - - case COMBINE_A: - Fa = MASK; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - Fb = combine_conjoint_out_part (da, sa); - break; - - case COMBINE_B_IN: - Fb = combine_conjoint_in_part (da, sa); - break; - - case COMBINE_B: - Fb = MASK; - break; - } - - m = GENERIC (s, d, 0, Fa, Fb, t, u, v); - n = GENERIC (s, d, G_SHIFT, Fa, Fb, t, u, v); - o = GENERIC (s, d, R_SHIFT, Fa, Fb, t, u, v); - p = GENERIC (s, d, A_SHIFT, Fa, Fb, t, u, v); - - s = m | n | o | p; - - *(dest + i) = s; - } -} - -static void -combine_conjoint_over_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_OVER); -} - -static void -combine_conjoint_over_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_OVER); -} - -static void -combine_conjoint_in_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_conjoint_in_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_conjoint_out_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_conjoint_out_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_conjoint_atop_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_conjoint_atop_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_conjoint_xor_u (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_XOR); -} - -/************************************************************************/ -/*********************** Per Channel functions **************************/ -/************************************************************************/ - -static void -combine_clear_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - memset (dest, 0, width * sizeof(comp4_t)); -} - -static void -combine_src_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = *(src + i); - comp4_t m = *(mask + i); - - combine_mask_value_ca (&s, &m); - - *(dest + i) = s; - } -} - -static void -combine_over_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = *(src + i); - comp4_t m = *(mask + i); - comp4_t a; - - combine_mask_ca (&s, &m); - - a = ~m; - if (a) - { - comp4_t d = *(dest + i); - UNcx4_MUL_UNcx4_ADD_UNcx4 (d, a, s); - s = d; - } - - *(dest + i) = s; - } -} - -static void -combine_over_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t d = *(dest + i); - comp4_t a = ~d >> A_SHIFT; - - if (a) - { - comp4_t s = *(src + i); - comp4_t m = *(mask + i); - - UNcx4_MUL_UNcx4 (s, m); - UNcx4_MUL_UNc_ADD_UNcx4 (s, a, d); - - *(dest + i) = s; - } - } -} - -static void -combine_in_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t d = *(dest + i); - comp2_t a = d >> A_SHIFT; - comp4_t s = 0; - - if (a) - { - comp4_t m = *(mask + i); - - s = *(src + i); - combine_mask_value_ca (&s, &m); - - if (a != MASK) - UNcx4_MUL_UNc (s, a); - } - - *(dest + i) = s; - } -} - -static void -combine_in_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = *(src + i); - comp4_t m = *(mask + i); - comp4_t a; - - combine_mask_alpha_ca (&s, &m); - - a = m; - if (a != ~0) - { - comp4_t d = 0; - - if (a) - { - d = *(dest + i); - UNcx4_MUL_UNcx4 (d, a); - } - - *(dest + i) = d; - } - } -} - -static void -combine_out_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t d = *(dest + i); - comp2_t a = ~d >> A_SHIFT; - comp4_t s = 0; - - if (a) - { - comp4_t m = *(mask + i); - - s = *(src + i); - combine_mask_value_ca (&s, &m); - - if (a != MASK) - UNcx4_MUL_UNc (s, a); - } - - *(dest + i) = s; - } -} - -static void -combine_out_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = *(src + i); - comp4_t m = *(mask + i); - comp4_t a; - - combine_mask_alpha_ca (&s, &m); - - a = ~m; - if (a != ~0) - { - comp4_t d = 0; - - if (a) - { - d = *(dest + i); - UNcx4_MUL_UNcx4 (d, a); - } - - *(dest + i) = d; - } - } -} - -static void -combine_atop_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t d = *(dest + i); - comp4_t s = *(src + i); - comp4_t m = *(mask + i); - comp4_t ad; - comp2_t as = d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - ad = ~m; - - UNcx4_MUL_UNcx4_ADD_UNcx4_MUL_UNc (d, ad, s, as); - - *(dest + i) = d; - } -} - -static void -combine_atop_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t d = *(dest + i); - comp4_t s = *(src + i); - comp4_t m = *(mask + i); - comp4_t ad; - comp2_t as = ~d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - ad = m; - - UNcx4_MUL_UNcx4_ADD_UNcx4_MUL_UNc (d, ad, s, as); - - *(dest + i) = d; - } -} - -static void -combine_xor_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t d = *(dest + i); - comp4_t s = *(src + i); - comp4_t m = *(mask + i); - comp4_t ad; - comp2_t as = ~d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - ad = ~m; - - UNcx4_MUL_UNcx4_ADD_UNcx4_MUL_UNc (d, ad, s, as); - - *(dest + i) = d; - } -} - -static void -combine_add_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s = *(src + i); - comp4_t m = *(mask + i); - comp4_t d = *(dest + i); - - combine_mask_value_ca (&s, &m); - - UNcx4_ADD_UNcx4 (d, s); - - *(dest + i) = d; - } -} - -static void -combine_saturate_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s, d; - comp2_t sa, sr, sg, sb, da; - comp2_t t, u, v; - comp4_t m, n, o, p; - - d = *(dest + i); - s = *(src + i); - m = *(mask + i); - - combine_mask_ca (&s, &m); - - sa = (m >> A_SHIFT); - sr = (m >> R_SHIFT) & MASK; - sg = (m >> G_SHIFT) & MASK; - sb = m & MASK; - da = ~d >> A_SHIFT; - - if (sb <= da) - m = ADD (s, d, 0, t); - else - m = GENERIC (s, d, 0, (da << G_SHIFT) / sb, MASK, t, u, v); - - if (sg <= da) - n = ADD (s, d, G_SHIFT, t); - else - n = GENERIC (s, d, G_SHIFT, (da << G_SHIFT) / sg, MASK, t, u, v); - - if (sr <= da) - o = ADD (s, d, R_SHIFT, t); - else - o = GENERIC (s, d, R_SHIFT, (da << G_SHIFT) / sr, MASK, t, u, v); - - if (sa <= da) - p = ADD (s, d, A_SHIFT, t); - else - p = GENERIC (s, d, A_SHIFT, (da << G_SHIFT) / sa, MASK, t, u, v); - - *(dest + i) = m | n | o | p; - } -} - -static void -combine_disjoint_general_ca (comp4_t * dest, - const comp4_t *src, - const comp4_t *mask, - int width, - comp1_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s, d; - comp4_t m, n, o, p; - comp4_t Fa, Fb; - comp2_t t, u, v; - comp4_t sa; - comp1_t da; - - s = *(src + i); - m = *(mask + i); - d = *(dest + i); - da = d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - sa = m; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - m = (comp4_t)combine_disjoint_out_part ((comp1_t) (sa >> 0), da); - n = (comp4_t)combine_disjoint_out_part ((comp1_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (comp4_t)combine_disjoint_out_part ((comp1_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (comp4_t)combine_disjoint_out_part ((comp1_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A_IN: - m = (comp4_t)combine_disjoint_in_part ((comp1_t) (sa >> 0), da); - n = (comp4_t)combine_disjoint_in_part ((comp1_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (comp4_t)combine_disjoint_in_part ((comp1_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (comp4_t)combine_disjoint_in_part ((comp1_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A: - Fa = ~0; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - m = (comp4_t)combine_disjoint_out_part (da, (comp1_t) (sa >> 0)); - n = (comp4_t)combine_disjoint_out_part (da, (comp1_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (comp4_t)combine_disjoint_out_part (da, (comp1_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (comp4_t)combine_disjoint_out_part (da, (comp1_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B_IN: - m = (comp4_t)combine_disjoint_in_part (da, (comp1_t) (sa >> 0)); - n = (comp4_t)combine_disjoint_in_part (da, (comp1_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (comp4_t)combine_disjoint_in_part (da, (comp1_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (comp4_t)combine_disjoint_in_part (da, (comp1_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B: - Fb = ~0; - break; - } - m = GENERIC (s, d, 0, GET_COMP (Fa, 0), GET_COMP (Fb, 0), t, u, v); - n = GENERIC (s, d, G_SHIFT, GET_COMP (Fa, G_SHIFT), GET_COMP (Fb, G_SHIFT), t, u, v); - o = GENERIC (s, d, R_SHIFT, GET_COMP (Fa, R_SHIFT), GET_COMP (Fb, R_SHIFT), t, u, v); - p = GENERIC (s, d, A_SHIFT, GET_COMP (Fa, A_SHIFT), GET_COMP (Fb, A_SHIFT), t, u, v); - - s = m | n | o | p; - - *(dest + i) = s; - } -} - -static void -combine_disjoint_over_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_OVER); -} - -static void -combine_disjoint_in_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_disjoint_in_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_disjoint_out_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_disjoint_out_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_disjoint_atop_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_disjoint_atop_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_disjoint_xor_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_XOR); -} - -static void -combine_conjoint_general_ca (comp4_t * dest, - const comp4_t *src, - const comp4_t *mask, - int width, - comp1_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - comp4_t s, d; - comp4_t m, n, o, p; - comp4_t Fa, Fb; - comp2_t t, u, v; - comp4_t sa; - comp1_t da; - - s = *(src + i); - m = *(mask + i); - d = *(dest + i); - da = d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - sa = m; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - m = (comp4_t)combine_conjoint_out_part ((comp1_t) (sa >> 0), da); - n = (comp4_t)combine_conjoint_out_part ((comp1_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (comp4_t)combine_conjoint_out_part ((comp1_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (comp4_t)combine_conjoint_out_part ((comp1_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A_IN: - m = (comp4_t)combine_conjoint_in_part ((comp1_t) (sa >> 0), da); - n = (comp4_t)combine_conjoint_in_part ((comp1_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (comp4_t)combine_conjoint_in_part ((comp1_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (comp4_t)combine_conjoint_in_part ((comp1_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A: - Fa = ~0; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - m = (comp4_t)combine_conjoint_out_part (da, (comp1_t) (sa >> 0)); - n = (comp4_t)combine_conjoint_out_part (da, (comp1_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (comp4_t)combine_conjoint_out_part (da, (comp1_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (comp4_t)combine_conjoint_out_part (da, (comp1_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B_IN: - m = (comp4_t)combine_conjoint_in_part (da, (comp1_t) (sa >> 0)); - n = (comp4_t)combine_conjoint_in_part (da, (comp1_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (comp4_t)combine_conjoint_in_part (da, (comp1_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (comp4_t)combine_conjoint_in_part (da, (comp1_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B: - Fb = ~0; - break; - } - m = GENERIC (s, d, 0, GET_COMP (Fa, 0), GET_COMP (Fb, 0), t, u, v); - n = GENERIC (s, d, G_SHIFT, GET_COMP (Fa, G_SHIFT), GET_COMP (Fb, G_SHIFT), t, u, v); - o = GENERIC (s, d, R_SHIFT, GET_COMP (Fa, R_SHIFT), GET_COMP (Fb, R_SHIFT), t, u, v); - p = GENERIC (s, d, A_SHIFT, GET_COMP (Fa, A_SHIFT), GET_COMP (Fb, A_SHIFT), t, u, v); - - s = m | n | o | p; - - *(dest + i) = s; - } -} - -static void -combine_conjoint_over_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_OVER); -} - -static void -combine_conjoint_over_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_OVER); -} - -static void -combine_conjoint_in_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_conjoint_in_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_conjoint_out_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_conjoint_out_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_conjoint_atop_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_conjoint_atop_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_conjoint_xor_ca (pixman_implementation_t *imp, - pixman_op_t op, - comp4_t * dest, - const comp4_t * src, - const comp4_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_XOR); -} - -void -_pixman_setup_combiner_functions_width (pixman_implementation_t *imp) -{ - /* Unified alpha */ - imp->combine_width[PIXMAN_OP_CLEAR] = combine_clear; - imp->combine_width[PIXMAN_OP_SRC] = combine_src_u; - imp->combine_width[PIXMAN_OP_DST] = combine_dst; - imp->combine_width[PIXMAN_OP_OVER] = combine_over_u; - imp->combine_width[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_u; - imp->combine_width[PIXMAN_OP_IN] = combine_in_u; - imp->combine_width[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_u; - imp->combine_width[PIXMAN_OP_OUT] = combine_out_u; - imp->combine_width[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_u; - imp->combine_width[PIXMAN_OP_ATOP] = combine_atop_u; - imp->combine_width[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_u; - imp->combine_width[PIXMAN_OP_XOR] = combine_xor_u; - imp->combine_width[PIXMAN_OP_ADD] = combine_add_u; - imp->combine_width[PIXMAN_OP_SATURATE] = combine_saturate_u; - - /* Disjoint, unified */ - imp->combine_width[PIXMAN_OP_DISJOINT_CLEAR] = combine_clear; - imp->combine_width[PIXMAN_OP_DISJOINT_SRC] = combine_src_u; - imp->combine_width[PIXMAN_OP_DISJOINT_DST] = combine_dst; - imp->combine_width[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_u; - imp->combine_width[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_saturate_u; - imp->combine_width[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_u; - imp->combine_width[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_u; - imp->combine_width[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_u; - imp->combine_width[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_u; - imp->combine_width[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_u; - imp->combine_width[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_u; - imp->combine_width[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_u; - - /* Conjoint, unified */ - imp->combine_width[PIXMAN_OP_CONJOINT_CLEAR] = combine_clear; - imp->combine_width[PIXMAN_OP_CONJOINT_SRC] = combine_src_u; - imp->combine_width[PIXMAN_OP_CONJOINT_DST] = combine_dst; - imp->combine_width[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_u; - imp->combine_width[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_u; - imp->combine_width[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_u; - imp->combine_width[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_u; - imp->combine_width[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_u; - imp->combine_width[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_u; - imp->combine_width[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_u; - imp->combine_width[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_u; - imp->combine_width[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_u; - - imp->combine_width[PIXMAN_OP_MULTIPLY] = combine_multiply_u; - imp->combine_width[PIXMAN_OP_SCREEN] = combine_screen_u; - imp->combine_width[PIXMAN_OP_OVERLAY] = combine_overlay_u; - imp->combine_width[PIXMAN_OP_DARKEN] = combine_darken_u; - imp->combine_width[PIXMAN_OP_LIGHTEN] = combine_lighten_u; - imp->combine_width[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_u; - imp->combine_width[PIXMAN_OP_COLOR_BURN] = combine_color_burn_u; - imp->combine_width[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_u; - imp->combine_width[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_u; - imp->combine_width[PIXMAN_OP_DIFFERENCE] = combine_difference_u; - imp->combine_width[PIXMAN_OP_EXCLUSION] = combine_exclusion_u; - imp->combine_width[PIXMAN_OP_HSL_HUE] = combine_hsl_hue_u; - imp->combine_width[PIXMAN_OP_HSL_SATURATION] = combine_hsl_saturation_u; - imp->combine_width[PIXMAN_OP_HSL_COLOR] = combine_hsl_color_u; - imp->combine_width[PIXMAN_OP_HSL_LUMINOSITY] = combine_hsl_luminosity_u; - - /* Component alpha combiners */ - imp->combine_width_ca[PIXMAN_OP_CLEAR] = combine_clear_ca; - imp->combine_width_ca[PIXMAN_OP_SRC] = combine_src_ca; - /* dest */ - imp->combine_width_ca[PIXMAN_OP_OVER] = combine_over_ca; - imp->combine_width_ca[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_IN] = combine_in_ca; - imp->combine_width_ca[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_OUT] = combine_out_ca; - imp->combine_width_ca[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_ATOP] = combine_atop_ca; - imp->combine_width_ca[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_XOR] = combine_xor_ca; - imp->combine_width_ca[PIXMAN_OP_ADD] = combine_add_ca; - imp->combine_width_ca[PIXMAN_OP_SATURATE] = combine_saturate_ca; - - /* Disjoint CA */ - imp->combine_width_ca[PIXMAN_OP_DISJOINT_CLEAR] = combine_clear_ca; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_SRC] = combine_src_ca; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_DST] = combine_dst; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_ca; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_saturate_ca; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_ca; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_ca; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_ca; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_ca; - - /* Conjoint CA */ - imp->combine_width_ca[PIXMAN_OP_CONJOINT_CLEAR] = combine_clear_ca; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_SRC] = combine_src_ca; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_DST] = combine_dst; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_ca; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_ca; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_ca; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_ca; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_ca; - imp->combine_width_ca[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_ca; - - imp->combine_width_ca[PIXMAN_OP_MULTIPLY] = combine_multiply_ca; - imp->combine_width_ca[PIXMAN_OP_SCREEN] = combine_screen_ca; - imp->combine_width_ca[PIXMAN_OP_OVERLAY] = combine_overlay_ca; - imp->combine_width_ca[PIXMAN_OP_DARKEN] = combine_darken_ca; - imp->combine_width_ca[PIXMAN_OP_LIGHTEN] = combine_lighten_ca; - imp->combine_width_ca[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_ca; - imp->combine_width_ca[PIXMAN_OP_COLOR_BURN] = combine_color_burn_ca; - imp->combine_width_ca[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_ca; - imp->combine_width_ca[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_ca; - imp->combine_width_ca[PIXMAN_OP_DIFFERENCE] = combine_difference_ca; - imp->combine_width_ca[PIXMAN_OP_EXCLUSION] = combine_exclusion_ca; - - /* It is not clear that these make sense, so make them noops for now */ - imp->combine_width_ca[PIXMAN_OP_HSL_HUE] = combine_dst; - imp->combine_width_ca[PIXMAN_OP_HSL_SATURATION] = combine_dst; - imp->combine_width_ca[PIXMAN_OP_HSL_COLOR] = combine_dst; - imp->combine_width_ca[PIXMAN_OP_HSL_LUMINOSITY] = combine_dst; -} - diff --git a/gfx/cairo/libpixman/src/pixman-combine.h.template b/gfx/cairo/libpixman/src/pixman-combine.h.template deleted file mode 100644 index 20f784b5b4..0000000000 --- a/gfx/cairo/libpixman/src/pixman-combine.h.template +++ /dev/null @@ -1,226 +0,0 @@ - -#define COMPONENT_SIZE -#define MASK -#define ONE_HALF - -#define A_SHIFT -#define R_SHIFT -#define G_SHIFT -#define A_MASK -#define R_MASK -#define G_MASK - -#define RB_MASK -#define AG_MASK -#define RB_ONE_HALF -#define RB_MASK_PLUS_ONE - -#define ALPHA_c(x) ((x) >> A_SHIFT) -#define RED_c(x) (((x) >> R_SHIFT) & MASK) -#define GREEN_c(x) (((x) >> G_SHIFT) & MASK) -#define BLUE_c(x) ((x) & MASK) - -/* - * Helper macros. - */ - -#define MUL_UNc(a, b, t) \ - ((t) = (a) * (comp2_t)(b) + ONE_HALF, ((((t) >> G_SHIFT ) + (t) ) >> G_SHIFT )) - -#define DIV_UNc(a, b) \ - (((comp2_t) (a) * MASK + ((b) / 2)) / (b)) - -#define ADD_UNc(x, y, t) \ - ((t) = (x) + (y), \ - (comp4_t) (comp1_t) ((t) | (0 - ((t) >> G_SHIFT)))) - -#define DIV_ONE_UNc(x) \ - (((x) + ONE_HALF + (((x) + ONE_HALF) >> G_SHIFT)) >> G_SHIFT) - -/* - * The methods below use some tricks to be able to do two color - * components at the same time. - */ - -/* - * x_rb = (x_rb * a) / 255 - */ -#define UNc_rb_MUL_UNc(x, a, t) \ - do \ - { \ - t = ((x) & RB_MASK) * (a); \ - t += RB_ONE_HALF; \ - x = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \ - x &= RB_MASK; \ - } while (0) - -/* - * x_rb = min (x_rb + y_rb, 255) - */ -#define UNc_rb_ADD_UNc_rb(x, y, t) \ - do \ - { \ - t = ((x) + (y)); \ - t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); \ - x = (t & RB_MASK); \ - } while (0) - -/* - * x_rb = (x_rb * a_rb) / 255 - */ -#define UNc_rb_MUL_UNc_rb(x, a, t) \ - do \ - { \ - t = (x & MASK) * (a & MASK); \ - t |= (x & R_MASK) * ((a >> R_SHIFT) & MASK); \ - t += RB_ONE_HALF; \ - t = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \ - x = t & RB_MASK; \ - } while (0) - -/* - * x_c = (x_c * a) / 255 - */ -#define UNcx4_MUL_UNc(x, a) \ - do \ - { \ - comp4_t r1__, r2__, t__; \ - \ - r1__ = (x); \ - UNc_rb_MUL_UNc (r1__, (a), t__); \ - \ - r2__ = (x) >> G_SHIFT; \ - UNc_rb_MUL_UNc (r2__, (a), t__); \ - \ - (x) = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - * x_c = (x_c * a) / 255 + y_c - */ -#define UNcx4_MUL_UNc_ADD_UNcx4(x, a, y) \ - do \ - { \ - comp4_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x); \ - r2__ = (y) & RB_MASK; \ - UNc_rb_MUL_UNc (r1__, (a), t__); \ - UNc_rb_ADD_UNc_rb (r1__, r2__, t__); \ - \ - r2__ = (x) >> G_SHIFT; \ - r3__ = ((y) >> G_SHIFT) & RB_MASK; \ - UNc_rb_MUL_UNc (r2__, (a), t__); \ - UNc_rb_ADD_UNc_rb (r2__, r3__, t__); \ - \ - (x) = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - * x_c = (x_c * a + y_c * b) / 255 - */ -#define UNcx4_MUL_UNc_ADD_UNcx4_MUL_UNc(x, a, y, b) \ - do \ - { \ - comp4_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x); \ - r2__ = (y); \ - UNc_rb_MUL_UNc (r1__, (a), t__); \ - UNc_rb_MUL_UNc (r2__, (b), t__); \ - UNc_rb_ADD_UNc_rb (r1__, r2__, t__); \ - \ - r2__ = ((x) >> G_SHIFT); \ - r3__ = ((y) >> G_SHIFT); \ - UNc_rb_MUL_UNc (r2__, (a), t__); \ - UNc_rb_MUL_UNc (r3__, (b), t__); \ - UNc_rb_ADD_UNc_rb (r2__, r3__, t__); \ - \ - (x) = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - * x_c = (x_c * a_c) / 255 - */ -#define UNcx4_MUL_UNcx4(x, a) \ - do \ - { \ - comp4_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x); \ - r2__ = (a); \ - UNc_rb_MUL_UNc_rb (r1__, r2__, t__); \ - \ - r2__ = (x) >> G_SHIFT; \ - r3__ = (a) >> G_SHIFT; \ - UNc_rb_MUL_UNc_rb (r2__, r3__, t__); \ - \ - (x) = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - * x_c = (x_c * a_c) / 255 + y_c - */ -#define UNcx4_MUL_UNcx4_ADD_UNcx4(x, a, y) \ - do \ - { \ - comp4_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x); \ - r2__ = (a); \ - UNc_rb_MUL_UNc_rb (r1__, r2__, t__); \ - r2__ = (y) & RB_MASK; \ - UNc_rb_ADD_UNc_rb (r1__, r2__, t__); \ - \ - r2__ = ((x) >> G_SHIFT); \ - r3__ = ((a) >> G_SHIFT); \ - UNc_rb_MUL_UNc_rb (r2__, r3__, t__); \ - r3__ = ((y) >> G_SHIFT) & RB_MASK; \ - UNc_rb_ADD_UNc_rb (r2__, r3__, t__); \ - \ - (x) = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - * x_c = (x_c * a_c + y_c * b) / 255 - */ -#define UNcx4_MUL_UNcx4_ADD_UNcx4_MUL_UNc(x, a, y, b) \ - do \ - { \ - comp4_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x); \ - r2__ = (a); \ - UNc_rb_MUL_UNc_rb (r1__, r2__, t__); \ - r2__ = (y); \ - UNc_rb_MUL_UNc (r2__, (b), t__); \ - UNc_rb_ADD_UNc_rb (r1__, r2__, t__); \ - \ - r2__ = (x) >> G_SHIFT; \ - r3__ = (a) >> G_SHIFT; \ - UNc_rb_MUL_UNc_rb (r2__, r3__, t__); \ - r3__ = (y) >> G_SHIFT; \ - UNc_rb_MUL_UNc (r3__, (b), t__); \ - UNc_rb_ADD_UNc_rb (r2__, r3__, t__); \ - \ - x = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - x_c = min(x_c + y_c, 255) -*/ -#define UNcx4_ADD_UNcx4(x, y) \ - do \ - { \ - comp4_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x) & RB_MASK; \ - r2__ = (y) & RB_MASK; \ - UNc_rb_ADD_UNc_rb (r1__, r2__, t__); \ - \ - r2__ = ((x) >> G_SHIFT) & RB_MASK; \ - r3__ = ((y) >> G_SHIFT) & RB_MASK; \ - UNc_rb_ADD_UNc_rb (r2__, r3__, t__); \ - \ - x = r1__ | (r2__ << G_SHIFT); \ - } while (0) diff --git a/gfx/cairo/libpixman/src/pixman-combine16.c b/gfx/cairo/libpixman/src/pixman-combine16.c deleted file mode 100644 index 9ba439fe5b..0000000000 --- a/gfx/cairo/libpixman/src/pixman-combine16.c +++ /dev/null @@ -1,114 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "pixman-private.h" - -#include "pixman-combine32.h" - -static force_inline uint32_t -combine_mask (const uint32_t src, const uint32_t mask) -{ - uint32_t s, m; - - m = mask >> A_SHIFT; - - if (!m) - return 0; - s = src; - - UN8x4_MUL_UN8 (s, m); - - return s; -} - -static void -combine_src_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - int i; - - if (!mask) - memcpy (dest, src, width * sizeof (uint16_t)); - else - { - uint16_t *d = (uint16_t*)dest; - uint16_t *src16 = (uint16_t*)src; - for (i = 0; i < width; ++i) - { - if ((*mask & 0xff000000) == 0xff000000) { - // it's likely worth special casing - // fully opaque because it avoids - // the cost of conversion as well the multiplication - *(d + i) = *src16; - } else { - // the mask is still 32bits - uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask); - *(d + i) = convert_8888_to_0565(s); - } - mask++; - src16++; - } - } - -} - -static void -combine_over_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - int i; - - if (!mask) - memcpy (dest, src, width * sizeof (uint16_t)); - else - { - uint16_t *d = (uint16_t*)dest; - uint16_t *src16 = (uint16_t*)src; - for (i = 0; i < width; ++i) - { - if ((*mask & 0xff000000) == 0xff000000) { - // it's likely worth special casing - // fully opaque because it avoids - // the cost of conversion as well the multiplication - *(d + i) = *src16; - } else if ((*mask & 0xff000000) == 0x00000000) { - // keep the dest the same - } else { - // the mask is still 32bits - uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask); - uint32_t ia = ALPHA_8 (~s); - uint32_t d32 = convert_0565_to_8888(*(d + i)); - UN8x4_MUL_UN8_ADD_UN8x4 (d32, ia, s); - *(d + i) = convert_8888_to_0565(d32); - } - mask++; - src16++; - } - } - -} - - -void -_pixman_setup_combiner_functions_16 (pixman_implementation_t *imp) -{ - int i; - for (i = 0; i < PIXMAN_N_OPERATORS; i++) { - imp->combine_16[i] = NULL; - } - imp->combine_16[PIXMAN_OP_SRC] = combine_src_u; - imp->combine_16[PIXMAN_OP_OVER] = combine_over_u; -} - diff --git a/gfx/cairo/libpixman/src/pixman-combine32.c b/gfx/cairo/libpixman/src/pixman-combine32.c index 3ac7576bdc..4a89384d9c 100644 --- a/gfx/cairo/libpixman/src/pixman-combine32.c +++ b/gfx/cairo/libpixman/src/pixman-combine32.c @@ -142,12 +142,12 @@ combine_mask (const uint32_t *src, const uint32_t *mask, int i) static void combine_clear (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { - memset (dest, 0, width * sizeof(uint32_t)); + memset (dest, 0, width * sizeof (uint32_t)); } static void @@ -155,7 +155,7 @@ combine_dst (pixman_implementation_t *imp, pixman_op_t op, uint32_t * dest, const uint32_t * src, - const uint32_t * mask, + const uint32_t * mask, int width) { return; @@ -164,9 +164,9 @@ combine_dst (pixman_implementation_t *imp, static void combine_src_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -189,9 +189,9 @@ combine_src_u (pixman_implementation_t *imp, static void combine_over_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -254,9 +254,9 @@ combine_over_u (pixman_implementation_t *imp, static void combine_over_reverse_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -274,9 +274,9 @@ combine_over_reverse_u (pixman_implementation_t *imp, static void combine_in_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -293,9 +293,9 @@ combine_in_u (pixman_implementation_t *imp, static void combine_in_reverse_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -313,9 +313,9 @@ combine_in_reverse_u (pixman_implementation_t *imp, static void combine_out_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -332,9 +332,9 @@ combine_out_u (pixman_implementation_t *imp, static void combine_out_reverse_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -352,9 +352,9 @@ combine_out_reverse_u (pixman_implementation_t *imp, static void combine_atop_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -374,9 +374,9 @@ combine_atop_u (pixman_implementation_t *imp, static void combine_atop_reverse_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -396,9 +396,9 @@ combine_atop_reverse_u (pixman_implementation_t *imp, static void combine_xor_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -418,9 +418,9 @@ combine_xor_u (pixman_implementation_t *imp, static void combine_add_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -434,68 +434,65 @@ combine_add_u (pixman_implementation_t *imp, } } -static void -combine_saturate_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint32_t s = combine_mask (src, mask, i); - uint32_t d = *(dest + i); - uint16_t sa, da; - - sa = s >> A_SHIFT; - da = ~d >> A_SHIFT; - if (sa > da) - { - sa = DIV_UN8 (da, sa); - UN8x4_MUL_UN8 (s, sa); - } - ; - UN8x4_ADD_UN8x4 (d, s); - *(dest + i) = d; - } -} - /* * PDF blend modes: + * * The following blend modes have been taken from the PDF ISO 32000 * specification, which at this point in time is available from - * http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf - * The relevant chapters are 11.3.5 and 11.3.6. + * + * http://www.adobe.com/devnet/pdf/pdf_reference.html + * + * The specific documents of interest are the PDF spec itself: + * + * http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf + * + * chapters 11.3.5 and 11.3.6 and a later supplement for Adobe Acrobat + * 9.1 and Reader 9.1: + * + * http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/adobe_supplement_iso32000_1.pdf + * + * that clarifies the specifications for blend modes ColorDodge and + * ColorBurn. + * * The formula for computing the final pixel color given in 11.3.6 is: - * αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs) - * with B() being the blend function. - * Note that OVER is a special case of this operation, using B(Cb, Cs) = Cs * - * These blend modes should match the SVG filter draft specification, as - * it has been designed to mirror ISO 32000. Note that at the current point - * no released draft exists that shows this, as the formulas have not been - * updated yet after the release of ISO 32000. + * αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs) * - * The default implementation here uses the PDF_SEPARABLE_BLEND_MODE and - * PDF_NON_SEPARABLE_BLEND_MODE macros, which take the blend function as an - * argument. Note that this implementation operates on premultiplied colors, - * while the PDF specification does not. Therefore the code uses the formula - * Cra = (1 – as) . Dca + (1 – ad) . Sca + B(Dca, ad, Sca, as) + * with B() is the blend function. When B(Cb, Cs) = Cs, this formula + * reduces to the regular OVER operator. + * + * Cs and Cb are not premultiplied, so in our implementation we instead + * use: + * + * cr = (1 – αs) × cb + (1 – αb) × cs + αb × αs × B (cb/αb, cs/αs) + * + * where cr, cs, and cb are premultiplied colors, and where the + * + * αb × αs × B(cb/αb, cs/αs) + * + * part is first arithmetically simplified under the assumption that αb + * and αs are not 0, and then updated to produce a meaningful result when + * they are. + * + * For all the blend mode operators, the alpha channel is given by + * + * αr = αs + αb + αb × αs */ /* * Multiply - * B(Dca, ad, Sca, as) = Dca.Sca + * + * ad * as * B(d / ad, s / as) + * = ad * as * d/ad * s/as + * = d * s + * */ static void combine_multiply_u (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -519,9 +516,9 @@ combine_multiply_u (pixman_implementation_t *imp, static void combine_multiply_ca (pixman_implementation_t *imp, pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, + uint32_t * dest, + const uint32_t * src, + const uint32_t * mask, int width) { int i; @@ -544,409 +541,23 @@ combine_multiply_ca (pixman_implementation_t *imp, } } +#define CLAMP(v, low, high) \ + do \ + { \ + if (v < (low)) \ + v = (low); \ + if (v > (high)) \ + v = (high); \ + } while (0) + #define PDF_SEPARABLE_BLEND_MODE(name) \ static void \ combine_ ## name ## _u (pixman_implementation_t *imp, \ pixman_op_t op, \ - uint32_t * dest, \ - const uint32_t * src, \ - const uint32_t * mask, \ + uint32_t * dest, \ + const uint32_t * src, \ + const uint32_t * mask, \ int width) \ - { \ - int i; \ - for (i = 0; i < width; ++i) { \ - uint32_t s = combine_mask (src, mask, i); \ - uint32_t d = *(dest + i); \ - uint8_t sa = ALPHA_8 (s); \ - uint8_t isa = ~sa; \ - uint8_t da = ALPHA_8 (d); \ - uint8_t ida = ~da; \ - uint32_t result; \ - \ - result = d; \ - UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (result, isa, s, ida); \ - \ - *(dest + i) = result + \ - (DIV_ONE_UN8 (sa * (uint32_t)da) << A_SHIFT) + \ - (blend_ ## name (RED_8 (d), da, RED_8 (s), sa) << R_SHIFT) + \ - (blend_ ## name (GREEN_8 (d), da, GREEN_8 (s), sa) << G_SHIFT) + \ - (blend_ ## name (BLUE_8 (d), da, BLUE_8 (s), sa)); \ - } \ - } \ - \ - static void \ - combine_ ## name ## _ca (pixman_implementation_t *imp, \ - pixman_op_t op, \ - uint32_t * dest, \ - const uint32_t * src, \ - const uint32_t * mask, \ - int width) \ - { \ - int i; \ - for (i = 0; i < width; ++i) { \ - uint32_t m = *(mask + i); \ - uint32_t s = *(src + i); \ - uint32_t d = *(dest + i); \ - uint8_t da = ALPHA_8 (d); \ - uint8_t ida = ~da; \ - uint32_t result; \ - \ - combine_mask_ca (&s, &m); \ - \ - result = d; \ - UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (result, ~m, s, ida); \ - \ - result += \ - (DIV_ONE_UN8 (ALPHA_8 (m) * (uint32_t)da) << A_SHIFT) + \ - (blend_ ## name (RED_8 (d), da, RED_8 (s), RED_8 (m)) << R_SHIFT) + \ - (blend_ ## name (GREEN_8 (d), da, GREEN_8 (s), GREEN_8 (m)) << G_SHIFT) + \ - (blend_ ## name (BLUE_8 (d), da, BLUE_8 (s), BLUE_8 (m))); \ - \ - *(dest + i) = result; \ - } \ - } - -/* - * Screen - * B(Dca, ad, Sca, as) = Dca.sa + Sca.da - Dca.Sca - */ -static inline uint32_t -blend_screen (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa) -{ - return DIV_ONE_UN8 (sca * da + dca * sa - sca * dca); -} - -PDF_SEPARABLE_BLEND_MODE (screen) - -/* - * Overlay - * B(Dca, Da, Sca, Sa) = - * if 2.Dca < Da - * 2.Sca.Dca - * otherwise - * Sa.Da - 2.(Da - Dca).(Sa - Sca) - */ -static inline uint32_t -blend_overlay (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa) -{ - uint32_t rca; - - if (2 * dca < da) - rca = 2 * sca * dca; - else - rca = sa * da - 2 * (da - dca) * (sa - sca); - return DIV_ONE_UN8 (rca); -} - -PDF_SEPARABLE_BLEND_MODE (overlay) - -/* - * Darken - * B(Dca, Da, Sca, Sa) = min (Sca.Da, Dca.Sa) - */ -static inline uint32_t -blend_darken (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa) -{ - uint32_t s, d; - - s = sca * da; - d = dca * sa; - return DIV_ONE_UN8 (s > d ? d : s); -} - -PDF_SEPARABLE_BLEND_MODE (darken) - -/* - * Lighten - * B(Dca, Da, Sca, Sa) = max (Sca.Da, Dca.Sa) - */ -static inline uint32_t -blend_lighten (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa) -{ - uint32_t s, d; - - s = sca * da; - d = dca * sa; - return DIV_ONE_UN8 (s > d ? s : d); -} - -PDF_SEPARABLE_BLEND_MODE (lighten) - -/* - * Color dodge - * B(Dca, Da, Sca, Sa) = - * if Dca == 0 - * 0 - * if Sca == Sa - * Sa.Da - * otherwise - * Sa.Da. min (1, Dca / Da / (1 - Sca/Sa)) - */ -static inline uint32_t -blend_color_dodge (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa) -{ - if (sca >= sa) - { - return dca == 0 ? 0 : DIV_ONE_UN8 (sa * da); - } - else - { - uint32_t rca = dca * sa / (sa - sca); - return DIV_ONE_UN8 (sa * MIN (rca, da)); - } -} - -PDF_SEPARABLE_BLEND_MODE (color_dodge) - -/* - * Color burn - * B(Dca, Da, Sca, Sa) = - * if Dca == Da - * Sa.Da - * if Sca == 0 - * 0 - * otherwise - * Sa.Da.(1 - min (1, (1 - Dca/Da).Sa / Sca)) - */ -static inline uint32_t -blend_color_burn (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa) -{ - if (sca == 0) - { - return dca < da ? 0 : DIV_ONE_UN8 (sa * da); - } - else - { - uint32_t rca = (da - dca) * sa / sca; - return DIV_ONE_UN8 (sa * (MAX (rca, da) - rca)); - } -} - -PDF_SEPARABLE_BLEND_MODE (color_burn) - -/* - * Hard light - * B(Dca, Da, Sca, Sa) = - * if 2.Sca < Sa - * 2.Sca.Dca - * otherwise - * Sa.Da - 2.(Da - Dca).(Sa - Sca) - */ -static inline uint32_t -blend_hard_light (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa) -{ - if (2 * sca < sa) - return DIV_ONE_UN8 (2 * sca * dca); - else - return DIV_ONE_UN8 (sa * da - 2 * (da - dca) * (sa - sca)); -} - -PDF_SEPARABLE_BLEND_MODE (hard_light) - -/* - * Soft light - * B(Dca, Da, Sca, Sa) = - * if (2.Sca <= Sa) - * Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa)) - * otherwise if Dca.4 <= Da - * Dca.(Sa + (2.Sca - Sa).((16.Dca/Da - 12).Dca/Da + 3) - * otherwise - * (Dca.Sa + (SQRT (Dca/Da).Da - Dca).(2.Sca - Sa)) - */ -static inline uint32_t -blend_soft_light (uint32_t dca_org, - uint32_t da_org, - uint32_t sca_org, - uint32_t sa_org) -{ - double dca = dca_org * (1.0 / MASK); - double da = da_org * (1.0 / MASK); - double sca = sca_org * (1.0 / MASK); - double sa = sa_org * (1.0 / MASK); - double rca; - - if (2 * sca < sa) - { - if (da == 0) - rca = dca * sa; - else - rca = dca * sa - dca * (da - dca) * (sa - 2 * sca) / da; - } - else if (da == 0) - { - rca = 0; - } - else if (4 * dca <= da) - { - rca = dca * sa + - (2 * sca - sa) * dca * ((16 * dca / da - 12) * dca / da + 3); - } - else - { - rca = dca * sa + (sqrt (dca * da) - dca) * (2 * sca - sa); - } - return rca * MASK + 0.5; -} - -PDF_SEPARABLE_BLEND_MODE (soft_light) - -/* - * Difference - * B(Dca, Da, Sca, Sa) = abs (Dca.Sa - Sca.Da) - */ -static inline uint32_t -blend_difference (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa) -{ - uint32_t dcasa = dca * sa; - uint32_t scada = sca * da; - - if (scada < dcasa) - return DIV_ONE_UN8 (dcasa - scada); - else - return DIV_ONE_UN8 (scada - dcasa); -} - -PDF_SEPARABLE_BLEND_MODE (difference) - -/* - * Exclusion - * B(Dca, Da, Sca, Sa) = (Sca.Da + Dca.Sa - 2.Sca.Dca) - */ - -/* This can be made faster by writing it directly and not using - * PDF_SEPARABLE_BLEND_MODE, but that's a performance optimization */ - -static inline uint32_t -blend_exclusion (uint32_t dca, uint32_t da, uint32_t sca, uint32_t sa) -{ - return DIV_ONE_UN8 (sca * da + dca * sa - 2 * dca * sca); -} - -PDF_SEPARABLE_BLEND_MODE (exclusion) - -#undef PDF_SEPARABLE_BLEND_MODE - -/* - * PDF nonseperable blend modes are implemented using the following functions - * to operate in Hsl space, with Cmax, Cmid, Cmin referring to the max, mid - * and min value of the red, green and blue components. - * - * LUM (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue - * - * clip_color (C): - * l = LUM (C) - * min = Cmin - * max = Cmax - * if n < 0.0 - * C = l + ( ( ( C – l ) × l ) ⁄ ( l – min ) ) - * if x > 1.0 - * C = l + ( ( ( C – l ) × ( 1 – l ) ) ⁄ ( max – l ) ) - * return C - * - * set_lum (C, l): - * d = l – LUM (C) - * C += d - * return clip_color (C) - * - * SAT (C) = CH_MAX (C) - CH_MIN (C) - * - * set_sat (C, s): - * if Cmax > Cmin - * Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) ) - * Cmax = s - * else - * Cmid = Cmax = 0.0 - * Cmin = 0.0 - * return C - */ - -/* For premultiplied colors, we need to know what happens when C is - * multiplied by a real number. LUM and SAT are linear: - * - * LUM (r × C) = r × LUM (C) SAT (r * C) = r * SAT (C) - * - * If we extend clip_color with an extra argument a and change - * - * if x >= 1.0 - * - * into - * - * if x >= a - * - * then clip_color is also linear: - * - * r * clip_color (C, a) = clip_color (r_c, ra); - * - * for positive r. - * - * Similarly, we can extend set_lum with an extra argument that is just passed - * on to clip_color: - * - * r * set_lum ( C, l, a) - * - * = r × clip_color ( C + l - LUM (C), a) - * - * = clip_color ( r * C + r × l - r * LUM (C), r * a) - * - * = set_lum ( r * C, r * l, r * a) - * - * Finally, set_sat: - * - * r * set_sat (C, s) = set_sat (x * C, r * s) - * - * The above holds for all non-zero x, because the x'es in the fraction for - * C_mid cancel out. Specifically, it holds for x = r: - * - * r * set_sat (C, s) = set_sat (r_c, rs) - * - */ - -/* So, for the non-separable PDF blend modes, we have (using s, d for - * non-premultiplied colors, and S, D for premultiplied: - * - * Color: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (S/a_s, LUM (D/a_d), 1) - * = set_lum (S * a_d, a_s * LUM (D), a_s * a_d) - * - * - * Luminosity: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (D/a_d, LUM(S/a_s), 1) - * = set_lum (a_s * D, a_d * LUM(S), a_s * a_d) - * - * - * Saturation: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (set_sat (D/a_d, SAT (S/a_s)), LUM (D/a_d), 1) - * = set_lum (a_s * a_d * set_sat (D/a_d, SAT (S/a_s)), - * a_s * LUM (D), a_s * a_d) - * = set_lum (set_sat (a_s * D, a_d * SAT (S), a_s * LUM (D), a_s * a_d)) - * - * Hue: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (set_sat (S/a_s, SAT (D/a_d)), LUM (D/a_d), 1) - * = set_lum (set_sat (a_d * S, a_s * SAT (D)), a_s * LUM (D), a_s * a_d) - * - */ - -#define CH_MIN(c) (c[0] < c[1] ? (c[0] < c[2] ? c[0] : c[2]) : (c[1] < c[2] ? c[1] : c[2])) -#define CH_MAX(c) (c[0] > c[1] ? (c[0] > c[2] ? c[0] : c[2]) : (c[1] > c[2] ? c[1] : c[2])) -#define LUM(c) ((c[0] * 30 + c[1] * 59 + c[2] * 11) / 100) -#define SAT(c) (CH_MAX (c) - CH_MIN (c)) - -#define PDF_NON_SEPARABLE_BLEND_MODE(name) \ - static void \ - combine_ ## name ## _u (pixman_implementation_t *imp, \ - pixman_op_t op, \ - uint32_t *dest, \ - const uint32_t *src, \ - const uint32_t *mask, \ - int width) \ { \ int i; \ for (i = 0; i < width; ++i) \ @@ -957,673 +568,243 @@ PDF_SEPARABLE_BLEND_MODE (exclusion) uint8_t isa = ~sa; \ uint8_t da = ALPHA_8 (d); \ uint8_t ida = ~da; \ - uint32_t result; \ - uint32_t sc[3], dc[3], c[3]; \ - \ - result = d; \ - UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (result, isa, s, ida); \ - dc[0] = RED_8 (d); \ - sc[0] = RED_8 (s); \ - dc[1] = GREEN_8 (d); \ - sc[1] = GREEN_8 (s); \ - dc[2] = BLUE_8 (d); \ - sc[2] = BLUE_8 (s); \ - blend_ ## name (c, dc, da, sc, sa); \ - \ - *(dest + i) = result + \ - (DIV_ONE_UN8 (sa * (uint32_t)da) << A_SHIFT) + \ - (DIV_ONE_UN8 (c[0]) << R_SHIFT) + \ - (DIV_ONE_UN8 (c[1]) << G_SHIFT) + \ - (DIV_ONE_UN8 (c[2])); \ + uint32_t ra, rr, rg, rb; \ + \ + ra = da * 0xff + sa * 0xff - sa * da; \ + rr = isa * RED_8 (d) + ida * RED_8 (s); \ + rg = isa * GREEN_8 (d) + ida * GREEN_8 (s); \ + rb = isa * BLUE_8 (d) + ida * BLUE_8 (s); \ + \ + rr += blend_ ## name (RED_8 (d), da, RED_8 (s), sa); \ + rg += blend_ ## name (GREEN_8 (d), da, GREEN_8 (s), sa); \ + rb += blend_ ## name (BLUE_8 (d), da, BLUE_8 (s), sa); \ + \ + CLAMP (ra, 0, 255 * 255); \ + CLAMP (rr, 0, 255 * 255); \ + CLAMP (rg, 0, 255 * 255); \ + CLAMP (rb, 0, 255 * 255); \ + \ + ra = DIV_ONE_UN8 (ra); \ + rr = DIV_ONE_UN8 (rr); \ + rg = DIV_ONE_UN8 (rg); \ + rb = DIV_ONE_UN8 (rb); \ + \ + *(dest + i) = ra << 24 | rr << 16 | rg << 8 | rb; \ + } \ + } \ + \ + static void \ + combine_ ## name ## _ca (pixman_implementation_t *imp, \ + pixman_op_t op, \ + uint32_t * dest, \ + const uint32_t * src, \ + const uint32_t * mask, \ + int width) \ + { \ + int i; \ + for (i = 0; i < width; ++i) \ + { \ + uint32_t m = *(mask + i); \ + uint32_t s = *(src + i); \ + uint32_t d = *(dest + i); \ + uint8_t da = ALPHA_8 (d); \ + uint8_t ida = ~da; \ + uint32_t ra, rr, rg, rb; \ + uint8_t ira, iga, iba; \ + \ + combine_mask_ca (&s, &m); \ + \ + ira = ~RED_8 (m); \ + iga = ~GREEN_8 (m); \ + iba = ~BLUE_8 (m); \ + \ + ra = da * 0xff + ALPHA_8 (s) * 0xff - ALPHA_8 (s) * da; \ + rr = ira * RED_8 (d) + ida * RED_8 (s); \ + rg = iga * GREEN_8 (d) + ida * GREEN_8 (s); \ + rb = iba * BLUE_8 (d) + ida * BLUE_8 (s); \ + \ + rr += blend_ ## name (RED_8 (d), da, RED_8 (s), RED_8 (m)); \ + rg += blend_ ## name (GREEN_8 (d), da, GREEN_8 (s), GREEN_8 (m)); \ + rb += blend_ ## name (BLUE_8 (d), da, BLUE_8 (s), BLUE_8 (m)); \ + \ + CLAMP (ra, 0, 255 * 255); \ + CLAMP (rr, 0, 255 * 255); \ + CLAMP (rg, 0, 255 * 255); \ + CLAMP (rb, 0, 255 * 255); \ + \ + ra = DIV_ONE_UN8 (ra); \ + rr = DIV_ONE_UN8 (rr); \ + rg = DIV_ONE_UN8 (rg); \ + rb = DIV_ONE_UN8 (rb); \ + \ + *(dest + i) = ra << 24 | rr << 16 | rg << 8 | rb; \ } \ } -static void -set_lum (uint32_t dest[3], uint32_t src[3], uint32_t sa, uint32_t lum) -{ - double a, l, min, max; - double tmp[3]; - - a = sa * (1.0 / MASK); - - l = lum * (1.0 / MASK); - tmp[0] = src[0] * (1.0 / MASK); - tmp[1] = src[1] * (1.0 / MASK); - tmp[2] = src[2] * (1.0 / MASK); - - l = l - LUM (tmp); - tmp[0] += l; - tmp[1] += l; - tmp[2] += l; - - /* clip_color */ - l = LUM (tmp); - min = CH_MIN (tmp); - max = CH_MAX (tmp); - - if (min < 0) - { - if (l - min == 0.0) - { - tmp[0] = 0; - tmp[1] = 0; - tmp[2] = 0; - } - else - { - tmp[0] = l + (tmp[0] - l) * l / (l - min); - tmp[1] = l + (tmp[1] - l) * l / (l - min); - tmp[2] = l + (tmp[2] - l) * l / (l - min); - } - } - if (max > a) - { - if (max - l == 0.0) - { - tmp[0] = a; - tmp[1] = a; - tmp[2] = a; - } - else - { - tmp[0] = l + (tmp[0] - l) * (a - l) / (max - l); - tmp[1] = l + (tmp[1] - l) * (a - l) / (max - l); - tmp[2] = l + (tmp[2] - l) * (a - l) / (max - l); - } - } - - dest[0] = tmp[0] * MASK + 0.5; - dest[1] = tmp[1] * MASK + 0.5; - dest[2] = tmp[2] * MASK + 0.5; -} - -static void -set_sat (uint32_t dest[3], uint32_t src[3], uint32_t sat) -{ - int id[3]; - uint32_t min, max; - - if (src[0] > src[1]) - { - if (src[0] > src[2]) - { - id[0] = 0; - if (src[1] > src[2]) - { - id[1] = 1; - id[2] = 2; - } - else - { - id[1] = 2; - id[2] = 1; - } - } - else - { - id[0] = 2; - id[1] = 0; - id[2] = 1; - } - } - else - { - if (src[0] > src[2]) - { - id[0] = 1; - id[1] = 0; - id[2] = 2; - } - else - { - id[2] = 0; - if (src[1] > src[2]) - { - id[0] = 1; - id[1] = 2; - } - else - { - id[0] = 2; - id[1] = 1; - } - } - } - - max = dest[id[0]]; - min = dest[id[2]]; - if (max > min) - { - dest[id[1]] = (dest[id[1]] - min) * sat / (max - min); - dest[id[0]] = sat; - dest[id[2]] = 0; - } - else - { - dest[0] = dest[1] = dest[2] = 0; - } -} - /* - * Hue: - * B(Cb, Cs) = set_lum (set_sat (Cs, SAT (Cb)), LUM (Cb)) - */ -static inline void -blend_hsl_hue (uint32_t c[3], - uint32_t dc[3], - uint32_t da, - uint32_t sc[3], - uint32_t sa) -{ - c[0] = sc[0] * da; - c[1] = sc[1] * da; - c[2] = sc[2] * da; - set_sat (c, c, SAT (dc) * sa); - set_lum (c, c, sa * da, LUM (dc) * sa); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_hue) - -/* - * Saturation: - * B(Cb, Cs) = set_lum (set_sat (Cb, SAT (Cs)), LUM (Cb)) - */ -static inline void -blend_hsl_saturation (uint32_t c[3], - uint32_t dc[3], - uint32_t da, - uint32_t sc[3], - uint32_t sa) -{ - c[0] = dc[0] * sa; - c[1] = dc[1] * sa; - c[2] = dc[2] * sa; - set_sat (c, c, SAT (sc) * da); - set_lum (c, c, sa * da, LUM (dc) * sa); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_saturation) - -/* - * Color: - * B(Cb, Cs) = set_lum (Cs, LUM (Cb)) - */ -static inline void -blend_hsl_color (uint32_t c[3], - uint32_t dc[3], - uint32_t da, - uint32_t sc[3], - uint32_t sa) -{ - c[0] = sc[0] * da; - c[1] = sc[1] * da; - c[2] = sc[2] * da; - set_lum (c, c, sa * da, LUM (dc) * sa); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_color) - -/* - * Luminosity: - * B(Cb, Cs) = set_lum (Cb, LUM (Cs)) - */ -static inline void -blend_hsl_luminosity (uint32_t c[3], - uint32_t dc[3], - uint32_t da, - uint32_t sc[3], - uint32_t sa) -{ - c[0] = dc[0] * sa; - c[1] = dc[1] * sa; - c[2] = dc[2] * sa; - set_lum (c, c, sa * da, LUM (sc) * da); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_luminosity) - -#undef SAT -#undef LUM -#undef CH_MAX -#undef CH_MIN -#undef PDF_NON_SEPARABLE_BLEND_MODE - -/* All of the disjoint/conjoint composing functions + * Screen * - * The four entries in the first column indicate what source contributions - * come from each of the four areas of the picture -- areas covered by neither - * A nor B, areas covered only by A, areas covered only by B and finally - * areas covered by both A and B. - * - * Disjoint Conjoint - * Fa Fb Fa Fb - * (0,0,0,0) 0 0 0 0 - * (0,A,0,A) 1 0 1 0 - * (0,0,B,B) 0 1 0 1 - * (0,A,B,A) 1 min((1-a)/b,1) 1 max(1-a/b,0) - * (0,A,B,B) min((1-b)/a,1) 1 max(1-b/a,0) 1 - * (0,0,0,A) max(1-(1-b)/a,0) 0 min(1,b/a) 0 - * (0,0,0,B) 0 max(1-(1-a)/b,0) 0 min(a/b,1) - * (0,A,0,0) min(1,(1-b)/a) 0 max(1-b/a,0) 0 - * (0,0,B,0) 0 min(1,(1-a)/b) 0 max(1-a/b,0) - * (0,0,B,A) max(1-(1-b)/a,0) min(1,(1-a)/b) min(1,b/a) max(1-a/b,0) - * (0,A,0,B) min(1,(1-b)/a) max(1-(1-a)/b,0) max(1-b/a,0) min(1,a/b) - * (0,A,B,0) min(1,(1-b)/a) min(1,(1-a)/b) max(1-b/a,0) max(1-a/b,0) + * ad * as * B(d/ad, s/as) + * = ad * as * (d/ad + s/as - s/as * d/ad) + * = ad * s + as * d - s * d + */ +static inline int32_t +blend_screen (int32_t d, int32_t ad, int32_t s, int32_t as) +{ + return s * ad + d * as - s * d; +} + +PDF_SEPARABLE_BLEND_MODE (screen) + +/* + * Overlay * - * See http://marc.info/?l=xfree-render&m=99792000027857&w=2 for more - * information about these operators. + * ad * as * B(d/ad, s/as) + * = ad * as * Hardlight (s, d) + * = if (d / ad < 0.5) + * as * ad * Multiply (s/as, 2 * d/ad) + * else + * as * ad * Screen (s/as, 2 * d / ad - 1) + * = if (d < 0.5 * ad) + * as * ad * s/as * 2 * d /ad + * else + * as * ad * (s/as + 2 * d / ad - 1 - s / as * (2 * d / ad - 1)) + * = if (2 * d < ad) + * 2 * s * d + * else + * ad * s + 2 * as * d - as * ad - ad * s * (2 * d / ad - 1) + * = if (2 * d < ad) + * 2 * s * d + * else + * as * ad - 2 * (ad - d) * (as - s) + */ +static inline int32_t +blend_overlay (int32_t d, int32_t ad, int32_t s, int32_t as) +{ + uint32_t r; + + if (2 * d < ad) + r = 2 * s * d; + else + r = as * ad - 2 * (ad - d) * (as - s); + + return r; +} + +PDF_SEPARABLE_BLEND_MODE (overlay) + +/* + * Darken + * + * ad * as * B(d/ad, s/as) + * = ad * as * MIN(d/ad, s/as) + * = MIN (as * d, ad * s) + */ +static inline int32_t +blend_darken (int32_t d, int32_t ad, int32_t s, int32_t as) +{ + s = ad * s; + d = as * d; + + return s > d ? d : s; +} + +PDF_SEPARABLE_BLEND_MODE (darken) + +/* + * Lighten + * + * ad * as * B(d/ad, s/as) + * = ad * as * MAX(d/ad, s/as) + * = MAX (as * d, ad * s) + */ +static inline int32_t +blend_lighten (int32_t d, int32_t ad, int32_t s, int32_t as) +{ + s = ad * s; + d = as * d; + + return s > d ? s : d; +} + +PDF_SEPARABLE_BLEND_MODE (lighten) + +/* + * Hard light + * + * ad * as * B(d/ad, s/as) + * = if (s/as <= 0.5) + * ad * as * Multiply (d/ad, 2 * s/as) + * else + * ad * as * Screen (d/ad, 2 * s/as - 1) + * = if 2 * s <= as + * ad * as * d/ad * 2 * s / as + * else + * ad * as * (d/ad + (2 * s/as - 1) + d/ad * (2 * s/as - 1)) + * = if 2 * s <= as + * 2 * s * d + * else + * as * ad - 2 * (ad - d) * (as - s) + */ +static inline int32_t +blend_hard_light (int32_t d, int32_t ad, int32_t s, int32_t as) +{ + if (2 * s < as) + return 2 * s * d; + else + return as * ad - 2 * (ad - d) * (as - s); +} + +PDF_SEPARABLE_BLEND_MODE (hard_light) + +/* + * Difference + * + * ad * as * B(s/as, d/ad) + * = ad * as * abs (s/as - d/ad) + * = if (s/as <= d/ad) + * ad * as * (d/ad - s/as) + * else + * ad * as * (s/as - d/ad) + * = if (ad * s <= as * d) + * as * d - ad * s + * else + * ad * s - as * d + */ +static inline int32_t +blend_difference (int32_t d, int32_t ad, int32_t s, int32_t as) +{ + int32_t das = d * as; + int32_t sad = s * ad; + + if (sad < das) + return das - sad; + else + return sad - das; +} + +PDF_SEPARABLE_BLEND_MODE (difference) + +/* + * Exclusion + * + * ad * as * B(s/as, d/ad) + * = ad * as * (d/ad + s/as - 2 * d/ad * s/as) + * = as * d + ad * s - 2 * s * d */ -#define COMBINE_A_OUT 1 -#define COMBINE_A_IN 2 -#define COMBINE_B_OUT 4 -#define COMBINE_B_IN 8 +/* This can be made faster by writing it directly and not using + * PDF_SEPARABLE_BLEND_MODE, but that's a performance optimization */ -#define COMBINE_CLEAR 0 -#define COMBINE_A (COMBINE_A_OUT | COMBINE_A_IN) -#define COMBINE_B (COMBINE_B_OUT | COMBINE_B_IN) -#define COMBINE_A_OVER (COMBINE_A_OUT | COMBINE_B_OUT | COMBINE_A_IN) -#define COMBINE_B_OVER (COMBINE_A_OUT | COMBINE_B_OUT | COMBINE_B_IN) -#define COMBINE_A_ATOP (COMBINE_B_OUT | COMBINE_A_IN) -#define COMBINE_B_ATOP (COMBINE_A_OUT | COMBINE_B_IN) -#define COMBINE_XOR (COMBINE_A_OUT | COMBINE_B_OUT) - -/* portion covered by a but not b */ -static uint8_t -combine_disjoint_out_part (uint8_t a, uint8_t b) +static inline int32_t +blend_exclusion (int32_t d, int32_t ad, int32_t s, int32_t as) { - /* min (1, (1-b) / a) */ - - b = ~b; /* 1 - b */ - if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */ - return MASK; /* 1 */ - return DIV_UN8 (b, a); /* (1-b) / a */ + return s * ad + d * as - 2 * d * s; } -/* portion covered by both a and b */ -static uint8_t -combine_disjoint_in_part (uint8_t a, uint8_t b) -{ - /* max (1-(1-b)/a,0) */ - /* = - min ((1-b)/a - 1, 0) */ - /* = 1 - min (1, (1-b)/a) */ - - b = ~b; /* 1 - b */ - if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */ - return 0; /* 1 - 1 */ - return ~DIV_UN8(b, a); /* 1 - (1-b) / a */ -} - -/* portion covered by a but not b */ -static uint8_t -combine_conjoint_out_part (uint8_t a, uint8_t b) -{ - /* max (1-b/a,0) */ - /* = 1-min(b/a,1) */ - - /* min (1, (1-b) / a) */ - - if (b >= a) /* b >= a -> b/a >= 1 */ - return 0x00; /* 0 */ - return ~DIV_UN8(b, a); /* 1 - b/a */ -} - -/* portion covered by both a and b */ -static uint8_t -combine_conjoint_in_part (uint8_t a, uint8_t b) -{ - /* min (1,b/a) */ - - if (b >= a) /* b >= a -> b/a >= 1 */ - return MASK; /* 1 */ - return DIV_UN8 (b, a); /* b/a */ -} - -#define GET_COMP(v, i) ((uint16_t) (uint8_t) ((v) >> i)) - -#define ADD(x, y, i, t) \ - ((t) = GET_COMP (x, i) + GET_COMP (y, i), \ - (uint32_t) ((uint8_t) ((t) | (0 - ((t) >> G_SHIFT)))) << (i)) - -#define GENERIC(x, y, i, ax, ay, t, u, v) \ - ((t) = (MUL_UN8 (GET_COMP (y, i), ay, (u)) + \ - MUL_UN8 (GET_COMP (x, i), ax, (v))), \ - (uint32_t) ((uint8_t) ((t) | \ - (0 - ((t) >> G_SHIFT)))) << (i)) - -static void -combine_disjoint_general_u (uint32_t * dest, - const uint32_t *src, - const uint32_t *mask, - int width, - uint8_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint32_t s = combine_mask (src, mask, i); - uint32_t d = *(dest + i); - uint32_t m, n, o, p; - uint16_t Fa, Fb, t, u, v; - uint8_t sa = s >> A_SHIFT; - uint8_t da = d >> A_SHIFT; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - Fa = combine_disjoint_out_part (sa, da); - break; - - case COMBINE_A_IN: - Fa = combine_disjoint_in_part (sa, da); - break; - - case COMBINE_A: - Fa = MASK; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - Fb = combine_disjoint_out_part (da, sa); - break; - - case COMBINE_B_IN: - Fb = combine_disjoint_in_part (da, sa); - break; - - case COMBINE_B: - Fb = MASK; - break; - } - m = GENERIC (s, d, 0, Fa, Fb, t, u, v); - n = GENERIC (s, d, G_SHIFT, Fa, Fb, t, u, v); - o = GENERIC (s, d, R_SHIFT, Fa, Fb, t, u, v); - p = GENERIC (s, d, A_SHIFT, Fa, Fb, t, u, v); - s = m | n | o | p; - *(dest + i) = s; - } -} - -static void -combine_disjoint_over_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint32_t s = combine_mask (src, mask, i); - uint16_t a = s >> A_SHIFT; - - if (s != 0x00) - { - uint32_t d = *(dest + i); - a = combine_disjoint_out_part (d >> A_SHIFT, a); - UN8x4_MUL_UN8_ADD_UN8x4 (d, a, s); - - *(dest + i) = d; - } - } -} - -static void -combine_disjoint_in_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_disjoint_in_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_disjoint_out_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_disjoint_out_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_disjoint_atop_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_disjoint_atop_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_disjoint_xor_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_XOR); -} - -static void -combine_conjoint_general_u (uint32_t * dest, - const uint32_t *src, - const uint32_t *mask, - int width, - uint8_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint32_t s = combine_mask (src, mask, i); - uint32_t d = *(dest + i); - uint32_t m, n, o, p; - uint16_t Fa, Fb, t, u, v; - uint8_t sa = s >> A_SHIFT; - uint8_t da = d >> A_SHIFT; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - Fa = combine_conjoint_out_part (sa, da); - break; - - case COMBINE_A_IN: - Fa = combine_conjoint_in_part (sa, da); - break; - - case COMBINE_A: - Fa = MASK; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - Fb = combine_conjoint_out_part (da, sa); - break; - - case COMBINE_B_IN: - Fb = combine_conjoint_in_part (da, sa); - break; - - case COMBINE_B: - Fb = MASK; - break; - } - - m = GENERIC (s, d, 0, Fa, Fb, t, u, v); - n = GENERIC (s, d, G_SHIFT, Fa, Fb, t, u, v); - o = GENERIC (s, d, R_SHIFT, Fa, Fb, t, u, v); - p = GENERIC (s, d, A_SHIFT, Fa, Fb, t, u, v); - - s = m | n | o | p; - - *(dest + i) = s; - } -} - -static void -combine_conjoint_over_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_OVER); -} - -static void -combine_conjoint_over_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_OVER); -} - -static void -combine_conjoint_in_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_conjoint_in_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_conjoint_out_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_conjoint_out_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_conjoint_atop_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_conjoint_atop_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_conjoint_xor_u (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_XOR); -} +PDF_SEPARABLE_BLEND_MODE (exclusion) +#undef PDF_SEPARABLE_BLEND_MODE /* Component alpha combiners */ @@ -1955,428 +1136,6 @@ combine_add_ca (pixman_implementation_t *imp, } } -static void -combine_saturate_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint32_t s, d; - uint16_t sa, sr, sg, sb, da; - uint16_t t, u, v; - uint32_t m, n, o, p; - - d = *(dest + i); - s = *(src + i); - m = *(mask + i); - - combine_mask_ca (&s, &m); - - sa = (m >> A_SHIFT); - sr = (m >> R_SHIFT) & MASK; - sg = (m >> G_SHIFT) & MASK; - sb = m & MASK; - da = ~d >> A_SHIFT; - - if (sb <= da) - m = ADD (s, d, 0, t); - else - m = GENERIC (s, d, 0, (da << G_SHIFT) / sb, MASK, t, u, v); - - if (sg <= da) - n = ADD (s, d, G_SHIFT, t); - else - n = GENERIC (s, d, G_SHIFT, (da << G_SHIFT) / sg, MASK, t, u, v); - - if (sr <= da) - o = ADD (s, d, R_SHIFT, t); - else - o = GENERIC (s, d, R_SHIFT, (da << G_SHIFT) / sr, MASK, t, u, v); - - if (sa <= da) - p = ADD (s, d, A_SHIFT, t); - else - p = GENERIC (s, d, A_SHIFT, (da << G_SHIFT) / sa, MASK, t, u, v); - - *(dest + i) = m | n | o | p; - } -} - -static void -combine_disjoint_general_ca (uint32_t * dest, - const uint32_t *src, - const uint32_t *mask, - int width, - uint8_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint32_t s, d; - uint32_t m, n, o, p; - uint32_t Fa, Fb; - uint16_t t, u, v; - uint32_t sa; - uint8_t da; - - s = *(src + i); - m = *(mask + i); - d = *(dest + i); - da = d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - sa = m; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - m = (uint32_t)combine_disjoint_out_part ((uint8_t) (sa >> 0), da); - n = (uint32_t)combine_disjoint_out_part ((uint8_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (uint32_t)combine_disjoint_out_part ((uint8_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (uint32_t)combine_disjoint_out_part ((uint8_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A_IN: - m = (uint32_t)combine_disjoint_in_part ((uint8_t) (sa >> 0), da); - n = (uint32_t)combine_disjoint_in_part ((uint8_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (uint32_t)combine_disjoint_in_part ((uint8_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (uint32_t)combine_disjoint_in_part ((uint8_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A: - Fa = ~0; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - m = (uint32_t)combine_disjoint_out_part (da, (uint8_t) (sa >> 0)); - n = (uint32_t)combine_disjoint_out_part (da, (uint8_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (uint32_t)combine_disjoint_out_part (da, (uint8_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (uint32_t)combine_disjoint_out_part (da, (uint8_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B_IN: - m = (uint32_t)combine_disjoint_in_part (da, (uint8_t) (sa >> 0)); - n = (uint32_t)combine_disjoint_in_part (da, (uint8_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (uint32_t)combine_disjoint_in_part (da, (uint8_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (uint32_t)combine_disjoint_in_part (da, (uint8_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B: - Fb = ~0; - break; - } - m = GENERIC (s, d, 0, GET_COMP (Fa, 0), GET_COMP (Fb, 0), t, u, v); - n = GENERIC (s, d, G_SHIFT, GET_COMP (Fa, G_SHIFT), GET_COMP (Fb, G_SHIFT), t, u, v); - o = GENERIC (s, d, R_SHIFT, GET_COMP (Fa, R_SHIFT), GET_COMP (Fb, R_SHIFT), t, u, v); - p = GENERIC (s, d, A_SHIFT, GET_COMP (Fa, A_SHIFT), GET_COMP (Fb, A_SHIFT), t, u, v); - - s = m | n | o | p; - - *(dest + i) = s; - } -} - -static void -combine_disjoint_over_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_OVER); -} - -static void -combine_disjoint_in_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_disjoint_in_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_disjoint_out_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_disjoint_out_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_disjoint_atop_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_disjoint_atop_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_disjoint_xor_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_XOR); -} - -static void -combine_conjoint_general_ca (uint32_t * dest, - const uint32_t *src, - const uint32_t *mask, - int width, - uint8_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint32_t s, d; - uint32_t m, n, o, p; - uint32_t Fa, Fb; - uint16_t t, u, v; - uint32_t sa; - uint8_t da; - - s = *(src + i); - m = *(mask + i); - d = *(dest + i); - da = d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - sa = m; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - m = (uint32_t)combine_conjoint_out_part ((uint8_t) (sa >> 0), da); - n = (uint32_t)combine_conjoint_out_part ((uint8_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (uint32_t)combine_conjoint_out_part ((uint8_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (uint32_t)combine_conjoint_out_part ((uint8_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A_IN: - m = (uint32_t)combine_conjoint_in_part ((uint8_t) (sa >> 0), da); - n = (uint32_t)combine_conjoint_in_part ((uint8_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (uint32_t)combine_conjoint_in_part ((uint8_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (uint32_t)combine_conjoint_in_part ((uint8_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A: - Fa = ~0; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - m = (uint32_t)combine_conjoint_out_part (da, (uint8_t) (sa >> 0)); - n = (uint32_t)combine_conjoint_out_part (da, (uint8_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (uint32_t)combine_conjoint_out_part (da, (uint8_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (uint32_t)combine_conjoint_out_part (da, (uint8_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B_IN: - m = (uint32_t)combine_conjoint_in_part (da, (uint8_t) (sa >> 0)); - n = (uint32_t)combine_conjoint_in_part (da, (uint8_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (uint32_t)combine_conjoint_in_part (da, (uint8_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (uint32_t)combine_conjoint_in_part (da, (uint8_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B: - Fb = ~0; - break; - } - m = GENERIC (s, d, 0, GET_COMP (Fa, 0), GET_COMP (Fb, 0), t, u, v); - n = GENERIC (s, d, G_SHIFT, GET_COMP (Fa, G_SHIFT), GET_COMP (Fb, G_SHIFT), t, u, v); - o = GENERIC (s, d, R_SHIFT, GET_COMP (Fa, R_SHIFT), GET_COMP (Fb, R_SHIFT), t, u, v); - p = GENERIC (s, d, A_SHIFT, GET_COMP (Fa, A_SHIFT), GET_COMP (Fb, A_SHIFT), t, u, v); - - s = m | n | o | p; - - *(dest + i) = s; - } -} - -static void -combine_conjoint_over_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_OVER); -} - -static void -combine_conjoint_over_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_OVER); -} - -static void -combine_conjoint_in_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_conjoint_in_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_conjoint_out_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_conjoint_out_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_conjoint_atop_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_conjoint_atop_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_conjoint_xor_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint32_t * dest, - const uint32_t * src, - const uint32_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_XOR); -} - void _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp) { @@ -2394,51 +1153,15 @@ _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp) imp->combine_32[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_u; imp->combine_32[PIXMAN_OP_XOR] = combine_xor_u; imp->combine_32[PIXMAN_OP_ADD] = combine_add_u; - imp->combine_32[PIXMAN_OP_SATURATE] = combine_saturate_u; - - /* Disjoint, unified */ - imp->combine_32[PIXMAN_OP_DISJOINT_CLEAR] = combine_clear; - imp->combine_32[PIXMAN_OP_DISJOINT_SRC] = combine_src_u; - imp->combine_32[PIXMAN_OP_DISJOINT_DST] = combine_dst; - imp->combine_32[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_u; - imp->combine_32[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_saturate_u; - imp->combine_32[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_u; - imp->combine_32[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_u; - imp->combine_32[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_u; - imp->combine_32[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_u; - imp->combine_32[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_u; - imp->combine_32[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_u; - imp->combine_32[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_u; - - /* Conjoint, unified */ - imp->combine_32[PIXMAN_OP_CONJOINT_CLEAR] = combine_clear; - imp->combine_32[PIXMAN_OP_CONJOINT_SRC] = combine_src_u; - imp->combine_32[PIXMAN_OP_CONJOINT_DST] = combine_dst; - imp->combine_32[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_u; - imp->combine_32[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_u; - imp->combine_32[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_u; - imp->combine_32[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_u; - imp->combine_32[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_u; - imp->combine_32[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_u; - imp->combine_32[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_u; - imp->combine_32[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_u; - imp->combine_32[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_u; imp->combine_32[PIXMAN_OP_MULTIPLY] = combine_multiply_u; imp->combine_32[PIXMAN_OP_SCREEN] = combine_screen_u; imp->combine_32[PIXMAN_OP_OVERLAY] = combine_overlay_u; imp->combine_32[PIXMAN_OP_DARKEN] = combine_darken_u; imp->combine_32[PIXMAN_OP_LIGHTEN] = combine_lighten_u; - imp->combine_32[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_u; - imp->combine_32[PIXMAN_OP_COLOR_BURN] = combine_color_burn_u; imp->combine_32[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_u; - imp->combine_32[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_u; imp->combine_32[PIXMAN_OP_DIFFERENCE] = combine_difference_u; imp->combine_32[PIXMAN_OP_EXCLUSION] = combine_exclusion_u; - imp->combine_32[PIXMAN_OP_HSL_HUE] = combine_hsl_hue_u; - imp->combine_32[PIXMAN_OP_HSL_SATURATION] = combine_hsl_saturation_u; - imp->combine_32[PIXMAN_OP_HSL_COLOR] = combine_hsl_color_u; - imp->combine_32[PIXMAN_OP_HSL_LUMINOSITY] = combine_hsl_luminosity_u; /* Component alpha combiners */ imp->combine_32_ca[PIXMAN_OP_CLEAR] = combine_clear_ca; @@ -2454,51 +1177,13 @@ _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp) imp->combine_32_ca[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_ca; imp->combine_32_ca[PIXMAN_OP_XOR] = combine_xor_ca; imp->combine_32_ca[PIXMAN_OP_ADD] = combine_add_ca; - imp->combine_32_ca[PIXMAN_OP_SATURATE] = combine_saturate_ca; - - /* Disjoint CA */ - imp->combine_32_ca[PIXMAN_OP_DISJOINT_CLEAR] = combine_clear_ca; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_SRC] = combine_src_ca; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_DST] = combine_dst; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_ca; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_saturate_ca; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_ca; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_ca; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_ca; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_ca; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_ca; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_ca; - imp->combine_32_ca[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_ca; - - /* Conjoint CA */ - imp->combine_32_ca[PIXMAN_OP_CONJOINT_CLEAR] = combine_clear_ca; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_SRC] = combine_src_ca; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_DST] = combine_dst; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_ca; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_ca; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_ca; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_ca; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_ca; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_ca; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_ca; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_ca; - imp->combine_32_ca[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_ca; imp->combine_32_ca[PIXMAN_OP_MULTIPLY] = combine_multiply_ca; imp->combine_32_ca[PIXMAN_OP_SCREEN] = combine_screen_ca; imp->combine_32_ca[PIXMAN_OP_OVERLAY] = combine_overlay_ca; imp->combine_32_ca[PIXMAN_OP_DARKEN] = combine_darken_ca; imp->combine_32_ca[PIXMAN_OP_LIGHTEN] = combine_lighten_ca; - imp->combine_32_ca[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_ca; - imp->combine_32_ca[PIXMAN_OP_COLOR_BURN] = combine_color_burn_ca; imp->combine_32_ca[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_ca; - imp->combine_32_ca[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_ca; imp->combine_32_ca[PIXMAN_OP_DIFFERENCE] = combine_difference_ca; imp->combine_32_ca[PIXMAN_OP_EXCLUSION] = combine_exclusion_ca; - - /* It is not clear that these make sense, so make them noops for now */ - imp->combine_32_ca[PIXMAN_OP_HSL_HUE] = combine_dst; - imp->combine_32_ca[PIXMAN_OP_HSL_SATURATION] = combine_dst; - imp->combine_32_ca[PIXMAN_OP_HSL_COLOR] = combine_dst; - imp->combine_32_ca[PIXMAN_OP_HSL_LUMINOSITY] = combine_dst; } diff --git a/gfx/cairo/libpixman/src/pixman-combine32.h b/gfx/cairo/libpixman/src/pixman-combine32.h index cdd56a61a1..59bb2477aa 100644 --- a/gfx/cairo/libpixman/src/pixman-combine32.h +++ b/gfx/cairo/libpixman/src/pixman-combine32.h @@ -12,7 +12,7 @@ #define RB_MASK 0xff00ff #define AG_MASK 0xff00ff00 #define RB_ONE_HALF 0x800080 -#define RB_MASK_PLUS_ONE 0x10000100 +#define RB_MASK_PLUS_ONE 0x1000100 #define ALPHA_8(x) ((x) >> A_SHIFT) #define RED_8(x) (((x) >> R_SHIFT) & MASK) diff --git a/gfx/cairo/libpixman/src/pixman-combine64.c b/gfx/cairo/libpixman/src/pixman-combine64.c deleted file mode 100644 index 1c85af8eec..0000000000 --- a/gfx/cairo/libpixman/src/pixman-combine64.c +++ /dev/null @@ -1,2465 +0,0 @@ -/* WARNING: This file is generated by combine.pl from combine.inc. - Please edit one of those files rather than this one. */ - -#line 1 "pixman-combine.c.template" -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "pixman-private.h" - -#include "pixman-combine64.h" - -/*** per channel helper functions ***/ - -static void -combine_mask_ca (uint64_t *src, uint64_t *mask) -{ - uint64_t a = *mask; - - uint64_t x; - uint32_t xa; - - if (!a) - { - *(src) = 0; - return; - } - - x = *(src); - if (a == ~0) - { - x = x >> A_SHIFT; - x |= x << G_SHIFT; - x |= x << R_SHIFT; - *(mask) = x; - return; - } - - xa = x >> A_SHIFT; - UN16x4_MUL_UN16x4 (x, a); - *(src) = x; - - UN16x4_MUL_UN16 (a, xa); - *(mask) = a; -} - -static void -combine_mask_value_ca (uint64_t *src, const uint64_t *mask) -{ - uint64_t a = *mask; - uint64_t x; - - if (!a) - { - *(src) = 0; - return; - } - - if (a == ~0) - return; - - x = *(src); - UN16x4_MUL_UN16x4 (x, a); - *(src) = x; -} - -static void -combine_mask_alpha_ca (const uint64_t *src, uint64_t *mask) -{ - uint64_t a = *(mask); - uint64_t x; - - if (!a) - return; - - x = *(src) >> A_SHIFT; - if (x == MASK) - return; - - if (a == ~0) - { - x |= x << G_SHIFT; - x |= x << R_SHIFT; - *(mask) = x; - return; - } - - UN16x4_MUL_UN16 (a, x); - *(mask) = a; -} - -/* - * There are two ways of handling alpha -- either as a single unified value or - * a separate value for each component, hence each macro must have two - * versions. The unified alpha version has a 'U' at the end of the name, - * the component version has a 'C'. Similarly, functions which deal with - * this difference will have two versions using the same convention. - */ - -/* - * All of the composing functions - */ - -static force_inline uint64_t -combine_mask (const uint64_t *src, const uint64_t *mask, int i) -{ - uint64_t s, m; - - if (mask) - { - m = *(mask + i) >> A_SHIFT; - - if (!m) - return 0; - } - - s = *(src + i); - - if (mask) - UN16x4_MUL_UN16 (s, m); - - return s; -} - -static void -combine_clear (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - memset (dest, 0, width * sizeof(uint64_t)); -} - -static void -combine_dst (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - return; -} - -static void -combine_src_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - if (!mask) - memcpy (dest, src, width * sizeof (uint64_t)); - else - { - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - - *(dest + i) = s; - } - } -} - -/* if the Src is opaque, call combine_src_u */ -static void -combine_over_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint64_t ia = ALPHA_16 (~s); - - UN16x4_MUL_UN16_ADD_UN16x4 (d, ia, s); - *(dest + i) = d; - } -} - -/* if the Dst is opaque, this is a noop */ -static void -combine_over_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint64_t ia = ALPHA_16 (~*(dest + i)); - UN16x4_MUL_UN16_ADD_UN16x4 (s, ia, d); - *(dest + i) = s; - } -} - -/* if the Dst is opaque, call combine_src_u */ -static void -combine_in_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t a = ALPHA_16 (*(dest + i)); - UN16x4_MUL_UN16 (s, a); - *(dest + i) = s; - } -} - -/* if the Src is opaque, this is a noop */ -static void -combine_in_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint64_t a = ALPHA_16 (s); - UN16x4_MUL_UN16 (d, a); - *(dest + i) = d; - } -} - -/* if the Dst is opaque, call combine_clear */ -static void -combine_out_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t a = ALPHA_16 (~*(dest + i)); - UN16x4_MUL_UN16 (s, a); - *(dest + i) = s; - } -} - -/* if the Src is opaque, call combine_clear */ -static void -combine_out_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint64_t a = ALPHA_16 (~s); - UN16x4_MUL_UN16 (d, a); - *(dest + i) = d; - } -} - -/* if the Src is opaque, call combine_in_u */ -/* if the Dst is opaque, call combine_over_u */ -/* if both the Src and Dst are opaque, call combine_src_u */ -static void -combine_atop_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint64_t dest_a = ALPHA_16 (d); - uint64_t src_ia = ALPHA_16 (~s); - - UN16x4_MUL_UN16_ADD_UN16x4_MUL_UN16 (s, dest_a, d, src_ia); - *(dest + i) = s; - } -} - -/* if the Src is opaque, call combine_over_reverse_u */ -/* if the Dst is opaque, call combine_in_reverse_u */ -/* if both the Src and Dst are opaque, call combine_dst_u */ -static void -combine_atop_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint64_t src_a = ALPHA_16 (s); - uint64_t dest_ia = ALPHA_16 (~d); - - UN16x4_MUL_UN16_ADD_UN16x4_MUL_UN16 (s, dest_ia, d, src_a); - *(dest + i) = s; - } -} - -/* if the Src is opaque, call combine_over_u */ -/* if the Dst is opaque, call combine_over_reverse_u */ -/* if both the Src and Dst are opaque, call combine_clear */ -static void -combine_xor_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint64_t src_ia = ALPHA_16 (~s); - uint64_t dest_ia = ALPHA_16 (~d); - - UN16x4_MUL_UN16_ADD_UN16x4_MUL_UN16 (s, dest_ia, d, src_ia); - *(dest + i) = s; - } -} - -static void -combine_add_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - UN16x4_ADD_UN16x4 (d, s); - *(dest + i) = d; - } -} - -/* if the Src is opaque, call combine_add_u */ -/* if the Dst is opaque, call combine_add_u */ -/* if both the Src and Dst are opaque, call combine_add_u */ -static void -combine_saturate_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint32_t sa, da; - - sa = s >> A_SHIFT; - da = ~d >> A_SHIFT; - if (sa > da) - { - sa = DIV_UN16 (da, sa); - UN16x4_MUL_UN16 (s, sa); - } - ; - UN16x4_ADD_UN16x4 (d, s); - *(dest + i) = d; - } -} - -/* - * PDF blend modes: - * The following blend modes have been taken from the PDF ISO 32000 - * specification, which at this point in time is available from - * http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf - * The relevant chapters are 11.3.5 and 11.3.6. - * The formula for computing the final pixel color given in 11.3.6 is: - * αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs) - * with B() being the blend function. - * Note that OVER is a special case of this operation, using B(Cb, Cs) = Cs - * - * These blend modes should match the SVG filter draft specification, as - * it has been designed to mirror ISO 32000. Note that at the current point - * no released draft exists that shows this, as the formulas have not been - * updated yet after the release of ISO 32000. - * - * The default implementation here uses the PDF_SEPARABLE_BLEND_MODE and - * PDF_NON_SEPARABLE_BLEND_MODE macros, which take the blend function as an - * argument. Note that this implementation operates on premultiplied colors, - * while the PDF specification does not. Therefore the code uses the formula - * Cra = (1 – as) . Dca + (1 – ad) . Sca + B(Dca, ad, Sca, as) - */ - -/* - * Multiply - * B(Dca, ad, Sca, as) = Dca.Sca - */ - -static void -combine_multiply_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint64_t ss = s; - uint64_t src_ia = ALPHA_16 (~s); - uint64_t dest_ia = ALPHA_16 (~d); - - UN16x4_MUL_UN16_ADD_UN16x4_MUL_UN16 (ss, dest_ia, d, src_ia); - UN16x4_MUL_UN16x4 (d, s); - UN16x4_ADD_UN16x4 (d, ss); - - *(dest + i) = d; - } -} - -static void -combine_multiply_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t m = *(mask + i); - uint64_t s = *(src + i); - uint64_t d = *(dest + i); - uint64_t r = d; - uint64_t dest_ia = ALPHA_16 (~d); - - combine_mask_value_ca (&s, &m); - - UN16x4_MUL_UN16x4_ADD_UN16x4_MUL_UN16 (r, ~m, s, dest_ia); - UN16x4_MUL_UN16x4 (d, s); - UN16x4_ADD_UN16x4 (r, d); - - *(dest + i) = r; - } -} - -#define PDF_SEPARABLE_BLEND_MODE(name) \ - static void \ - combine_ ## name ## _u (pixman_implementation_t *imp, \ - pixman_op_t op, \ - uint64_t * dest, \ - const uint64_t * src, \ - const uint64_t * mask, \ - int width) \ - { \ - int i; \ - for (i = 0; i < width; ++i) { \ - uint64_t s = combine_mask (src, mask, i); \ - uint64_t d = *(dest + i); \ - uint16_t sa = ALPHA_16 (s); \ - uint16_t isa = ~sa; \ - uint16_t da = ALPHA_16 (d); \ - uint16_t ida = ~da; \ - uint64_t result; \ - \ - result = d; \ - UN16x4_MUL_UN16_ADD_UN16x4_MUL_UN16 (result, isa, s, ida); \ - \ - *(dest + i) = result + \ - (DIV_ONE_UN16 (sa * (uint64_t)da) << A_SHIFT) + \ - (blend_ ## name (RED_16 (d), da, RED_16 (s), sa) << R_SHIFT) + \ - (blend_ ## name (GREEN_16 (d), da, GREEN_16 (s), sa) << G_SHIFT) + \ - (blend_ ## name (BLUE_16 (d), da, BLUE_16 (s), sa)); \ - } \ - } \ - \ - static void \ - combine_ ## name ## _ca (pixman_implementation_t *imp, \ - pixman_op_t op, \ - uint64_t * dest, \ - const uint64_t * src, \ - const uint64_t * mask, \ - int width) \ - { \ - int i; \ - for (i = 0; i < width; ++i) { \ - uint64_t m = *(mask + i); \ - uint64_t s = *(src + i); \ - uint64_t d = *(dest + i); \ - uint16_t da = ALPHA_16 (d); \ - uint16_t ida = ~da; \ - uint64_t result; \ - \ - combine_mask_value_ca (&s, &m); \ - \ - result = d; \ - UN16x4_MUL_UN16x4_ADD_UN16x4_MUL_UN16 (result, ~m, s, ida); \ - \ - result += \ - (DIV_ONE_UN16 (ALPHA_16 (m) * (uint64_t)da) << A_SHIFT) + \ - (blend_ ## name (RED_16 (d), da, RED_16 (s), RED_16 (m)) << R_SHIFT) + \ - (blend_ ## name (GREEN_16 (d), da, GREEN_16 (s), GREEN_16 (m)) << G_SHIFT) + \ - (blend_ ## name (BLUE_16 (d), da, BLUE_16 (s), BLUE_16 (m))); \ - \ - *(dest + i) = result; \ - } \ - } - -/* - * Screen - * B(Dca, ad, Sca, as) = Dca.sa + Sca.da - Dca.Sca - */ -static inline uint64_t -blend_screen (uint64_t dca, uint64_t da, uint64_t sca, uint64_t sa) -{ - return DIV_ONE_UN16 (sca * da + dca * sa - sca * dca); -} - -PDF_SEPARABLE_BLEND_MODE (screen) - -/* - * Overlay - * B(Dca, Da, Sca, Sa) = - * if 2.Dca < Da - * 2.Sca.Dca - * otherwise - * Sa.Da - 2.(Da - Dca).(Sa - Sca) - */ -static inline uint64_t -blend_overlay (uint64_t dca, uint64_t da, uint64_t sca, uint64_t sa) -{ - uint64_t rca; - - if (2 * dca < da) - rca = 2 * sca * dca; - else - rca = sa * da - 2 * (da - dca) * (sa - sca); - return DIV_ONE_UN16 (rca); -} - -PDF_SEPARABLE_BLEND_MODE (overlay) - -/* - * Darken - * B(Dca, Da, Sca, Sa) = min (Sca.Da, Dca.Sa) - */ -static inline uint64_t -blend_darken (uint64_t dca, uint64_t da, uint64_t sca, uint64_t sa) -{ - uint64_t s, d; - - s = sca * da; - d = dca * sa; - return DIV_ONE_UN16 (s > d ? d : s); -} - -PDF_SEPARABLE_BLEND_MODE (darken) - -/* - * Lighten - * B(Dca, Da, Sca, Sa) = max (Sca.Da, Dca.Sa) - */ -static inline uint64_t -blend_lighten (uint64_t dca, uint64_t da, uint64_t sca, uint64_t sa) -{ - uint64_t s, d; - - s = sca * da; - d = dca * sa; - return DIV_ONE_UN16 (s > d ? s : d); -} - -PDF_SEPARABLE_BLEND_MODE (lighten) - -/* - * Color dodge - * B(Dca, Da, Sca, Sa) = - * if Dca == 0 - * 0 - * if Sca == Sa - * Sa.Da - * otherwise - * Sa.Da. min (1, Dca / Da / (1 - Sca/Sa)) - */ -static inline uint64_t -blend_color_dodge (uint64_t dca, uint64_t da, uint64_t sca, uint64_t sa) -{ - if (sca >= sa) - { - return dca == 0 ? 0 : DIV_ONE_UN16 (sa * da); - } - else - { - uint64_t rca = dca * sa / (sa - sca); - return DIV_ONE_UN16 (sa * MIN (rca, da)); - } -} - -PDF_SEPARABLE_BLEND_MODE (color_dodge) - -/* - * Color burn - * B(Dca, Da, Sca, Sa) = - * if Dca == Da - * Sa.Da - * if Sca == 0 - * 0 - * otherwise - * Sa.Da.(1 - min (1, (1 - Dca/Da).Sa / Sca)) - */ -static inline uint64_t -blend_color_burn (uint64_t dca, uint64_t da, uint64_t sca, uint64_t sa) -{ - if (sca == 0) - { - return dca < da ? 0 : DIV_ONE_UN16 (sa * da); - } - else - { - uint64_t rca = (da - dca) * sa / sca; - return DIV_ONE_UN16 (sa * (MAX (rca, da) - rca)); - } -} - -PDF_SEPARABLE_BLEND_MODE (color_burn) - -/* - * Hard light - * B(Dca, Da, Sca, Sa) = - * if 2.Sca < Sa - * 2.Sca.Dca - * otherwise - * Sa.Da - 2.(Da - Dca).(Sa - Sca) - */ -static inline uint64_t -blend_hard_light (uint64_t dca, uint64_t da, uint64_t sca, uint64_t sa) -{ - if (2 * sca < sa) - return DIV_ONE_UN16 (2 * sca * dca); - else - return DIV_ONE_UN16 (sa * da - 2 * (da - dca) * (sa - sca)); -} - -PDF_SEPARABLE_BLEND_MODE (hard_light) - -/* - * Soft light - * B(Dca, Da, Sca, Sa) = - * if (2.Sca <= Sa) - * Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa)) - * otherwise if Dca.4 <= Da - * Dca.(Sa + (2.Sca - Sa).((16.Dca/Da - 12).Dca/Da + 3) - * otherwise - * (Dca.Sa + (SQRT (Dca/Da).Da - Dca).(2.Sca - Sa)) - */ -static inline uint64_t -blend_soft_light (uint64_t dca_org, - uint64_t da_org, - uint64_t sca_org, - uint64_t sa_org) -{ - double dca = dca_org * (1.0 / MASK); - double da = da_org * (1.0 / MASK); - double sca = sca_org * (1.0 / MASK); - double sa = sa_org * (1.0 / MASK); - double rca; - - if (2 * sca < sa) - { - if (da == 0) - rca = dca * sa; - else - rca = dca * sa - dca * (da - dca) * (sa - 2 * sca) / da; - } - else if (da == 0) - { - rca = 0; - } - else if (4 * dca <= da) - { - rca = dca * sa + - (2 * sca - sa) * dca * ((16 * dca / da - 12) * dca / da + 3); - } - else - { - rca = dca * sa + (sqrt (dca * da) - dca) * (2 * sca - sa); - } - return rca * MASK + 0.5; -} - -PDF_SEPARABLE_BLEND_MODE (soft_light) - -/* - * Difference - * B(Dca, Da, Sca, Sa) = abs (Dca.Sa - Sca.Da) - */ -static inline uint64_t -blend_difference (uint64_t dca, uint64_t da, uint64_t sca, uint64_t sa) -{ - uint64_t dcasa = dca * sa; - uint64_t scada = sca * da; - - if (scada < dcasa) - return DIV_ONE_UN16 (dcasa - scada); - else - return DIV_ONE_UN16 (scada - dcasa); -} - -PDF_SEPARABLE_BLEND_MODE (difference) - -/* - * Exclusion - * B(Dca, Da, Sca, Sa) = (Sca.Da + Dca.Sa - 2.Sca.Dca) - */ - -/* This can be made faster by writing it directly and not using - * PDF_SEPARABLE_BLEND_MODE, but that's a performance optimization */ - -static inline uint64_t -blend_exclusion (uint64_t dca, uint64_t da, uint64_t sca, uint64_t sa) -{ - return DIV_ONE_UN16 (sca * da + dca * sa - 2 * dca * sca); -} - -PDF_SEPARABLE_BLEND_MODE (exclusion) - -#undef PDF_SEPARABLE_BLEND_MODE - -/* - * PDF nonseperable blend modes are implemented using the following functions - * to operate in Hsl space, with Cmax, Cmid, Cmin referring to the max, mid - * and min value of the red, green and blue components. - * - * LUM (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue - * - * clip_color (C): - * l = LUM (C) - * min = Cmin - * max = Cmax - * if n < 0.0 - * C = l + ( ( ( C – l ) × l ) ⁄ ( l – min ) ) - * if x > 1.0 - * C = l + ( ( ( C – l ) × ( 1 – l ) ) ⁄ ( max – l ) ) - * return C - * - * set_lum (C, l): - * d = l – LUM (C) - * C += d - * return clip_color (C) - * - * SAT (C) = CH_MAX (C) - CH_MIN (C) - * - * set_sat (C, s): - * if Cmax > Cmin - * Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) ) - * Cmax = s - * else - * Cmid = Cmax = 0.0 - * Cmin = 0.0 - * return C - */ - -/* For premultiplied colors, we need to know what happens when C is - * multiplied by a real number. LUM and SAT are linear: - * - * LUM (r × C) = r × LUM (C) SAT (r * C) = r * SAT (C) - * - * If we extend clip_color with an extra argument a and change - * - * if x >= 1.0 - * - * into - * - * if x >= a - * - * then clip_color is also linear: - * - * r * clip_color (C, a) = clip_color (r_c, ra); - * - * for positive r. - * - * Similarly, we can extend set_lum with an extra argument that is just passed - * on to clip_color: - * - * r * set_lum ( C, l, a) - * - * = r × clip_color ( C + l - LUM (C), a) - * - * = clip_color ( r * C + r × l - r * LUM (C), r * a) - * - * = set_lum ( r * C, r * l, r * a) - * - * Finally, set_sat: - * - * r * set_sat (C, s) = set_sat (x * C, r * s) - * - * The above holds for all non-zero x, because the x'es in the fraction for - * C_mid cancel out. Specifically, it holds for x = r: - * - * r * set_sat (C, s) = set_sat (r_c, rs) - * - */ - -/* So, for the non-separable PDF blend modes, we have (using s, d for - * non-premultiplied colors, and S, D for premultiplied: - * - * Color: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (S/a_s, LUM (D/a_d), 1) - * = set_lum (S * a_d, a_s * LUM (D), a_s * a_d) - * - * - * Luminosity: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (D/a_d, LUM(S/a_s), 1) - * = set_lum (a_s * D, a_d * LUM(S), a_s * a_d) - * - * - * Saturation: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (set_sat (D/a_d, SAT (S/a_s)), LUM (D/a_d), 1) - * = set_lum (a_s * a_d * set_sat (D/a_d, SAT (S/a_s)), - * a_s * LUM (D), a_s * a_d) - * = set_lum (set_sat (a_s * D, a_d * SAT (S), a_s * LUM (D), a_s * a_d)) - * - * Hue: - * - * a_s * a_d * B(s, d) - * = a_s * a_d * set_lum (set_sat (S/a_s, SAT (D/a_d)), LUM (D/a_d), 1) - * = set_lum (set_sat (a_d * S, a_s * SAT (D)), a_s * LUM (D), a_s * a_d) - * - */ - -#define CH_MIN(c) (c[0] < c[1] ? (c[0] < c[2] ? c[0] : c[2]) : (c[1] < c[2] ? c[1] : c[2])) -#define CH_MAX(c) (c[0] > c[1] ? (c[0] > c[2] ? c[0] : c[2]) : (c[1] > c[2] ? c[1] : c[2])) -#define LUM(c) ((c[0] * 30 + c[1] * 59 + c[2] * 11) / 100) -#define SAT(c) (CH_MAX (c) - CH_MIN (c)) - -#define PDF_NON_SEPARABLE_BLEND_MODE(name) \ - static void \ - combine_ ## name ## _u (pixman_implementation_t *imp, \ - pixman_op_t op, \ - uint64_t *dest, \ - const uint64_t *src, \ - const uint64_t *mask, \ - int width) \ - { \ - int i; \ - for (i = 0; i < width; ++i) \ - { \ - uint64_t s = combine_mask (src, mask, i); \ - uint64_t d = *(dest + i); \ - uint16_t sa = ALPHA_16 (s); \ - uint16_t isa = ~sa; \ - uint16_t da = ALPHA_16 (d); \ - uint16_t ida = ~da; \ - uint64_t result; \ - uint64_t sc[3], dc[3], c[3]; \ - \ - result = d; \ - UN16x4_MUL_UN16_ADD_UN16x4_MUL_UN16 (result, isa, s, ida); \ - dc[0] = RED_16 (d); \ - sc[0] = RED_16 (s); \ - dc[1] = GREEN_16 (d); \ - sc[1] = GREEN_16 (s); \ - dc[2] = BLUE_16 (d); \ - sc[2] = BLUE_16 (s); \ - blend_ ## name (c, dc, da, sc, sa); \ - \ - *(dest + i) = result + \ - (DIV_ONE_UN16 (sa * (uint64_t)da) << A_SHIFT) + \ - (DIV_ONE_UN16 (c[0]) << R_SHIFT) + \ - (DIV_ONE_UN16 (c[1]) << G_SHIFT) + \ - (DIV_ONE_UN16 (c[2])); \ - } \ - } - -static void -set_lum (uint64_t dest[3], uint64_t src[3], uint64_t sa, uint64_t lum) -{ - double a, l, min, max; - double tmp[3]; - - a = sa * (1.0 / MASK); - - l = lum * (1.0 / MASK); - tmp[0] = src[0] * (1.0 / MASK); - tmp[1] = src[1] * (1.0 / MASK); - tmp[2] = src[2] * (1.0 / MASK); - - l = l - LUM (tmp); - tmp[0] += l; - tmp[1] += l; - tmp[2] += l; - - /* clip_color */ - l = LUM (tmp); - min = CH_MIN (tmp); - max = CH_MAX (tmp); - - if (min < 0) - { - if (l - min == 0.0) - { - tmp[0] = 0; - tmp[1] = 0; - tmp[2] = 0; - } - else - { - tmp[0] = l + (tmp[0] - l) * l / (l - min); - tmp[1] = l + (tmp[1] - l) * l / (l - min); - tmp[2] = l + (tmp[2] - l) * l / (l - min); - } - } - if (max > a) - { - if (max - l == 0.0) - { - tmp[0] = a; - tmp[1] = a; - tmp[2] = a; - } - else - { - tmp[0] = l + (tmp[0] - l) * (a - l) / (max - l); - tmp[1] = l + (tmp[1] - l) * (a - l) / (max - l); - tmp[2] = l + (tmp[2] - l) * (a - l) / (max - l); - } - } - - dest[0] = tmp[0] * MASK + 0.5; - dest[1] = tmp[1] * MASK + 0.5; - dest[2] = tmp[2] * MASK + 0.5; -} - -static void -set_sat (uint64_t dest[3], uint64_t src[3], uint64_t sat) -{ - int id[3]; - uint64_t min, max; - - if (src[0] > src[1]) - { - if (src[0] > src[2]) - { - id[0] = 0; - if (src[1] > src[2]) - { - id[1] = 1; - id[2] = 2; - } - else - { - id[1] = 2; - id[2] = 1; - } - } - else - { - id[0] = 2; - id[1] = 0; - id[2] = 1; - } - } - else - { - if (src[0] > src[2]) - { - id[0] = 1; - id[1] = 0; - id[2] = 2; - } - else - { - id[2] = 0; - if (src[1] > src[2]) - { - id[0] = 1; - id[1] = 2; - } - else - { - id[0] = 2; - id[1] = 1; - } - } - } - - max = dest[id[0]]; - min = dest[id[2]]; - if (max > min) - { - dest[id[1]] = (dest[id[1]] - min) * sat / (max - min); - dest[id[0]] = sat; - dest[id[2]] = 0; - } - else - { - dest[0] = dest[1] = dest[2] = 0; - } -} - -/* - * Hue: - * B(Cb, Cs) = set_lum (set_sat (Cs, SAT (Cb)), LUM (Cb)) - */ -static inline void -blend_hsl_hue (uint64_t c[3], - uint64_t dc[3], - uint64_t da, - uint64_t sc[3], - uint64_t sa) -{ - c[0] = sc[0] * da; - c[1] = sc[1] * da; - c[2] = sc[2] * da; - set_sat (c, c, SAT (dc) * sa); - set_lum (c, c, sa * da, LUM (dc) * sa); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_hue) - -/* - * Saturation: - * B(Cb, Cs) = set_lum (set_sat (Cb, SAT (Cs)), LUM (Cb)) - */ -static inline void -blend_hsl_saturation (uint64_t c[3], - uint64_t dc[3], - uint64_t da, - uint64_t sc[3], - uint64_t sa) -{ - c[0] = dc[0] * sa; - c[1] = dc[1] * sa; - c[2] = dc[2] * sa; - set_sat (c, c, SAT (sc) * da); - set_lum (c, c, sa * da, LUM (dc) * sa); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_saturation) - -/* - * Color: - * B(Cb, Cs) = set_lum (Cs, LUM (Cb)) - */ -static inline void -blend_hsl_color (uint64_t c[3], - uint64_t dc[3], - uint64_t da, - uint64_t sc[3], - uint64_t sa) -{ - c[0] = sc[0] * da; - c[1] = sc[1] * da; - c[2] = sc[2] * da; - set_lum (c, c, sa * da, LUM (dc) * sa); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_color) - -/* - * Luminosity: - * B(Cb, Cs) = set_lum (Cb, LUM (Cs)) - */ -static inline void -blend_hsl_luminosity (uint64_t c[3], - uint64_t dc[3], - uint64_t da, - uint64_t sc[3], - uint64_t sa) -{ - c[0] = dc[0] * sa; - c[1] = dc[1] * sa; - c[2] = dc[2] * sa; - set_lum (c, c, sa * da, LUM (sc) * da); -} - -PDF_NON_SEPARABLE_BLEND_MODE (hsl_luminosity) - -#undef SAT -#undef LUM -#undef CH_MAX -#undef CH_MIN -#undef PDF_NON_SEPARABLE_BLEND_MODE - -/* All of the disjoint/conjoint composing functions - * - * The four entries in the first column indicate what source contributions - * come from each of the four areas of the picture -- areas covered by neither - * A nor B, areas covered only by A, areas covered only by B and finally - * areas covered by both A and B. - * - * Disjoint Conjoint - * Fa Fb Fa Fb - * (0,0,0,0) 0 0 0 0 - * (0,A,0,A) 1 0 1 0 - * (0,0,B,B) 0 1 0 1 - * (0,A,B,A) 1 min((1-a)/b,1) 1 max(1-a/b,0) - * (0,A,B,B) min((1-b)/a,1) 1 max(1-b/a,0) 1 - * (0,0,0,A) max(1-(1-b)/a,0) 0 min(1,b/a) 0 - * (0,0,0,B) 0 max(1-(1-a)/b,0) 0 min(a/b,1) - * (0,A,0,0) min(1,(1-b)/a) 0 max(1-b/a,0) 0 - * (0,0,B,0) 0 min(1,(1-a)/b) 0 max(1-a/b,0) - * (0,0,B,A) max(1-(1-b)/a,0) min(1,(1-a)/b) min(1,b/a) max(1-a/b,0) - * (0,A,0,B) min(1,(1-b)/a) max(1-(1-a)/b,0) max(1-b/a,0) min(1,a/b) - * (0,A,B,0) min(1,(1-b)/a) min(1,(1-a)/b) max(1-b/a,0) max(1-a/b,0) - * - * See http://marc.info/?l=xfree-render&m=99792000027857&w=2 for more - * information about these operators. - */ - -#define COMBINE_A_OUT 1 -#define COMBINE_A_IN 2 -#define COMBINE_B_OUT 4 -#define COMBINE_B_IN 8 - -#define COMBINE_CLEAR 0 -#define COMBINE_A (COMBINE_A_OUT | COMBINE_A_IN) -#define COMBINE_B (COMBINE_B_OUT | COMBINE_B_IN) -#define COMBINE_A_OVER (COMBINE_A_OUT | COMBINE_B_OUT | COMBINE_A_IN) -#define COMBINE_B_OVER (COMBINE_A_OUT | COMBINE_B_OUT | COMBINE_B_IN) -#define COMBINE_A_ATOP (COMBINE_B_OUT | COMBINE_A_IN) -#define COMBINE_B_ATOP (COMBINE_A_OUT | COMBINE_B_IN) -#define COMBINE_XOR (COMBINE_A_OUT | COMBINE_B_OUT) - -/* portion covered by a but not b */ -static uint16_t -combine_disjoint_out_part (uint16_t a, uint16_t b) -{ - /* min (1, (1-b) / a) */ - - b = ~b; /* 1 - b */ - if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */ - return MASK; /* 1 */ - return DIV_UN16 (b, a); /* (1-b) / a */ -} - -/* portion covered by both a and b */ -static uint16_t -combine_disjoint_in_part (uint16_t a, uint16_t b) -{ - /* max (1-(1-b)/a,0) */ - /* = - min ((1-b)/a - 1, 0) */ - /* = 1 - min (1, (1-b)/a) */ - - b = ~b; /* 1 - b */ - if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */ - return 0; /* 1 - 1 */ - return ~DIV_UN16(b, a); /* 1 - (1-b) / a */ -} - -/* portion covered by a but not b */ -static uint16_t -combine_conjoint_out_part (uint16_t a, uint16_t b) -{ - /* max (1-b/a,0) */ - /* = 1-min(b/a,1) */ - - /* min (1, (1-b) / a) */ - - if (b >= a) /* b >= a -> b/a >= 1 */ - return 0x00; /* 0 */ - return ~DIV_UN16(b, a); /* 1 - b/a */ -} - -/* portion covered by both a and b */ -static uint16_t -combine_conjoint_in_part (uint16_t a, uint16_t b) -{ - /* min (1,b/a) */ - - if (b >= a) /* b >= a -> b/a >= 1 */ - return MASK; /* 1 */ - return DIV_UN16 (b, a); /* b/a */ -} - -#define GET_COMP(v, i) ((uint32_t) (uint16_t) ((v) >> i)) - -#define ADD(x, y, i, t) \ - ((t) = GET_COMP (x, i) + GET_COMP (y, i), \ - (uint64_t) ((uint16_t) ((t) | (0 - ((t) >> G_SHIFT)))) << (i)) - -#define GENERIC(x, y, i, ax, ay, t, u, v) \ - ((t) = (MUL_UN16 (GET_COMP (y, i), ay, (u)) + \ - MUL_UN16 (GET_COMP (x, i), ax, (v))), \ - (uint64_t) ((uint16_t) ((t) | \ - (0 - ((t) >> G_SHIFT)))) << (i)) - -static void -combine_disjoint_general_u (uint64_t * dest, - const uint64_t *src, - const uint64_t *mask, - int width, - uint16_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint64_t m, n, o, p; - uint32_t Fa, Fb, t, u, v; - uint16_t sa = s >> A_SHIFT; - uint16_t da = d >> A_SHIFT; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - Fa = combine_disjoint_out_part (sa, da); - break; - - case COMBINE_A_IN: - Fa = combine_disjoint_in_part (sa, da); - break; - - case COMBINE_A: - Fa = MASK; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - Fb = combine_disjoint_out_part (da, sa); - break; - - case COMBINE_B_IN: - Fb = combine_disjoint_in_part (da, sa); - break; - - case COMBINE_B: - Fb = MASK; - break; - } - m = GENERIC (s, d, 0, Fa, Fb, t, u, v); - n = GENERIC (s, d, G_SHIFT, Fa, Fb, t, u, v); - o = GENERIC (s, d, R_SHIFT, Fa, Fb, t, u, v); - p = GENERIC (s, d, A_SHIFT, Fa, Fb, t, u, v); - s = m | n | o | p; - *(dest + i) = s; - } -} - -static void -combine_disjoint_over_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint32_t a = s >> A_SHIFT; - - if (s != 0x00) - { - uint64_t d = *(dest + i); - a = combine_disjoint_out_part (d >> A_SHIFT, a); - UN16x4_MUL_UN16_ADD_UN16x4 (d, a, s); - - *(dest + i) = d; - } - } -} - -static void -combine_disjoint_in_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_disjoint_in_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_disjoint_out_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_disjoint_out_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_disjoint_atop_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_disjoint_atop_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_disjoint_xor_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_u (dest, src, mask, width, COMBINE_XOR); -} - -static void -combine_conjoint_general_u (uint64_t * dest, - const uint64_t *src, - const uint64_t *mask, - int width, - uint16_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = combine_mask (src, mask, i); - uint64_t d = *(dest + i); - uint64_t m, n, o, p; - uint32_t Fa, Fb, t, u, v; - uint16_t sa = s >> A_SHIFT; - uint16_t da = d >> A_SHIFT; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - Fa = combine_conjoint_out_part (sa, da); - break; - - case COMBINE_A_IN: - Fa = combine_conjoint_in_part (sa, da); - break; - - case COMBINE_A: - Fa = MASK; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - Fb = combine_conjoint_out_part (da, sa); - break; - - case COMBINE_B_IN: - Fb = combine_conjoint_in_part (da, sa); - break; - - case COMBINE_B: - Fb = MASK; - break; - } - - m = GENERIC (s, d, 0, Fa, Fb, t, u, v); - n = GENERIC (s, d, G_SHIFT, Fa, Fb, t, u, v); - o = GENERIC (s, d, R_SHIFT, Fa, Fb, t, u, v); - p = GENERIC (s, d, A_SHIFT, Fa, Fb, t, u, v); - - s = m | n | o | p; - - *(dest + i) = s; - } -} - -static void -combine_conjoint_over_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_OVER); -} - -static void -combine_conjoint_over_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_OVER); -} - -static void -combine_conjoint_in_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_conjoint_in_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_conjoint_out_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_conjoint_out_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_conjoint_atop_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_conjoint_atop_reverse_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_conjoint_xor_u (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_u (dest, src, mask, width, COMBINE_XOR); -} - -/************************************************************************/ -/*********************** Per Channel functions **************************/ -/************************************************************************/ - -static void -combine_clear_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - memset (dest, 0, width * sizeof(uint64_t)); -} - -static void -combine_src_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = *(src + i); - uint64_t m = *(mask + i); - - combine_mask_value_ca (&s, &m); - - *(dest + i) = s; - } -} - -static void -combine_over_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = *(src + i); - uint64_t m = *(mask + i); - uint64_t a; - - combine_mask_ca (&s, &m); - - a = ~m; - if (a) - { - uint64_t d = *(dest + i); - UN16x4_MUL_UN16x4_ADD_UN16x4 (d, a, s); - s = d; - } - - *(dest + i) = s; - } -} - -static void -combine_over_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t d = *(dest + i); - uint64_t a = ~d >> A_SHIFT; - - if (a) - { - uint64_t s = *(src + i); - uint64_t m = *(mask + i); - - UN16x4_MUL_UN16x4 (s, m); - UN16x4_MUL_UN16_ADD_UN16x4 (s, a, d); - - *(dest + i) = s; - } - } -} - -static void -combine_in_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t d = *(dest + i); - uint32_t a = d >> A_SHIFT; - uint64_t s = 0; - - if (a) - { - uint64_t m = *(mask + i); - - s = *(src + i); - combine_mask_value_ca (&s, &m); - - if (a != MASK) - UN16x4_MUL_UN16 (s, a); - } - - *(dest + i) = s; - } -} - -static void -combine_in_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = *(src + i); - uint64_t m = *(mask + i); - uint64_t a; - - combine_mask_alpha_ca (&s, &m); - - a = m; - if (a != ~0) - { - uint64_t d = 0; - - if (a) - { - d = *(dest + i); - UN16x4_MUL_UN16x4 (d, a); - } - - *(dest + i) = d; - } - } -} - -static void -combine_out_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t d = *(dest + i); - uint32_t a = ~d >> A_SHIFT; - uint64_t s = 0; - - if (a) - { - uint64_t m = *(mask + i); - - s = *(src + i); - combine_mask_value_ca (&s, &m); - - if (a != MASK) - UN16x4_MUL_UN16 (s, a); - } - - *(dest + i) = s; - } -} - -static void -combine_out_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = *(src + i); - uint64_t m = *(mask + i); - uint64_t a; - - combine_mask_alpha_ca (&s, &m); - - a = ~m; - if (a != ~0) - { - uint64_t d = 0; - - if (a) - { - d = *(dest + i); - UN16x4_MUL_UN16x4 (d, a); - } - - *(dest + i) = d; - } - } -} - -static void -combine_atop_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t d = *(dest + i); - uint64_t s = *(src + i); - uint64_t m = *(mask + i); - uint64_t ad; - uint32_t as = d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - ad = ~m; - - UN16x4_MUL_UN16x4_ADD_UN16x4_MUL_UN16 (d, ad, s, as); - - *(dest + i) = d; - } -} - -static void -combine_atop_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t d = *(dest + i); - uint64_t s = *(src + i); - uint64_t m = *(mask + i); - uint64_t ad; - uint32_t as = ~d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - ad = m; - - UN16x4_MUL_UN16x4_ADD_UN16x4_MUL_UN16 (d, ad, s, as); - - *(dest + i) = d; - } -} - -static void -combine_xor_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t d = *(dest + i); - uint64_t s = *(src + i); - uint64_t m = *(mask + i); - uint64_t ad; - uint32_t as = ~d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - ad = ~m; - - UN16x4_MUL_UN16x4_ADD_UN16x4_MUL_UN16 (d, ad, s, as); - - *(dest + i) = d; - } -} - -static void -combine_add_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s = *(src + i); - uint64_t m = *(mask + i); - uint64_t d = *(dest + i); - - combine_mask_value_ca (&s, &m); - - UN16x4_ADD_UN16x4 (d, s); - - *(dest + i) = d; - } -} - -static void -combine_saturate_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s, d; - uint32_t sa, sr, sg, sb, da; - uint32_t t, u, v; - uint64_t m, n, o, p; - - d = *(dest + i); - s = *(src + i); - m = *(mask + i); - - combine_mask_ca (&s, &m); - - sa = (m >> A_SHIFT); - sr = (m >> R_SHIFT) & MASK; - sg = (m >> G_SHIFT) & MASK; - sb = m & MASK; - da = ~d >> A_SHIFT; - - if (sb <= da) - m = ADD (s, d, 0, t); - else - m = GENERIC (s, d, 0, (da << G_SHIFT) / sb, MASK, t, u, v); - - if (sg <= da) - n = ADD (s, d, G_SHIFT, t); - else - n = GENERIC (s, d, G_SHIFT, (da << G_SHIFT) / sg, MASK, t, u, v); - - if (sr <= da) - o = ADD (s, d, R_SHIFT, t); - else - o = GENERIC (s, d, R_SHIFT, (da << G_SHIFT) / sr, MASK, t, u, v); - - if (sa <= da) - p = ADD (s, d, A_SHIFT, t); - else - p = GENERIC (s, d, A_SHIFT, (da << G_SHIFT) / sa, MASK, t, u, v); - - *(dest + i) = m | n | o | p; - } -} - -static void -combine_disjoint_general_ca (uint64_t * dest, - const uint64_t *src, - const uint64_t *mask, - int width, - uint16_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s, d; - uint64_t m, n, o, p; - uint64_t Fa, Fb; - uint32_t t, u, v; - uint64_t sa; - uint16_t da; - - s = *(src + i); - m = *(mask + i); - d = *(dest + i); - da = d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - sa = m; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - m = (uint64_t)combine_disjoint_out_part ((uint16_t) (sa >> 0), da); - n = (uint64_t)combine_disjoint_out_part ((uint16_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (uint64_t)combine_disjoint_out_part ((uint16_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (uint64_t)combine_disjoint_out_part ((uint16_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A_IN: - m = (uint64_t)combine_disjoint_in_part ((uint16_t) (sa >> 0), da); - n = (uint64_t)combine_disjoint_in_part ((uint16_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (uint64_t)combine_disjoint_in_part ((uint16_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (uint64_t)combine_disjoint_in_part ((uint16_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A: - Fa = ~0; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - m = (uint64_t)combine_disjoint_out_part (da, (uint16_t) (sa >> 0)); - n = (uint64_t)combine_disjoint_out_part (da, (uint16_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (uint64_t)combine_disjoint_out_part (da, (uint16_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (uint64_t)combine_disjoint_out_part (da, (uint16_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B_IN: - m = (uint64_t)combine_disjoint_in_part (da, (uint16_t) (sa >> 0)); - n = (uint64_t)combine_disjoint_in_part (da, (uint16_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (uint64_t)combine_disjoint_in_part (da, (uint16_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (uint64_t)combine_disjoint_in_part (da, (uint16_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B: - Fb = ~0; - break; - } - m = GENERIC (s, d, 0, GET_COMP (Fa, 0), GET_COMP (Fb, 0), t, u, v); - n = GENERIC (s, d, G_SHIFT, GET_COMP (Fa, G_SHIFT), GET_COMP (Fb, G_SHIFT), t, u, v); - o = GENERIC (s, d, R_SHIFT, GET_COMP (Fa, R_SHIFT), GET_COMP (Fb, R_SHIFT), t, u, v); - p = GENERIC (s, d, A_SHIFT, GET_COMP (Fa, A_SHIFT), GET_COMP (Fb, A_SHIFT), t, u, v); - - s = m | n | o | p; - - *(dest + i) = s; - } -} - -static void -combine_disjoint_over_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_OVER); -} - -static void -combine_disjoint_in_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_disjoint_in_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_disjoint_out_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_disjoint_out_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_disjoint_atop_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_disjoint_atop_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_disjoint_xor_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_disjoint_general_ca (dest, src, mask, width, COMBINE_XOR); -} - -static void -combine_conjoint_general_ca (uint64_t * dest, - const uint64_t *src, - const uint64_t *mask, - int width, - uint16_t combine) -{ - int i; - - for (i = 0; i < width; ++i) - { - uint64_t s, d; - uint64_t m, n, o, p; - uint64_t Fa, Fb; - uint32_t t, u, v; - uint64_t sa; - uint16_t da; - - s = *(src + i); - m = *(mask + i); - d = *(dest + i); - da = d >> A_SHIFT; - - combine_mask_ca (&s, &m); - - sa = m; - - switch (combine & COMBINE_A) - { - default: - Fa = 0; - break; - - case COMBINE_A_OUT: - m = (uint64_t)combine_conjoint_out_part ((uint16_t) (sa >> 0), da); - n = (uint64_t)combine_conjoint_out_part ((uint16_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (uint64_t)combine_conjoint_out_part ((uint16_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (uint64_t)combine_conjoint_out_part ((uint16_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A_IN: - m = (uint64_t)combine_conjoint_in_part ((uint16_t) (sa >> 0), da); - n = (uint64_t)combine_conjoint_in_part ((uint16_t) (sa >> G_SHIFT), da) << G_SHIFT; - o = (uint64_t)combine_conjoint_in_part ((uint16_t) (sa >> R_SHIFT), da) << R_SHIFT; - p = (uint64_t)combine_conjoint_in_part ((uint16_t) (sa >> A_SHIFT), da) << A_SHIFT; - Fa = m | n | o | p; - break; - - case COMBINE_A: - Fa = ~0; - break; - } - - switch (combine & COMBINE_B) - { - default: - Fb = 0; - break; - - case COMBINE_B_OUT: - m = (uint64_t)combine_conjoint_out_part (da, (uint16_t) (sa >> 0)); - n = (uint64_t)combine_conjoint_out_part (da, (uint16_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (uint64_t)combine_conjoint_out_part (da, (uint16_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (uint64_t)combine_conjoint_out_part (da, (uint16_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B_IN: - m = (uint64_t)combine_conjoint_in_part (da, (uint16_t) (sa >> 0)); - n = (uint64_t)combine_conjoint_in_part (da, (uint16_t) (sa >> G_SHIFT)) << G_SHIFT; - o = (uint64_t)combine_conjoint_in_part (da, (uint16_t) (sa >> R_SHIFT)) << R_SHIFT; - p = (uint64_t)combine_conjoint_in_part (da, (uint16_t) (sa >> A_SHIFT)) << A_SHIFT; - Fb = m | n | o | p; - break; - - case COMBINE_B: - Fb = ~0; - break; - } - m = GENERIC (s, d, 0, GET_COMP (Fa, 0), GET_COMP (Fb, 0), t, u, v); - n = GENERIC (s, d, G_SHIFT, GET_COMP (Fa, G_SHIFT), GET_COMP (Fb, G_SHIFT), t, u, v); - o = GENERIC (s, d, R_SHIFT, GET_COMP (Fa, R_SHIFT), GET_COMP (Fb, R_SHIFT), t, u, v); - p = GENERIC (s, d, A_SHIFT, GET_COMP (Fa, A_SHIFT), GET_COMP (Fb, A_SHIFT), t, u, v); - - s = m | n | o | p; - - *(dest + i) = s; - } -} - -static void -combine_conjoint_over_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_OVER); -} - -static void -combine_conjoint_over_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_OVER); -} - -static void -combine_conjoint_in_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_IN); -} - -static void -combine_conjoint_in_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_IN); -} - -static void -combine_conjoint_out_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_OUT); -} - -static void -combine_conjoint_out_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_OUT); -} - -static void -combine_conjoint_atop_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_A_ATOP); -} - -static void -combine_conjoint_atop_reverse_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_B_ATOP); -} - -static void -combine_conjoint_xor_ca (pixman_implementation_t *imp, - pixman_op_t op, - uint64_t * dest, - const uint64_t * src, - const uint64_t * mask, - int width) -{ - combine_conjoint_general_ca (dest, src, mask, width, COMBINE_XOR); -} - -void -_pixman_setup_combiner_functions_64 (pixman_implementation_t *imp) -{ - /* Unified alpha */ - imp->combine_64[PIXMAN_OP_CLEAR] = combine_clear; - imp->combine_64[PIXMAN_OP_SRC] = combine_src_u; - imp->combine_64[PIXMAN_OP_DST] = combine_dst; - imp->combine_64[PIXMAN_OP_OVER] = combine_over_u; - imp->combine_64[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_u; - imp->combine_64[PIXMAN_OP_IN] = combine_in_u; - imp->combine_64[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_u; - imp->combine_64[PIXMAN_OP_OUT] = combine_out_u; - imp->combine_64[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_u; - imp->combine_64[PIXMAN_OP_ATOP] = combine_atop_u; - imp->combine_64[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_u; - imp->combine_64[PIXMAN_OP_XOR] = combine_xor_u; - imp->combine_64[PIXMAN_OP_ADD] = combine_add_u; - imp->combine_64[PIXMAN_OP_SATURATE] = combine_saturate_u; - - /* Disjoint, unified */ - imp->combine_64[PIXMAN_OP_DISJOINT_CLEAR] = combine_clear; - imp->combine_64[PIXMAN_OP_DISJOINT_SRC] = combine_src_u; - imp->combine_64[PIXMAN_OP_DISJOINT_DST] = combine_dst; - imp->combine_64[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_u; - imp->combine_64[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_saturate_u; - imp->combine_64[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_u; - imp->combine_64[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_u; - imp->combine_64[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_u; - imp->combine_64[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_u; - imp->combine_64[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_u; - imp->combine_64[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_u; - imp->combine_64[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_u; - - /* Conjoint, unified */ - imp->combine_64[PIXMAN_OP_CONJOINT_CLEAR] = combine_clear; - imp->combine_64[PIXMAN_OP_CONJOINT_SRC] = combine_src_u; - imp->combine_64[PIXMAN_OP_CONJOINT_DST] = combine_dst; - imp->combine_64[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_u; - imp->combine_64[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_u; - imp->combine_64[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_u; - imp->combine_64[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_u; - imp->combine_64[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_u; - imp->combine_64[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_u; - imp->combine_64[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_u; - imp->combine_64[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_u; - imp->combine_64[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_u; - - imp->combine_64[PIXMAN_OP_MULTIPLY] = combine_multiply_u; - imp->combine_64[PIXMAN_OP_SCREEN] = combine_screen_u; - imp->combine_64[PIXMAN_OP_OVERLAY] = combine_overlay_u; - imp->combine_64[PIXMAN_OP_DARKEN] = combine_darken_u; - imp->combine_64[PIXMAN_OP_LIGHTEN] = combine_lighten_u; - imp->combine_64[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_u; - imp->combine_64[PIXMAN_OP_COLOR_BURN] = combine_color_burn_u; - imp->combine_64[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_u; - imp->combine_64[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_u; - imp->combine_64[PIXMAN_OP_DIFFERENCE] = combine_difference_u; - imp->combine_64[PIXMAN_OP_EXCLUSION] = combine_exclusion_u; - imp->combine_64[PIXMAN_OP_HSL_HUE] = combine_hsl_hue_u; - imp->combine_64[PIXMAN_OP_HSL_SATURATION] = combine_hsl_saturation_u; - imp->combine_64[PIXMAN_OP_HSL_COLOR] = combine_hsl_color_u; - imp->combine_64[PIXMAN_OP_HSL_LUMINOSITY] = combine_hsl_luminosity_u; - - /* Component alpha combiners */ - imp->combine_64_ca[PIXMAN_OP_CLEAR] = combine_clear_ca; - imp->combine_64_ca[PIXMAN_OP_SRC] = combine_src_ca; - /* dest */ - imp->combine_64_ca[PIXMAN_OP_OVER] = combine_over_ca; - imp->combine_64_ca[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_IN] = combine_in_ca; - imp->combine_64_ca[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_OUT] = combine_out_ca; - imp->combine_64_ca[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_ATOP] = combine_atop_ca; - imp->combine_64_ca[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_XOR] = combine_xor_ca; - imp->combine_64_ca[PIXMAN_OP_ADD] = combine_add_ca; - imp->combine_64_ca[PIXMAN_OP_SATURATE] = combine_saturate_ca; - - /* Disjoint CA */ - imp->combine_64_ca[PIXMAN_OP_DISJOINT_CLEAR] = combine_clear_ca; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_SRC] = combine_src_ca; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_DST] = combine_dst; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_ca; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_saturate_ca; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_ca; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_ca; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_ca; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_ca; - - /* Conjoint CA */ - imp->combine_64_ca[PIXMAN_OP_CONJOINT_CLEAR] = combine_clear_ca; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_SRC] = combine_src_ca; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_DST] = combine_dst; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_ca; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_ca; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_ca; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_ca; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_ca; - imp->combine_64_ca[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_ca; - - imp->combine_64_ca[PIXMAN_OP_MULTIPLY] = combine_multiply_ca; - imp->combine_64_ca[PIXMAN_OP_SCREEN] = combine_screen_ca; - imp->combine_64_ca[PIXMAN_OP_OVERLAY] = combine_overlay_ca; - imp->combine_64_ca[PIXMAN_OP_DARKEN] = combine_darken_ca; - imp->combine_64_ca[PIXMAN_OP_LIGHTEN] = combine_lighten_ca; - imp->combine_64_ca[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_ca; - imp->combine_64_ca[PIXMAN_OP_COLOR_BURN] = combine_color_burn_ca; - imp->combine_64_ca[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_ca; - imp->combine_64_ca[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_ca; - imp->combine_64_ca[PIXMAN_OP_DIFFERENCE] = combine_difference_ca; - imp->combine_64_ca[PIXMAN_OP_EXCLUSION] = combine_exclusion_ca; - - /* It is not clear that these make sense, so make them noops for now */ - imp->combine_64_ca[PIXMAN_OP_HSL_HUE] = combine_dst; - imp->combine_64_ca[PIXMAN_OP_HSL_SATURATION] = combine_dst; - imp->combine_64_ca[PIXMAN_OP_HSL_COLOR] = combine_dst; - imp->combine_64_ca[PIXMAN_OP_HSL_LUMINOSITY] = combine_dst; -} - diff --git a/gfx/cairo/libpixman/src/pixman-combine64.h b/gfx/cairo/libpixman/src/pixman-combine64.h deleted file mode 100644 index 00413a85f6..0000000000 --- a/gfx/cairo/libpixman/src/pixman-combine64.h +++ /dev/null @@ -1,230 +0,0 @@ -/* WARNING: This file is generated by combine.pl from combine.inc. - Please edit one of those files rather than this one. */ - -#line 1 "pixman-combine.c.template" - -#define COMPONENT_SIZE 16 -#define MASK 0xffffULL -#define ONE_HALF 0x8000ULL - -#define A_SHIFT 16 * 3 -#define R_SHIFT 16 * 2 -#define G_SHIFT 16 -#define A_MASK 0xffff000000000000ULL -#define R_MASK 0xffff00000000ULL -#define G_MASK 0xffff0000ULL - -#define RB_MASK 0xffff0000ffffULL -#define AG_MASK 0xffff0000ffff0000ULL -#define RB_ONE_HALF 0x800000008000ULL -#define RB_MASK_PLUS_ONE 0x10000000010000ULL - -#define ALPHA_16(x) ((x) >> A_SHIFT) -#define RED_16(x) (((x) >> R_SHIFT) & MASK) -#define GREEN_16(x) (((x) >> G_SHIFT) & MASK) -#define BLUE_16(x) ((x) & MASK) - -/* - * Helper macros. - */ - -#define MUL_UN16(a, b, t) \ - ((t) = (a) * (uint32_t)(b) + ONE_HALF, ((((t) >> G_SHIFT ) + (t) ) >> G_SHIFT )) - -#define DIV_UN16(a, b) \ - (((uint32_t) (a) * MASK + ((b) / 2)) / (b)) - -#define ADD_UN16(x, y, t) \ - ((t) = (x) + (y), \ - (uint64_t) (uint16_t) ((t) | (0 - ((t) >> G_SHIFT)))) - -#define DIV_ONE_UN16(x) \ - (((x) + ONE_HALF + (((x) + ONE_HALF) >> G_SHIFT)) >> G_SHIFT) - -/* - * The methods below use some tricks to be able to do two color - * components at the same time. - */ - -/* - * x_rb = (x_rb * a) / 255 - */ -#define UN16_rb_MUL_UN16(x, a, t) \ - do \ - { \ - t = ((x) & RB_MASK) * (a); \ - t += RB_ONE_HALF; \ - x = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \ - x &= RB_MASK; \ - } while (0) - -/* - * x_rb = min (x_rb + y_rb, 255) - */ -#define UN16_rb_ADD_UN16_rb(x, y, t) \ - do \ - { \ - t = ((x) + (y)); \ - t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); \ - x = (t & RB_MASK); \ - } while (0) - -/* - * x_rb = (x_rb * a_rb) / 255 - */ -#define UN16_rb_MUL_UN16_rb(x, a, t) \ - do \ - { \ - t = (x & MASK) * (a & MASK); \ - t |= (x & R_MASK) * ((a >> R_SHIFT) & MASK); \ - t += RB_ONE_HALF; \ - t = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \ - x = t & RB_MASK; \ - } while (0) - -/* - * x_c = (x_c * a) / 255 - */ -#define UN16x4_MUL_UN16(x, a) \ - do \ - { \ - uint64_t r1__, r2__, t__; \ - \ - r1__ = (x); \ - UN16_rb_MUL_UN16 (r1__, (a), t__); \ - \ - r2__ = (x) >> G_SHIFT; \ - UN16_rb_MUL_UN16 (r2__, (a), t__); \ - \ - (x) = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - * x_c = (x_c * a) / 255 + y_c - */ -#define UN16x4_MUL_UN16_ADD_UN16x4(x, a, y) \ - do \ - { \ - uint64_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x); \ - r2__ = (y) & RB_MASK; \ - UN16_rb_MUL_UN16 (r1__, (a), t__); \ - UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \ - \ - r2__ = (x) >> G_SHIFT; \ - r3__ = ((y) >> G_SHIFT) & RB_MASK; \ - UN16_rb_MUL_UN16 (r2__, (a), t__); \ - UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \ - \ - (x) = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - * x_c = (x_c * a + y_c * b) / 255 - */ -#define UN16x4_MUL_UN16_ADD_UN16x4_MUL_UN16(x, a, y, b) \ - do \ - { \ - uint64_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x); \ - r2__ = (y); \ - UN16_rb_MUL_UN16 (r1__, (a), t__); \ - UN16_rb_MUL_UN16 (r2__, (b), t__); \ - UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \ - \ - r2__ = ((x) >> G_SHIFT); \ - r3__ = ((y) >> G_SHIFT); \ - UN16_rb_MUL_UN16 (r2__, (a), t__); \ - UN16_rb_MUL_UN16 (r3__, (b), t__); \ - UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \ - \ - (x) = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - * x_c = (x_c * a_c) / 255 - */ -#define UN16x4_MUL_UN16x4(x, a) \ - do \ - { \ - uint64_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x); \ - r2__ = (a); \ - UN16_rb_MUL_UN16_rb (r1__, r2__, t__); \ - \ - r2__ = (x) >> G_SHIFT; \ - r3__ = (a) >> G_SHIFT; \ - UN16_rb_MUL_UN16_rb (r2__, r3__, t__); \ - \ - (x) = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - * x_c = (x_c * a_c) / 255 + y_c - */ -#define UN16x4_MUL_UN16x4_ADD_UN16x4(x, a, y) \ - do \ - { \ - uint64_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x); \ - r2__ = (a); \ - UN16_rb_MUL_UN16_rb (r1__, r2__, t__); \ - r2__ = (y) & RB_MASK; \ - UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \ - \ - r2__ = ((x) >> G_SHIFT); \ - r3__ = ((a) >> G_SHIFT); \ - UN16_rb_MUL_UN16_rb (r2__, r3__, t__); \ - r3__ = ((y) >> G_SHIFT) & RB_MASK; \ - UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \ - \ - (x) = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - * x_c = (x_c * a_c + y_c * b) / 255 - */ -#define UN16x4_MUL_UN16x4_ADD_UN16x4_MUL_UN16(x, a, y, b) \ - do \ - { \ - uint64_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x); \ - r2__ = (a); \ - UN16_rb_MUL_UN16_rb (r1__, r2__, t__); \ - r2__ = (y); \ - UN16_rb_MUL_UN16 (r2__, (b), t__); \ - UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \ - \ - r2__ = (x) >> G_SHIFT; \ - r3__ = (a) >> G_SHIFT; \ - UN16_rb_MUL_UN16_rb (r2__, r3__, t__); \ - r3__ = (y) >> G_SHIFT; \ - UN16_rb_MUL_UN16 (r3__, (b), t__); \ - UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \ - \ - x = r1__ | (r2__ << G_SHIFT); \ - } while (0) - -/* - x_c = min(x_c + y_c, 255) -*/ -#define UN16x4_ADD_UN16x4(x, y) \ - do \ - { \ - uint64_t r1__, r2__, r3__, t__; \ - \ - r1__ = (x) & RB_MASK; \ - r2__ = (y) & RB_MASK; \ - UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \ - \ - r2__ = ((x) >> G_SHIFT) & RB_MASK; \ - r3__ = ((y) >> G_SHIFT) & RB_MASK; \ - UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \ - \ - x = r1__ | (r2__ << G_SHIFT); \ - } while (0) diff --git a/gfx/cairo/libpixman/src/pixman-compiler.h b/gfx/cairo/libpixman/src/pixman-compiler.h index fb674c5f08..d852f93798 100644 --- a/gfx/cairo/libpixman/src/pixman-compiler.h +++ b/gfx/cairo/libpixman/src/pixman-compiler.h @@ -18,6 +18,12 @@ # define FUNC ((const char*) ("???")) #endif +#if defined (__GNUC__) +# define unlikely(expr) __builtin_expect ((expr), 0) +#else +# define unlikely(expr) (expr) +#endif + #if defined (__GNUC__) # define MAYBE_UNUSED __attribute__((unused)) #else @@ -106,6 +112,8 @@ /* Sun Studio 8 visibility */ #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) # define PIXMAN_EXPORT __global +#elif defined (_MSC_VER) || defined(__MINGW32__) +# define PIXMAN_EXPORT PIXMAN_API #else # define PIXMAN_EXPORT #endif @@ -131,12 +139,10 @@ # define PIXMAN_GET_THREAD_LOCAL(name) \ (&name) -#elif defined(__MINGW32__) || defined(PIXMAN_USE_XP_DLL_TLS_WORKAROUND) +#elif defined(__MINGW32__) # define _NO_W32_PSEUDO_MODIFIERS # include -#undef IN -#undef OUT # define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \ static volatile int tls_ ## name ## _initialized = 0; \ @@ -193,7 +199,7 @@ # define PIXMAN_GET_THREAD_LOCAL(name) \ (&name) -#elif defined(HAVE_PTHREAD_SETSPECIFIC) +#elif defined(HAVE_PTHREADS) #include diff --git a/gfx/cairo/libpixman/src/pixman-conical-gradient.c b/gfx/cairo/libpixman/src/pixman-conical-gradient.c index 8bb46aecdc..a39e20c4eb 100644 --- a/gfx/cairo/libpixman/src/pixman-conical-gradient.c +++ b/gfx/cairo/libpixman/src/pixman-conical-gradient.c @@ -51,7 +51,10 @@ coordinates_to_parameter (double x, double y, double angle) } static uint32_t * -conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) +conical_get_scanline (pixman_iter_t *iter, + const uint32_t *mask, + int Bpp, + pixman_gradient_walker_write_t write_pixel) { pixman_image_t *image = iter->image; int x = iter->x; @@ -61,7 +64,7 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) gradient_t *gradient = (gradient_t *)image; conical_gradient_t *conical = (conical_gradient_t *)image; - uint32_t *end = buffer + width; + uint32_t *end = buffer + width * (Bpp / 4); pixman_gradient_walker_t walker; pixman_bool_t affine = TRUE; double cx = 1.; @@ -109,11 +112,12 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) { double t = coordinates_to_parameter (rx, ry, conical->angle); - *buffer = _pixman_gradient_walker_pixel ( - &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t)); + write_pixel (&walker, + (pixman_fixed_48_16_t)pixman_double_to_fixed (t), + buffer); } - ++buffer; + buffer += (Bpp / 4); rx += cx; ry += cy; @@ -144,11 +148,12 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) t = coordinates_to_parameter (x, y, conical->angle); - *buffer = _pixman_gradient_walker_pixel ( - &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t)); + write_pixel (&walker, + (pixman_fixed_48_16_t)pixman_double_to_fixed (t), + buffer); } - ++buffer; + buffer += (Bpp / 4); rx += cx; ry += cy; @@ -160,15 +165,18 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) return iter->buffer; } +static uint32_t * +conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) +{ + return conical_get_scanline (iter, mask, 4, + _pixman_gradient_walker_write_narrow); +} + static uint32_t * conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) { - uint32_t *buffer = conical_get_scanline_narrow (iter, NULL); - - pixman_expand_to_float ( - (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); - - return buffer; + return conical_get_scanline (iter, NULL, 16, + _pixman_gradient_walker_write_wide); } void diff --git a/gfx/cairo/libpixman/src/pixman-cpu.c b/gfx/cairo/libpixman/src/pixman-cpu.c deleted file mode 100644 index 30f5fba8a4..0000000000 --- a/gfx/cairo/libpixman/src/pixman-cpu.c +++ /dev/null @@ -1,765 +0,0 @@ -/* - * Copyright © 2000 SuSE, Inc. - * Copyright © 2007 Red Hat, Inc. - * Copyright © 2021 Moonchild Productions - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the names of the authors not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The authors make no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. - * - * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE AUTHORS - * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#if defined(USE_ARM_SIMD) && defined(_MSC_VER) -/* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */ -#include -#endif - -#if defined(__APPLE__) -#include "TargetConditionals.h" -#endif - -#include "pixman-private.h" - -#ifdef USE_VMX - -/* The CPU detection code needs to be in a file not compiled with - * "-maltivec -mabi=altivec", as gcc would try to save vector register - * across function calls causing SIGILL on cpus without Altivec/vmx. - */ -static pixman_bool_t initialized = FALSE; -static volatile pixman_bool_t have_vmx = TRUE; - -#ifdef __APPLE__ -#include - -static pixman_bool_t -pixman_have_vmx (void) -{ - if (!initialized) - { - size_t length = sizeof(have_vmx); - int error = - sysctlbyname ("hw.optional.altivec", &have_vmx, &length, NULL, 0); - - if (error) - have_vmx = FALSE; - - initialized = TRUE; - } - return have_vmx; -} - -#elif defined (__OpenBSD__) -#include -#include -#include - -static pixman_bool_t -pixman_have_vmx (void) -{ - if (!initialized) - { - int mib[2] = { CTL_MACHDEP, CPU_ALTIVEC }; - size_t length = sizeof(have_vmx); - int error = - sysctl (mib, 2, &have_vmx, &length, NULL, 0); - - if (error != 0) - have_vmx = FALSE; - - initialized = TRUE; - } - return have_vmx; -} - -#elif defined (__linux__) -#include -#include -#include -#include -#include -#include -#include - -static pixman_bool_t -pixman_have_vmx (void) -{ - if (!initialized) - { - char fname[64]; - unsigned long buf[64]; - ssize_t count = 0; - pid_t pid; - int fd, i; - - pid = getpid (); - snprintf (fname, sizeof(fname) - 1, "/proc/%d/auxv", pid); - - fd = open (fname, O_RDONLY); - if (fd >= 0) - { - for (i = 0; i <= (count / sizeof(unsigned long)); i += 2) - { - /* Read more if buf is empty... */ - if (i == (count / sizeof(unsigned long))) - { - count = read (fd, buf, sizeof(buf)); - if (count <= 0) - break; - i = 0; - } - - if (buf[i] == AT_HWCAP) - { - have_vmx = !!(buf[i + 1] & PPC_FEATURE_HAS_ALTIVEC); - initialized = TRUE; - break; - } - else if (buf[i] == AT_NULL) - { - break; - } - } - close (fd); - } - } - if (!initialized) - { - /* Something went wrong. Assume 'no' rather than playing - fragile tricks with catching SIGILL. */ - have_vmx = FALSE; - initialized = TRUE; - } - - return have_vmx; -} - -#else /* !__APPLE__ && !__OpenBSD__ && !__linux__ */ -#include -#include - -static jmp_buf jump_env; - -static void -vmx_test (int sig, - siginfo_t *si, - void * unused) -{ - longjmp (jump_env, 1); -} - -static pixman_bool_t -pixman_have_vmx (void) -{ - struct sigaction sa, osa; - int jmp_result; - - if (!initialized) - { - sa.sa_flags = SA_SIGINFO; - sigemptyset (&sa.sa_mask); - sa.sa_sigaction = vmx_test; - sigaction (SIGILL, &sa, &osa); - jmp_result = setjmp (jump_env); - if (jmp_result == 0) - { - asm volatile ( "vor 0, 0, 0" ); - } - sigaction (SIGILL, &osa, NULL); - have_vmx = (jmp_result == 0); - initialized = TRUE; - } - return have_vmx; -} - -#endif /* __APPLE__ */ -#endif /* USE_VMX */ - -#if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON) || defined(USE_ARM_IWMMXT) - -#if defined(_MSC_VER) - -#if defined(USE_ARM_SIMD) -extern int pixman_msvc_try_arm_simd_op (); - -pixman_bool_t -pixman_have_arm_simd (void) -{ - static pixman_bool_t initialized = FALSE; - static pixman_bool_t have_arm_simd = FALSE; - - if (!initialized) - { - __try { - pixman_msvc_try_arm_simd_op (); - have_arm_simd = TRUE; - } __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) { - have_arm_simd = FALSE; - } - initialized = TRUE; - } - - return have_arm_simd; -} - -#endif /* USE_ARM_SIMD */ - -#if defined(USE_ARM_NEON) -extern int pixman_msvc_try_arm_neon_op (); - -pixman_bool_t -pixman_have_arm_neon (void) -{ - static pixman_bool_t initialized = FALSE; - static pixman_bool_t have_arm_neon = FALSE; - - if (!initialized) - { - __try - { - pixman_msvc_try_arm_neon_op (); - have_arm_neon = TRUE; - } - __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) - { - have_arm_neon = FALSE; - } - initialized = TRUE; - } - - return have_arm_neon; -} - -#endif /* USE_ARM_NEON */ - -#elif (defined (__APPLE__) && defined(TARGET_OS_IPHONE)) /* iOS (iPhone/iPad/iPod touch) */ - -/* Detection of ARM NEON on iOS is fairly simple because iOS binaries - * contain separate executable images for each processor architecture. - * So all we have to do is detect the armv7 architecture build. The - * operating system automatically runs the armv7 binary for armv7 devices - * and the armv6 binary for armv6 devices. - */ - -pixman_bool_t -pixman_have_arm_simd (void) -{ -#if defined(USE_ARM_SIMD) - return TRUE; -#else - return FALSE; -#endif -} - -pixman_bool_t -pixman_have_arm_neon (void) -{ -#if defined(USE_ARM_NEON) && defined(__ARM_NEON__) - /* This is an armv7 cpu build */ - return TRUE; -#else - /* This is an armv6 cpu build */ - return FALSE; -#endif -} - -pixman_bool_t -pixman_have_arm_iwmmxt (void) -{ -#if defined(USE_ARM_IWMMXT) - return FALSE; -#else - return FALSE; -#endif -} - -#elif defined (__linux__) /* linux ELF */ - -static pixman_bool_t arm_has_v7 = FALSE; -static pixman_bool_t arm_has_v6 = FALSE; -static pixman_bool_t arm_has_vfp = FALSE; -static pixman_bool_t arm_has_neon = FALSE; -static pixman_bool_t arm_has_iwmmxt = FALSE; -static pixman_bool_t arm_tests_initialized = FALSE; - -#include -#include -#include -#include -#include -#include -#include - -static void -pixman_arm_read_auxv_or_cpu_features () -{ - int fd; - Elf32_auxv_t aux; - - fd = open ("/proc/self/auxv", O_RDONLY); - if (fd >= 0) - { - while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t)) - { - if (aux.a_type == AT_HWCAP) - { - uint32_t hwcap = aux.a_un.a_val; - /* hardcode these values to avoid depending on specific - * versions of the hwcap header, e.g. HWCAP_NEON - */ - arm_has_vfp = (hwcap & 64) != 0; - arm_has_iwmmxt = (hwcap & 512) != 0; - /* this flag is only present on kernel 2.6.29 */ - arm_has_neon = (hwcap & 4096) != 0; - } - else if (aux.a_type == AT_PLATFORM) - { - const char *plat = (const char*) aux.a_un.a_val; - if (strncmp (plat, "v7l", 3) == 0) - { - arm_has_v7 = TRUE; - arm_has_v6 = TRUE; - } - else if (strncmp (plat, "v6l", 3) == 0) - { - arm_has_v6 = TRUE; - } - } - } - close (fd); - } - - arm_tests_initialized = TRUE; -} - -#if defined(USE_ARM_SIMD) -pixman_bool_t -pixman_have_arm_simd (void) -{ - if (!arm_tests_initialized) - pixman_arm_read_auxv_or_cpu_features (); - - return arm_has_v6; -} - -#endif /* USE_ARM_SIMD */ - -#if defined(USE_ARM_NEON) -pixman_bool_t -pixman_have_arm_neon (void) -{ - if (!arm_tests_initialized) - pixman_arm_read_auxv_or_cpu_features (); - - return arm_has_neon; -} - -#endif /* USE_ARM_NEON */ - -#if defined(USE_ARM_IWMMXT) -pixman_bool_t -pixman_have_arm_iwmmxt (void) -{ - if (!arm_tests_initialized) - pixman_arm_read_auxv_or_cpu_features (); - - return arm_has_iwmmxt; -} - -#endif /* USE_ARM_IWMMXT */ - -#else /* !_MSC_VER && !Linux elf */ - -#define pixman_have_arm_simd() FALSE -#define pixman_have_arm_neon() FALSE -#define pixman_have_arm_iwmmxt() FALSE - -#endif - -#endif /* USE_ARM_SIMD || USE_ARM_NEON || USE_ARM_IWMMXT */ - -#if defined(USE_MIPS_DSPR2) - -#if defined (__linux__) /* linux ELF */ - -pixman_bool_t -pixman_have_mips_dspr2 (void) -{ - const char *search_string = "MIPS 74K"; - const char *file_name = "/proc/cpuinfo"; - /* Simple detection of MIPS DSP ASE (revision 2) at runtime for Linux. - * It is based on /proc/cpuinfo, which reveals hardware configuration - * to user-space applications. According to MIPS (early 2010), no similar - * facility is universally available on the MIPS architectures, so it's up - * to individual OSes to provide such. - * - * Only currently available MIPS core that supports DSPr2 is 74K. - */ - - char cpuinfo_line[256]; - - FILE *f = NULL; - - if ((f = fopen (file_name, "r")) == NULL) - return FALSE; - - while (fgets (cpuinfo_line, sizeof (cpuinfo_line), f) != NULL) - { - if (strstr (cpuinfo_line, search_string) != NULL) - { - fclose (f); - return TRUE; - } - } - - fclose (f); - - /* Did not find string in the proc file. */ - return FALSE; -} - -#else /* linux ELF */ - -#define pixman_have_mips_dspr2() FALSE - -#endif /* linux ELF */ - -#endif /* USE_MIPS_DSPR2 */ - -#if defined(USE_X86_MMX) || defined(USE_SSE2) -/* The CPU detection code needs to be in a file not compiled with - * "-mmmx -msse", as gcc would generate CMOV instructions otherwise - * that would lead to SIGILL instructions on old CPUs that don't have - * it. - */ -#if !defined(__amd64__) && !defined(__x86_64__) && !defined(_M_AMD64) - -#ifdef HAVE_GETISAX -#include -#endif - -typedef enum -{ - NO_FEATURES = 0, - MMX = 0x1, - MMX_EXTENSIONS = 0x2, - SSE = 0x6, - SSE2 = 0x8, - CMOV = 0x10 -} cpu_features_t; - - -static unsigned int -detect_cpu_features (void) -{ - unsigned int features = 0; - unsigned int result = 0; - -#ifdef HAVE_GETISAX - if (getisax (&result, 1)) - { - if (result & AV_386_CMOV) - features |= CMOV; - if (result & AV_386_MMX) - features |= MMX; - if (result & AV_386_AMD_MMX) - features |= MMX_EXTENSIONS; - if (result & AV_386_SSE) - features |= SSE; - if (result & AV_386_SSE2) - features |= SSE2; - } -#else - char vendor[13]; -#ifdef _MSC_VER - int vendor0 = 0, vendor1, vendor2; -#endif - vendor[0] = 0; - vendor[12] = 0; - -#ifdef __GNUC__ - /* see p. 118 of amd64 instruction set manual Vol3 */ - /* We need to be careful about the handling of %ebx and - * %esp here. We can't declare either one as clobbered - * since they are special registers (%ebx is the "PIC - * register" holding an offset to global data, %esp the - * stack pointer), so we need to make sure they have their - * original values when we access the output operands. - */ - __asm__ ( - "pushf\n" - "pop %%eax\n" - "mov %%eax, %%ecx\n" - "xor $0x00200000, %%eax\n" - "push %%eax\n" - "popf\n" - "pushf\n" - "pop %%eax\n" - "mov $0x0, %%edx\n" - "xor %%ecx, %%eax\n" - "jz 1f\n" - - "mov $0x00000000, %%eax\n" - "push %%ebx\n" - "cpuid\n" - "mov %%ebx, %%eax\n" - "pop %%ebx\n" - "mov %%eax, %1\n" - "mov %%edx, %2\n" - "mov %%ecx, %3\n" - "mov $0x00000001, %%eax\n" - "push %%ebx\n" - "cpuid\n" - "pop %%ebx\n" - "1:\n" - "mov %%edx, %0\n" - : "=r" (result), - "=m" (vendor[0]), - "=m" (vendor[4]), - "=m" (vendor[8]) - : - : "%eax", "%ecx", "%edx" - ); - -#elif defined (_MSC_VER) - - _asm { - pushfd - pop eax - mov ecx, eax - xor eax, 00200000h - push eax - popfd - pushfd - pop eax - mov edx, 0 - xor eax, ecx - jz nocpuid - - mov eax, 0 - push ebx - cpuid - mov eax, ebx - pop ebx - mov vendor0, eax - mov vendor1, edx - mov vendor2, ecx - mov eax, 1 - push ebx - cpuid - pop ebx - nocpuid: - mov result, edx - } - memmove (vendor + 0, &vendor0, 4); - memmove (vendor + 4, &vendor1, 4); - memmove (vendor + 8, &vendor2, 4); - -#else -# error unsupported compiler -#endif - - features = 0; - if (result) - { - /* result now contains the standard feature bits */ - if (result & (1 << 15)) - features |= CMOV; - if (result & (1 << 23)) - features |= MMX; - if (result & (1 << 25)) - features |= SSE; - if (result & (1 << 26)) - features |= SSE2; - if ((features & MMX) && !(features & SSE) && - (strcmp (vendor, "AuthenticAMD") == 0 || - strcmp (vendor, "Geode by NSC") == 0)) - { - /* check for AMD MMX extensions */ -#ifdef __GNUC__ - __asm__ ( - " push %%ebx\n" - " mov $0x80000000, %%eax\n" - " cpuid\n" - " xor %%edx, %%edx\n" - " cmp $0x1, %%eax\n" - " jge 2f\n" - " mov $0x80000001, %%eax\n" - " cpuid\n" - "2:\n" - " pop %%ebx\n" - " mov %%edx, %0\n" - : "=r" (result) - : - : "%eax", "%ecx", "%edx" - ); -#elif defined _MSC_VER - _asm { - push ebx - mov eax, 80000000h - cpuid - xor edx, edx - cmp eax, 1 - jge notamd - mov eax, 80000001h - cpuid - notamd: - pop ebx - mov result, edx - } -#endif - if (result & (1 << 22)) - features |= MMX_EXTENSIONS; - } - } -#endif /* HAVE_GETISAX */ - - return features; -} - -#ifdef USE_X86_MMX -static pixman_bool_t -pixman_have_mmx (void) -{ - static pixman_bool_t initialized = FALSE; - static pixman_bool_t mmx_present; - - if (!initialized) - { - unsigned int features = detect_cpu_features (); - mmx_present = (features & (MMX | MMX_EXTENSIONS)) == (MMX | MMX_EXTENSIONS); - initialized = TRUE; - } - - return mmx_present; -} -#endif - -#ifdef USE_SSE2 -static pixman_bool_t -pixman_have_sse2 (void) -{ - static pixman_bool_t initialized = FALSE; - static pixman_bool_t sse2_present; - - if (!initialized) - { - unsigned int features = detect_cpu_features (); - sse2_present = (features & (MMX | MMX_EXTENSIONS | SSE | SSE2)) == (MMX | MMX_EXTENSIONS | SSE | SSE2); - initialized = TRUE; - } - - return sse2_present; -} - -#endif - -#else /* __amd64__ */ -#ifdef USE_X86_MMX -#define pixman_have_mmx() TRUE -#endif -#ifdef USE_SSE2 -#define pixman_have_sse2() TRUE -#endif -#endif /* __amd64__ */ -#endif - -static pixman_bool_t -disabled (const char *name) -{ - const char *env; - - if ((env = getenv ("PIXMAN_DISABLE"))) - { - do - { - const char *end; - int len; - - if ((end = strchr (env, ' '))) - len = end - env; - else - len = strlen (env); - - if (strlen (name) == len && strncmp (name, env, len) == 0) - { - printf ("pixman: Disabled %s implementation\n", name); - return TRUE; - } - - env += len; - } - while (*env++); - } - - return FALSE; -} - -pixman_implementation_t * -_pixman_choose_implementation (void) -{ - pixman_implementation_t *imp; - - imp = _pixman_implementation_create_general(); - - if (!disabled ("fast")) - imp = _pixman_implementation_create_fast_path (imp); - -#ifdef USE_X86_MMX - if (!disabled ("mmx") && pixman_have_mmx ()) - imp = _pixman_implementation_create_mmx (imp); -#endif - -#ifdef USE_SSE2 - if (!disabled ("sse2") && pixman_have_sse2 ()) - imp = _pixman_implementation_create_sse2 (imp); -#endif - -#ifdef USE_ARM_SIMD - if (!disabled ("arm-simd") && pixman_have_arm_simd ()) - imp = _pixman_implementation_create_arm_simd (imp); -#endif - -#ifdef USE_ARM_IWMMXT - if (!disabled ("arm-iwmmxt") && pixman_have_arm_iwmmxt ()) - imp = _pixman_implementation_create_mmx (imp); -#endif - -#ifdef USE_ARM_NEON - if (!disabled ("arm-neon") && pixman_have_arm_neon ()) - imp = _pixman_implementation_create_arm_neon (imp); -#endif - -#ifdef USE_MIPS_DSPR2 - if (!disabled ("mips-dspr2") && pixman_have_mips_dspr2 ()) - imp = _pixman_implementation_create_mips_dspr2 (imp); -#endif - -#ifdef USE_VMX - if (!disabled ("vmx") && pixman_have_vmx ()) - imp = _pixman_implementation_create_vmx (imp); -#endif - - imp = _pixman_implementation_create_noop (imp); - - return imp; -} - diff --git a/gfx/cairo/libpixman/src/pixman-dither.h b/gfx/cairo/libpixman/src/pixman-dither.h deleted file mode 100644 index ead9f38d8c..0000000000 --- a/gfx/cairo/libpixman/src/pixman-dither.h +++ /dev/null @@ -1,51 +0,0 @@ -#define R16_BITS 5 -#define G16_BITS 6 -#define B16_BITS 5 - -#define R16_SHIFT (B16_BITS + G16_BITS) -#define G16_SHIFT (B16_BITS) -#define B16_SHIFT 0 - -#define MASK 0xff -#define ONE_HALF 0x80 - -#define A_SHIFT 8 * 3 -#define R_SHIFT 8 * 2 -#define G_SHIFT 8 -#define A_MASK 0xff000000 -#define R_MASK 0xff0000 -#define G_MASK 0xff00 - -#define RB_MASK 0xff00ff -#define AG_MASK 0xff00ff00 -#define RB_ONE_HALF 0x800080 -#define RB_MASK_PLUS_ONE 0x10000100 - -#define ALPHA_8(x) ((x) >> A_SHIFT) -#define RED_8(x) (((x) >> R_SHIFT) & MASK) -#define GREEN_8(x) (((x) >> G_SHIFT) & MASK) -#define BLUE_8(x) ((x) & MASK) - -// This uses the same dithering technique that Skia does. -// It is essentially preturbing the lower bit based on the -// high bit -static inline uint16_t dither_32_to_16(uint32_t c) -{ - uint8_t b = BLUE_8(c); - uint8_t g = GREEN_8(c); - uint8_t r = RED_8(c); - r = ((r << 1) - ((r >> (8 - R16_BITS) << (8 - R16_BITS)) | (r >> R16_BITS))) >> (8 - R16_BITS); - g = ((g << 1) - ((g >> (8 - G16_BITS) << (8 - G16_BITS)) | (g >> G16_BITS))) >> (8 - G16_BITS); - b = ((b << 1) - ((b >> (8 - B16_BITS) << (8 - B16_BITS)) | (b >> B16_BITS))) >> (8 - B16_BITS); - return ((r << R16_SHIFT) | (g << G16_SHIFT) | (b << B16_SHIFT)); -} - -static inline uint16_t dither_8888_to_0565(uint32_t color, pixman_bool_t toggle) -{ - // alternate between a preturbed truncation and a regular truncation - if (toggle) { - return dither_32_to_16(color); - } else { - return convert_8888_to_0565(color); - } -} diff --git a/gfx/cairo/libpixman/src/pixman-edge-imp.h b/gfx/cairo/libpixman/src/pixman-edge-imp.h index a47098a896..a4698eddb2 100644 --- a/gfx/cairo/libpixman/src/pixman-edge-imp.h +++ b/gfx/cairo/libpixman/src/pixman-edge-imp.h @@ -55,9 +55,8 @@ RASTERIZE_EDGES (pixman_image_t *image, * * (The AA case does a similar adjustment in RENDER_SAMPLES_X) */ - /* we cast to unsigned to get defined behaviour for overflow */ - lx = (unsigned)lx + X_FRAC_FIRST(1) - pixman_fixed_e; - rx = (unsigned)rx + X_FRAC_FIRST(1) - pixman_fixed_e; + lx += X_FRAC_FIRST(1) - pixman_fixed_e; + rx += X_FRAC_FIRST(1) - pixman_fixed_e; #endif /* clip X */ if (lx < 0) diff --git a/gfx/cairo/libpixman/src/pixman-fast-path.c b/gfx/cairo/libpixman/src/pixman-fast-path.c index 9b22d7b464..4b7a6f897f 100644 --- a/gfx/cairo/libpixman/src/pixman-fast-path.c +++ b/gfx/cairo/libpixman/src/pixman-fast-path.c @@ -908,7 +908,7 @@ fast_composite_add_n_8_8 (pixman_implementation_t *imp, #define CREATE_BITMASK(n) (0x80000000 >> (n)) #define UPDATE_BITMASK(n) ((n) >> 1) #else -#define CREATE_BITMASK(n) (1 << (n)) +#define CREATE_BITMASK(n) (1U << (n)) #define UPDATE_BITMASK(n) ((n) << 1) #endif @@ -1203,228 +1203,6 @@ FAST_NEAREST (8888_565_none, 8888, 0565, uint32_t, uint16_t, OVER, NONE) FAST_NEAREST (8888_565_pad, 8888, 0565, uint32_t, uint16_t, OVER, PAD) FAST_NEAREST (8888_565_normal, 8888, 0565, uint32_t, uint16_t, OVER, NORMAL) -static force_inline void -scaled_bilinear_scanline_8888_565_OVER (uint16_t * dst, - const uint32_t * mask, - const uint32_t * src_top, - const uint32_t * src_bottom, - int32_t w, - int wt, - int wb, - pixman_fixed_t vx, - pixman_fixed_t unit_x, - pixman_fixed_t max_vx, - pixman_bool_t zero_src) -{ - while ((w -= 1) >= 0) - { - uint32_t tl = src_top [pixman_fixed_to_int (vx)]; - uint32_t tr = src_top [pixman_fixed_to_int (vx) + 1]; - uint32_t bl = src_bottom [pixman_fixed_to_int (vx)]; - uint32_t br = src_bottom [pixman_fixed_to_int (vx) + 1]; - uint32_t src, result; - uint16_t d; - d = *dst; - src = bilinear_interpolation (tl, tr, - bl, br, - pixman_fixed_to_bilinear_weight(vx), - wb); - vx += unit_x; - result = over (src, convert_0565_to_0888 (d)); - *dst++ = convert_8888_to_0565 (result); - } -} - -static force_inline void -scaled_bilinear_scanline_8888_8888_OVER (uint32_t * dst, - const uint32_t * mask, - const uint32_t * src_top, - const uint32_t * src_bottom, - int32_t w, - int wt, - int wb, - pixman_fixed_t vx, - pixman_fixed_t unit_x, - pixman_fixed_t max_vx, - pixman_bool_t zero_src) -{ - while ((w -= 1) >= 0) - { - uint32_t tl = src_top [pixman_fixed_to_int (vx)]; - uint32_t tr = src_top [pixman_fixed_to_int (vx) + 1]; - uint32_t bl = src_bottom [pixman_fixed_to_int (vx)]; - uint32_t br = src_bottom [pixman_fixed_to_int (vx) + 1]; - uint32_t src; - uint32_t d; - uint32_t result; - d = *dst; - src = bilinear_interpolation (tl, tr, - bl, br, - pixman_fixed_to_bilinear_weight(vx), - wb); - vx += unit_x; - *dst++ = over (src, d); - } -} - -#ifndef LOWER_QUALITY_INTERPOLATION - -static force_inline void -scaled_bilinear_scanline_565_565_SRC (uint16_t * dst, - const uint32_t * mask, - const uint16_t * src_top, - const uint16_t * src_bottom, - int32_t w, - int wt, - int wb, - pixman_fixed_t vx, - pixman_fixed_t unit_x, - pixman_fixed_t max_vx, - pixman_bool_t zero_src) -{ - while ((w -= 1) >= 0) - { - uint16_t tl = src_top [pixman_fixed_to_int (vx)]; - uint16_t tr = src_top [pixman_fixed_to_int (vx) + 1]; - uint16_t bl = src_bottom [pixman_fixed_to_int (vx)]; - uint16_t br = src_bottom [pixman_fixed_to_int (vx) + 1]; - uint32_t d; - d = bilinear_interpolation(convert_0565_to_8888 (tl), - convert_0565_to_8888 (tr), - convert_0565_to_8888 (bl), - convert_0565_to_8888 (br), - pixman_fixed_to_bilinear_weight (vx), - wb); - vx += unit_x; - *dst++ = convert_8888_to_0565 (d); - } -} - -#else - -/* This is a clever low resolution bilinear interpolation inspired by the code - in Skia */ - -/* This takes the green component from the 565 representation and moves it: - 00000000 00000000 rrrrrggg gggbbbbb - - 00000ggg ggg00000 rrrrr000 000bbbbb - - This gives us 5 extra bits of space before each component to let us do - SWAR style optimizations -*/ - -#define GREEN_MASK (((1 << 6) - 1) << 5) - -static inline uint32_t -expand_rgb_565 (uint16_t c) { - return ((c & GREEN_MASK) << 16) | (c & ~GREEN_MASK); -} - -static inline uint16_t -compact_rgb_565 (uint32_t c) { - return ((c >> 16) & GREEN_MASK) | (c & ~GREEN_MASK); -} - -static inline uint16_t -bilinear_interpolation_565(uint16_t tl, uint16_t tr, - uint16_t bl, uint16_t br, - int x, int y) -{ - int xy; - uint32_t a00 = expand_rgb_565 (tl); - uint32_t a01 = expand_rgb_565 (tr); - uint32_t a10 = expand_rgb_565 (bl); - uint32_t a11 = expand_rgb_565 (br); - - xy = (x * y) >> 3; - return compact_rgb_565 ((a00 * (32 - 2*y - 2*x + xy) + - a01 * (2*x - xy) + - a10 * (2*y - xy) + - a11 * xy) >> 5); -} - -static force_inline void -scaled_bilinear_scanline_565_565_SRC (uint16_t * dst, - const uint32_t * mask, - const uint16_t * src_top, - const uint16_t * src_bottom, - int32_t w, - int wt, - int wb, - pixman_fixed_t vx, - pixman_fixed_t unit_x, - pixman_fixed_t max_vx, - pixman_bool_t zero_src) -{ - while ((w -= 1) >= 0) - { - uint16_t tl = src_top [pixman_fixed_to_int (vx)]; - uint16_t tr = src_top [pixman_fixed_to_int (vx) + 1]; - uint16_t bl = src_bottom [pixman_fixed_to_int (vx)]; - uint16_t br = src_bottom [pixman_fixed_to_int (vx) + 1]; - - uint16_t d = bilinear_interpolation_565 (tl, tr, bl, br, - pixman_fixed_to_bilinear_weight(vx), - wb); - vx += unit_x; - *dst++ = d; - } -} - -#endif - -FAST_BILINEAR_MAINLOOP_COMMON (565_565_cover_SRC, - scaled_bilinear_scanline_565_565_SRC, NULL, - uint16_t, uint32_t, uint16_t, - COVER, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (565_565_pad_SRC, - scaled_bilinear_scanline_565_565_SRC, NULL, - uint16_t, uint32_t, uint16_t, - PAD, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (565_565_none_SRC, - scaled_bilinear_scanline_565_565_SRC, NULL, - uint16_t, uint32_t, uint16_t, - NONE, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (565_565_normal_SRC, - scaled_bilinear_scanline_565_565_SRC, NULL, - uint16_t, uint32_t, uint16_t, - NORMAL, FLAG_NONE) - -FAST_BILINEAR_MAINLOOP_COMMON (8888_565_cover_OVER, - scaled_bilinear_scanline_8888_565_OVER, NULL, - uint32_t, uint32_t, uint16_t, - COVER, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (8888_565_pad_OVER, - scaled_bilinear_scanline_8888_565_OVER, NULL, - uint32_t, uint32_t, uint16_t, - PAD, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (8888_565_none_OVER, - scaled_bilinear_scanline_8888_565_OVER, NULL, - uint32_t, uint32_t, uint16_t, - NONE, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (8888_565_normal_OVER, - scaled_bilinear_scanline_8888_565_OVER, NULL, - uint32_t, uint32_t, uint16_t, - NORMAL, FLAG_NONE) - -FAST_BILINEAR_MAINLOOP_COMMON (8888_8888_cover_OVER, - scaled_bilinear_scanline_8888_8888_OVER, NULL, - uint32_t, uint32_t, uint32_t, - COVER, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (8888_8888_pad_OVER, - scaled_bilinear_scanline_8888_8888_OVER, NULL, - uint32_t, uint32_t, uint32_t, - PAD, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (8888_8888_none_OVER, - scaled_bilinear_scanline_8888_8888_OVER, NULL, - uint32_t, uint32_t, uint32_t, - NONE, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (8888_8888_normal_OVER, - scaled_bilinear_scanline_8888_8888_OVER, NULL, - uint32_t, uint32_t, uint32_t, - NORMAL, FLAG_NONE) - #define REPEAT_MIN_WIDTH 32 static void @@ -2193,10 +1971,6 @@ static const pixman_fast_path_t c_fast_paths[] = fast_composite_tiled_repeat }, - SIMPLE_BILINEAR_FAST_PATH (SRC, r5g6b5, r5g6b5, 565_565), - SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, r5g6b5, 8888_565), - SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, 8888_8888), - { PIXMAN_OP_NONE }, }; @@ -2489,93 +2263,1024 @@ fast_write_back_r5g6b5 (pixman_iter_t *iter) typedef struct { - pixman_format_code_t format; - pixman_iter_get_scanline_t get_scanline; - pixman_iter_write_back_t write_back; -} fetcher_info_t; + int y; + uint64_t * buffer; +} line_t; -static const fetcher_info_t fetchers[] = +typedef struct { - { PIXMAN_r5g6b5, fast_fetch_r5g6b5, fast_write_back_r5g6b5 }, - { PIXMAN_null } -}; + line_t lines[2]; + pixman_fixed_t y; + pixman_fixed_t x; + uint64_t data[1]; +} bilinear_info_t; -static pixman_bool_t -fast_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) +static void +fetch_horizontal (bits_image_t *image, line_t *line, + int y, pixman_fixed_t x, pixman_fixed_t ux, int n) { - pixman_image_t *image = iter->image; + uint32_t *bits = image->bits + y * image->rowstride; + int i; -#define FLAGS \ + for (i = 0; i < n; ++i) + { + int x0 = pixman_fixed_to_int (x); + int x1 = x0 + 1; + int32_t dist_x; + + uint32_t left = *(bits + x0); + uint32_t right = *(bits + x1); + + dist_x = pixman_fixed_to_bilinear_weight (x); + dist_x <<= (8 - BILINEAR_INTERPOLATION_BITS); + +#if SIZEOF_LONG <= 4 + { + uint32_t lag, rag, ag; + uint32_t lrb, rrb, rb; + + lag = (left & 0xff00ff00) >> 8; + rag = (right & 0xff00ff00) >> 8; + ag = (lag << 8) + dist_x * (rag - lag); + + lrb = (left & 0x00ff00ff); + rrb = (right & 0x00ff00ff); + rb = (lrb << 8) + dist_x * (rrb - lrb); + + *((uint32_t *)(line->buffer + i)) = ag; + *((uint32_t *)(line->buffer + i) + 1) = rb; + } +#else + { + uint64_t lagrb, ragrb; + uint32_t lag, rag; + uint32_t lrb, rrb; + + lag = (left & 0xff00ff00); + lrb = (left & 0x00ff00ff); + rag = (right & 0xff00ff00); + rrb = (right & 0x00ff00ff); + lagrb = (((uint64_t)lag) << 24) | lrb; + ragrb = (((uint64_t)rag) << 24) | rrb; + + line->buffer[i] = (lagrb << 8) + dist_x * (ragrb - lagrb); + } +#endif + + x += ux; + } + + line->y = y; +} + +static uint32_t * +fast_fetch_bilinear_cover (pixman_iter_t *iter, const uint32_t *mask) +{ + pixman_fixed_t fx, ux; + bilinear_info_t *info = iter->data; + line_t *line0, *line1; + int y0, y1; + int32_t dist_y; + int i; + + COMPILE_TIME_ASSERT (BILINEAR_INTERPOLATION_BITS < 8); + + fx = info->x; + ux = iter->image->common.transform->matrix[0][0]; + + y0 = pixman_fixed_to_int (info->y); + y1 = y0 + 1; + dist_y = pixman_fixed_to_bilinear_weight (info->y); + dist_y <<= (8 - BILINEAR_INTERPOLATION_BITS); + + line0 = &info->lines[y0 & 0x01]; + line1 = &info->lines[y1 & 0x01]; + + if (line0->y != y0) + { + fetch_horizontal ( + &iter->image->bits, line0, y0, fx, ux, iter->width); + } + + if (line1->y != y1) + { + fetch_horizontal ( + &iter->image->bits, line1, y1, fx, ux, iter->width); + } + + for (i = 0; i < iter->width; ++i) + { +#if SIZEOF_LONG <= 4 + uint32_t ta, tr, tg, tb; + uint32_t ba, br, bg, bb; + uint32_t tag, trb; + uint32_t bag, brb; + uint32_t a, r, g, b; + + tag = *((uint32_t *)(line0->buffer + i)); + trb = *((uint32_t *)(line0->buffer + i) + 1); + bag = *((uint32_t *)(line1->buffer + i)); + brb = *((uint32_t *)(line1->buffer + i) + 1); + + ta = tag >> 16; + ba = bag >> 16; + a = (ta << 8) + dist_y * (ba - ta); + + tr = trb >> 16; + br = brb >> 16; + r = (tr << 8) + dist_y * (br - tr); + + tg = tag & 0xffff; + bg = bag & 0xffff; + g = (tg << 8) + dist_y * (bg - tg); + + tb = trb & 0xffff; + bb = brb & 0xffff; + b = (tb << 8) + dist_y * (bb - tb); + + a = (a << 8) & 0xff000000; + r = (r << 0) & 0x00ff0000; + g = (g >> 8) & 0x0000ff00; + b = (b >> 16) & 0x000000ff; +#else + uint64_t top = line0->buffer[i]; + uint64_t bot = line1->buffer[i]; + uint64_t tar = (top & 0xffff0000ffff0000ULL) >> 16; + uint64_t bar = (bot & 0xffff0000ffff0000ULL) >> 16; + uint64_t tgb = (top & 0x0000ffff0000ffffULL); + uint64_t bgb = (bot & 0x0000ffff0000ffffULL); + uint64_t ar, gb; + uint32_t a, r, g, b; + + ar = (tar << 8) + dist_y * (bar - tar); + gb = (tgb << 8) + dist_y * (bgb - tgb); + + a = ((ar >> 24) & 0xff000000); + r = ((ar >> 0) & 0x00ff0000); + g = ((gb >> 40) & 0x0000ff00); + b = ((gb >> 16) & 0x000000ff); +#endif + + iter->buffer[i] = a | r | g | b; + } + + info->y += iter->image->common.transform->matrix[1][1]; + + return iter->buffer; +} + +static void +bilinear_cover_iter_fini (pixman_iter_t *iter) +{ + free (iter->data); +} + +static void +fast_bilinear_cover_iter_init (pixman_iter_t *iter, const pixman_iter_info_t *iter_info) +{ + int width = iter->width; + bilinear_info_t *info; + pixman_vector_t v; + + /* Reference point is the center of the pixel */ + v.vector[0] = pixman_int_to_fixed (iter->x) + pixman_fixed_1 / 2; + v.vector[1] = pixman_int_to_fixed (iter->y) + pixman_fixed_1 / 2; + v.vector[2] = pixman_fixed_1; + + if (!pixman_transform_point_3d (iter->image->common.transform, &v)) + goto fail; + + info = malloc (sizeof (*info) + (2 * width - 1) * sizeof (uint64_t)); + if (!info) + goto fail; + + info->x = v.vector[0] - pixman_fixed_1 / 2; + info->y = v.vector[1] - pixman_fixed_1 / 2; + + /* It is safe to set the y coordinates to -1 initially + * because COVER_CLIP_BILINEAR ensures that we will only + * be asked to fetch lines in the [0, height) interval + */ + info->lines[0].y = -1; + info->lines[0].buffer = &(info->data[0]); + info->lines[1].y = -1; + info->lines[1].buffer = &(info->data[width]); + + iter->get_scanline = fast_fetch_bilinear_cover; + iter->fini = bilinear_cover_iter_fini; + + iter->data = info; + return; + +fail: + /* Something went wrong, either a bad matrix or OOM; in such cases, + * we don't guarantee any particular rendering. + */ + _pixman_log_error ( + FUNC, "Allocation failure or bad matrix, skipping rendering\n"); + + iter->get_scanline = _pixman_iter_get_scanline_noop; + iter->fini = NULL; +} + +static uint32_t * +bits_image_fetch_bilinear_no_repeat_8888 (pixman_iter_t *iter, + const uint32_t *mask) +{ + + pixman_image_t * ima = iter->image; + int offset = iter->x; + int line = iter->y++; + int width = iter->width; + uint32_t * buffer = iter->buffer; + + bits_image_t *bits = &ima->bits; + pixman_fixed_t x_top, x_bottom, x; + pixman_fixed_t ux_top, ux_bottom, ux; + pixman_vector_t v; + uint32_t top_mask, bottom_mask; + uint32_t *top_row; + uint32_t *bottom_row; + uint32_t *end; + uint32_t zero[2] = { 0, 0 }; + uint32_t one = 1; + int y, y1, y2; + int disty; + int mask_inc; + int w; + + /* reference point is the center of the pixel */ + v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; + v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; + v.vector[2] = pixman_fixed_1; + + if (!pixman_transform_point_3d (bits->common.transform, &v)) + return iter->buffer; + + ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0]; + x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2; + + y = v.vector[1] - pixman_fixed_1/2; + disty = pixman_fixed_to_bilinear_weight (y); + + /* Load the pointers to the first and second lines from the source + * image that bilinear code must read. + * + * The main trick in this code is about the check if any line are + * outside of the image; + * + * When I realize that a line (any one) is outside, I change + * the pointer to a dummy area with zeros. Once I change this, I + * must be sure the pointer will not change, so I set the + * variables to each pointer increments inside the loop. + */ + y1 = pixman_fixed_to_int (y); + y2 = y1 + 1; + + if (y1 < 0 || y1 >= bits->height) + { + top_row = zero; + x_top = 0; + ux_top = 0; + } + else + { + top_row = bits->bits + y1 * bits->rowstride; + x_top = x; + ux_top = ux; + } + + if (y2 < 0 || y2 >= bits->height) + { + bottom_row = zero; + x_bottom = 0; + ux_bottom = 0; + } + else + { + bottom_row = bits->bits + y2 * bits->rowstride; + x_bottom = x; + ux_bottom = ux; + } + + /* Instead of checking whether the operation uses the mast in + * each loop iteration, verify this only once and prepare the + * variables to make the code smaller inside the loop. + */ + if (!mask) + { + mask_inc = 0; + mask = &one; + } + else + { + /* If have a mask, prepare the variables to check it */ + mask_inc = 1; + } + + /* If both are zero, then the whole thing is zero */ + if (top_row == zero && bottom_row == zero) + { + memset (buffer, 0, width * sizeof (uint32_t)); + return iter->buffer; + } + else if (bits->format == PIXMAN_x8r8g8b8) + { + if (top_row == zero) + { + top_mask = 0; + bottom_mask = 0xff000000; + } + else if (bottom_row == zero) + { + top_mask = 0xff000000; + bottom_mask = 0; + } + else + { + top_mask = 0xff000000; + bottom_mask = 0xff000000; + } + } + else + { + top_mask = 0; + bottom_mask = 0; + } + + end = buffer + width; + + /* Zero fill to the left of the image */ + while (buffer < end && x < pixman_fixed_minus_1) + { + *buffer++ = 0; + x += ux; + x_top += ux_top; + x_bottom += ux_bottom; + mask += mask_inc; + } + + /* Left edge + */ + while (buffer < end && x < 0) + { + uint32_t tr, br; + int32_t distx; + + tr = top_row[pixman_fixed_to_int (x_top) + 1] | top_mask; + br = bottom_row[pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; + + distx = pixman_fixed_to_bilinear_weight (x); + + *buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty); + + x += ux; + x_top += ux_top; + x_bottom += ux_bottom; + mask += mask_inc; + } + + /* Main part */ + w = pixman_int_to_fixed (bits->width - 1); + + while (buffer < end && x < w) + { + if (*mask) + { + uint32_t tl, tr, bl, br; + int32_t distx; + + tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; + tr = top_row [pixman_fixed_to_int (x_top) + 1] | top_mask; + bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; + br = bottom_row [pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; + + distx = pixman_fixed_to_bilinear_weight (x); + + *buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty); + } + + buffer++; + x += ux; + x_top += ux_top; + x_bottom += ux_bottom; + mask += mask_inc; + } + + /* Right Edge */ + w = pixman_int_to_fixed (bits->width); + while (buffer < end && x < w) + { + if (*mask) + { + uint32_t tl, bl; + int32_t distx; + + tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; + bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; + + distx = pixman_fixed_to_bilinear_weight (x); + + *buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty); + } + + buffer++; + x += ux; + x_top += ux_top; + x_bottom += ux_bottom; + mask += mask_inc; + } + + /* Zero fill to the left of the image */ + while (buffer < end) + *buffer++ = 0; + + return iter->buffer; +} + +typedef uint32_t (* convert_pixel_t) (const uint8_t *row, int x); + +static force_inline void +bits_image_fetch_separable_convolution_affine (pixman_image_t * image, + int offset, + int line, + int width, + uint32_t * buffer, + const uint32_t * mask, + + convert_pixel_t convert_pixel, + pixman_format_code_t format, + pixman_repeat_t repeat_mode) +{ + bits_image_t *bits = &image->bits; + pixman_fixed_t *params = image->common.filter_params; + int cwidth = pixman_fixed_to_int (params[0]); + int cheight = pixman_fixed_to_int (params[1]); + int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; + int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; + int x_phase_bits = pixman_fixed_to_int (params[2]); + int y_phase_bits = pixman_fixed_to_int (params[3]); + int x_phase_shift = 16 - x_phase_bits; + int y_phase_shift = 16 - y_phase_bits; + pixman_fixed_t vx, vy; + pixman_fixed_t ux, uy; + pixman_vector_t v; + int k; + + /* reference point is the center of the pixel */ + v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; + v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; + v.vector[2] = pixman_fixed_1; + + if (!pixman_transform_point_3d (image->common.transform, &v)) + return; + + ux = image->common.transform->matrix[0][0]; + uy = image->common.transform->matrix[1][0]; + + vx = v.vector[0]; + vy = v.vector[1]; + + for (k = 0; k < width; ++k) + { + pixman_fixed_t *y_params; + int satot, srtot, sgtot, sbtot; + pixman_fixed_t x, y; + int32_t x1, x2, y1, y2; + int32_t px, py; + int i, j; + + if (mask && !mask[k]) + goto next; + + /* Round x and y to the middle of the closest phase before continuing. This + * ensures that the convolution matrix is aligned right, since it was + * positioned relative to a particular phase (and not relative to whatever + * exact fraction we happen to get here). + */ + x = ((vx >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1); + y = ((vy >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1); + + px = (x & 0xffff) >> x_phase_shift; + py = (y & 0xffff) >> y_phase_shift; + + x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off); + y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off); + x2 = x1 + cwidth; + y2 = y1 + cheight; + + satot = srtot = sgtot = sbtot = 0; + + y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight; + + for (i = y1; i < y2; ++i) + { + pixman_fixed_t fy = *y_params++; + + if (fy) + { + pixman_fixed_t *x_params = params + 4 + px * cwidth; + + for (j = x1; j < x2; ++j) + { + pixman_fixed_t fx = *x_params++; + int rx = j; + int ry = i; + + if (fx) + { + pixman_fixed_t f; + uint32_t pixel, mask; + uint8_t *row; + + mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; + + if (repeat_mode != PIXMAN_REPEAT_NONE) + { + repeat (repeat_mode, &rx, bits->width); + repeat (repeat_mode, &ry, bits->height); + + row = (uint8_t *)(bits->bits + bits->rowstride * ry); + pixel = convert_pixel (row, rx) | mask; + } + else + { + if (rx < 0 || ry < 0 || rx >= bits->width || ry >= bits->height) + { + pixel = 0; + } + else + { + row = (uint8_t *)(bits->bits + bits->rowstride * ry); + pixel = convert_pixel (row, rx) | mask; + } + } + + f = ((pixman_fixed_32_32_t)fx * fy + 0x8000) >> 16; + srtot += (int)RED_8 (pixel) * f; + sgtot += (int)GREEN_8 (pixel) * f; + sbtot += (int)BLUE_8 (pixel) * f; + satot += (int)ALPHA_8 (pixel) * f; + } + } + } + } + + satot = (satot + 0x8000) >> 16; + srtot = (srtot + 0x8000) >> 16; + sgtot = (sgtot + 0x8000) >> 16; + sbtot = (sbtot + 0x8000) >> 16; + + satot = CLIP (satot, 0, 0xff); + srtot = CLIP (srtot, 0, 0xff); + sgtot = CLIP (sgtot, 0, 0xff); + sbtot = CLIP (sbtot, 0, 0xff); + + buffer[k] = (satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot << 0); + + next: + vx += ux; + vy += uy; + } +} + +static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +static force_inline void +bits_image_fetch_bilinear_affine (pixman_image_t * image, + int offset, + int line, + int width, + uint32_t * buffer, + const uint32_t * mask, + + convert_pixel_t convert_pixel, + pixman_format_code_t format, + pixman_repeat_t repeat_mode) +{ + pixman_fixed_t x, y; + pixman_fixed_t ux, uy; + pixman_vector_t v; + bits_image_t *bits = &image->bits; + int i; + + /* reference point is the center of the pixel */ + v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; + v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; + v.vector[2] = pixman_fixed_1; + + if (!pixman_transform_point_3d (image->common.transform, &v)) + return; + + ux = image->common.transform->matrix[0][0]; + uy = image->common.transform->matrix[1][0]; + + x = v.vector[0]; + y = v.vector[1]; + + for (i = 0; i < width; ++i) + { + int x1, y1, x2, y2; + uint32_t tl, tr, bl, br; + int32_t distx, disty; + int width = image->bits.width; + int height = image->bits.height; + const uint8_t *row1; + const uint8_t *row2; + + if (mask && !mask[i]) + goto next; + + x1 = x - pixman_fixed_1 / 2; + y1 = y - pixman_fixed_1 / 2; + + distx = pixman_fixed_to_bilinear_weight (x1); + disty = pixman_fixed_to_bilinear_weight (y1); + + y1 = pixman_fixed_to_int (y1); + y2 = y1 + 1; + x1 = pixman_fixed_to_int (x1); + x2 = x1 + 1; + + if (repeat_mode != PIXMAN_REPEAT_NONE) + { + uint32_t mask; + + mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; + + repeat (repeat_mode, &x1, width); + repeat (repeat_mode, &y1, height); + repeat (repeat_mode, &x2, width); + repeat (repeat_mode, &y2, height); + + row1 = (uint8_t *)(bits->bits + bits->rowstride * y1); + row2 = (uint8_t *)(bits->bits + bits->rowstride * y2); + + tl = convert_pixel (row1, x1) | mask; + tr = convert_pixel (row1, x2) | mask; + bl = convert_pixel (row2, x1) | mask; + br = convert_pixel (row2, x2) | mask; + } + else + { + uint32_t mask1, mask2; + int bpp; + + /* Note: PIXMAN_FORMAT_BPP() returns an unsigned value, + * which means if you use it in expressions, those + * expressions become unsigned themselves. Since + * the variables below can be negative in some cases, + * that will lead to crashes on 64 bit architectures. + * + * So this line makes sure bpp is signed + */ + bpp = PIXMAN_FORMAT_BPP (format); + + if (x1 >= width || x2 < 0 || y1 >= height || y2 < 0) + { + buffer[i] = 0; + goto next; + } + + if (y2 == 0) + { + row1 = zero; + mask1 = 0; + } + else + { + row1 = (uint8_t *)(bits->bits + bits->rowstride * y1); + row1 += bpp / 8 * x1; + + mask1 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; + } + + if (y1 == height - 1) + { + row2 = zero; + mask2 = 0; + } + else + { + row2 = (uint8_t *)(bits->bits + bits->rowstride * y2); + row2 += bpp / 8 * x1; + + mask2 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; + } + + if (x2 == 0) + { + tl = 0; + bl = 0; + } + else + { + tl = convert_pixel (row1, 0) | mask1; + bl = convert_pixel (row2, 0) | mask2; + } + + if (x1 == width - 1) + { + tr = 0; + br = 0; + } + else + { + tr = convert_pixel (row1, 1) | mask1; + br = convert_pixel (row2, 1) | mask2; + } + } + + buffer[i] = bilinear_interpolation ( + tl, tr, bl, br, distx, disty); + + next: + x += ux; + y += uy; + } +} + +static force_inline void +bits_image_fetch_nearest_affine (pixman_image_t * image, + int offset, + int line, + int width, + uint32_t * buffer, + const uint32_t * mask, + + convert_pixel_t convert_pixel, + pixman_format_code_t format, + pixman_repeat_t repeat_mode) +{ + pixman_fixed_t x, y; + pixman_fixed_t ux, uy; + pixman_vector_t v; + bits_image_t *bits = &image->bits; + int i; + + /* reference point is the center of the pixel */ + v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; + v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; + v.vector[2] = pixman_fixed_1; + + if (!pixman_transform_point_3d (image->common.transform, &v)) + return; + + ux = image->common.transform->matrix[0][0]; + uy = image->common.transform->matrix[1][0]; + + x = v.vector[0]; + y = v.vector[1]; + + for (i = 0; i < width; ++i) + { + int width, height, x0, y0; + const uint8_t *row; + + if (mask && !mask[i]) + goto next; + + width = image->bits.width; + height = image->bits.height; + x0 = pixman_fixed_to_int (x - pixman_fixed_e); + y0 = pixman_fixed_to_int (y - pixman_fixed_e); + + if (repeat_mode == PIXMAN_REPEAT_NONE && + (y0 < 0 || y0 >= height || x0 < 0 || x0 >= width)) + { + buffer[i] = 0; + } + else + { + uint32_t mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000; + + if (repeat_mode != PIXMAN_REPEAT_NONE) + { + repeat (repeat_mode, &x0, width); + repeat (repeat_mode, &y0, height); + } + + row = (uint8_t *)(bits->bits + bits->rowstride * y0); + + buffer[i] = convert_pixel (row, x0) | mask; + } + + next: + x += ux; + y += uy; + } +} + +static force_inline uint32_t +convert_a8r8g8b8 (const uint8_t *row, int x) +{ + return *(((uint32_t *)row) + x); +} + +static force_inline uint32_t +convert_x8r8g8b8 (const uint8_t *row, int x) +{ + return *(((uint32_t *)row) + x); +} + +static force_inline uint32_t +convert_a8 (const uint8_t *row, int x) +{ + return (uint32_t) *(row + x) << 24; +} + +static force_inline uint32_t +convert_r5g6b5 (const uint8_t *row, int x) +{ + return convert_0565_to_0888 (*((uint16_t *)row + x)); +} + +#define MAKE_SEPARABLE_CONVOLUTION_FETCHER(name, format, repeat_mode) \ + static uint32_t * \ + bits_image_fetch_separable_convolution_affine_ ## name (pixman_iter_t *iter, \ + const uint32_t * mask) \ + { \ + bits_image_fetch_separable_convolution_affine ( \ + iter->image, \ + iter->x, iter->y++, \ + iter->width, \ + iter->buffer, mask, \ + convert_ ## format, \ + PIXMAN_ ## format, \ + repeat_mode); \ + \ + return iter->buffer; \ + } + +#define MAKE_BILINEAR_FETCHER(name, format, repeat_mode) \ + static uint32_t * \ + bits_image_fetch_bilinear_affine_ ## name (pixman_iter_t *iter, \ + const uint32_t * mask) \ + { \ + bits_image_fetch_bilinear_affine (iter->image, \ + iter->x, iter->y++, \ + iter->width, \ + iter->buffer, mask, \ + convert_ ## format, \ + PIXMAN_ ## format, \ + repeat_mode); \ + return iter->buffer; \ + } + +#define MAKE_NEAREST_FETCHER(name, format, repeat_mode) \ + static uint32_t * \ + bits_image_fetch_nearest_affine_ ## name (pixman_iter_t *iter, \ + const uint32_t * mask) \ + { \ + bits_image_fetch_nearest_affine (iter->image, \ + iter->x, iter->y++, \ + iter->width, \ + iter->buffer, mask, \ + convert_ ## format, \ + PIXMAN_ ## format, \ + repeat_mode); \ + return iter->buffer; \ + } + +#define MAKE_FETCHERS(name, format, repeat_mode) \ + MAKE_NEAREST_FETCHER (name, format, repeat_mode) \ + MAKE_BILINEAR_FETCHER (name, format, repeat_mode) \ + MAKE_SEPARABLE_CONVOLUTION_FETCHER (name, format, repeat_mode) + +MAKE_FETCHERS (pad_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_PAD) +MAKE_FETCHERS (none_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NONE) +MAKE_FETCHERS (reflect_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_REFLECT) +MAKE_FETCHERS (normal_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_NORMAL) +MAKE_FETCHERS (pad_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_PAD) +MAKE_FETCHERS (none_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NONE) +MAKE_FETCHERS (reflect_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_REFLECT) +MAKE_FETCHERS (normal_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_NORMAL) +MAKE_FETCHERS (pad_a8, a8, PIXMAN_REPEAT_PAD) +MAKE_FETCHERS (none_a8, a8, PIXMAN_REPEAT_NONE) +MAKE_FETCHERS (reflect_a8, a8, PIXMAN_REPEAT_REFLECT) +MAKE_FETCHERS (normal_a8, a8, PIXMAN_REPEAT_NORMAL) +MAKE_FETCHERS (pad_r5g6b5, r5g6b5, PIXMAN_REPEAT_PAD) +MAKE_FETCHERS (none_r5g6b5, r5g6b5, PIXMAN_REPEAT_NONE) +MAKE_FETCHERS (reflect_r5g6b5, r5g6b5, PIXMAN_REPEAT_REFLECT) +MAKE_FETCHERS (normal_r5g6b5, r5g6b5, PIXMAN_REPEAT_NORMAL) + +#define IMAGE_FLAGS \ (FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM | \ FAST_PATH_BITS_IMAGE | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST) - if (iter->iter_flags & ITER_16) - return FALSE; - - if ((iter->iter_flags & ITER_NARROW) && - (iter->image_flags & FLAGS) == FLAGS) - { - const fetcher_info_t *f; - - for (f = &fetchers[0]; f->format != PIXMAN_null; f++) - { - if (image->common.extended_format_code == f->format) - { - uint8_t *b = (uint8_t *)image->bits.bits; - int s = image->bits.rowstride * 4; - - iter->bits = b + s * iter->y + iter->x * PIXMAN_FORMAT_BPP (f->format) / 8; - iter->stride = s; - - iter->get_scanline = f->get_scanline; - return TRUE; - } - } - } - - return FALSE; -} - -static pixman_bool_t -fast_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) +static const pixman_iter_info_t fast_iters[] = { - pixman_image_t *image = iter->image; + { PIXMAN_r5g6b5, IMAGE_FLAGS, ITER_NARROW | ITER_SRC, + _pixman_iter_init_bits_stride, fast_fetch_r5g6b5, NULL }, - if (iter->iter_flags & ITER_16) - return FALSE; + { PIXMAN_r5g6b5, FAST_PATH_STD_DEST_FLAGS, + ITER_NARROW | ITER_DEST, + _pixman_iter_init_bits_stride, + fast_fetch_r5g6b5, fast_write_back_r5g6b5 }, + + { PIXMAN_r5g6b5, FAST_PATH_STD_DEST_FLAGS, + ITER_NARROW | ITER_DEST | ITER_IGNORE_RGB | ITER_IGNORE_ALPHA, + _pixman_iter_init_bits_stride, + fast_dest_fetch_noop, fast_write_back_r5g6b5 }, - if ((iter->iter_flags & ITER_NARROW) && - (iter->image_flags & FAST_PATH_STD_DEST_FLAGS) == FAST_PATH_STD_DEST_FLAGS) - { - const fetcher_info_t *f; + { PIXMAN_a8r8g8b8, + (FAST_PATH_STANDARD_FLAGS | + FAST_PATH_SCALE_TRANSFORM | + FAST_PATH_BILINEAR_FILTER | + FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR), + ITER_NARROW | ITER_SRC, + fast_bilinear_cover_iter_init, + NULL, NULL + }, - for (f = &fetchers[0]; f->format != PIXMAN_null; f++) - { - if (image->common.extended_format_code == f->format) - { - uint8_t *b = (uint8_t *)image->bits.bits; - int s = image->bits.rowstride * 4; +#define FAST_BILINEAR_FLAGS \ + (FAST_PATH_NO_ALPHA_MAP | \ + FAST_PATH_NO_ACCESSORS | \ + FAST_PATH_HAS_TRANSFORM | \ + FAST_PATH_AFFINE_TRANSFORM | \ + FAST_PATH_X_UNIT_POSITIVE | \ + FAST_PATH_Y_UNIT_ZERO | \ + FAST_PATH_NONE_REPEAT | \ + FAST_PATH_BILINEAR_FILTER) - iter->bits = b + s * iter->y + iter->x * PIXMAN_FORMAT_BPP (f->format) / 8; - iter->stride = s; + { PIXMAN_a8r8g8b8, + FAST_BILINEAR_FLAGS, + ITER_NARROW | ITER_SRC, + NULL, bits_image_fetch_bilinear_no_repeat_8888, NULL + }, - if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) == - (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) - { - iter->get_scanline = fast_dest_fetch_noop; - } - else - { - iter->get_scanline = f->get_scanline; - } - iter->write_back = f->write_back; - return TRUE; - } - } - } - return FALSE; -} + { PIXMAN_x8r8g8b8, + FAST_BILINEAR_FLAGS, + ITER_NARROW | ITER_SRC, + NULL, bits_image_fetch_bilinear_no_repeat_8888, NULL + }, +#define GENERAL_BILINEAR_FLAGS \ + (FAST_PATH_NO_ALPHA_MAP | \ + FAST_PATH_NO_ACCESSORS | \ + FAST_PATH_HAS_TRANSFORM | \ + FAST_PATH_AFFINE_TRANSFORM | \ + FAST_PATH_BILINEAR_FILTER) + +#define GENERAL_NEAREST_FLAGS \ + (FAST_PATH_NO_ALPHA_MAP | \ + FAST_PATH_NO_ACCESSORS | \ + FAST_PATH_HAS_TRANSFORM | \ + FAST_PATH_AFFINE_TRANSFORM | \ + FAST_PATH_NEAREST_FILTER) + +#define GENERAL_SEPARABLE_CONVOLUTION_FLAGS \ + (FAST_PATH_NO_ALPHA_MAP | \ + FAST_PATH_NO_ACCESSORS | \ + FAST_PATH_HAS_TRANSFORM | \ + FAST_PATH_AFFINE_TRANSFORM | \ + FAST_PATH_SEPARABLE_CONVOLUTION_FILTER) + +#define SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) \ + { PIXMAN_ ## format, \ + GENERAL_SEPARABLE_CONVOLUTION_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ + ITER_NARROW | ITER_SRC, \ + NULL, bits_image_fetch_separable_convolution_affine_ ## name, NULL \ + }, + +#define BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \ + { PIXMAN_ ## format, \ + GENERAL_BILINEAR_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ + ITER_NARROW | ITER_SRC, \ + NULL, bits_image_fetch_bilinear_affine_ ## name, NULL, \ + }, + +#define NEAREST_AFFINE_FAST_PATH(name, format, repeat) \ + { PIXMAN_ ## format, \ + GENERAL_NEAREST_FLAGS | FAST_PATH_ ## repeat ## _REPEAT, \ + ITER_NARROW | ITER_SRC, \ + NULL, bits_image_fetch_nearest_affine_ ## name, NULL \ + }, + +#define AFFINE_FAST_PATHS(name, format, repeat) \ + NEAREST_AFFINE_FAST_PATH(name, format, repeat) \ + BILINEAR_AFFINE_FAST_PATH(name, format, repeat) \ + SEPARABLE_CONVOLUTION_AFFINE_FAST_PATH(name, format, repeat) + + AFFINE_FAST_PATHS (pad_a8r8g8b8, a8r8g8b8, PAD) + AFFINE_FAST_PATHS (none_a8r8g8b8, a8r8g8b8, NONE) + AFFINE_FAST_PATHS (reflect_a8r8g8b8, a8r8g8b8, REFLECT) + AFFINE_FAST_PATHS (normal_a8r8g8b8, a8r8g8b8, NORMAL) + AFFINE_FAST_PATHS (pad_x8r8g8b8, x8r8g8b8, PAD) + AFFINE_FAST_PATHS (none_x8r8g8b8, x8r8g8b8, NONE) + AFFINE_FAST_PATHS (reflect_x8r8g8b8, x8r8g8b8, REFLECT) + AFFINE_FAST_PATHS (normal_x8r8g8b8, x8r8g8b8, NORMAL) + AFFINE_FAST_PATHS (pad_a8, a8, PAD) + AFFINE_FAST_PATHS (none_a8, a8, NONE) + AFFINE_FAST_PATHS (reflect_a8, a8, REFLECT) + AFFINE_FAST_PATHS (normal_a8, a8, NORMAL) + AFFINE_FAST_PATHS (pad_r5g6b5, r5g6b5, PAD) + AFFINE_FAST_PATHS (none_r5g6b5, r5g6b5, NONE) + AFFINE_FAST_PATHS (reflect_r5g6b5, r5g6b5, REFLECT) + AFFINE_FAST_PATHS (normal_r5g6b5, r5g6b5, NORMAL) + + { PIXMAN_null }, +}; pixman_implementation_t * _pixman_implementation_create_fast_path (pixman_implementation_t *fallback) @@ -2583,8 +3288,7 @@ _pixman_implementation_create_fast_path (pixman_implementation_t *fallback) pixman_implementation_t *imp = _pixman_implementation_create (fallback, c_fast_paths); imp->fill = fast_path_fill; - imp->src_iter_init = fast_src_iter_init; - imp->dest_iter_init = fast_dest_iter_init; + imp->iter_info = fast_iters; return imp; } diff --git a/gfx/cairo/libpixman/src/pixman-fast-path.h b/gfx/cairo/libpixman/src/pixman-fast-path.h deleted file mode 100644 index 1885d47e77..0000000000 --- a/gfx/cairo/libpixman/src/pixman-fast-path.h +++ /dev/null @@ -1,1022 +0,0 @@ -/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */ -/* - * Copyright © 2000 SuSE, Inc. - * Copyright © 2007 Red Hat, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of SuSE not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. SuSE makes no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. - * - * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE - * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Author: Keith Packard, SuSE, Inc. - */ - -#ifndef PIXMAN_FAST_PATH_H__ -#define PIXMAN_FAST_PATH_H__ - -#include "pixman-private.h" - -#define PIXMAN_REPEAT_COVER -1 - -static force_inline pixman_bool_t -repeat (pixman_repeat_t repeat, int *c, int size) -{ - if (repeat == PIXMAN_REPEAT_NONE) - { - if (*c < 0 || *c >= size) - return FALSE; - } - else if (repeat == PIXMAN_REPEAT_NORMAL) - { - while (*c >= size) - *c -= size; - while (*c < 0) - *c += size; - } - else if (repeat == PIXMAN_REPEAT_PAD) - { - *c = CLIP (*c, 0, size - 1); - } - else /* REFLECT */ - { - *c = MOD (*c, size * 2); - if (*c >= size) - *c = size * 2 - *c - 1; - } - return TRUE; -} - -/* - * For each scanline fetched from source image with PAD repeat: - * - calculate how many pixels need to be padded on the left side - * - calculate how many pixels need to be padded on the right side - * - update width to only count pixels which are fetched from the image - * All this information is returned via 'width', 'left_pad', 'right_pad' - * arguments. The code is assuming that 'unit_x' is positive. - * - * Note: 64-bit math is used in order to avoid potential overflows, which - * is probably excessive in many cases. This particular function - * may need its own correctness test and performance tuning. - */ -static force_inline void -pad_repeat_get_scanline_bounds (int32_t source_image_width, - pixman_fixed_t vx, - pixman_fixed_t unit_x, - int32_t * width, - int32_t * left_pad, - int32_t * right_pad) -{ - int64_t max_vx = (int64_t) source_image_width << 16; - int64_t tmp; - if (vx < 0) - { - tmp = ((int64_t) unit_x - 1 - vx) / unit_x; - if (tmp > *width) - { - *left_pad = *width; - *width = 0; - } - else - { - *left_pad = (int32_t) tmp; - *width -= (int32_t) tmp; - } - } - else - { - *left_pad = 0; - } - tmp = ((int64_t) unit_x - 1 - vx + max_vx) / unit_x - *left_pad; - if (tmp < 0) - { - *right_pad = *width; - *width = 0; - } - else if (tmp >= *width) - { - *right_pad = 0; - } - else - { - *right_pad = *width - (int32_t) tmp; - *width = (int32_t) tmp; - } -} - -/* A macroified version of specialized nearest scalers for some - * common 8888 and 565 formats. It supports SRC and OVER ops. - * - * There are two repeat versions, one that handles repeat normal, - * and one without repeat handling that only works if the src region - * used is completely covered by the pre-repeated source samples. - * - * The loops are unrolled to process two pixels per iteration for better - * performance on most CPU architectures (superscalar processors - * can issue several operations simultaneously, other processors can hide - * instructions latencies by pipelining operations). Unrolling more - * does not make much sense because the compiler will start running out - * of spare registers soon. - */ - -#define GET_8888_ALPHA(s) ((s) >> 24) - /* This is not actually used since we don't have an OVER with - 565 source, but it is needed to build. */ -#define GET_0565_ALPHA(s) 0xff - -#define FAST_NEAREST_SCANLINE(scanline_func_name, SRC_FORMAT, DST_FORMAT, \ - src_type_t, dst_type_t, OP, repeat_mode) \ -static force_inline void \ -scanline_func_name (dst_type_t *dst, \ - const src_type_t *src, \ - int32_t w, \ - pixman_fixed_t vx, \ - pixman_fixed_t unit_x, \ - pixman_fixed_t max_vx, \ - pixman_bool_t fully_transparent_src) \ -{ \ - uint32_t d; \ - src_type_t s1, s2; \ - uint8_t a1, a2; \ - int x1, x2; \ - \ - if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER && fully_transparent_src) \ - return; \ - \ - if (PIXMAN_OP_ ## OP != PIXMAN_OP_SRC && PIXMAN_OP_ ## OP != PIXMAN_OP_OVER) \ - abort(); \ - \ - while ((w -= 2) >= 0) \ - { \ - x1 = vx >> 16; \ - vx += unit_x; \ - if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \ - { \ - /* This works because we know that unit_x is positive */ \ - while (vx >= max_vx) \ - vx -= max_vx; \ - } \ - s1 = src[x1]; \ - \ - x2 = vx >> 16; \ - vx += unit_x; \ - if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \ - { \ - /* This works because we know that unit_x is positive */ \ - while (vx >= max_vx) \ - vx -= max_vx; \ - } \ - s2 = src[x2]; \ - \ - if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER) \ - { \ - a1 = GET_ ## SRC_FORMAT ## _ALPHA(s1); \ - a2 = GET_ ## SRC_FORMAT ## _ALPHA(s2); \ - \ - if (a1 == 0xff) \ - { \ - *dst = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s1); \ - } \ - else if (s1) \ - { \ - d = CONVERT_ ## DST_FORMAT ## _TO_8888 (*dst); \ - s1 = CONVERT_ ## SRC_FORMAT ## _TO_8888 (s1); \ - a1 ^= 0xff; \ - UN8x4_MUL_UN8_ADD_UN8x4 (d, a1, s1); \ - *dst = CONVERT_8888_TO_ ## DST_FORMAT (d); \ - } \ - dst++; \ - \ - if (a2 == 0xff) \ - { \ - *dst = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s2); \ - } \ - else if (s2) \ - { \ - d = CONVERT_## DST_FORMAT ## _TO_8888 (*dst); \ - s2 = CONVERT_## SRC_FORMAT ## _TO_8888 (s2); \ - a2 ^= 0xff; \ - UN8x4_MUL_UN8_ADD_UN8x4 (d, a2, s2); \ - *dst = CONVERT_8888_TO_ ## DST_FORMAT (d); \ - } \ - dst++; \ - } \ - else /* PIXMAN_OP_SRC */ \ - { \ - *dst++ = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s1); \ - *dst++ = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s2); \ - } \ - } \ - \ - if (w & 1) \ - { \ - x1 = vx >> 16; \ - s1 = src[x1]; \ - \ - if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER) \ - { \ - a1 = GET_ ## SRC_FORMAT ## _ALPHA(s1); \ - \ - if (a1 == 0xff) \ - { \ - *dst = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s1); \ - } \ - else if (s1) \ - { \ - d = CONVERT_## DST_FORMAT ## _TO_8888 (*dst); \ - s1 = CONVERT_ ## SRC_FORMAT ## _TO_8888 (s1); \ - a1 ^= 0xff; \ - UN8x4_MUL_UN8_ADD_UN8x4 (d, a1, s1); \ - *dst = CONVERT_8888_TO_ ## DST_FORMAT (d); \ - } \ - dst++; \ - } \ - else /* PIXMAN_OP_SRC */ \ - { \ - *dst++ = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s1); \ - } \ - } \ -} - -#define FAST_NEAREST_MAINLOOP_INT(scale_func_name, scanline_func, src_type_t, mask_type_t, \ - dst_type_t, repeat_mode, have_mask, mask_is_solid) \ -static void \ -fast_composite_scaled_nearest ## scale_func_name (pixman_implementation_t *imp, \ - pixman_op_t op, \ - pixman_image_t * src_image, \ - pixman_image_t * mask_image, \ - pixman_image_t * dst_image, \ - int32_t src_x, \ - int32_t src_y, \ - int32_t mask_x, \ - int32_t mask_y, \ - int32_t dst_x, \ - int32_t dst_y, \ - int32_t width, \ - int32_t height) \ -{ \ - dst_type_t *dst_line; \ - mask_type_t *mask_line; \ - src_type_t *src_first_line; \ - int y; \ - pixman_fixed_t max_vx = INT32_MAX; /* suppress uninitialized variable warning */ \ - pixman_fixed_t max_vy; \ - pixman_vector_t v; \ - pixman_fixed_t vx, vy; \ - pixman_fixed_t unit_x, unit_y; \ - int32_t left_pad, right_pad; \ - \ - src_type_t *src; \ - dst_type_t *dst; \ - mask_type_t solid_mask; \ - const mask_type_t *mask = &solid_mask; \ - int src_stride, mask_stride, dst_stride; \ - \ - PIXMAN_IMAGE_GET_LINE (dst_image, dst_x, dst_y, dst_type_t, dst_stride, dst_line, 1); \ - if (have_mask) \ - { \ - if (mask_is_solid) \ - solid_mask = _pixman_image_get_solid (imp, mask_image, dst_image->bits.format); \ - else \ - PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type_t, \ - mask_stride, mask_line, 1); \ - } \ - /* pass in 0 instead of src_x and src_y because src_x and src_y need to be \ - * transformed from destination space to source space */ \ - PIXMAN_IMAGE_GET_LINE (src_image, 0, 0, src_type_t, src_stride, src_first_line, 1); \ - \ - /* reference point is the center of the pixel */ \ - v.vector[0] = pixman_int_to_fixed (src_x) + pixman_fixed_1 / 2; \ - v.vector[1] = pixman_int_to_fixed (src_y) + pixman_fixed_1 / 2; \ - v.vector[2] = pixman_fixed_1; \ - \ - if (!pixman_transform_point_3d (src_image->common.transform, &v)) \ - return; \ - \ - unit_x = src_image->common.transform->matrix[0][0]; \ - unit_y = src_image->common.transform->matrix[1][1]; \ - \ - /* Round down to closest integer, ensuring that 0.5 rounds to 0, not 1 */ \ - v.vector[0] -= pixman_fixed_e; \ - v.vector[1] -= pixman_fixed_e; \ - \ - vx = v.vector[0]; \ - vy = v.vector[1]; \ - \ - if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \ - { \ - /* Clamp repeating positions inside the actual samples */ \ - max_vx = src_image->bits.width << 16; \ - max_vy = src_image->bits.height << 16; \ - \ - repeat (PIXMAN_REPEAT_NORMAL, &vx, max_vx); \ - repeat (PIXMAN_REPEAT_NORMAL, &vy, max_vy); \ - } \ - \ - if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD || \ - PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \ - { \ - pad_repeat_get_scanline_bounds (src_image->bits.width, vx, unit_x, \ - &width, &left_pad, &right_pad); \ - vx += left_pad * unit_x; \ - } \ - \ - while (--height >= 0) \ - { \ - dst = dst_line; \ - dst_line += dst_stride; \ - if (have_mask && !mask_is_solid) \ - { \ - mask = mask_line; \ - mask_line += mask_stride; \ - } \ - \ - y = vy >> 16; \ - vy += unit_y; \ - if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \ - repeat (PIXMAN_REPEAT_NORMAL, &vy, max_vy); \ - if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \ - { \ - repeat (PIXMAN_REPEAT_PAD, &y, src_image->bits.height); \ - src = src_first_line + src_stride * y; \ - if (left_pad > 0) \ - { \ - scanline_func (mask, dst, src, left_pad, 0, 0, 0, FALSE); \ - } \ - if (width > 0) \ - { \ - scanline_func (mask + (mask_is_solid ? 0 : left_pad), \ - dst + left_pad, src, width, vx, unit_x, 0, FALSE); \ - } \ - if (right_pad > 0) \ - { \ - scanline_func (mask + (mask_is_solid ? 0 : left_pad + width), \ - dst + left_pad + width, src + src_image->bits.width - 1, \ - right_pad, 0, 0, 0, FALSE); \ - } \ - } \ - else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \ - { \ - static const src_type_t zero[1] = { 0 }; \ - if (y < 0 || y >= src_image->bits.height) \ - { \ - scanline_func (mask, dst, zero, left_pad + width + right_pad, 0, 0, 0, TRUE); \ - continue; \ - } \ - src = src_first_line + src_stride * y; \ - if (left_pad > 0) \ - { \ - scanline_func (mask, dst, zero, left_pad, 0, 0, 0, TRUE); \ - } \ - if (width > 0) \ - { \ - scanline_func (mask + (mask_is_solid ? 0 : left_pad), \ - dst + left_pad, src, width, vx, unit_x, 0, FALSE); \ - } \ - if (right_pad > 0) \ - { \ - scanline_func (mask + (mask_is_solid ? 0 : left_pad + width), \ - dst + left_pad + width, zero, right_pad, 0, 0, 0, TRUE); \ - } \ - } \ - else \ - { \ - src = src_first_line + src_stride * y; \ - scanline_func (mask, dst, src, width, vx, unit_x, max_vx, FALSE); \ - } \ - } \ -} - -/* A workaround for old sun studio, see: https://bugs.freedesktop.org/show_bug.cgi?id=32764 */ -#define FAST_NEAREST_MAINLOOP_COMMON(scale_func_name, scanline_func, src_type_t, mask_type_t, \ - dst_type_t, repeat_mode, have_mask, mask_is_solid) \ - FAST_NEAREST_MAINLOOP_INT(_ ## scale_func_name, scanline_func, src_type_t, mask_type_t, \ - dst_type_t, repeat_mode, have_mask, mask_is_solid) - -#define FAST_NEAREST_MAINLOOP_NOMASK(scale_func_name, scanline_func, src_type_t, dst_type_t, \ - repeat_mode) \ - static force_inline void \ - scanline_func##scale_func_name##_wrapper ( \ - const uint8_t *mask, \ - dst_type_t *dst, \ - const src_type_t *src, \ - int32_t w, \ - pixman_fixed_t vx, \ - pixman_fixed_t unit_x, \ - pixman_fixed_t max_vx, \ - pixman_bool_t fully_transparent_src) \ - { \ - scanline_func (dst, src, w, vx, unit_x, max_vx, fully_transparent_src); \ - } \ - FAST_NEAREST_MAINLOOP_INT (scale_func_name, scanline_func##scale_func_name##_wrapper, \ - src_type_t, uint8_t, dst_type_t, repeat_mode, FALSE, FALSE) - -#define FAST_NEAREST_MAINLOOP(scale_func_name, scanline_func, src_type_t, dst_type_t, \ - repeat_mode) \ - FAST_NEAREST_MAINLOOP_NOMASK(_ ## scale_func_name, scanline_func, src_type_t, \ - dst_type_t, repeat_mode) - -#define FAST_NEAREST(scale_func_name, SRC_FORMAT, DST_FORMAT, \ - src_type_t, dst_type_t, OP, repeat_mode) \ - FAST_NEAREST_SCANLINE(scaled_nearest_scanline_ ## scale_func_name ## _ ## OP, \ - SRC_FORMAT, DST_FORMAT, src_type_t, dst_type_t, \ - OP, repeat_mode) \ - FAST_NEAREST_MAINLOOP_NOMASK(_ ## scale_func_name ## _ ## OP, \ - scaled_nearest_scanline_ ## scale_func_name ## _ ## OP, \ - src_type_t, dst_type_t, repeat_mode) - - -#define SCALED_NEAREST_FLAGS \ - (FAST_PATH_SCALE_TRANSFORM | \ - FAST_PATH_NO_ALPHA_MAP | \ - FAST_PATH_NEAREST_FILTER | \ - FAST_PATH_NO_ACCESSORS | \ - FAST_PATH_NARROW_FORMAT) - -#define SIMPLE_NEAREST_FAST_PATH_NORMAL(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_NEAREST_FLAGS | \ - FAST_PATH_NORMAL_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_null, 0, \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \ - } - -#define SIMPLE_NEAREST_FAST_PATH_PAD(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_NEAREST_FLAGS | \ - FAST_PATH_PAD_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_null, 0, \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \ - } - -#define SIMPLE_NEAREST_FAST_PATH_NONE(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_NEAREST_FLAGS | \ - FAST_PATH_NONE_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_null, 0, \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \ - } - -#define SIMPLE_NEAREST_FAST_PATH_COVER(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \ - PIXMAN_null, 0, \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \ - } - -#define SIMPLE_NEAREST_A8_MASK_FAST_PATH_NORMAL(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_NEAREST_FLAGS | \ - FAST_PATH_NORMAL_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \ - } - -#define SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_NEAREST_FLAGS | \ - FAST_PATH_PAD_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \ - } - -#define SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_NEAREST_FLAGS | \ - FAST_PATH_NONE_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \ - } - -#define SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \ - PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \ - } - -#define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_NEAREST_FLAGS | \ - FAST_PATH_NORMAL_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \ - } - -#define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_NEAREST_FLAGS | \ - FAST_PATH_PAD_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \ - } - -#define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NONE(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_NEAREST_FLAGS | \ - FAST_PATH_NONE_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \ - } - -#define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \ - PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \ - } - -/* Prefer the use of 'cover' variant, because it is faster */ -#define SIMPLE_NEAREST_FAST_PATH(op,s,d,func) \ - SIMPLE_NEAREST_FAST_PATH_COVER (op,s,d,func), \ - SIMPLE_NEAREST_FAST_PATH_NONE (op,s,d,func), \ - SIMPLE_NEAREST_FAST_PATH_PAD (op,s,d,func), \ - SIMPLE_NEAREST_FAST_PATH_NORMAL (op,s,d,func) - -#define SIMPLE_NEAREST_A8_MASK_FAST_PATH(op,s,d,func) \ - SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER (op,s,d,func), \ - SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE (op,s,d,func), \ - SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD (op,s,d,func) - -#define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH(op,s,d,func) \ - SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER (op,s,d,func), \ - SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NONE (op,s,d,func), \ - SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD (op,s,d,func) - -/*****************************************************************************/ - -/* - * Identify 5 zones in each scanline for bilinear scaling. Depending on - * whether 2 pixels to be interpolated are fetched from the image itself, - * from the padding area around it or from both image and padding area. - */ -static force_inline void -bilinear_pad_repeat_get_scanline_bounds (int32_t source_image_width, - pixman_fixed_t vx, - pixman_fixed_t unit_x, - int32_t * left_pad, - int32_t * left_tz, - int32_t * width, - int32_t * right_tz, - int32_t * right_pad) -{ - int width1 = *width, left_pad1, right_pad1; - int width2 = *width, left_pad2, right_pad2; - - pad_repeat_get_scanline_bounds (source_image_width, vx, unit_x, - &width1, &left_pad1, &right_pad1); - pad_repeat_get_scanline_bounds (source_image_width, vx + pixman_fixed_1, - unit_x, &width2, &left_pad2, &right_pad2); - - *left_pad = left_pad2; - *left_tz = left_pad1 - left_pad2; - *right_tz = right_pad2 - right_pad1; - *right_pad = right_pad1; - *width -= *left_pad + *left_tz + *right_tz + *right_pad; -} - -/* - * Main loop template for single pass bilinear scaling. It needs to be - * provided with 'scanline_func' which should do the compositing operation. - * The needed function has the following prototype: - * - * scanline_func (dst_type_t * dst, - * const mask_type_ * mask, - * const src_type_t * src_top, - * const src_type_t * src_bottom, - * int32_t width, - * int weight_top, - * int weight_bottom, - * pixman_fixed_t vx, - * pixman_fixed_t unit_x, - * pixman_fixed_t max_vx, - * pixman_bool_t zero_src) - * - * Where: - * dst - destination scanline buffer for storing results - * mask - mask buffer (or single value for solid mask) - * src_top, src_bottom - two source scanlines - * width - number of pixels to process - * weight_top - weight of the top row for interpolation - * weight_bottom - weight of the bottom row for interpolation - * vx - initial position for fetching the first pair of - * pixels from the source buffer - * unit_x - position increment needed to move to the next pair - * of pixels - * max_vx - image size as a fixed point value, can be used for - * implementing NORMAL repeat (when it is supported) - * zero_src - boolean hint variable, which is set to TRUE when - * all source pixels are fetched from zero padding - * zone for NONE repeat - * - * Note: normally the sum of 'weight_top' and 'weight_bottom' is equal to 256, - * but sometimes it may be less than that for NONE repeat when handling - * fuzzy antialiased top or bottom image edges. Also both top and - * bottom weight variables are guaranteed to have value in 0-255 - * range and can fit into unsigned byte or be used with 8-bit SIMD - * multiplication instructions. - */ -#define FAST_BILINEAR_MAINLOOP_INT(scale_func_name, scanline_func, src_type_t, mask_type_t, \ - dst_type_t, repeat_mode, have_mask, mask_is_solid) \ -static void \ -fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, \ - pixman_op_t op, \ - pixman_image_t * src_image, \ - pixman_image_t * mask_image, \ - pixman_image_t * dst_image, \ - int32_t src_x, \ - int32_t src_y, \ - int32_t mask_x, \ - int32_t mask_y, \ - int32_t dst_x, \ - int32_t dst_y, \ - int32_t width, \ - int32_t height) \ -{ \ - dst_type_t *dst_line; \ - mask_type_t *mask_line; \ - src_type_t *src_first_line; \ - int y1, y2; \ - pixman_fixed_t max_vx = INT32_MAX; /* suppress uninitialized variable warning */ \ - pixman_vector_t v; \ - pixman_fixed_t vx, vy; \ - pixman_fixed_t unit_x, unit_y; \ - int32_t left_pad, left_tz, right_tz, right_pad; \ - \ - dst_type_t *dst; \ - mask_type_t solid_mask; \ - const mask_type_t *mask = &solid_mask; \ - int src_stride, mask_stride, dst_stride; \ - \ - PIXMAN_IMAGE_GET_LINE (dst_image, dst_x, dst_y, dst_type_t, dst_stride, dst_line, 1); \ - if (have_mask) \ - { \ - if (mask_is_solid) \ - { \ - solid_mask = _pixman_image_get_solid (imp, mask_image, dst_image->bits.format); \ - mask_stride = 0; \ - } \ - else \ - { \ - PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type_t, \ - mask_stride, mask_line, 1); \ - } \ - } \ - /* pass in 0 instead of src_x and src_y because src_x and src_y need to be \ - * transformed from destination space to source space */ \ - PIXMAN_IMAGE_GET_LINE (src_image, 0, 0, src_type_t, src_stride, src_first_line, 1); \ - \ - /* reference point is the center of the pixel */ \ - v.vector[0] = pixman_int_to_fixed (src_x) + pixman_fixed_1 / 2; \ - v.vector[1] = pixman_int_to_fixed (src_y) + pixman_fixed_1 / 2; \ - v.vector[2] = pixman_fixed_1; \ - \ - if (!pixman_transform_point_3d (src_image->common.transform, &v)) \ - return; \ - \ - unit_x = src_image->common.transform->matrix[0][0]; \ - unit_y = src_image->common.transform->matrix[1][1]; \ - \ - v.vector[0] -= pixman_fixed_1 / 2; \ - v.vector[1] -= pixman_fixed_1 / 2; \ - \ - vy = v.vector[1]; \ - \ - if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD || \ - PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \ - { \ - bilinear_pad_repeat_get_scanline_bounds (src_image->bits.width, v.vector[0], unit_x, \ - &left_pad, &left_tz, &width, &right_tz, &right_pad); \ - if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \ - { \ - /* PAD repeat does not need special handling for 'transition zones' and */ \ - /* they can be combined with 'padding zones' safely */ \ - left_pad += left_tz; \ - right_pad += right_tz; \ - left_tz = right_tz = 0; \ - } \ - v.vector[0] += left_pad * unit_x; \ - } \ - \ - while (--height >= 0) \ - { \ - int weight1, weight2; \ - dst = dst_line; \ - dst_line += dst_stride; \ - vx = v.vector[0]; \ - if (have_mask && !mask_is_solid) \ - { \ - mask = mask_line; \ - mask_line += mask_stride; \ - } \ - \ - y1 = pixman_fixed_to_int (vy); \ - weight2 = (vy >> 8) & 0xff; \ - if (weight2) \ - { \ - /* normal case, both row weights are in 0-255 range and fit unsigned byte */ \ - y2 = y1 + 1; \ - weight1 = 256 - weight2; \ - } \ - else \ - { \ - /* set both top and bottom row to the same scanline, and weights to 128+128 */ \ - y2 = y1; \ - weight1 = weight2 = 128; \ - } \ - vy += unit_y; \ - if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \ - { \ - src_type_t *src1, *src2; \ - src_type_t buf1[2]; \ - src_type_t buf2[2]; \ - repeat (PIXMAN_REPEAT_PAD, &y1, src_image->bits.height); \ - repeat (PIXMAN_REPEAT_PAD, &y2, src_image->bits.height); \ - src1 = src_first_line + src_stride * y1; \ - src2 = src_first_line + src_stride * y2; \ - \ - if (left_pad > 0) \ - { \ - buf1[0] = buf1[1] = src1[0]; \ - buf2[0] = buf2[1] = src2[0]; \ - scanline_func (dst, mask, \ - buf1, buf2, left_pad, weight1, weight2, 0, 0, 0, FALSE); \ - dst += left_pad; \ - if (have_mask && !mask_is_solid) \ - mask += left_pad; \ - } \ - if (width > 0) \ - { \ - scanline_func (dst, mask, \ - src1, src2, width, weight1, weight2, vx, unit_x, 0, FALSE); \ - dst += width; \ - if (have_mask && !mask_is_solid) \ - mask += width; \ - } \ - if (right_pad > 0) \ - { \ - buf1[0] = buf1[1] = src1[src_image->bits.width - 1]; \ - buf2[0] = buf2[1] = src2[src_image->bits.width - 1]; \ - scanline_func (dst, mask, \ - buf1, buf2, right_pad, weight1, weight2, 0, 0, 0, FALSE); \ - } \ - } \ - else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \ - { \ - src_type_t *src1, *src2; \ - src_type_t buf1[2]; \ - src_type_t buf2[2]; \ - /* handle top/bottom zero padding by just setting weights to 0 if needed */ \ - if (y1 < 0) \ - { \ - weight1 = 0; \ - y1 = 0; \ - } \ - if (y1 >= src_image->bits.height) \ - { \ - weight1 = 0; \ - y1 = src_image->bits.height - 1; \ - } \ - if (y2 < 0) \ - { \ - weight2 = 0; \ - y2 = 0; \ - } \ - if (y2 >= src_image->bits.height) \ - { \ - weight2 = 0; \ - y2 = src_image->bits.height - 1; \ - } \ - src1 = src_first_line + src_stride * y1; \ - src2 = src_first_line + src_stride * y2; \ - \ - if (left_pad > 0) \ - { \ - buf1[0] = buf1[1] = 0; \ - buf2[0] = buf2[1] = 0; \ - scanline_func (dst, mask, \ - buf1, buf2, left_pad, weight1, weight2, 0, 0, 0, TRUE); \ - dst += left_pad; \ - if (have_mask && !mask_is_solid) \ - mask += left_pad; \ - } \ - if (left_tz > 0) \ - { \ - buf1[0] = 0; \ - buf1[1] = src1[0]; \ - buf2[0] = 0; \ - buf2[1] = src2[0]; \ - scanline_func (dst, mask, \ - buf1, buf2, left_tz, weight1, weight2, \ - pixman_fixed_frac (vx), unit_x, 0, FALSE); \ - dst += left_tz; \ - if (have_mask && !mask_is_solid) \ - mask += left_tz; \ - vx += left_tz * unit_x; \ - } \ - if (width > 0) \ - { \ - scanline_func (dst, mask, \ - src1, src2, width, weight1, weight2, vx, unit_x, 0, FALSE); \ - dst += width; \ - if (have_mask && !mask_is_solid) \ - mask += width; \ - vx += width * unit_x; \ - } \ - if (right_tz > 0) \ - { \ - buf1[0] = src1[src_image->bits.width - 1]; \ - buf1[1] = 0; \ - buf2[0] = src2[src_image->bits.width - 1]; \ - buf2[1] = 0; \ - scanline_func (dst, mask, \ - buf1, buf2, right_tz, weight1, weight2, \ - pixman_fixed_frac (vx), unit_x, 0, FALSE); \ - dst += right_tz; \ - if (have_mask && !mask_is_solid) \ - mask += right_tz; \ - } \ - if (right_pad > 0) \ - { \ - buf1[0] = buf1[1] = 0; \ - buf2[0] = buf2[1] = 0; \ - scanline_func (dst, mask, \ - buf1, buf2, right_pad, weight1, weight2, 0, 0, 0, TRUE); \ - } \ - } \ - else \ - { \ - scanline_func (dst, mask, src_first_line + src_stride * y1, \ - src_first_line + src_stride * y2, width, \ - weight1, weight2, vx, unit_x, max_vx, FALSE); \ - } \ - } \ -} - -/* A workaround for old sun studio, see: https://bugs.freedesktop.org/show_bug.cgi?id=32764 */ -#define FAST_BILINEAR_MAINLOOP_COMMON(scale_func_name, scanline_func, src_type_t, mask_type_t, \ - dst_type_t, repeat_mode, have_mask, mask_is_solid) \ - FAST_BILINEAR_MAINLOOP_INT(_ ## scale_func_name, scanline_func, src_type_t, mask_type_t,\ - dst_type_t, repeat_mode, have_mask, mask_is_solid) - -#define SCALED_BILINEAR_FLAGS \ - (FAST_PATH_SCALE_TRANSFORM | \ - FAST_PATH_NO_ALPHA_MAP | \ - FAST_PATH_BILINEAR_FILTER | \ - FAST_PATH_NO_ACCESSORS | \ - FAST_PATH_NARROW_FORMAT) - -#define SIMPLE_BILINEAR_FAST_PATH_PAD(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_BILINEAR_FLAGS | \ - FAST_PATH_PAD_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_null, 0, \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \ - } - -#define SIMPLE_BILINEAR_FAST_PATH_NONE(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_BILINEAR_FLAGS | \ - FAST_PATH_NONE_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_null, 0, \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \ - } - -#define SIMPLE_BILINEAR_FAST_PATH_COVER(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \ - PIXMAN_null, 0, \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \ - } - -#define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_PAD(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_BILINEAR_FLAGS | \ - FAST_PATH_PAD_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \ - } - -#define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NONE(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_BILINEAR_FLAGS | \ - FAST_PATH_NONE_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \ - } - -#define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_COVER(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \ - PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \ - } - -#define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_PAD(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_BILINEAR_FLAGS | \ - FAST_PATH_PAD_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \ - } - -#define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NONE(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - (SCALED_BILINEAR_FLAGS | \ - FAST_PATH_NONE_REPEAT | \ - FAST_PATH_X_UNIT_POSITIVE), \ - PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \ - } - -#define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_COVER(op,s,d,func) \ - { PIXMAN_OP_ ## op, \ - PIXMAN_ ## s, \ - SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \ - PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \ - PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \ - fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \ - } - -/* Prefer the use of 'cover' variant, because it is faster */ -#define SIMPLE_BILINEAR_FAST_PATH(op,s,d,func) \ - SIMPLE_BILINEAR_FAST_PATH_COVER (op,s,d,func), \ - SIMPLE_BILINEAR_FAST_PATH_NONE (op,s,d,func), \ - SIMPLE_BILINEAR_FAST_PATH_PAD (op,s,d,func) - -#define SIMPLE_BILINEAR_A8_MASK_FAST_PATH(op,s,d,func) \ - SIMPLE_BILINEAR_A8_MASK_FAST_PATH_COVER (op,s,d,func), \ - SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NONE (op,s,d,func), \ - SIMPLE_BILINEAR_A8_MASK_FAST_PATH_PAD (op,s,d,func) - -#define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH(op,s,d,func) \ - SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_COVER (op,s,d,func), \ - SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NONE (op,s,d,func), \ - SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_PAD (op,s,d,func) - -#endif diff --git a/gfx/cairo/libpixman/src/pixman-filter.c b/gfx/cairo/libpixman/src/pixman-filter.c index 5ff7b6eaad..5f3b752f9b 100644 --- a/gfx/cairo/libpixman/src/pixman-filter.c +++ b/gfx/cairo/libpixman/src/pixman-filter.c @@ -109,14 +109,16 @@ general_cubic (double x, double B, double C) if (ax < 1) { - return ((12 - 9 * B - 6 * C) * ax * ax * ax + - (-18 + 12 * B + 6 * C) * ax * ax + (6 - 2 * B)) / 6; + return (((12 - 9 * B - 6 * C) * ax + + (-18 + 12 * B + 6 * C)) * ax * ax + + (6 - 2 * B)) / 6; } - else if (ax >= 1 && ax < 2) + else if (ax < 2) { - return ((-B - 6 * C) * ax * ax * ax + - (6 * B + 30 * C) * ax * ax + (-12 * B - 48 * C) * - ax + (8 * B + 24 * C)) / 6; + return ((((-B - 6 * C) * ax + + (6 * B + 30 * C)) * ax + + (-12 * B - 48 * C)) * ax + + (8 * B + 24 * C)) / 6; } else { @@ -141,7 +143,7 @@ static const filter_info_t filters[] = { PIXMAN_KERNEL_BOX, box_kernel, 1.0 }, { PIXMAN_KERNEL_LINEAR, linear_kernel, 2.0 }, { PIXMAN_KERNEL_CUBIC, cubic_kernel, 4.0 }, - { PIXMAN_KERNEL_GAUSSIAN, gaussian_kernel, 6 * SIGMA }, + { PIXMAN_KERNEL_GAUSSIAN, gaussian_kernel, 5.0 }, { PIXMAN_KERNEL_LANCZOS2, lanczos2_kernel, 4.0 }, { PIXMAN_KERNEL_LANCZOS3, lanczos3_kernel, 6.0 }, { PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel, 8.0 }, @@ -160,18 +162,21 @@ integral (pixman_kernel_t kernel1, double x1, pixman_kernel_t kernel2, double scale, double x2, double width) { - /* If the integration interval crosses zero, break it into - * two separate integrals. This ensures that filters such - * as LINEAR that are not differentiable at 0 will still - * integrate properly. + if (kernel1 == PIXMAN_KERNEL_BOX && kernel2 == PIXMAN_KERNEL_BOX) + { + return width; + } + /* The LINEAR filter is not differentiable at 0, so if the + * integration interval crosses zero, break it into two + * separate integrals. */ - if (x1 < 0 && x1 + width > 0) + else if (kernel1 == PIXMAN_KERNEL_LINEAR && x1 < 0 && x1 + width > 0) { return integral (kernel1, x1, kernel2, scale, x2, - x1) + integral (kernel1, 0, kernel2, scale, x2 - x1, width + x1); } - else if (x2 < 0 && x2 + width > 0) + else if (kernel2 == PIXMAN_KERNEL_LINEAR && x2 < 0 && x2 + width > 0) { return integral (kernel1, x1, kernel2, scale, x2, - x2) + @@ -189,13 +194,19 @@ integral (pixman_kernel_t kernel1, double x1, } else { - /* Integration via Simpson's rule */ -#define N_SEGMENTS 128 + /* Integration via Simpson's rule + * See http://www.intmath.com/integration/6-simpsons-rule.php + * 12 segments (6 cubic approximations) seems to produce best + * result for lanczos3.linear, which was the combination that + * showed the most errors. This makes sense as the lanczos3 + * filter is 6 wide. + */ +#define N_SEGMENTS 12 #define SAMPLE(a1, a2) \ (filters[kernel1].func ((a1)) * filters[kernel2].func ((a2) * scale)) double s = 0.0; - double h = width / (double)N_SEGMENTS; + double h = width / N_SEGMENTS; int i; s = SAMPLE (x1, x2); @@ -204,11 +215,14 @@ integral (pixman_kernel_t kernel1, double x1, { double a1 = x1 + h * i; double a2 = x2 + h * i; + s += 4 * SAMPLE (a1, a2); + } + for (i = 2; i < N_SEGMENTS; i += 2) + { + double a1 = x1 + h * i; + double a2 = x2 + h * i; s += 2 * SAMPLE (a1, a2); - - if (i >= 2 && i < N_SEGMENTS - 1) - s += 4 * SAMPLE (a1, a2); } s += SAMPLE (x1 + width, x2 + width); @@ -217,25 +231,17 @@ integral (pixman_kernel_t kernel1, double x1, } } -static pixman_fixed_t * -create_1d_filter (int *width, +static void +create_1d_filter (int width, pixman_kernel_t reconstruct, pixman_kernel_t sample, double scale, - int n_phases) + int n_phases, + pixman_fixed_t *p) { - pixman_fixed_t *params, *p; double step; - double size; int i; - size = scale * filters[sample].width + filters[reconstruct].width; - *width = ceil (size); - - p = params = malloc (*width * n_phases * sizeof (pixman_fixed_t)); - if (!params) - return NULL; - step = 1.0 / n_phases; for (i = 0; i < n_phases; ++i) @@ -243,15 +249,15 @@ create_1d_filter (int *width, double frac = step / 2.0 + i * step; pixman_fixed_t new_total; int x, x1, x2; - double total; + double total, e; /* Sample convolution of reconstruction and sampling * filter. See rounding.txt regarding the rounding * and sample positions. */ - x1 = ceil (frac - *width / 2.0 - 0.5); - x2 = x1 + *width; + x1 = ceil (frac - width / 2.0 - 0.5); + x2 = x1 + width; total = 0; for (x = x1; x < x2; ++x) @@ -274,29 +280,154 @@ create_1d_filter (int *width, ihigh - ilow); } - total += c; - *p++ = (pixman_fixed_t)(c * 65535.0 + 0.5); + *p = (pixman_fixed_t)floor (c * 65536.0 + 0.5); + total += *p; + p++; } - /* Normalize */ - p -= *width; - total = 1 / total; + /* Normalize, with error diffusion */ + p -= width; + total = 65536.0 / total; new_total = 0; + e = 0.0; for (x = x1; x < x2; ++x) { - pixman_fixed_t t = (*p) * total + 0.5; + double v = (*p) * total + e; + pixman_fixed_t t = floor (v + 0.5); + e = v - t; new_total += t; *p++ = t; } - if (new_total != pixman_fixed_1) - *(p - *width / 2) += (pixman_fixed_1 - new_total); + /* pixman_fixed_e's worth of error may remain; put it + * at the first sample, since that is the only one that + * hasn't had any error diffused into it. + */ + *(p - width) += pixman_fixed_1 - new_total; + } +} + + +static int +filter_width (pixman_kernel_t reconstruct, pixman_kernel_t sample, double size) +{ + return ceil (filters[reconstruct].width + size * filters[sample].width); +} + +#ifdef PIXMAN_GNUPLOT + +/* If enable-gnuplot is configured, then you can pipe the output of a + * pixman-using program to gnuplot and get a continuously-updated plot + * of the horizontal filter. This works well with demos/scale to test + * the filter generation. + * + * The plot is all the different subposition filters shuffled + * together. This is misleading in a few cases: + * + * IMPULSE.BOX - goes up and down as the subfilters have different + * numbers of non-zero samples + * IMPULSE.TRIANGLE - somewhat crooked for the same reason + * 1-wide filters - looks triangular, but a 1-wide box would be more + * accurate + */ +static void +gnuplot_filter (int width, int n_phases, const pixman_fixed_t* p) +{ + double step; + int i, j; + int first; + + step = 1.0 / n_phases; + + printf ("set style line 1 lc rgb '#0060ad' lt 1 lw 0.5 pt 7 pi 1 ps 0.5\n"); + printf ("plot [x=%g:%g] '-' with linespoints ls 1\n", -width*0.5, width*0.5); + /* Print a point at the origin so that y==0 line is included: */ + printf ("0 0\n\n"); + + /* The position of the first sample of the phase corresponding to + * frac is given by: + * + * ceil (frac - width / 2.0 - 0.5) + 0.5 - frac + * + * We have to find the frac that minimizes this expression. + * + * For odd widths, we have + * + * ceil (frac - width / 2.0 - 0.5) + 0.5 - frac + * = ceil (frac) + K - frac + * = 1 + K - frac + * + * for some K, so this is minimized when frac is maximized and + * strictly growing with frac. So for odd widths, we can simply + * start at the last phase and go backwards. + * + * For even widths, we have + * + * ceil (frac - width / 2.0 - 0.5) + 0.5 - frac + * = ceil (frac - 0.5) + K - frac + * + * The graph for this function (ignoring K) looks like this: + * + * 0.5 + * | |\ + * | | \ + * | | \ + * 0 | | \ + * |\ | + * | \ | + * | \ | + * -0.5 | \| + * --------------------------------- + * 0 0.5 1 + * + * So in this case we need to start with the phase whose frac is + * less than, but as close as possible to 0.5, then go backwards + * until we hit the first phase, then wrap around to the last + * phase and continue backwards. + * + * Which phase is as close as possible 0.5? The locations of the + * sampling point corresponding to the kth phase is given by + * 1/(2 * n_phases) + k / n_phases: + * + * 1/(2 * n_phases) + k / n_phases = 0.5 + * + * from which it follows that + * + * k = (n_phases - 1) / 2 + * + * rounded down is the phase in question. + */ + if (width & 1) + first = n_phases - 1; + else + first = (n_phases - 1) / 2; + + for (j = 0; j < width; ++j) + { + for (i = 0; i < n_phases; ++i) + { + int phase = first - i; + double frac, pos; + + if (phase < 0) + phase = n_phases + phase; + + frac = step / 2.0 + phase * step; + pos = ceil (frac - width / 2.0 - 0.5) + 0.5 - frac + j; + + printf ("%g %g\n", + pos, + pixman_fixed_to_double (*(p + phase * width + j))); + } } - return params; + printf ("e\n"); + fflush (stdout); } +#endif + /* Create the parameter list for a SEPARABLE_CONVOLUTION filter * with the given kernels and scale parameters */ @@ -313,38 +444,35 @@ pixman_filter_create_separable_convolution (int *n_values, { double sx = fabs (pixman_fixed_to_double (scale_x)); double sy = fabs (pixman_fixed_to_double (scale_y)); - pixman_fixed_t *horz = NULL, *vert = NULL, *params = NULL; + pixman_fixed_t *params; int subsample_x, subsample_y; int width, height; + width = filter_width (reconstruct_x, sample_x, sx); subsample_x = (1 << subsample_bits_x); + + height = filter_width (reconstruct_y, sample_y, sy); subsample_y = (1 << subsample_bits_y); - horz = create_1d_filter (&width, reconstruct_x, sample_x, sx, subsample_x); - vert = create_1d_filter (&height, reconstruct_y, sample_y, sy, subsample_y); - - if (!horz || !vert) - goto out; - *n_values = 4 + width * subsample_x + height * subsample_y; params = malloc (*n_values * sizeof (pixman_fixed_t)); if (!params) - goto out; + return NULL; params[0] = pixman_int_to_fixed (width); params[1] = pixman_int_to_fixed (height); params[2] = pixman_int_to_fixed (subsample_bits_x); params[3] = pixman_int_to_fixed (subsample_bits_y); - memcpy (params + 4, horz, - width * subsample_x * sizeof (pixman_fixed_t)); - memcpy (params + 4 + width * subsample_x, vert, - height * subsample_y * sizeof (pixman_fixed_t)); + create_1d_filter (width, reconstruct_x, sample_x, sx, subsample_x, + params + 4); + create_1d_filter (height, reconstruct_y, sample_y, sy, subsample_y, + params + 4 + width * subsample_x); -out: - free (horz); - free (vert); +#ifdef PIXMAN_GNUPLOT + gnuplot_filter(width, subsample_x, params + 4); +#endif return params; } diff --git a/gfx/cairo/libpixman/src/pixman-general.c b/gfx/cairo/libpixman/src/pixman-general.c index 2a551e3a5e..7e5a0d09cc 100644 --- a/gfx/cairo/libpixman/src/pixman-general.c +++ b/gfx/cairo/libpixman/src/pixman-general.c @@ -37,43 +37,47 @@ #include #include "pixman-private.h" -static pixman_bool_t -general_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) +static void +general_iter_init (pixman_iter_t *iter, const pixman_iter_info_t *info) { pixman_image_t *image = iter->image; - if (image->type == LINEAR) - _pixman_linear_gradient_iter_init (image, iter); - else if (image->type == RADIAL) + switch (image->type) + { + case BITS: + if ((iter->iter_flags & ITER_SRC) == ITER_SRC) + _pixman_bits_image_src_iter_init (image, iter); + else + _pixman_bits_image_dest_iter_init (image, iter); + break; + + case LINEAR: + _pixman_linear_gradient_iter_init (image, iter); + break; + + case RADIAL: _pixman_radial_gradient_iter_init (image, iter); - else if (image->type == CONICAL) + break; + + case CONICAL: _pixman_conical_gradient_iter_init (image, iter); - else if (image->type == BITS) - _pixman_bits_image_src_iter_init (image, iter); - else if (image->type == SOLID) + break; + + case SOLID: _pixman_log_error (FUNC, "Solid image not handled by noop"); - else + break; + + default: _pixman_log_error (FUNC, "Pixman bug: unknown image type\n"); - - return TRUE; + break; + } } -static pixman_bool_t -general_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) +static const pixman_iter_info_t general_iters[] = { - if (iter->image->type == BITS) - { - _pixman_bits_image_dest_iter_init (iter->image, iter); - - return TRUE; - } - else - { - _pixman_log_error (FUNC, "Trying to write to a non-writable image"); - - return FALSE; - } -} + { PIXMAN_any, 0, 0, general_iter_init, NULL, NULL }, + { PIXMAN_null }, +}; typedef struct op_info_t op_info_t; struct op_info_t @@ -105,62 +109,75 @@ static const op_info_t op_flags[PIXMAN_N_OPERATORS] = #define SCANLINE_BUFFER_LENGTH 8192 +static pixman_bool_t +operator_needs_division (pixman_op_t op) +{ + static const uint8_t needs_division[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* SATURATE */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, /* DISJOINT */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, /* CONJOINT */ + 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, /* blend ops */ + }; + + return needs_division[op]; +} + static void general_composite_rect (pixman_implementation_t *imp, pixman_composite_info_t *info) { PIXMAN_COMPOSITE_ARGS (info); - uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 3 + 7) / 8]; + uint8_t stack_scanline_buffer[3 * SCANLINE_BUFFER_LENGTH]; uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer; uint8_t *src_buffer, *mask_buffer, *dest_buffer; pixman_iter_t src_iter, mask_iter, dest_iter; pixman_combine_32_func_t compose; pixman_bool_t component_alpha; - iter_flags_t narrow, src_iter_flags; - iter_flags_t rgb16; + iter_flags_t width_flag, src_iter_flags; int Bpp; int i; - if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) && - (!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) && - (dest_image->common.flags & FAST_PATH_NARROW_FORMAT)) + if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) && + (!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) && + (dest_image->common.flags & FAST_PATH_NARROW_FORMAT) && + !(operator_needs_division (op)) && + (dest_image->bits.dither == PIXMAN_DITHER_NONE)) { - narrow = ITER_NARROW; + width_flag = ITER_NARROW; Bpp = 4; } else { - narrow = 0; + width_flag = ITER_WIDE; Bpp = 16; } - // XXX: This special casing is bad. Ideally, we'd keep the general code general perhaps - // by having it deal more specifically with different intermediate formats - if ( - (dest_image->common.flags & FAST_PATH_16_FORMAT && (src_image->type == LINEAR || src_image->type == RADIAL)) && - ( op == PIXMAN_OP_SRC || - (op == PIXMAN_OP_OVER && (src_image->common.flags & FAST_PATH_IS_OPAQUE)) - ) - ) { - rgb16 = ITER_16; - } else { - rgb16 = 0; - } +#define ALIGN(addr) \ + ((uint8_t *)((((uintptr_t)(addr)) + 15) & (~15))) + if (width <= 0 || _pixman_multiply_overflows_int (width, Bpp * 3)) + return; - if (width * Bpp > SCANLINE_BUFFER_LENGTH) + if (width * Bpp * 3 > sizeof (stack_scanline_buffer) - 15 * 3) { - scanline_buffer = pixman_malloc_abc (width, 3, Bpp); + scanline_buffer = pixman_malloc_ab_plus_c (width, Bpp * 3, 15 * 3); if (!scanline_buffer) return; + + memset (scanline_buffer, 0, width * Bpp * 3 + 15 * 3); + } + else + { + memset (stack_scanline_buffer, 0, sizeof (stack_scanline_buffer)); } - src_buffer = scanline_buffer; - mask_buffer = src_buffer + width * Bpp; - dest_buffer = mask_buffer + width * Bpp; + src_buffer = ALIGN (scanline_buffer); + mask_buffer = ALIGN (src_buffer + width * Bpp); + dest_buffer = ALIGN (mask_buffer + width * Bpp); - if (!narrow) + if (width_flag == ITER_WIDE) { /* To make sure there aren't any NANs in the buffers */ memset (src_buffer, 0, width * Bpp); @@ -169,11 +186,12 @@ general_composite_rect (pixman_implementation_t *imp, } /* src iter */ - src_iter_flags = narrow | op_flags[op].src | rgb16; + src_iter_flags = width_flag | op_flags[op].src | ITER_SRC; - _pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src_image, - src_x, src_y, width, height, - src_buffer, src_iter_flags, info->src_flags); + _pixman_implementation_iter_init (imp->toplevel, &src_iter, src_image, + src_x, src_y, width, height, + src_buffer, src_iter_flags, + info->src_flags); /* mask iter */ if ((src_iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) == @@ -185,23 +203,21 @@ general_composite_rect (pixman_implementation_t *imp, mask_image = NULL; } - component_alpha = - mask_image && - mask_image->common.type == BITS && - mask_image->common.component_alpha && - PIXMAN_FORMAT_RGB (mask_image->bits.format); + component_alpha = mask_image && mask_image->common.component_alpha; - _pixman_implementation_src_iter_init ( - imp->toplevel, &mask_iter, mask_image, mask_x, mask_y, width, height, - mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB), info->mask_flags); + _pixman_implementation_iter_init ( + imp->toplevel, &mask_iter, + mask_image, mask_x, mask_y, width, height, mask_buffer, + ITER_SRC | width_flag | (component_alpha? 0 : ITER_IGNORE_RGB), + info->mask_flags); /* dest iter */ - _pixman_implementation_dest_iter_init ( + _pixman_implementation_iter_init ( imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height, - dest_buffer, narrow | op_flags[op].dst | rgb16, info->dest_flags); + dest_buffer, ITER_DEST | width_flag | op_flags[op].dst, info->dest_flags); compose = _pixman_implementation_lookup_combiner ( - imp->toplevel, op, component_alpha, narrow, !!rgb16); + imp->toplevel, op, component_alpha, width_flag != ITER_WIDE); for (i = 0; i < height; ++i) { @@ -216,6 +232,13 @@ general_composite_rect (pixman_implementation_t *imp, dest_iter.write_back (&dest_iter); } + if (src_iter.fini) + src_iter.fini (&src_iter); + if (mask_iter.fini) + mask_iter.fini (&mask_iter); + if (dest_iter.fini) + dest_iter.fini (&dest_iter); + if (scanline_buffer != (uint8_t *) stack_scanline_buffer) free (scanline_buffer); } @@ -231,12 +254,10 @@ _pixman_implementation_create_general (void) { pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path); - _pixman_setup_combiner_functions_16 (imp); _pixman_setup_combiner_functions_32 (imp); _pixman_setup_combiner_functions_float (imp); - imp->src_iter_init = general_src_iter_init; - imp->dest_iter_init = general_dest_iter_init; + imp->iter_info = general_iters; return imp; } diff --git a/gfx/cairo/libpixman/src/pixman-glyph.c b/gfx/cairo/libpixman/src/pixman-glyph.c index 5a271b64b8..96a349ab47 100644 --- a/gfx/cairo/libpixman/src/pixman-glyph.c +++ b/gfx/cairo/libpixman/src/pixman-glyph.c @@ -391,6 +391,9 @@ box32_intersect (pixman_box32_t *dest, return dest->x2 > dest->x1 && dest->y2 > dest->y1; } +#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) +__attribute__((__force_align_arg_pointer__)) +#endif PIXMAN_EXPORT void pixman_composite_glyphs_no_mask (pixman_op_t op, pixman_image_t *src, @@ -630,6 +633,9 @@ out: * - Trim the mask to the destination clip/image? * - Trim composite region based on sources, when the op ignores 0s. */ +#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) +__attribute__((__force_align_arg_pointer__)) +#endif PIXMAN_EXPORT void pixman_composite_glyphs (pixman_op_t op, pixman_image_t *src, diff --git a/gfx/cairo/libpixman/src/pixman-gradient-walker.c b/gfx/cairo/libpixman/src/pixman-gradient-walker.c index e7e724fa6c..fb7f401dac 100644 --- a/gfx/cairo/libpixman/src/pixman-gradient-walker.c +++ b/gfx/cairo/libpixman/src/pixman-gradient-walker.c @@ -37,11 +37,14 @@ _pixman_gradient_walker_init (pixman_gradient_walker_t *walker, walker->stops = gradient->stops; walker->left_x = 0; walker->right_x = 0x10000; - walker->stepper = 0; - walker->left_ag = 0; - walker->left_rb = 0; - walker->right_ag = 0; - walker->right_rb = 0; + walker->a_s = 0.0f; + walker->a_b = 0.0f; + walker->r_s = 0.0f; + walker->r_b = 0.0f; + walker->g_s = 0.0f; + walker->g_b = 0.0f; + walker->b_s = 0.0f; + walker->b_b = 0.0f; walker->repeat = repeat; walker->need_reset = TRUE; @@ -51,10 +54,13 @@ static void gradient_walker_reset (pixman_gradient_walker_t *walker, pixman_fixed_48_16_t pos) { - int32_t x, left_x, right_x; + int64_t x, left_x, right_x; pixman_color_t *left_c, *right_c; int n, count = walker->num_stops; pixman_gradient_stop_t *stops = walker->stops; + float la, lr, lg, lb; + float ra, rr, rg, rb; + float lx, rx; if (walker->repeat == PIXMAN_REPEAT_NORMAL) { @@ -116,57 +122,143 @@ gradient_walker_reset (pixman_gradient_walker_t *walker, left_c = right_c; } - walker->left_x = left_x; - walker->right_x = right_x; - walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8); - walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8); - walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8); - walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8); + /* The alpha/red/green/blue channels are scaled to be in [0, 1]. + * This ensures that after premultiplication all channels will + * be in the [0, 1] interval. + */ + la = (left_c->alpha * (1.0f/257.0f)); + lr = (left_c->red * (1.0f/257.0f)); + lg = (left_c->green * (1.0f/257.0f)); + lb = (left_c->blue * (1.0f/257.0f)); - if (walker->left_x == walker->right_x || - (walker->left_ag == walker->right_ag && - walker->left_rb == walker->right_rb)) + ra = (right_c->alpha * (1.0f/257.0f)); + rr = (right_c->red * (1.0f/257.0f)); + rg = (right_c->green * (1.0f/257.0f)); + rb = (right_c->blue * (1.0f/257.0f)); + + lx = left_x * (1.0f/65536.0f); + rx = right_x * (1.0f/65536.0f); + + if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX) { - walker->stepper = 0; + walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f; + walker->a_b = (la + ra) / 510.0f; + walker->r_b = (lr + rr) / 510.0f; + walker->g_b = (lg + rg) / 510.0f; + walker->b_b = (lb + rb) / 510.0f; } else { - int32_t width = right_x - left_x; - walker->stepper = ((1 << 24) + width / 2) / width; + float w_rec = 1.0f / (rx - lx); + + walker->a_b = (la * rx - ra * lx) * w_rec * (1.0f/255.0f); + walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f); + walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f); + walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f); + + walker->a_s = (ra - la) * w_rec * (1.0f/255.0f); + walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f); + walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f); + walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f); } + + walker->left_x = left_x; + walker->right_x = right_x; walker->need_reset = FALSE; } -uint32_t -_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker, - pixman_fixed_48_16_t x) +static argb_t +pixman_gradient_walker_pixel_float (pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x) { - int dist, idist; - uint32_t t1, t2, a, color; + argb_t f; + float y; if (walker->need_reset || x < walker->left_x || x >= walker->right_x) gradient_walker_reset (walker, x); - dist = ((int)(x - walker->left_x) * walker->stepper) >> 16; - idist = 256 - dist; + y = x * (1.0f / 65536.0f); - /* combined INTERPOLATE and premultiply */ - t1 = walker->left_rb * idist + walker->right_rb * dist; - t1 = (t1 >> 8) & 0xff00ff; + f.a = walker->a_s * y + walker->a_b; + f.r = f.a * (walker->r_s * y + walker->r_b); + f.g = f.a * (walker->g_s * y + walker->g_b); + f.b = f.a * (walker->b_s * y + walker->b_b); - t2 = walker->left_ag * idist + walker->right_ag * dist; - t2 &= 0xff00ff00; - - color = t2 & 0xff000000; - a = t2 >> 24; - - t1 = t1 * a + 0x800080; - t1 = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8; - - t2 = (t2 >> 8) * a + 0x800080; - t2 = (t2 + ((t2 >> 8) & 0xff00ff)); - - return (color | (t1 & 0xff00ff) | (t2 & 0xff00)); + return f; } +static uint32_t +pixman_gradient_walker_pixel_32 (pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x) +{ + argb_t f; + float y; + + if (walker->need_reset || x < walker->left_x || x >= walker->right_x) + gradient_walker_reset (walker, x); + + y = x * (1.0f / 65536.0f); + + /* Instead of [0...1] for ARGB, we want [0...255], + * multiply alpha with 255 and the color channels + * also get multiplied by the alpha multiplier. + * + * We don't use pixman_contract_from_float because it causes a 2x + * slowdown to do so, and the values are already normalized, + * so we don't have to worry about values < 0.f or > 1.f + */ + f.a = 255.f * (walker->a_s * y + walker->a_b); + f.r = f.a * (walker->r_s * y + walker->r_b); + f.g = f.a * (walker->g_s * y + walker->g_b); + f.b = f.a * (walker->b_s * y + walker->b_b); + + return (((uint32_t)(f.a + .5f) << 24) & 0xff000000) | + (((uint32_t)(f.r + .5f) << 16) & 0x00ff0000) | + (((uint32_t)(f.g + .5f) << 8) & 0x0000ff00) | + (((uint32_t)(f.b + .5f) >> 0) & 0x000000ff); +} + +void +_pixman_gradient_walker_write_narrow (pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x, + uint32_t *buffer) +{ + *buffer = pixman_gradient_walker_pixel_32 (walker, x); +} + +void +_pixman_gradient_walker_write_wide (pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x, + uint32_t *buffer) +{ + *(argb_t *)buffer = pixman_gradient_walker_pixel_float (walker, x); +} + +void +_pixman_gradient_walker_fill_narrow (pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x, + uint32_t *buffer, + uint32_t *end) +{ + register uint32_t color; + + color = pixman_gradient_walker_pixel_32 (walker, x); + while (buffer < end) + *buffer++ = color; +} + +void +_pixman_gradient_walker_fill_wide (pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x, + uint32_t *buffer, + uint32_t *end) +{ + register argb_t color; + argb_t *buffer_wide = (argb_t *)buffer; + argb_t *end_wide = (argb_t *)end; + + color = pixman_gradient_walker_pixel_float (walker, x); + while (buffer_wide < end_wide) + *buffer_wide++ = color; +} diff --git a/gfx/cairo/libpixman/src/pixman-image.c b/gfx/cairo/libpixman/src/pixman-image.c index f43e07f41d..db29ff5b4f 100644 --- a/gfx/cairo/libpixman/src/pixman-image.c +++ b/gfx/cairo/libpixman/src/pixman-image.c @@ -33,25 +33,6 @@ static const pixman_color_t transparent_black = { 0, 0, 0, 0 }; -/** - ** bug 1293598 - clean up every pointer after free to avoid - ** "dereferencing freed memory" problem - **/ -#define PIXMAN_POSION - -static void -free_memory (void** p) -{ -#ifdef PIXMAN_POISON - if (*p) { -#endif - free (*p); -#ifdef PIXMAN_POISON - *p = NULL; - } -#endif -} - static void gradient_property_changed (pixman_image_t *image) { @@ -164,8 +145,8 @@ _pixman_image_fini (pixman_image_t *image) pixman_region32_fini (&common->clip_region); - free_memory (&common->transform); - free_memory (&common->filter_params); + free (common->transform); + free (common->filter_params); if (common->alpha_map) pixman_image_unref ((pixman_image_t *)common->alpha_map); @@ -177,8 +158,7 @@ _pixman_image_fini (pixman_image_t *image) if (image->gradient.stops) { /* See _pixman_init_gradient() for an explanation of the - 1 */ - void *addr = image->gradient.stops - 1; - free_memory (&addr); + free (image->gradient.stops - 1); } /* This will trigger if someone adds a property_changed @@ -189,11 +169,8 @@ _pixman_image_fini (pixman_image_t *image) image->common.property_changed == gradient_property_changed); } - if (image->type == BITS && image->bits.free_me) { - free_memory (&image->bits.free_me); - image->bits.bits = NULL; - } - + if (image->type == BITS && image->bits.free_me) + free (image->bits.free_me); return TRUE; } @@ -233,7 +210,7 @@ pixman_image_unref (pixman_image_t *image) { if (_pixman_image_fini (image)) { - free_memory (&image); + free (image); return TRUE; } @@ -358,37 +335,47 @@ compute_image_info (pixman_image_t *image) { flags |= FAST_PATH_NEAREST_FILTER; } - else if ( - /* affine and integer translation components in matrix ... */ - ((flags & FAST_PATH_AFFINE_TRANSFORM) && - !pixman_fixed_frac (image->common.transform->matrix[0][2] | - image->common.transform->matrix[1][2])) && - ( - /* ... combined with a simple rotation */ - (flags & (FAST_PATH_ROTATE_90_TRANSFORM | - FAST_PATH_ROTATE_180_TRANSFORM | - FAST_PATH_ROTATE_270_TRANSFORM)) || - /* ... or combined with a simple non-rotated translation */ - (image->common.transform->matrix[0][0] == pixman_fixed_1 && - image->common.transform->matrix[1][1] == pixman_fixed_1 && - image->common.transform->matrix[0][1] == 0 && - image->common.transform->matrix[1][0] == 0) - ) - ) + else if (flags & FAST_PATH_AFFINE_TRANSFORM) { - /* FIXME: there are some affine-test failures, showing that - * handling of BILINEAR and NEAREST filter is not quite - * equivalent when getting close to 32K for the translation - * components of the matrix. That's likely some bug, but for - * now just skip BILINEAR->NEAREST optimization in this case. + /* Suppose the transform is + * + * [ t00, t01, t02 ] + * [ t10, t11, t12 ] + * [ 0, 0, 1 ] + * + * and the destination coordinates are (n + 0.5, m + 0.5). Then + * the transformed x coordinate is: + * + * tx = t00 * (n + 0.5) + t01 * (m + 0.5) + t02 + * = t00 * n + t01 * m + t02 + (t00 + t01) * 0.5 + * + * which implies that if t00, t01 and t02 are all integers + * and (t00 + t01) is odd, then tx will be an integer plus 0.5, + * which means a BILINEAR filter will reduce to NEAREST. The same + * applies in the y direction */ - pixman_fixed_t magic_limit = pixman_int_to_fixed (30000); - if (image->common.transform->matrix[0][2] <= magic_limit && - image->common.transform->matrix[1][2] <= magic_limit && - image->common.transform->matrix[0][2] >= -magic_limit && - image->common.transform->matrix[1][2] >= -magic_limit) + pixman_fixed_t (*t)[3] = image->common.transform->matrix; + + if ((pixman_fixed_frac ( + t[0][0] | t[0][1] | t[0][2] | + t[1][0] | t[1][1] | t[1][2]) == 0) && + (pixman_fixed_to_int ( + (t[0][0] + t[0][1]) & (t[1][0] + t[1][1])) % 2) == 1) { - flags |= FAST_PATH_NEAREST_FILTER; + /* FIXME: there are some affine-test failures, showing that + * handling of BILINEAR and NEAREST filter is not quite + * equivalent when getting close to 32K for the translation + * components of the matrix. That's likely some bug, but for + * now just skip BILINEAR->NEAREST optimization in this case. + */ + pixman_fixed_t magic_limit = pixman_int_to_fixed (30000); + if (image->common.transform->matrix[0][2] <= magic_limit && + image->common.transform->matrix[1][2] <= magic_limit && + image->common.transform->matrix[0][2] >= -magic_limit && + image->common.transform->matrix[1][2] >= -magic_limit) + { + flags |= FAST_PATH_NEAREST_FILTER; + } } } break; @@ -483,10 +470,6 @@ compute_image_info (pixman_image_t *image) if (PIXMAN_FORMAT_IS_WIDE (image->bits.format)) flags &= ~FAST_PATH_NARROW_FORMAT; - - if (image->bits.format == PIXMAN_r5g6b5) - flags |= FAST_PATH_16_FORMAT; - break; case RADIAL: @@ -529,8 +512,10 @@ compute_image_info (pixman_image_t *image) break; } - /* Alpha map */ - if (!image->common.alpha_map) + /* Alpha maps are only supported for BITS images, so it's always + * safe to ignore their presense for non-BITS images + */ + if (!image->common.alpha_map || image->type != BITS) { flags |= FAST_PATH_NO_ALPHA_MAP; } @@ -699,6 +684,41 @@ pixman_image_set_repeat (pixman_image_t *image, image_property_changed (image); } +PIXMAN_EXPORT void +pixman_image_set_dither (pixman_image_t *image, + pixman_dither_t dither) +{ + if (image->type == BITS) + { + if (image->bits.dither == dither) + return; + + image->bits.dither = dither; + + image_property_changed (image); + } +} + +PIXMAN_EXPORT void +pixman_image_set_dither_offset (pixman_image_t *image, + int offset_x, + int offset_y) +{ + if (image->type == BITS) + { + if (image->bits.dither_offset_x == offset_x && + image->bits.dither_offset_y == offset_y) + { + return; + } + + image->bits.dither_offset_x = offset_x; + image->bits.dither_offset_y = offset_y; + + image_property_changed (image); + } +} + PIXMAN_EXPORT pixman_bool_t pixman_image_set_filter (pixman_image_t * image, pixman_filter_t filter, @@ -857,6 +877,10 @@ pixman_image_set_accessors (pixman_image_t * image, if (image->type == BITS) { + /* Accessors only work for <= 32 bpp. */ + if (PIXMAN_FORMAT_BPP(image->bits.format) > 32) + return_if_fail (!read_func && !write_func); + image->bits.read_func = read_func; image->bits.write_func = write_func; @@ -936,7 +960,7 @@ _pixman_image_get_solid (pixman_implementation_t *imp, else if (image->bits.format == PIXMAN_x8r8g8b8) result = image->bits.bits[0] | 0xff000000; else if (image->bits.format == PIXMAN_a8) - result = (*(uint8_t *)image->bits.bits) << 24; + result = (uint32_t)(*(uint8_t *)image->bits.bits) << 24; else goto otherwise; } @@ -945,12 +969,15 @@ _pixman_image_get_solid (pixman_implementation_t *imp, pixman_iter_t iter; otherwise: - _pixman_implementation_src_iter_init ( + _pixman_implementation_iter_init ( imp, &iter, image, 0, 0, 1, 1, (uint8_t *)&result, - ITER_NARROW, image->common.flags); + ITER_NARROW | ITER_SRC, image->common.flags); result = *iter.get_scanline (&iter, NULL); + + if (iter.fini) + iter.fini (&iter); } /* If necessary, convert RGB <--> BGR. */ diff --git a/gfx/cairo/libpixman/src/pixman-implementation.c b/gfx/cairo/libpixman/src/pixman-implementation.c index 44d4097852..2c7de4c687 100644 --- a/gfx/cairo/libpixman/src/pixman-implementation.c +++ b/gfx/cairo/libpixman/src/pixman-implementation.c @@ -90,15 +90,7 @@ _pixman_implementation_lookup_composite (pixman_implementation_t *toplevel, /* Check cache for fast paths */ cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache); - /* Bug 1324130 - For compatibility with Windows XP, we have to use Tls - * functions for the per-thread fast-path cache instead of the safer - * __declspec(thread) mechanism. If the Tls functions fail to set up - * the storage for some reason, cache will end up null here. As a - * temporary workaround, just check that cache is not null before - * using it. The implementation lookup will still function without the - * fast-path cache, however, it will incur a slow linear search. - */ - if (cache) for (i = 0; i < N_CACHED_FAST_PATHS; ++i) + for (i = 0; i < N_CACHED_FAST_PATHS; ++i) { const pixman_fast_path_t *info = &(cache->cache[i].fast_path); @@ -158,12 +150,19 @@ _pixman_implementation_lookup_composite (pixman_implementation_t *toplevel, } /* We should never reach this point */ - _pixman_log_error (FUNC, "No known composite function\n"); + _pixman_log_error ( + FUNC, + "No composite function found\n" + "\n" + "The most likely cause of this is that this system has issues with\n" + "thread local storage\n"); + *out_imp = NULL; *out_func = dummy_composite_rect; + return; update_cache: - if (cache && i) + if (i) { while (i--) cache->cache[i + 1] = cache->cache[i]; @@ -194,8 +193,7 @@ pixman_combine_32_func_t _pixman_implementation_lookup_combiner (pixman_implementation_t *imp, pixman_op_t op, pixman_bool_t component_alpha, - pixman_bool_t narrow, - pixman_bool_t rgb16) + pixman_bool_t narrow) { while (imp) { @@ -219,8 +217,6 @@ _pixman_implementation_lookup_combiner (pixman_implementation_t *imp, f = imp->combine_32_ca[op]; break; } - if (rgb16) - f = (pixman_combine_32_func_t *)imp->combine_16[op]; if (f) return f; @@ -289,50 +285,26 @@ _pixman_implementation_fill (pixman_implementation_t *imp, return FALSE; } -pixman_bool_t -_pixman_implementation_src_iter_init (pixman_implementation_t *imp, - pixman_iter_t *iter, - pixman_image_t *image, - int x, - int y, - int width, - int height, - uint8_t *buffer, - iter_flags_t iter_flags, - uint32_t image_flags) +static uint32_t * +get_scanline_null (pixman_iter_t *iter, const uint32_t *mask) { - iter->image = image; - iter->buffer = (uint32_t *)buffer; - iter->x = x; - iter->y = y; - iter->width = width; - iter->height = height; - iter->iter_flags = iter_flags; - iter->image_flags = image_flags; - - while (imp) - { - if (imp->src_iter_init && (*imp->src_iter_init) (imp, iter)) - return TRUE; - - imp = imp->fallback; - } - - return FALSE; + return NULL; } -pixman_bool_t -_pixman_implementation_dest_iter_init (pixman_implementation_t *imp, - pixman_iter_t *iter, - pixman_image_t *image, - int x, - int y, - int width, - int height, - uint8_t *buffer, - iter_flags_t iter_flags, - uint32_t image_flags) +void +_pixman_implementation_iter_init (pixman_implementation_t *imp, + pixman_iter_t *iter, + pixman_image_t *image, + int x, + int y, + int width, + int height, + uint8_t *buffer, + iter_flags_t iter_flags, + uint32_t image_flags) { + pixman_format_code_t format; + iter->image = image; iter->buffer = (uint32_t *)buffer; iter->x = x; @@ -341,16 +313,40 @@ _pixman_implementation_dest_iter_init (pixman_implementation_t *imp, iter->height = height; iter->iter_flags = iter_flags; iter->image_flags = image_flags; + iter->fini = NULL; + + if (!iter->image) + { + iter->get_scanline = get_scanline_null; + return; + } + + format = iter->image->common.extended_format_code; while (imp) { - if (imp->dest_iter_init && (*imp->dest_iter_init) (imp, iter)) - return TRUE; + if (imp->iter_info) + { + const pixman_iter_info_t *info; - imp = imp->fallback; + for (info = imp->iter_info; info->format != PIXMAN_null; ++info) + { + if ((info->format == PIXMAN_any || info->format == format) && + (info->image_flags & image_flags) == info->image_flags && + (info->iter_flags & iter_flags) == info->iter_flags) + { + iter->get_scanline = info->get_scanline; + iter->write_back = info->write_back; + + if (info->initializer) + info->initializer (iter, info); + return; + } + } + } + + imp = imp->fallback; } - - return FALSE; } pixman_bool_t @@ -384,6 +380,11 @@ _pixman_disabled (const char *name) return FALSE; } +static const pixman_fast_path_t empty_fast_path[] = +{ + { PIXMAN_OP_NONE } +}; + pixman_implementation_t * _pixman_choose_implementation (void) { @@ -401,5 +402,16 @@ _pixman_choose_implementation (void) imp = _pixman_implementation_create_noop (imp); + if (_pixman_disabled ("wholeops")) + { + pixman_implementation_t *cur; + + /* Disable all whole-operation paths except the general one, + * so that optimized iterators are used as much as possible. + */ + for (cur = imp; cur->fallback; cur = cur->fallback) + cur->fast_paths = empty_fast_path; + } + return imp; } diff --git a/gfx/cairo/libpixman/src/pixman-inlines.h b/gfx/cairo/libpixman/src/pixman-inlines.h index 6d78aa7cb0..f785910f80 100644 --- a/gfx/cairo/libpixman/src/pixman-inlines.h +++ b/gfx/cairo/libpixman/src/pixman-inlines.h @@ -173,34 +173,6 @@ bilinear_interpolation (uint32_t tl, uint32_t tr, #else -#ifdef LOW_QUALITY_INTERPOLATION -/* Based on Filter_32_opaque_portable from Skia */ -static force_inline uint32_t -bilinear_interpolation(uint32_t a00, uint32_t a01, - uint32_t a10, uint32_t a11, - int x, int y) -{ - int xy = x * y; - static const uint32_t mask = 0xff00ff; - - int scale = 256 - 16*y - 16*x + xy; - uint32_t lo = (a00 & mask) * scale; - uint32_t hi = ((a00 >> 8) & mask) * scale; - - scale = 16*x - xy; - lo += (a01 & mask) * scale; - hi += ((a01 >> 8) & mask) * scale; - - scale = 16*y - xy; - lo += (a10 & mask) * scale; - hi += ((a10 >> 8) & mask) * scale; - - lo += (a11 & mask) * xy; - hi += ((a11 >> 8) & mask) * xy; - - return ((lo >> 8) & mask) | (hi & ~mask); -} -#else static force_inline uint32_t bilinear_interpolation (uint32_t tl, uint32_t tr, uint32_t bl, uint32_t br, @@ -246,10 +218,35 @@ bilinear_interpolation (uint32_t tl, uint32_t tr, return r; } -#endif + #endif #endif // BILINEAR_INTERPOLATION_BITS <= 4 +static force_inline argb_t +bilinear_interpolation_float (argb_t tl, argb_t tr, + argb_t bl, argb_t br, + float distx, float disty) +{ + float distxy, distxiy, distixy, distixiy; + argb_t r; + + distxy = distx * disty; + distxiy = distx * (1.f - disty); + distixy = (1.f - distx) * disty; + distixiy = (1.f - distx) * (1.f - disty); + + r.a = tl.a * distixiy + tr.a * distxiy + + bl.a * distixy + br.a * distxy; + r.r = tl.r * distixiy + tr.r * distxiy + + bl.r * distixy + br.r * distxy; + r.g = tl.g * distixiy + tr.g * distxiy + + bl.g * distixy + br.g * distxy; + r.b = tl.b * distixiy + tr.b * distxiy + + bl.b * distixy + br.b * distxy; + + return r; +} + /* * For each scanline fetched from source image with PAD repeat: * - calculate how many pixels need to be padded on the left side @@ -775,7 +772,8 @@ fast_composite_scaled_nearest ## scale_func_name (pixman_implementation_t *imp, #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH(op,s,d,func) \ SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER (op,s,d,func), \ SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NONE (op,s,d,func), \ - SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD (op,s,d,func) + SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD (op,s,d,func), \ + SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL (op,s,d,func) /*****************************************************************************/ @@ -852,38 +850,8 @@ bilinear_pad_repeat_get_scanline_bounds (int32_t source_image_width, * with 8-bit SIMD multiplication instructions for 8-bit interpolation * precision. */ - -/* Replace a single "scanline_func" with "fetch_func" & "op_func" to allow optional - * two stage processing (bilinear fetch to a temp buffer, followed by unscaled - * combine), "op_func" may be NULL, in this case we keep old behavior. - * This is ugly and gcc issues some warnings, but works. - * - * An advice: clang has much better error reporting than gcc for deeply nested macros. - */ - -#define scanline_func(dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, dst, \ - scanline_buf, mask, src_top, src_bottom, width, \ - weight_top, weight_bottom, vx, unit_x, max_vx, zero_src) \ - do { \ - if (op_func != NULL) \ - { \ - fetch_func ((void *)scanline_buf, (mask), (src_top), (src_bottom), (width), \ - (weight_top), (weight_bottom), (vx), (unit_x), (max_vx), (zero_src)); \ - ((void (*)(dst_type_t *, const mask_type_t *, const src_type_t *, int)) op_func)\ - ((dst), (mask), (src_type_t *)scanline_buf, (width)); \ - } \ - else \ - { \ - fetch_func ((void*)(dst), (mask), (src_top), (src_bottom), (width), (weight_top), \ - (weight_bottom), (vx), (unit_x), (max_vx), (zero_src)); \ - } \ - } while (0) - - -#define SCANLINE_BUFFER_LENGTH 3072 - -#define FAST_BILINEAR_MAINLOOP_INT(scale_func_name, fetch_func, op_func, src_type_t, \ - mask_type_t, dst_type_t, repeat_mode, flags) \ +#define FAST_BILINEAR_MAINLOOP_INT(scale_func_name, scanline_func, src_type_t, mask_type_t, \ + dst_type_t, repeat_mode, flags) \ static void \ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, \ pixman_composite_info_t *info) \ @@ -908,9 +876,6 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, pixman_fixed_t src_width_fixed; \ int max_x; \ pixman_bool_t need_src_extension; \ - \ - uint64_t stack_scanline_buffer[SCANLINE_BUFFER_LENGTH]; \ - uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer; \ \ PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type_t, dst_stride, dst_line, 1); \ if (flags & FLAG_HAVE_SOLID_MASK) \ @@ -983,14 +948,6 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, \ src_width_fixed = pixman_int_to_fixed (src_width); \ } \ - \ - if (op_func != NULL && width * sizeof(src_type_t) > sizeof(stack_scanline_buffer)) \ - { \ - scanline_buffer = pixman_malloc_ab (width, sizeof(src_type_t)); \ - \ - if (!scanline_buffer) \ - return; \ - } \ \ while (--height >= 0) \ { \ @@ -1033,18 +990,16 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, { \ buf1[0] = buf1[1] = src1[0]; \ buf2[0] = buf2[1] = src2[0]; \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, dst, \ - scanline_buffer, mask, buf1, buf2, left_pad, weight1, weight2, \ - 0, 0, 0, FALSE); \ + scanline_func (dst, mask, \ + buf1, buf2, left_pad, weight1, weight2, 0, 0, 0, FALSE); \ dst += left_pad; \ if (flags & FLAG_HAVE_NON_SOLID_MASK) \ mask += left_pad; \ } \ if (width > 0) \ { \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, dst, \ - scanline_buffer, mask, src1, src2, width, weight1, weight2, \ - vx, unit_x, 0, FALSE); \ + scanline_func (dst, mask, \ + src1, src2, width, weight1, weight2, vx, unit_x, 0, FALSE); \ dst += width; \ if (flags & FLAG_HAVE_NON_SOLID_MASK) \ mask += width; \ @@ -1053,9 +1008,8 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, { \ buf1[0] = buf1[1] = src1[src_image->bits.width - 1]; \ buf2[0] = buf2[1] = src2[src_image->bits.width - 1]; \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, dst, \ - scanline_buffer, mask, buf1, buf2, right_pad, weight1, weight2, \ - 0, 0, 0, FALSE); \ + scanline_func (dst, mask, \ + buf1, buf2, right_pad, weight1, weight2, 0, 0, 0, FALSE); \ } \ } \ else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \ @@ -1091,9 +1045,8 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, { \ buf1[0] = buf1[1] = 0; \ buf2[0] = buf2[1] = 0; \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, dst, \ - scanline_buffer, mask, buf1, buf2, left_pad, weight1, weight2, \ - 0, 0, 0, TRUE); \ + scanline_func (dst, mask, \ + buf1, buf2, left_pad, weight1, weight2, 0, 0, 0, TRUE); \ dst += left_pad; \ if (flags & FLAG_HAVE_NON_SOLID_MASK) \ mask += left_pad; \ @@ -1104,8 +1057,8 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, buf1[1] = src1[0]; \ buf2[0] = 0; \ buf2[1] = src2[0]; \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, dst, \ - scanline_buffer, mask, buf1, buf2, left_tz, weight1, weight2, \ + scanline_func (dst, mask, \ + buf1, buf2, left_tz, weight1, weight2, \ pixman_fixed_frac (vx), unit_x, 0, FALSE); \ dst += left_tz; \ if (flags & FLAG_HAVE_NON_SOLID_MASK) \ @@ -1114,9 +1067,8 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, } \ if (width > 0) \ { \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, dst, \ - scanline_buffer, mask, src1, src2, width, weight1, weight2, \ - vx, unit_x, 0, FALSE); \ + scanline_func (dst, mask, \ + src1, src2, width, weight1, weight2, vx, unit_x, 0, FALSE); \ dst += width; \ if (flags & FLAG_HAVE_NON_SOLID_MASK) \ mask += width; \ @@ -1128,8 +1080,8 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, buf1[1] = 0; \ buf2[0] = src2[src_image->bits.width - 1]; \ buf2[1] = 0; \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, dst, \ - scanline_buffer, mask, buf1, buf2, right_tz, weight1, weight2, \ + scanline_func (dst, mask, \ + buf1, buf2, right_tz, weight1, weight2, \ pixman_fixed_frac (vx), unit_x, 0, FALSE); \ dst += right_tz; \ if (flags & FLAG_HAVE_NON_SOLID_MASK) \ @@ -1139,9 +1091,8 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, { \ buf1[0] = buf1[1] = 0; \ buf2[0] = buf2[1] = 0; \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, dst, \ - scanline_buffer, mask, buf1, buf2, right_pad, weight1, weight2, \ - 0, 0, 0, TRUE); \ + scanline_func (dst, mask, \ + buf1, buf2, right_pad, weight1, weight2, 0, 0, 0, TRUE); \ } \ } \ else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \ @@ -1203,8 +1154,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, if (num_pixels > width_remain) \ num_pixels = width_remain; \ \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, \ - dst, scanline_buffer, mask, buf1, buf2, num_pixels, \ + scanline_func (dst, mask, buf1, buf2, num_pixels, \ weight1, weight2, pixman_fixed_frac(vx), \ unit_x, src_width_fixed, FALSE); \ \ @@ -1233,10 +1183,8 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, if (num_pixels > width_remain) \ num_pixels = width_remain; \ \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, \ - dst, scanline_buffer, mask, src_line_top, src_line_bottom, \ - num_pixels, weight1, weight2, vx, unit_x, src_width_fixed, \ - FALSE); \ + scanline_func (dst, mask, src_line_top, src_line_bottom, num_pixels, \ + weight1, weight2, vx, unit_x, src_width_fixed, FALSE); \ \ width_remain -= num_pixels; \ vx += num_pixels * unit_x; \ @@ -1249,21 +1197,17 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, } \ else \ { \ - scanline_func (dst_type_t, mask_type_t, src_type_t, fetch_func, op_func, dst, \ - scanline_buffer, mask, \ - src_first_line + src_stride * y1, \ + scanline_func (dst, mask, src_first_line + src_stride * y1, \ src_first_line + src_stride * y2, width, \ weight1, weight2, vx, unit_x, max_vx, FALSE); \ } \ } \ - if (scanline_buffer != (uint8_t *) stack_scanline_buffer) \ - free (scanline_buffer); \ } /* A workaround for old sun studio, see: https://bugs.freedesktop.org/show_bug.cgi?id=32764 */ -#define FAST_BILINEAR_MAINLOOP_COMMON(scale_func_name, fetch_func, op_func, src_type_t, mask_type_t,\ +#define FAST_BILINEAR_MAINLOOP_COMMON(scale_func_name, scanline_func, src_type_t, mask_type_t, \ dst_type_t, repeat_mode, flags) \ - FAST_BILINEAR_MAINLOOP_INT(_ ## scale_func_name, fetch_func, op_func, src_type_t, mask_type_t,\ + FAST_BILINEAR_MAINLOOP_INT(_ ## scale_func_name, scanline_func, src_type_t, mask_type_t,\ dst_type_t, repeat_mode, flags) #define SCALED_BILINEAR_FLAGS \ diff --git a/gfx/cairo/libpixman/src/pixman-linear-gradient.c b/gfx/cairo/libpixman/src/pixman-linear-gradient.c index f5ba51b604..3f528508a1 100644 --- a/gfx/cairo/libpixman/src/pixman-linear-gradient.c +++ b/gfx/cairo/libpixman/src/pixman-linear-gradient.c @@ -31,8 +31,6 @@ #include #include "pixman-private.h" -#include "pixman-dither.h" - static pixman_bool_t linear_gradient_is_horizontal (pixman_image_t *image, int x, @@ -91,8 +89,11 @@ linear_gradient_is_horizontal (pixman_image_t *image, } static uint32_t * -linear_get_scanline_narrow (pixman_iter_t *iter, - const uint32_t *mask) +linear_get_scanline (pixman_iter_t *iter, + const uint32_t *mask, + int Bpp, + pixman_gradient_walker_write_t write_pixel, + pixman_gradient_walker_fill_t fill_pixel) { pixman_image_t *image = iter->image; int x = iter->x; @@ -105,7 +106,7 @@ linear_get_scanline_narrow (pixman_iter_t *iter, pixman_fixed_48_16_t dx, dy; gradient_t *gradient = (gradient_t *)image; linear_gradient_t *linear = (linear_gradient_t *)image; - uint32_t *end = buffer + width; + uint32_t *end = buffer + width * (Bpp / 4); pixman_gradient_walker_t walker; _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); @@ -139,7 +140,7 @@ linear_get_scanline_narrow (pixman_iter_t *iter, if (l == 0 || unit.vector[2] == 0) { /* affine transformation only */ - pixman_fixed_32_32_t t, next_inc; + pixman_fixed_32_32_t t, next_inc; double inc; if (l == 0 || v.vector[2] == 0) @@ -154,7 +155,7 @@ linear_get_scanline_narrow (pixman_iter_t *iter, invden = pixman_fixed_1 * (double) pixman_fixed_1 / (l * (double) v.vector[2]); v2 = v.vector[2] * (1. / pixman_fixed_1); - t = ((dx * v.vector[0] + dy * v.vector[1]) - + t = ((dx * v.vector[0] + dy * v.vector[1]) - (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden; } @@ -162,11 +163,7 @@ linear_get_scanline_narrow (pixman_iter_t *iter, if (((pixman_fixed_32_32_t )(inc * width)) == 0) { - register uint32_t color; - - color = _pixman_gradient_walker_pixel (&walker, t); - while (buffer < end) - *buffer++ = color; + fill_pixel (&walker, t, buffer, end); } else { @@ -177,12 +174,11 @@ linear_get_scanline_narrow (pixman_iter_t *iter, { if (!mask || *mask++) { - *buffer = _pixman_gradient_walker_pixel (&walker, - t + next_inc); + write_pixel (&walker, t + next_inc, buffer); } i++; next_inc = inc * i; - buffer++; + buffer += (Bpp / 4); } } } @@ -204,14 +200,14 @@ linear_get_scanline_narrow (pixman_iter_t *iter, invden = pixman_fixed_1 * (double) pixman_fixed_1 / (l * (double) v.vector[2]); v2 = v.vector[2] * (1. / pixman_fixed_1); - t = ((dx * v.vector[0] + dy * v.vector[1]) - + t = ((dx * v.vector[0] + dy * v.vector[1]) - (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; } - *buffer = _pixman_gradient_walker_pixel (&walker, t); + write_pixel (&walker, t, buffer); } - ++buffer; + buffer += (Bpp / 4); v.vector[0] += unit.vector[0]; v.vector[1] += unit.vector[1]; @@ -225,176 +221,30 @@ linear_get_scanline_narrow (pixman_iter_t *iter, } static uint32_t * -linear_get_scanline_16 (pixman_iter_t *iter, - const uint32_t *mask) +linear_get_scanline_narrow (pixman_iter_t *iter, + const uint32_t *mask) { - pixman_image_t *image = iter->image; - int x = iter->x; - int y = iter->y; - int width = iter->width; - uint16_t * buffer = (uint16_t*)iter->buffer; - pixman_bool_t toggle = ((x ^ y) & 1); - - pixman_vector_t v, unit; - pixman_fixed_32_32_t l; - pixman_fixed_48_16_t dx, dy; - gradient_t *gradient = (gradient_t *)image; - linear_gradient_t *linear = (linear_gradient_t *)image; - uint16_t *end = buffer + width; - pixman_gradient_walker_t walker; - - _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); - - /* reference point is the center of the pixel */ - v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; - v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; - v.vector[2] = pixman_fixed_1; - - if (image->common.transform) - { - if (!pixman_transform_point_3d (image->common.transform, &v)) - return iter->buffer; - - unit.vector[0] = image->common.transform->matrix[0][0]; - unit.vector[1] = image->common.transform->matrix[1][0]; - unit.vector[2] = image->common.transform->matrix[2][0]; - } - else - { - unit.vector[0] = pixman_fixed_1; - unit.vector[1] = 0; - unit.vector[2] = 0; - } - - dx = linear->p2.x - linear->p1.x; - dy = linear->p2.y - linear->p1.y; - - l = dx * dx + dy * dy; - - if (l == 0 || unit.vector[2] == 0) - { - /* affine transformation only */ - pixman_fixed_32_32_t t, next_inc; - double inc; - - if (l == 0 || v.vector[2] == 0) - { - t = 0; - inc = 0; - } - else - { - double invden, v2; - - invden = pixman_fixed_1 * (double) pixman_fixed_1 / - (l * (double) v.vector[2]); - v2 = v.vector[2] * (1. / pixman_fixed_1); - t = ((dx * v.vector[0] + dy * v.vector[1]) - - (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; - inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden; - } - next_inc = 0; - - if (((pixman_fixed_32_32_t )(inc * width)) == 0) - { - register uint32_t color; - uint16_t dither_diff; - uint16_t color16; - uint16_t color16b; - - color = _pixman_gradient_walker_pixel (&walker, t); - color16 = dither_8888_to_0565(color, toggle); - color16b = dither_8888_to_0565(color, toggle^1); - // compute the difference - dither_diff = color16 ^ color16b; - while (buffer < end) { - *buffer++ = color16; - // use dither_diff to toggle between color16 and color16b - color16 ^= dither_diff; - toggle ^= 1; - } - } - else - { - int i; - - i = 0; - while (buffer < end) - { - if (!mask || *mask++) - { - *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, - t + next_inc), - toggle); - } - toggle ^= 1; - i++; - next_inc = inc * i; - buffer++; - } - } - } - else - { - /* projective transformation */ - double t; - - t = 0; - - while (buffer < end) - { - if (!mask || *mask++) - { - if (v.vector[2] != 0) - { - double invden, v2; - - invden = pixman_fixed_1 * (double) pixman_fixed_1 / - (l * (double) v.vector[2]); - v2 = v.vector[2] * (1. / pixman_fixed_1); - t = ((dx * v.vector[0] + dy * v.vector[1]) - - (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; - } - - *buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t), - toggle); - } - toggle ^= 1; - - ++buffer; - - v.vector[0] += unit.vector[0]; - v.vector[1] += unit.vector[1]; - v.vector[2] += unit.vector[2]; - } - } - - iter->y++; - - return iter->buffer; + return linear_get_scanline (iter, mask, 4, + _pixman_gradient_walker_write_narrow, + _pixman_gradient_walker_fill_narrow); } + static uint32_t * linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) { - uint32_t *buffer = linear_get_scanline_narrow (iter, NULL); - - pixman_expand_to_float ( - (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); - - return buffer; + return linear_get_scanline (iter, NULL, 16, + _pixman_gradient_walker_write_wide, + _pixman_gradient_walker_fill_wide); } void _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) { - // XXX: we can't use this optimization when dithering - if (0 && linear_gradient_is_horizontal ( + if (linear_gradient_is_horizontal ( iter->image, iter->x, iter->y, iter->width, iter->height)) { - if (iter->iter_flags & ITER_16) - linear_get_scanline_16 (iter, NULL); - else if (iter->iter_flags & ITER_NARROW) + if (iter->iter_flags & ITER_NARROW) linear_get_scanline_narrow (iter, NULL); else linear_get_scanline_wide (iter, NULL); @@ -403,9 +253,7 @@ _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) } else { - if (iter->iter_flags & ITER_16) - iter->get_scanline = linear_get_scanline_16; - else if (iter->iter_flags & ITER_NARROW) + if (iter->iter_flags & ITER_NARROW) iter->get_scanline = linear_get_scanline_narrow; else iter->get_scanline = linear_get_scanline_wide; diff --git a/gfx/cairo/libpixman/src/pixman-matrix.c b/gfx/cairo/libpixman/src/pixman-matrix.c index 89b96826b8..81b6e613ed 100644 --- a/gfx/cairo/libpixman/src/pixman-matrix.c +++ b/gfx/cairo/libpixman/src/pixman-matrix.c @@ -37,7 +37,7 @@ static force_inline int count_leading_zeros (uint32_t x) { -#ifdef __GNUC__ +#ifdef HAVE_BUILTIN_CLZ return __builtin_clz (x); #else int n = 0; @@ -273,7 +273,7 @@ pixman_transform_point_31_16 (const pixman_transform_t *t, { /* the divisor is small, we can actually keep all the bits */ int64_t hi, rhi, lo, rlo; - int64_t div = (divint << 16) + divfrac; + int64_t div = ((uint64_t)divint << 16) + divfrac; fixed_64_16_to_int128 (tmp[0][0], tmp[0][1], &hi, &lo, 32); rlo = rounded_sdiv_128_by_49 (hi, lo, div, &rhi); diff --git a/gfx/cairo/libpixman/src/pixman-mips-dspr2-asm.S b/gfx/cairo/libpixman/src/pixman-mips-dspr2-asm.S index ddfacef62e..9dad163b79 100644 --- a/gfx/cairo/libpixman/src/pixman-mips-dspr2-asm.S +++ b/gfx/cairo/libpixman/src/pixman-mips-dspr2-asm.S @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Author: Nemanja Lukic (nlukic@mips.com) + * Author: Nemanja Lukic (nemanja.lukic@rt-rk.com) */ #include "pixman-private.h" @@ -310,6 +310,516 @@ LEAF_MIPS_DSPR2(pixman_composite_src_x888_8888_asm_mips) END(pixman_composite_src_x888_8888_asm_mips) +#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) +LEAF_MIPS_DSPR2(pixman_composite_src_0888_8888_rev_asm_mips) +/* + * a0 - dst (a8r8g8b8) + * a1 - src (b8g8r8) + * a2 - w + */ + + beqz a2, 6f + nop + + lui t8, 0xff00; + srl t9, a2, 2 /* t9 = how many multiples of 4 src pixels */ + beqz t9, 4f /* branch if less than 4 src pixels */ + nop + + li t0, 0x1 + li t1, 0x2 + li t2, 0x3 + andi t3, a1, 0x3 + beq t3, t0, 1f + nop + beq t3, t1, 2f + nop + beq t3, t2, 3f + nop + +0: + beqz t9, 4f + addiu t9, t9, -1 + lw t0, 0(a1) /* t0 = R2 | B1 | G1 | R1 */ + lw t1, 4(a1) /* t1 = G3 | R3 | B2 | G2 */ + lw t2, 8(a1) /* t2 = B4 | G4 | R4 | B3 */ + + addiu a1, a1, 12 + addiu a2, a2, -4 + + wsbh t0, t0 /* t0 = B1 | R2 | R1 | G1 */ + wsbh t1, t1 /* t1 = R3 | G3 | G2 | B2 */ + wsbh t2, t2 /* t2 = G4 | B4 | B3 | R4 */ + + packrl.ph t3, t1, t0 /* t3 = G2 | B2 | B1 | R2 */ + packrl.ph t4, t0, t0 /* t4 = R1 | G1 | B1 | R2 */ + rotr t3, t3, 16 /* t3 = B1 | R2 | G2 | B2 */ + or t3, t3, t8 /* t3 = FF | R2 | G2 | B2 */ + srl t4, t4, 8 /* t4 = 0 | R1 | G1 | B1 */ + or t4, t4, t8 /* t4 = FF | R1 | G1 | B1 */ + packrl.ph t5, t2, t1 /* t5 = B3 | R4 | R3 | G3 */ + rotr t5, t5, 24 /* t5 = R4 | R3 | G3 | B3 */ + or t5, t5, t8 /* t5 = FF | R3 | G3 | B3 */ + rotr t2, t2, 16 /* t2 = B3 | R4 | G4 | B4 */ + or t2, t2, t8 /* t5 = FF | R3 | G3 | B3 */ + + sw t4, 0(a0) + sw t3, 4(a0) + sw t5, 8(a0) + sw t2, 12(a0) + b 0b + addiu a0, a0, 16 + +1: + lbu t6, 0(a1) /* t6 = 0 | 0 | 0 | R1 */ + lhu t7, 1(a1) /* t7 = 0 | 0 | B1 | G1 */ + sll t6, t6, 16 /* t6 = 0 | R1 | 0 | 0 */ + wsbh t7, t7 /* t7 = 0 | 0 | G1 | B1 */ + or t7, t6, t7 /* t7 = 0 | R1 | G1 | B1 */ +11: + beqz t9, 4f + addiu t9, t9, -1 + lw t0, 3(a1) /* t0 = R3 | B2 | G2 | R2 */ + lw t1, 7(a1) /* t1 = G4 | R4 | B3 | G3 */ + lw t2, 11(a1) /* t2 = B5 | G5 | R5 | B4 */ + + addiu a1, a1, 12 + addiu a2, a2, -4 + + wsbh t0, t0 /* t0 = B2 | R3 | R2 | G2 */ + wsbh t1, t1 /* t1 = R4 | G4 | G3 | B3 */ + wsbh t2, t2 /* t2 = G5 | B5 | B4 | R5 */ + + packrl.ph t3, t1, t0 /* t3 = G3 | B3 | B2 | R3 */ + packrl.ph t4, t2, t1 /* t4 = B4 | R5 | R4 | G4 */ + rotr t0, t0, 24 /* t0 = R3 | R2 | G2 | B2 */ + rotr t3, t3, 16 /* t3 = B2 | R3 | G3 | B3 */ + rotr t4, t4, 24 /* t4 = R5 | R4 | G4 | B4 */ + or t7, t7, t8 /* t7 = FF | R1 | G1 | B1 */ + or t0, t0, t8 /* t0 = FF | R2 | G2 | B2 */ + or t3, t3, t8 /* t1 = FF | R3 | G3 | B3 */ + or t4, t4, t8 /* t3 = FF | R4 | G4 | B4 */ + + sw t7, 0(a0) + sw t0, 4(a0) + sw t3, 8(a0) + sw t4, 12(a0) + rotr t7, t2, 16 /* t7 = xx | R5 | G5 | B5 */ + b 11b + addiu a0, a0, 16 + +2: + lhu t7, 0(a1) /* t7 = 0 | 0 | G1 | R1 */ + wsbh t7, t7 /* t7 = 0 | 0 | R1 | G1 */ +21: + beqz t9, 4f + addiu t9, t9, -1 + lw t0, 2(a1) /* t0 = B2 | G2 | R2 | B1 */ + lw t1, 6(a1) /* t1 = R4 | B3 | G3 | R3 */ + lw t2, 10(a1) /* t2 = G5 | R5 | B4 | G4 */ + + addiu a1, a1, 12 + addiu a2, a2, -4 + + wsbh t0, t0 /* t0 = G2 | B2 | B1 | R2 */ + wsbh t1, t1 /* t1 = B3 | R4 | R3 | G3 */ + wsbh t2, t2 /* t2 = R5 | G5 | G4 | B4 */ + + precr_sra.ph.w t7, t0, 0 /* t7 = R1 | G1 | B1 | R2 */ + rotr t0, t0, 16 /* t0 = B1 | R2 | G2 | B2 */ + packrl.ph t3, t2, t1 /* t3 = G4 | B4 | B3 | R4 */ + rotr t1, t1, 24 /* t1 = R4 | R3 | G3 | B3 */ + srl t7, t7, 8 /* t7 = 0 | R1 | G1 | B1 */ + rotr t3, t3, 16 /* t3 = B3 | R4 | G4 | B4 */ + or t7, t7, t8 /* t7 = FF | R1 | G1 | B1 */ + or t0, t0, t8 /* t0 = FF | R2 | G2 | B2 */ + or t1, t1, t8 /* t1 = FF | R3 | G3 | B3 */ + or t3, t3, t8 /* t3 = FF | R4 | G4 | B4 */ + + sw t7, 0(a0) + sw t0, 4(a0) + sw t1, 8(a0) + sw t3, 12(a0) + srl t7, t2, 16 /* t7 = 0 | 0 | R5 | G5 */ + b 21b + addiu a0, a0, 16 + +3: + lbu t7, 0(a1) /* t7 = 0 | 0 | 0 | R1 */ +31: + beqz t9, 4f + addiu t9, t9, -1 + lw t0, 1(a1) /* t0 = G2 | R2 | B1 | G1 */ + lw t1, 5(a1) /* t1 = B3 | G3 | R3 | B2 */ + lw t2, 9(a1) /* t2 = R5 | B4 | G4 | R4 */ + + addiu a1, a1, 12 + addiu a2, a2, -4 + + wsbh t0, t0 /* t0 = R2 | G2 | G1 | B1 */ + wsbh t1, t1 /* t1 = G3 | B3 | B2 | R3 */ + wsbh t2, t2 /* t2 = B4 | R5 | R4 | G4 */ + + precr_sra.ph.w t7, t0, 0 /* t7 = xx | R1 | G1 | B1 */ + packrl.ph t3, t1, t0 /* t3 = B2 | R3 | R2 | G2 */ + rotr t1, t1, 16 /* t1 = B2 | R3 | G3 | B3 */ + rotr t4, t2, 24 /* t4 = R5 | R4 | G4 | B4 */ + rotr t3, t3, 24 /* t3 = R3 | R2 | G2 | B2 */ + or t7, t7, t8 /* t7 = FF | R1 | G1 | B1 */ + or t3, t3, t8 /* t3 = FF | R2 | G2 | B2 */ + or t1, t1, t8 /* t1 = FF | R3 | G3 | B3 */ + or t4, t4, t8 /* t4 = FF | R4 | G4 | B4 */ + + sw t7, 0(a0) + sw t3, 4(a0) + sw t1, 8(a0) + sw t4, 12(a0) + srl t7, t2, 16 /* t7 = 0 | 0 | xx | R5 */ + b 31b + addiu a0, a0, 16 + +4: + beqz a2, 6f + nop +5: + lbu t0, 0(a1) /* t0 = 0 | 0 | 0 | R */ + lbu t1, 1(a1) /* t1 = 0 | 0 | 0 | G */ + lbu t2, 2(a1) /* t2 = 0 | 0 | 0 | B */ + addiu a1, a1, 3 + + sll t0, t0, 16 /* t2 = 0 | R | 0 | 0 */ + sll t1, t1, 8 /* t1 = 0 | 0 | G | 0 */ + + or t2, t2, t1 /* t2 = 0 | 0 | G | B */ + or t2, t2, t0 /* t2 = 0 | R | G | B */ + or t2, t2, t8 /* t2 = FF | R | G | B */ + + sw t2, 0(a0) + addiu a2, a2, -1 + bnez a2, 5b + addiu a0, a0, 4 +6: + j ra + nop + +END(pixman_composite_src_0888_8888_rev_asm_mips) + +LEAF_MIPS_DSPR2(pixman_composite_src_0888_0565_rev_asm_mips) +/* + * a0 - dst (r5g6b5) + * a1 - src (b8g8r8) + * a2 - w + */ + + SAVE_REGS_ON_STACK 0, v0, v1 + beqz a2, 6f + nop + + li t6, 0xf800f800 + li t7, 0x07e007e0 + li t8, 0x001F001F + srl t9, a2, 2 /* t9 = how many multiples of 4 src pixels */ + beqz t9, 4f /* branch if less than 4 src pixels */ + nop + + li t0, 0x1 + li t1, 0x2 + li t2, 0x3 + andi t3, a1, 0x3 + beq t3, t0, 1f + nop + beq t3, t1, 2f + nop + beq t3, t2, 3f + nop + +0: + beqz t9, 4f + addiu t9, t9, -1 + lw t0, 0(a1) /* t0 = R2 | B1 | G1 | R1 */ + lw t1, 4(a1) /* t1 = G3 | R3 | B2 | G2 */ + lw t2, 8(a1) /* t2 = B4 | G4 | R4 | B3 */ + + addiu a1, a1, 12 + addiu a2, a2, -4 + + wsbh t0, t0 /* t0 = B1 | R2 | R1 | G1 */ + wsbh t1, t1 /* t1 = R3 | G3 | G2 | B2 */ + wsbh t2, t2 /* t2 = G4 | B4 | B3 | R4 */ + + packrl.ph t3, t1, t0 /* t3 = G2 | B2 | B1 | R2 */ + packrl.ph t4, t0, t0 /* t4 = R1 | G1 | B1 | R2 */ + rotr t3, t3, 16 /* t3 = B1 | R2 | G2 | B2 */ + srl t4, t4, 8 /* t4 = 0 | R1 | G1 | B1 */ + packrl.ph t5, t2, t1 /* t5 = B3 | R4 | R3 | G3 */ + rotr t5, t5, 24 /* t5 = R4 | R3 | G3 | B3 */ + rotr t2, t2, 16 /* t2 = B3 | R4 | G4 | B4 */ + + CONVERT_2x8888_TO_2x0565 t4, t3, t4, t3, t6, t7, t8, v0, v1 + CONVERT_2x8888_TO_2x0565 t5, t2, t5, t2, t6, t7, t8, v0, v1 + + sh t4, 0(a0) + sh t3, 2(a0) + sh t5, 4(a0) + sh t2, 6(a0) + b 0b + addiu a0, a0, 8 + +1: + lbu t4, 0(a1) /* t4 = 0 | 0 | 0 | R1 */ + lhu t5, 1(a1) /* t5 = 0 | 0 | B1 | G1 */ + sll t4, t4, 16 /* t4 = 0 | R1 | 0 | 0 */ + wsbh t5, t5 /* t5 = 0 | 0 | G1 | B1 */ + or t5, t4, t5 /* t5 = 0 | R1 | G1 | B1 */ +11: + beqz t9, 4f + addiu t9, t9, -1 + lw t0, 3(a1) /* t0 = R3 | B2 | G2 | R2 */ + lw t1, 7(a1) /* t1 = G4 | R4 | B3 | G3 */ + lw t2, 11(a1) /* t2 = B5 | G5 | R5 | B4 */ + + addiu a1, a1, 12 + addiu a2, a2, -4 + + wsbh t0, t0 /* t0 = B2 | R3 | R2 | G2 */ + wsbh t1, t1 /* t1 = R4 | G4 | G3 | B3 */ + wsbh t2, t2 /* t2 = G5 | B5 | B4 | R5 */ + + packrl.ph t3, t1, t0 /* t3 = G3 | B3 | B2 | R3 */ + packrl.ph t4, t2, t1 /* t4 = B4 | R5 | R4 | G4 */ + rotr t0, t0, 24 /* t0 = R3 | R2 | G2 | B2 */ + rotr t3, t3, 16 /* t3 = B2 | R3 | G3 | B3 */ + rotr t4, t4, 24 /* t4 = R5 | R4 | G4 | B4 */ + + CONVERT_2x8888_TO_2x0565 t5, t0, t5, t0, t6, t7, t8, v0, v1 + CONVERT_2x8888_TO_2x0565 t3, t4, t3, t4, t6, t7, t8, v0, v1 + + sh t5, 0(a0) + sh t0, 2(a0) + sh t3, 4(a0) + sh t4, 6(a0) + rotr t5, t2, 16 /* t5 = xx | R5 | G5 | B5 */ + b 11b + addiu a0, a0, 8 + +2: + lhu t5, 0(a1) /* t5 = 0 | 0 | G1 | R1 */ + wsbh t5, t5 /* t5 = 0 | 0 | R1 | G1 */ +21: + beqz t9, 4f + addiu t9, t9, -1 + lw t0, 2(a1) /* t0 = B2 | G2 | R2 | B1 */ + lw t1, 6(a1) /* t1 = R4 | B3 | G3 | R3 */ + lw t2, 10(a1) /* t2 = G5 | R5 | B4 | G4 */ + + addiu a1, a1, 12 + addiu a2, a2, -4 + + wsbh t0, t0 /* t0 = G2 | B2 | B1 | R2 */ + wsbh t1, t1 /* t1 = B3 | R4 | R3 | G3 */ + wsbh t2, t2 /* t2 = R5 | G5 | G4 | B4 */ + + precr_sra.ph.w t5, t0, 0 /* t5 = R1 | G1 | B1 | R2 */ + rotr t0, t0, 16 /* t0 = B1 | R2 | G2 | B2 */ + packrl.ph t3, t2, t1 /* t3 = G4 | B4 | B3 | R4 */ + rotr t1, t1, 24 /* t1 = R4 | R3 | G3 | B3 */ + srl t5, t5, 8 /* t5 = 0 | R1 | G1 | B1 */ + rotr t3, t3, 16 /* t3 = B3 | R4 | G4 | B4 */ + + CONVERT_2x8888_TO_2x0565 t5, t0, t5, t0, t6, t7, t8, v0, v1 + CONVERT_2x8888_TO_2x0565 t1, t3, t1, t3, t6, t7, t8, v0, v1 + + sh t5, 0(a0) + sh t0, 2(a0) + sh t1, 4(a0) + sh t3, 6(a0) + srl t5, t2, 16 /* t5 = 0 | 0 | R5 | G5 */ + b 21b + addiu a0, a0, 8 + +3: + lbu t5, 0(a1) /* t5 = 0 | 0 | 0 | R1 */ +31: + beqz t9, 4f + addiu t9, t9, -1 + lw t0, 1(a1) /* t0 = G2 | R2 | B1 | G1 */ + lw t1, 5(a1) /* t1 = B3 | G3 | R3 | B2 */ + lw t2, 9(a1) /* t2 = R5 | B4 | G4 | R4 */ + + addiu a1, a1, 12 + addiu a2, a2, -4 + + wsbh t0, t0 /* t0 = R2 | G2 | G1 | B1 */ + wsbh t1, t1 /* t1 = G3 | B3 | B2 | R3 */ + wsbh t2, t2 /* t2 = B4 | R5 | R4 | G4 */ + + precr_sra.ph.w t5, t0, 0 /* t5 = xx | R1 | G1 | B1 */ + packrl.ph t3, t1, t0 /* t3 = B2 | R3 | R2 | G2 */ + rotr t1, t1, 16 /* t1 = B2 | R3 | G3 | B3 */ + rotr t4, t2, 24 /* t4 = R5 | R4 | G4 | B4 */ + rotr t3, t3, 24 /* t3 = R3 | R2 | G2 | B2 */ + + CONVERT_2x8888_TO_2x0565 t5, t3, t5, t3, t6, t7, t8, v0, v1 + CONVERT_2x8888_TO_2x0565 t1, t4, t1, t4, t6, t7, t8, v0, v1 + + sh t5, 0(a0) + sh t3, 2(a0) + sh t1, 4(a0) + sh t4, 6(a0) + srl t5, t2, 16 /* t5 = 0 | 0 | xx | R5 */ + b 31b + addiu a0, a0, 8 + +4: + beqz a2, 6f + nop +5: + lbu t0, 0(a1) /* t0 = 0 | 0 | 0 | R */ + lbu t1, 1(a1) /* t1 = 0 | 0 | 0 | G */ + lbu t2, 2(a1) /* t2 = 0 | 0 | 0 | B */ + addiu a1, a1, 3 + + sll t0, t0, 16 /* t2 = 0 | R | 0 | 0 */ + sll t1, t1, 8 /* t1 = 0 | 0 | G | 0 */ + + or t2, t2, t1 /* t2 = 0 | 0 | G | B */ + or t2, t2, t0 /* t2 = 0 | R | G | B */ + + CONVERT_1x8888_TO_1x0565 t2, t3, t4, t5 + + sh t3, 0(a0) + addiu a2, a2, -1 + bnez a2, 5b + addiu a0, a0, 2 +6: + RESTORE_REGS_FROM_STACK 0, v0, v1 + j ra + nop + +END(pixman_composite_src_0888_0565_rev_asm_mips) +#endif + +LEAF_MIPS_DSPR2(pixman_composite_src_pixbuf_8888_asm_mips) +/* + * a0 - dst (a8b8g8r8) + * a1 - src (a8r8g8b8) + * a2 - w + */ + + SAVE_REGS_ON_STACK 0, v0 + li v0, 0x00ff00ff + + beqz a2, 3f + nop + addiu t1, a2, -1 + beqz t1, 2f + nop +1: + lw t0, 0(a1) + lw t1, 4(a1) + addiu a1, a1, 8 + addiu a2, a2, -2 + srl t2, t0, 24 + srl t3, t1, 24 + + MIPS_2xUN8x4_MUL_2xUN8 t0, t1, t2, t3, t0, t1, v0, t4, t5, t6, t7, t8, t9 + + sll t0, t0, 8 + sll t1, t1, 8 + andi t2, t2, 0xff + andi t3, t3, 0xff + or t0, t0, t2 + or t1, t1, t3 + wsbh t0, t0 + wsbh t1, t1 + rotr t0, t0, 16 + rotr t1, t1, 16 + sw t0, 0(a0) + sw t1, 4(a0) + + addiu t2, a2, -1 + bgtz t2, 1b + addiu a0, a0, 8 +2: + beqz a2, 3f + nop + lw t0, 0(a1) + srl t1, t0, 24 + + MIPS_UN8x4_MUL_UN8 t0, t1, t0, v0, t3, t4, t5 + + sll t0, t0, 8 + andi t1, t1, 0xff + or t0, t0, t1 + wsbh t0, t0 + rotr t0, t0, 16 + sw t0, 0(a0) +3: + RESTORE_REGS_FROM_STACK 0, v0 + j ra + nop + +END(pixman_composite_src_pixbuf_8888_asm_mips) + +LEAF_MIPS_DSPR2(pixman_composite_src_rpixbuf_8888_asm_mips) +/* + * a0 - dst (a8r8g8b8) + * a1 - src (a8r8g8b8) + * a2 - w + */ + + SAVE_REGS_ON_STACK 0, v0 + li v0, 0x00ff00ff + + beqz a2, 3f + nop + addiu t1, a2, -1 + beqz t1, 2f + nop +1: + lw t0, 0(a1) + lw t1, 4(a1) + addiu a1, a1, 8 + addiu a2, a2, -2 + srl t2, t0, 24 + srl t3, t1, 24 + + MIPS_2xUN8x4_MUL_2xUN8 t0, t1, t2, t3, t0, t1, v0, t4, t5, t6, t7, t8, t9 + + sll t0, t0, 8 + sll t1, t1, 8 + andi t2, t2, 0xff + andi t3, t3, 0xff + or t0, t0, t2 + or t1, t1, t3 + rotr t0, t0, 8 + rotr t1, t1, 8 + sw t0, 0(a0) + sw t1, 4(a0) + + addiu t2, a2, -1 + bgtz t2, 1b + addiu a0, a0, 8 +2: + beqz a2, 3f + nop + lw t0, 0(a1) + srl t1, t0, 24 + + MIPS_UN8x4_MUL_UN8 t0, t1, t0, v0, t3, t4, t5 + + sll t0, t0, 8 + andi t1, t1, 0xff + or t0, t0, t1 + rotr t0, t0, 8 + sw t0, 0(a0) +3: + RESTORE_REGS_FROM_STACK 0, v0 + j ra + nop + +END(pixman_composite_src_rpixbuf_8888_asm_mips) + LEAF_MIPS_DSPR2(pixman_composite_src_n_8_8888_asm_mips) /* * a0 - dst (a8r8g8b8) @@ -451,34 +961,35 @@ LEAF_MIPS_DSPR2(pixman_composite_over_n_8888_8888_ca_asm_mips) * a3 - w */ - SAVE_REGS_ON_STACK 8, s0, s1, s2, s3, s4, s5 - beqz a3, 4f + beqz a3, 8f nop + SAVE_REGS_ON_STACK 8, s0, s1, s2, s3, s4, s5 + li t6, 0xff addiu t7, zero, -1 /* t7 = 0xffffffff */ srl t8, a1, 24 /* t8 = srca */ li t9, 0x00ff00ff + addiu t1, a3, -1 - beqz t1, 3f /* last pixel */ + beqz t1, 4f /* last pixel */ nop - beq t8, t6, 2f /* if (srca == 0xff) */ - nop -1: - /* a1 = src */ + +0: lw t0, 0(a2) /* t0 = mask */ lw t1, 4(a2) /* t1 = mask */ + addiu a3, a3, -2 /* w = w - 2 */ or t2, t0, t1 - beqz t2, 12f /* if (t0 == 0) && (t1 == 0) */ + beqz t2, 3f /* if (t0 == 0) && (t1 == 0) */ addiu a2, a2, 8 - and t3, t0, t1 - move t4, a1 /* t4 = src */ - move t5, a1 /* t5 = src */ + and t2, t0, t1 + beq t2, t7, 1f /* if (t0 == 0xffffffff) && (t1 == 0xffffffff) */ + nop + +//if(ma) lw t2, 0(a0) /* t2 = dst */ - beq t3, t7, 11f /* if (t0 == 0xffffffff) && (t1 == 0xffffffff) */ - lw t3, 4(a0) /* t3 = dst */ + lw t3, 4(a0) /* t3 = dst */ MIPS_2xUN8x4_MUL_2xUN8x4 a1, a1, t0, t1, t4, t5, t9, s0, s1, s2, s3, s4, s5 MIPS_2xUN8x4_MUL_2xUN8 t0, t1, t8, t8, t0, t1, t9, s0, s1, s2, s3, s4, s5 -11: not t0, t0 not t1, t1 MIPS_2xUN8x4_MUL_2xUN8x4 t2, t3, t0, t1, t2, t3, t9, s0, s1, s2, s3, s4, s5 @@ -486,62 +997,79 @@ LEAF_MIPS_DSPR2(pixman_composite_over_n_8888_8888_ca_asm_mips) addu_s.qb t3, t5, t3 sw t2, 0(a0) sw t3, 4(a0) -12: - addiu a3, a3, -2 addiu t1, a3, -1 - bgtz t1, 1b + bgtz t1, 0b addiu a0, a0, 8 - b 3f + b 4f + nop +1: +//if (t0 == 0xffffffff) && (t1 == 0xffffffff): + beq t8, t6, 2f /* if (srca == 0xff) */ nop -2: - /* a1 = src */ - lw t0, 0(a2) /* t0 = mask */ - lw t1, 4(a2) /* t1 = mask */ - or t2, t0, t1 - beqz t2, 22f /* if (t0 == 0) & (t1 == 0) */ - addiu a2, a2, 8 - and t2, t0, t1 - move t4, a1 - beq t2, t7, 21f /* if (t0 == 0xffffffff) && (t1 == 0xffffffff) */ - move t5, a1 lw t2, 0(a0) /* t2 = dst */ lw t3, 4(a0) /* t3 = dst */ - MIPS_2xUN8x4_MUL_2xUN8x4 a1, a1, t0, t1, t4, t5, t9, s0, s1, s2, s3, s4, s5 - not t0, t0 - not t1, t1 - MIPS_2xUN8x4_MUL_2xUN8x4 t2, t3, t0, t1, t2, t3, t9, s0, s1, s2, s3, s4, s5 - addu_s.qb t4, t4, t2 - addu_s.qb t5, t5, t3 -21: - sw t4, 0(a0) - sw t5, 4(a0) -22: - addiu a3, a3, -2 + not t0, a1 + not t1, a1 + srl t0, t0, 24 + srl t1, t1, 24 + MIPS_2xUN8x4_MUL_2xUN8 t2, t3, t0, t1, t2, t3, t9, s0, s1, s2, s3, s4, s5 + addu_s.qb t2, a1, t2 + addu_s.qb t3, a1, t3 + sw t2, 0(a0) + sw t3, 4(a0) addiu t1, a3, -1 - bgtz t1, 2b + bgtz t1, 0b addiu a0, a0, 8 + b 4f + nop +2: + sw a1, 0(a0) + sw a1, 4(a0) 3: - blez a3, 4f + addiu t1, a3, -1 + bgtz t1, 0b + addiu a0, a0, 8 + +4: + beqz a3, 7f nop /* a1 = src */ - lw t1, 0(a2) /* t1 = mask */ - beqz t1, 4f + lw t0, 0(a2) /* t0 = mask */ + beqz t0, 7f /* if (t0 == 0) */ nop - move t2, a1 /* t2 = src */ - beq t1, t7, 31f - lw t0, 0(a0) /* t0 = dst */ - - MIPS_UN8x4_MUL_UN8x4 a1, t1, t2, t9, t3, t4, t5, t6 - MIPS_UN8x4_MUL_UN8 t1, t8, t1, t9, t3, t4, t5 -31: - not t1, t1 - MIPS_UN8x4_MUL_UN8x4 t0, t1, t0, t9, t3, t4, t5, t6 - addu_s.qb t0, t2, t0 - sw t0, 0(a0) -4: + beq t0, t7, 5f /* if (t0 == 0xffffffff) */ + nop +//if(ma) + lw t1, 0(a0) /* t1 = dst */ + MIPS_UN8x4_MUL_UN8x4 a1, t0, t2, t9, t3, t4, t5, s0 + MIPS_UN8x4_MUL_UN8 t0, t8, t0, t9, t3, t4, t5 + not t0, t0 + MIPS_UN8x4_MUL_UN8x4 t1, t0, t1, t9, t3, t4, t5, s0 + addu_s.qb t1, t2, t1 + sw t1, 0(a0) RESTORE_REGS_FROM_STACK 8, s0, s1, s2, s3, s4, s5 j ra nop +5: +//if (t0 == 0xffffffff) + beq t8, t6, 6f /* if (srca == 0xff) */ + nop + lw t1, 0(a0) /* t1 = dst */ + not t0, a1 + srl t0, t0, 24 + MIPS_UN8x4_MUL_UN8 t1, t0, t1, t9, t2, t3, t4 + addu_s.qb t1, a1, t1 + sw t1, 0(a0) + RESTORE_REGS_FROM_STACK 8, s0, s1, s2, s3, s4, s5 + j ra + nop +6: + sw a1, 0(a0) +7: + RESTORE_REGS_FROM_STACK 8, s0, s1, s2, s3, s4, s5 +8: + j ra + nop END(pixman_composite_over_n_8888_8888_ca_asm_mips) @@ -553,111 +1081,251 @@ LEAF_MIPS_DSPR2(pixman_composite_over_n_8888_0565_ca_asm_mips) * a3 - w */ + beqz a3, 8f + nop SAVE_REGS_ON_STACK 20, s0, s1, s2, s3, s4, s5, s6, s7, s8 - beqz a3, 4f - nop - li t5, 0xf800f800 - li t6, 0x07e007e0 - li t7, 0x001F001F - li t9, 0x00ff00ff + li t6, 0xff + addiu t7, zero, -1 /* t7 = 0xffffffff */ srl t8, a1, 24 /* t8 = srca */ - addiu t1, a3, -1 - beqz t1, 3f /* last pixel */ - nop - li s0, 0xff /* s0 = 0xff */ - addiu s1, zero, -1 /* s1 = 0xffffffff */ + li t9, 0x00ff00ff + li s6, 0xf800f800 + li s7, 0x07e007e0 + li s8, 0x001F001F - beq t8, s0, 2f /* if (srca == 0xff) */ - nop -1: - /* a1 = src */ - lw t0, 0(a2) /* t0 = mask */ - lw t1, 4(a2) /* t1 = mask */ - or t2, t0, t1 - beqz t2, 12f /* if (t0 == 0) && (t1 == 0) */ - addiu a2, a2, 8 - and t3, t0, t1 - move s2, a1 /* s2 = src */ - move s3, a1 /* s3 = src */ - lhu t2, 0(a0) /* t2 = dst */ - beq t3, s1, 11f /* if (t0 == 0xffffffff) && (t1 == 0xffffffff) */ - lhu t3, 2(a0) /* t3 = dst */ - MIPS_2xUN8x4_MUL_2xUN8x4 a1, a1, t0, t1, s2, s3, t9, t4, s4, s5, s6, s7, s8 - MIPS_2xUN8x4_MUL_2xUN8 t0, t1, t8, t8, t0, t1, t9, t4, s4, s5, s6, s7, s8 -11: - not t0, t0 - not t1, t1 - CONVERT_2x0565_TO_2x8888 t2, t3, s4, s5, t6, t7, t4, s6, s7, s8 - MIPS_2xUN8x4_MUL_2xUN8x4 s4, s5, t0, t1, s4, s5, t9, t4, s6, s7, s8, t0, t1 - addu_s.qb s2, s2, s4 - addu_s.qb s3, s3, s5 - CONVERT_2x8888_TO_2x0565 s2, s3, t2, t3, t5, t6, t7, s4, s5 - sh t2, 0(a0) - sh t3, 2(a0) -12: - addiu a3, a3, -2 addiu t1, a3, -1 - bgtz t1, 1b - addiu a0, a0, 4 - b 3f + beqz t1, 4f /* last pixel */ nop -2: - /* a1 = src */ + +0: lw t0, 0(a2) /* t0 = mask */ lw t1, 4(a2) /* t1 = mask */ + addiu a3, a3, -2 /* w = w - 2 */ or t2, t0, t1 - beqz t2, 22f /* if (t0 == 0) & (t1 == 0) */ + beqz t2, 3f /* if (t0 == 0) && (t1 == 0) */ addiu a2, a2, 8 - and t3, t0, t1 - move t2, a1 - beq t3, s1, 21f /* if (t0 == 0xffffffff) && (t1 == 0xffffffff) */ - move t3, a1 + and t2, t0, t1 + beq t2, t7, 1f /* if (t0 == 0xffffffff) && (t1 == 0xffffffff) */ + nop + +//if(ma) lhu t2, 0(a0) /* t2 = dst */ lhu t3, 2(a0) /* t3 = dst */ - MIPS_2xUN8x4_MUL_2xUN8x4 a1, a1, t0, t1, s2, s3, t9, t4, s4, s5, s6, s7, s8 + MIPS_2xUN8x4_MUL_2xUN8x4 a1, a1, t0, t1, t4, t5, t9, s0, s1, s2, s3, s4, s5 + MIPS_2xUN8x4_MUL_2xUN8 t0, t1, t8, t8, t0, t1, t9, s0, s1, s2, s3, s4, s5 not t0, t0 not t1, t1 - CONVERT_2x0565_TO_2x8888 t2, t3, s4, s5, t6, t7, t4, s6, s7, s8 - MIPS_2xUN8x4_MUL_2xUN8x4 s4, s5, t0, t1, s4, s5, t9, t4, s6, s7, s8, t2, t3 - addu_s.qb t2, s2, s4 - addu_s.qb t3, s3, s5 -21: - CONVERT_2x8888_TO_2x0565 t2, t3, t0, t1, t5, t6, t7, s2, s3 - sh t0, 0(a0) - sh t1, 2(a0) -22: - addiu a3, a3, -2 + CONVERT_2x0565_TO_2x8888 t2, t3, t2, t3, s7, s8, s0, s1, s2, s3 + MIPS_2xUN8x4_MUL_2xUN8x4 t2, t3, t0, t1, t2, t3, t9, s0, s1, s2, s3, s4, s5 + addu_s.qb t2, t4, t2 + addu_s.qb t3, t5, t3 + CONVERT_2x8888_TO_2x0565 t2, t3, t2, t3, s6, s7, s8, s0, s1 + sh t2, 0(a0) + sh t3, 2(a0) addiu t1, a3, -1 - bgtz t1, 2b + bgtz t1, 0b addiu a0, a0, 4 + b 4f + nop +1: +//if (t0 == 0xffffffff) && (t1 == 0xffffffff): + beq t8, t6, 2f /* if (srca == 0xff) */ + nop + lhu t2, 0(a0) /* t2 = dst */ + lhu t3, 2(a0) /* t3 = dst */ + not t0, a1 + not t1, a1 + srl t0, t0, 24 + srl t1, t1, 24 + CONVERT_2x0565_TO_2x8888 t2, t3, t2, t3, s7, s8, s0, s1, s2, s3 + MIPS_2xUN8x4_MUL_2xUN8 t2, t3, t0, t1, t2, t3, t9, s0, s1, s2, s3, s4, s5 + addu_s.qb t2, a1, t2 + addu_s.qb t3, a1, t3 + CONVERT_2x8888_TO_2x0565 t2, t3, t2, t3, s6, s7, s8, s0, s1 + sh t2, 0(a0) + sh t3, 2(a0) + addiu t1, a3, -1 + bgtz t1, 0b + addiu a0, a0, 4 + b 4f + nop +2: + CONVERT_1x8888_TO_1x0565 a1, t2, s0, s1 + sh t2, 0(a0) + sh t2, 2(a0) 3: - blez a3, 4f + addiu t1, a3, -1 + bgtz t1, 0b + addiu a0, a0, 4 + +4: + beqz a3, 7f nop /* a1 = src */ - lw t1, 0(a2) /* t1 = mask */ - beqz t1, 4f + lw t0, 0(a2) /* t0 = mask */ + beqz t0, 7f /* if (t0 == 0) */ nop - move t2, a1 /* t2 = src */ - beq t1, t7, 31f - lhu t0, 0(a0) /* t0 = dst */ - - MIPS_UN8x4_MUL_UN8x4 a1, t1, t2, t9, t3, t4, t5, t6 - MIPS_UN8x4_MUL_UN8 t1, t8, t1, t9, t3, t4, t5 -31: - not t1, t1 - CONVERT_1x0565_TO_1x8888 t0, s1, s2, s3 - MIPS_UN8x4_MUL_UN8x4 s1, t1, t3, t9, t4, t5, t6, t7 - addu_s.qb t0, t2, t3 - CONVERT_1x8888_TO_1x0565 t0, s1, s2, s3 - sh s1, 0(a0) -4: - RESTORE_REGS_FROM_STACK 20, s0, s1, s2, s3, s4, s5, s6, s7, s8 + beq t0, t7, 5f /* if (t0 == 0xffffffff) */ + nop +//if(ma) + lhu t1, 0(a0) /* t1 = dst */ + MIPS_UN8x4_MUL_UN8x4 a1, t0, t2, t9, t3, t4, t5, s0 + MIPS_UN8x4_MUL_UN8 t0, t8, t0, t9, t3, t4, t5 + not t0, t0 + CONVERT_1x0565_TO_1x8888 t1, s1, s2, s3 + MIPS_UN8x4_MUL_UN8x4 s1, t0, s1, t9, t3, t4, t5, s0 + addu_s.qb s1, t2, s1 + CONVERT_1x8888_TO_1x0565 s1, t1, s0, s2 + sh t1, 0(a0) + RESTORE_REGS_FROM_STACK 20, s0, s1, s2, s3, s4, s5, s6, s7, s8 + j ra + nop +5: +//if (t0 == 0xffffffff) + beq t8, t6, 6f /* if (srca == 0xff) */ + nop + lhu t1, 0(a0) /* t1 = dst */ + not t0, a1 + srl t0, t0, 24 + CONVERT_1x0565_TO_1x8888 t1, s1, s2, s3 + MIPS_UN8x4_MUL_UN8 s1, t0, s1, t9, t2, t3, t4 + addu_s.qb s1, a1, s1 + CONVERT_1x8888_TO_1x0565 s1, t1, s0, s2 + sh t1, 0(a0) + RESTORE_REGS_FROM_STACK 20, s0, s1, s2, s3, s4, s5, s6, s7, s8 + j ra + nop +6: + CONVERT_1x8888_TO_1x0565 a1, t1, s0, s2 + sh t1, 0(a0) +7: + RESTORE_REGS_FROM_STACK 20, s0, s1, s2, s3, s4, s5, s6, s7, s8 +8: j ra nop END(pixman_composite_over_n_8888_0565_ca_asm_mips) +LEAF_MIPS_DSPR2(pixman_composite_over_n_8_8_asm_mips) +/* + * a0 - dst (a8) + * a1 - src (32bit constant) + * a2 - mask (a8) + * a3 - w + */ + + SAVE_REGS_ON_STACK 0, v0 + li t9, 0x00ff00ff + beqz a3, 3f + nop + srl v0, a3, 2 /* v0 = how many multiples of 4 dst pixels */ + beqz v0, 1f /* branch if less than 4 src pixels */ + nop + + srl t8, a1, 24 + replv.ph t8, t8 + +0: + beqz v0, 1f + addiu v0, v0, -1 + lbu t0, 0(a2) + lbu t1, 1(a2) + lbu t2, 2(a2) + lbu t3, 3(a2) + lbu t4, 0(a0) + lbu t5, 1(a0) + lbu t6, 2(a0) + lbu t7, 3(a0) + + addiu a2, a2, 4 + + precr_sra.ph.w t1, t0, 0 + precr_sra.ph.w t3, t2, 0 + precr_sra.ph.w t5, t4, 0 + precr_sra.ph.w t7, t6, 0 + + precr.qb.ph t0, t3, t1 + precr.qb.ph t1, t7, t5 + + muleu_s.ph.qbl t2, t0, t8 + muleu_s.ph.qbr t3, t0, t8 + shra_r.ph t4, t2, 8 + shra_r.ph t5, t3, 8 + and t4, t4, t9 + and t5, t5, t9 + addq.ph t2, t2, t4 + addq.ph t3, t3, t5 + shra_r.ph t2, t2, 8 + shra_r.ph t3, t3, 8 + precr.qb.ph t0, t2, t3 + not t6, t0 + + preceu.ph.qbl t7, t6 + preceu.ph.qbr t6, t6 + + muleu_s.ph.qbl t2, t1, t7 + muleu_s.ph.qbr t3, t1, t6 + shra_r.ph t4, t2, 8 + shra_r.ph t5, t3, 8 + and t4, t4, t9 + and t5, t5, t9 + addq.ph t2, t2, t4 + addq.ph t3, t3, t5 + shra_r.ph t2, t2, 8 + shra_r.ph t3, t3, 8 + precr.qb.ph t1, t2, t3 + + addu_s.qb t2, t0, t1 + + sb t2, 0(a0) + srl t2, t2, 8 + sb t2, 1(a0) + srl t2, t2, 8 + sb t2, 2(a0) + srl t2, t2, 8 + sb t2, 3(a0) + addiu a3, a3, -4 + b 0b + addiu a0, a0, 4 + +1: + beqz a3, 3f + nop + srl t8, a1, 24 +2: + lbu t0, 0(a2) + lbu t1, 0(a0) + addiu a2, a2, 1 + + mul t2, t0, t8 + shra_r.ph t3, t2, 8 + andi t3, t3, 0x00ff + addq.ph t2, t2, t3 + shra_r.ph t2, t2, 8 + not t3, t2 + andi t3, t3, 0x00ff + + + mul t4, t1, t3 + shra_r.ph t5, t4, 8 + andi t5, t5, 0x00ff + addq.ph t4, t4, t5 + shra_r.ph t4, t4, 8 + andi t4, t4, 0x00ff + + addu_s.qb t2, t2, t4 + sb t2, 0(a0) + addiu a3, a3, -1 + bnez a3, 2b + addiu a0, a0, 1 + +3: + RESTORE_REGS_FROM_STACK 0, v0 + j ra + nop + +END(pixman_composite_over_n_8_8_asm_mips) + LEAF_MIPS_DSPR2(pixman_composite_over_n_8_8888_asm_mips) /* * a0 - dst (a8r8g8b8) @@ -1342,6 +2010,84 @@ LEAF_MIPS_DSPR2(pixman_composite_over_8888_8888_asm_mips) END(pixman_composite_over_8888_8888_asm_mips) +LEAF_MIPS_DSPR2(pixman_composite_over_8888_0565_asm_mips) +/* + * a0 - dst (r5g6b5) + * a1 - src (a8r8g8b8) + * a2 - w + */ + + SAVE_REGS_ON_STACK 8, s0, s1, s2, s3, s4, s5 + li t4, 0x00ff00ff + li s3, 0xf800f800 + li s4, 0x07e007e0 + li s5, 0x001F001F + beqz a2, 3f + nop + addiu t1, a2, -1 + beqz t1, 2f + nop +1: + lw t0, 0(a1) /* t0 = source (a8r8g8b8) */ + lw t1, 4(a1) /* t1 = source (a8r8g8b8) */ + lhu t2, 0(a0) /* t2 = destination (r5g6b5) */ + lhu t3, 2(a0) /* t3 = destination (r5g6b5) */ + addiu a1, a1, 8 + + not t5, t0 + srl t5, t5, 24 + not t6, t1 + srl t6, t6, 24 + + or t7, t5, t6 + beqz t7, 11f + or t8, t0, t1 + beqz t8, 12f + + CONVERT_2x0565_TO_2x8888 t2, t3, s0, s1, s4, s5, t7, t8, t9, s2 + MIPS_2xUN8x4_MUL_2xUN8 s0, s1, t5, t6, t7, t8, t4, t9, t2, t3, s2, s0, s1 + + addu_s.qb t0, t7, t0 + addu_s.qb t1, t8, t1 +11: + CONVERT_2x8888_TO_2x0565 t0, t1, t7, t8, s3, s4, s5, t2, t3 + sh t7, 0(a0) + sh t8, 2(a0) +12: + addiu a2, a2, -2 + addiu t1, a2, -1 + bgtz t1, 1b + addiu a0, a0, 4 +2: + beqz a2, 3f + nop + + lw t0, 0(a1) /* t0 = source (a8r8g8b8) */ + lhu t1, 0(a0) /* t1 = destination (r5g6b5) */ + addiu a1, a1, 4 + + not t2, t0 + srl t2, t2, 24 + + beqz t2, 21f + nop + beqz t0, 3f + + CONVERT_1x0565_TO_1x8888 t1, s0, t8, t9 + MIPS_UN8x4_MUL_UN8 s0, t2, t3, t4, t5, t6, t7 + + addu_s.qb t0, t3, t0 +21: + CONVERT_1x8888_TO_1x0565 t0, s0, t8, t9 + sh s0, 0(a0) + +3: + RESTORE_REGS_FROM_STACK 8, s0, s1, s2, s3, s4, s5 + j ra + nop + +END(pixman_composite_over_8888_0565_asm_mips) + LEAF_MIPS_DSPR2(pixman_composite_over_n_0565_asm_mips) /* * a0 - dst (r5g6b5) @@ -2349,101 +3095,265 @@ END(pixman_composite_over_reverse_n_8888_asm_mips) LEAF_MIPS_DSPR2(pixman_composite_in_n_8_asm_mips) /* * a0 - dst (a8) - * a1 - src (a8r8g8b8) + * a1 - src (32bit constant) * a2 - w */ - beqz a2, 5f + li t9, 0x00ff00ff + beqz a2, 3f + nop + srl t7, a2, 2 /* t7 = how many multiples of 4 dst pixels */ + beqz t7, 1f /* branch if less than 4 src pixels */ nop - SAVE_REGS_ON_STACK 20, s0, s1, s2, s3, s4, s5, s6, s7 - move t7, a1 - srl t5, t7, 24 - replv.ph t5, t5 - srl t9, a2, 2 /* t1 = how many multiples of 4 src pixels */ - beqz t9, 2f /* branch if less than 4 src pixels */ - nop + srl t8, a1, 24 + replv.ph t8, t8 -1: - addiu t9, t9, -1 - addiu a2, a2, -4 +0: + beqz t7, 1f + addiu t7, t7, -1 lbu t0, 0(a0) lbu t1, 1(a0) lbu t2, 2(a0) lbu t3, 3(a0) - muleu_s.ph.qbl s0, t0, t5 - muleu_s.ph.qbr s1, t0, t5 - muleu_s.ph.qbl s2, t1, t5 - muleu_s.ph.qbr s3, t1, t5 - muleu_s.ph.qbl s4, t2, t5 - muleu_s.ph.qbr s5, t2, t5 - muleu_s.ph.qbl s6, t3, t5 - muleu_s.ph.qbr s7, t3, t5 + precr_sra.ph.w t1, t0, 0 + precr_sra.ph.w t3, t2, 0 + precr.qb.ph t0, t3, t1 - shrl.ph t4, s0, 8 - shrl.ph t6, s1, 8 - shrl.ph t7, s2, 8 - shrl.ph t8, s3, 8 - addq.ph t0, s0, t4 - addq.ph t1, s1, t6 - addq.ph t2, s2, t7 - addq.ph t3, s3, t8 - shra_r.ph t0, t0, 8 - shra_r.ph t1, t1, 8 + muleu_s.ph.qbl t2, t0, t8 + muleu_s.ph.qbr t3, t0, t8 + shra_r.ph t4, t2, 8 + shra_r.ph t5, t3, 8 + and t4, t4, t9 + and t5, t5, t9 + addq.ph t2, t2, t4 + addq.ph t3, t3, t5 shra_r.ph t2, t2, 8 shra_r.ph t3, t3, 8 - shrl.ph t4, s4, 8 - shrl.ph t6, s5, 8 - shrl.ph t7, s6, 8 - shrl.ph t8, s7, 8 - addq.ph s0, s4, t4 - addq.ph s1, s5, t6 - addq.ph s2, s6, t7 - addq.ph s3, s7, t8 - shra_r.ph t4, s0, 8 - shra_r.ph t6, s1, 8 - shra_r.ph t7, s2, 8 - shra_r.ph t8, s3, 8 + precr.qb.ph t2, t2, t3 - precr.qb.ph s0, t0, t1 - precr.qb.ph s1, t2, t3 - precr.qb.ph s2, t4, t6 - precr.qb.ph s3, t7, t8 - - sb s0, 0(a0) - sb s1, 1(a0) - sb s2, 2(a0) - sb s3, 3(a0) - bgtz t9, 1b + sb t2, 0(a0) + srl t2, t2, 8 + sb t2, 1(a0) + srl t2, t2, 8 + sb t2, 2(a0) + srl t2, t2, 8 + sb t2, 3(a0) + addiu a2, a2, -4 + b 0b addiu a0, a0, 4 -2: - beqz a2, 4f - nop -3: - lbu t1, 0(a0) - muleu_s.ph.qbl t4, t1, t5 - muleu_s.ph.qbr t7, t1, t5 - shrl.ph t6, t4, 8 - shrl.ph t0, t7, 8 - addq.ph t8, t4, t6 - addq.ph t9, t7, t0 - shra_r.ph t8, t8, 8 - shra_r.ph t9, t9, 8 - precr.qb.ph t2, t8, t9 +1: + beqz a2, 3f + nop + srl t8, a1, 24 +2: + lbu t0, 0(a0) + + mul t2, t0, t8 + shra_r.ph t3, t2, 8 + andi t3, t3, 0x00ff + addq.ph t2, t2, t3 + shra_r.ph t2, t2, 8 + sb t2, 0(a0) addiu a2, a2, -1 - bnez a2, 3b + bnez a2, 2b addiu a0, a0, 1 -4: - RESTORE_REGS_FROM_STACK 20, s0, s1, s2, s3, s4, s5, s6, s7 -5: + +3: j ra nop END(pixman_composite_in_n_8_asm_mips) +LEAF_MIPS_DSPR2(pixman_scaled_nearest_scanline_8888_8888_OVER_asm_mips) +/* + * a0 - dst (a8r8g8b8) + * a1 - src (a8r8g8b8) + * a2 - w + * a3 - vx + * 16(sp) - unit_x + */ + + SAVE_REGS_ON_STACK 0, s0, s1, s2, s3 + lw t8, 16(sp) /* t8 = unit_x */ + li t6, 0x00ff00ff + beqz a2, 3f + nop + addiu t1, a2, -1 + beqz t1, 2f + nop +1: + sra t0, a3, 16 /* t0 = vx >> 16 */ + sll t0, t0, 2 /* t0 = t0 * 4 (a8r8g8b8) */ + addu t0, a1, t0 + lw t0, 0(t0) /* t0 = source (a8r8g8b8) */ + addu a3, a3, t8 /* a3 = vx + unit_x */ + + sra t1, a3, 16 /* t0 = vx >> 16 */ + sll t1, t1, 2 /* t0 = t0 * 4 (a8r8g8b8) */ + addu t1, a1, t1 + lw t1, 0(t1) /* t1 = source (a8r8g8b8) */ + addu a3, a3, t8 /* a3 = vx + unit_x */ + + lw t2, 0(a0) /* t2 = destination (a8r8g8b8) */ + lw t3, 4(a0) /* t3 = destination (a8r8g8b8) */ + + OVER_2x8888_2x8888 t0, t1, t2, t3, t4, t5, t6, t7, t9, s0, s1, s2, s3 + + sw t4, 0(a0) + sw t5, 4(a0) + addiu a2, a2, -2 + addiu t1, a2, -1 + bgtz t1, 1b + addiu a0, a0, 8 +2: + beqz a2, 3f + nop + sra t0, a3, 16 /* t0 = vx >> 16 */ + sll t0, t0, 2 /* t0 = t0 * 4 (a8r8g8b8) */ + addu t0, a1, t0 + lw t0, 0(t0) /* t0 = source (a8r8g8b8) */ + lw t1, 0(a0) /* t1 = destination (a8r8g8b8) */ + addu a3, a3, t8 /* a3 = vx + unit_x */ + + OVER_8888_8888 t0, t1, t2, t6, t4, t5, t3, t7 + + sw t2, 0(a0) +3: + RESTORE_REGS_FROM_STACK 0, s0, s1, s2, s3 + j ra + nop + +END(pixman_scaled_nearest_scanline_8888_8888_OVER_asm_mips) + +LEAF_MIPS_DSPR2(pixman_scaled_nearest_scanline_8888_0565_OVER_asm_mips) +/* + * a0 - dst (r5g6b5) + * a1 - src (a8r8g8b8) + * a2 - w + * a3 - vx + * 16(sp) - unit_x + */ + + SAVE_REGS_ON_STACK 24, s0, s1, s2, s3, s4, v0, v1 + lw t8, 40(sp) /* t8 = unit_x */ + li t4, 0x00ff00ff + li t5, 0xf800f800 + li t6, 0x07e007e0 + li t7, 0x001F001F + beqz a2, 3f + nop + addiu t1, a2, -1 + beqz t1, 2f + nop +1: + sra t0, a3, 16 /* t0 = vx >> 16 */ + sll t0, t0, 2 /* t0 = t0 * 4 (a8r8g8b8) */ + addu t0, a1, t0 + lw t0, 0(t0) /* t0 = source (a8r8g8b8) */ + addu a3, a3, t8 /* a3 = vx + unit_x */ + sra t1, a3, 16 /* t0 = vx >> 16 */ + sll t1, t1, 2 /* t0 = t0 * 4 (a8r8g8b8) */ + addu t1, a1, t1 + lw t1, 0(t1) /* t1 = source (a8r8g8b8) */ + addu a3, a3, t8 /* a3 = vx + unit_x */ + lhu t2, 0(a0) /* t2 = destination (r5g6b5) */ + lhu t3, 2(a0) /* t3 = destination (r5g6b5) */ + + CONVERT_2x0565_TO_2x8888 t2, t3, v0, v1, t6, t7, s0, s1, s2, s3 + OVER_2x8888_2x8888 t0, t1, v0, v1, t2, t3, t4, t9, s0, s1, s2, s3, s4 + CONVERT_2x8888_TO_2x0565 t2, t3, v0, v1, t5, t6, t7, t9, s2 + + sh v0, 0(a0) + sh v1, 2(a0) + addiu a2, a2, -2 + addiu t1, a2, -1 + bgtz t1, 1b + addiu a0, a0, 4 +2: + beqz a2, 3f + nop + sra t0, a3, 16 /* t0 = vx >> 16 */ + sll t0, t0, 2 /* t0 = t0 * 4 (a8r8g8b8) */ + addu t0, a1, t0 + lw t0, 0(t0) /* t0 = source (a8r8g8b8) */ + lhu t1, 0(a0) /* t1 = destination (r5g6b5) */ + addu a3, a3, t8 /* a3 = vx + unit_x */ + + CONVERT_1x0565_TO_1x8888 t1, t2, t5, t6 + OVER_8888_8888 t0, t2, t1, t4, t3, t5, t6, t7 + CONVERT_1x8888_TO_1x0565 t1, t2, t5, t6 + + sh t2, 0(a0) +3: + RESTORE_REGS_FROM_STACK 24, s0, s1, s2, s3, s4, v0, v1 + j ra + nop + +END(pixman_scaled_nearest_scanline_8888_0565_OVER_asm_mips) + +LEAF_MIPS_DSPR2(pixman_scaled_nearest_scanline_0565_8888_SRC_asm_mips) +/* + * a0 - dst (a8r8g8b8) + * a1 - src (r5g6b5) + * a2 - w + * a3 - vx + * 16(sp) - unit_x + */ + + SAVE_REGS_ON_STACK 0, v0 + beqz a2, 3f + nop + + lw v0, 16(sp) /* v0 = unit_x */ + addiu t1, a2, -1 + beqz t1, 2f + nop + + li t4, 0x07e007e0 + li t5, 0x001F001F +1: + sra t0, a3, 16 /* t0 = vx >> 16 */ + sll t0, t0, 1 /* t0 = t0 * 2 ((r5g6b5)) */ + addu t0, a1, t0 + lhu t0, 0(t0) /* t0 = source ((r5g6b5)) */ + addu a3, a3, v0 /* a3 = vx + unit_x */ + sra t1, a3, 16 /* t1 = vx >> 16 */ + sll t1, t1, 1 /* t1 = t1 * 2 ((r5g6b5)) */ + addu t1, a1, t1 + lhu t1, 0(t1) /* t1 = source ((r5g6b5)) */ + addu a3, a3, v0 /* a3 = vx + unit_x */ + addiu a2, a2, -2 + + CONVERT_2x0565_TO_2x8888 t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 + + sw t2, 0(a0) + sw t3, 4(a0) + + addiu t2, a2, -1 + bgtz t2, 1b + addiu a0, a0, 8 +2: + beqz a2, 3f + nop + sra t0, a3, 16 /* t0 = vx >> 16 */ + sll t0, t0, 1 /* t0 = t0 * 2 ((r5g6b5)) */ + addu t0, a1, t0 + lhu t0, 0(t0) /* t0 = source ((r5g6b5)) */ + + CONVERT_1x0565_TO_1x8888 t0, t1, t2, t3 + + sw t1, 0(a0) +3: + RESTORE_REGS_FROM_STACK 0, v0 + j ra + nop + +END(pixman_scaled_nearest_scanline_0565_8888_SRC_asm_mips) + LEAF_MIPS_DSPR2(pixman_scaled_nearest_scanline_8888_8_0565_OVER_asm_mips) /* * a0 - dst (r5g6b5) diff --git a/gfx/cairo/libpixman/src/pixman-mips-dspr2-asm.h b/gfx/cairo/libpixman/src/pixman-mips-dspr2-asm.h index b330c0f0d9..e238566196 100644 --- a/gfx/cairo/libpixman/src/pixman-mips-dspr2-asm.h +++ b/gfx/cairo/libpixman/src/pixman-mips-dspr2-asm.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Author: Nemanja Lukic (nlukic@mips.com) + * Author: Nemanja Lukic (nemanja.lukic@rt-rk.com) */ #ifndef PIXMAN_MIPS_DSPR2_ASM_H @@ -72,6 +72,7 @@ #define LEAF_MIPS32R2(symbol) \ .globl symbol; \ .align 2; \ + .hidden symbol; \ .type symbol, @function; \ .ent symbol, 0; \ symbol: .frame sp, 0, ra; \ @@ -354,17 +355,16 @@ LEAF_MIPS32R2(symbol) \ out1_565, out2_565, \ maskR, maskG, maskB, \ scratch1, scratch2 - precrq.ph.w \scratch1, \in2_8888, \in1_8888 - precr_sra.ph.w \in2_8888, \in1_8888, 0 - shll.ph \scratch1, \scratch1, 8 - srl \in2_8888, \in2_8888, 3 - and \scratch2, \in2_8888, \maskB - and \scratch1, \scratch1, \maskR - srl \in2_8888, \in2_8888, 2 - and \out2_565, \in2_8888, \maskG - or \out2_565, \out2_565, \scratch2 - or \out1_565, \out2_565, \scratch1 - srl \out2_565, \out1_565, 16 + precr.qb.ph \scratch1, \in2_8888, \in1_8888 + precrq.qb.ph \in2_8888, \in2_8888, \in1_8888 + and \out1_565, \scratch1, \maskR + shrl.ph \scratch1, \scratch1, 3 + shll.ph \in2_8888, \in2_8888, 3 + and \scratch1, \scratch1, \maskB + or \out1_565, \out1_565, \scratch1 + and \in2_8888, \in2_8888, \maskG + or \out1_565, \out1_565, \in2_8888 + srl \out2_565, \out1_565, 16 .endm /* @@ -587,6 +587,36 @@ LEAF_MIPS32R2(symbol) \ addu_s.qb \out_8888, \out_8888, \s_8888 .endm +/* + * OVER operation on two a8r8g8b8 source pixels (s1_8888 and s2_8888) and two + * a8r8g8b8 destination pixels (d1_8888 and d2_8888). It also requires maskLSR + * needed for rounding process. maskLSR must have following value: + * li maskLSR, 0x00ff00ff + */ +.macro OVER_2x8888_2x8888 s1_8888, \ + s2_8888, \ + d1_8888, \ + d2_8888, \ + out1_8888, \ + out2_8888, \ + maskLSR, \ + scratch1, scratch2, scratch3, \ + scratch4, scratch5, scratch6 + not \scratch1, \s1_8888 + srl \scratch1, \scratch1, 24 + not \scratch2, \s2_8888 + srl \scratch2, \scratch2, 24 + MIPS_2xUN8x4_MUL_2xUN8 \d1_8888, \d2_8888, \ + \scratch1, \scratch2, \ + \out1_8888, \out2_8888, \ + \maskLSR, \ + \scratch3, \scratch4, \scratch5, \ + \scratch6, \d1_8888, \d2_8888 + + addu_s.qb \out1_8888, \out1_8888, \s1_8888 + addu_s.qb \out2_8888, \out2_8888, \s2_8888 +.endm + .macro MIPS_UN8x4_MUL_UN8_ADD_UN8x4 s_8888, \ m_8, \ d_8888, \ diff --git a/gfx/cairo/libpixman/src/pixman-mips-dspr2.c b/gfx/cairo/libpixman/src/pixman-mips-dspr2.c index e14e1c43b9..87969ae704 100644 --- a/gfx/cairo/libpixman/src/pixman-mips-dspr2.c +++ b/gfx/cairo/libpixman/src/pixman-mips-dspr2.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Author: Nemanja Lukic (nlukic@mips.com) + * Author: Nemanja Lukic (nemanja.lukic@rt-rk.com) */ #ifdef HAVE_CONFIG_H @@ -48,8 +48,20 @@ PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (DO_FAST_MEMCPY, src_8888_8888, uint32_t, 1, uint32_t, 1) PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (DO_FAST_MEMCPY, src_0888_0888, uint8_t, 3, uint8_t, 3) +#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) +PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, src_0888_8888_rev, + uint8_t, 3, uint32_t, 1) +PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, src_0888_0565_rev, + uint8_t, 3, uint16_t, 1) +#endif +PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, src_pixbuf_8888, + uint32_t, 1, uint32_t, 1) +PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, src_rpixbuf_8888, + uint32_t, 1, uint32_t, 1) PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, over_8888_8888, uint32_t, 1, uint32_t, 1) +PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, over_8888_0565, + uint32_t, 1, uint16_t, 1) PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, add_8_8, uint8_t, 1, uint8_t, 1) PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, add_8888_8888, @@ -67,6 +79,8 @@ PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, over_n_8888_8888_ca, uint32_t, 1, uint32_t, 1) PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, over_n_8888_0565_ca, uint32_t, 1, uint16_t, 1) +PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, over_n_8_8, + uint8_t, 1, uint8_t, 1) PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, over_n_8_8888, uint8_t, 1, uint32_t, 1) PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, over_n_8_0565, @@ -111,6 +125,13 @@ PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST (over_0565_8_0565, uint16_t, 1, PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST (over_8888_8888_8888, uint32_t, 1, uint32_t, 1, uint32_t, 1) +PIXMAN_MIPS_BIND_SCALED_NEAREST_SRC_DST (8888_8888, OVER, + uint32_t, uint32_t) +PIXMAN_MIPS_BIND_SCALED_NEAREST_SRC_DST (8888_0565, OVER, + uint32_t, uint16_t) +PIXMAN_MIPS_BIND_SCALED_NEAREST_SRC_DST (0565_8888, SRC, + uint16_t, uint32_t) + PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_DST (0, 8888_8888, SRC, uint32_t, uint32_t) PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_DST (0, 8888_0565, SRC, @@ -278,6 +299,14 @@ static const pixman_fast_path_t mips_dspr2_fast_paths[] = PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, a8r8g8b8, mips_composite_src_x888_8888), PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, a8b8g8r8, mips_composite_src_x888_8888), PIXMAN_STD_FAST_PATH (SRC, r8g8b8, null, r8g8b8, mips_composite_src_0888_0888), +#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + PIXMAN_STD_FAST_PATH (SRC, b8g8r8, null, x8r8g8b8, mips_composite_src_0888_8888_rev), + PIXMAN_STD_FAST_PATH (SRC, b8g8r8, null, r5g6b5, mips_composite_src_0888_0565_rev), +#endif + PIXMAN_STD_FAST_PATH (SRC, pixbuf, pixbuf, a8r8g8b8, mips_composite_src_pixbuf_8888), + PIXMAN_STD_FAST_PATH (SRC, pixbuf, pixbuf, a8b8g8r8, mips_composite_src_rpixbuf_8888), + PIXMAN_STD_FAST_PATH (SRC, rpixbuf, rpixbuf, a8r8g8b8, mips_composite_src_rpixbuf_8888), + PIXMAN_STD_FAST_PATH (SRC, rpixbuf, rpixbuf, a8b8g8r8, mips_composite_src_pixbuf_8888), PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8r8g8b8, mips_composite_src_n_8_8888), PIXMAN_STD_FAST_PATH (SRC, solid, a8, x8r8g8b8, mips_composite_src_n_8_8888), PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8b8g8r8, mips_composite_src_n_8_8888), @@ -290,6 +319,7 @@ static const pixman_fast_path_t mips_dspr2_fast_paths[] = PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, x8b8g8r8, mips_composite_over_n_8888_8888_ca), PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, r5g6b5, mips_composite_over_n_8888_0565_ca), PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, b5g6r5, mips_composite_over_n_8888_0565_ca), + PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8, mips_composite_over_n_8_8), PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, mips_composite_over_n_8_8888), PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8r8g8b8, mips_composite_over_n_8_8888), PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, mips_composite_over_n_8_8888), @@ -318,6 +348,8 @@ static const pixman_fast_path_t mips_dspr2_fast_paths[] = PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, mips_composite_over_8888_8888), PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, mips_composite_over_8888_8888), PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, x8b8g8r8, mips_composite_over_8888_8888), + PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, r5g6b5, mips_composite_over_8888_0565), + PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, b5g6r5, mips_composite_over_8888_0565), PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8, mips_composite_add_n_8_8), PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8r8g8b8, mips_composite_add_n_8_8888), PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8b8g8r8, mips_composite_add_n_8_8888), @@ -340,11 +372,27 @@ static const pixman_fast_path_t mips_dspr2_fast_paths[] = PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8b8g8r8, mips_composite_over_reverse_n_8888), PIXMAN_STD_FAST_PATH (IN, solid, null, a8, mips_composite_in_n_8), - PIXMAN_MIPS_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, a8r8g8b8, r5g6b5, mips_8888_8_0565), - PIXMAN_MIPS_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, a8b8g8r8, b5g6r5, mips_8888_8_0565), + PIXMAN_MIPS_SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, mips_8888_8888), + PIXMAN_MIPS_SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, mips_8888_8888), + PIXMAN_MIPS_SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, mips_8888_8888), + PIXMAN_MIPS_SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, mips_8888_8888), - PIXMAN_MIPS_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, r5g6b5, r5g6b5, mips_0565_8_0565), - PIXMAN_MIPS_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, b5g6r5, b5g6r5, mips_0565_8_0565), + PIXMAN_MIPS_SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, r5g6b5, mips_8888_0565), + PIXMAN_MIPS_SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, b5g6r5, mips_8888_0565), + + PIXMAN_MIPS_SIMPLE_NEAREST_FAST_PATH (SRC, b5g6r5, x8b8g8r8, mips_0565_8888), + PIXMAN_MIPS_SIMPLE_NEAREST_FAST_PATH (SRC, r5g6b5, x8r8g8b8, mips_0565_8888), + /* Note: NONE repeat is not supported yet */ + SIMPLE_NEAREST_FAST_PATH_COVER (SRC, r5g6b5, a8r8g8b8, mips_0565_8888), + SIMPLE_NEAREST_FAST_PATH_COVER (SRC, b5g6r5, a8b8g8r8, mips_0565_8888), + SIMPLE_NEAREST_FAST_PATH_PAD (SRC, r5g6b5, a8r8g8b8, mips_0565_8888), + SIMPLE_NEAREST_FAST_PATH_PAD (SRC, b5g6r5, a8b8g8r8, mips_0565_8888), + + SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, a8r8g8b8, r5g6b5, mips_8888_8_0565), + SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, a8b8g8r8, b5g6r5, mips_8888_8_0565), + + SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, r5g6b5, r5g6b5, mips_0565_8_0565), + SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, b5g6r5, b5g6r5, mips_0565_8_0565), SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, mips_8888_8888), SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, mips_8888_8888), diff --git a/gfx/cairo/libpixman/src/pixman-mips-dspr2.h b/gfx/cairo/libpixman/src/pixman-mips-dspr2.h index 4ac9ff95df..57b38359e3 100644 --- a/gfx/cairo/libpixman/src/pixman-mips-dspr2.h +++ b/gfx/cairo/libpixman/src/pixman-mips-dspr2.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Author: Nemanja Lukic (nlukic@mips.com) + * Author: Nemanja Lukic (nemanja.lukic@rt-rk.com) */ #ifndef PIXMAN_MIPS_DSPR2_H @@ -246,6 +246,48 @@ mips_composite_##name (pixman_implementation_t *imp, \ } \ } +/****************************************************************************/ + +#define PIXMAN_MIPS_BIND_SCALED_NEAREST_SRC_DST(name, op, \ + src_type, dst_type) \ +void \ +pixman_scaled_nearest_scanline_##name##_##op##_asm_mips ( \ + dst_type * dst, \ + const src_type * src, \ + int32_t w, \ + pixman_fixed_t vx, \ + pixman_fixed_t unit_x); \ + \ +static force_inline void \ +scaled_nearest_scanline_mips_##name##_##op (dst_type * pd, \ + const src_type * ps, \ + int32_t w, \ + pixman_fixed_t vx, \ + pixman_fixed_t unit_x, \ + pixman_fixed_t max_vx, \ + pixman_bool_t zero_src) \ +{ \ + pixman_scaled_nearest_scanline_##name##_##op##_asm_mips (pd, ps, w, \ + vx, unit_x); \ +} \ + \ +FAST_NEAREST_MAINLOOP (mips_##name##_cover_##op, \ + scaled_nearest_scanline_mips_##name##_##op, \ + src_type, dst_type, COVER) \ +FAST_NEAREST_MAINLOOP (mips_##name##_none_##op, \ + scaled_nearest_scanline_mips_##name##_##op, \ + src_type, dst_type, NONE) \ +FAST_NEAREST_MAINLOOP (mips_##name##_pad_##op, \ + scaled_nearest_scanline_mips_##name##_##op, \ + src_type, dst_type, PAD) + +/* Provide entries for the fast path table */ +#define PIXMAN_MIPS_SIMPLE_NEAREST_FAST_PATH(op,s,d,func) \ + SIMPLE_NEAREST_FAST_PATH_COVER (op,s,d,func), \ + SIMPLE_NEAREST_FAST_PATH_NONE (op,s,d,func), \ + SIMPLE_NEAREST_FAST_PATH_PAD (op,s,d,func) + + /*****************************************************************************/ #define PIXMAN_MIPS_BIND_SCALED_NEAREST_SRC_A8_DST(flags, name, op, \ @@ -286,12 +328,6 @@ FAST_NEAREST_MAINLOOP_COMMON (mips_##name##_pad_##op, \ scaled_nearest_scanline_mips_##name##_##op, \ src_type, uint8_t, dst_type, PAD, TRUE, FALSE) -/* Provide entries for the fast path table */ -#define PIXMAN_MIPS_SIMPLE_NEAREST_A8_MASK_FAST_PATH(op,s,d,func) \ - SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER (op,s,d,func), \ - SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE (op,s,d,func), \ - SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD (op,s,d,func) - /****************************************************************************/ #define PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_DST(flags, name, op, \ diff --git a/gfx/cairo/libpixman/src/pixman-mmx.c b/gfx/cairo/libpixman/src/pixman-mmx.c index ca2ac83d90..d7cf2659df 100644 --- a/gfx/cairo/libpixman/src/pixman-mmx.c +++ b/gfx/cairo/libpixman/src/pixman-mmx.c @@ -44,8 +44,6 @@ #include "pixman-combine32.h" #include "pixman-inlines.h" -#define no_vERBOSE - #ifdef VERBOSE #define CHECKPOINT() error_f ("at %s %d\n", __FUNCTION__, __LINE__) #else @@ -91,21 +89,7 @@ _mm_mulhi_pu16 (__m64 __A, __m64 __B) return __A; } -# ifdef __OPTIMIZE__ -extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) -_mm_shuffle_pi16 (__m64 __A, int8_t const __N) -{ - __m64 ret; - - asm ("pshufw %2, %1, %0\n\t" - : "=y" (ret) - : "y" (__A), "K" (__N) - ); - - return ret; -} -# else -# define _mm_shuffle_pi16(A, N) \ +# define _mm_shuffle_pi16(A, N) \ ({ \ __m64 ret; \ \ @@ -116,7 +100,6 @@ _mm_shuffle_pi16 (__m64 __A, int8_t const __N) \ ret; \ }) -# endif # endif #endif @@ -303,6 +286,29 @@ negate (__m64 mask) return _mm_xor_si64 (mask, MC (4x00ff)); } +/* Computes the product of two unsigned fixed-point 8-bit values from 0 to 1 + * and maps its result to the same range. + * + * Jim Blinn gives multiple ways to compute this in "Jim Blinn's Corner: + * Notation, Notation, Notation", the first of which is + * + * prod(a, b) = (a * b + 128) / 255. + * + * By approximating the division by 255 as 257/65536 it can be replaced by a + * multiply and a right shift. This is the implementation that we use in + * pix_multiply(), but we _mm_mulhi_pu16() by 257 (part of SSE1 or Extended + * 3DNow!, and unavailable at the time of the book's publication) to perform + * the multiplication and right shift in a single operation. + * + * prod(a, b) = ((a * b + 128) * 257) >> 16. + * + * A third way (how pix_multiply() was implemented prior to 14208344) exists + * also that performs the multiplication by 257 with adds and shifts. + * + * Where temp = a * b + 128 + * + * prod(a, b) = (temp + (temp >> 8)) >> 8. + */ static force_inline __m64 pix_multiply (__m64 a, __m64 b) { @@ -381,8 +387,10 @@ in_over (__m64 src, __m64 srca, __m64 mask, __m64 dest) static force_inline __m64 ldq_u(__m64 *p) { #ifdef USE_X86_MMX - /* x86's alignment restrictions are very relaxed. */ - return *(__m64 *)p; + /* x86's alignment restrictions are very relaxed, but that's no excuse */ + __m64 r; + memcpy(&r, p, sizeof(__m64)); + return r; #elif defined USE_ARM_IWMMXT int align = (uintptr_t)p & 7; __m64 *aligned_p; @@ -401,7 +409,9 @@ static force_inline uint32_t ldl_u(const uint32_t *p) { #ifdef USE_X86_MMX /* x86's alignment restrictions are very relaxed. */ - return *p; + uint32_t r; + memcpy(&r, p, sizeof(uint32_t)); + return r; #else struct __una_u32 { uint32_t x __attribute__((packed)); }; const struct __una_u32 *ptr = (const struct __una_u32 *) p; @@ -3534,13 +3544,111 @@ mmx_composite_over_reverse_n_8888 (pixman_implementation_t *imp, _mm_empty (); } +static force_inline void +scaled_nearest_scanline_mmx_8888_8888_OVER (uint32_t* pd, + const uint32_t* ps, + int32_t w, + pixman_fixed_t vx, + pixman_fixed_t unit_x, + pixman_fixed_t src_width_fixed, + pixman_bool_t fully_transparent_src) +{ + if (fully_transparent_src) + return; + + while (w) + { + __m64 d = load (pd); + __m64 s = load (ps + pixman_fixed_to_int (vx)); + vx += unit_x; + while (vx >= 0) + vx -= src_width_fixed; + + store8888 (pd, core_combine_over_u_pixel_mmx (s, d)); + pd++; + + w--; + } + + _mm_empty (); +} + +FAST_NEAREST_MAINLOOP (mmx_8888_8888_cover_OVER, + scaled_nearest_scanline_mmx_8888_8888_OVER, + uint32_t, uint32_t, COVER) +FAST_NEAREST_MAINLOOP (mmx_8888_8888_none_OVER, + scaled_nearest_scanline_mmx_8888_8888_OVER, + uint32_t, uint32_t, NONE) +FAST_NEAREST_MAINLOOP (mmx_8888_8888_pad_OVER, + scaled_nearest_scanline_mmx_8888_8888_OVER, + uint32_t, uint32_t, PAD) +FAST_NEAREST_MAINLOOP (mmx_8888_8888_normal_OVER, + scaled_nearest_scanline_mmx_8888_8888_OVER, + uint32_t, uint32_t, NORMAL) + +static force_inline void +scaled_nearest_scanline_mmx_8888_n_8888_OVER (const uint32_t * mask, + uint32_t * dst, + const uint32_t * src, + int32_t w, + pixman_fixed_t vx, + pixman_fixed_t unit_x, + pixman_fixed_t src_width_fixed, + pixman_bool_t zero_src) +{ + __m64 mm_mask; + + if (zero_src || (*mask >> 24) == 0) + { + /* A workaround for https://gcc.gnu.org/PR47759 */ + _mm_empty (); + return; + } + + mm_mask = expand_alpha (load8888 (mask)); + + while (w) + { + uint32_t s = *(src + pixman_fixed_to_int (vx)); + vx += unit_x; + while (vx >= 0) + vx -= src_width_fixed; + + if (s) + { + __m64 ms = load8888 (&s); + __m64 alpha = expand_alpha (ms); + __m64 dest = load8888 (dst); + + store8888 (dst, (in_over (ms, alpha, mm_mask, dest))); + } + + dst++; + w--; + } + + _mm_empty (); +} + +FAST_NEAREST_MAINLOOP_COMMON (mmx_8888_n_8888_cover_OVER, + scaled_nearest_scanline_mmx_8888_n_8888_OVER, + uint32_t, uint32_t, uint32_t, COVER, TRUE, TRUE) +FAST_NEAREST_MAINLOOP_COMMON (mmx_8888_n_8888_pad_OVER, + scaled_nearest_scanline_mmx_8888_n_8888_OVER, + uint32_t, uint32_t, uint32_t, PAD, TRUE, TRUE) +FAST_NEAREST_MAINLOOP_COMMON (mmx_8888_n_8888_none_OVER, + scaled_nearest_scanline_mmx_8888_n_8888_OVER, + uint32_t, uint32_t, uint32_t, NONE, TRUE, TRUE) +FAST_NEAREST_MAINLOOP_COMMON (mmx_8888_n_8888_normal_OVER, + scaled_nearest_scanline_mmx_8888_n_8888_OVER, + uint32_t, uint32_t, uint32_t, NORMAL, TRUE, TRUE) + #define BSHIFT ((1 << BILINEAR_INTERPOLATION_BITS)) #define BMSK (BSHIFT - 1) #define BILINEAR_DECLARE_VARIABLES \ const __m64 mm_wt = _mm_set_pi16 (wt, wt, wt, wt); \ const __m64 mm_wb = _mm_set_pi16 (wb, wb, wb, wb); \ - const __m64 mm_BSHIFT = _mm_set_pi16 (BSHIFT, BSHIFT, BSHIFT, BSHIFT); \ const __m64 mm_addc7 = _mm_set_pi16 (0, 1, 0, 1); \ const __m64 mm_xorc7 = _mm_set_pi16 (0, BMSK, 0, BMSK); \ const __m64 mm_ux = _mm_set_pi16 (unit_x, unit_x, unit_x, unit_x); \ @@ -3559,36 +3667,16 @@ do { \ __m64 b_lo = _mm_mullo_pi16 (_mm_unpacklo_pi8 (b, mm_zero), mm_wb); \ __m64 hi = _mm_add_pi16 (t_hi, b_hi); \ __m64 lo = _mm_add_pi16 (t_lo, b_lo); \ - vx += unit_x; \ - if (BILINEAR_INTERPOLATION_BITS < 8) \ - { \ - /* calculate horizontal weights */ \ - __m64 mm_wh = _mm_add_pi16 (mm_addc7, _mm_xor_si64 (mm_xorc7, \ + /* calculate horizontal weights */ \ + __m64 mm_wh = _mm_add_pi16 (mm_addc7, _mm_xor_si64 (mm_xorc7, \ _mm_srli_pi16 (mm_x, \ 16 - BILINEAR_INTERPOLATION_BITS))); \ - /* horizontal interpolation */ \ - __m64 p = _mm_unpacklo_pi16 (lo, hi); \ - __m64 q = _mm_unpackhi_pi16 (lo, hi); \ - lo = _mm_madd_pi16 (p, mm_wh); \ - hi = _mm_madd_pi16 (q, mm_wh); \ - } \ - else \ - { \ - /* calculate horizontal weights */ \ - __m64 mm_wh_lo = _mm_sub_pi16 (mm_BSHIFT, _mm_srli_pi16 (mm_x, \ - 16 - BILINEAR_INTERPOLATION_BITS)); \ - __m64 mm_wh_hi = _mm_srli_pi16 (mm_x, \ - 16 - BILINEAR_INTERPOLATION_BITS); \ - /* horizontal interpolation */ \ - __m64 mm_lo_lo = _mm_mullo_pi16 (lo, mm_wh_lo); \ - __m64 mm_lo_hi = _mm_mullo_pi16 (hi, mm_wh_hi); \ - __m64 mm_hi_lo = _mm_mulhi_pu16 (lo, mm_wh_lo); \ - __m64 mm_hi_hi = _mm_mulhi_pu16 (hi, mm_wh_hi); \ - lo = _mm_add_pi32 (_mm_unpacklo_pi16 (mm_lo_lo, mm_hi_lo), \ - _mm_unpacklo_pi16 (mm_lo_hi, mm_hi_hi)); \ - hi = _mm_add_pi32 (_mm_unpackhi_pi16 (mm_lo_lo, mm_hi_lo), \ - _mm_unpackhi_pi16 (mm_lo_hi, mm_hi_hi)); \ - } \ + /* horizontal interpolation */ \ + __m64 p = _mm_unpacklo_pi16 (lo, hi); \ + __m64 q = _mm_unpackhi_pi16 (lo, hi); \ + vx += unit_x; \ + lo = _mm_madd_pi16 (p, mm_wh); \ + hi = _mm_madd_pi16 (q, mm_wh); \ mm_x = _mm_add_pi16 (mm_x, mm_ux); \ /* shift and pack the result */ \ hi = _mm_srli_pi32 (hi, BILINEAR_INTERPOLATION_BITS * 2); \ @@ -3866,7 +3954,7 @@ mmx_fetch_a8 (pixman_iter_t *iter, const uint32_t *mask) while (w && (((uintptr_t)dst) & 15)) { - *dst++ = *(src++) << 24; + *dst++ = (uint32_t)*(src++) << 24; w--; } @@ -3893,7 +3981,7 @@ mmx_fetch_a8 (pixman_iter_t *iter, const uint32_t *mask) while (w) { - *dst++ = *(src++) << 24; + *dst++ = (uint32_t)*(src++) << 24; w--; } @@ -3901,52 +3989,23 @@ mmx_fetch_a8 (pixman_iter_t *iter, const uint32_t *mask) return iter->buffer; } -typedef struct -{ - pixman_format_code_t format; - pixman_iter_get_scanline_t get_scanline; -} fetcher_info_t; - -static const fetcher_info_t fetchers[] = -{ - { PIXMAN_x8r8g8b8, mmx_fetch_x8r8g8b8 }, - { PIXMAN_r5g6b5, mmx_fetch_r5g6b5 }, - { PIXMAN_a8, mmx_fetch_a8 }, - { PIXMAN_null } -}; - -static pixman_bool_t -mmx_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) -{ - pixman_image_t *image = iter->image; - -#define FLAGS \ +#define IMAGE_FLAGS \ (FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM | \ FAST_PATH_BITS_IMAGE | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST) - if ((iter->iter_flags & ITER_NARROW) && - (iter->image_flags & FLAGS) == FLAGS) - { - const fetcher_info_t *f; - - for (f = &fetchers[0]; f->format != PIXMAN_null; f++) - { - if (image->common.extended_format_code == f->format) - { - uint8_t *b = (uint8_t *)image->bits.bits; - int s = image->bits.rowstride * 4; - - iter->bits = b + s * iter->y + iter->x * PIXMAN_FORMAT_BPP (f->format) / 8; - iter->stride = s; - - iter->get_scanline = f->get_scanline; - return TRUE; - } - } - } - - return FALSE; -} +static const pixman_iter_info_t mmx_iters[] = +{ + { PIXMAN_x8r8g8b8, IMAGE_FLAGS, ITER_NARROW, + _pixman_iter_init_bits_stride, mmx_fetch_x8r8g8b8, NULL + }, + { PIXMAN_r5g6b5, IMAGE_FLAGS, ITER_NARROW, + _pixman_iter_init_bits_stride, mmx_fetch_r5g6b5, NULL + }, + { PIXMAN_a8, IMAGE_FLAGS, ITER_NARROW, + _pixman_iter_init_bits_stride, mmx_fetch_a8, NULL + }, + { PIXMAN_null }, +}; static const pixman_fast_path_t mmx_fast_paths[] = { @@ -4024,6 +4083,16 @@ static const pixman_fast_path_t mmx_fast_paths[] = PIXMAN_STD_FAST_PATH (IN, a8, null, a8, mmx_composite_in_8_8 ), PIXMAN_STD_FAST_PATH (IN, solid, a8, a8, mmx_composite_in_n_8_8 ), + SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, mmx_8888_8888 ), + SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, mmx_8888_8888 ), + SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, mmx_8888_8888 ), + SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, mmx_8888_8888 ), + + SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, mmx_8888_n_8888 ), + SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, mmx_8888_n_8888 ), + SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, mmx_8888_n_8888 ), + SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, mmx_8888_n_8888 ), + SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, mmx_8888_8888 ), SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, mmx_8888_8888 ), SIMPLE_BILINEAR_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, mmx_8888_8888 ), @@ -4076,7 +4145,7 @@ _pixman_implementation_create_mmx (pixman_implementation_t *fallback) imp->blt = mmx_blt; imp->fill = mmx_fill; - imp->src_iter_init = mmx_src_iter_init; + imp->iter_info = mmx_iters; return imp; } diff --git a/gfx/cairo/libpixman/src/pixman-noop.c b/gfx/cairo/libpixman/src/pixman-noop.c index e39996d9df..e59890492f 100644 --- a/gfx/cairo/libpixman/src/pixman-noop.c +++ b/gfx/cairo/libpixman/src/pixman-noop.c @@ -37,12 +37,6 @@ noop_composite (pixman_implementation_t *imp, return; } -static void -dest_write_back_direct (pixman_iter_t *iter) -{ - iter->buffer += iter->image->bits.rowstride; -} - static uint32_t * noop_get_scanline (pixman_iter_t *iter, const uint32_t *mask) { @@ -53,110 +47,102 @@ noop_get_scanline (pixman_iter_t *iter, const uint32_t *mask) return result; } -static uint32_t * -get_scanline_null (pixman_iter_t *iter, const uint32_t *mask) -{ - return NULL; +static void +noop_init_solid_narrow (pixman_iter_t *iter, + const pixman_iter_info_t *info) +{ + pixman_image_t *image = iter->image; + uint32_t *buffer = iter->buffer; + uint32_t *end = buffer + iter->width; + uint32_t color; + + if (iter->image->type == SOLID) + color = image->solid.color_32; + else + color = image->bits.fetch_pixel_32 (&image->bits, 0, 0); + + while (buffer < end) + *(buffer++) = color; } -static pixman_bool_t -noop_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) +static void +noop_init_solid_wide (pixman_iter_t *iter, + const pixman_iter_info_t *info) +{ + pixman_image_t *image = iter->image; + argb_t *buffer = (argb_t *)iter->buffer; + argb_t *end = buffer + iter->width; + argb_t color; + + if (iter->image->type == SOLID) + color = image->solid.color_float; + else + color = image->bits.fetch_pixel_float (&image->bits, 0, 0); + + while (buffer < end) + *(buffer++) = color; +} + +static void +noop_init_direct_buffer (pixman_iter_t *iter, const pixman_iter_info_t *info) { pixman_image_t *image = iter->image; -#define FLAGS \ - (FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM) - - if (!image) - { - iter->get_scanline = get_scanline_null; - } - else if ((iter->iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) == - (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) - { - iter->get_scanline = _pixman_iter_get_scanline_noop; - } - else if (image->common.extended_format_code == PIXMAN_solid && - (iter->image->type == SOLID || - (iter->image_flags & FAST_PATH_NO_ALPHA_MAP))) - { - if (iter->iter_flags & ITER_NARROW) - { - uint32_t *buffer = iter->buffer; - uint32_t *end = buffer + iter->width; - uint32_t color; - - if (image->type == SOLID) - color = image->solid.color_32; - else - color = image->bits.fetch_pixel_32 (&image->bits, 0, 0); - - while (buffer < end) - *(buffer++) = color; - } - else - { - argb_t *buffer = (argb_t *)iter->buffer; - argb_t *end = buffer + iter->width; - argb_t color; - - if (image->type == SOLID) - color = image->solid.color_float; - else - color = image->bits.fetch_pixel_float (&image->bits, 0, 0); - - while (buffer < end) - *(buffer++) = color; - } - - iter->get_scanline = _pixman_iter_get_scanline_noop; - } - else if (image->common.extended_format_code == PIXMAN_a8r8g8b8 && - (iter->iter_flags & ITER_NARROW) && - (iter->image_flags & FLAGS) == FLAGS && - iter->x >= 0 && iter->y >= 0 && - iter->x + iter->width <= image->bits.width && - iter->y + iter->height <= image->bits.height) - { - iter->buffer = - image->bits.bits + iter->y * image->bits.rowstride + iter->x; - - iter->get_scanline = noop_get_scanline; - } - else - { - return FALSE; - } - - return TRUE; + iter->buffer = + image->bits.bits + iter->y * image->bits.rowstride + iter->x; } -static pixman_bool_t -noop_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) +static void +dest_write_back_direct (pixman_iter_t *iter) { - pixman_image_t *image = iter->image; - uint32_t image_flags = iter->image_flags; - uint32_t iter_flags = iter->iter_flags; - - if ((image_flags & FAST_PATH_STD_DEST_FLAGS) == FAST_PATH_STD_DEST_FLAGS && - (iter_flags & ITER_NARROW) == ITER_NARROW && - ((image->common.extended_format_code == PIXMAN_a8r8g8b8) || - (image->common.extended_format_code == PIXMAN_x8r8g8b8 && - (iter_flags & (ITER_LOCALIZED_ALPHA))))) - { - iter->buffer = image->bits.bits + iter->y * image->bits.rowstride + iter->x; - - iter->get_scanline = _pixman_iter_get_scanline_noop; - iter->write_back = dest_write_back_direct; - - return TRUE; - } - else - { - return FALSE; - } + iter->buffer += iter->image->bits.rowstride; } +static const pixman_iter_info_t noop_iters[] = +{ + /* Source iters */ + { PIXMAN_any, + 0, ITER_IGNORE_ALPHA | ITER_IGNORE_RGB | ITER_SRC, + NULL, + _pixman_iter_get_scanline_noop, + NULL + }, + { PIXMAN_solid, + FAST_PATH_NO_ALPHA_MAP, ITER_NARROW | ITER_SRC, + noop_init_solid_narrow, + _pixman_iter_get_scanline_noop, + NULL, + }, + { PIXMAN_solid, + FAST_PATH_NO_ALPHA_MAP, ITER_WIDE | ITER_SRC, + noop_init_solid_wide, + _pixman_iter_get_scanline_noop, + NULL + }, + { PIXMAN_a8r8g8b8, + FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM | + FAST_PATH_BITS_IMAGE | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST, + ITER_NARROW | ITER_SRC, + noop_init_direct_buffer, + noop_get_scanline, + NULL + }, + /* Dest iters */ + { PIXMAN_a8r8g8b8, + FAST_PATH_STD_DEST_FLAGS, ITER_NARROW | ITER_DEST, + noop_init_direct_buffer, + _pixman_iter_get_scanline_noop, + dest_write_back_direct + }, + { PIXMAN_x8r8g8b8, + FAST_PATH_STD_DEST_FLAGS, ITER_NARROW | ITER_DEST | ITER_LOCALIZED_ALPHA, + noop_init_direct_buffer, + _pixman_iter_get_scanline_noop, + dest_write_back_direct + }, + { PIXMAN_null }, +}; + static const pixman_fast_path_t noop_fast_paths[] = { { PIXMAN_OP_DST, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, noop_composite }, @@ -169,8 +155,7 @@ _pixman_implementation_create_noop (pixman_implementation_t *fallback) pixman_implementation_t *imp = _pixman_implementation_create (fallback, noop_fast_paths); - imp->src_iter_init = noop_src_iter_init; - imp->dest_iter_init = noop_dest_iter_init; + imp->iter_info = noop_iters; return imp; } diff --git a/gfx/cairo/libpixman/src/pixman-private.h b/gfx/cairo/libpixman/src/pixman-private.h index 2313e65583..a0459dac19 100644 --- a/gfx/cairo/libpixman/src/pixman-private.h +++ b/gfx/cairo/libpixman/src/pixman-private.h @@ -9,7 +9,13 @@ #ifndef MOZILLA_VERSION #error "Need mozilla headers" #endif +#ifdef MOZ_GFX_OPTIMIZE_MOBILE +#define LOW_QUALITY_INTERPOLATION +#define LOWER_QUALITY_INTERPOLATION +#define BILINEAR_INTERPOLATION_BITS 4 +#else #define BILINEAR_INTERPOLATION_BITS 7 +#endif #define BILINEAR_INTERPOLATION_RANGE (1 << BILINEAR_INTERPOLATION_BITS) /* @@ -31,6 +37,7 @@ #include #include #include +#include #include "pixman-compiler.h" @@ -58,7 +65,7 @@ struct argb_t float b; }; -typedef void (*fetch_scanline_t) (pixman_image_t *image, +typedef void (*fetch_scanline_t) (bits_image_t *image, int x, int y, int width, @@ -182,7 +189,9 @@ struct bits_image uint32_t * free_me; int rowstride; /* in number of uint32_t's */ - fetch_scanline_t fetch_scanline_16; + pixman_dither_t dither; + uint32_t dither_offset_y; + uint32_t dither_offset_x; fetch_scanline_t fetch_scanline_32; fetch_pixel_32_t fetch_pixel_32; @@ -192,8 +201,6 @@ struct bits_image fetch_pixel_float_t fetch_pixel_float; store_scanline_t store_scanline_float; - store_scanline_t store_scanline_16; - /* Used for indirect access to the bits */ pixman_read_memory_func_t read_func; pixman_write_memory_func_t write_func; @@ -214,10 +221,12 @@ union pixman_image typedef struct pixman_iter_t pixman_iter_t; typedef uint32_t *(* pixman_iter_get_scanline_t) (pixman_iter_t *iter, const uint32_t *mask); typedef void (* pixman_iter_write_back_t) (pixman_iter_t *iter); +typedef void (* pixman_iter_fini_t) (pixman_iter_t *iter); typedef enum { - ITER_NARROW = (1 << 0), + ITER_NARROW = (1 << 0), + ITER_WIDE = (1 << 1), /* "Localized alpha" is when the alpha channel is used only to compute * the alpha value of the destination. This means that the computation @@ -234,16 +243,15 @@ typedef enum * we can treat it as if it were ARGB, which means in some cases we can * avoid copying it to a temporary buffer. */ - ITER_LOCALIZED_ALPHA = (1 << 1), - ITER_IGNORE_ALPHA = (1 << 2), - ITER_IGNORE_RGB = (1 << 3), + ITER_LOCALIZED_ALPHA = (1 << 2), + ITER_IGNORE_ALPHA = (1 << 3), + ITER_IGNORE_RGB = (1 << 4), - /* With the addition of ITER_16 we now have two flags that to represent - * 3 pipelines. This means that there can be an invalid state when - * both ITER_NARROW and ITER_16 are set. In this case - * ITER_16 overrides NARROW and we should use the 16 bit pipeline. - * Note: ITER_16 still has a 32 bit mask, which is a bit weird. */ - ITER_16 = (1 << 4) + /* These indicate whether the iterator is for a source + * or a destination image + */ + ITER_SRC = (1 << 5), + ITER_DEST = (1 << 6) } iter_flags_t; struct pixman_iter_t @@ -260,6 +268,7 @@ struct pixman_iter_t /* These function pointers are initialized by the implementation */ pixman_iter_get_scanline_t get_scanline; pixman_iter_write_back_t write_back; + pixman_iter_fini_t fini; /* These fields are scratch data that implementations can use */ void * data; @@ -267,6 +276,19 @@ struct pixman_iter_t int stride; }; +typedef struct pixman_iter_info_t pixman_iter_info_t; +typedef void (* pixman_iter_initializer_t) (pixman_iter_t *iter, + const pixman_iter_info_t *info); +struct pixman_iter_info_t +{ + pixman_format_code_t format; + uint32_t image_flags; + iter_flags_t iter_flags; + pixman_iter_initializer_t initializer; + pixman_iter_get_scanline_t get_scanline; + pixman_iter_write_back_t write_back; +}; + void _pixman_bits_image_setup_accessors (bits_image_t *image); @@ -331,13 +353,12 @@ _pixman_image_validate (pixman_image_t *image); */ typedef struct { - uint32_t left_ag; - uint32_t left_rb; - uint32_t right_ag; - uint32_t right_rb; - pixman_fixed_t left_x; - pixman_fixed_t right_x; - pixman_fixed_t stepper; + float a_s, a_b; + float r_s, r_b; + float g_s, g_b; + float b_s, b_b; + pixman_fixed_48_16_t left_x; + pixman_fixed_48_16_t right_x; pixman_gradient_stop_t *stops; int num_stops; @@ -355,9 +376,38 @@ void _pixman_gradient_walker_reset (pixman_gradient_walker_t *walker, pixman_fixed_48_16_t pos); -uint32_t -_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker, - pixman_fixed_48_16_t x); +typedef void (*pixman_gradient_walker_write_t) ( + pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x, + uint32_t *buffer); + +void +_pixman_gradient_walker_write_narrow(pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x, + uint32_t *buffer); + +void +_pixman_gradient_walker_write_wide(pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x, + uint32_t *buffer); + +typedef void (*pixman_gradient_walker_fill_t) ( + pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x, + uint32_t *buffer, + uint32_t *end); + +void +_pixman_gradient_walker_fill_narrow(pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x, + uint32_t *buffer, + uint32_t *end); + +void +_pixman_gradient_walker_fill_wide(pixman_gradient_walker_t *walker, + pixman_fixed_48_16_t x, + uint32_t *buffer, + uint32_t *end); /* * Edges @@ -467,10 +517,7 @@ typedef pixman_bool_t (*pixman_fill_func_t) (pixman_implementation_t *imp, int width, int height, uint32_t filler); -typedef pixman_bool_t (*pixman_iter_init_func_t) (pixman_implementation_t *imp, - pixman_iter_t *iter); -void _pixman_setup_combiner_functions_16 (pixman_implementation_t *imp); void _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp); void _pixman_setup_combiner_functions_float (pixman_implementation_t *imp); @@ -491,14 +538,11 @@ struct pixman_implementation_t pixman_implementation_t * toplevel; pixman_implementation_t * fallback; const pixman_fast_path_t * fast_paths; + const pixman_iter_info_t * iter_info; pixman_blt_func_t blt; pixman_fill_func_t fill; - pixman_iter_init_func_t src_iter_init; - pixman_iter_init_func_t dest_iter_init; - pixman_combine_32_func_t combine_16[PIXMAN_N_OPERATORS]; - pixman_combine_32_func_t combine_16_ca[PIXMAN_N_OPERATORS]; pixman_combine_32_func_t combine_32[PIXMAN_N_OPERATORS]; pixman_combine_32_func_t combine_32_ca[PIXMAN_N_OPERATORS]; pixman_combine_float_func_t combine_float[PIXMAN_N_OPERATORS]; @@ -530,8 +574,7 @@ pixman_combine_32_func_t _pixman_implementation_lookup_combiner (pixman_implementation_t *imp, pixman_op_t op, pixman_bool_t component_alpha, - pixman_bool_t wide, - pixman_bool_t rgb16); + pixman_bool_t wide); pixman_bool_t _pixman_implementation_blt (pixman_implementation_t *imp, @@ -559,29 +602,17 @@ _pixman_implementation_fill (pixman_implementation_t *imp, int height, uint32_t filler); -pixman_bool_t -_pixman_implementation_src_iter_init (pixman_implementation_t *imp, - pixman_iter_t *iter, - pixman_image_t *image, - int x, - int y, - int width, - int height, - uint8_t *buffer, - iter_flags_t flags, - uint32_t image_flags); - -pixman_bool_t -_pixman_implementation_dest_iter_init (pixman_implementation_t *imp, - pixman_iter_t *iter, - pixman_image_t *image, - int x, - int y, - int width, - int height, - uint8_t *buffer, - iter_flags_t flags, - uint32_t image_flags); +void +_pixman_implementation_iter_init (pixman_implementation_t *imp, + pixman_iter_t *iter, + pixman_image_t *image, + int x, + int y, + int width, + int height, + uint8_t *buffer, + iter_flags_t flags, + uint32_t image_flags); /* Specific implementations */ pixman_implementation_t * @@ -603,6 +634,11 @@ pixman_implementation_t * _pixman_implementation_create_sse2 (pixman_implementation_t *fallback); #endif +#ifdef USE_SSSE3 +pixman_implementation_t * +_pixman_implementation_create_ssse3 (pixman_implementation_t *fallback); +#endif + #ifdef USE_ARM_SIMD pixman_implementation_t * _pixman_implementation_create_arm_simd (pixman_implementation_t *fallback); @@ -664,6 +700,9 @@ _pixman_compute_composite_region32 (pixman_region32_t * region, uint32_t * _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask); +void +_pixman_iter_init_bits_stride (pixman_iter_t *iter, const pixman_iter_info_t *info); + /* These "formats" all have depth 0, so they * will never clash with any real ones */ @@ -703,7 +742,6 @@ _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask); #define FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR (1 << 24) #define FAST_PATH_BITS_IMAGE (1 << 25) #define FAST_PATH_SEPARABLE_CONVOLUTION_FILTER (1 << 26) -#define FAST_PATH_16_FORMAT (1 << 27) #define FAST_PATH_PAD_REPEAT \ (FAST_PATH_NO_NONE_REPEAT | \ @@ -795,6 +833,9 @@ pixman_malloc_ab (unsigned int n, unsigned int b); void * pixman_malloc_abc (unsigned int a, unsigned int b, unsigned int c); +void * +pixman_malloc_ab_plus_c (unsigned int a, unsigned int b, unsigned int c); + pixman_bool_t _pixman_multiply_overflows_size (size_t a, size_t b); @@ -898,6 +939,8 @@ pixman_list_move_to_front (pixman_list_t *list, pixman_link_t *link) #define CLIP(v, low, high) ((v) < (low) ? (low) : ((v) > (high) ? (high) : (v))) +#define FLOAT_IS_ZERO(f) (-FLT_MIN < (f) && (f) < FLT_MIN) + /* Conversion between 8888 and 0565 */ static force_inline uint16_t @@ -1033,15 +1076,13 @@ float pixman_unorm_to_float (uint16_t u, int n_bits); #endif -#ifdef DEBUG - void _pixman_log_error (const char *function, const char *message); #define return_if_fail(expr) \ do \ { \ - if (!(expr)) \ + if (unlikely (!(expr))) \ { \ _pixman_log_error (FUNC, "The expression " # expr " was false"); \ return; \ @@ -1052,7 +1093,7 @@ _pixman_log_error (const char *function, const char *message); #define return_val_if_fail(expr, retval) \ do \ { \ - if (!(expr)) \ + if (unlikely (!(expr))) \ { \ _pixman_log_error (FUNC, "The expression " # expr " was false"); \ return (retval); \ @@ -1063,55 +1104,30 @@ _pixman_log_error (const char *function, const char *message); #define critical_if_fail(expr) \ do \ { \ - if (!(expr)) \ + if (unlikely (!(expr))) \ _pixman_log_error (FUNC, "The expression " # expr " was false"); \ } \ while (0) - -#else - -#define _pixman_log_error(f,m) do { } while (0) - -#define return_if_fail(expr) \ - do \ - { \ - if (!(expr)) \ - return; \ - } \ - while (0) - -#define return_val_if_fail(expr, retval) \ - do \ - { \ - if (!(expr)) \ - return (retval); \ - } \ - while (0) - -#define critical_if_fail(expr) \ - do \ - { \ - } \ - while (0) -#endif - /* * Matrix */ typedef struct { pixman_fixed_48_16_t v[3]; } pixman_vector_48_16_t; +PIXMAN_EXPORT pixman_bool_t pixman_transform_point_31_16 (const pixman_transform_t *t, const pixman_vector_48_16_t *v, pixman_vector_48_16_t *result); +PIXMAN_EXPORT void pixman_transform_point_31_16_3d (const pixman_transform_t *t, const pixman_vector_48_16_t *v, pixman_vector_48_16_t *result); +PIXMAN_EXPORT void pixman_transform_point_31_16_affine (const pixman_transform_t *t, const pixman_vector_48_16_t *v, diff --git a/gfx/cairo/libpixman/src/pixman-radial-gradient.c b/gfx/cairo/libpixman/src/pixman-radial-gradient.c index 3d539b1c86..e8e99c98b9 100644 --- a/gfx/cairo/libpixman/src/pixman-radial-gradient.c +++ b/gfx/cairo/libpixman/src/pixman-radial-gradient.c @@ -34,8 +34,6 @@ #include #include "pixman-private.h" -#include "pixman-dither.h" - static inline pixman_fixed_32_32_t dot (pixman_fixed_48_16_t x1, pixman_fixed_48_16_t y1, @@ -68,15 +66,18 @@ fdot (double x1, return x1 * x2 + y1 * y2 + z1 * z2; } -static uint32_t -radial_compute_color (double a, - double b, - double c, - double inva, - double dr, - double mindr, - pixman_gradient_walker_t *walker, - pixman_repeat_t repeat) +static void +radial_write_color (double a, + double b, + double c, + double inva, + double dr, + double mindr, + pixman_gradient_walker_t *walker, + pixman_repeat_t repeat, + int Bpp, + pixman_gradient_walker_write_t write_pixel, + uint32_t *buffer) { /* * In this function error propagation can lead to bad results: @@ -101,21 +102,31 @@ radial_compute_color (double a, double t; if (b == 0) - return 0; + { + memset (buffer, 0, Bpp); + return; + } t = pixman_fixed_1 / 2 * c / b; if (repeat == PIXMAN_REPEAT_NONE) { if (0 <= t && t <= pixman_fixed_1) - return _pixman_gradient_walker_pixel (walker, t); + { + write_pixel (walker, t, buffer); + return; + } } else { if (t * dr >= mindr) - return _pixman_gradient_walker_pixel (walker, t); + { + write_pixel (walker, t, buffer); + return; + } } - return 0; + memset (buffer, 0, Bpp); + return; } discr = fdot (b, a, 0, b, -c, 0); @@ -141,24 +152,40 @@ radial_compute_color (double a, if (repeat == PIXMAN_REPEAT_NONE) { if (0 <= t0 && t0 <= pixman_fixed_1) - return _pixman_gradient_walker_pixel (walker, t0); + { + write_pixel (walker, t0, buffer); + return; + } else if (0 <= t1 && t1 <= pixman_fixed_1) - return _pixman_gradient_walker_pixel (walker, t1); + { + write_pixel (walker, t1, buffer); + return; + } } else { if (t0 * dr >= mindr) - return _pixman_gradient_walker_pixel (walker, t0); + { + write_pixel (walker, t0, buffer); + return; + } else if (t1 * dr >= mindr) - return _pixman_gradient_walker_pixel (walker, t1); + { + write_pixel (walker, t1, buffer); + return; + } } } - return 0; + memset (buffer, 0, Bpp); + return; } static uint32_t * -radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) +radial_get_scanline (pixman_iter_t *iter, + const uint32_t *mask, + int Bpp, + pixman_gradient_walker_write_t write_pixel) { /* * Implementation of radial gradients following the PDF specification. @@ -249,7 +276,7 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) gradient_t *gradient = (gradient_t *)image; radial_gradient_t *radial = (radial_gradient_t *)image; - uint32_t *end = buffer + width; + uint32_t *end = buffer + width * (Bpp / 4); pixman_gradient_walker_t walker; pixman_vector_t v, unit; @@ -332,18 +359,21 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) { if (!mask || *mask++) { - *buffer = radial_compute_color (radial->a, b, c, - radial->inva, - radial->delta.radius, - radial->mindr, - &walker, - image->common.repeat); + radial_write_color (radial->a, b, c, + radial->inva, + radial->delta.radius, + radial->mindr, + &walker, + image->common.repeat, + Bpp, + write_pixel, + buffer); } b += db; c += dc; dc += ddc; - ++buffer; + buffer += (Bpp / 4); } } else @@ -377,20 +407,23 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) pdx, pdy, radial->c1.radius); /* / pixman_fixed_1 / pixman_fixed_1 */ - *buffer = radial_compute_color (radial->a, b, c, - radial->inva, - radial->delta.radius, - radial->mindr, - &walker, - image->common.repeat); + radial_write_color (radial->a, b, c, + radial->inva, + radial->delta.radius, + radial->mindr, + &walker, + image->common.repeat, + Bpp, + write_pixel, + buffer); } else { - *buffer = 0; + memset (buffer, 0, Bpp); } } - ++buffer; + buffer += (Bpp / 4); v.vector[0] += unit.vector[0]; v.vector[1] += unit.vector[1]; @@ -403,286 +436,35 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) } static uint32_t * -radial_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask) +radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) { - /* - * Implementation of radial gradients following the PDF specification. - * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference - * Manual (PDF 32000-1:2008 at the time of this writing). - * - * In the radial gradient problem we are given two circles (c₁,r₁) and - * (c₂,r₂) that define the gradient itself. - * - * Mathematically the gradient can be defined as the family of circles - * - * ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂) - * - * excluding those circles whose radius would be < 0. When a point - * belongs to more than one circle, the one with a bigger t is the only - * one that contributes to its color. When a point does not belong - * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0). - * Further limitations on the range of values for t are imposed when - * the gradient is not repeated, namely t must belong to [0,1]. - * - * The graphical result is the same as drawing the valid (radius > 0) - * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient - * is not repeated) using SOURCE operator composition. - * - * It looks like a cone pointing towards the viewer if the ending circle - * is smaller than the starting one, a cone pointing inside the page if - * the starting circle is the smaller one and like a cylinder if they - * have the same radius. - * - * What we actually do is, given the point whose color we are interested - * in, compute the t values for that point, solving for t in: - * - * length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂ - * - * Let's rewrite it in a simpler way, by defining some auxiliary - * variables: - * - * cd = c₂ - c₁ - * pd = p - c₁ - * dr = r₂ - r₁ - * length(t·cd - pd) = r₁ + t·dr - * - * which actually means - * - * hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr - * - * or - * - * ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr. - * - * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes: - * - * (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)² - * - * where we can actually expand the squares and solve for t: - * - * t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² = - * = r₁² + 2·r₁·t·dr + t²·dr² - * - * (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t + - * (pdx² + pdy² - r₁²) = 0 - * - * A = cdx² + cdy² - dr² - * B = pdx·cdx + pdy·cdy + r₁·dr - * C = pdx² + pdy² - r₁² - * At² - 2Bt + C = 0 - * - * The solutions (unless the equation degenerates because of A = 0) are: - * - * t = (B ± ⎷(B² - A·C)) / A - * - * The solution we are going to prefer is the bigger one, unless the - * radius associated to it is negative (or it falls outside the valid t - * range). - * - * Additional observations (useful for optimizations): - * A does not depend on p - * - * A < 0 <=> one of the two circles completely contains the other one - * <=> for every p, the radiuses associated with the two t solutions - * have opposite sign - */ - pixman_image_t *image = iter->image; - int x = iter->x; - int y = iter->y; - int width = iter->width; - uint16_t *buffer = iter->buffer; - pixman_bool_t toggle = ((x ^ y) & 1); - - gradient_t *gradient = (gradient_t *)image; - radial_gradient_t *radial = (radial_gradient_t *)image; - uint16_t *end = buffer + width; - pixman_gradient_walker_t walker; - pixman_vector_t v, unit; - - /* reference point is the center of the pixel */ - v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; - v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; - v.vector[2] = pixman_fixed_1; - - _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); - - if (image->common.transform) - { - if (!pixman_transform_point_3d (image->common.transform, &v)) - return iter->buffer; - - unit.vector[0] = image->common.transform->matrix[0][0]; - unit.vector[1] = image->common.transform->matrix[1][0]; - unit.vector[2] = image->common.transform->matrix[2][0]; - } - else - { - unit.vector[0] = pixman_fixed_1; - unit.vector[1] = 0; - unit.vector[2] = 0; - } - - if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1) - { - /* - * Given: - * - * t = (B ± ⎷(B² - A·C)) / A - * - * where - * - * A = cdx² + cdy² - dr² - * B = pdx·cdx + pdy·cdy + r₁·dr - * C = pdx² + pdy² - r₁² - * det = B² - A·C - * - * Since we have an affine transformation, we know that (pdx, pdy) - * increase linearly with each pixel, - * - * pdx = pdx₀ + n·ux, - * pdy = pdy₀ + n·uy, - * - * we can then express B, C and det through multiple differentiation. - */ - pixman_fixed_32_32_t b, db, c, dc, ddc; - - /* warning: this computation may overflow */ - v.vector[0] -= radial->c1.x; - v.vector[1] -= radial->c1.y; - - /* - * B and C are computed and updated exactly. - * If fdot was used instead of dot, in the worst case it would - * lose 11 bits of precision in each of the multiplication and - * summing up would zero out all the bit that were preserved, - * thus making the result 0 instead of the correct one. - * This would mean a worst case of unbound relative error or - * about 2^10 absolute error - */ - b = dot (v.vector[0], v.vector[1], radial->c1.radius, - radial->delta.x, radial->delta.y, radial->delta.radius); - db = dot (unit.vector[0], unit.vector[1], 0, - radial->delta.x, radial->delta.y, 0); - - c = dot (v.vector[0], v.vector[1], - -((pixman_fixed_48_16_t) radial->c1.radius), - v.vector[0], v.vector[1], radial->c1.radius); - dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0], - 2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1], - 0, - unit.vector[0], unit.vector[1], 0); - ddc = 2 * dot (unit.vector[0], unit.vector[1], 0, - unit.vector[0], unit.vector[1], 0); - - while (buffer < end) - { - if (!mask || *mask++) - { - *buffer = dither_8888_to_0565( - radial_compute_color (radial->a, b, c, - radial->inva, - radial->delta.radius, - radial->mindr, - &walker, - image->common.repeat), - toggle); - } - - toggle ^= 1; - b += db; - c += dc; - dc += ddc; - ++buffer; - } - } - else - { - /* projective */ - /* Warning: - * error propagation guarantees are much looser than in the affine case - */ - while (buffer < end) - { - if (!mask || *mask++) - { - if (v.vector[2] != 0) - { - double pdx, pdy, invv2, b, c; - - invv2 = 1. * pixman_fixed_1 / v.vector[2]; - - pdx = v.vector[0] * invv2 - radial->c1.x; - /* / pixman_fixed_1 */ - - pdy = v.vector[1] * invv2 - radial->c1.y; - /* / pixman_fixed_1 */ - - b = fdot (pdx, pdy, radial->c1.radius, - radial->delta.x, radial->delta.y, - radial->delta.radius); - /* / pixman_fixed_1 / pixman_fixed_1 */ - - c = fdot (pdx, pdy, -radial->c1.radius, - pdx, pdy, radial->c1.radius); - /* / pixman_fixed_1 / pixman_fixed_1 */ - - *buffer = dither_8888_to_0565 ( - radial_compute_color (radial->a, b, c, - radial->inva, - radial->delta.radius, - radial->mindr, - &walker, - image->common.repeat), - toggle); - } - else - { - *buffer = 0; - } - } - - ++buffer; - toggle ^= 1; - - v.vector[0] += unit.vector[0]; - v.vector[1] += unit.vector[1]; - v.vector[2] += unit.vector[2]; - } - } - - iter->y++; - return iter->buffer; + return radial_get_scanline (iter, mask, 4, + _pixman_gradient_walker_write_narrow); } + static uint32_t * radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) { - uint32_t *buffer = radial_get_scanline_narrow (iter, NULL); - - pixman_expand_to_float ( - (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); - - return buffer; + return radial_get_scanline (iter, NULL, 16, + _pixman_gradient_walker_write_wide); } void _pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) { - if (iter->iter_flags & ITER_16) - iter->get_scanline = radial_get_scanline_16; - else if (iter->iter_flags & ITER_NARROW) + if (iter->iter_flags & ITER_NARROW) iter->get_scanline = radial_get_scanline_narrow; else iter->get_scanline = radial_get_scanline_wide; } - PIXMAN_EXPORT pixman_image_t * pixman_image_create_radial_gradient (const pixman_point_fixed_t * inner, - const pixman_point_fixed_t * outer, - pixman_fixed_t inner_radius, - pixman_fixed_t outer_radius, - const pixman_gradient_stop_t *stops, - int n_stops) + const pixman_point_fixed_t * outer, + pixman_fixed_t inner_radius, + pixman_fixed_t outer_radius, + const pixman_gradient_stop_t *stops, + int n_stops) { pixman_image_t *image; radial_gradient_t *radial; diff --git a/gfx/cairo/libpixman/src/pixman-region.c b/gfx/cairo/libpixman/src/pixman-region.c index 7f2e29b15b..59bc9c7971 100644 --- a/gfx/cairo/libpixman/src/pixman-region.c +++ b/gfx/cairo/libpixman/src/pixman-region.c @@ -298,13 +298,6 @@ PREFIX (_equal) (region_type_t *reg1, region_type_t *reg2) box_type_t *rects1; box_type_t *rects2; - /* - * If the region is empty the extents are undefined so we need to check - * for empty before comparing the extents. - */ - if (PIXREGION_NIL (reg1) && PIXREGION_NIL(reg2)) - return TRUE; - if (reg1->extents.x1 != reg2->extents.x1) return FALSE; @@ -1341,15 +1334,6 @@ PREFIX(_intersect_rect) (region_type_t *dest, region.extents.x2 = x + width; region.extents.y2 = y + height; - if (!GOOD_RECT (®ion.extents)) - { - if (BAD_RECT (®ion.extents)) - _pixman_log_error (FUNC, "Invalid rectangle passed"); - FREE_DATA (dest); - PREFIX (_init) (dest); - return TRUE; - } - return PREFIX(_intersect) (dest, source, ®ion); } @@ -1874,7 +1858,7 @@ pixman_region_subtract_o (region_type_t * region, else if (r2->x1 <= x1) { /* - * Subtrahend preceeds minuend: nuke left edge of minuend. + * Subtrahend precedes minuend: nuke left edge of minuend. */ x1 = r2->x2; if (x1 >= r1->x2) @@ -1998,7 +1982,7 @@ PREFIX (_subtract) (region_type_t *reg_d, } /* Add those rectangles in region 1 that aren't in region 2, - do yucky substraction for overlaps, and + do yucky subtraction for overlaps, and just throw away rectangles in region 2 that aren't in region 1 */ if (!pixman_op (reg_d, reg_m, reg_s, pixman_region_subtract_o, TRUE, FALSE)) return FALSE; @@ -2058,7 +2042,7 @@ PREFIX (_inverse) (region_type_t *new_reg, /* Destination region */ } /* Add those rectangles in region 1 that aren't in region 2, - * do yucky substraction for overlaps, and + * do yucky subtraction for overlaps, and * just throw away rectangles in region 2 that aren't in region 1 */ inv_reg.extents = *inv_rect; diff --git a/gfx/cairo/libpixman/src/pixman-solid-fill.c b/gfx/cairo/libpixman/src/pixman-solid-fill.c index 5f9fef6306..4694ebc700 100644 --- a/gfx/cairo/libpixman/src/pixman-solid-fill.c +++ b/gfx/cairo/libpixman/src/pixman-solid-fill.c @@ -30,10 +30,10 @@ static uint32_t color_to_uint32 (const pixman_color_t *color) { return - (color->alpha >> 8 << 24) | - (color->red >> 8 << 16) | - (color->green & 0xff00) | - (color->blue >> 8); + ((unsigned int) color->alpha >> 8 << 24) | + ((unsigned int) color->red >> 8 << 16) | + ((unsigned int) color->green & 0xff00) | + ((unsigned int) color->blue >> 8); } static argb_t diff --git a/gfx/cairo/libpixman/src/pixman-sse2.c b/gfx/cairo/libpixman/src/pixman-sse2.c index e4e668d389..ce4e75f247 100644 --- a/gfx/cairo/libpixman/src/pixman-sse2.c +++ b/gfx/cairo/libpixman/src/pixman-sse2.c @@ -30,6 +30,9 @@ #include #endif +/* PSHUFD is slow on a lot of old processors, and new processors have SSSE3 */ +#define PSHUFD_IS_FAST 0 + #include /* for _mm_shuffle_pi16 and _MM_SHUFFLE */ #include /* for SSE2 intrinsics */ #include "pixman-private.h" @@ -515,7 +518,8 @@ core_combine_over_u_pixel_sse2 (uint32_t src, uint32_t dst) static force_inline uint32_t combine1 (const uint32_t *ps, const uint32_t *pm) { - uint32_t s = *ps; + uint32_t s; + memcpy(&s, ps, sizeof(uint32_t)); if (pm) { @@ -3198,7 +3202,7 @@ sse2_composite_over_n_8_8888 (pixman_implementation_t *imp, uint8_t *mask_line, *mask; int dst_stride, mask_stride; int32_t w; - uint32_t m, d; + uint32_t d; __m128i xmm_src, xmm_alpha, xmm_def; __m128i xmm_dst, xmm_dst_lo, xmm_dst_hi; @@ -3253,7 +3257,8 @@ sse2_composite_over_n_8_8888 (pixman_implementation_t *imp, while (w >= 4) { - m = *((uint32_t*)mask); + uint32_t m; + memcpy(&m, mask, sizeof(uint32_t)); if (srca == 0xff && m == 0xffffffff) { @@ -3330,8 +3335,8 @@ sse2_fill (pixman_implementation_t *imp, if (bpp == 8) { - uint8_t b; - uint16_t w; + uint32_t b; + uint32_t w; stride = stride * (int) sizeof (uint32_t) / 1; byte_line = (uint8_t *)(((uint8_t *)bits) + stride * y + x); @@ -3473,7 +3478,6 @@ sse2_composite_src_n_8_8888 (pixman_implementation_t *imp, uint8_t *mask_line, *mask; int dst_stride, mask_stride; int32_t w; - uint32_t m; __m128i xmm_src, xmm_def; __m128i xmm_mask, xmm_mask_lo, xmm_mask_hi; @@ -3525,7 +3529,8 @@ sse2_composite_src_n_8_8888 (pixman_implementation_t *imp, while (w >= 4) { - m = *((uint32_t*)mask); + uint32_t m; + memcpy(&m, mask, sizeof(uint32_t)); if (srca == 0xff && m == 0xffffffff) { @@ -3591,7 +3596,6 @@ sse2_composite_over_n_8_0565 (pixman_implementation_t *imp, uint8_t *mask_line, *mask; int dst_stride, mask_stride; int32_t w; - uint32_t m; __m128i mmx_src, mmx_alpha, mmx_mask, mmx_dest; __m128i xmm_src, xmm_alpha; @@ -3623,7 +3627,7 @@ sse2_composite_over_n_8_0565 (pixman_implementation_t *imp, while (w && (uintptr_t)dst & 15) { - m = *mask++; + uint8_t m = *mask++; if (m) { @@ -3643,11 +3647,13 @@ sse2_composite_over_n_8_0565 (pixman_implementation_t *imp, while (w >= 8) { + uint32_t m; + xmm_dst = load_128_aligned ((__m128i*) dst); unpack_565_128_4x128 (xmm_dst, &xmm_dst0, &xmm_dst1, &xmm_dst2, &xmm_dst3); - m = *((uint32_t*)mask); + memcpy(&m, mask, sizeof(uint32_t)); mask += 4; if (m) @@ -3667,7 +3673,7 @@ sse2_composite_over_n_8_0565 (pixman_implementation_t *imp, &xmm_dst0, &xmm_dst1); } - m = *((uint32_t*)mask); + memcpy(&m, mask, sizeof(uint32_t)); mask += 4; if (m) @@ -3696,7 +3702,7 @@ sse2_composite_over_n_8_0565 (pixman_implementation_t *imp, while (w) { - m = *mask++; + uint8_t m = *mask++; if (m) { @@ -4058,7 +4064,7 @@ sse2_composite_in_n_8_8 (pixman_implementation_t *imp, uint8_t *dst_line, *dst; uint8_t *mask_line, *mask; int dst_stride, mask_stride; - uint32_t d, m; + uint32_t d; uint32_t src; int32_t w; @@ -4085,7 +4091,7 @@ sse2_composite_in_n_8_8 (pixman_implementation_t *imp, while (w && ((uintptr_t)dst & 15)) { - m = (uint32_t) *mask++; + uint8_t m = *mask++; d = (uint32_t) *dst; *dst++ = (uint8_t) pack_1x128_32 ( @@ -4122,7 +4128,7 @@ sse2_composite_in_n_8_8 (pixman_implementation_t *imp, while (w) { - m = (uint32_t) *mask++; + uint8_t m = *mask++; d = (uint32_t) *dst; *dst++ = (uint8_t) pack_1x128_32 ( @@ -4299,7 +4305,7 @@ sse2_composite_add_n_8_8 (pixman_implementation_t *imp, int dst_stride, mask_stride; int32_t w; uint32_t src; - uint32_t m, d; + uint32_t d; __m128i xmm_alpha; __m128i xmm_mask, xmm_mask_lo, xmm_mask_hi; @@ -4324,7 +4330,7 @@ sse2_composite_add_n_8_8 (pixman_implementation_t *imp, while (w && ((uintptr_t)dst & 15)) { - m = (uint32_t) *mask++; + uint8_t m = *mask++; d = (uint32_t) *dst; *dst++ = (uint8_t) pack_1x128_32 ( @@ -4360,7 +4366,7 @@ sse2_composite_add_n_8_8 (pixman_implementation_t *imp, while (w) { - m = (uint32_t) *mask++; + uint8_t m = (uint32_t) *mask++; d = (uint32_t) *dst; *dst++ = (uint8_t) pack_1x128_32 ( @@ -4558,7 +4564,7 @@ sse2_composite_add_n_8888 (pixman_implementation_t *imp, dst = dst_line; dst_line += dst_stride; - while (w && (unsigned long)dst & 15) + while (w && (uintptr_t)dst & 15) { d = *dst; *dst++ = @@ -4617,7 +4623,7 @@ sse2_composite_add_n_8_8888 (pixman_implementation_t *imp, mask_line += mask_stride; w = width; - while (w && ((unsigned long)dst & 15)) + while (w && ((uintptr_t)dst & 15)) { uint8_t m = *mask++; if (m) @@ -4633,7 +4639,9 @@ sse2_composite_add_n_8_8888 (pixman_implementation_t *imp, while (w >= 4) { - uint32_t m = *(uint32_t*)mask; + uint32_t m; + memcpy(&m, mask, sizeof(uint32_t)); + if (m) { __m128i xmm_mask_lo, xmm_mask_hi; @@ -4740,7 +4748,7 @@ sse2_blt (pixman_implementation_t *imp, while (w >= 2 && ((uintptr_t)d & 3)) { - *(uint16_t *)d = *(uint16_t *)s; + memmove(d, s, 2); w -= 2; s += 2; d += 2; @@ -4748,7 +4756,7 @@ sse2_blt (pixman_implementation_t *imp, while (w >= 4 && ((uintptr_t)d & 15)) { - *(uint32_t *)d = *(uint32_t *)s; + memmove(d, s, 4); w -= 4; s += 4; @@ -4785,7 +4793,7 @@ sse2_blt (pixman_implementation_t *imp, while (w >= 4) { - *(uint32_t *)d = *(uint32_t *)s; + memmove(d, s, 4); w -= 4; s += 4; @@ -4794,7 +4802,7 @@ sse2_blt (pixman_implementation_t *imp, if (w >= 2) { - *(uint16_t *)d = *(uint16_t *)s; + memmove(d, s, 2); w -= 2; s += 2; d += 2; @@ -4826,7 +4834,6 @@ sse2_composite_over_x888_8_8888 (pixman_implementation_t *imp, uint32_t *src, *src_line, s; uint32_t *dst, *dst_line, d; uint8_t *mask, *mask_line; - uint32_t m; int src_stride, mask_stride, dst_stride; int32_t w; __m128i ms; @@ -4855,8 +4862,8 @@ sse2_composite_over_x888_8_8888 (pixman_implementation_t *imp, while (w && (uintptr_t)dst & 15) { + uint8_t m = *mask++; s = 0xff000000 | *src++; - m = (uint32_t) *mask++; d = *dst; ms = unpack_32_1x128 (s); @@ -4874,7 +4881,8 @@ sse2_composite_over_x888_8_8888 (pixman_implementation_t *imp, while (w >= 4) { - m = *(uint32_t*) mask; + uint32_t m; + memcpy(&m, mask, sizeof(uint32_t)); xmm_src = _mm_or_si128 ( load_128_unaligned ((__m128i*)src), mask_ff000000); @@ -4910,7 +4918,7 @@ sse2_composite_over_x888_8_8888 (pixman_implementation_t *imp, while (w) { - m = (uint32_t) *mask++; + uint8_t m = *mask++; if (m) { @@ -4951,7 +4959,6 @@ sse2_composite_over_8888_8_8888 (pixman_implementation_t *imp, uint32_t *src, *src_line, s; uint32_t *dst, *dst_line, d; uint8_t *mask, *mask_line; - uint32_t m; int src_stride, mask_stride, dst_stride; int32_t w; @@ -4980,9 +4987,9 @@ sse2_composite_over_8888_8_8888 (pixman_implementation_t *imp, while (w && (uintptr_t)dst & 15) { uint32_t sa; + uint8_t m = *mask++; s = *src++; - m = (uint32_t) *mask++; d = *dst; sa = s >> 24; @@ -5013,7 +5020,8 @@ sse2_composite_over_8888_8_8888 (pixman_implementation_t *imp, while (w >= 4) { - m = *(uint32_t *) mask; + uint32_t m; + memcpy(&m, mask, sizeof(uint32_t)); if (m) { @@ -5052,9 +5060,9 @@ sse2_composite_over_8888_8_8888 (pixman_implementation_t *imp, while (w) { uint32_t sa; + uint8_t m = *mask++; s = *src++; - m = (uint32_t) *mask++; d = *dst; sa = s >> 24; @@ -5554,69 +5562,134 @@ FAST_NEAREST_MAINLOOP_COMMON (sse2_8888_n_8888_normal_OVER, scaled_nearest_scanline_sse2_8888_n_8888_OVER, uint32_t, uint32_t, uint32_t, NORMAL, TRUE, TRUE) -#define BMSK ((1 << BILINEAR_INTERPOLATION_BITS) - 1) +#if PSHUFD_IS_FAST -#define BILINEAR_DECLARE_VARIABLES \ +/***********************************************************************************/ + +# define BILINEAR_DECLARE_VARIABLES \ const __m128i xmm_wt = _mm_set_epi16 (wt, wt, wt, wt, wt, wt, wt, wt); \ const __m128i xmm_wb = _mm_set_epi16 (wb, wb, wb, wb, wb, wb, wb, wb); \ - const __m128i xmm_xorc8 = _mm_set_epi16 (0, 0, 0, 0, BMSK, BMSK, BMSK, BMSK);\ - const __m128i xmm_addc8 = _mm_set_epi16 (0, 0, 0, 0, 1, 1, 1, 1); \ - const __m128i xmm_xorc7 = _mm_set_epi16 (0, BMSK, 0, BMSK, 0, BMSK, 0, BMSK);\ - const __m128i xmm_addc7 = _mm_set_epi16 (0, 1, 0, 1, 0, 1, 0, 1); \ - const __m128i xmm_ux = _mm_set_epi16 (unit_x, unit_x, unit_x, unit_x, \ - unit_x, unit_x, unit_x, unit_x); \ + const __m128i xmm_addc = _mm_set_epi16 (0, 1, 0, 1, 0, 1, 0, 1); \ + const __m128i xmm_ux1 = _mm_set_epi16 (unit_x, -unit_x, unit_x, -unit_x, \ + unit_x, -unit_x, unit_x, -unit_x); \ + const __m128i xmm_ux4 = _mm_set_epi16 (unit_x * 4, -unit_x * 4, \ + unit_x * 4, -unit_x * 4, \ + unit_x * 4, -unit_x * 4, \ + unit_x * 4, -unit_x * 4); \ const __m128i xmm_zero = _mm_setzero_si128 (); \ - __m128i xmm_x = _mm_set_epi16 (vx, vx, vx, vx, vx, vx, vx, vx) + __m128i xmm_x = _mm_set_epi16 (vx + unit_x * 3, -(vx + 1) - unit_x * 3, \ + vx + unit_x * 2, -(vx + 1) - unit_x * 2, \ + vx + unit_x * 1, -(vx + 1) - unit_x * 1, \ + vx + unit_x * 0, -(vx + 1) - unit_x * 0); \ + __m128i xmm_wh_state; -#define BILINEAR_INTERPOLATE_ONE_PIXEL(pix) \ +#define BILINEAR_INTERPOLATE_ONE_PIXEL_HELPER(pix, phase_) \ do { \ - __m128i xmm_wh, xmm_lo, xmm_hi, a; \ + int phase = phase_; \ + __m128i xmm_wh, xmm_a, xmm_b; \ /* fetch 2x2 pixel block into sse2 registers */ \ - __m128i tltr = _mm_loadl_epi64 ( \ - (__m128i *)&src_top[pixman_fixed_to_int (vx)]); \ - __m128i blbr = _mm_loadl_epi64 ( \ - (__m128i *)&src_bottom[pixman_fixed_to_int (vx)]); \ + __m128i tltr = _mm_loadl_epi64 ((__m128i *)&src_top[vx >> 16]); \ + __m128i blbr = _mm_loadl_epi64 ((__m128i *)&src_bottom[vx >> 16]); \ vx += unit_x; \ /* vertical interpolation */ \ - a = _mm_add_epi16 (_mm_mullo_epi16 (_mm_unpacklo_epi8 (tltr, xmm_zero), \ - xmm_wt), \ - _mm_mullo_epi16 (_mm_unpacklo_epi8 (blbr, xmm_zero), \ - xmm_wb)); \ - if (BILINEAR_INTERPOLATION_BITS < 8) \ + xmm_a = _mm_mullo_epi16 (_mm_unpacklo_epi8 (tltr, xmm_zero), xmm_wt); \ + xmm_b = _mm_mullo_epi16 (_mm_unpacklo_epi8 (blbr, xmm_zero), xmm_wb); \ + xmm_a = _mm_add_epi16 (xmm_a, xmm_b); \ + /* calculate horizontal weights */ \ + if (phase <= 0) \ { \ - /* calculate horizontal weights */ \ - xmm_wh = _mm_add_epi16 (xmm_addc7, _mm_xor_si128 (xmm_xorc7, \ - _mm_srli_epi16 (xmm_x, 16 - BILINEAR_INTERPOLATION_BITS))); \ - xmm_x = _mm_add_epi16 (xmm_x, xmm_ux); \ - /* horizontal interpolation */ \ - a = _mm_madd_epi16 (_mm_unpackhi_epi16 (_mm_shuffle_epi32 ( \ - a, _MM_SHUFFLE (1, 0, 3, 2)), a), xmm_wh); \ + xmm_wh_state = _mm_add_epi16 (xmm_addc, _mm_srli_epi16 (xmm_x, \ + 16 - BILINEAR_INTERPOLATION_BITS)); \ + xmm_x = _mm_add_epi16 (xmm_x, (phase < 0) ? xmm_ux1 : xmm_ux4); \ + phase = 0; \ } \ - else \ - { \ - /* calculate horizontal weights */ \ - xmm_wh = _mm_add_epi16 (xmm_addc8, _mm_xor_si128 (xmm_xorc8, \ - _mm_srli_epi16 (xmm_x, 16 - BILINEAR_INTERPOLATION_BITS))); \ - xmm_x = _mm_add_epi16 (xmm_x, xmm_ux); \ - /* horizontal interpolation */ \ - xmm_lo = _mm_mullo_epi16 (a, xmm_wh); \ - xmm_hi = _mm_mulhi_epu16 (a, xmm_wh); \ - a = _mm_add_epi32 (_mm_unpacklo_epi16 (xmm_lo, xmm_hi), \ - _mm_unpackhi_epi16 (xmm_lo, xmm_hi)); \ - } \ - /* shift and pack the result */ \ - a = _mm_srli_epi32 (a, BILINEAR_INTERPOLATION_BITS * 2); \ - a = _mm_packs_epi32 (a, a); \ - a = _mm_packus_epi16 (a, a); \ - pix = _mm_cvtsi128_si32 (a); \ + xmm_wh = _mm_shuffle_epi32 (xmm_wh_state, _MM_SHUFFLE (phase, phase, \ + phase, phase)); \ + /* horizontal interpolation */ \ + xmm_a = _mm_madd_epi16 (_mm_unpackhi_epi16 (_mm_shuffle_epi32 ( \ + xmm_a, _MM_SHUFFLE (1, 0, 3, 2)), xmm_a), xmm_wh); \ + /* shift the result */ \ + pix = _mm_srli_epi32 (xmm_a, BILINEAR_INTERPOLATION_BITS * 2); \ } while (0) +#else /************************************************************************/ + +# define BILINEAR_DECLARE_VARIABLES \ + const __m128i xmm_wt = _mm_set_epi16 (wt, wt, wt, wt, wt, wt, wt, wt); \ + const __m128i xmm_wb = _mm_set_epi16 (wb, wb, wb, wb, wb, wb, wb, wb); \ + const __m128i xmm_addc = _mm_set_epi16 (0, 1, 0, 1, 0, 1, 0, 1); \ + const __m128i xmm_ux1 = _mm_set_epi16 (unit_x, -unit_x, unit_x, -unit_x, \ + unit_x, -unit_x, unit_x, -unit_x); \ + const __m128i xmm_ux4 = _mm_set_epi16 (unit_x * 4, -unit_x * 4, \ + unit_x * 4, -unit_x * 4, \ + unit_x * 4, -unit_x * 4, \ + unit_x * 4, -unit_x * 4); \ + const __m128i xmm_zero = _mm_setzero_si128 (); \ + __m128i xmm_x = _mm_set_epi16 (vx, -(vx + 1), vx, -(vx + 1), \ + vx, -(vx + 1), vx, -(vx + 1)) + +#define BILINEAR_INTERPOLATE_ONE_PIXEL_HELPER(pix, phase) \ +do { \ + __m128i xmm_wh, xmm_a, xmm_b; \ + /* fetch 2x2 pixel block into sse2 registers */ \ + __m128i tltr = _mm_loadl_epi64 ((__m128i *)&src_top[vx >> 16]); \ + __m128i blbr = _mm_loadl_epi64 ((__m128i *)&src_bottom[vx >> 16]); \ + (void)xmm_ux4; /* suppress warning: unused variable 'xmm_ux4' */ \ + vx += unit_x; \ + /* vertical interpolation */ \ + xmm_a = _mm_mullo_epi16 (_mm_unpacklo_epi8 (tltr, xmm_zero), xmm_wt); \ + xmm_b = _mm_mullo_epi16 (_mm_unpacklo_epi8 (blbr, xmm_zero), xmm_wb); \ + xmm_a = _mm_add_epi16 (xmm_a, xmm_b); \ + /* calculate horizontal weights */ \ + xmm_wh = _mm_add_epi16 (xmm_addc, _mm_srli_epi16 (xmm_x, \ + 16 - BILINEAR_INTERPOLATION_BITS)); \ + xmm_x = _mm_add_epi16 (xmm_x, xmm_ux1); \ + /* horizontal interpolation */ \ + xmm_b = _mm_unpacklo_epi64 (/* any value is fine here */ xmm_b, xmm_a); \ + xmm_a = _mm_madd_epi16 (_mm_unpackhi_epi16 (xmm_b, xmm_a), xmm_wh); \ + /* shift the result */ \ + pix = _mm_srli_epi32 (xmm_a, BILINEAR_INTERPOLATION_BITS * 2); \ +} while (0) + +/***********************************************************************************/ + +#endif + +#define BILINEAR_INTERPOLATE_ONE_PIXEL(pix); \ +do { \ + __m128i xmm_pix; \ + BILINEAR_INTERPOLATE_ONE_PIXEL_HELPER (xmm_pix, -1); \ + xmm_pix = _mm_packs_epi32 (xmm_pix, xmm_pix); \ + xmm_pix = _mm_packus_epi16 (xmm_pix, xmm_pix); \ + pix = _mm_cvtsi128_si32 (xmm_pix); \ +} while(0) + +#define BILINEAR_INTERPOLATE_FOUR_PIXELS(pix); \ +do { \ + __m128i xmm_pix1, xmm_pix2, xmm_pix3, xmm_pix4; \ + BILINEAR_INTERPOLATE_ONE_PIXEL_HELPER (xmm_pix1, 0); \ + BILINEAR_INTERPOLATE_ONE_PIXEL_HELPER (xmm_pix2, 1); \ + BILINEAR_INTERPOLATE_ONE_PIXEL_HELPER (xmm_pix3, 2); \ + BILINEAR_INTERPOLATE_ONE_PIXEL_HELPER (xmm_pix4, 3); \ + xmm_pix1 = _mm_packs_epi32 (xmm_pix1, xmm_pix2); \ + xmm_pix3 = _mm_packs_epi32 (xmm_pix3, xmm_pix4); \ + pix = _mm_packus_epi16 (xmm_pix1, xmm_pix3); \ +} while(0) + #define BILINEAR_SKIP_ONE_PIXEL() \ do { \ vx += unit_x; \ - xmm_x = _mm_add_epi16 (xmm_x, xmm_ux); \ + xmm_x = _mm_add_epi16 (xmm_x, xmm_ux1); \ } while(0) +#define BILINEAR_SKIP_FOUR_PIXELS() \ +do { \ + vx += unit_x * 4; \ + xmm_x = _mm_add_epi16 (xmm_x, xmm_ux4); \ +} while(0) + +/***********************************************************************************/ + static force_inline void scaled_bilinear_scanline_sse2_8888_8888_SRC (uint32_t * dst, const uint32_t * mask, @@ -5625,24 +5698,28 @@ scaled_bilinear_scanline_sse2_8888_8888_SRC (uint32_t * dst, int32_t w, int wt, int wb, - pixman_fixed_t vx, - pixman_fixed_t unit_x, + pixman_fixed_t vx_, + pixman_fixed_t unit_x_, pixman_fixed_t max_vx, pixman_bool_t zero_src) { + intptr_t vx = vx_; + intptr_t unit_x = unit_x_; BILINEAR_DECLARE_VARIABLES; - uint32_t pix1, pix2, pix3, pix4; + uint32_t pix1, pix2; - while ((w -= 4) >= 0) + while (w && ((uintptr_t)dst & 15)) { BILINEAR_INTERPOLATE_ONE_PIXEL (pix1); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix2); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix3); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix4); *dst++ = pix1; - *dst++ = pix2; - *dst++ = pix3; - *dst++ = pix4; + w--; + } + + while ((w -= 4) >= 0) { + __m128i xmm_src; + BILINEAR_INTERPOLATE_FOUR_PIXELS (xmm_src); + _mm_store_si128 ((__m128i *)dst, xmm_src); + dst += 4; } if (w & 2) @@ -5661,23 +5738,20 @@ scaled_bilinear_scanline_sse2_8888_8888_SRC (uint32_t * dst, } -/* Add extra NULL argument to the existing bilinear fast paths to indicate - * that we don't need two-pass processing */ - FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_cover_SRC, - scaled_bilinear_scanline_sse2_8888_8888_SRC, NULL, + scaled_bilinear_scanline_sse2_8888_8888_SRC, uint32_t, uint32_t, uint32_t, COVER, FLAG_NONE) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_pad_SRC, - scaled_bilinear_scanline_sse2_8888_8888_SRC, NULL, + scaled_bilinear_scanline_sse2_8888_8888_SRC, uint32_t, uint32_t, uint32_t, PAD, FLAG_NONE) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_none_SRC, - scaled_bilinear_scanline_sse2_8888_8888_SRC, NULL, + scaled_bilinear_scanline_sse2_8888_8888_SRC, uint32_t, uint32_t, uint32_t, NONE, FLAG_NONE) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_normal_SRC, - scaled_bilinear_scanline_sse2_8888_8888_SRC, NULL, + scaled_bilinear_scanline_sse2_8888_8888_SRC, uint32_t, uint32_t, uint32_t, NORMAL, FLAG_NONE) @@ -5697,7 +5771,7 @@ scaled_bilinear_scanline_sse2_x888_8888_SRC (uint32_t * dst, intptr_t vx = vx_; intptr_t unit_x = unit_x_; BILINEAR_DECLARE_VARIABLES; - uint32_t pix1, pix2, pix3, pix4; + uint32_t pix1, pix2; while (w && ((uintptr_t)dst & 15)) { @@ -5708,14 +5782,9 @@ scaled_bilinear_scanline_sse2_x888_8888_SRC (uint32_t * dst, while ((w -= 4) >= 0) { __m128i xmm_src; - BILINEAR_INTERPOLATE_ONE_PIXEL (pix1); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix2); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix3); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix4); - - xmm_src = _mm_set_epi32 (pix4, pix3, pix2, pix1); - _mm_store_si128 ((__m128i *)dst, _mm_or_si128 (xmm_src, mask_ff000000)); - dst += 4; + BILINEAR_INTERPOLATE_FOUR_PIXELS (xmm_src); + _mm_store_si128 ((__m128i *)dst, _mm_or_si128 (xmm_src, mask_ff000000)); + dst += 4; } if (w & 2) @@ -5734,23 +5803,18 @@ scaled_bilinear_scanline_sse2_x888_8888_SRC (uint32_t * dst, } FAST_BILINEAR_MAINLOOP_COMMON (sse2_x888_8888_cover_SRC, - scaled_bilinear_scanline_sse2_x888_8888_SRC, NULL, + scaled_bilinear_scanline_sse2_x888_8888_SRC, uint32_t, uint32_t, uint32_t, COVER, FLAG_NONE) FAST_BILINEAR_MAINLOOP_COMMON (sse2_x888_8888_pad_SRC, - scaled_bilinear_scanline_sse2_x888_8888_SRC, NULL, + scaled_bilinear_scanline_sse2_x888_8888_SRC, uint32_t, uint32_t, uint32_t, PAD, FLAG_NONE) FAST_BILINEAR_MAINLOOP_COMMON (sse2_x888_8888_normal_SRC, - scaled_bilinear_scanline_sse2_x888_8888_SRC, NULL, + scaled_bilinear_scanline_sse2_x888_8888_SRC, uint32_t, uint32_t, uint32_t, NORMAL, FLAG_NONE) -#if 0 -FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_pad_OVER, - scaled_bilinear_scanline_sse2_8888_8888_OVER, NULL, - uint32_t, uint32_t, uint32_t, - PAD, FLAG_NONE) -#endif + static force_inline void scaled_bilinear_scanline_sse2_8888_8888_OVER (uint32_t * dst, const uint32_t * mask, @@ -5759,13 +5823,15 @@ scaled_bilinear_scanline_sse2_8888_8888_OVER (uint32_t * dst, int32_t w, int wt, int wb, - pixman_fixed_t vx, - pixman_fixed_t unit_x, + pixman_fixed_t vx_, + pixman_fixed_t unit_x_, pixman_fixed_t max_vx, pixman_bool_t zero_src) { + intptr_t vx = vx_; + intptr_t unit_x = unit_x_; BILINEAR_DECLARE_VARIABLES; - uint32_t pix1, pix2, pix3, pix4; + uint32_t pix1, pix2; while (w && ((uintptr_t)dst & 15)) { @@ -5787,12 +5853,7 @@ scaled_bilinear_scanline_sse2_8888_8888_OVER (uint32_t * dst, __m128i xmm_src_hi, xmm_src_lo, xmm_dst_hi, xmm_dst_lo; __m128i xmm_alpha_hi, xmm_alpha_lo; - BILINEAR_INTERPOLATE_ONE_PIXEL (pix1); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix2); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix3); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix4); - - xmm_src = _mm_set_epi32 (pix4, pix3, pix2, pix1); + BILINEAR_INTERPOLATE_FOUR_PIXELS (xmm_src); if (!is_zero (xmm_src)) { @@ -5835,56 +5896,22 @@ scaled_bilinear_scanline_sse2_8888_8888_OVER (uint32_t * dst, } FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_cover_OVER, - scaled_bilinear_scanline_sse2_8888_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_8888_OVER, uint32_t, uint32_t, uint32_t, COVER, FLAG_NONE) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_pad_OVER, - scaled_bilinear_scanline_sse2_8888_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_8888_OVER, uint32_t, uint32_t, uint32_t, PAD, FLAG_NONE) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_none_OVER, - scaled_bilinear_scanline_sse2_8888_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_8888_OVER, uint32_t, uint32_t, uint32_t, NONE, FLAG_NONE) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_normal_OVER, - scaled_bilinear_scanline_sse2_8888_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_8888_OVER, uint32_t, uint32_t, uint32_t, NORMAL, FLAG_NONE) - -/* An example of SSE2 two-stage bilinear_over_8888_0565 fast path, which is implemented - as scaled_bilinear_scanline_sse2_8888_8888_SRC + op_bilinear_over_8888_0565 */ - -void op_bilinear_over_8888_0565(uint16_t *dst, const uint32_t *mask, const uint32_t *src, int width) -{ - /* Note: this is not really fast and should be based on 8 pixel loop from sse2_composite_over_8888_0565 */ - while (--width >= 0) - { - *dst = composite_over_8888_0565pixel (*src, *dst); - src++; - dst++; - } -} - -FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_0565_cover_OVER, - scaled_bilinear_scanline_sse2_8888_8888_SRC, op_bilinear_over_8888_0565, - uint32_t, uint32_t, uint16_t, - COVER, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_0565_pad_OVER, - scaled_bilinear_scanline_sse2_8888_8888_SRC, op_bilinear_over_8888_0565, - uint32_t, uint32_t, uint16_t, - PAD, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_0565_none_OVER, - scaled_bilinear_scanline_sse2_8888_8888_SRC, op_bilinear_over_8888_0565, - uint32_t, uint32_t, uint16_t, - NONE, FLAG_NONE) -FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_0565_normal_OVER, - scaled_bilinear_scanline_sse2_8888_8888_SRC, op_bilinear_over_8888_0565, - uint32_t, uint32_t, uint16_t, - NORMAL, FLAG_NONE) - -/*****************************/ - static force_inline void scaled_bilinear_scanline_sse2_8888_8_8888_OVER (uint32_t * dst, const uint8_t * mask, @@ -5893,20 +5920,20 @@ scaled_bilinear_scanline_sse2_8888_8_8888_OVER (uint32_t * dst, int32_t w, int wt, int wb, - pixman_fixed_t vx, - pixman_fixed_t unit_x, + pixman_fixed_t vx_, + pixman_fixed_t unit_x_, pixman_fixed_t max_vx, pixman_bool_t zero_src) { + intptr_t vx = vx_; + intptr_t unit_x = unit_x_; BILINEAR_DECLARE_VARIABLES; - uint32_t pix1, pix2, pix3, pix4; - uint32_t m; + uint32_t pix1, pix2; while (w && ((uintptr_t)dst & 15)) { uint32_t sa; - - m = (uint32_t) *mask++; + uint8_t m = *mask++; if (m) { @@ -5942,20 +5969,17 @@ scaled_bilinear_scanline_sse2_8888_8_8888_OVER (uint32_t * dst, while (w >= 4) { + uint32_t m; + __m128i xmm_src, xmm_src_lo, xmm_src_hi, xmm_srca_lo, xmm_srca_hi; __m128i xmm_dst, xmm_dst_lo, xmm_dst_hi; __m128i xmm_mask, xmm_mask_lo, xmm_mask_hi; - m = *(uint32_t*)mask; + memcpy(&m, mask, sizeof(uint32_t)); if (m) { - BILINEAR_INTERPOLATE_ONE_PIXEL (pix1); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix2); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix3); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix4); - - xmm_src = _mm_set_epi32 (pix4, pix3, pix2, pix1); + BILINEAR_INTERPOLATE_FOUR_PIXELS (xmm_src); if (m == 0xffffffff && is_opaque (xmm_src)) { @@ -5982,10 +6006,7 @@ scaled_bilinear_scanline_sse2_8888_8_8888_OVER (uint32_t * dst, } else { - BILINEAR_SKIP_ONE_PIXEL (); - BILINEAR_SKIP_ONE_PIXEL (); - BILINEAR_SKIP_ONE_PIXEL (); - BILINEAR_SKIP_ONE_PIXEL (); + BILINEAR_SKIP_FOUR_PIXELS (); } w -= 4; @@ -5996,8 +6017,7 @@ scaled_bilinear_scanline_sse2_8888_8_8888_OVER (uint32_t * dst, while (w) { uint32_t sa; - - m = (uint32_t) *mask++; + uint8_t m = *mask++; if (m) { @@ -6033,19 +6053,19 @@ scaled_bilinear_scanline_sse2_8888_8_8888_OVER (uint32_t * dst, } FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8_8888_cover_OVER, - scaled_bilinear_scanline_sse2_8888_8_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_8_8888_OVER, uint32_t, uint8_t, uint32_t, COVER, FLAG_HAVE_NON_SOLID_MASK) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8_8888_pad_OVER, - scaled_bilinear_scanline_sse2_8888_8_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_8_8888_OVER, uint32_t, uint8_t, uint32_t, PAD, FLAG_HAVE_NON_SOLID_MASK) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8_8888_none_OVER, - scaled_bilinear_scanline_sse2_8888_8_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_8_8888_OVER, uint32_t, uint8_t, uint32_t, NONE, FLAG_HAVE_NON_SOLID_MASK) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8_8888_normal_OVER, - scaled_bilinear_scanline_sse2_8888_8_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_8_8888_OVER, uint32_t, uint8_t, uint32_t, NORMAL, FLAG_HAVE_NON_SOLID_MASK) @@ -6057,13 +6077,15 @@ scaled_bilinear_scanline_sse2_8888_n_8888_OVER (uint32_t * dst, int32_t w, int wt, int wb, - pixman_fixed_t vx, - pixman_fixed_t unit_x, + pixman_fixed_t vx_, + pixman_fixed_t unit_x_, pixman_fixed_t max_vx, pixman_bool_t zero_src) { + intptr_t vx = vx_; + intptr_t unit_x = unit_x_; BILINEAR_DECLARE_VARIABLES; - uint32_t pix1, pix2, pix3, pix4; + uint32_t pix1; __m128i xmm_mask; if (zero_src || (*mask >> 24) == 0) @@ -6093,19 +6115,15 @@ scaled_bilinear_scanline_sse2_8888_n_8888_OVER (uint32_t * dst, while (w >= 4) { - BILINEAR_INTERPOLATE_ONE_PIXEL (pix1); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix2); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix3); - BILINEAR_INTERPOLATE_ONE_PIXEL (pix4); + __m128i xmm_src; + BILINEAR_INTERPOLATE_FOUR_PIXELS (xmm_src); - if (pix1 | pix2 | pix3 | pix4) + if (!is_zero (xmm_src)) { - __m128i xmm_src, xmm_src_lo, xmm_src_hi; + __m128i xmm_src_lo, xmm_src_hi; __m128i xmm_dst, xmm_dst_lo, xmm_dst_hi; __m128i xmm_alpha_lo, xmm_alpha_hi; - xmm_src = _mm_set_epi32 (pix4, pix3, pix2, pix1); - xmm_dst = load_128_aligned ((__m128i*)dst); unpack_128_2x128 (xmm_src, &xmm_src_lo, &xmm_src_hi); @@ -6148,19 +6166,19 @@ scaled_bilinear_scanline_sse2_8888_n_8888_OVER (uint32_t * dst, } FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_n_8888_cover_OVER, - scaled_bilinear_scanline_sse2_8888_n_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_n_8888_OVER, uint32_t, uint32_t, uint32_t, COVER, FLAG_HAVE_SOLID_MASK) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_n_8888_pad_OVER, - scaled_bilinear_scanline_sse2_8888_n_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_n_8888_OVER, uint32_t, uint32_t, uint32_t, PAD, FLAG_HAVE_SOLID_MASK) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_n_8888_none_OVER, - scaled_bilinear_scanline_sse2_8888_n_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_n_8888_OVER, uint32_t, uint32_t, uint32_t, NONE, FLAG_HAVE_SOLID_MASK) FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_n_8888_normal_OVER, - scaled_bilinear_scanline_sse2_8888_n_8888_OVER, NULL, + scaled_bilinear_scanline_sse2_8888_n_8888_OVER, uint32_t, uint32_t, uint32_t, NORMAL, FLAG_HAVE_SOLID_MASK) @@ -6260,31 +6278,15 @@ static const pixman_fast_path_t sse2_fast_paths[] = PIXMAN_STD_FAST_PATH (IN, solid, a8, a8, sse2_composite_in_n_8_8), PIXMAN_STD_FAST_PATH (IN, solid, null, a8, sse2_composite_in_n_8), - SIMPLE_NEAREST_FAST_PATH_COVER (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_COVER (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_COVER (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_COVER (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_NONE (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_NONE (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_NONE (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_NONE (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_PAD (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_PAD (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_PAD (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_PAD (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_NORMAL (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_NORMAL (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_NORMAL (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888), - SIMPLE_NEAREST_FAST_PATH_NORMAL (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888), SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_n_8888), SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_n_8888), SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_n_8888), SIMPLE_NEAREST_SOLID_MASK_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_n_8888), - SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_n_8888), - SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_n_8888), - SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_n_8888), - SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_n_8888), SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, sse2_8888_8888), SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, sse2_8888_8888), @@ -6315,11 +6317,6 @@ static const pixman_fast_path_t sse2_fast_paths[] = SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8_8888), SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8_8888), - /* and here the needed entries are added to the fast path table */ - - SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, r5g6b5, sse2_8888_0565), - SIMPLE_BILINEAR_FAST_PATH (OVER, a8b8g8r8, b5g6r5, sse2_8888_0565), - { PIXMAN_OP_NONE }, }; @@ -6417,7 +6414,7 @@ sse2_fetch_a8 (pixman_iter_t *iter, const uint32_t *mask) while (w && (((uintptr_t)dst) & 15)) { - *dst++ = *(src++) << 24; + *dst++ = (uint32_t)(*(src++)) << 24; w--; } @@ -6444,59 +6441,30 @@ sse2_fetch_a8 (pixman_iter_t *iter, const uint32_t *mask) while (w) { - *dst++ = *(src++) << 24; + *dst++ = (uint32_t)(*(src++)) << 24; w--; } return iter->buffer; } -typedef struct -{ - pixman_format_code_t format; - pixman_iter_get_scanline_t get_scanline; -} fetcher_info_t; - -static const fetcher_info_t fetchers[] = -{ - { PIXMAN_x8r8g8b8, sse2_fetch_x8r8g8b8 }, - { PIXMAN_r5g6b5, sse2_fetch_r5g6b5 }, - { PIXMAN_a8, sse2_fetch_a8 }, - { PIXMAN_null } -}; - -static pixman_bool_t -sse2_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) -{ - pixman_image_t *image = iter->image; - -#define FLAGS \ +#define IMAGE_FLAGS \ (FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM | \ FAST_PATH_BITS_IMAGE | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST) - if ((iter->iter_flags & ITER_NARROW) && - (iter->image_flags & FLAGS) == FLAGS) - { - const fetcher_info_t *f; - - for (f = &fetchers[0]; f->format != PIXMAN_null; f++) - { - if (image->common.extended_format_code == f->format) - { - uint8_t *b = (uint8_t *)image->bits.bits; - int s = image->bits.rowstride * 4; - - iter->bits = b + s * iter->y + iter->x * PIXMAN_FORMAT_BPP (f->format) / 8; - iter->stride = s; - - iter->get_scanline = f->get_scanline; - return TRUE; - } - } - } - - return FALSE; -} +static const pixman_iter_info_t sse2_iters[] = +{ + { PIXMAN_x8r8g8b8, IMAGE_FLAGS, ITER_NARROW, + _pixman_iter_init_bits_stride, sse2_fetch_x8r8g8b8, NULL + }, + { PIXMAN_r5g6b5, IMAGE_FLAGS, ITER_NARROW, + _pixman_iter_init_bits_stride, sse2_fetch_r5g6b5, NULL + }, + { PIXMAN_a8, IMAGE_FLAGS, ITER_NARROW, + _pixman_iter_init_bits_stride, sse2_fetch_a8, NULL + }, + { PIXMAN_null }, +}; #if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) __attribute__((__force_align_arg_pointer__)) @@ -6554,7 +6522,7 @@ _pixman_implementation_create_sse2 (pixman_implementation_t *fallback) imp->blt = sse2_blt; imp->fill = sse2_fill; - imp->src_iter_init = sse2_src_iter_init; + imp->iter_info = sse2_iters; return imp; } diff --git a/gfx/cairo/libpixman/src/pixman-ssse3.c b/gfx/cairo/libpixman/src/pixman-ssse3.c new file mode 100644 index 0000000000..680d6b95a0 --- /dev/null +++ b/gfx/cairo/libpixman/src/pixman-ssse3.c @@ -0,0 +1,351 @@ +/* + * Copyright © 2013 Soren Sandmann Pedersen + * Copyright © 2013 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Soren Sandmann (soren.sandmann@gmail.com) + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include "pixman-private.h" +#include "pixman-inlines.h" + +typedef struct +{ + int y; + uint64_t * buffer; +} line_t; + +typedef struct +{ + line_t lines[2]; + pixman_fixed_t y; + pixman_fixed_t x; + uint64_t data[1]; +} bilinear_info_t; + +static void +ssse3_fetch_horizontal (bits_image_t *image, line_t *line, + int y, pixman_fixed_t x, pixman_fixed_t ux, int n) +{ + uint32_t *bits = image->bits + y * image->rowstride; + __m128i vx = _mm_set_epi16 ( + - (x + 1), x, - (x + 1), x, + - (x + ux + 1), x + ux, - (x + ux + 1), x + ux); + __m128i vux = _mm_set_epi16 ( + - 2 * ux, 2 * ux, - 2 * ux, 2 * ux, + - 2 * ux, 2 * ux, - 2 * ux, 2 * ux); + __m128i vaddc = _mm_set_epi16 (1, 0, 1, 0, 1, 0, 1, 0); + __m128i *b = (__m128i *)line->buffer; + __m128i vrl0, vrl1; + + while ((n -= 2) >= 0) + { + __m128i vw, vr, s; + + vrl1 = _mm_loadl_epi64 ( + (__m128i *)(bits + pixman_fixed_to_int (x + ux))); + /* vrl1: R1, L1 */ + + final_pixel: + vrl0 = _mm_loadl_epi64 ( + (__m128i *)(bits + pixman_fixed_to_int (x))); + /* vrl0: R0, L0 */ + + /* The weights are based on vx which is a vector of + * + * - (x + 1), x, - (x + 1), x, + * - (x + ux + 1), x + ux, - (x + ux + 1), x + ux + * + * so the 16 bit weights end up like this: + * + * iw0, w0, iw0, w0, iw1, w1, iw1, w1 + * + * and after shifting and packing, we get these bytes: + * + * iw0, w0, iw0, w0, iw1, w1, iw1, w1, + * iw0, w0, iw0, w0, iw1, w1, iw1, w1, + * + * which means the first and the second input pixel + * have to be interleaved like this: + * + * la0, ra0, lr0, rr0, la1, ra1, lr1, rr1, + * lg0, rg0, lb0, rb0, lg1, rg1, lb1, rb1 + * + * before maddubsw can be used. + */ + + vw = _mm_add_epi16 ( + vaddc, _mm_srli_epi16 (vx, 16 - BILINEAR_INTERPOLATION_BITS)); + /* vw: iw0, w0, iw0, w0, iw1, w1, iw1, w1 + */ + + vw = _mm_packus_epi16 (vw, vw); + /* vw: iw0, w0, iw0, w0, iw1, w1, iw1, w1, + * iw0, w0, iw0, w0, iw1, w1, iw1, w1 + */ + vx = _mm_add_epi16 (vx, vux); + + x += 2 * ux; + + vr = _mm_unpacklo_epi16 (vrl1, vrl0); + /* vr: rar0, rar1, rgb0, rgb1, lar0, lar1, lgb0, lgb1 */ + + s = _mm_shuffle_epi32 (vr, _MM_SHUFFLE (1, 0, 3, 2)); + /* s: lar0, lar1, lgb0, lgb1, rar0, rar1, rgb0, rgb1 */ + + vr = _mm_unpackhi_epi8 (vr, s); + /* vr: la0, ra0, lr0, rr0, la1, ra1, lr1, rr1, + * lg0, rg0, lb0, rb0, lg1, rg1, lb1, rb1 + */ + + vr = _mm_maddubs_epi16 (vr, vw); + + /* When the weight is 0, the inverse weight is + * 128 which can't be represented in a signed byte. + * As a result maddubsw computes the following: + * + * r = l * -128 + r * 0 + * + * rather than the desired + * + * r = l * 128 + r * 0 + * + * We fix this by taking the absolute value of the + * result. + */ + vr = _mm_abs_epi16 (vr); + + /* vr: A0, R0, A1, R1, G0, B0, G1, B1 */ + _mm_store_si128 (b++, vr); + } + + if (n == -1) + { + vrl1 = _mm_setzero_si128(); + goto final_pixel; + } + + line->y = y; +} + +static uint32_t * +ssse3_fetch_bilinear_cover (pixman_iter_t *iter, const uint32_t *mask) +{ + pixman_fixed_t fx, ux; + bilinear_info_t *info = iter->data; + line_t *line0, *line1; + int y0, y1; + int32_t dist_y; + __m128i vw; + int i; + + fx = info->x; + ux = iter->image->common.transform->matrix[0][0]; + + y0 = pixman_fixed_to_int (info->y); + y1 = y0 + 1; + + line0 = &info->lines[y0 & 0x01]; + line1 = &info->lines[y1 & 0x01]; + + if (line0->y != y0) + { + ssse3_fetch_horizontal ( + &iter->image->bits, line0, y0, fx, ux, iter->width); + } + + if (line1->y != y1) + { + ssse3_fetch_horizontal ( + &iter->image->bits, line1, y1, fx, ux, iter->width); + } + + dist_y = pixman_fixed_to_bilinear_weight (info->y); + dist_y <<= (16 - BILINEAR_INTERPOLATION_BITS); + + vw = _mm_set_epi16 ( + dist_y, dist_y, dist_y, dist_y, dist_y, dist_y, dist_y, dist_y); + + for (i = 0; i + 3 < iter->width; i += 4) + { + __m128i top0 = _mm_load_si128 ((__m128i *)(line0->buffer + i)); + __m128i bot0 = _mm_load_si128 ((__m128i *)(line1->buffer + i)); + __m128i top1 = _mm_load_si128 ((__m128i *)(line0->buffer + i + 2)); + __m128i bot1 = _mm_load_si128 ((__m128i *)(line1->buffer + i + 2)); + __m128i r0, r1, tmp, p; + + r0 = _mm_mulhi_epu16 ( + _mm_sub_epi16 (bot0, top0), vw); + tmp = _mm_cmplt_epi16 (bot0, top0); + tmp = _mm_and_si128 (tmp, vw); + r0 = _mm_sub_epi16 (r0, tmp); + r0 = _mm_add_epi16 (r0, top0); + r0 = _mm_srli_epi16 (r0, BILINEAR_INTERPOLATION_BITS); + /* r0: A0 R0 A1 R1 G0 B0 G1 B1 */ + r0 = _mm_shuffle_epi32 (r0, _MM_SHUFFLE (2, 0, 3, 1)); + /* r0: A1 R1 G1 B1 A0 R0 G0 B0 */ + + r1 = _mm_mulhi_epu16 ( + _mm_sub_epi16 (bot1, top1), vw); + tmp = _mm_cmplt_epi16 (bot1, top1); + tmp = _mm_and_si128 (tmp, vw); + r1 = _mm_sub_epi16 (r1, tmp); + r1 = _mm_add_epi16 (r1, top1); + r1 = _mm_srli_epi16 (r1, BILINEAR_INTERPOLATION_BITS); + r1 = _mm_shuffle_epi32 (r1, _MM_SHUFFLE (2, 0, 3, 1)); + /* r1: A3 R3 G3 B3 A2 R2 G2 B2 */ + + p = _mm_packus_epi16 (r0, r1); + + _mm_storeu_si128 ((__m128i *)(iter->buffer + i), p); + } + + while (i < iter->width) + { + __m128i top0 = _mm_load_si128 ((__m128i *)(line0->buffer + i)); + __m128i bot0 = _mm_load_si128 ((__m128i *)(line1->buffer + i)); + __m128i r0, tmp, p; + + r0 = _mm_mulhi_epu16 ( + _mm_sub_epi16 (bot0, top0), vw); + tmp = _mm_cmplt_epi16 (bot0, top0); + tmp = _mm_and_si128 (tmp, vw); + r0 = _mm_sub_epi16 (r0, tmp); + r0 = _mm_add_epi16 (r0, top0); + r0 = _mm_srli_epi16 (r0, BILINEAR_INTERPOLATION_BITS); + /* r0: A0 R0 A1 R1 G0 B0 G1 B1 */ + r0 = _mm_shuffle_epi32 (r0, _MM_SHUFFLE (2, 0, 3, 1)); + /* r0: A1 R1 G1 B1 A0 R0 G0 B0 */ + + p = _mm_packus_epi16 (r0, r0); + + if (iter->width - i == 1) + { + *(uint32_t *)(iter->buffer + i) = _mm_cvtsi128_si32 (p); + i++; + } + else + { + _mm_storel_epi64 ((__m128i *)(iter->buffer + i), p); + i += 2; + } + } + + info->y += iter->image->common.transform->matrix[1][1]; + + return iter->buffer; +} + +static void +ssse3_bilinear_cover_iter_fini (pixman_iter_t *iter) +{ + free (iter->data); +} + +static void +ssse3_bilinear_cover_iter_init (pixman_iter_t *iter, const pixman_iter_info_t *iter_info) +{ + int width = iter->width; + bilinear_info_t *info; + pixman_vector_t v; + + /* Reference point is the center of the pixel */ + v.vector[0] = pixman_int_to_fixed (iter->x) + pixman_fixed_1 / 2; + v.vector[1] = pixman_int_to_fixed (iter->y) + pixman_fixed_1 / 2; + v.vector[2] = pixman_fixed_1; + + if (!pixman_transform_point_3d (iter->image->common.transform, &v)) + goto fail; + + info = malloc (sizeof (*info) + (2 * width - 1) * sizeof (uint64_t) + 64); + if (!info) + goto fail; + + info->x = v.vector[0] - pixman_fixed_1 / 2; + info->y = v.vector[1] - pixman_fixed_1 / 2; + +#define ALIGN(addr) \ + ((void *)((((uintptr_t)(addr)) + 15) & (~15))) + + /* It is safe to set the y coordinates to -1 initially + * because COVER_CLIP_BILINEAR ensures that we will only + * be asked to fetch lines in the [0, height) interval + */ + info->lines[0].y = -1; + info->lines[0].buffer = ALIGN (&(info->data[0])); + info->lines[1].y = -1; + info->lines[1].buffer = ALIGN (info->lines[0].buffer + width); + + iter->get_scanline = ssse3_fetch_bilinear_cover; + iter->fini = ssse3_bilinear_cover_iter_fini; + + iter->data = info; + return; + +fail: + /* Something went wrong, either a bad matrix or OOM; in such cases, + * we don't guarantee any particular rendering. + */ + _pixman_log_error ( + FUNC, "Allocation failure or bad matrix, skipping rendering\n"); + + iter->get_scanline = _pixman_iter_get_scanline_noop; + iter->fini = NULL; +} + +static const pixman_iter_info_t ssse3_iters[] = +{ + { PIXMAN_a8r8g8b8, + (FAST_PATH_STANDARD_FLAGS | + FAST_PATH_SCALE_TRANSFORM | + FAST_PATH_BILINEAR_FILTER | + FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR), + ITER_NARROW | ITER_SRC, + ssse3_bilinear_cover_iter_init, + NULL, NULL + }, + + { PIXMAN_null }, +}; + +static const pixman_fast_path_t ssse3_fast_paths[] = +{ + { PIXMAN_OP_NONE }, +}; + +pixman_implementation_t * +_pixman_implementation_create_ssse3 (pixman_implementation_t *fallback) +{ + pixman_implementation_t *imp = + _pixman_implementation_create (fallback, ssse3_fast_paths); + + imp->iter_info = ssse3_iters; + + return imp; +} diff --git a/gfx/cairo/libpixman/src/pixman-utils.c b/gfx/cairo/libpixman/src/pixman-utils.c index b2ffb8ca2c..2c2dddd64c 100644 --- a/gfx/cairo/libpixman/src/pixman-utils.c +++ b/gfx/cairo/libpixman/src/pixman-utils.c @@ -27,7 +27,6 @@ #endif #include #include -#include #include "pixman-private.h" @@ -49,6 +48,15 @@ _pixman_addition_overflows_int (unsigned int a, unsigned int b) return a > INT32_MAX - b; } +void * +pixman_malloc_ab_plus_c (unsigned int a, unsigned int b, unsigned int c) +{ + if (!b || a >= INT32_MAX / b || (a * b) > INT32_MAX - c) + return NULL; + + return malloc (a * b + c); +} + void * pixman_malloc_ab (unsigned int a, unsigned int b) @@ -198,7 +206,7 @@ pixman_contract_from_float (uint32_t *dst, for (i = 0; i < width; ++i) { - uint8_t a, r, g, b; + uint32_t a, r, g, b; a = float_to_unorm (src[i].a, 8); r = float_to_unorm (src[i].r, 8); @@ -215,6 +223,17 @@ _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask) return iter->buffer; } +void +_pixman_iter_init_bits_stride (pixman_iter_t *iter, const pixman_iter_info_t *info) +{ + pixman_image_t *image = iter->image; + uint8_t *b = (uint8_t *)image->bits.bits; + int s = image->bits.rowstride * 4; + + iter->bits = b + s * iter->y + iter->x * PIXMAN_FORMAT_BPP (info->format) / 8; + iter->stride = s; +} + #define N_TMP_BOXES (16) pixman_bool_t @@ -293,8 +312,6 @@ _pixman_internal_only_get_implementation (void) return get_implementation (); } -#ifdef DEBUG - void _pixman_log_error (const char *function, const char *message) { @@ -311,5 +328,3 @@ _pixman_log_error (const char *function, const char *message) n_messages++; } } - -#endif diff --git a/gfx/cairo/libpixman/src/pixman-version.h b/gfx/cairo/libpixman/src/pixman-version.h index fac4225b07..8b0e774271 100644 --- a/gfx/cairo/libpixman/src/pixman-version.h +++ b/gfx/cairo/libpixman/src/pixman-version.h @@ -32,10 +32,10 @@ #endif #define PIXMAN_VERSION_MAJOR 0 -#define PIXMAN_VERSION_MINOR 27 -#define PIXMAN_VERSION_MICRO 1 +#define PIXMAN_VERSION_MINOR 40 +#define PIXMAN_VERSION_MICRO 0 -#define PIXMAN_VERSION_STRING "0.27.1" +#define PIXMAN_VERSION_STRING "0.40.0" #define PIXMAN_VERSION_ENCODE(major, minor, micro) ( \ ((major) * 10000) \ @@ -47,4 +47,8 @@ PIXMAN_VERSION_MINOR, \ PIXMAN_VERSION_MICRO) +#ifndef PIXMAN_API +# define PIXMAN_API +#endif + #endif /* PIXMAN_VERSION_H__ */ diff --git a/gfx/cairo/libpixman/src/pixman-version.h.in b/gfx/cairo/libpixman/src/pixman-version.h.in new file mode 100644 index 0000000000..64778a595c --- /dev/null +++ b/gfx/cairo/libpixman/src/pixman-version.h.in @@ -0,0 +1,54 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Author: Carl D. Worth + */ + +#ifndef PIXMAN_VERSION_H__ +#define PIXMAN_VERSION_H__ + +#ifndef PIXMAN_H__ +# error pixman-version.h should only be included by pixman.h +#endif + +#define PIXMAN_VERSION_MAJOR @PIXMAN_VERSION_MAJOR@ +#define PIXMAN_VERSION_MINOR @PIXMAN_VERSION_MINOR@ +#define PIXMAN_VERSION_MICRO @PIXMAN_VERSION_MICRO@ + +#define PIXMAN_VERSION_STRING "@PIXMAN_VERSION_MAJOR@.@PIXMAN_VERSION_MINOR@.@PIXMAN_VERSION_MICRO@" + +#define PIXMAN_VERSION_ENCODE(major, minor, micro) ( \ + ((major) * 10000) \ + + ((minor) * 100) \ + + ((micro) * 1)) + +#define PIXMAN_VERSION PIXMAN_VERSION_ENCODE( \ + PIXMAN_VERSION_MAJOR, \ + PIXMAN_VERSION_MINOR, \ + PIXMAN_VERSION_MICRO) + +#ifndef PIXMAN_API +# define PIXMAN_API +#endif + +#endif /* PIXMAN_VERSION_H__ */ diff --git a/gfx/cairo/libpixman/src/pixman-vmx.c b/gfx/cairo/libpixman/src/pixman-vmx.c index 6868704a87..52de37e69e 100644 --- a/gfx/cairo/libpixman/src/pixman-vmx.c +++ b/gfx/cairo/libpixman/src/pixman-vmx.c @@ -25,20 +25,46 @@ * Based on fbmmx.c by Owen Taylor, Søren Sandmann and Nicholas Miell */ +#ifdef HAVE_CONFIG_H #include +#endif #include "pixman-private.h" #include "pixman-combine32.h" +#include "pixman-inlines.h" #include #define AVV(x...) {x} +static vector unsigned int mask_ff000000; +static vector unsigned int mask_red; +static vector unsigned int mask_green; +static vector unsigned int mask_blue; +static vector unsigned int mask_565_fix_rb; +static vector unsigned int mask_565_fix_g; + static force_inline vector unsigned int splat_alpha (vector unsigned int pix) { +#ifdef WORDS_BIGENDIAN return vec_perm (pix, pix, (vector unsigned char)AVV ( 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0C, 0x0C, 0x0C)); +#else + return vec_perm (pix, pix, + (vector unsigned char)AVV ( + 0x03, 0x03, 0x03, 0x03, 0x07, 0x07, 0x07, 0x07, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0F, 0x0F, 0x0F, 0x0F)); +#endif +} + +static force_inline vector unsigned int +splat_pixel (vector unsigned int pix) +{ + return vec_perm (pix, pix, + (vector unsigned char)AVV ( + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03)); } static force_inline vector unsigned int @@ -48,12 +74,22 @@ pix_multiply (vector unsigned int p, vector unsigned int a) /* unpack to short */ hi = (vector unsigned short) +#ifdef WORDS_BIGENDIAN vec_mergeh ((vector unsigned char)AVV (0), (vector unsigned char)p); +#else + vec_mergeh ((vector unsigned char) p, + (vector unsigned char) AVV (0)); +#endif mod = (vector unsigned short) +#ifdef WORDS_BIGENDIAN vec_mergeh ((vector unsigned char)AVV (0), (vector unsigned char)a); +#else + vec_mergeh ((vector unsigned char) a, + (vector unsigned char) AVV (0)); +#endif hi = vec_mladd (hi, mod, (vector unsigned short) AVV (0x0080, 0x0080, 0x0080, 0x0080, @@ -65,11 +101,22 @@ pix_multiply (vector unsigned int p, vector unsigned int a) /* unpack to short */ lo = (vector unsigned short) +#ifdef WORDS_BIGENDIAN vec_mergel ((vector unsigned char)AVV (0), (vector unsigned char)p); +#else + vec_mergel ((vector unsigned char) p, + (vector unsigned char) AVV (0)); +#endif + mod = (vector unsigned short) +#ifdef WORDS_BIGENDIAN vec_mergel ((vector unsigned char)AVV (0), (vector unsigned char)a); +#else + vec_mergel ((vector unsigned char) a, + (vector unsigned char) AVV (0)); +#endif lo = vec_mladd (lo, mod, (vector unsigned short) AVV (0x0080, 0x0080, 0x0080, 0x0080, @@ -127,60 +174,316 @@ over (vector unsigned int src, over (pix_multiply (src, mask), \ pix_multiply (srca, mask), dest) +#ifdef WORDS_BIGENDIAN #define COMPUTE_SHIFT_MASK(source) \ source ## _mask = vec_lvsl (0, source); #define COMPUTE_SHIFT_MASKS(dest, source) \ - dest ## _mask = vec_lvsl (0, dest); \ - source ## _mask = vec_lvsl (0, source); \ - store_mask = vec_lvsr (0, dest); + source ## _mask = vec_lvsl (0, source); #define COMPUTE_SHIFT_MASKC(dest, source, mask) \ mask ## _mask = vec_lvsl (0, mask); \ - dest ## _mask = vec_lvsl (0, dest); \ - source ## _mask = vec_lvsl (0, source); \ - store_mask = vec_lvsr (0, dest); + source ## _mask = vec_lvsl (0, source); -/* notice you have to declare temp vars... - * Note: tmp3 and tmp4 must remain untouched! - */ +#define LOAD_VECTOR(source) \ +do \ +{ \ + vector unsigned char tmp1, tmp2; \ + tmp1 = (typeof(tmp1))vec_ld (0, source); \ + tmp2 = (typeof(tmp2))vec_ld (15, source); \ + v ## source = (typeof(v ## source)) \ + vec_perm (tmp1, tmp2, source ## _mask); \ +} while (0) #define LOAD_VECTORS(dest, source) \ - tmp1 = (typeof(tmp1))vec_ld (0, source); \ - tmp2 = (typeof(tmp2))vec_ld (15, source); \ - tmp3 = (typeof(tmp3))vec_ld (0, dest); \ - v ## source = (typeof(v ## source)) \ - vec_perm (tmp1, tmp2, source ## _mask); \ - tmp4 = (typeof(tmp4))vec_ld (15, dest); \ - v ## dest = (typeof(v ## dest)) \ - vec_perm (tmp3, tmp4, dest ## _mask); +do \ +{ \ + LOAD_VECTOR(source); \ + v ## dest = (typeof(v ## dest))vec_ld (0, dest); \ +} while (0) #define LOAD_VECTORSC(dest, source, mask) \ - tmp1 = (typeof(tmp1))vec_ld (0, source); \ - tmp2 = (typeof(tmp2))vec_ld (15, source); \ - tmp3 = (typeof(tmp3))vec_ld (0, dest); \ - v ## source = (typeof(v ## source)) \ - vec_perm (tmp1, tmp2, source ## _mask); \ - tmp4 = (typeof(tmp4))vec_ld (15, dest); \ - tmp1 = (typeof(tmp1))vec_ld (0, mask); \ - v ## dest = (typeof(v ## dest)) \ - vec_perm (tmp3, tmp4, dest ## _mask); \ - tmp2 = (typeof(tmp2))vec_ld (15, mask); \ - v ## mask = (typeof(v ## mask)) \ - vec_perm (tmp1, tmp2, mask ## _mask); +do \ +{ \ + LOAD_VECTORS(dest, source); \ + LOAD_VECTOR(mask); \ +} while (0) + +#define DECLARE_SRC_MASK_VAR vector unsigned char src_mask +#define DECLARE_MASK_MASK_VAR vector unsigned char mask_mask + +#else + +/* Now the COMPUTE_SHIFT_{MASK, MASKS, MASKC} below are just no-op. + * They are defined that way because little endian altivec can do unaligned + * reads natively and have no need for constructing the permutation pattern + * variables. + */ +#define COMPUTE_SHIFT_MASK(source) + +#define COMPUTE_SHIFT_MASKS(dest, source) + +#define COMPUTE_SHIFT_MASKC(dest, source, mask) + +# define LOAD_VECTOR(source) \ + v ## source = (typeof(v ## source))vec_xl(0, source); + +# define LOAD_VECTORS(dest, source) \ + LOAD_VECTOR(source); \ + LOAD_VECTOR(dest); \ + +# define LOAD_VECTORSC(dest, source, mask) \ + LOAD_VECTORS(dest, source); \ + LOAD_VECTOR(mask); \ + +#define DECLARE_SRC_MASK_VAR +#define DECLARE_MASK_MASK_VAR + +#endif /* WORDS_BIGENDIAN */ #define LOAD_VECTORSM(dest, source, mask) \ - LOAD_VECTORSC (dest, source, mask) \ + LOAD_VECTORSC (dest, source, mask); \ v ## source = pix_multiply (v ## source, \ splat_alpha (v ## mask)); #define STORE_VECTOR(dest) \ - edges = vec_perm (tmp4, tmp3, dest ## _mask); \ - tmp3 = vec_perm ((vector unsigned char)v ## dest, edges, store_mask); \ - tmp1 = vec_perm (edges, (vector unsigned char)v ## dest, store_mask); \ - vec_st ((vector unsigned int) tmp3, 15, dest); \ - vec_st ((vector unsigned int) tmp1, 0, dest); + vec_st ((vector unsigned int) v ## dest, 0, dest); + +/* load 4 pixels from a 16-byte boundary aligned address */ +static force_inline vector unsigned int +load_128_aligned (const uint32_t* src) +{ + return *((vector unsigned int *) src); +} + +/* load 4 pixels from a unaligned address */ +static force_inline vector unsigned int +load_128_unaligned (const uint32_t* src) +{ + vector unsigned int vsrc; + DECLARE_SRC_MASK_VAR; + + COMPUTE_SHIFT_MASK (src); + LOAD_VECTOR (src); + + return vsrc; +} + +/* save 4 pixels on a 16-byte boundary aligned address */ +static force_inline void +save_128_aligned (uint32_t* data, + vector unsigned int vdata) +{ + STORE_VECTOR(data) +} + +static force_inline vector unsigned int +create_mask_1x32_128 (const uint32_t *src) +{ + vector unsigned int vsrc; + DECLARE_SRC_MASK_VAR; + + COMPUTE_SHIFT_MASK (src); + LOAD_VECTOR (src); + return vec_splat(vsrc, 0); +} + +static force_inline vector unsigned int +create_mask_32_128 (uint32_t mask) +{ + return create_mask_1x32_128(&mask); +} + +static force_inline vector unsigned int +unpacklo_128_16x8 (vector unsigned int data1, vector unsigned int data2) +{ + vector unsigned char lo; + + /* unpack to short */ + lo = (vector unsigned char) +#ifdef WORDS_BIGENDIAN + vec_mergel ((vector unsigned char) data2, + (vector unsigned char) data1); +#else + vec_mergel ((vector unsigned char) data1, + (vector unsigned char) data2); +#endif + + return (vector unsigned int) lo; +} + +static force_inline vector unsigned int +unpackhi_128_16x8 (vector unsigned int data1, vector unsigned int data2) +{ + vector unsigned char hi; + + /* unpack to short */ + hi = (vector unsigned char) +#ifdef WORDS_BIGENDIAN + vec_mergeh ((vector unsigned char) data2, + (vector unsigned char) data1); +#else + vec_mergeh ((vector unsigned char) data1, + (vector unsigned char) data2); +#endif + + return (vector unsigned int) hi; +} + +static force_inline vector unsigned int +unpacklo_128_8x16 (vector unsigned int data1, vector unsigned int data2) +{ + vector unsigned short lo; + + /* unpack to char */ + lo = (vector unsigned short) +#ifdef WORDS_BIGENDIAN + vec_mergel ((vector unsigned short) data2, + (vector unsigned short) data1); +#else + vec_mergel ((vector unsigned short) data1, + (vector unsigned short) data2); +#endif + + return (vector unsigned int) lo; +} + +static force_inline vector unsigned int +unpackhi_128_8x16 (vector unsigned int data1, vector unsigned int data2) +{ + vector unsigned short hi; + + /* unpack to char */ + hi = (vector unsigned short) +#ifdef WORDS_BIGENDIAN + vec_mergeh ((vector unsigned short) data2, + (vector unsigned short) data1); +#else + vec_mergeh ((vector unsigned short) data1, + (vector unsigned short) data2); +#endif + + return (vector unsigned int) hi; +} + +static force_inline void +unpack_128_2x128 (vector unsigned int data1, vector unsigned int data2, + vector unsigned int* data_lo, vector unsigned int* data_hi) +{ + *data_lo = unpacklo_128_16x8(data1, data2); + *data_hi = unpackhi_128_16x8(data1, data2); +} + +static force_inline void +unpack_128_2x128_16 (vector unsigned int data1, vector unsigned int data2, + vector unsigned int* data_lo, vector unsigned int* data_hi) +{ + *data_lo = unpacklo_128_8x16(data1, data2); + *data_hi = unpackhi_128_8x16(data1, data2); +} + +static force_inline vector unsigned int +unpack_565_to_8888 (vector unsigned int lo) +{ + vector unsigned int r, g, b, rb, t; + + r = vec_and (vec_sl(lo, create_mask_32_128(8)), mask_red); + g = vec_and (vec_sl(lo, create_mask_32_128(5)), mask_green); + b = vec_and (vec_sl(lo, create_mask_32_128(3)), mask_blue); + + rb = vec_or (r, b); + t = vec_and (rb, mask_565_fix_rb); + t = vec_sr (t, create_mask_32_128(5)); + rb = vec_or (rb, t); + + t = vec_and (g, mask_565_fix_g); + t = vec_sr (t, create_mask_32_128(6)); + g = vec_or (g, t); + + return vec_or (rb, g); +} + +static force_inline int +is_opaque (vector unsigned int x) +{ + uint32_t cmp_result; + vector bool int ffs = vec_cmpeq(x, x); + + cmp_result = vec_all_eq(x, ffs); + + return (cmp_result & 0x8888) == 0x8888; +} + +static force_inline int +is_zero (vector unsigned int x) +{ + uint32_t cmp_result; + + cmp_result = vec_all_eq(x, (vector unsigned int) AVV(0)); + + return cmp_result == 0xffff; +} + +static force_inline int +is_transparent (vector unsigned int x) +{ + uint32_t cmp_result; + + cmp_result = vec_all_eq(x, (vector unsigned int) AVV(0)); + return (cmp_result & 0x8888) == 0x8888; +} + +static force_inline uint32_t +core_combine_over_u_pixel_vmx (uint32_t src, uint32_t dst) +{ + uint32_t a; + + a = ALPHA_8(src); + + if (a == 0xff) + { + return src; + } + else if (src) + { + UN8x4_MUL_UN8_ADD_UN8x4(dst, (~a & MASK), src); + } + + return dst; +} + +static force_inline uint32_t +combine1 (const uint32_t *ps, const uint32_t *pm) +{ + uint32_t s = *ps; + + if (pm) + UN8x4_MUL_UN8(s, ALPHA_8(*pm)); + + return s; +} + +static force_inline vector unsigned int +combine4 (const uint32_t* ps, const uint32_t* pm) +{ + vector unsigned int src, msk; + + if (pm) + { + msk = load_128_unaligned(pm); + + if (is_transparent(msk)) + return (vector unsigned int) AVV(0); + } + + src = load_128_unaligned(ps); + + if (pm) + src = pix_multiply(src, msk); + + return src; +} static void vmx_combine_over_u_no_mask (uint32_t * dest, @@ -189,8 +492,19 @@ vmx_combine_over_u_no_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t ia = ALPHA_8 (~s); + + UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, s); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKS (dest, src); @@ -228,8 +542,24 @@ vmx_combine_over_u_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, mask_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t m = ALPHA_8 (*mask++); + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t ia; + + UN8x4_MUL_UN8 (s, m); + + ia = ALPHA_8 (~s); + + UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, s); + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -284,8 +614,18 @@ vmx_combine_over_reverse_u_no_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t ia = ALPHA_8 (~d); + + UN8x4_MUL_UN8_ADD_UN8x4 (s, ia, d); + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKS (dest, src); @@ -322,8 +662,22 @@ vmx_combine_over_reverse_u_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, mask_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t m = ALPHA_8 (*mask++); + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t ia = ALPHA_8 (~d); + + UN8x4_MUL_UN8 (s, m); + + UN8x4_MUL_UN8_ADD_UN8x4 (s, ia, d); + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -377,8 +731,17 @@ vmx_combine_in_u_no_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t s = *src++; + uint32_t a = ALPHA_8 (*dest); + + UN8x4_MUL_UN8 (s, a); + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKS (dest, src); @@ -413,8 +776,21 @@ vmx_combine_in_u_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, mask_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t m = ALPHA_8 (*mask++); + uint32_t s = *src++; + uint32_t a = ALPHA_8 (*dest); + + UN8x4_MUL_UN8 (s, m); + UN8x4_MUL_UN8 (s, a); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -466,8 +842,18 @@ vmx_combine_in_reverse_u_no_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t d = *dest; + uint32_t a = ALPHA_8 (*src++); + + UN8x4_MUL_UN8 (d, a); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKS (dest, src); @@ -503,8 +889,22 @@ vmx_combine_in_reverse_u_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, mask_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t m = ALPHA_8 (*mask++); + uint32_t d = *dest; + uint32_t a = *src++; + + UN8x4_MUL_UN8 (a, m); + a = ALPHA_8 (a); + UN8x4_MUL_UN8 (d, a); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -557,8 +957,18 @@ vmx_combine_out_u_no_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t s = *src++; + uint32_t a = ALPHA_8 (~(*dest)); + + UN8x4_MUL_UN8 (s, a); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKS (dest, src); @@ -594,8 +1004,21 @@ vmx_combine_out_u_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, mask_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t m = ALPHA_8 (*mask++); + uint32_t s = *src++; + uint32_t a = ALPHA_8 (~(*dest)); + + UN8x4_MUL_UN8 (s, m); + UN8x4_MUL_UN8 (s, a); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -647,8 +1070,18 @@ vmx_combine_out_reverse_u_no_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t d = *dest; + uint32_t a = ALPHA_8 (~(*src++)); + + UN8x4_MUL_UN8 (d, a); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKS (dest, src); @@ -685,8 +1118,22 @@ vmx_combine_out_reverse_u_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, mask_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t m = ALPHA_8 (*mask++); + uint32_t d = *dest; + uint32_t a = *src++; + + UN8x4_MUL_UN8 (a, m); + a = ALPHA_8 (~a); + UN8x4_MUL_UN8 (d, a); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -739,8 +1186,20 @@ vmx_combine_atop_u_no_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t dest_a = ALPHA_8 (d); + uint32_t src_ia = ALPHA_8 (~s); + + UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_a, d, src_ia); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKS (dest, src); @@ -779,8 +1238,26 @@ vmx_combine_atop_u_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, mask_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t m = ALPHA_8 (*mask++); + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t dest_a = ALPHA_8 (d); + uint32_t src_ia; + + UN8x4_MUL_UN8 (s, m); + + src_ia = ALPHA_8 (~s); + + UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_a, d, src_ia); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -838,8 +1315,20 @@ vmx_combine_atop_reverse_u_no_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t src_a = ALPHA_8 (s); + uint32_t dest_ia = ALPHA_8 (~d); + + UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_ia, d, src_a); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKS (dest, src); @@ -878,8 +1367,26 @@ vmx_combine_atop_reverse_u_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, mask_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t m = ALPHA_8 (*mask++); + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t src_a; + uint32_t dest_ia = ALPHA_8 (~d); + + UN8x4_MUL_UN8 (s, m); + + src_a = ALPHA_8 (s); + + UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_ia, d, src_a); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -937,8 +1444,20 @@ vmx_combine_xor_u_no_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t src_ia = ALPHA_8 (~s); + uint32_t dest_ia = ALPHA_8 (~d); + + UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_ia, d, src_ia); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKS (dest, src); @@ -977,8 +1496,26 @@ vmx_combine_xor_u_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, mask_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t m = ALPHA_8 (*mask++); + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t src_ia; + uint32_t dest_ia = ALPHA_8 (~d); + + UN8x4_MUL_UN8 (s, m); + + src_ia = ALPHA_8 (~s); + + UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_ia, d, src_ia); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1036,8 +1573,18 @@ vmx_combine_add_u_no_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t s = *src++; + uint32_t d = *dest; + + UN8x4_ADD_UN8x4 (d, s); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKS (dest, src); /* printf ("%s\n",__PRETTY_FUNCTION__); */ @@ -1072,8 +1619,21 @@ vmx_combine_add_u_mask (uint32_t * dest, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, src_mask, mask_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t m = ALPHA_8 (*mask++); + uint32_t s = *src++; + uint32_t d = *dest; + + UN8x4_MUL_UN8 (s, m); + UN8x4_ADD_UN8x4 (d, s); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1128,8 +1688,19 @@ vmx_combine_src_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t s = *src++; + + UN8x4_MUL_UN8x4 (s, a); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1168,8 +1739,23 @@ vmx_combine_over_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t sa = ALPHA_8 (s); + + UN8x4_MUL_UN8x4 (s, a); + UN8x4_MUL_UN8 (a, sa); + UN8x4_MUL_UN8x4_ADD_UN8x4 (d, ~a, s); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1212,8 +1798,22 @@ vmx_combine_over_reverse_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t ida = ALPHA_8 (~d); + + UN8x4_MUL_UN8x4 (s, a); + UN8x4_MUL_UN8_ADD_UN8x4 (s, ida, d); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1255,8 +1855,21 @@ vmx_combine_in_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t s = *src++; + uint32_t da = ALPHA_8 (*dest); + + UN8x4_MUL_UN8x4 (s, a); + UN8x4_MUL_UN8 (s, da); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1297,8 +1910,21 @@ vmx_combine_in_reverse_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t d = *dest; + uint32_t sa = ALPHA_8 (*src++); + + UN8x4_MUL_UN8 (a, sa); + UN8x4_MUL_UN8x4 (d, a); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1340,8 +1966,22 @@ vmx_combine_out_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t da = ALPHA_8 (~d); + + UN8x4_MUL_UN8x4 (s, a); + UN8x4_MUL_UN8 (s, da); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1384,8 +2024,22 @@ vmx_combine_out_reverse_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t sa = ALPHA_8 (s); + + UN8x4_MUL_UN8 (a, sa); + UN8x4_MUL_UN8x4 (d, ~a); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1428,8 +2082,24 @@ vmx_combine_atop_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask, vsrca; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t sa = ALPHA_8 (s); + uint32_t da = ALPHA_8 (d); + + UN8x4_MUL_UN8x4 (s, a); + UN8x4_MUL_UN8 (a, sa); + UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (d, ~a, s, da); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1479,8 +2149,24 @@ vmx_combine_atop_reverse_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t sa = ALPHA_8 (s); + uint32_t da = ALPHA_8 (~d); + + UN8x4_MUL_UN8x4 (s, a); + UN8x4_MUL_UN8 (a, sa); + UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (d, a, s, da); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1527,8 +2213,24 @@ vmx_combine_xor_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t s = *src++; + uint32_t d = *dest; + uint32_t sa = ALPHA_8 (s); + uint32_t da = ALPHA_8 (~d); + + UN8x4_MUL_UN8x4 (s, a); + UN8x4_MUL_UN8 (a, sa); + UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (d, ~a, s, da); + + *dest++ = d; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1575,8 +2277,21 @@ vmx_combine_add_ca (pixman_implementation_t *imp, { int i; vector unsigned int vdest, vsrc, vmask; - vector unsigned char tmp1, tmp2, tmp3, tmp4, edges, - dest_mask, mask_mask, src_mask, store_mask; + DECLARE_SRC_MASK_VAR; + DECLARE_MASK_MASK_VAR; + + while (width && ((uintptr_t)dest & 15)) + { + uint32_t a = *mask++; + uint32_t s = *src++; + uint32_t d = *dest; + + UN8x4_MUL_UN8x4 (s, a); + UN8x4_ADD_UN8x4 (s, d); + + *dest++ = s; + width--; + } COMPUTE_SHIFT_MASKC (dest, src, mask); @@ -1607,16 +2322,809 @@ vmx_combine_add_ca (pixman_implementation_t *imp, } } +static void +vmx_composite_over_n_8_8888 (pixman_implementation_t *imp, + pixman_composite_info_t *info) +{ + PIXMAN_COMPOSITE_ARGS (info); + uint32_t src, srca; + uint32_t *dst_line, *dst; + uint8_t *mask_line; + int dst_stride, mask_stride; + int32_t w; + uint32_t m, d, s, ia; + + vector unsigned int vsrc, valpha, vmask, vdst; + + src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format); + + srca = ALPHA_8(src); + if (src == 0) + return; + + PIXMAN_IMAGE_GET_LINE ( + dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1); + PIXMAN_IMAGE_GET_LINE ( + mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1); + + vsrc = (vector unsigned int) {src, src, src, src}; + valpha = splat_alpha(vsrc); + + while (height--) + { + const uint8_t *pm = mask_line; + dst = dst_line; + dst_line += dst_stride; + mask_line += mask_stride; + w = width; + + while (w && (uintptr_t)dst & 15) + { + s = src; + m = *pm++; + + if (m) + { + d = *dst; + UN8x4_MUL_UN8 (s, m); + ia = ALPHA_8 (~s); + UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, s); + *dst = d; + } + + w--; + dst++; + } + + while (w >= 4) + { + m = *((uint32_t*)pm); + + if (srca == 0xff && m == 0xffffffff) + { + save_128_aligned(dst, vsrc); + } + else if (m) + { + vmask = splat_pixel((vector unsigned int) {m, m, m, m}); + + /* dst is 16-byte aligned */ + vdst = in_over (vsrc, valpha, vmask, load_128_aligned (dst)); + + save_128_aligned(dst, vdst); + } + + w -= 4; + dst += 4; + pm += 4; + } + + while (w) + { + s = src; + m = *pm++; + + if (m) + { + d = *dst; + UN8x4_MUL_UN8 (s, m); + ia = ALPHA_8 (~s); + UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, s); + *dst = d; + } + + w--; + dst++; + } + } + +} + +static pixman_bool_t +vmx_fill (pixman_implementation_t *imp, + uint32_t * bits, + int stride, + int bpp, + int x, + int y, + int width, + int height, + uint32_t filler) +{ + uint32_t byte_width; + uint8_t *byte_line; + + vector unsigned int vfiller; + + if (bpp == 8) + { + uint8_t b; + uint16_t w; + + stride = stride * (int) sizeof (uint32_t) / 1; + byte_line = (uint8_t *)(((uint8_t *)bits) + stride * y + x); + byte_width = width; + stride *= 1; + + b = filler & 0xff; + w = (b << 8) | b; + filler = (w << 16) | w; + } + else if (bpp == 16) + { + stride = stride * (int) sizeof (uint32_t) / 2; + byte_line = (uint8_t *)(((uint16_t *)bits) + stride * y + x); + byte_width = 2 * width; + stride *= 2; + + filler = (filler & 0xffff) * 0x00010001; + } + else if (bpp == 32) + { + stride = stride * (int) sizeof (uint32_t) / 4; + byte_line = (uint8_t *)(((uint32_t *)bits) + stride * y + x); + byte_width = 4 * width; + stride *= 4; + } + else + { + return FALSE; + } + + vfiller = create_mask_1x32_128(&filler); + + while (height--) + { + int w; + uint8_t *d = byte_line; + byte_line += stride; + w = byte_width; + + if (w >= 1 && ((uintptr_t)d & 1)) + { + *(uint8_t *)d = filler; + w -= 1; + d += 1; + } + + while (w >= 2 && ((uintptr_t)d & 3)) + { + *(uint16_t *)d = filler; + w -= 2; + d += 2; + } + + while (w >= 4 && ((uintptr_t)d & 15)) + { + *(uint32_t *)d = filler; + + w -= 4; + d += 4; + } + + while (w >= 128) + { + vec_st(vfiller, 0, (uint32_t *) d); + vec_st(vfiller, 0, (uint32_t *) d + 4); + vec_st(vfiller, 0, (uint32_t *) d + 8); + vec_st(vfiller, 0, (uint32_t *) d + 12); + vec_st(vfiller, 0, (uint32_t *) d + 16); + vec_st(vfiller, 0, (uint32_t *) d + 20); + vec_st(vfiller, 0, (uint32_t *) d + 24); + vec_st(vfiller, 0, (uint32_t *) d + 28); + + d += 128; + w -= 128; + } + + if (w >= 64) + { + vec_st(vfiller, 0, (uint32_t *) d); + vec_st(vfiller, 0, (uint32_t *) d + 4); + vec_st(vfiller, 0, (uint32_t *) d + 8); + vec_st(vfiller, 0, (uint32_t *) d + 12); + + d += 64; + w -= 64; + } + + if (w >= 32) + { + vec_st(vfiller, 0, (uint32_t *) d); + vec_st(vfiller, 0, (uint32_t *) d + 4); + + d += 32; + w -= 32; + } + + if (w >= 16) + { + vec_st(vfiller, 0, (uint32_t *) d); + + d += 16; + w -= 16; + } + + while (w >= 4) + { + *(uint32_t *)d = filler; + + w -= 4; + d += 4; + } + + if (w >= 2) + { + *(uint16_t *)d = filler; + w -= 2; + d += 2; + } + + if (w >= 1) + { + *(uint8_t *)d = filler; + w -= 1; + d += 1; + } + } + + return TRUE; +} + +static void +vmx_composite_src_x888_8888 (pixman_implementation_t *imp, + pixman_composite_info_t *info) +{ + PIXMAN_COMPOSITE_ARGS (info); + uint32_t *dst_line, *dst; + uint32_t *src_line, *src; + int32_t w; + int dst_stride, src_stride; + + PIXMAN_IMAGE_GET_LINE ( + dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1); + PIXMAN_IMAGE_GET_LINE ( + src_image, src_x, src_y, uint32_t, src_stride, src_line, 1); + + while (height--) + { + dst = dst_line; + dst_line += dst_stride; + src = src_line; + src_line += src_stride; + w = width; + + while (w && (uintptr_t)dst & 15) + { + *dst++ = *src++ | 0xff000000; + w--; + } + + while (w >= 16) + { + vector unsigned int vmx_src1, vmx_src2, vmx_src3, vmx_src4; + + vmx_src1 = load_128_unaligned (src); + vmx_src2 = load_128_unaligned (src + 4); + vmx_src3 = load_128_unaligned (src + 8); + vmx_src4 = load_128_unaligned (src + 12); + + save_128_aligned (dst, vec_or (vmx_src1, mask_ff000000)); + save_128_aligned (dst + 4, vec_or (vmx_src2, mask_ff000000)); + save_128_aligned (dst + 8, vec_or (vmx_src3, mask_ff000000)); + save_128_aligned (dst + 12, vec_or (vmx_src4, mask_ff000000)); + + dst += 16; + src += 16; + w -= 16; + } + + while (w) + { + *dst++ = *src++ | 0xff000000; + w--; + } + } +} + +static void +vmx_composite_over_n_8888 (pixman_implementation_t *imp, + pixman_composite_info_t *info) +{ + PIXMAN_COMPOSITE_ARGS (info); + uint32_t *dst_line, *dst; + uint32_t src, ia; + int i, w, dst_stride; + vector unsigned int vdst, vsrc, via; + + src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format); + + if (src == 0) + return; + + PIXMAN_IMAGE_GET_LINE ( + dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1); + + vsrc = (vector unsigned int){src, src, src, src}; + via = negate (splat_alpha (vsrc)); + ia = ALPHA_8 (~src); + + while (height--) + { + dst = dst_line; + dst_line += dst_stride; + w = width; + + while (w && ((uintptr_t)dst & 15)) + { + uint32_t d = *dst; + UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, src); + *dst++ = d; + w--; + } + + for (i = w / 4; i > 0; i--) + { + vdst = pix_multiply (load_128_aligned (dst), via); + save_128_aligned (dst, pix_add (vsrc, vdst)); + dst += 4; + } + + for (i = w % 4; --i >= 0;) + { + uint32_t d = dst[i]; + UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, src); + dst[i] = d; + } + } +} + +static void +vmx_composite_over_8888_8888 (pixman_implementation_t *imp, + pixman_composite_info_t *info) +{ + PIXMAN_COMPOSITE_ARGS (info); + int dst_stride, src_stride; + uint32_t *dst_line, *dst; + uint32_t *src_line, *src; + + PIXMAN_IMAGE_GET_LINE ( + dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1); + PIXMAN_IMAGE_GET_LINE ( + src_image, src_x, src_y, uint32_t, src_stride, src_line, 1); + + dst = dst_line; + src = src_line; + + while (height--) + { + vmx_combine_over_u (imp, op, dst, src, NULL, width); + + dst += dst_stride; + src += src_stride; + } +} + +static void +vmx_composite_over_n_8888_8888_ca (pixman_implementation_t *imp, + pixman_composite_info_t *info) +{ + PIXMAN_COMPOSITE_ARGS (info); + uint32_t src, ia; + uint32_t *dst_line, d; + uint32_t *mask_line, m; + uint32_t pack_cmp; + int dst_stride, mask_stride; + + vector unsigned int vsrc, valpha, vmask, vdest; + + src = _pixman_image_get_solid (imp, src_image, dest_image->bits.format); + + if (src == 0) + return; + + PIXMAN_IMAGE_GET_LINE ( + dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1); + PIXMAN_IMAGE_GET_LINE ( + mask_image, mask_x, mask_y, uint32_t, mask_stride, mask_line, 1); + + vsrc = (vector unsigned int) {src, src, src, src}; + valpha = splat_alpha(vsrc); + ia = ALPHA_8 (src); + + while (height--) + { + int w = width; + const uint32_t *pm = (uint32_t *)mask_line; + uint32_t *pd = (uint32_t *)dst_line; + uint32_t s; + + dst_line += dst_stride; + mask_line += mask_stride; + + while (w && (uintptr_t)pd & 15) + { + s = src; + m = *pm++; + + if (m) + { + d = *pd; + UN8x4_MUL_UN8x4 (s, m); + UN8x4_MUL_UN8 (m, ia); + m = ~m; + UN8x4_MUL_UN8x4_ADD_UN8x4 (d, m, s); + *pd = d; + } + + pd++; + w--; + } + + while (w >= 4) + { + /* pm is NOT necessarily 16-byte aligned */ + vmask = load_128_unaligned (pm); + + pack_cmp = vec_all_eq(vmask, (vector unsigned int) AVV(0)); + + /* if all bits in mask are zero, pack_cmp is not 0 */ + if (pack_cmp == 0) + { + /* pd is 16-byte aligned */ + vdest = in_over (vsrc, valpha, vmask, load_128_aligned (pd)); + + save_128_aligned(pd, vdest); + } + + pd += 4; + pm += 4; + w -= 4; + } + + while (w) + { + s = src; + m = *pm++; + + if (m) + { + d = *pd; + UN8x4_MUL_UN8x4 (s, m); + UN8x4_MUL_UN8 (m, ia); + m = ~m; + UN8x4_MUL_UN8x4_ADD_UN8x4 (d, m, s); + *pd = d; + } + + pd++; + w--; + } + } +} + +static void +vmx_composite_add_8_8 (pixman_implementation_t *imp, + pixman_composite_info_t *info) +{ + PIXMAN_COMPOSITE_ARGS (info); + uint8_t *dst_line, *dst; + uint8_t *src_line, *src; + int dst_stride, src_stride; + int32_t w; + uint16_t t; + + PIXMAN_IMAGE_GET_LINE ( + src_image, src_x, src_y, uint8_t, src_stride, src_line, 1); + PIXMAN_IMAGE_GET_LINE ( + dest_image, dest_x, dest_y, uint8_t, dst_stride, dst_line, 1); + + while (height--) + { + dst = dst_line; + src = src_line; + + dst_line += dst_stride; + src_line += src_stride; + w = width; + + /* Small head */ + while (w && (uintptr_t)dst & 3) + { + t = (*dst) + (*src++); + *dst++ = t | (0 - (t >> 8)); + w--; + } + + vmx_combine_add_u (imp, op, + (uint32_t*)dst, (uint32_t*)src, NULL, w >> 2); + + /* Small tail */ + dst += w & 0xfffc; + src += w & 0xfffc; + + w &= 3; + + while (w) + { + t = (*dst) + (*src++); + *dst++ = t | (0 - (t >> 8)); + w--; + } + } +} + +static void +vmx_composite_add_8888_8888 (pixman_implementation_t *imp, + pixman_composite_info_t *info) +{ + PIXMAN_COMPOSITE_ARGS (info); + uint32_t *dst_line, *dst; + uint32_t *src_line, *src; + int dst_stride, src_stride; + + PIXMAN_IMAGE_GET_LINE ( + src_image, src_x, src_y, uint32_t, src_stride, src_line, 1); + PIXMAN_IMAGE_GET_LINE ( + dest_image, dest_x, dest_y, uint32_t, dst_stride, dst_line, 1); + + while (height--) + { + dst = dst_line; + dst_line += dst_stride; + src = src_line; + src_line += src_stride; + + vmx_combine_add_u (imp, op, dst, src, NULL, width); + } +} + +static force_inline void +scaled_nearest_scanline_vmx_8888_8888_OVER (uint32_t* pd, + const uint32_t* ps, + int32_t w, + pixman_fixed_t vx, + pixman_fixed_t unit_x, + pixman_fixed_t src_width_fixed, + pixman_bool_t fully_transparent_src) +{ + uint32_t s, d; + const uint32_t* pm = NULL; + + vector unsigned int vsrc, vdst; + + if (fully_transparent_src) + return; + + /* Align dst on a 16-byte boundary */ + while (w && ((uintptr_t)pd & 15)) + { + d = *pd; + s = combine1 (ps + pixman_fixed_to_int (vx), pm); + vx += unit_x; + while (vx >= 0) + vx -= src_width_fixed; + + *pd++ = core_combine_over_u_pixel_vmx (s, d); + if (pm) + pm++; + w--; + } + + while (w >= 4) + { + vector unsigned int tmp; + uint32_t tmp1, tmp2, tmp3, tmp4; + + tmp1 = *(ps + pixman_fixed_to_int (vx)); + vx += unit_x; + while (vx >= 0) + vx -= src_width_fixed; + tmp2 = *(ps + pixman_fixed_to_int (vx)); + vx += unit_x; + while (vx >= 0) + vx -= src_width_fixed; + tmp3 = *(ps + pixman_fixed_to_int (vx)); + vx += unit_x; + while (vx >= 0) + vx -= src_width_fixed; + tmp4 = *(ps + pixman_fixed_to_int (vx)); + vx += unit_x; + while (vx >= 0) + vx -= src_width_fixed; + + tmp[0] = tmp1; + tmp[1] = tmp2; + tmp[2] = tmp3; + tmp[3] = tmp4; + + vsrc = combine4 ((const uint32_t *) &tmp, pm); + + if (is_opaque (vsrc)) + { + save_128_aligned (pd, vsrc); + } + else if (!is_zero (vsrc)) + { + vdst = over(vsrc, splat_alpha(vsrc), load_128_aligned (pd)); + + save_128_aligned (pd, vdst); + } + + w -= 4; + pd += 4; + if (pm) + pm += 4; + } + + while (w) + { + d = *pd; + s = combine1 (ps + pixman_fixed_to_int (vx), pm); + vx += unit_x; + while (vx >= 0) + vx -= src_width_fixed; + + *pd++ = core_combine_over_u_pixel_vmx (s, d); + if (pm) + pm++; + + w--; + } +} + +FAST_NEAREST_MAINLOOP (vmx_8888_8888_cover_OVER, + scaled_nearest_scanline_vmx_8888_8888_OVER, + uint32_t, uint32_t, COVER) +FAST_NEAREST_MAINLOOP (vmx_8888_8888_none_OVER, + scaled_nearest_scanline_vmx_8888_8888_OVER, + uint32_t, uint32_t, NONE) +FAST_NEAREST_MAINLOOP (vmx_8888_8888_pad_OVER, + scaled_nearest_scanline_vmx_8888_8888_OVER, + uint32_t, uint32_t, PAD) +FAST_NEAREST_MAINLOOP (vmx_8888_8888_normal_OVER, + scaled_nearest_scanline_vmx_8888_8888_OVER, + uint32_t, uint32_t, NORMAL) + static const pixman_fast_path_t vmx_fast_paths[] = { + PIXMAN_STD_FAST_PATH (OVER, solid, null, a8r8g8b8, vmx_composite_over_n_8888), + PIXMAN_STD_FAST_PATH (OVER, solid, null, x8r8g8b8, vmx_composite_over_n_8888), + PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, a8r8g8b8, vmx_composite_over_8888_8888), + PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, vmx_composite_over_8888_8888), + PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, vmx_composite_over_8888_8888), + PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, x8b8g8r8, vmx_composite_over_8888_8888), + PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, vmx_composite_over_n_8_8888), + PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8r8g8b8, vmx_composite_over_n_8_8888), + PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, vmx_composite_over_n_8_8888), + PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8b8g8r8, vmx_composite_over_n_8_8888), + PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, a8r8g8b8, vmx_composite_over_n_8888_8888_ca), + PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, x8r8g8b8, vmx_composite_over_n_8888_8888_ca), + PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, a8b8g8r8, vmx_composite_over_n_8888_8888_ca), + PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, x8b8g8r8, vmx_composite_over_n_8888_8888_ca), + + /* PIXMAN_OP_ADD */ + PIXMAN_STD_FAST_PATH (ADD, a8, null, a8, vmx_composite_add_8_8), + PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, null, a8r8g8b8, vmx_composite_add_8888_8888), + PIXMAN_STD_FAST_PATH (ADD, a8b8g8r8, null, a8b8g8r8, vmx_composite_add_8888_8888), + + /* PIXMAN_OP_SRC */ + PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, a8r8g8b8, vmx_composite_src_x888_8888), + PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, a8b8g8r8, vmx_composite_src_x888_8888), + + SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, vmx_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, vmx_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, vmx_8888_8888), + SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, vmx_8888_8888), + { PIXMAN_OP_NONE }, }; +static uint32_t * +vmx_fetch_x8r8g8b8 (pixman_iter_t *iter, const uint32_t *mask) +{ + int w = iter->width; + vector unsigned int ff000000 = mask_ff000000; + uint32_t *dst = iter->buffer; + uint32_t *src = (uint32_t *)iter->bits; + + iter->bits += iter->stride; + + while (w && ((uintptr_t)dst) & 0x0f) + { + *dst++ = (*src++) | 0xff000000; + w--; + } + + while (w >= 4) + { + save_128_aligned(dst, vec_or(load_128_unaligned(src), ff000000)); + + dst += 4; + src += 4; + w -= 4; + } + + while (w) + { + *dst++ = (*src++) | 0xff000000; + w--; + } + + return iter->buffer; +} + +static uint32_t * +vmx_fetch_a8 (pixman_iter_t *iter, const uint32_t *mask) +{ + int w = iter->width; + uint32_t *dst = iter->buffer; + uint8_t *src = iter->bits; + vector unsigned int vmx0, vmx1, vmx2, vmx3, vmx4, vmx5, vmx6; + + iter->bits += iter->stride; + + while (w && (((uintptr_t)dst) & 15)) + { + *dst++ = *(src++) << 24; + w--; + } + + while (w >= 16) + { + vmx0 = load_128_unaligned((uint32_t *) src); + + unpack_128_2x128((vector unsigned int) AVV(0), vmx0, &vmx1, &vmx2); + unpack_128_2x128_16((vector unsigned int) AVV(0), vmx1, &vmx3, &vmx4); + unpack_128_2x128_16((vector unsigned int) AVV(0), vmx2, &vmx5, &vmx6); + + save_128_aligned(dst, vmx6); + save_128_aligned((dst + 4), vmx5); + save_128_aligned((dst + 8), vmx4); + save_128_aligned((dst + 12), vmx3); + + dst += 16; + src += 16; + w -= 16; + } + + while (w) + { + *dst++ = *(src++) << 24; + w--; + } + + return iter->buffer; +} + +#define IMAGE_FLAGS \ + (FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM | \ + FAST_PATH_BITS_IMAGE | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST) + +static const pixman_iter_info_t vmx_iters[] = +{ + { PIXMAN_x8r8g8b8, IMAGE_FLAGS, ITER_NARROW, + _pixman_iter_init_bits_stride, vmx_fetch_x8r8g8b8, NULL + }, + { PIXMAN_a8, IMAGE_FLAGS, ITER_NARROW, + _pixman_iter_init_bits_stride, vmx_fetch_a8, NULL + }, + { PIXMAN_null }, +}; + pixman_implementation_t * _pixman_implementation_create_vmx (pixman_implementation_t *fallback) { pixman_implementation_t *imp = _pixman_implementation_create (fallback, vmx_fast_paths); + /* VMX constants */ + mask_ff000000 = create_mask_32_128 (0xff000000); + mask_red = create_mask_32_128 (0x00f80000); + mask_green = create_mask_32_128 (0x0000fc00); + mask_blue = create_mask_32_128 (0x000000f8); + mask_565_fix_rb = create_mask_32_128 (0x00e000e0); + mask_565_fix_g = create_mask_32_128 (0x0000c000); + /* Set up function pointers */ imp->combine_32[PIXMAN_OP_OVER] = vmx_combine_over_u; @@ -1643,5 +3151,9 @@ _pixman_implementation_create_vmx (pixman_implementation_t *fallback) imp->combine_32_ca[PIXMAN_OP_XOR] = vmx_combine_xor_ca; imp->combine_32_ca[PIXMAN_OP_ADD] = vmx_combine_add_ca; + imp->fill = vmx_fill; + + imp->iter_info = vmx_iters; + return imp; } diff --git a/gfx/cairo/libpixman/src/pixman-x64-mmx-emulation.h b/gfx/cairo/libpixman/src/pixman-x64-mmx-emulation.h deleted file mode 100644 index 378019cf27..0000000000 --- a/gfx/cairo/libpixman/src/pixman-x64-mmx-emulation.h +++ /dev/null @@ -1,263 +0,0 @@ -#ifndef MMX_X64_H_INCLUDED -#define MMX_X64_H_INCLUDED - -/* Implementation of x64 MMX substitition functions, before - * pixman is reimplemented not to use __m64 type on Visual C++ - * - * Copyright (C)2009 by George Yohng - * Released in public domain. - */ - -#include - -#define M64C(a) (*(const __m64 *)(&a)) -#define M64U(a) (*(const unsigned long long *)(&a)) - -__inline __m64 -_m_from_int (int a) -{ - long long i64 = a; - - return M64C (i64); -} - -__inline __m64 -_mm_setzero_si64 () -{ - long long i64 = 0; - - return M64C (i64); -} - -__inline __m64 -_mm_set_pi32 (int i1, int i0) -{ - unsigned long long i64 = ((unsigned)i0) + (((unsigned long long)(unsigned)i1) << 32); - - return M64C (i64); -} - -__inline void -_m_empty () -{ -} - -__inline __m64 -_mm_set1_pi16 (short w) -{ - unsigned long long i64 = ((unsigned long long)(unsigned short)(w)) * 0x0001000100010001ULL; - - return M64C (i64); -} - -__inline int -_m_to_int (__m64 m) -{ - return m.m64_i32[0]; -} - -__inline __m64 -_mm_movepi64_pi64 (__m128i a) -{ - return M64C (a.m128i_i64[0]); -} - -__inline __m64 -_m_pand (__m64 a, __m64 b) -{ - unsigned long long i64 = M64U (a) & M64U (b); - - return M64C (i64); -} - -__inline __m64 -_m_por (__m64 a, __m64 b) -{ - unsigned long long i64 = M64U (a) | M64U (b); - - return M64C (i64); -} - -__inline __m64 -_m_pxor (__m64 a, __m64 b) -{ - unsigned long long i64 = M64U (a) ^ M64U (b); - - return M64C (i64); -} - -__inline __m64 -_m_pmulhuw (__m64 a, __m64 b) /* unoptimized */ -{ - unsigned short d[4] = - { - (unsigned short)((((unsigned)a.m64_u16[0]) * b.m64_u16[0]) >> 16), - (unsigned short)((((unsigned)a.m64_u16[1]) * b.m64_u16[1]) >> 16), - (unsigned short)((((unsigned)a.m64_u16[2]) * b.m64_u16[2]) >> 16), - (unsigned short)((((unsigned)a.m64_u16[3]) * b.m64_u16[3]) >> 16) - }; - - return M64C (d[0]); -} - -__inline __m64 -_m_pmullw2 (__m64 a, __m64 b) /* unoptimized */ -{ - unsigned short d[4] = - { - (unsigned short)((((unsigned)a.m64_u16[0]) * b.m64_u16[0])), - (unsigned short)((((unsigned)a.m64_u16[1]) * b.m64_u16[1])), - (unsigned short)((((unsigned)a.m64_u16[2]) * b.m64_u16[2])), - (unsigned short)((((unsigned)a.m64_u16[3]) * b.m64_u16[3])) - }; - - return M64C (d[0]); -} - -__inline __m64 -_m_pmullw (__m64 a, __m64 b) /* unoptimized */ -{ - unsigned long long x = - ((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[0]) * b.m64_u16[0]))) + - (((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[1]) * b.m64_u16[1]))) << 16) + - (((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[2]) * b.m64_u16[2]))) << 32) + - (((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[3]) * b.m64_u16[3]))) << 48); - - return M64C (x); -} - -__inline __m64 -_m_paddusb (__m64 a, __m64 b) /* unoptimized */ -{ - unsigned long long x = (M64U (a) & 0x00FF00FF00FF00FFULL) + - (M64U (b) & 0x00FF00FF00FF00FFULL); - - unsigned long long y = ((M64U (a) >> 8) & 0x00FF00FF00FF00FFULL) + - ((M64U (b) >> 8) & 0x00FF00FF00FF00FFULL); - - x |= ((x & 0xFF00FF00FF00FF00ULL) >> 8) * 0xFF; - y |= ((y & 0xFF00FF00FF00FF00ULL) >> 8) * 0xFF; - - x = (x & 0x00FF00FF00FF00FFULL) | ((y & 0x00FF00FF00FF00FFULL) << 8); - - return M64C (x); -} - -__inline __m64 -_m_paddusw (__m64 a, __m64 b) /* unoptimized */ -{ - unsigned long long x = (M64U (a) & 0x0000FFFF0000FFFFULL) + - (M64U (b) & 0x0000FFFF0000FFFFULL); - - unsigned long long y = ((M64U (a) >> 16) & 0x0000FFFF0000FFFFULL) + - ((M64U (b) >> 16) & 0x0000FFFF0000FFFFULL); - - x |= ((x & 0xFFFF0000FFFF0000) >> 16) * 0xFFFF; - y |= ((y & 0xFFFF0000FFFF0000) >> 16) * 0xFFFF; - - x = (x & 0x0000FFFF0000FFFFULL) | ((y & 0x0000FFFF0000FFFFULL) << 16); - - return M64C (x); -} - -__inline __m64 -_m_pshufw (__m64 a, int n) /* unoptimized */ -{ - unsigned short d[4] = - { - a.m64_u16[n & 3], - a.m64_u16[(n >> 2) & 3], - a.m64_u16[(n >> 4) & 3], - a.m64_u16[(n >> 6) & 3] - }; - - return M64C (d[0]); -} - -__inline unsigned char -sat16 (unsigned short d) -{ - if (d > 0xFF) return 0xFF; - else return d & 0xFF; -} - -__inline __m64 -_m_packuswb (__m64 m1, __m64 m2) /* unoptimized */ -{ - unsigned char d[8] = - { - sat16 (m1.m64_u16[0]), - sat16 (m1.m64_u16[1]), - sat16 (m1.m64_u16[2]), - sat16 (m1.m64_u16[3]), - sat16 (m2.m64_u16[0]), - sat16 (m2.m64_u16[1]), - sat16 (m2.m64_u16[2]), - sat16 (m2.m64_u16[3]) - }; - - return M64C (d[0]); -} - -__inline __m64 _m_punpcklbw (__m64 m1, __m64 m2) /* unoptimized */ -{ - unsigned char d[8] = - { - m1.m64_u8[0], - m2.m64_u8[0], - m1.m64_u8[1], - m2.m64_u8[1], - m1.m64_u8[2], - m2.m64_u8[2], - m1.m64_u8[3], - m2.m64_u8[3], - }; - - return M64C (d[0]); -} - -__inline __m64 _m_punpckhbw (__m64 m1, __m64 m2) /* unoptimized */ -{ - unsigned char d[8] = - { - m1.m64_u8[4], - m2.m64_u8[4], - m1.m64_u8[5], - m2.m64_u8[5], - m1.m64_u8[6], - m2.m64_u8[6], - m1.m64_u8[7], - m2.m64_u8[7], - }; - - return M64C (d[0]); -} - -__inline __m64 _m_psrlwi (__m64 a, int n) /* unoptimized */ -{ - unsigned short d[4] = - { - a.m64_u16[0] >> n, - a.m64_u16[1] >> n, - a.m64_u16[2] >> n, - a.m64_u16[3] >> n - }; - - return M64C (d[0]); -} - -__inline __m64 _m_psrlqi (__m64 m, int n) -{ - unsigned long long x = M64U (m) >> n; - - return M64C (x); -} - -__inline __m64 _m_psllqi (__m64 m, int n) -{ - unsigned long long x = M64U (m) << n; - - return M64C (x); -} - -#endif /* MMX_X64_H_INCLUDED */ diff --git a/gfx/cairo/libpixman/src/pixman-x86.c b/gfx/cairo/libpixman/src/pixman-x86.c index feea23e790..2c702e5c3b 100644 --- a/gfx/cairo/libpixman/src/pixman-x86.c +++ b/gfx/cairo/libpixman/src/pixman-x86.c @@ -25,7 +25,7 @@ #include "pixman-private.h" -#if defined(USE_X86_MMX) || defined (USE_SSE2) +#if defined(USE_X86_MMX) || defined (USE_SSE2) || defined (USE_SSSE3) /* The CPU detection code needs to be in a file not compiled with * "-mmmx -msse", as gcc would generate CMOV instructions otherwise @@ -39,7 +39,8 @@ typedef enum X86_MMX_EXTENSIONS = (1 << 1), X86_SSE = (1 << 2) | X86_MMX_EXTENSIONS, X86_SSE2 = (1 << 3), - X86_CMOV = (1 << 4) + X86_CMOV = (1 << 4), + X86_SSSE3 = (1 << 5) } cpu_features_t; #ifdef HAVE_GETISAX @@ -64,6 +65,8 @@ detect_cpu_features (void) features |= X86_SSE; if (result & AV_386_SSE2) features |= X86_SSE2; + if (result & AV_386_SSSE3) + features |= X86_SSSE3; } return features; @@ -171,6 +174,8 @@ detect_cpu_features (void) features |= X86_SSE; if (d & (1 << 26)) features |= X86_SSE2; + if (c & (1 << 9)) + features |= X86_SSSE3; /* Check for AMD specific features */ if ((features & X86_MMX) && !(features & X86_SSE)) @@ -186,6 +191,7 @@ detect_cpu_features (void) memcpy (vendor + 8, &c, 4); if (strcmp (vendor, "AuthenticAMD") == 0 || + strcmp (vendor, "HygonGenuine") == 0 || strcmp (vendor, "Geode by NSC") == 0) { pixman_cpuid (0x80000000, &a, &b, &c, &d); @@ -226,6 +232,7 @@ _pixman_x86_get_implementations (pixman_implementation_t *imp) { #define MMX_BITS (X86_MMX | X86_MMX_EXTENSIONS) #define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2) +#define SSSE3_BITS (X86_SSE | X86_SSE2 | X86_SSSE3) #ifdef USE_X86_MMX if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS)) @@ -237,5 +244,10 @@ _pixman_x86_get_implementations (pixman_implementation_t *imp) imp = _pixman_implementation_create_sse2 (imp); #endif +#ifdef USE_SSSE3 + if (!_pixman_disabled ("ssse3") && have_feature (SSSE3_BITS)) + imp = _pixman_implementation_create_ssse3 (imp); +#endif + return imp; } diff --git a/gfx/cairo/libpixman/src/pixman.c b/gfx/cairo/libpixman/src/pixman.c index 184f0c4e6a..c09b528083 100644 --- a/gfx/cairo/libpixman/src/pixman.c +++ b/gfx/cairo/libpixman/src/pixman.c @@ -325,18 +325,20 @@ _pixman_compute_composite_region32 (pixman_region32_t * region, return TRUE; } -typedef struct +typedef struct box_48_16 box_48_16_t; + +struct box_48_16 { - pixman_fixed_48_16_t x1; - pixman_fixed_48_16_t y1; - pixman_fixed_48_16_t x2; - pixman_fixed_48_16_t y2; -} box_48_16_t; + pixman_fixed_48_16_t x1; + pixman_fixed_48_16_t y1; + pixman_fixed_48_16_t x2; + pixman_fixed_48_16_t y2; +}; static pixman_bool_t -compute_transformed_extents (pixman_transform_t *transform, +compute_transformed_extents (pixman_transform_t *transform, const pixman_box32_t *extents, - box_48_16_t *transformed) + box_48_16_t *transformed) { pixman_fixed_48_16_t tx1, ty1, tx2, ty2; pixman_fixed_t x1, y1, x2, y2; @@ -495,21 +497,12 @@ analyze_extent (pixman_image_t *image, if (!compute_transformed_extents (transform, extents, &transformed)) return FALSE; - /* Expand the source area by a tiny bit so account of different rounding that - * may happen during sampling. Note that (8 * pixman_fixed_e) is very far from - * 0.5 so this won't cause the area computed to be overly pessimistic. - */ - transformed.x1 -= 8 * pixman_fixed_e; - transformed.y1 -= 8 * pixman_fixed_e; - transformed.x2 += 8 * pixman_fixed_e; - transformed.y2 += 8 * pixman_fixed_e; - if (image->common.type == BITS) { - if (pixman_fixed_to_int (transformed.x1) >= 0 && - pixman_fixed_to_int (transformed.y1) >= 0 && - pixman_fixed_to_int (transformed.x2) < image->bits.width && - pixman_fixed_to_int (transformed.y2) < image->bits.height) + if (pixman_fixed_to_int (transformed.x1 - pixman_fixed_e) >= 0 && + pixman_fixed_to_int (transformed.y1 - pixman_fixed_e) >= 0 && + pixman_fixed_to_int (transformed.x2 - pixman_fixed_e) < image->bits.width && + pixman_fixed_to_int (transformed.y2 - pixman_fixed_e) < image->bits.height) { *flags |= FAST_PATH_SAMPLES_COVER_CLIP_NEAREST; } @@ -605,7 +598,7 @@ pixman_image_composite32 (pixman_op_t op, else { mask_format = PIXMAN_null; - info.mask_flags = FAST_PATH_IS_OPAQUE; + info.mask_flags = FAST_PATH_IS_OPAQUE | FAST_PATH_NO_ALPHA_MAP; } dest_format = dest->common.extended_format_code; @@ -784,6 +777,11 @@ color_to_pixel (const pixman_color_t *color, { uint32_t c = color_to_uint32 (color); + if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_RGBA_FLOAT) + { + return FALSE; + } + if (!(format == PIXMAN_a8r8g8b8 || format == PIXMAN_x8r8g8b8 || format == PIXMAN_a8b8g8r8 || diff --git a/gfx/cairo/libpixman/src/pixman.h b/gfx/cairo/libpixman/src/pixman.h index 23408b0286..66bc9abb1d 100644 --- a/gfx/cairo/libpixman/src/pixman.h +++ b/gfx/cairo/libpixman/src/pixman.h @@ -73,7 +73,6 @@ SOFTWARE. #include "cairo/pixman-rename.h" #endif - #include #ifdef __cplusplus @@ -104,6 +103,8 @@ typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; +#elif defined (_AIX) +# include #else # include #endif @@ -130,7 +131,7 @@ typedef pixman_fixed_16_16_t pixman_fixed_t; #define pixman_fixed_1_minus_e (pixman_fixed_1 - pixman_fixed_e) #define pixman_fixed_minus_1 (pixman_int_to_fixed(-1)) #define pixman_fixed_to_int(f) ((int) ((f) >> 16)) -#define pixman_int_to_fixed(i) ((pixman_fixed_t) ((i) << 16)) +#define pixman_int_to_fixed(i) ((pixman_fixed_t) ((uint32_t) (i) << 16)) #define pixman_fixed_to_double(f) (double) ((f) / (double) pixman_fixed_1) #define pixman_double_to_fixed(d) ((pixman_fixed_t) ((d) * 65536.0)) #define pixman_fixed_frac(f) ((f) & pixman_fixed_1_minus_e) @@ -187,42 +188,73 @@ struct pixman_transform struct pixman_box16; typedef union pixman_image pixman_image_t; +PIXMAN_API void pixman_transform_init_identity (struct pixman_transform *matrix); + +PIXMAN_API pixman_bool_t pixman_transform_point_3d (const struct pixman_transform *transform, struct pixman_vector *vector); + +PIXMAN_API pixman_bool_t pixman_transform_point (const struct pixman_transform *transform, struct pixman_vector *vector); + +PIXMAN_API pixman_bool_t pixman_transform_multiply (struct pixman_transform *dst, const struct pixman_transform *l, const struct pixman_transform *r); + +PIXMAN_API void pixman_transform_init_scale (struct pixman_transform *t, pixman_fixed_t sx, pixman_fixed_t sy); + +PIXMAN_API pixman_bool_t pixman_transform_scale (struct pixman_transform *forward, struct pixman_transform *reverse, pixman_fixed_t sx, pixman_fixed_t sy); + +PIXMAN_API void pixman_transform_init_rotate (struct pixman_transform *t, pixman_fixed_t cos, pixman_fixed_t sin); + +PIXMAN_API pixman_bool_t pixman_transform_rotate (struct pixman_transform *forward, struct pixman_transform *reverse, pixman_fixed_t c, pixman_fixed_t s); + +PIXMAN_API void pixman_transform_init_translate (struct pixman_transform *t, pixman_fixed_t tx, pixman_fixed_t ty); + +PIXMAN_API pixman_bool_t pixman_transform_translate (struct pixman_transform *forward, struct pixman_transform *reverse, pixman_fixed_t tx, pixman_fixed_t ty); + +PIXMAN_API pixman_bool_t pixman_transform_bounds (const struct pixman_transform *matrix, struct pixman_box16 *b); + +PIXMAN_API pixman_bool_t pixman_transform_invert (struct pixman_transform *dst, const struct pixman_transform *src); + +PIXMAN_API pixman_bool_t pixman_transform_is_identity (const struct pixman_transform *t); + +PIXMAN_API pixman_bool_t pixman_transform_is_scale (const struct pixman_transform *t); + +PIXMAN_API pixman_bool_t pixman_transform_is_int_translate (const struct pixman_transform *t); + +PIXMAN_API pixman_bool_t pixman_transform_is_inverse (const struct pixman_transform *a, const struct pixman_transform *b); @@ -242,42 +274,70 @@ struct pixman_f_transform double m[3][3]; }; + +PIXMAN_API pixman_bool_t pixman_transform_from_pixman_f_transform (struct pixman_transform *t, const struct pixman_f_transform *ft); + +PIXMAN_API void pixman_f_transform_from_pixman_transform (struct pixman_f_transform *ft, const struct pixman_transform *t); + +PIXMAN_API pixman_bool_t pixman_f_transform_invert (struct pixman_f_transform *dst, const struct pixman_f_transform *src); + +PIXMAN_API pixman_bool_t pixman_f_transform_point (const struct pixman_f_transform *t, struct pixman_f_vector *v); + +PIXMAN_API void pixman_f_transform_point_3d (const struct pixman_f_transform *t, struct pixman_f_vector *v); + +PIXMAN_API void pixman_f_transform_multiply (struct pixman_f_transform *dst, const struct pixman_f_transform *l, const struct pixman_f_transform *r); + +PIXMAN_API void pixman_f_transform_init_scale (struct pixman_f_transform *t, double sx, double sy); + +PIXMAN_API pixman_bool_t pixman_f_transform_scale (struct pixman_f_transform *forward, struct pixman_f_transform *reverse, double sx, double sy); + +PIXMAN_API void pixman_f_transform_init_rotate (struct pixman_f_transform *t, double cos, double sin); + +PIXMAN_API pixman_bool_t pixman_f_transform_rotate (struct pixman_f_transform *forward, struct pixman_f_transform *reverse, double c, double s); + +PIXMAN_API void pixman_f_transform_init_translate (struct pixman_f_transform *t, double tx, double ty); + +PIXMAN_API pixman_bool_t pixman_f_transform_translate (struct pixman_f_transform *forward, struct pixman_f_transform *reverse, double tx, double ty); + +PIXMAN_API pixman_bool_t pixman_f_transform_bounds (const struct pixman_f_transform *t, struct pixman_box16 *b); + +PIXMAN_API void pixman_f_transform_init_identity (struct pixman_f_transform *t); typedef enum @@ -288,6 +348,16 @@ typedef enum PIXMAN_REPEAT_REFLECT } pixman_repeat_t; +typedef enum +{ + PIXMAN_DITHER_NONE, + PIXMAN_DITHER_FAST, + PIXMAN_DITHER_GOOD, + PIXMAN_DITHER_BEST, + PIXMAN_DITHER_ORDERED_BAYER_8, + PIXMAN_DITHER_ORDERED_BLUE_NOISE_64, +} pixman_dither_t; + typedef enum { PIXMAN_FILTER_FAST, @@ -426,73 +496,120 @@ typedef enum /* This function exists only to make it possible to preserve * the X ABI - it should go away at first opportunity. */ +PIXMAN_API void pixman_region_set_static_pointers (pixman_box16_t *empty_box, pixman_region16_data_t *empty_data, pixman_region16_data_t *broken_data); /* creation/destruction */ +PIXMAN_API void pixman_region_init (pixman_region16_t *region); + +PIXMAN_API void pixman_region_init_rect (pixman_region16_t *region, int x, int y, unsigned int width, unsigned int height); + +PIXMAN_API pixman_bool_t pixman_region_init_rects (pixman_region16_t *region, const pixman_box16_t *boxes, int count); + +PIXMAN_API void pixman_region_init_with_extents (pixman_region16_t *region, pixman_box16_t *extents); + +PIXMAN_API void pixman_region_init_from_image (pixman_region16_t *region, pixman_image_t *image); + +PIXMAN_API void pixman_region_fini (pixman_region16_t *region); /* manipulation */ +PIXMAN_API void pixman_region_translate (pixman_region16_t *region, int x, int y); + +PIXMAN_API pixman_bool_t pixman_region_copy (pixman_region16_t *dest, pixman_region16_t *source); + +PIXMAN_API pixman_bool_t pixman_region_intersect (pixman_region16_t *new_reg, pixman_region16_t *reg1, pixman_region16_t *reg2); + +PIXMAN_API pixman_bool_t pixman_region_union (pixman_region16_t *new_reg, pixman_region16_t *reg1, pixman_region16_t *reg2); + +PIXMAN_API pixman_bool_t pixman_region_union_rect (pixman_region16_t *dest, pixman_region16_t *source, int x, int y, unsigned int width, unsigned int height); + +PIXMAN_API pixman_bool_t pixman_region_intersect_rect (pixman_region16_t *dest, pixman_region16_t *source, int x, int y, unsigned int width, unsigned int height); + +PIXMAN_API pixman_bool_t pixman_region_subtract (pixman_region16_t *reg_d, pixman_region16_t *reg_m, pixman_region16_t *reg_s); + +PIXMAN_API pixman_bool_t pixman_region_inverse (pixman_region16_t *new_reg, pixman_region16_t *reg1, pixman_box16_t *inv_rect); + +PIXMAN_API pixman_bool_t pixman_region_contains_point (pixman_region16_t *region, int x, int y, pixman_box16_t *box); + +PIXMAN_API pixman_region_overlap_t pixman_region_contains_rectangle (pixman_region16_t *region, pixman_box16_t *prect); + +PIXMAN_API pixman_bool_t pixman_region_not_empty (pixman_region16_t *region); + +PIXMAN_API pixman_box16_t * pixman_region_extents (pixman_region16_t *region); + +PIXMAN_API int pixman_region_n_rects (pixman_region16_t *region); + +PIXMAN_API pixman_box16_t * pixman_region_rectangles (pixman_region16_t *region, int *n_rects); + +PIXMAN_API pixman_bool_t pixman_region_equal (pixman_region16_t *region1, pixman_region16_t *region2); + +PIXMAN_API pixman_bool_t pixman_region_selfcheck (pixman_region16_t *region); + +PIXMAN_API void pixman_region_reset (pixman_region16_t *region, pixman_box16_t *box); + +PIXMAN_API void pixman_region_clear (pixman_region16_t *region); /* * 32 bit regions @@ -526,72 +643,119 @@ struct pixman_region32 }; /* creation/destruction */ +PIXMAN_API void pixman_region32_init (pixman_region32_t *region); + +PIXMAN_API void pixman_region32_init_rect (pixman_region32_t *region, int x, int y, unsigned int width, unsigned int height); + +PIXMAN_API pixman_bool_t pixman_region32_init_rects (pixman_region32_t *region, const pixman_box32_t *boxes, int count); + +PIXMAN_API void pixman_region32_init_with_extents (pixman_region32_t *region, pixman_box32_t *extents); + +PIXMAN_API void pixman_region32_init_from_image (pixman_region32_t *region, pixman_image_t *image); + +PIXMAN_API void pixman_region32_fini (pixman_region32_t *region); /* manipulation */ +PIXMAN_API void pixman_region32_translate (pixman_region32_t *region, int x, int y); + +PIXMAN_API pixman_bool_t pixman_region32_copy (pixman_region32_t *dest, pixman_region32_t *source); + +PIXMAN_API pixman_bool_t pixman_region32_intersect (pixman_region32_t *new_reg, pixman_region32_t *reg1, pixman_region32_t *reg2); + +PIXMAN_API pixman_bool_t pixman_region32_union (pixman_region32_t *new_reg, pixman_region32_t *reg1, pixman_region32_t *reg2); + +PIXMAN_API pixman_bool_t pixman_region32_intersect_rect (pixman_region32_t *dest, pixman_region32_t *source, int x, int y, unsigned int width, unsigned int height); + +PIXMAN_API pixman_bool_t pixman_region32_union_rect (pixman_region32_t *dest, pixman_region32_t *source, int x, int y, unsigned int width, unsigned int height); + +PIXMAN_API pixman_bool_t pixman_region32_subtract (pixman_region32_t *reg_d, pixman_region32_t *reg_m, pixman_region32_t *reg_s); + +PIXMAN_API pixman_bool_t pixman_region32_inverse (pixman_region32_t *new_reg, pixman_region32_t *reg1, pixman_box32_t *inv_rect); + +PIXMAN_API pixman_bool_t pixman_region32_contains_point (pixman_region32_t *region, int x, int y, pixman_box32_t *box); + +PIXMAN_API pixman_region_overlap_t pixman_region32_contains_rectangle (pixman_region32_t *region, pixman_box32_t *prect); + +PIXMAN_API pixman_bool_t pixman_region32_not_empty (pixman_region32_t *region); + +PIXMAN_API pixman_box32_t * pixman_region32_extents (pixman_region32_t *region); + +PIXMAN_API int pixman_region32_n_rects (pixman_region32_t *region); + +PIXMAN_API pixman_box32_t * pixman_region32_rectangles (pixman_region32_t *region, int *n_rects); + +PIXMAN_API pixman_bool_t pixman_region32_equal (pixman_region32_t *region1, pixman_region32_t *region2); + +PIXMAN_API pixman_bool_t pixman_region32_selfcheck (pixman_region32_t *region); + +PIXMAN_API void pixman_region32_reset (pixman_region32_t *region, pixman_box32_t *box); + +PIXMAN_API void pixman_region32_clear (pixman_region32_t *region); /* Copy / Fill / Misc */ +PIXMAN_API pixman_bool_t pixman_blt (uint32_t *src_bits, uint32_t *dst_bits, int src_stride, @@ -604,6 +768,8 @@ pixman_bool_t pixman_blt (uint32_t *src_bits, int dest_y, int width, int height); + +PIXMAN_API pixman_bool_t pixman_fill (uint32_t *bits, int stride, int bpp, @@ -613,7 +779,11 @@ pixman_bool_t pixman_fill (uint32_t *bits, int height, uint32_t _xor); + +PIXMAN_API int pixman_version (void); + +PIXMAN_API const char* pixman_version_string (void); /* @@ -657,12 +827,24 @@ struct pixman_indexed ((g) << 4) | \ ((b))) -#define PIXMAN_FORMAT_BPP(f) (((f) >> 24) ) -#define PIXMAN_FORMAT_TYPE(f) (((f) >> 16) & 0xff) -#define PIXMAN_FORMAT_A(f) (((f) >> 12) & 0x0f) -#define PIXMAN_FORMAT_R(f) (((f) >> 8) & 0x0f) -#define PIXMAN_FORMAT_G(f) (((f) >> 4) & 0x0f) -#define PIXMAN_FORMAT_B(f) (((f) ) & 0x0f) +#define PIXMAN_FORMAT_BYTE(bpp,type,a,r,g,b) \ + (((bpp >> 3) << 24) | \ + (3 << 22) | ((type) << 16) | \ + ((a >> 3) << 12) | \ + ((r >> 3) << 8) | \ + ((g >> 3) << 4) | \ + ((b >> 3))) + +#define PIXMAN_FORMAT_RESHIFT(val, ofs, num) \ + (((val >> (ofs)) & ((1 << (num)) - 1)) << ((val >> 22) & 3)) + +#define PIXMAN_FORMAT_BPP(f) PIXMAN_FORMAT_RESHIFT(f, 24, 8) +#define PIXMAN_FORMAT_SHIFT(f) ((uint32_t)((f >> 22) & 3)) +#define PIXMAN_FORMAT_TYPE(f) (((f) >> 16) & 0x3f) +#define PIXMAN_FORMAT_A(f) PIXMAN_FORMAT_RESHIFT(f, 12, 4) +#define PIXMAN_FORMAT_R(f) PIXMAN_FORMAT_RESHIFT(f, 8, 4) +#define PIXMAN_FORMAT_G(f) PIXMAN_FORMAT_RESHIFT(f, 4, 4) +#define PIXMAN_FORMAT_B(f) PIXMAN_FORMAT_RESHIFT(f, 0, 4) #define PIXMAN_FORMAT_RGB(f) (((f) ) & 0xfff) #define PIXMAN_FORMAT_VIS(f) (((f) ) & 0xffff) #define PIXMAN_FORMAT_DEPTH(f) (PIXMAN_FORMAT_A(f) + \ @@ -681,15 +863,22 @@ struct pixman_indexed #define PIXMAN_TYPE_BGRA 8 #define PIXMAN_TYPE_RGBA 9 #define PIXMAN_TYPE_ARGB_SRGB 10 +#define PIXMAN_TYPE_RGBA_FLOAT 11 #define PIXMAN_FORMAT_COLOR(f) \ (PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_ARGB || \ PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_ABGR || \ PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_BGRA || \ - PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_RGBA) + PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_RGBA || \ + PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_RGBA_FLOAT) + +typedef enum { +/* 128bpp formats */ + PIXMAN_rgba_float = PIXMAN_FORMAT_BYTE(128,PIXMAN_TYPE_RGBA_FLOAT,32,32,32,32), +/* 96bpp formats */ + PIXMAN_rgb_float = PIXMAN_FORMAT_BYTE(96,PIXMAN_TYPE_RGBA_FLOAT,0,32,32,32), /* 32bpp formats */ -typedef enum { PIXMAN_a8r8g8b8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB,8,8,8,8), PIXMAN_x8r8g8b8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB,0,8,8,8), PIXMAN_a8b8g8r8 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ABGR,8,8,8,8), @@ -760,30 +949,44 @@ typedef enum { } pixman_format_code_t; /* Querying supported format values. */ +PIXMAN_API pixman_bool_t pixman_format_supported_destination (pixman_format_code_t format); + +PIXMAN_API pixman_bool_t pixman_format_supported_source (pixman_format_code_t format); /* Constructors */ +PIXMAN_API pixman_image_t *pixman_image_create_solid_fill (const pixman_color_t *color); + +PIXMAN_API pixman_image_t *pixman_image_create_linear_gradient (const pixman_point_fixed_t *p1, const pixman_point_fixed_t *p2, const pixman_gradient_stop_t *stops, int n_stops); + +PIXMAN_API pixman_image_t *pixman_image_create_radial_gradient (const pixman_point_fixed_t *inner, const pixman_point_fixed_t *outer, pixman_fixed_t inner_radius, pixman_fixed_t outer_radius, const pixman_gradient_stop_t *stops, int n_stops); + +PIXMAN_API pixman_image_t *pixman_image_create_conical_gradient (const pixman_point_fixed_t *center, pixman_fixed_t angle, const pixman_gradient_stop_t *stops, int n_stops); + +PIXMAN_API pixman_image_t *pixman_image_create_bits (pixman_format_code_t format, int width, int height, uint32_t *bits, int rowstride_bytes); + +PIXMAN_API pixman_image_t *pixman_image_create_bits_no_clear (pixman_format_code_t format, int width, int height, @@ -791,48 +994,99 @@ pixman_image_t *pixman_image_create_bits_no_clear (pixman_format_code_t forma int rowstride_bytes); /* Destructor */ +PIXMAN_API pixman_image_t *pixman_image_ref (pixman_image_t *image); + +PIXMAN_API pixman_bool_t pixman_image_unref (pixman_image_t *image); + +PIXMAN_API void pixman_image_set_destroy_function (pixman_image_t *image, pixman_image_destroy_func_t function, void *data); + +PIXMAN_API void * pixman_image_get_destroy_data (pixman_image_t *image); /* Set properties */ +PIXMAN_API pixman_bool_t pixman_image_set_clip_region (pixman_image_t *image, pixman_region16_t *region); + +PIXMAN_API pixman_bool_t pixman_image_set_clip_region32 (pixman_image_t *image, pixman_region32_t *region); + +PIXMAN_API void pixman_image_set_has_client_clip (pixman_image_t *image, pixman_bool_t clien_clip); + +PIXMAN_API pixman_bool_t pixman_image_set_transform (pixman_image_t *image, const pixman_transform_t *transform); + +PIXMAN_API void pixman_image_set_repeat (pixman_image_t *image, pixman_repeat_t repeat); + +PIXMAN_API +void pixman_image_set_dither (pixman_image_t *image, + pixman_dither_t dither); + +PIXMAN_API +void pixman_image_set_dither_offset (pixman_image_t *image, + int offset_x, + int offset_y); + +PIXMAN_API pixman_bool_t pixman_image_set_filter (pixman_image_t *image, pixman_filter_t filter, const pixman_fixed_t *filter_params, int n_filter_params); + +PIXMAN_API void pixman_image_set_source_clipping (pixman_image_t *image, pixman_bool_t source_clipping); + +PIXMAN_API void pixman_image_set_alpha_map (pixman_image_t *image, pixman_image_t *alpha_map, int16_t x, int16_t y); + +PIXMAN_API void pixman_image_set_component_alpha (pixman_image_t *image, pixman_bool_t component_alpha); + +PIXMAN_API pixman_bool_t pixman_image_get_component_alpha (pixman_image_t *image); + +PIXMAN_API void pixman_image_set_accessors (pixman_image_t *image, pixman_read_memory_func_t read_func, pixman_write_memory_func_t write_func); + +PIXMAN_API void pixman_image_set_indexed (pixman_image_t *image, const pixman_indexed_t *indexed); + +PIXMAN_API uint32_t *pixman_image_get_data (pixman_image_t *image); + +PIXMAN_API int pixman_image_get_width (pixman_image_t *image); + +PIXMAN_API int pixman_image_get_height (pixman_image_t *image); + +PIXMAN_API int pixman_image_get_stride (pixman_image_t *image); /* in bytes */ + +PIXMAN_API int pixman_image_get_depth (pixman_image_t *image); + +PIXMAN_API pixman_format_code_t pixman_image_get_format (pixman_image_t *image); typedef enum @@ -850,6 +1104,7 @@ typedef enum /* Create the parameter list for a SEPARABLE_CONVOLUTION filter * with the given kernels and scale parameters. */ +PIXMAN_API pixman_fixed_t * pixman_filter_create_separable_convolution (int *n_values, pixman_fixed_t scale_x, @@ -861,11 +1116,15 @@ pixman_filter_create_separable_convolution (int *n_values, int subsample_bits_x, int subsample_bits_y); + +PIXMAN_API pixman_bool_t pixman_image_fill_rectangles (pixman_op_t op, pixman_image_t *image, const pixman_color_t *color, int n_rects, const pixman_rectangle16_t *rects); + +PIXMAN_API pixman_bool_t pixman_image_fill_boxes (pixman_op_t op, pixman_image_t *dest, const pixman_color_t *color, @@ -873,6 +1132,7 @@ pixman_bool_t pixman_image_fill_boxes (pixman_op_t const pixman_box32_t *boxes); /* Composite */ +PIXMAN_API pixman_bool_t pixman_compute_composite_region (pixman_region16_t *region, pixman_image_t *src_image, pixman_image_t *mask_image, @@ -885,6 +1145,8 @@ pixman_bool_t pixman_compute_composite_region (pixman_region16_t *region, int16_t dest_y, uint16_t width, uint16_t height); + +PIXMAN_API void pixman_image_composite (pixman_op_t op, pixman_image_t *src, pixman_image_t *mask, @@ -897,6 +1159,8 @@ void pixman_image_composite (pixman_op_t op, int16_t dest_y, uint16_t width, uint16_t height); + +PIXMAN_API void pixman_image_composite32 (pixman_op_t op, pixman_image_t *src, pixman_image_t *mask, @@ -928,6 +1192,7 @@ void pixman_image_composite32 (pixman_op_t op, * Since 0.21.2, pixman doesn't do these workarounds anymore, so now this * function is a no-op. */ +PIXMAN_API void pixman_disable_out_of_bounds_workaround (void); /* @@ -940,29 +1205,48 @@ typedef struct const void *glyph; } pixman_glyph_t; +PIXMAN_API pixman_glyph_cache_t *pixman_glyph_cache_create (void); + +PIXMAN_API void pixman_glyph_cache_destroy (pixman_glyph_cache_t *cache); + +PIXMAN_API void pixman_glyph_cache_freeze (pixman_glyph_cache_t *cache); + +PIXMAN_API void pixman_glyph_cache_thaw (pixman_glyph_cache_t *cache); + +PIXMAN_API const void * pixman_glyph_cache_lookup (pixman_glyph_cache_t *cache, void *font_key, void *glyph_key); + +PIXMAN_API const void * pixman_glyph_cache_insert (pixman_glyph_cache_t *cache, void *font_key, void *glyph_key, int origin_x, int origin_y, pixman_image_t *glyph_image); + +PIXMAN_API void pixman_glyph_cache_remove (pixman_glyph_cache_t *cache, void *font_key, void *glyph_key); + +PIXMAN_API void pixman_glyph_get_extents (pixman_glyph_cache_t *cache, int n_glyphs, pixman_glyph_t *glyphs, pixman_box32_t *extents); + +PIXMAN_API pixman_format_code_t pixman_glyph_get_mask_format (pixman_glyph_cache_t *cache, int n_glyphs, const pixman_glyph_t *glyphs); + +PIXMAN_API void pixman_composite_glyphs (pixman_op_t op, pixman_image_t *src, pixman_image_t *dest, @@ -978,6 +1262,8 @@ void pixman_composite_glyphs (pixman_op_t op, pixman_glyph_cache_t *cache, int n_glyphs, const pixman_glyph_t *glyphs); + +PIXMAN_API void pixman_composite_glyphs_no_mask (pixman_op_t op, pixman_image_t *src, pixman_image_t *dest, @@ -1033,7 +1319,7 @@ struct pixman_triangle #define pixman_trapezoid_valid(t) \ ((t)->left.p1.y != (t)->left.p2.y && \ (t)->right.p1.y != (t)->right.p2.y && \ - (int) ((t)->bottom - (t)->top) > 0) + ((t)->bottom > (t)->top)) struct pixman_span_fix { @@ -1045,12 +1331,19 @@ struct pixman_trap pixman_span_fix_t top, bot; }; +PIXMAN_API pixman_fixed_t pixman_sample_ceil_y (pixman_fixed_t y, int bpp); + +PIXMAN_API pixman_fixed_t pixman_sample_floor_y (pixman_fixed_t y, int bpp); + +PIXMAN_API void pixman_edge_step (pixman_edge_t *e, int n); + +PIXMAN_API void pixman_edge_init (pixman_edge_t *e, int bpp, pixman_fixed_t y_start, @@ -1058,31 +1351,43 @@ void pixman_edge_init (pixman_edge_t *e, pixman_fixed_t y_top, pixman_fixed_t x_bot, pixman_fixed_t y_bot); + +PIXMAN_API void pixman_line_fixed_edge_init (pixman_edge_t *e, int bpp, pixman_fixed_t y, const pixman_line_fixed_t *line, int x_off, int y_off); + +PIXMAN_API void pixman_rasterize_edges (pixman_image_t *image, pixman_edge_t *l, pixman_edge_t *r, pixman_fixed_t t, pixman_fixed_t b); + +PIXMAN_API void pixman_add_traps (pixman_image_t *image, int16_t x_off, int16_t y_off, int ntrap, const pixman_trap_t *traps); + +PIXMAN_API void pixman_add_trapezoids (pixman_image_t *image, int16_t x_off, int y_off, int ntraps, const pixman_trapezoid_t *traps); + +PIXMAN_API void pixman_rasterize_trapezoid (pixman_image_t *image, const pixman_trapezoid_t *trap, int x_off, int y_off); + +PIXMAN_API void pixman_composite_trapezoids (pixman_op_t op, pixman_image_t * src, pixman_image_t * dst, @@ -1093,6 +1398,8 @@ void pixman_composite_trapezoids (pixman_op_t op, int y_dst, int n_traps, const pixman_trapezoid_t * traps); + +PIXMAN_API void pixman_composite_triangles (pixman_op_t op, pixman_image_t * src, pixman_image_t * dst, @@ -1103,6 +1410,8 @@ void pixman_composite_triangles (pixman_op_t op, int y_dst, int n_tris, const pixman_triangle_t * tris); + +PIXMAN_API void pixman_add_triangles (pixman_image_t *image, int32_t x_off, int32_t y_off, diff --git a/gfx/cairo/libpixman/src/refactor b/gfx/cairo/libpixman/src/refactor deleted file mode 100644 index 52fceab175..0000000000 --- a/gfx/cairo/libpixman/src/refactor +++ /dev/null @@ -1,478 +0,0 @@ -Roadmap - -- Move all the fetchers etc. into pixman-image to make pixman-compose.c - less intimidating. - - DONE - -- Make combiners for unified alpha take a mask argument. That way - we won't need two separate paths for unified vs component in the - general compositing code. - - DONE, except that the Altivec code needs to be updated. Luca is - looking into that. - -- Delete separate 'unified alpha' path - - DONE - -- Split images into their own files - - DONE - -- Split the gradient walker code out into its own file - - DONE - -- Add scanline getters per image - - DONE - -- Generic 64 bit fetcher - - DONE - -- Split fast path tables into their respective architecture dependent - files. - -See "Render Algorithm" below for rationale - -Images will eventually have these virtual functions: - - get_scanline() - get_scanline_wide() - get_pixel() - get_pixel_wide() - get_untransformed_pixel() - get_untransformed_pixel_wide() - get_unfiltered_pixel() - get_unfiltered_pixel_wide() - - store_scanline() - store_scanline_wide() - -1. - -Initially we will just have get_scanline() and get_scanline_wide(); -these will be based on the ones in pixman-compose. Hopefully this will -reduce the complexity in pixman_composite_rect_general(). - -Note that there is access considerations - the compose function is -being compiled twice. - - -2. - -Split image types into their own source files. Export noop virtual -reinit() call. Call this whenever a property of the image changes. - - -3. - -Split the get_scanline() call into smaller functions that are -initialized by the reinit() call. - -The Render Algorithm: - (first repeat, then filter, then transform, then clip) - -Starting from a destination pixel (x, y), do - - 1 x = x - xDst + xSrc - y = y - yDst + ySrc - - 2 reject pixel that is outside the clip - - This treats clipping as something that happens after - transformation, which I think is correct for client clips. For - hierarchy clips it is wrong, but who really cares? Without - GraphicsExposes hierarchy clips are basically irrelevant. Yes, - you could imagine cases where the pixels of a subwindow of a - redirected, transformed window should be treated as - transparent. I don't really care - - Basically, I think the render spec should say that pixels that - are unavailable due to the hierarcy have undefined content, - and that GraphicsExposes are not generated. Ie., basically - that using non-redirected windows as sources is fail. This is - at least consistent with the current implementation and we can - update the spec later if someone makes it work. - - The implication for render is that it should stop passing the - hierarchy clip to pixman. In pixman, if a souce image has a - clip it should be used in computing the composite region and - nowhere else, regardless of what "has_client_clip" says. The - default should be for there to not be any clip. - - I would really like to get rid of the client clip as well for - source images, but unfortunately there is at least one - application in the wild that uses them. - - 3 Transform pixel: (x, y) = T(x, y) - - 4 Call p = GetUntransformedPixel (x, y) - - 5 If the image has an alpha map, then - - Call GetUntransformedPixel (x, y) on the alpha map - - add resulting alpha channel to p - - return p - - Where GetUnTransformedPixel is: - - 6 switch (filter) - { - case NEAREST: - return GetUnfilteredPixel (x, y); - break; - - case BILINEAR: - return GetUnfilteredPixel (...) // 4 times - break; - - case CONVOLUTION: - return GetUnfilteredPixel (...) // as many times as necessary. - break; - } - - Where GetUnfilteredPixel (x, y) is - - 7 switch (repeat) - { - case REPEAT_NORMAL: - case REPEAT_PAD: - case REPEAT_REFLECT: - // adjust x, y as appropriate - break; - - case REPEAT_NONE: - if (x, y) is outside image bounds - return 0; - break; - } - - return GetRawPixel(x, y) - - Where GetRawPixel (x, y) is - - 8 Compute the pixel in question, depending on image type. - -For gradients, repeat has a totally different meaning, so -UnfilteredPixel() and RawPixel() must be the same function so that -gradients can do their own repeat algorithm. - -So, the GetRawPixel - - for bits must deal with repeats - for gradients must deal with repeats (differently) - for solids, should ignore repeats. - - for polygons, when we add them, either ignore repeats or do - something similar to bits (in which case, we may want an extra - layer of indirection to modify the coordinates). - -It is then possible to build things like "get scanline" or "get tile" on -top of this. In the simplest case, just repeatedly calling GetPixel() -would work, but specialized get_scanline()s or get_tile()s could be -plugged in for common cases. - -By not plugging anything in for images with access functions, we only -have to compile the pixel functions twice, not the scanline functions. - -And we can get rid of fetchers for the bizarre formats that no one -uses. Such as b2g3r3 etc. r1g2b1? Seriously? It is also worth -considering a generic format based pixel fetcher for these edge cases. - -Since the actual routines depend on the image attributes, the images -must be notified when those change and update their function pointers -appropriately. So there should probably be a virtual function called -(* reinit) or something like that. - -There will also be wide fetchers for both pixels and lines. The line -fetcher will just call the wide pixel fetcher. The wide pixel fetcher -will just call expand, except for 10 bit formats. - -Rendering pipeline: - -Drawable: - 0. if (picture has alpha map) - 0.1. Position alpha map according to the alpha_x/alpha_y - 0.2. Where the two drawables intersect, the alpha channel - Replace the alpha channel of source with the one - from the alpha map. Replacement only takes place - in the intersection of the two drawables' geometries. - 1. Repeat the drawable according to the repeat attribute - 2. Reconstruct a continuous image according to the filter - 3. Transform according to the transform attribute - 4. Position image such that src_x, src_y is over dst_x, dst_y - 5. Sample once per destination pixel - 6. Clip. If a pixel is not within the source clip, then no - compositing takes place at that pixel. (Ie., it's *not* - treated as 0). - - Sampling a drawable: - - - If the channel does not have an alpha channel, the pixels in it - are treated as opaque. - - Note on reconstruction: - - - The top left pixel has coordinates (0.5, 0.5) and pixels are - spaced 1 apart. - -Gradient: - 1. Unless gradient type is conical, repeat the underlying (0, 1) - gradient according to the repeat attribute - 2. Integrate the gradient across the plane according to type. - 3. Transform according to transform attribute - 4. Position gradient - 5. Sample once per destination pixel. - 6. Clip - -Solid Fill: - 1. Repeat has no effect - 2. Image is already continuous and defined for the entire plane - 3. Transform has no effect - 4. Positioning has no effect - 5. Sample once per destination pixel. - 6. Clip - -Polygon: - 1. Repeat has no effect - 2. Image is already continuous and defined on the whole plane - 3. Transform according to transform attribute - 4. Position image - 5. Supersample 15x17 per destination pixel. - 6. Clip - -Possibly interesting additions: - - More general transformations, such as warping, or general - shading. - - - Shader image where a function is called to generate the - pixel (ie., uploading assembly code). - - - Resampling kernels - - In principle the polygon image uses a 15x17 box filter for - resampling. If we allow general resampling filters, then we - get all the various antialiasing types for free. - - Bilinear downsampling looks terrible and could be much - improved by a resampling filter. NEAREST reconstruction - combined with a box resampling filter is what GdkPixbuf - does, I believe. - - Useful for high frequency gradients as well. - - (Note that the difference between a reconstruction and a - resampling filter is mainly where in the pipeline they - occur. High quality resampling should use a correctly - oriented kernel so it should happen after transformation. - - An implementation can transform the resampling kernel and - convolve it with the reconstruction if it so desires, but it - will need to deal with the fact that the resampling kernel - will not necessarily be pixel aligned. - - "Output kernels" - - One could imagine doing the resampling after compositing, - ie., for each destination pixel sample each source image 16 - times, then composite those subpixels individually, then - finally apply a kernel. - - However, this is effectively the same as full screen - antialiasing, which is a simpler way to think about it. So - resampling kernels may make sense for individual images, but - not as a post-compositing step. - - Fullscreen AA is inefficient without chained compositing - though. Consider an (image scaled up to oversample size IN - some polygon) scaled down to screen size. With the current - implementation, there will be a huge temporary. With chained - compositing, the whole thing ends up being equivalent to the - output kernel from above. - - - Color space conversion - - The complete model here is that each surface has a color - space associated with it and that the compositing operation - also has one associated with it. Note also that gradients - should have associcated colorspaces. - - - Dithering - - If people dither something that is already dithered, it will - look terrible, but don't do that, then. (Dithering happens - after resampling if at all - what is the relationship - with color spaces? Presumably dithering should happen in linear - intensity space). - - - Floating point surfaces, 16, 32 and possibly 64 bit per - channel. - - Maybe crack: - - - Glyph polygons - - If glyphs could be given as polygons, they could be - positioned and rasterized more accurately. The glyph - structure would need subpixel positioning though. - - - Luminance vs. coverage for the alpha channel - - Whether the alpha channel should be interpreted as luminance - modulation or as coverage (intensity modulation). This is a - bit of a departure from the rendering model though. It could - also be considered whether it should be possible to have - both channels in the same drawable. - - - Alternative for component alpha - - - Set component-alpha on the output image. - - - This means each of the components are sampled - independently and composited in the corresponding - channel only. - - - Have 3 x oversampled mask - - - Scale it down by 3 horizontally, with [ 1/3, 1/3, 1/3 ] - resampling filter. - - Is this equivalent to just using a component alpha mask? - - Incompatible changes: - - - Gradients could be specified with premultiplied colors. (You - can use a mask to get things like gradients from solid red to - transparent red. - -Refactoring pixman - -The pixman code is not particularly nice to put it mildly. Among the -issues are - -- inconsistent naming style (fb vs Fb, camelCase vs - underscore_naming). Sometimes there is even inconsistency *within* - one name. - - fetchProc32 ACCESS(pixman_fetchProcForPicture32) - - may be one of the uglies names ever created. - - coding style: - use the one from cairo except that pixman uses this brace style: - - while (blah) - { - } - - Format do while like this: - - do - { - - } - while (...); - -- PIXMAN_COMPOSITE_RECT_GENERAL() is horribly complex - -- switch case logic in pixman-access.c - - Instead it would be better to just store function pointers in the - image objects themselves, - - get_pixel() - get_scanline() - -- Much of the scanline fetching code is for formats that no one - ever uses. a2r2g2b2 anyone? - - It would probably be worthwhile having a generic fetcher for any - pixman format whatsoever. - -- Code related to particular image types should be split into individual - files. - - pixman-bits-image.c - pixman-linear-gradient-image.c - pixman-radial-gradient-image.c - pixman-solid-image.c - -- Fast path code should be split into files based on architecture: - - pixman-mmx-fastpath.c - pixman-sse2-fastpath.c - pixman-c-fastpath.c - - etc. - - Each of these files should then export a fastpath table, which would - be declared in pixman-private.h. This should allow us to get rid - of the pixman-mmx.h files. - - The fast path table should describe each fast path. Ie there should - be bitfields indicating what things the fast path can handle, rather than - like now where it is only allowed to take one format per src/mask/dest. Ie., - - { - FAST_a8r8g8b8 | FAST_x8r8g8b8, - FAST_null, - FAST_x8r8g8b8, - FAST_repeat_normal | FAST_repeat_none, - the_fast_path - } - -There should then be *one* file that implements pixman_image_composite(). -This should do this: - - optimize_operator(); - - convert 1x1 repeat to solid (actually this should be done at - image creation time). - - is there a useful fastpath? - -There should be a file called pixman-cpu.c that contains all the -architecture specific stuff to detect what CPU features we have. - -Issues that must be kept in mind: - - - we need accessor code to be preserved - - - maybe there should be a "store_scanline" too? - - Is this sufficient? - - We should preserve the optimization where the - compositing happens directly in the destination - whenever possible. - - - It should be possible to create GPU samplers from the - images. - -The "horizontal" classification should be a bit in the image, the -"vertical" classification should just happen inside the gradient -file. Note though that - - (a) these will change if the tranformation/repeat changes. - - (b) at the moment the optimization for linear gradients - takes the source rectangle into account. Presumably - this is to also optimize the case where the gradient - is close enough to horizontal? - -Who is responsible for repeats? In principle it should be the scanline -fetch. Right now NORMAL repeats are handled by walk_composite_region() -while other repeats are handled by the scanline code. - - -(Random note on filtering: do you filter before or after -transformation? Hardware is going to filter after transformation; -this is also what pixman does currently). It's not completely clear -what filtering *after* transformation means. One thing that might look -good would be to do *supersampling*, ie., compute multiple subpixels -per destination pixel, then average them together. diff --git a/gfx/cairo/libpixman/src/solaris-hwcap.mapfile b/gfx/cairo/libpixman/src/solaris-hwcap.mapfile new file mode 100644 index 0000000000..87efce1e34 --- /dev/null +++ b/gfx/cairo/libpixman/src/solaris-hwcap.mapfile @@ -0,0 +1,30 @@ +############################################################################### +# +# Copyright 2009, Oracle and/or its affiliates. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +############################################################################### +# +# Override the linker's detection of CMOV/MMX/SSE instructions so this +# library isn't flagged as only usable on CPU's with those ISA's, since it +# checks at runtime for availability before calling them + +hwcap_1 = V0x0 FPU OVERRIDE; From 517a6b90a3dcb7b60f63144063ebc90a74b75dc9 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sat, 20 Nov 2021 16:58:45 +0000 Subject: [PATCH 04/40] Issue #3039 - Extend cairo API with an explicit font_get_hint_metrics function. This extension allows us to get font hint metrics without having to create and destroy cairo font options structs. Since this is used in loops, this will improve performance, especially in documents which have many text segments. --- gfx/cairo/cairo/src/cairo-rename.h | 1 + gfx/cairo/cairo/src/cairo-scaled-font.c | 20 ++++++++++++++++++++ gfx/cairo/cairo/src/cairo.h | 3 +++ gfx/cairo/cairo/src/cairoint.h | 1 + gfx/thebes/gfxFont.cpp | 5 +---- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/gfx/cairo/cairo/src/cairo-rename.h b/gfx/cairo/cairo/src/cairo-rename.h index db20352ea6..0228596c3d 100644 --- a/gfx/cairo/cairo/src/cairo-rename.h +++ b/gfx/cairo/cairo/src/cairo-rename.h @@ -267,6 +267,7 @@ #define cairo_scaled_font_get_font_face _moz_cairo_scaled_font_get_font_face #define cairo_scaled_font_get_font_matrix _moz_cairo_scaled_font_get_font_matrix #define cairo_scaled_font_get_font_options _moz_cairo_scaled_font_get_font_options +#define cairo_scaled_font_get_hint_metrics _moz_cairo_scaled_font_get_hint_metrics #define cairo_scaled_font_get_reference_count _moz_cairo_scaled_font_get_reference_count #define cairo_scaled_font_get_scale_matrix _moz_cairo_scaled_font_get_scale_matrix #define cairo_scaled_font_get_type _moz_cairo_scaled_font_get_type diff --git a/gfx/cairo/cairo/src/cairo-scaled-font.c b/gfx/cairo/cairo/src/cairo-scaled-font.c index 37806bc63c..1bffdce203 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font.c +++ b/gfx/cairo/cairo/src/cairo-scaled-font.c @@ -2952,3 +2952,23 @@ cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font, _cairo_font_options_init_copy (options, &scaled_font->options); } slim_hidden_def (cairo_scaled_font_get_font_options); + +/** + * cairo_scaled_font_get_hint_metrics: + * @scaled_font: a #cairo_scaled_font_t + * + * Mozilla extension since the required malloc/free to use + * cairo_scaled_font_get_font_options() above is too slow. + **/ +cairo_public cairo_hint_metrics_t +cairo_scaled_font_get_hint_metrics (cairo_scaled_font_t *scaled_font) +{ + cairo_font_options_t options; + if (scaled_font->status) { + _cairo_font_options_init_default (&options); + } else { + _cairo_font_options_init_copy (&options, &scaled_font->options); + } + return options.hint_metrics; +} +slim_hidden_def (cairo_scaled_font_get_hint_metrics); \ No newline at end of file diff --git a/gfx/cairo/cairo/src/cairo.h b/gfx/cairo/cairo/src/cairo.h index 3a34e80bfe..f566687f98 100644 --- a/gfx/cairo/cairo/src/cairo.h +++ b/gfx/cairo/cairo/src/cairo.h @@ -1465,6 +1465,9 @@ cairo_public void cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font, cairo_font_options_t *options); +// API extension for GRE. +cairo_public cairo_hint_metrics_t +cairo_scaled_font_get_hint_metrics (cairo_scaled_font_t *scaled_font); /* Toy fonts */ diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h index 2f638f2d7f..f5dc0da817 100644 --- a/gfx/cairo/cairo/src/cairoint.h +++ b/gfx/cairo/cairo/src/cairoint.h @@ -2434,6 +2434,7 @@ slim_hidden_proto (cairo_scaled_font_get_ctm); slim_hidden_proto (cairo_scaled_font_get_font_face); slim_hidden_proto (cairo_scaled_font_get_font_matrix); slim_hidden_proto (cairo_scaled_font_get_font_options); +slim_hidden_proto (cairo_scaled_font_get_hint_metrics); // GRE API extension slim_hidden_proto (cairo_scaled_font_glyph_extents); slim_hidden_proto_no_warn (cairo_scaled_font_reference); slim_hidden_proto (cairo_scaled_font_status); diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index a732527598..dba322521f 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -591,11 +591,8 @@ gfxFontShaper::GetRoundOffsetsToPixels(DrawTarget* aDrawTarget, } // Sometimes hint metrics gets set for us, most notably for printing. - cairo_font_options_t *font_options = cairo_font_options_create(); - cairo_scaled_font_get_font_options(scaled_font, font_options); cairo_hint_metrics_t hint_metrics = - cairo_font_options_get_hint_metrics(font_options); - cairo_font_options_destroy(font_options); + cairo_scaled_font_get_hint_metrics(scaled_font); switch (hint_metrics) { case CAIRO_HINT_METRICS_OFF: From 42fc0af325226af38f62fa9b973027529e74c576 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sat, 20 Nov 2021 21:50:59 +0000 Subject: [PATCH 05/40] Issue #3039 - Add closure point to bounds calculation. This addition of a closure point (explicitly completing the closed shape) isn't strictly needed in our current cairo version as it works perfectly fine without, but if our clipping extents code changes then this might cause problems if the extra point isn't added (in case of 0-length paths). --- gfx/cairo/cairo/src/cairo-path-bounds.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gfx/cairo/cairo/src/cairo-path-bounds.c b/gfx/cairo/cairo/src/cairo-path-bounds.c index c752fbca1d..701539e3a3 100644 --- a/gfx/cairo/cairo/src/cairo-path-bounds.c +++ b/gfx/cairo/cairo/src/cairo-path-bounds.c @@ -107,6 +107,16 @@ _cairo_path_bounder_curve_to (void *closure, static cairo_status_t _cairo_path_bounder_close_path (void *closure) { + // XXXMC: This addition of a closure point isn't strictly needed but + // if our clipping extents code changes then this might cause problems + // if the extra point isn't added (in case of 0-length paths). + cairo_path_bounder_t *bounder = closure; + + if (bounder->has_initial_point) { + _cairo_path_bounder_add_point (bounder, &bounder->current_point); + bounder->has_initial_point = FALSE; + } + return CAIRO_STATUS_SUCCESS; } From 35164e28604b853ec7e1802fe160ef297aff38ff Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sat, 20 Nov 2021 22:10:34 +0000 Subject: [PATCH 06/40] Issue #3039 - Increase the MAX_FONT_SIZE limit applied in cairo_ft_font to match the gfxFont size limit. Also adds synching comments just to be sure. --- gfx/cairo/cairo/src/cairo-ft-font.c | 7 +++++-- gfx/thebes/gfxFont.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/gfx/cairo/cairo/src/cairo-ft-font.c b/gfx/cairo/cairo/src/cairo-ft-font.c index 1a2799b86c..a2259c173a 100644 --- a/gfx/cairo/cairo/src/cairo-ft-font.c +++ b/gfx/cairo/cairo/src/cairo-ft-font.c @@ -64,9 +64,12 @@ static setLcdFilterFunc setLcdFilter; /* This is the max number of FT_face objects we keep open at once */ #define MAX_OPEN_FACES 10 -/* This is the maximum font size we allow to be passed to FT_Set_Char_Size + +/* This is the (arbitrary) maximum font size we allow to be passed to + FT_Set_Char_Size. + Note: This should be equal to FONT_MAX_SIZE in thebes/gfxFont.h */ -#define MAX_FONT_SIZE 1000 +#define MAX_FONT_SIZE 2000 /** * SECTION:cairo-ft diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 07c00f04c5..ab1677b9c5 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -47,6 +47,7 @@ class gfxShapedWord; class gfxSkipChars; class gfxMathTable; +// If you change this value, also change MAX_FONT_SIZE in cairo-ft-font.c to match #define FONT_MAX_SIZE 2000.0 #define NO_FONT_LANGUAGE_OVERRIDE 0 From dda2b7972afeafcf106a4de3c9ff8c15f6c05229 Mon Sep 17 00:00:00 2001 From: David Major Date: Sat, 20 Nov 2021 22:23:40 +0000 Subject: [PATCH 07/40] Issue #3039 - Reapply bug 624198 fix that got lost in an upstream update. --- gfx/cairo/cairo/src/cairo-win32-surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c index 0fecc3ad89..23761cae89 100644 --- a/gfx/cairo/cairo/src/cairo-win32-surface.c +++ b/gfx/cairo/cairo/src/cairo-win32-surface.c @@ -93,7 +93,7 @@ _cairo_win32_print_gdi_error (const char *context) 0, NULL)) { fprintf (stderr, "%s: Unknown GDI error", context); } else { - fwprintf (stderr, L"%s: %S", context, (wchar_t *)lpMsgBuf); + fprintf (stderr, L"%s: %S", context, (wchar_t *)lpMsgBuf); LocalFree (lpMsgBuf); } From 3bb1c962ebd6e6edc0af80706922e984983733b9 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sat, 20 Nov 2021 23:05:25 +0000 Subject: [PATCH 08/40] Issue #3039 - Don't try to pass a dash array of > 16 elements to ExtCreatePen. According to MSDN documentation, the count of the style array passed to ExtCreatePen is limited to 16. When we call ExtCreatePen with cStyle=17 or more, it simply returns an error and the cairo surface used for printing is getting into an error state, after which nothing further gets printed. Instead of erroring out, this code change returns an unsupported status so that cairo will provide fallback handling for it. --- gfx/cairo/cairo/src/cairo-win32-printing-surface.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c index 23db876940..89b6e1b810 100644 --- a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c +++ b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c @@ -1265,6 +1265,9 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface, } if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + /* Win32 does not support more than 16 elements in the dash array. */ + if (style->num_dashes > 16) + return CAIRO_INT_STATUS_UNSUPPORTED; /* Win32 does not support a dash offset. */ if (style->num_dashes > 0 && style->dash_offset != 0.0) return CAIRO_INT_STATUS_UNSUPPORTED; From 4cc56c2cb63675ecacbbde9d99f6f1024132b754 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Sun, 5 Dec 2021 20:16:02 -0500 Subject: [PATCH 09/40] Issue #3024 - First pass support for :host and :host-context --- dom/base/ShadowRoot.h | 1 + dom/xbl/nsBindingManager.cpp | 64 +++++++- dom/xbl/nsBindingManager.h | 6 +- dom/xbl/nsXBLBinding.h | 5 + layout/style/StyleRule.cpp | 23 ++- layout/style/StyleRule.h | 7 +- layout/style/nsCSSParser.cpp | 5 +- layout/style/nsCSSPseudoClassList.h | 6 + layout/style/nsCSSPseudoClasses.h | 7 +- layout/style/nsCSSRuleProcessor.cpp | 230 ++++++++++++++++++++++++++-- layout/style/nsRuleProcessorData.h | 35 +++++ layout/style/nsStyleSet.cpp | 3 +- 12 files changed, 358 insertions(+), 34 deletions(-) diff --git a/dom/base/ShadowRoot.h b/dom/base/ShadowRoot.h index 775eaae957..63535c9a06 100644 --- a/dom/base/ShadowRoot.h +++ b/dom/base/ShadowRoot.h @@ -108,6 +108,7 @@ public: void SetInsertionPointChanged() { mInsertionPointChanged = true; } + nsXBLBinding* GetAssociatedBinding() { return mAssociatedBinding; } void SetAssociatedBinding(nsXBLBinding* aBinding) { mAssociatedBinding = aBinding; } JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; diff --git a/dom/xbl/nsBindingManager.cpp b/dom/xbl/nsBindingManager.cpp index a2c18bcb99..8f18f112af 100644 --- a/dom/xbl/nsBindingManager.cpp +++ b/dom/xbl/nsBindingManager.cpp @@ -30,6 +30,7 @@ #include "nsXBLPrototypeBinding.h" #include "nsXBLDocumentInfo.h" #include "mozilla/dom/XBLChildrenElement.h" +#include "mozilla/dom/ShadowRoot.h" #include "nsIStyleRuleProcessor.h" #include "nsRuleProcessorData.h" @@ -663,13 +664,32 @@ nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, NS_ASSERTION(aData->mElement, "How did that happen?"); + // Walk the rules in shadow root for :host pseudo-class rules. + aData->mTreeMatchContext.mOnlyMatchHostPseudo = true; + aData->mElementIsFeatureless = true; + + ShadowRoot* currentShadow = aData->mElement->GetShadowRoot(); + + if (currentShadow) { + nsXBLBinding* associatedBinding = currentShadow->GetAssociatedBinding(); + if (associatedBinding) { + aData->mTreeMatchContext.mScopedRoot = aData->mElement; + associatedBinding->WalkRules(aFunc, aData); + } + } + + aData->mElementIsFeatureless = false; + aData->mTreeMatchContext.mOnlyMatchHostPseudo = false; + // Walk the binding scope chain, starting with the binding attached to our // content, up till we run out of scopes or we get cut off. nsIContent *content = aData->mElement; do { nsXBLBinding *binding = content->GetXBLBinding(); - if (binding) { + if (binding && + // Unlike XBL, styles in the shadow root are not applied to the host. + !(content == aData->mElement && binding->IsShadowRootBinding())) { aData->mTreeMatchContext.mScopedRoot = content; binding->WalkRules(aFunc, aData); // If we're not looking at our original content, allow the binding to cut @@ -702,14 +722,26 @@ nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, typedef nsTHashtable > RuleProcessorSet; static RuleProcessorSet* -GetContentSetRuleProcessors(nsTHashtable>* aContentSet) +GetContentSetRuleProcessors(nsTHashtable>* aContentSet, bool aOnlyWalkShadowRootRules) { RuleProcessorSet* set = nullptr; for (auto iter = aContentSet->Iter(); !iter.Done(); iter.Next()) { nsIContent* boundContent = iter.Get()->GetKey(); - for (nsXBLBinding* binding = boundContent->GetXBLBinding(); binding; - binding = binding->GetBaseBinding()) { + + // If we are only walking rules for shadow root hosts, skip other types + // of bound content. + ShadowRoot *shadowRoot = boundContent->GetShadowRoot(); + if (aOnlyWalkShadowRootRules && !shadowRoot) { + return set; + } + + // Bound content may have multiple rule processors, potentially one + // for its immediate binding, and one more for each binding in the + // inheritance chain. Additionally, a bound content may host multiple + // shadow roots, each with its own rule processor. + for (nsXBLBinding *binding = boundContent->GetXBLBinding(); binding; + binding = binding->GetBaseBinding()) { nsIStyleRuleProcessor* ruleProc = binding->PrototypeBinding()->GetRuleProcessor(); if (ruleProc) { @@ -718,22 +750,27 @@ GetContentSetRuleProcessors(nsTHashtable>* aContentS } set->PutEntry(ruleProc); } + + if (shadowRoot) { + binding = shadowRoot->GetAssociatedBinding(); + } + } } - } return set; } void nsBindingManager::WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc, - ElementDependentRuleProcessorData* aData) + ElementDependentRuleProcessorData* aData, + bool aOnlyWalkShadowRootRules) { if (!mBoundContentSet) { return; } nsAutoPtr set; - set = GetContentSetRuleProcessors(mBoundContentSet); + set = GetContentSetRuleProcessors(mBoundContentSet, aOnlyWalkShadowRootRules); if (!set) { return; } @@ -744,6 +781,17 @@ nsBindingManager::WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc, } } +// The approach in WalkAllShadowRootHostRules seems reasonable on the surface and reminds me of what is done with mScopedRoot elsewhere. But something important is missing, either here or in the code that would normally use it. + +void +nsBindingManager::WalkAllShadowRootHostRules(nsIStyleRuleProcessor::EnumFunc aFunc, + ElementDependentRuleProcessorData* aData) + { + aData->mTreeMatchContext.mOnlyMatchHostPseudo = true; + WalkAllRules(aFunc, aData, true); + aData->mTreeMatchContext.mOnlyMatchHostPseudo = false; + } + nsresult nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext, bool* aRulesChanged) @@ -754,7 +802,7 @@ nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext, } nsAutoPtr set; - set = GetContentSetRuleProcessors(mBoundContentSet); + set = GetContentSetRuleProcessors(mBoundContentSet, false); if (!set) { return NS_OK; } diff --git a/dom/xbl/nsBindingManager.h b/dom/xbl/nsBindingManager.h index cb15aa57f6..35d31b387a 100644 --- a/dom/xbl/nsBindingManager.h +++ b/dom/xbl/nsBindingManager.h @@ -128,7 +128,11 @@ public: bool* aCutOffInheritance); void WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc, - ElementDependentRuleProcessorData* aData); + ElementDependentRuleProcessorData* aData, + bool aOnlyWalkShadowRootRules = false); + + void WalkAllShadowRootHostRules(nsIStyleRuleProcessor::EnumFunc aFunc, + ElementDependentRuleProcessorData* aData); /** * Do any processing that needs to happen as a result of a change in * the characteristics of the medium, and return whether this rule diff --git a/dom/xbl/nsXBLBinding.h b/dom/xbl/nsXBLBinding.h index 5eb743398a..a61866aed4 100644 --- a/dom/xbl/nsXBLBinding.h +++ b/dom/xbl/nsXBLBinding.h @@ -138,6 +138,11 @@ public: mozilla::dom::XBLChildrenElement* FindInsertionPointFor(nsIContent* aChild); + bool IsShadowRootBinding() + { + return mIsShadowRootBinding; + } + bool HasFilteredInsertionPoints() { return !mInsertionPoints.IsEmpty(); diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp index 8fde725349..bf5eefa156 100644 --- a/layout/style/StyleRule.cpp +++ b/layout/style/StyleRule.cpp @@ -148,7 +148,8 @@ nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType, : mType(aType), mNext(nullptr) { - NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(aType), + NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(aType) || + nsCSSPseudoClasses::HasOptionalSelectorListArg(aType), "unexpected pseudo-class"); NS_ASSERTION(aSelectorList, "selector list expected"); MOZ_COUNT_CTOR(nsPseudoClassList); @@ -313,6 +314,7 @@ nsCSSSelector::nsCSSSelector(void) mPseudoClassList(nullptr), mAttrList(nullptr), mNegations(nullptr), + mExplicitUniversal(false), mNext(nullptr), mNameSpace(kNameSpaceID_Unknown), mOperator(0), @@ -382,6 +384,17 @@ void nsCSSSelector::Reset(void) mOperator = char16_t(0); } +bool nsCSSSelector::HasFeatureSelectors() +{ + return mExplicitUniversal || mLowercaseTag || mCasedTag || + mIDList || mClassList || mAttrList; +} + +void nsCSSSelector::SetHasExplicitUniversal() +{ + mExplicitUniversal = true; +} + void nsCSSSelector::SetNameSpace(int32_t aNameSpace) { mNameSpace = aNameSpace; @@ -750,9 +763,9 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations // Universal selector: avoid writing the universal selector when we // can avoid it, especially since we're required to avoid it for the // inside of :not() - if (wroteNamespace || + if (wroteNamespace || mExplicitUniversal || (!mIDList && !mClassList && !mPseudoClassList && !mAttrList && - (aIsNegated || !mNegations))) { + aIsNegated)) { aString.Append(char16_t('*')); } } else { @@ -760,9 +773,7 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations nsAutoString tag; (isPseudoElement ? mLowercaseTag : mCasedTag)->ToString(tag); if (isPseudoElement) { - if (!mNext) { - // Lone pseudo-element selector -- toss in a wildcard type selector - // XXXldb Why? + if (mExplicitUniversal) { aString.Append(char16_t('*')); } // While our atoms use one colon, most pseudo-elements require two diff --git a/layout/style/StyleRule.h b/layout/style/StyleRule.h index 907e55448a..dbf4e08406 100644 --- a/layout/style/StyleRule.h +++ b/layout/style/StyleRule.h @@ -151,6 +151,8 @@ public: nsCSSSelector* Clone() const { return Clone(true, true); } void Reset(void); + bool HasFeatureSelectors(); + void SetHasExplicitUniversal(); void SetNameSpace(int32_t aNameSpace); void SetTag(const nsString& aTag); void AddID(const nsString& aID); @@ -231,9 +233,10 @@ public: // the argument to functional pseudos nsAttrSelector* mAttrList; nsCSSSelector* mNegations; - nsCSSSelector* mNext; + bool mExplicitUniversal; // True if universal selector explicitly + nsCSSSelector* mNext; // appears in the selector int32_t mNameSpace; - char16_t mOperator; + char mOperator; private: // The underlying type of CSSPseudoElementType is uint8_t and // it packs well with mOperator. (char16_t + uint8_t is less than 32bits.) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 4be2372347..d55080dbb9 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -5641,6 +5641,7 @@ CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask, aSelector.SetTag(mToken.mIdent); } else if (mToken.IsSymbol('*')) { // universal selector + aSelector.SetHasExplicitUniversal(); aDataMask |= SEL_MASK_ELEM; // don't set tag } @@ -5652,6 +5653,7 @@ CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask, } else { // was universal element selector SetDefaultNamespaceOnSelector(aSelector); + aSelector.SetHasExplicitUniversal(); aDataMask |= SEL_MASK_ELEM; // don't set any tag in the selector } @@ -6097,7 +6099,8 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, CSSPseudoClassType::negation == pseudoClassType || nsCSSPseudoClasses::HasStringArg(pseudoClassType) || nsCSSPseudoClasses::HasNthPairArg(pseudoClassType) || - nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType))) { + nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType)) && + !nsCSSPseudoClasses::HasOptionalSelectorListArg(pseudoClassType)) { // There are no other function pseudos REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc); UngetToken(); diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index 7f620ec32f..c57c28bc0b 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -133,6 +133,12 @@ CSS_PSEUDO_CLASS(scope, ":scope", 0, "layout.css.scope-pseudo.enabled") // it doesn't actually get directly matched on in SelectorMatches. CSS_PSEUDO_CLASS(negation, ":not", 0, "") +// http://drafts.csswg.org/css-scoping/#selectordef-host-context +CSS_PSEUDO_CLASS(hostContext, ":host-context", 0, "dom.webcomponents.enabled") + +// http://drafts.csswg.org/css-scoping/#selectordef-host-context +CSS_PSEUDO_CLASS(host, ":host", 0, "dom.webcomponents.enabled") + // :dir(ltr) and :dir(rtl) match elements whose resolved // directionality in the markup language is ltr or rtl respectively. CSS_STATE_DEPENDENT_PSEUDO_CLASS(dir, ":dir", 0, "", diff --git a/layout/style/nsCSSPseudoClasses.h b/layout/style/nsCSSPseudoClasses.h index 55e5bf9d2e..05f67b05cd 100644 --- a/layout/style/nsCSSPseudoClasses.h +++ b/layout/style/nsCSSPseudoClasses.h @@ -59,7 +59,12 @@ public: static bool HasStringArg(Type aType); static bool HasNthPairArg(Type aType); static bool HasSelectorListArg(Type aType) { - return aType == Type::any; + return aType == Type::any || + aType == Type::host || + aType == Type::hostContext; + } + static bool HasOptionalSelectorListArg(Type aType) { + return aType == Type::host; } static bool IsUserActionPseudoClass(Type aType); diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index 810a8f8f00..dbd0e099b0 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -48,6 +48,7 @@ #include "nsCSSRules.h" #include "nsStyleSet.h" #include "mozilla/dom/Element.h" +#include "mozilla/dom/ShadowRoot.h" #include "nsNthIndexCache.h" #include "mozilla/ArrayUtils.h" #include "mozilla/EventStates.h" @@ -1342,9 +1343,17 @@ struct NodeMatchContext { // mForStyling is false, we have to assume we don't know.) const bool mIsRelevantLink; - NodeMatchContext(EventStates aStateMask, bool aIsRelevantLink) + // If the node should be considered featureless (as specified in + // selectors 4), then mIsFeature should be set to true to prevent + // matching unless the selector is a special pseudo class or pseudo + // element that matches featureless elements. + const bool mIsFeatureless; + + NodeMatchContext(EventStates aStateMask, bool aIsRelevantLink, + bool aIsFeatureless = false) : mStateMask(aStateMask) , mIsRelevantLink(aIsRelevantLink) + , mIsFeatureless(aIsFeatureless) { } }; @@ -1631,6 +1640,11 @@ StateSelectorMatches(Element* aElement, return true; } +static bool AnySelectorInArgListMatches(Element* aElement, + nsPseudoClassList* aList, + NodeMatchContext& aNodeMatchContext, + TreeMatchContext& aTreeMatchContext); + static bool StateSelectorMatches(Element* aElement, nsCSSSelector* aSelector, @@ -1652,6 +1666,26 @@ StateSelectorMatches(Element* aElement, return true; } +// Returns whether aSelector can match featureless elements. +static bool CanMatchFeaturelessElement(nsCSSSelector* aSelector) +{ + if (aSelector->HasFeatureSelectors()) { + return false; + } + + for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList; + pseudoClass; + pseudoClass = pseudoClass->mNext) { + if (pseudoClass->mType == CSSPseudoClassType::host || + pseudoClass->mType == CSSPseudoClassType::hostContext) { + return true; + } + } + + return false; +} + + // |aDependence| has two functions: // * when non-null, it indicates that we're processing a negation, // which is done only when SelectorMatches calls itself recursively @@ -1672,6 +1706,11 @@ static bool SelectorMatches(Element* aElement, "is false since we don't know how to set it correctly in " "Has(Attribute|State)DependentStyle"); + if (aNodeMatchContext.mIsFeatureless && + !CanMatchFeaturelessElement(aSelector)) { + return false; + } + // namespace/tag match // optimization : bail out early if we can if ((kNameSpaceID_Unknown != aSelector->mNameSpace && @@ -1870,18 +1909,89 @@ static bool SelectorMatches(Element* aElement, case CSSPseudoClassType::any: { - nsCSSSelectorList *l; - for (l = pseudoClass->u.mSelectors; l; l = l->mNext) { - nsCSSSelector *s = l->mSelectors; - MOZ_ASSERT(!s->mNext && !s->IsPseudoElement(), - "parser failed"); - if (SelectorMatches( - aElement, s, aNodeMatchContext, aTreeMatchContext, - SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) { + if (!AnySelectorInArgListMatches(aElement, pseudoClass, + aNodeMatchContext, + aTreeMatchContext)) { + return false; + } + } + break; + + case CSSPseudoClassType::host: + { + // In order to match :host, the element must be a shadow root host, + // we must be matching only against host pseudo selectors, and the + // selector's context must be the shadow root (the selector must be + // featureless, the left-most selector, and be in a shadow root + // style). The :host selector may also be be functional, with a + // compound selector. If this is the case, then also ensure that the + // host element matches against the compound + // selector. + + // We match automatically if GetParent() and GetShadowRoot() have + // the same result. Without special casing this ahead of all other + // selector matching, it fails. Have not determined the cause. + + if (aElement->GetParent() == aElement->GetShadowRoot()) { + break; + } + + // Match if any selector in the argument list matches. + + NodeMatchContext nodeContext(EventStates(), + nsCSSRuleProcessor::IsLink(aElement)); + if (AnySelectorInArgListMatches(aElement, pseudoClass, + nodeContext, + aTreeMatchContext)) { + break; + } + + // Finally, with the exception of the two above cases, make sure we + // don't match if GetContainingShadow() returns null. For whatever + // reason, we can't test for this case first. + + if (aElement->GetContainingShadow() == nullptr) { + return false; + } + + } + break; + + + case CSSPseudoClassType::hostContext: + { + // In order to match host-context, the element must be a + // shadow root host and the selector's context must be the + // shadow root (aTreeMatchContext.mScopedRoot is set to the + // host of the shadow root where the style is contained, + // thus the element must be mScopedRoot). If the UNKNOWN + // selector flag is set, relax the shadow root host + // requirement because this pseudo class walks through + // ancestors looking for a match, thus the selector can be + // dependant on aElement even though it is not the host. The + // dependency would otherwise be missed because when UNKNOWN + // is set, selector matching may not have started from the top. + if (!((aElement->GetShadowRoot() && + aElement == aTreeMatchContext.mScopedRoot) || + aSelectorFlags & SelectorMatchesFlags::UNKNOWN)) { + return false; + } + + Element* currentElement = aElement; + while (currentElement) { + NodeMatchContext nodeContext(EventStates(), + nsCSSRuleProcessor::IsLink(currentElement)); + if (AnySelectorInArgListMatches(currentElement, pseudoClass, + nodeContext, + aTreeMatchContext)) { break; } + + nsIContent* flattenedParent = currentElement->GetFlattenedTreeParent(); + currentElement = flattenedParent && flattenedParent->IsElement() ? + flattenedParent->AsElement() : nullptr; } - if (!l) { + if (!currentElement) { return false; } } @@ -2263,6 +2373,26 @@ static bool SelectorMatches(Element* aElement, return result; } +static bool AnySelectorInArgListMatches(Element* aElement, + nsPseudoClassList* aList, + NodeMatchContext& aNodeMatchContext, + TreeMatchContext& aTreeMatchContext) +{ + nsCSSSelectorList *l; + for (l = aList->u.mSelectors; l; l = l->mNext) { + nsCSSSelector *s = l->mSelectors; + MOZ_ASSERT(!s->mNext && !s->IsPseudoElement(), + "parser failed"); + if (SelectorMatches( + aElement, s, aNodeMatchContext, aTreeMatchContext, + SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) { + break; + } + } + + return !!l; +} + #undef STATE_CHECK #ifdef DEBUG @@ -2352,7 +2482,9 @@ SelectorMatchesTree(Element* aPrevElement, MOZ_ASSERT(!aSelector || !aSelector->IsPseudoElement()); nsCSSSelector* selector = aSelector; Element* prevElement = aPrevElement; + bool crossedShadowRootBoundary = false; while (selector) { // check compound selectors + bool contentIsFeatureless = false; NS_ASSERTION(!selector->mNext || selector->mNext->mOperator != char16_t(0), "compound selector without combinator"); @@ -2383,6 +2515,20 @@ SelectorMatchesTree(Element* aPrevElement, // to test against is the parent else { nsIContent *content = prevElement->GetParent(); + + // In the shadow tree, the shadow host behaves as if it + // is a featureless parent of top-level elements of the shadow + // tree. Only cross shadow root boundary when the selector is the + // left most selector because ancestors of the host are not in + // the selector match list. + ShadowRoot* shadowRoot = content ? + ShadowRoot::FromNode(content) : nullptr; + if (shadowRoot && !selector->mNext && !crossedShadowRootBoundary) { + content = shadowRoot->GetHost(); + crossedShadowRootBoundary = true; + contentIsFeatureless = true; + } + // GetParent could return a document fragment; we only want // element parents. if (content && content->IsElement()) { @@ -2434,7 +2580,8 @@ SelectorMatchesTree(Element* aPrevElement, } const bool isRelevantLink = (aFlags & eLookForRelevantLink) && nsCSSRuleProcessor::IsLink(element); - NodeMatchContext nodeContext(EventStates(), isRelevantLink); + + NodeMatchContext nodeContext(EventStates(), isRelevantLink, contentIsFeatureless); if (isRelevantLink) { // If we find an ancestor of the matched node that is a link // during the matching process, then it's the relevant link (see @@ -2504,6 +2651,29 @@ void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector, // We won't match; nothing else to do here return; } + // If mOnlyMatchHostPseudo is set, then we only want to match against + // selectors that contain a :host-context pseudo class. + if (data->mTreeMatchContext.mOnlyMatchHostPseudo) { + nsCSSSelector* selector = aSelector; + while (selector && selector->mNext != nullptr) { + selector = selector->mNext; + } + + bool seenHostPseudo = false; + for (nsPseudoClassList* pseudoClass = selector->mPseudoClassList; + pseudoClass; + pseudoClass = pseudoClass->mNext) { + if (pseudoClass->mType == CSSPseudoClassType::host || + pseudoClass->mType == CSSPseudoClassType::hostContext) { + seenHostPseudo = true; + break; + } + } + + if (!seenHostPseudo) { + return; + } + } if (!data->mTreeMatchContext.SetStyleScopeForSelectorMatching(data->mElement, data->mScope)) { // The selector is for a rule in a scoped style sheet, and the subject @@ -2563,7 +2733,8 @@ nsCSSRuleProcessor::RulesMatching(ElementRuleProcessorData *aData) if (cascade) { NodeMatchContext nodeContext(EventStates(), - nsCSSRuleProcessor::IsLink(aData->mElement)); + nsCSSRuleProcessor::IsLink(aData->mElement), + aData->mElementIsFeatureless); cascade->mRuleHash.EnumerateAllRules(aData->mElement, aData, nodeContext); } } @@ -2847,6 +3018,34 @@ AttributeEnumFunc(nsCSSSelector* aSelector, nsRestyleHint possibleChange = RestyleHintForSelectorWithAttributeChange(aData->change, aSelector, aRightmostSelector); + // If mOnlyMatchHostPseudo is set, then we only want to match against + // selectors that contain a :host-context pseudo class. + if (data->mTreeMatchContext.mOnlyMatchHostPseudo) { + nsCSSSelector* selector = aSelector; + while (selector && selector->mNext != nullptr) { + selector = selector->mNext; + } + + bool seenHostPseudo = false; + for (nsPseudoClassList* pseudoClass = selector->mPseudoClassList; + pseudoClass; + pseudoClass = pseudoClass->mNext) { + if (pseudoClass->mType == CSSPseudoClassType::host || + pseudoClass->mType == CSSPseudoClassType::hostContext) { + // :host-context will walk ancestors looking for a match of a compound + // selector, thus any changes to ancestors may require restyling the + // subtree. + possibleChange |= eRestyle_Subtree; + seenHostPseudo = true; + break; + } + } + + if (!seenHostPseudo) { + return; + } + } + // If, ignoring eRestyle_SomeDescendants, enumData->change already includes // all the bits of possibleChange, don't bother calling SelectorMatches, since @@ -3318,10 +3517,12 @@ AddSelector(RuleCascadeData* aCascade, } } - // Recur through any :-moz-any selectors + // Recur through any :-moz-any or :host-context selectors for (nsPseudoClassList* pseudoClass = negation->mPseudoClassList; pseudoClass; pseudoClass = pseudoClass->mNext) { - if (pseudoClass->mType == CSSPseudoClassType::any) { + if (pseudoClass->mType == CSSPseudoClassType::any || + pseudoClass->mType == CSSPseudoClassType::host || + pseudoClass->mType == CSSPseudoClassType::hostContext) { for (nsCSSSelectorList *l = pseudoClass->u.mSelectors; l; l = l->mNext) { nsCSSSelector *s = l->mSelectors; if (!AddSelector(aCascade, aSelectorInTopLevel, s, @@ -3970,6 +4171,7 @@ TreeMatchContext::InitAncestors(Element *aElement) for (uint32_t i = ancestors.Length(); i-- != 0; ) { mAncestorFilter.PushAncestor(ancestors[i]); PushStyleScope(ancestors[i]); + PushShadowHost(ancestors[i]); } } } diff --git a/layout/style/nsRuleProcessorData.h b/layout/style/nsRuleProcessorData.h index 6f8cba8959..769c53f573 100644 --- a/layout/style/nsRuleProcessorData.h +++ b/layout/style/nsRuleProcessorData.h @@ -164,6 +164,23 @@ struct MOZ_STACK_CLASS TreeMatchContext { mStyleScopes.TruncateLength(mStyleScopes.Length() - 1); } } + + void PushShadowHost(mozilla::dom::Element* aElement) + { + NS_PRECONDITION(aElement, "aElement must not be null"); + if (aElement->GetShadowRoot()) { + mShadowHosts.AppendElement(aElement); + } + } + + void PopShadowHost(mozilla::dom::Element* aElement) + { + NS_PRECONDITION(aElement, "aElement must not be null"); + if (mShadowHosts.SafeLastElement(nullptr) == aElement) { + mShadowHosts.TruncateLength(mShadowHosts.Length() - 1); + } + } + bool PopStyleScopeForSelectorMatching(mozilla::dom::Element* aElement) { @@ -233,6 +250,7 @@ struct MOZ_STACK_CLASS TreeMatchContext { MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mPushedAncestor(false) , mPushedStyleScope(false) + , mPushedShadowHost(false) , mTreeMatchContext(aTreeMatchContext) , mElement(nullptr) { @@ -245,8 +263,10 @@ struct MOZ_STACK_CLASS TreeMatchContext { mElement = aElement; mPushedAncestor = true; mPushedStyleScope = true; + mPushedShadowHost = true; mTreeMatchContext.mAncestorFilter.PushAncestor(aElement); mTreeMatchContext.PushStyleScope(aElement); + mTreeMatchContext.PushShadowHost(aElement); } } @@ -278,11 +298,15 @@ struct MOZ_STACK_CLASS TreeMatchContext { if (mPushedStyleScope) { mTreeMatchContext.PopStyleScope(mElement); } + if (mPushedShadowHost) { + mTreeMatchContext.PopShadowHost(mElement); + } } private: bool mPushedAncestor; bool mPushedStyleScope; + bool mPushedShadowHost; TreeMatchContext& mTreeMatchContext; mozilla::dom::Element* mElement; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER @@ -342,6 +366,11 @@ struct MOZ_STACK_CLASS TreeMatchContext { // The document we're working with. nsIDocument* const mDocument; + // Only selectors that contain :host or :host-context pseudo class + // should be matched against elements. All other selectors should not + // match. + bool mOnlyMatchHostPseudo; + // Root of scoped stylesheet (set and unset by the supplier of the // scoped stylesheet). nsIContent* mScopedRoot; @@ -383,6 +412,9 @@ struct MOZ_STACK_CLASS TreeMatchContext { //