~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/painting/qdrawhelper_x86.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if defined(Q_CC_GNU) && defined(__i386__)
 
2
enum CPUFeatures {
 
3
    None = 0,
 
4
    MMX = 0x1,
 
5
    SSE = 0x2,
 
6
    SSE2 = 0x4,
 
7
    CMOV = 0x8
 
8
};
 
9
static uint detectCPUFeatures() {
 
10
    uint result;
 
11
    /* see p. 118 of amd64 instruction set manual Vol3 */
 
12
    asm ("push %%ebx\n"
 
13
         "pushf\n"
 
14
         "pop %%eax\n"
 
15
         "mov %%eax, %%ebx\n"
 
16
         "xor $0x00200000, %%eax\n"
 
17
         "push %%eax\n"
 
18
         "popf\n"
 
19
         "pushf\n"
 
20
         "pop %%eax\n"
 
21
         "mov $0x0, %%edx\n"
 
22
         "xor %%ebx, %%eax\n"
 
23
         "jz 1f\n"
 
24
 
 
25
         "mov $0x00000001, %%eax\n"
 
26
         "cpuid\n"
 
27
         "1:\n"
 
28
         "pop %%ebx\n"
 
29
         "mov %%edx, %0\n"
 
30
        : "=r" (result)
 
31
        :
 
32
        : "%eax", "%ecx", "%edx"
 
33
        );
 
34
 
 
35
    uint features = 0;
 
36
    // result now contains the standard feature bits
 
37
    if (result & (1 << 15))
 
38
        features |= CMOV;
 
39
    if (result & (1 << 23))
 
40
        features |= MMX;
 
41
    if (result & (1 << 25))
 
42
        features |= SSE;
 
43
    if (result & (1 << 26))
 
44
        features |= SSE2;
 
45
    return features;
 
46
}
 
47
 
 
48
 
 
49
static void sse_memfill(uint *target, uint value, int len)
 
50
{
 
51
    uint *end = target + len;
 
52
    if (len >= 7) {
 
53
        {
 
54
            int align = (((ulong)target) & 0xf) >> 2;
 
55
            switch(align) {
 
56
            case 1:
 
57
                *target++ = value;
 
58
            case 2:
 
59
                *target++ = value;
 
60
            case 3:
 
61
                *target++ = value;
 
62
            default:
 
63
                break;
 
64
            }
 
65
        }
 
66
        asm("movd %1, %%xmm1\n"
 
67
            "pshufd $0x0, %%xmm1, %%xmm0\n"
 
68
            "mov %2, %%eax\n"
 
69
            "mov %3, %%edx\n"
 
70
            "1: movdqa %%xmm0, (%%eax)\n"
 
71
            "add $0x10, %%eax\n"
 
72
            "cmp %%eax, %%edx\n"
 
73
            "jb 1b\n"
 
74
            "mov %%eax, %0\n"
 
75
            : "=r" (target)
 
76
            : "m" (value),
 
77
              "r" (target),
 
78
              "m" (end)
 
79
            : "%eax", "%edx", "%xmm0", "%xmm1"
 
80
            );
 
81
    }
 
82
    while (target < end) {
 
83
        *target = value;
 
84
        ++target;
 
85
    }
 
86
}
 
87
 
 
88
#define qt_alpha_pixel(s, t, a, ra) { int tmp = s*a + t*ra; t = qt_div_255(tmp); }
 
89
#define qt_alpha_pixel_pm(s, t, ra) { int tmp = s + t*ra; t = qt_div_255(tmp); }
 
90
 
 
91
static void blend_color_sse(ARGB *target, const QSpan *span, ARGB color)
 
