|
1 /* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
2 * |
|
3 * Permission is hereby granted, free of charge, to any person obtaining a |
|
4 * copy of this software and /or associated documentation files |
|
5 * (the "Materials "), to deal in the Materials without restriction, |
|
6 * including without limitation the rights to use, copy, modify, merge, |
|
7 * publish, distribute, sublicense, and/or sell copies of the Materials, |
|
8 * and to permit persons to whom the Materials are furnished to do so, |
|
9 * subject to the following conditions: |
|
10 * |
|
11 * The above copyright notice and this permission notice shall be included |
|
12 * in all copies or substantial portions of the Materials. |
|
13 * |
|
14 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR |
|
20 * THE USE OR OTHER DEALINGS IN THE MATERIALS. |
|
21 */ |
|
22 |
|
23 #include "sfDynamicBlitter.h" |
|
24 |
|
25 #ifndef __SFBLITTER_H |
|
26 # include "sfBlitter.h" |
|
27 #endif |
|
28 |
|
29 #ifndef __SFMASK_H |
|
30 # include "sfMask.h" |
|
31 #endif |
|
32 |
|
33 namespace OpenVGRI { |
|
34 |
|
35 RI_INLINE static bool maskOperationRequiresLoad(VGMaskOperation op) |
|
36 { |
|
37 switch(op) |
|
38 { |
|
39 case VG_CLEAR_MASK: |
|
40 case VG_FILL_MASK: |
|
41 case VG_SET_MASK: |
|
42 return false; |
|
43 default: |
|
44 RI_ASSERT(op == VG_UNION_MASK || op == VG_INTERSECT_MASK || op == VG_SUBTRACT_MASK); |
|
45 return true; |
|
46 } |
|
47 } |
|
48 |
|
49 /** |
|
50 * \brief Blit rectangular areas between similar or different color format buffers. |
|
51 * \note Implementation is structured so that the per-pixel branches are minimized |
|
52 * even if dynamic compilation is not in use. |
|
53 * \todo For some reason the completely generic integer conversion does not optimize |
|
54 * fully run-time. Check what causes this! |
|
55 */ |
|
56 void executeBlitter(const DynamicBlitter::BlitSignatureState& state, const DynamicBlitter::BlitUniforms& uniforms) |
|
57 { |
|
58 const void* srcPtr = Image::calculateAddress( |
|
59 uniforms.src, state.srcDesc.bitsPerPixel, uniforms.srcX, uniforms.srcY, uniforms.srcStride); |
|
60 void* dstPtr = Image::calculateAddress( |
|
61 uniforms.dst, state.dstDesc.bitsPerPixel, uniforms.dstX, uniforms.dstY, uniforms.dstStride); |
|
62 |
|
63 // The following flag is useful for debugging. Enabling it will hurt performance. |
|
64 //#define ALWAYS_FORCE_FULL_CONVERSION |
|
65 |
|
66 // Currently the data must be byte-aligned for memcpy optimizations: |
|
67 const int minBpp = RI_INT_MIN(state.srcDesc.bitsPerPixel, state.dstDesc.bitsPerPixel); |
|
68 const bool byteCopy = minBpp >= 8 ? true : false; |
|
69 const bool forceFullConversion = state.isMaskOperation || state.unsafeInput || !byteCopy; |
|
70 |
|
71 #if !defined(ALWAYS_FORCE_FULL_CONVERSION) |
|
72 if (state.srcDesc.isZeroConversion(state.dstDesc) && !forceFullConversion) |
|
73 { |
|
74 const int fullCopyStride = Image::descriptorToStride(state.srcDesc, uniforms.width); |
|
75 |
|
76 if ((uniforms.dstStride != uniforms.srcStride) || (fullCopyStride != uniforms.srcStride)) |
|
77 { |
|
78 // memcpy individual scanlines. |
|
79 const size_t scanLength = (size_t)RI_INT_ABS(Image::descriptorToStride(state.srcDesc, uniforms.width)); |
|
80 for (RIuint32 i = 0; i < uniforms.height; i++) |
|
81 { |
|
82 memcpy(dstPtr, srcPtr, scanLength); |
|
83 dstPtr = (void*)((RIuint8*)dstPtr + uniforms.dstStride); |
|
84 srcPtr = (void*)((RIuint8*)srcPtr + uniforms.srcStride); |
|
85 } |
|
86 } else |
|
87 { |
|
88 // memcpy the whole area |
|
89 memcpy(dstPtr, srcPtr, uniforms.srcStride * uniforms.height); |
|
90 } |
|
91 } else if (state.srcDesc.isShiftConversion(state.dstDesc) && !forceFullConversion) |
|
92 { |
|
93 // \todo Separate to function? Replace with pointer read/write & advance. |
|
94 if (state.srcDesc.isShiftConversionToLower(state.dstDesc)) |
|
95 { |
|
96 // Components can be immediately shifted down to lower bit-depth. |
|
97 for (RIuint32 j = 0; j < uniforms.height; j++) |
|
98 { |
|
99 RIuint8* srcStart = (RIuint8*)srcPtr; |
|
100 RIuint8* dstStart = (RIuint8*)dstPtr; |
|
101 RIuint32 srcX = uniforms.srcX; |
|
102 RIuint32 dstX = uniforms.dstX; |
|
103 for (RIuint32 i = 0; i < uniforms.width; i++) |
|
104 { |
|
105 RIuint32 c = Image::readPackedPixelFromAddress(srcPtr, state.srcDesc.bitsPerPixel, srcX); // \todo srcX! |
|
106 RIuint32 dc = Color::Descriptor::crossConvertToLower(c, state.srcDesc, state.dstDesc); |
|
107 Image::writePackedPixelToAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX, dc); |
|
108 |
|
109 srcPtr = Image::incrementPointer(srcPtr, state.srcDesc.bitsPerPixel, srcX); |
|
110 dstPtr = (void*)Image::incrementPointer(dstPtr, state.dstDesc.bitsPerPixel, dstX); |
|
111 |
|
112 srcX++; |
|
113 dstX++; |
|
114 } |
|
115 srcPtr = (void*)(srcStart + uniforms.srcStride); |
|
116 dstPtr = (void*)(dstStart + uniforms.dstStride); |
|
117 } |
|
118 } |
|
119 else |
|
120 { |
|
121 // Color components require expansion before shifting to destination color-format */ |
|
122 for (RIuint32 j = 0; j < uniforms.height; j++) |
|
123 { |
|
124 RIuint8* srcStart = (RIuint8*)srcPtr; |
|
125 RIuint8* dstStart = (RIuint8*)dstPtr; |
|
126 RIuint32 srcX = uniforms.srcX; |
|
127 RIuint32 dstX = uniforms.dstX; |
|
128 for (RIuint32 i = 0; i < uniforms.width; i++) |
|
129 { |
|
130 RIuint32 c = Image::readPackedPixelFromAddress(srcPtr, state.srcDesc.bitsPerPixel, srcX); |
|
131 IntegerColor ic = IntegerColor(c, state.srcDesc); |
|
132 ic.expandColor(state.srcDesc); |
|
133 ic.truncateColor(state.dstDesc); |
|
134 RIuint32 dc = ic.getPackedColor(state.dstDesc); |
|
135 Image::writePackedPixelToAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX, dc); |
|
136 |
|
137 srcPtr = Image::incrementPointer(srcPtr, state.srcDesc.bitsPerPixel, srcX); |
|
138 dstPtr = (void*)Image::incrementPointer(dstPtr, state.dstDesc.bitsPerPixel, dstX); |
|
139 |
|
140 srcX++; |
|
141 dstX++; |
|
142 } |
|
143 srcPtr = (void*)(srcStart + uniforms.srcStride); |
|
144 dstPtr = (void*)(dstStart + uniforms.dstStride); |
|
145 } |
|
146 } |
|
147 } else |
|
148 #endif |
|
149 { |
|
150 /* This block should handle the rest (and all) of the color-conversion cases. */ |
|
151 for (RIuint32 j = 0; j < uniforms.height; j++) |
|
152 { |
|
153 RIuint8* srcStart = (RIuint8*)srcPtr; |
|
154 RIuint8* dstStart = (RIuint8*)dstPtr; |
|
155 RIuint32 srcX = uniforms.srcX; |
|
156 RIuint32 dstX = uniforms.dstX; |
|
157 for (RIuint32 i = 0; i < uniforms.width; i++) |
|
158 { |
|
159 RIuint32 c = Image::readPackedPixelFromAddress(srcPtr, state.srcDesc.bitsPerPixel, srcX); |
|
160 IntegerColor ic; |
|
161 RIuint32 dc; |
|
162 |
|
163 if (!state.isMaskOperation) |
|
164 { |
|
165 ic = IntegerColor(c, state.srcDesc); |
|
166 if (state.unsafeInput) |
|
167 ic.clampToAlpha(); |
|
168 |
|
169 ic.convertToFrom(state.dstDesc, state.srcDesc, false); |
|
170 dc = ic.getPackedColor(state.dstDesc); |
|
171 } |
|
172 else |
|
173 { |
|
174 // Apply the given mask operation between two surfaces. |
|
175 IntegerColor id; |
|
176 |
|
177 if (maskOperationRequiresLoad(state.maskOperation)) |
|
178 { |
|
179 ic.fromPackedMask(c, state.srcDesc); |
|
180 ic.expandMask(state.srcDesc); |
|
181 |
|
182 IntegerColor id; |
|
183 |
|
184 RIuint32 d = Image::readPackedPixelFromAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX); |
|
185 id.fromPackedMask(d, state.dstDesc); |
|
186 id.expandColor(state.dstDesc); |
|
187 |
|
188 RIuint32 coverage = ic.a + (ic.a >> 7); |
|
189 ic = intMaskOperation(coverage, id, state.maskOperation); |
|
190 } |
|
191 else |
|
192 { |
|
193 // Other ops handled with memset, not blitter |
|
194 RI_ASSERT(state.maskOperation == VG_SET_MASK); |
|
195 ic.fromPackedMask(c, state.srcDesc); |
|
196 //ic.expandMask(state.srcDesc); |
|
197 ic.convertToFrom(state.dstDesc, state.srcDesc, true); |
|
198 } |
|
199 dc = ic.getPackedMaskColor(state.dstDesc); |
|
200 } |
|
201 |
|
202 Image::writePackedPixelToAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX, dc); |
|
203 |
|
204 srcPtr = Image::incrementPointer(srcPtr, state.srcDesc.bitsPerPixel, srcX); |
|
205 dstPtr = (void*)Image::incrementPointer(dstPtr, state.dstDesc.bitsPerPixel, dstX); |
|
206 |
|
207 srcX++; |
|
208 dstX++; |
|
209 } |
|
210 srcPtr = (void*)(srcStart + uniforms.srcStride); |
|
211 dstPtr = (void*)(dstStart + uniforms.dstStride); |
|
212 } |
|
213 } |
|
214 } |
|
215 |
|
216 } |
|
217 |