92
{
 
93
    if (!span->len)
 
94
        return;
 
95
 
 
96
    int alpha = qt_div_255(color.a * span->coverage);
 
97
    int pr = alpha * color.r;
 
98
    int pg = alpha * color.g;
 
99
    int pb = alpha * color.b;
 
100
 
 
101
    int rev_alpha = 255 - alpha;
 
102
 
 
103
    const ushort pm[4]
 
104
        = { (ushort)pb, (ushort)pg, (ushort)pr, 0 };
 
105
    const ushort mask[4]
 
106
        = { 0, 0, 0, 0xffff };
 
107
    if (span->len > 1 ) {
 
108
        /*
 
109
          registers:
 
110
          xmm0: premultiplied src
 
111
          xmm1: rev_alpha
 
112
          xmm2: *target
 
113
          xmm7: 0
 
114
          xmm6: alpha mask
 
115
        */
 
116
        asm("pxor %%xmm7, %%xmm7\n" // clear xmm7
 
117
            "movlps %2, %%xmm0\n" // src to xmm0
 
118
            "movlhps %%xmm0, %%xmm0\n"
 
119
            "movlps %5, %%xmm6\n" // src to xmm0
 
120
            "movlhps %%xmm6, %%xmm6\n"
 
121
            "movd %3, %%xmm1\n"  // rev_alpha to xmm1
 
122
            // #### should work without the line below
 
123
            "punpcklbw %%xmm7, %%xmm1\n"
 
124
            "pshuflw $0, %%xmm1, %%xmm1\n"
 
125
            "movlhps %%xmm1, %%xmm1\n" // spread rev_alpha over all channels
 
126
            "1:\n"
 
127
            "prefetchnta 128(%1)\n"
 
128
            "movlps (%1), %%xmm2\n" // target to xmm2
 
129
            "punpcklbw %%xmm7, %%xmm2\n" //  to xmm1
 
130
            "pmullw %%xmm1, %%xmm2\n" // target * ralpha
 
131
            "paddw %%xmm0, %%xmm2\n" // sum to xmm1
 
132
            "por %%xmm6, %%xmm2\n" // make sure alpha is set to 0xff
 
133
            "psrlw $8, %%xmm2\n" // shift right
 
134
            "packuswb %%xmm2, %%xmm2\n" // pack to 8 bits
 
135
            "movlps %%xmm2, (%1)\n"
 
136
            "add $8, %1\n"
 
137
            "dec %4\n"
 
138
            "jnz 1b\n"
 
139
            "mov %1, %0\n"
 
140
            : "=m" (target)
 
141
            : "r" (target),
 
142
              "m" (*pm),
 
143
              "r" (rev_alpha),
 
144
              "r" (span->len/2),
 
145
              "m" (*mask)
 
146
            : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7"
 
147
            );
 
148
    }
 
149
    if (span->len % 2) {
 
150
        qt_alpha_pixel_pm(pr, target->r, rev_alpha);
 
151
        qt_alpha_pixel_pm(pg, target->g, rev_alpha);
 
152
        qt_alpha_pixel_pm(pb, target->b, rev_alpha);
 
153
        target->a = 255;
 
154
    }
 
155
}
 
156
 
 
157
#define CMOV_PIX(pixel, out, mask, image_bits, offset) \
 
158
    asm ("mov %1, %%edx\n"                             \
 
159
         "and $"#mask",%%edx\n"                         \
 
160
         "cmovnz (%2,%3,0x4), %%edx\n"                  \
 
161
         "mov %%edx, %0\n"                             \
 
162
         : "=m" (pixel)                                \
 
163
         : "r" (out),                                  \
 
164
           "r" (image_bits),                           \
 
165
           "r" (offset)                                \
 
166
         : "%edx"                             \
 
167
        )
 
168
 
 
169
static void blend_transformed_bilinear_sse(ARGB *target, const QSpan *span,
 
170
                                           qreal ix, qreal iy, qreal dx, qreal dy,
 
171
                                           ARGB *image_bits, int image_width, int image_height)
 
172
{
 
173
    const int fixed_scale = 1 << 16;
 
174
    int x = int((ix + dx * span->x) * fixed_scale);
 
175
    int y = int((iy + dy * span->x) * fixed_scale);
 
176
 
 
177
    int fdx = (int)(dx * fixed_scale);
 
178
    int fdy = (int)(dy * fixed_scale);
 
179
 
 
180
    /*
 
181
      set up constant xmm registers:
 
182
      xmm7 : 0
 
183
      xmm6 : coverage
 
184
      xmm5 : alpha mask on xmm5
 
185
      xmm4 : 0x00ff...
 
186
    */
 
187
    {
 
188
        const ushort mask[4] = { 0, 0, 0, 0xffff };
 
189
        uint coverage = span->coverage;
 
190
        asm("pxor %%xmm7, %%xmm7\n" // clear xmm7
 
191
            "movd %0, %%xmm6\n"  // coverage to xmm6
 
192
            "punpcklbw %%xmm7, %%xmm6\n"
 
193
            "pshuflw $0, %%xmm6, %%xmm6\n" // spread over all channels
 
194
            "movlps %1, %%xmm5\n" // mask to xmm5
 
195
            "movlhps %%xmm5, %%xmm5\n"
 
196
            "movd %%xmm6, %0\n"
 
197
            "pcmpeqb %%xmm4, %%xmm4\n"
 
198
            "psrlw $8, %%xmm4\n" // 0x255 in xmm4
 
199
            :
 
200
            : "r" (coverage),
 
201
              "m" (*mask)
 
202
            : "%xmm5", "%xmm6", "%xmm7"
 
203
            );
 
204
    }
 
205
    for (int i = 0; i < span->len; ++i) {
 
206
        const int x1 = (x >> 16);
 
207
        const int y1 = (y >> 16);
 
208
 
 
209
        const int distx = ((x - (x1 << 16)) >> 8);
 
210
        const int disty = ((y - (y1 << 16)) >> 8);
 
211
        const int idistx = 256 - distx;
 
212
        const int idisty = 256 - disty;
 
213
 
 
214
        const long y1_offset = y1 * image_width;
 
215
        const long y2_offset = y1_offset + image_width;
 
216
 
 
217
        struct {
 
218
            uint tl;
 
219
            uint bl;
 
220
        } left;
 
221
        struct {
 
222
            uint tr;
 
223
            uint br;
 
224
        } right;
 
225
 
 
226
        {
 
227
            const int x2 = x1 + 1;
 
228
            const int y2 = y1 + 1;
 
229
            enum {
 
230
                X1Out = 0x1,
 
231
                X2Out = 0x2,
 
232
                Y1Out = 0x4,
 
233
                Y2Out = 0x8
 
234
            };
 
235
            register const uint out = (x1 >= 0 & x1 < image_width)
 
236
                                      | ((x2 >= 0 & x2 < image_width) << 1)
 
237
                                      | ((y1 >= 0 & y1 < image_height) << 2)
 
238
                                      | ((y2 >= 0 & y2 < image_height) << 3);
 
239
            CMOV_PIX(left.tl, out, 0x5, image_bits, y1_offset + x1); // X1Out|Y2Out
 
240
            CMOV_PIX(left.bl, out, 0x8, image_bits, y2_offset + x1); // X1Out|Y2Out
 
241
            CMOV_PIX(right.tr, out, 0x6, image_bits, y1_offset + x2); // X2Out|Y1Out
 
242
            CMOV_PIX(right.br, out, 0xa, image_bits, y2_offset + x2); // X2Out|Y2Out
 
243
        }
 
244
        /*
 
245
          tl, bl : xmm0
 
246
          tr: xmm1 low
 
247
          br : xmm1 high
 
248
          distx, idistx :  xmm2
 
249
          idistx, idisty: xmm3
 
250
          scratch: xmm6
 
251
          zero: xmm7
 
252
        */
 
253
 
 
254
        asm("movlps %0, %%xmm0\n" // left to xmm0
 
255
            "punpcklbw %%xmm7, %%xmm0\n"
 
256
 
 
257
            "movlps %1, %%xmm1\n"
 
258
            "punpcklbw %%xmm7, %%xmm1\n"
 
259
 
 
260
            "movd %2, %%xmm2\n"
 
261
            "pshuflw $0, %%xmm2, %%xmm2\n"
 
262
            "movlhps %%xmm2, %%xmm2\n" // spread distx
 
263
            "pmullw %%xmm2, %%xmm1\n"
 
264
 
 
265
            "movd %3, %%xmm2\n"
 
266
            "pshuflw $0, %%xmm2, %%xmm2\n"
 
267
            "movlhps %%xmm2, %%xmm2\n" // spread distx
 
268
            "pmullw %%xmm2, %%xmm0\n"
 
269
 
 
270
            "paddw %%xmm1, %%xmm0\n" // now contains xtop and xbottom
 
271
            "psrlw $8, %%xmm0\n"
 
272
 
 
273
            "movd %4, %%xmm2\n"
 
274
            "pshuflw $0, %%xmm2, %%xmm2\n"
 
275
            "movd %5, %%xmm3\n"
 
276
            "pshuflw $0, %%xmm3, %%xmm3\n"
 
277
            "movlhps %%xmm2, %%xmm3\n" // disty and idisty in mm2
 
278
 
 
279
            "pmullw %%xmm3, %%xmm0\n"
 
280
 
 
281
            "movhlps %%xmm0, %%xmm1\n"
 
282
            "paddw %%xmm1, %%xmm0\n"
 
283
            "psrlw $8, %%xmm0\n" // src is now in xmm0, ready for blend
 
284
 
 
285
            // blend operation follows
 
286
            /*
 
287
              src already in xmm0
 
288
              target in xmm1
 
289
              alpha of src in xmm2
 
290
              rev alpha in xmm5
 
291
            */
 
292
            "movd (%6), %%xmm1\n" // target to mm1
 
293
            "punpcklbw %%xmm7, %%xmm1\n"
 
294
            "pshuflw $255, %%xmm0, %%xmm2\n" // spread alpha over all channels
 
295
            "pmullw %%xmm6, %%xmm2\n" // alpha *= coverage
 
296
            "psrlw $8, %%xmm2\n" // shift right
 
297
            "pmullw %%xmm2, %%xmm0\n" // src *= alpha
 
298
            "movdqa %%xmm4, %%xmm3\n"
 
299
            "psubw %%xmm2, %%xmm3\n" // 0x255 - alpha in xmm3
 
300
            "pmullw %%xmm3, %%xmm1\n" // target *= ralpha
 
301
            "paddw %%xmm1, %%xmm0\n" // sum to xmm1
 
302
            "por %%xmm5, %%xmm0\n" // make sure alpha is set to 0xff
 
303
            "psrlw $8, %%xmm0\n" // shift right
 
304
            "packuswb %%xmm0, %%xmm0\n" // pack to 8 bits
 
305
            "movd %%xmm0, (%6)\n"
 
306
            :
 
307
            : "m" (left),
 
308
              "m" (right),
 
309
              "r" (distx),
 
310
              "r" (idistx),
 
311
              "r" (disty),
 
312
              "r" (idisty),
 
313
              "r" (target)
 
314
            : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7"
 
315
            );
 
316
//         qDebug("target = %x", *((uint *)target));
 
317
        x += fdx;
 
318
        y += fdy;
 
319
        ++target;
 
320
    }
 
321
}
 
322
 
 
323
#elif defined Q_CC_MSVC
 
324
 
 
325
 
 
326
#endif // Q_CC_GCC and Q_CC_MSVC
 
327
 
 
328
void qInitDrawhelperAsm()
 
329
{
 
330
    static uint features = 0;
 
331
    if (features)
 
332
        return;
 
333
 
 
334
#if defined (Q_CC_GNU) && defined (__i386__)
 
335
    features = detectCPUFeatures();
 
336
 
 
337
    if (features & SSE2) {
 
338
        dh[DrawHelper_RGB32]->blendColor = blend_color_sse;
 
339
        dh[DrawHelper_RGB32]->blendTransformedBilinear = blend_transformed_bilinear_sse;
 
340
    }
 
341
#else
 
342
    Q_UNUSED(dh)
 
343
#endif
 
344
}