|
1 /*------------------------------------------------------------------------ |
|
2 * |
|
3 * OpenVG 1.1 Reference Implementation |
|
4 * ----------------------------------- |
|
5 * |
|
6 * Copyright (c) 2007 The Khronos Group Inc. |
|
7 * Portions copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
8 * |
|
9 * Permission is hereby granted, free of charge, to any person obtaining a |
|
10 * copy of this software and /or associated documentation files |
|
11 * (the "Materials "), to deal in the Materials without restriction, |
|
12 * including without limitation the rights to use, copy, modify, merge, |
|
13 * publish, distribute, sublicense, and/or sell copies of the Materials, |
|
14 * and to permit persons to whom the Materials are furnished to do so, |
|
15 * subject to the following conditions: |
|
16 * |
|
17 * The above copyright notice and this permission notice shall be included |
|
18 * in all copies or substantial portions of the Materials. |
|
19 * |
|
20 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
24 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
25 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR |
|
26 * THE USE OR OTHER DEALINGS IN THE MATERIALS. |
|
27 * |
|
28 *//** |
|
29 * \file |
|
30 * \brief Implementation of polygon rasterizer. |
|
31 * \note |
|
32 *//*-------------------------------------------------------------------*/ |
|
33 |
|
34 #include "riRasterizer.h" |
|
35 |
|
36 // TEMP! |
|
37 #ifndef __SFCOMPILER_H |
|
38 # include "sfCompiler.h" |
|
39 #endif |
|
40 |
|
41 |
|
42 namespace OpenVGRI |
|
43 { |
|
44 |
|
45 /*-------------------------------------------------------------------*//*! |
|
46 * \brief Rasterizer constructor. |
|
47 * \param |
|
48 * \return |
|
49 * \note |
|
50 *//*-------------------------------------------------------------------*/ |
|
51 |
|
52 Rasterizer::Rasterizer() : |
|
53 m_covBuffer(NULL), |
|
54 m_covBufferSz(0), |
|
55 m_edges(), |
|
56 m_scissorEdges(), |
|
57 m_scissor(false), |
|
58 m_aa(true), |
|
59 m_vpx(0), |
|
60 m_vpy(0), |
|
61 m_vpwidth(0), |
|
62 m_vpheight(0), |
|
63 m_fillRule(VG_EVEN_ODD), |
|
64 m_pixelPipe(NULL), |
|
65 m_nSpans(0) |
|
66 {} |
|
67 |
|
68 /*-------------------------------------------------------------------*//*! |
|
69 * \brief Rasterizer destructor. |
|
70 * \param |
|
71 * \return |
|
72 * \note |
|
73 *//*-------------------------------------------------------------------*/ |
|
74 |
|
75 Rasterizer::~Rasterizer() |
|
76 { |
|
77 if(m_covBuffer) |
|
78 RI_DELETE_ARRAY(m_covBuffer); |
|
79 } |
|
80 |
|
81 /*-------------------------------------------------------------------*//*! |
|
82 * \brief Removes all appended edges. |
|
83 * \param |
|
84 * \return |
|
85 * \note |
|
86 *//*-------------------------------------------------------------------*/ |
|
87 |
|
88 #define EDGE_TERMINATOR 0xFFFFFFFFu |
|
89 |
|
90 void Rasterizer::clear() |
|
91 { |
|
92 //m_edges.clear(); |
|
93 for (int i = 0; i < m_edges.size(); i++) |
|
94 m_edges[i] = EDGE_TERMINATOR; |
|
95 |
|
96 m_edgePool.clear(); |
|
97 |
|
98 m_edgeMin.set(0x7fffffffu, 0x7fffffffu); |
|
99 m_edgeMax.set(0x80000000, 0x80000000); |
|
100 } |
|
101 |
|
102 /*-------------------------------------------------------------------*//*! |
|
103 * \brief Appends an edge to the rasterizer. |
|
104 * \param |
|
105 * \return |
|
106 * \note |
|
107 *//*-------------------------------------------------------------------*/ |
|
108 |
|
109 void Rasterizer::addBBox(const IVector2& v) |
|
110 { |
|
111 if(v.x < m_edgeMin.x) m_edgeMin.x = v.x; |
|
112 if(v.y < m_edgeMin.y) m_edgeMin.y = v.y; |
|
113 if(v.x > m_edgeMax.x) m_edgeMax.x = v.x; |
|
114 if(v.y > m_edgeMax.y) m_edgeMax.y = v.y; |
|
115 } |
|
116 |
|
117 void Rasterizer::pushEdge(const Edge& edge) |
|
118 { |
|
119 addBBox(edge.v0); |
|
120 addBBox(edge.v1); |
|
121 |
|
122 // Only add processed edges. |
|
123 |
|
124 RI_ASSERT(edge.v0.y >= 0); |
|
125 RI_ASSERT(edge.v0.y < edge.v1.y); //horizontal edges should have been dropped already |
|
126 |
|
127 ActiveEdge ae; |
|
128 ae.direction = edge.direction; |
|
129 |
|
130 // \todo Adjust for non-AA cases |
|
131 // \todo verySteep is temporary. Either clip to right edge also, or validate that a proper slope can be |
|
132 // calculated here. |
|
133 const int slope = RI_SAT_SHL((edge.v1.x - edge.v0.x), RASTERIZER_BITS - X_BITS) / (edge.v1.y - edge.v0.y); |
|
134 //const bool verySteep = RI_INT_ABS(edge.v1.x - edge.v0.x) > (1 << (30-RASTERIZER_BITS)) ? true : false; |
|
135 //const int slope = verySteep ? 1 << 30 : RI_SHL((edge.v1.x - edge.v0.x), RASTERIZER_BITS - X_BITS) / (edge.v1.y - edge.v0.y); |
|
136 // slope: SI.(RASTERIZER_BITS - Y_BITS) |
|
137 const int yF = edge.v0.y & Y_MASK; |
|
138 // \todo See verySteep note for this hack also. (Clip to right edge?) |
|
139 const int xRef = RI_SAT_SHL(edge.v0.x, RASTERIZER_BITS - X_BITS) - (yF * slope); |
|
140 //const int xRef = edge.v0.x > (1<<(30-RASTERIZER_BITS)) ? 1<<30 : RI_SHL(edge.v0.x, RASTERIZER_BITS - X_BITS) - (yF * slope); |
|
141 |
|
142 RI_ASSERT(RI_INT_ABS(edge.v0.y <= 32767)); |
|
143 RI_ASSERT(RI_INT_ABS(edge.v1.y <= 32767)); |
|
144 |
|
145 ae.yStart = (RIint16)edge.v0.y; |
|
146 ae.yEnd = (RIint16)edge.v1.y; |
|
147 ae.xRef = xRef; |
|
148 ae.slope = slope; |
|
149 // Scanline range. |
|
150 ae.minx = xRef >> RASTERIZER_BITS; |
|
151 ae.maxx = (xRef + slope * (1<<Y_BITS)) >> RASTERIZER_BITS; |
|
152 |
|
153 if (ae.minx > ae.maxx) |
|
154 RI_ANY_SWAP(ActiveEdge::XCoord, ae.minx, ae.maxx); |
|
155 |
|
156 if (ae.maxx < 0) |
|
157 ae.minx = ae.maxx = LEFT_DISCARD_SHORT; |
|
158 |
|
159 if (m_edges[ae.yStart>>Y_BITS] == EDGE_TERMINATOR) |
|
160 ae.next = EDGE_TERMINATOR; |
|
161 else |
|
162 ae.next = m_edges[ae.yStart>>Y_BITS]; |
|
163 |
|
164 m_edgePool.push_back(ae); //throws bad_alloc |
|
165 |
|
166 RI_ASSERT(m_edgePool.size() > 0); |
|
167 m_edges[ae.yStart>>Y_BITS] = m_edgePool.size()-1; |
|
168 } |
|
169 |
|
170 /** |
|
171 * \brief Clips an edge and if something remains, adds it to the list of edges. |
|
172 * \todo Enhance precision: Currently this just uses doubles and gets away with |
|
173 * it in most cases. |
|
174 */ |
|
175 void Rasterizer::clipAndAddEdge(Edge& edge) |
|
176 { |
|
177 //if (m_edges.size() > 48) |
|
178 //return; |
|
179 // Check y-clips |
|
180 // \todo Reduce amount of clips. |
|
181 bool outLeft[2] = {(edge.v0.x < m_vpMinx), (edge.v1.x < m_vpMinx)}; |
|
182 bool outRight[2] = {(edge.v0.x > m_vpMaxx), (edge.v1.x > m_vpMaxx)}; |
|
183 bool outTop[2] = {(edge.v0.y < m_vpMiny), (edge.v1.y < m_vpMiny)}; |
|
184 bool outBottom[2] = {(edge.v0.y > m_vpMaxy), (edge.v1.y > m_vpMaxy)}; |
|
185 |
|
186 if (!(outLeft[0] || outLeft[1] || outRight[0] || outRight[1] || outTop[0] || outTop[1] || outBottom[0] || outBottom[1])) |
|
187 { |
|
188 pushEdge(edge); |
|
189 return; |
|
190 } |
|
191 |
|
192 // \todo Make sure that checking out-of-right works with the scanconverter. |
|
193 if ((outBottom[0] && outBottom[1]) || (outTop[0] && outTop[1])) |
|
194 return; // Out of bounds |
|
195 |
|
196 // \todo Clip to right edge of screen. |
|
197 // \todo Make slope-calculation and signs consistent. |
|
198 // |
|
199 if (outTop[0] || outBottom[1]) |
|
200 { |
|
201 // Clip to top/bottom. |
|
202 double slope = (double)(edge.v1.x - edge.v0.x)/(edge.v1.y - edge.v0.y); |
|
203 |
|
204 if (outTop[0]) |
|
205 { |
|
206 RI_ASSERT(-(RIint64)edge.v0.y >= 0); |
|
207 RIint32 dx = RI_ROUND_TO_INT(-slope * edge.v0.y); |
|
208 edge.v0.y = 0; |
|
209 edge.v0.x += dx; |
|
210 } |
|
211 |
|
212 if (outBottom[1]) |
|
213 { |
|
214 RIint32 dy = edge.v1.y - m_vpMaxy; |
|
215 RI_ASSERT(dy >= 0); |
|
216 RIint32 dx = -RI_ROUND_TO_INT(slope * dy); |
|
217 edge.v1.y = m_vpMaxy; |
|
218 edge.v1.x += dx; |
|
219 } |
|
220 |
|
221 } |
|
222 |
|
223 if (edge.v0.y >= edge.v1.y) |
|
224 return; |
|
225 |
|
226 // \todo Recheck left/right. |
|
227 outLeft[0] = (edge.v0.x < m_vpMinx); outLeft[1] = (edge.v1.x < m_vpMinx); |
|
228 outRight[1] = (edge.v0.x > m_vpMaxx); outRight[1] = (edge.v1.x > m_vpMaxx); |
|
229 |
|
230 if (outLeft[0] && outLeft[1]) |
|
231 { |
|
232 edge.v0.x = m_vpMinx; |
|
233 edge.v1.x = m_vpMinx; |
|
234 pushEdge(edge); |
|
235 return; |
|
236 } |
|
237 if (outRight[0] && outRight[1]) |
|
238 { |
|
239 edge.v0.x = m_vpMaxx; |
|
240 edge.v1.x = m_vpMaxx; |
|
241 pushEdge(edge); |
|
242 return; |
|
243 } |
|
244 |
|
245 // From outside -> screen |
|
246 if (outLeft[0] || outRight[1]) |
|
247 { |
|
248 // infinite slope? |
|
249 double slope = (double)((RIint64)edge.v1.y - edge.v0.y)/((RIint64)edge.v1.x - edge.v0.x); |
|
250 |
|
251 if (outLeft[0]) |
|
252 { |
|
253 RIint32 dx = edge.v0.x; |
|
254 //RI_ASSERT(dx >= 0); |
|
255 // Note the sign. |
|
256 RIint32 dy = RI_ROUND_TO_INT(-slope * dx); |
|
257 |
|
258 Edge vpart = edge; |
|
259 vpart.v1.y = edge.v0.y + dy; |
|
260 //vpart.v1.x = edge.v0.x; // = 0? |
|
261 // \note This should be flagged instead of setting the smallest possible |
|
262 // value because of extremely gentle slopes may cause bugs: |
|
263 vpart.v1.x = vpart.v0.x = -0x100000; |
|
264 |
|
265 if (vpart.v1.y > vpart.v0.y) |
|
266 pushEdge(vpart); |
|
267 |
|
268 edge.v0.y += dy; |
|
269 edge.v0.x = 0; |
|
270 } |
|
271 } |
|
272 // From screen -> outside |
|
273 if (outLeft[1] || outRight[0]) |
|
274 { |
|
275 // infinite slope? |
|
276 double slope = (double)((RIint64)edge.v1.y - edge.v0.y)/((RIint64)edge.v1.x - edge.v0.x); |
|
277 |
|
278 if (outLeft[1]) |
|
279 { |
|
280 RIint32 dx = edge.v0.x; |
|
281 RI_ASSERT(dx >= 0); |
|
282 RIint32 dy = RI_ROUND_TO_INT(-slope * dx); |
|
283 |
|
284 Edge vpart = edge; |
|
285 vpart.v0.y = edge.v0.y + dy; |
|
286 vpart.v1.x = vpart.v0.x = LEFT_DISCARD; |
|
287 |
|
288 if (vpart.v1.y > vpart.v0.y) |
|
289 pushEdge(vpart); |
|
290 |
|
291 edge.v1.y = edge.v0.y + dy; |
|
292 edge.v1.x = 0; |
|
293 } |
|
294 } |
|
295 |
|
296 if (edge.v0.y >= edge.v1.y) |
|
297 return; |
|
298 |
|
299 // Finally, add the edge: |
|
300 pushEdge(edge); |
|
301 } |
|
302 |
|
303 void Rasterizer::addEdge(const Vector2& v0, const Vector2& v1) |
|
304 { |
|
305 if( m_edges.size() >= RI_MAX_EDGES ) |
|
306 throw std::bad_alloc(); //throw an out of memory error if there are too many edges |
|
307 |
|
308 Edge e; |
|
309 |
|
310 { |
|
311 IVector2 i0(RI_ROUND_TO_INT(v0.x * (1<<X_BITS)), RI_ROUND_TO_INT(v0.y * (1<<Y_BITS))); |
|
312 IVector2 i1(RI_ROUND_TO_INT(v1.x * (1<<X_BITS)), RI_ROUND_TO_INT(v1.y * (1<<Y_BITS))); |
|
313 |
|
314 if(i0.y == i1.y) |
|
315 return; //skip horizontal edges (they don't affect rasterization since we scan horizontally) |
|
316 |
|
317 if (i0.y < i1.y) |
|
318 { |
|
319 // Edge is going upward |
|
320 e.v0 = i0; |
|
321 e.v1 = i1; |
|
322 e.direction = 1; |
|
323 } |
|
324 else |
|
325 { |
|
326 // Edge is going downward |
|
327 e.v0 = i1; |
|
328 e.v1 = i0; |
|
329 e.direction = -1; |
|
330 } |
|
331 } |
|
332 |
|
333 // Clip and insert. |
|
334 |
|
335 clipAndAddEdge(e); |
|
336 } |
|
337 |
|
338 /*-------------------------------------------------------------------*//*! |
|
339 * \brief Set up rasterizer |
|
340 * \param |
|
341 * \return |
|
342 * \note |
|
343 *//*-------------------------------------------------------------------*/ |
|
344 |
|
345 void Rasterizer::setup(int vpx, int vpy, int vpwidth, int vpheight, VGFillRule fillRule, const PixelPipe* pixelPipe) |
|
346 { |
|
347 RI_ASSERT(vpwidth >= 0 && vpheight >= 0); |
|
348 RI_ASSERT(vpx + vpwidth >= vpx && vpy + vpheight >= vpy); |
|
349 RI_ASSERT(fillRule == VG_EVEN_ODD || fillRule == VG_NON_ZERO); |
|
350 RI_ASSERT(pixelPipe); |
|
351 |
|
352 clear(); |
|
353 |
|
354 m_vpx = vpx; |
|
355 m_vpy = vpy; |
|
356 m_vpwidth = vpwidth; |
|
357 m_vpheight = vpheight; |
|
358 |
|
359 if (m_vpheight > m_edges.size()) |
|
360 { |
|
361 int os = m_edges.size(); |
|
362 m_edges.resize(m_vpheight); |
|
363 for (int i = os; i < m_edges.size(); i++) |
|
364 m_edges[i] = EDGE_TERMINATOR; |
|
365 } |
|
366 |
|
367 m_vpMinx = RI_SHL(vpx, X_BITS); |
|
368 m_vpMiny = RI_SHL(vpy, Y_BITS); |
|
369 m_vpMaxx = RI_SHL(vpx + vpwidth, X_BITS); |
|
370 m_vpMaxy = RI_SHL(vpy + vpheight, Y_BITS); |
|
371 |
|
372 m_fillRule = fillRule; |
|
373 |
|
374 RIuint32 fillRuleMask = fillRule == VG_NON_ZERO ? 0xffffffffu : 1; |
|
375 m_fillRuleMask = fillRuleMask; |
|
376 |
|
377 m_pixelPipe = pixelPipe; |
|
378 m_covMinx = vpx+vpwidth; |
|
379 m_covMiny = vpy+vpheight; |
|
380 m_covMaxx = vpx; |
|
381 m_covMaxy = vpy; |
|
382 } |
|
383 |
|
384 /*-------------------------------------------------------------------*//*! |
|
385 * \brief Sets scissor rectangles. |
|
386 * \param |
|
387 * \return |
|
388 * \note |
|
389 *//*-------------------------------------------------------------------*/ |
|
390 |
|
391 void Rasterizer::setScissor(const Array<Rectangle>& scissors) |
|
392 { |
|
393 try |
|
394 { |
|
395 m_scissorEdges.clear(); |
|
396 for(int i=0;i<scissors.size();i++) |
|
397 { |
|
398 if(scissors[i].width > 0 && scissors[i].height > 0) |
|
399 { |
|
400 ScissorEdge e; |
|
401 e.miny = scissors[i].y; |
|
402 e.maxy = RI_INT_ADDSATURATE(scissors[i].y, scissors[i].height); |
|
403 |
|
404 e.x = scissors[i].x; |
|
405 e.direction = 1; |
|
406 m_scissorEdges.push_back(e); //throws bad_alloc |
|
407 e.x = RI_INT_ADDSATURATE(scissors[i].x, scissors[i].width); |
|
408 e.direction = -1; |
|
409 m_scissorEdges.push_back(e); //throws bad_alloc |
|
410 } |
|
411 } |
|
412 } |
|
413 catch(std::bad_alloc) |
|
414 { |
|
415 m_scissorEdges.clear(); |
|
416 throw; |
|
417 } |
|
418 } |
|
419 |
|
420 void Rasterizer::setScissoring(bool enabled) |
|
421 { |
|
422 m_scissor = enabled; |
|
423 } |
|
424 |
|
425 static RI_INLINE void small_memcpy32(void* dst, const void* src, size_t n) |
|
426 { |
|
427 RIuint32 *d = (RIuint32*)dst; |
|
428 const RIuint32 *s = (const RIuint32*)src; |
|
429 while(n) |
|
430 { |
|
431 *d++ = *s++; |
|
432 n-=4; |
|
433 } |
|
434 } |
|
435 |
|
436 // \todo Move this to some debug file or remove. |
|
437 #if defined(USE_SSE2) && !defined(_WIN32) |
|
438 RI_INLINE static void print128(__m128i ll) |
|
439 { |
|
440 #if defined(RI_DEBUG) |
|
441 unsigned long long v[2]; |
|
442 _mm_storeu_pd((double*)v, (__m128d)ll); |
|
443 RI_PRINTF("0x%016llx %016llx\n", v[0], v[1]); |
|
444 #else |
|
445 (void)ll; |
|
446 #endif |
|
447 } |
|
448 #endif |
|
449 |
|
450 #if defined(USE_SSE2) |
|
451 RI_INLINE static __m128i mm_mul4x32(const __m128i a, const __m128i b) { |
|
452 __m128i res; |
|
453 #if (_MSC_VER > 1400 ) |
|
454 // \todo Simpler way to do this on intel? |
|
455 __m128i m0 = _mm_mul_epu32(a, _mm_shuffle_epi32(b, _MM_SHUFFLE(1, 1, 0, 0))); |
|
456 __m128i m1 = _mm_mul_epu32(a, _mm_shuffle_epi32(b, _MM_SHUFFLE(3, 3, 2, 2))); |
|
457 |
|
458 res = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(m0), _mm_castsi128_ps(m1), _MM_SHUFFLE(2, 0, 2, 0))); |
|
459 #else |
|
460 __asm { |
|
461 movdqa xmm1, a; |
|
462 movdqa xmm2, b; |
|
463 pshufd xmm3, xmm2, 80; |
|
464 movdqa xmm0, xmm1; |
|
465 |
|
466 pshufd xmm2, xmm2, 250; |
|
467 pmuludq xmm0, xmm3; |
|
468 pmuludq xmm1, xmm2; |
|
469 |
|
470 shufps xmm0, xmm1, 136; |
|
471 movdqa res, xmm0; |
|
472 } |
|
473 #endif |
|
474 return res; |
|
475 } |
|
476 #endif |
|
477 |
|
478 #if defined(USE_SSE2) |
|
479 RI_INLINE static void mm_get_xmasks(const __m128i& coords, const __m128i& sampleCoords, __m128i& slWindMask, __m128i& pxWindMask) |
|
480 { |
|
481 const __m128i z = _mm_setzero_si128(); |
|
482 const __m128i xMask = _mm_cmpeq_epi16(_mm_srai_epi16(coords, Rasterizer::RASTERIZER_BITS), z); |
|
483 const __m128i sCmp = _mm_or_si128(_mm_cmpgt_epi16(sampleCoords, coords), _mm_cmpeq_epi16(sampleCoords, coords)); |
|
484 //const __m128i sCmp = _mm_cmplt_epi16(coords, sampleCoords); |
|
485 slWindMask = xMask; |
|
486 pxWindMask = _mm_and_si128(xMask, sCmp); |
|
487 } |
|
488 #endif |
|
489 |
|
490 RI_INLINE static void getVerticalSubpixels(int iY, int yStart, int yEnd, int& py0, int& py1) |
|
491 { |
|
492 const int cy = iY << Rasterizer::Y_BITS; |
|
493 py0 = cy > yStart ? 0 : yStart & Rasterizer::Y_MASK; |
|
494 py1 = (RI_INT_MIN(yEnd, cy + (1<<Rasterizer::Y_BITS)) - 1) & Rasterizer::Y_MASK; |
|
495 } |
|
496 |
|
497 RI_INLINE static void applyLeftEdge(const Rasterizer::ActiveEdge& currAe, Rasterizer::Windings& scanline, int intY) |
|
498 { |
|
499 // Applies the whole edge at a time. Make sure xRight < x for all y. |
|
500 // \todo Remove duplicate code for determining the active samples |
|
501 #if defined(USE_SSE2) |
|
502 int py0, py1; |
|
503 |
|
504 getVerticalSubpixels(intY, currAe.yStart, currAe.yEnd, py0, py1); |
|
505 |
|
506 const __m128i csteps = _mm_set_epi16(7,6,5,4,3,2,1,0); |
|
507 |
|
508 const __m128i ssePy0 = _mm_set1_epi16(py0-1); |
|
509 const __m128i ssePy1 = _mm_set1_epi16(py1+1); |
|
510 |
|
511 const __m128i yMask = _mm_and_si128(_mm_cmpgt_epi16(csteps, ssePy0), _mm_cmplt_epi16(csteps, ssePy1)); |
|
512 const __m128i dir = _mm_set1_epi16(currAe.direction); |
|
513 |
|
514 scanline.sseWinding = _mm_add_epi16(scanline.sseWinding, _mm_and_si128(yMask, dir)); |
|
515 |
|
516 #else |
|
517 RI_ASSERT(false); // Not implemented yet. |
|
518 #endif |
|
519 } |
|
520 |
|
521 RI_INLINE static void applyLeftEdgeNoAA(const Rasterizer::ActiveEdge& currAe, Rasterizer::Windings& scanline, int intY) |
|
522 { |
|
523 // Applies the whole edge at a time. Make sure xRight < x for all y. |
|
524 // \todo Remove duplicate code for determining the active samples? |
|
525 #if defined(USE_SSE2) |
|
526 int py0, py1; |
|
527 |
|
528 getVerticalSubpixels(intY, currAe.yStart, currAe.yEnd, py0, py1); |
|
529 |
|
530 //const __m128i csteps = _mm_set_epi16(4,4,4,4,4,4,4,4); |
|
531 |
|
532 __m128i yMask; |
|
533 |
|
534 if (py0 <= 4 && py1 >= 4) |
|
535 yMask = _mm_set1_epi8(-1); |
|
536 else |
|
537 yMask = _mm_set1_epi8(0); |
|
538 |
|
539 const __m128i dir = _mm_set1_epi16(currAe.direction); |
|
540 |
|
541 scanline.sseWinding = _mm_add_epi16(scanline.sseWinding, _mm_and_si128(yMask, dir)); |
|
542 //scanline.sseWinding = _mm_add_epi32(scanline.sseWinding, dir); |
|
543 |
|
544 #else |
|
545 RI_ASSERT(false); // Not implemented yet. |
|
546 #endif |
|
547 } |
|
548 |
|
549 RI_INLINE void calculateAEWinding(const Rasterizer::ActiveEdge& currAe, Rasterizer::Windings& pixel, Rasterizer::Windings& scanline, int intY, int pixelX) |
|
550 { |
|
551 #define QUEEN_COORD(Y) ((Y<<(Rasterizer::RASTERIZER_BITS - Rasterizer::SAMPLE_BITS)) + (1<<(Rasterizer::RASTERIZER_BITS-Rasterizer::SAMPLE_BITS-1))) |
|
552 |
|
553 #if !defined(USE_SSE2) |
|
554 static const int queenCoords[(1<<Rasterizer::SAMPLE_BITS)] = { |
|
555 QUEEN_COORD(3), QUEEN_COORD(7), QUEEN_COORD(0), QUEEN_COORD(2), |
|
556 QUEEN_COORD(5), QUEEN_COORD(1), QUEEN_COORD(6), QUEEN_COORD(4) |
|
557 }; |
|
558 |
|
559 const int ix = pixelX >> Rasterizer::RASTERIZER_BITS; |
|
560 const int cy = intY << Rasterizer::Y_BITS; |
|
561 |
|
562 const int py0 = cy > currAe.yStart ? 0 : currAe.yStart & Rasterizer::Y_MASK; |
|
563 const int py1 = (RI_INT_MIN(currAe.yEnd, cy + (1<<Rasterizer::Y_BITS)) - 1) & Rasterizer::Y_MASK; |
|
564 |
|
565 int edgeX = currAe.xRef + (cy + py0 - (currAe.yStart & ~Rasterizer::Y_MASK)) * currAe.slope; |
|
566 |
|
567 RI_ASSERT(py1 >= py0); |
|
568 |
|
569 for (int s = py0; s <= py1; s++) |
|
570 { |
|
571 const int sampleX = pixelX + queenCoords[s]; |
|
572 |
|
573 //compute winding number by evaluating the edge functions of edges to the left of the sampling point |
|
574 if(((edgeX >> Rasterizer::RASTERIZER_BITS) == ix)) |
|
575 { |
|
576 if (sampleX >= edgeX) |
|
577 { |
|
578 pixel.winding[s] += currAe.direction; |
|
579 } |
|
580 scanline.winding[s] += currAe.direction; |
|
581 } |
|
582 |
|
583 edgeX += currAe.slope; |
|
584 } |
|
585 #else |
|
586 |
|
587 __m128i qCoords = _mm_set_epi16( |
|
588 QUEEN_COORD(4), QUEEN_COORD(6), QUEEN_COORD(1), QUEEN_COORD(5), |
|
589 QUEEN_COORD(2), QUEEN_COORD(0), QUEEN_COORD(7), QUEEN_COORD(3)); |
|
590 |
|
591 RI_ASSERT(Rasterizer::RASTERIZER_BITS <= 14); |
|
592 |
|
593 // TEROP: Optimize conditions. |
|
594 int py0, py1; |
|
595 getVerticalSubpixels(intY, currAe.yStart, currAe.yEnd, py0, py1); |
|
596 |
|
597 const int cy = intY << Rasterizer::Y_BITS; |
|
598 |
|
599 const __m128i csteps0 = _mm_set_epi32(3,2,1,0); |
|
600 const __m128i csteps1 = _mm_set_epi32(7,6,5,4); |
|
601 |
|
602 const __m128i ssePy0 = _mm_set1_epi32(py0-1); |
|
603 const __m128i ssePy1 = _mm_set1_epi32(py1+1); |
|
604 |
|
605 const __m128i yMask0 = _mm_and_si128(_mm_cmpgt_epi32(csteps0, ssePy0), _mm_cmplt_epi32(csteps0, ssePy1)); |
|
606 const __m128i yMask1 = _mm_and_si128(_mm_cmpgt_epi32(csteps1, ssePy0), _mm_cmplt_epi32(csteps1, ssePy1)); |
|
607 |
|
608 const int edgeX = currAe.xRef + (cy - (currAe.yStart & ~Rasterizer::Y_MASK)) * currAe.slope; |
|
609 const __m128i xStart = _mm_set1_epi32(edgeX - pixelX); |
|
610 |
|
611 const __m128i xs0 = _mm_set1_epi32(currAe.slope); |
|
612 |
|
613 __m128i xAdd0 = mm_mul4x32(xs0, csteps0); |
|
614 __m128i xAdd1 = mm_mul4x32(xs0, csteps1); |
|
615 __m128i coords0 = _mm_add_epi32(xStart, xAdd0); |
|
616 __m128i coords1 = _mm_add_epi32(xStart, xAdd1); |
|
617 __m128i coords = _mm_packs_epi32(coords0, coords1); |
|
618 |
|
619 __m128i dir = _mm_set1_epi16(currAe.direction); |
|
620 __m128i yMask = _mm_packs_epi32(yMask0, yMask1); |
|
621 __m128i mDir = _mm_and_si128(dir, yMask); |
|
622 |
|
623 __m128i sampleCoords = qCoords; |
|
624 |
|
625 __m128i sw, pw; |
|
626 mm_get_xmasks(coords, sampleCoords, sw, pw); |
|
627 |
|
628 pixel.sseWinding = _mm_add_epi16(pixel.sseWinding, _mm_and_si128(pw, mDir)); |
|
629 scanline.sseWinding = _mm_add_epi16(scanline.sseWinding, _mm_and_si128(sw, mDir)); |
|
630 #endif |
|
631 |
|
632 #undef QUEEN_COORD |
|
633 |
|
634 } |
|
635 |
|
636 /** |
|
637 * \brief Calculate winding using one sample only. |
|
638 * \note This uses most of the same code as the AA-case even though it is not |
|
639 * necessary (one sample would be enough). |
|
640 */ |
|
641 RI_INLINE void calculateAEWindingNoAA(const Rasterizer::ActiveEdge& currAe, Rasterizer::Windings& pixel, Rasterizer::Windings& scanline, int intY, int pixelX) |
|
642 { |
|
643 #if defined(USE_SSE2) |
|
644 |
|
645 #define QUEEN_COORD(Y) ((Y<<(Rasterizer::RASTERIZER_BITS - Rasterizer::SAMPLE_BITS)) + (1<<(Rasterizer::RASTERIZER_BITS-Rasterizer::SAMPLE_BITS-1))) |
|
646 const int half = 1<<(Rasterizer::RASTERIZER_BITS-1); |
|
647 |
|
648 __m128i sampleCoords = _mm_set1_epi16(half); |
|
649 |
|
650 RI_ASSERT(Rasterizer::RASTERIZER_BITS <= 14); |
|
651 |
|
652 const int cy = intY << Rasterizer::Y_BITS; |
|
653 |
|
654 int py0, py1; |
|
655 getVerticalSubpixels(intY, currAe.yStart, currAe.yEnd, py0, py1); |
|
656 |
|
657 __m128i yMask; |
|
658 |
|
659 if (py0 <= 4 && py1 >= 4) |
|
660 yMask = _mm_set1_epi8(-1); |
|
661 else |
|
662 yMask = _mm_set1_epi8(0); |
|
663 |
|
664 const __m128i csteps0 = _mm_set_epi32(4,4,4,4); |
|
665 const __m128i csteps1 = _mm_set_epi32(4,4,4,4); |
|
666 |
|
667 const int edgeX = currAe.xRef + (cy - (currAe.yStart & ~Rasterizer::Y_MASK)) * currAe.slope; |
|
668 const __m128i xStart = _mm_set1_epi32(edgeX - pixelX); |
|
669 |
|
670 const __m128i xs0 = _mm_set1_epi32(currAe.slope); |
|
671 |
|
672 __m128i xAdd0 = mm_mul4x32(xs0, csteps0); |
|
673 __m128i xAdd1 = mm_mul4x32(xs0, csteps1); |
|
674 __m128i coords0 = _mm_add_epi32(xStart, xAdd0); |
|
675 __m128i coords1 = _mm_add_epi32(xStart, xAdd1); |
|
676 __m128i coords = _mm_packs_epi32(coords0, coords1); |
|
677 |
|
678 __m128i dir = _mm_set1_epi16(currAe.direction); |
|
679 __m128i mDir = _mm_and_si128(dir, yMask); |
|
680 //__m128i mDir = dir; |
|
681 |
|
682 __m128i sw, pw; |
|
683 mm_get_xmasks(coords, sampleCoords, sw, pw); |
|
684 |
|
685 pixel.sseWinding = _mm_add_epi16(pixel.sseWinding, _mm_and_si128(pw, mDir)); |
|
686 scanline.sseWinding = _mm_add_epi16(scanline.sseWinding, _mm_and_si128(sw, mDir)); |
|
687 |
|
688 #undef QUEEN_COORD |
|
689 |
|
690 #else |
|
691 RI_ASSERT(false); // Not implemented. |
|
692 #endif |
|
693 } |
|
694 |
|
695 #if defined(USE_SSE2) |
|
696 RI_INLINE static int mm_winding_to_coverage(const Rasterizer::Windings& pixel, int fillRuleMask) |
|
697 { |
|
698 // This version uses SSE2 counters. |
|
699 __m128i mask = _mm_set1_epi16(fillRuleMask); |
|
700 __m128i t = _mm_and_si128(mask, pixel.sseWinding); |
|
701 __m128i z = _mm_setzero_si128(); |
|
702 __m128i isz = _mm_cmpeq_epi16(t, z); |
|
703 __m128i ones = _mm_set1_epi16(1); |
|
704 __m128i res = _mm_add_epi16(ones, isz); |
|
705 __m128i add0 = _mm_add_epi16(res, _mm_shuffle_epi32(res, _MM_SHUFFLE(2, 3, 2, 3))); |
|
706 __m128i add1 = _mm_add_epi16(add0, _mm_shuffle_epi32(add0, _MM_SHUFFLE(1, 1, 1, 1))); |
|
707 __m128i add2 = _mm_add_epi16(add1, _mm_shufflelo_epi16(add1, _MM_SHUFFLE(1, 1, 1, 1))); |
|
708 |
|
709 int nSamples = _mm_cvtsi128_si32(add2) & 0xff; |
|
710 return nSamples; |
|
711 } |
|
712 #endif |
|
713 |
|
714 #define RI_DEBUG |
|
715 #if defined(RI_DEBUG) |
|
716 void maybeDumpEdges(Array<Rasterizer::ActiveEdge> &edgePool) |
|
717 { |
|
718 return; |
|
719 // \note This gives an idea about the edges at the rasterization stage. |
|
720 // Input edges must be output at a different stage. |
|
721 RI_PRINTF("lines = []\n"); |
|
722 for (int i = 0 ; i < edgePool.size(); i++) |
|
723 { |
|
724 const int slope = edgePool[i].slope; |
|
725 int x0, x1, y0, y1; |
|
726 y0 = edgePool[i].yStart; |
|
727 y1 = edgePool[i].yEnd; |
|
728 x0 = edgePool[i].xRef + (slope * (y0 & Rasterizer::Y_MASK)); |
|
729 x1 = (edgePool[i].xRef + (slope * (y1 - (y0 & ~Rasterizer::Y_MASK))))>>(Rasterizer::RASTERIZER_BITS-Rasterizer::X_BITS); |
|
730 RI_PRINTF("lines += [[%d, %d], [%d, %d]]\n",x0>>(Rasterizer::RASTERIZER_BITS-Rasterizer::X_BITS),y0,x1,y1); |
|
731 } |
|
732 } |
|
733 #endif |
|
734 |
|
735 /*-------------------------------------------------------------------*//*! |
|
736 * \brief Calls PixelPipe::pixelPipe for each pixel with coverage greater |
|
737 * than zero. |
|
738 * \param |
|
739 * \return |
|
740 * \note |
|
741 *//*-------------------------------------------------------------------*/ |
|
742 void Rasterizer::fill() |
|
743 { |
|
744 if(m_scissor && !m_scissorEdges.size()) |
|
745 return; //scissoring is on, but there are no scissor rectangles => nothing is visible |
|
746 |
|
747 int firstAe = 0; |
|
748 |
|
749 //proceed scanline by scanline |
|
750 //keep track of edges that can intersect the pixel filters of the current scanline (Active Edge Table) |
|
751 //until all pixels of the scanline have been processed |
|
752 // for all sampling points of the current pixel |
|
753 // determine the winding number using edge functions |
|
754 // add filter weight to coverage |
|
755 // divide coverage by the number of samples |
|
756 // determine a run of pixels with constant coverage |
|
757 // call fill callback for each pixel of the run |
|
758 |
|
759 const int fillRuleMask = m_fillRuleMask; |
|
760 |
|
761 int bbminx = (m_edgeMin.x >> X_BITS); |
|
762 int bbminy = (m_edgeMin.y >> Y_BITS); |
|
763 int bbmaxx = (m_edgeMax.x >> X_BITS)+1; |
|
764 int bbmaxy = (m_edgeMax.y >> Y_BITS)+1; |
|
765 int sx = RI_INT_MAX(m_vpx, bbminx); |
|
766 int ex = RI_INT_MIN(m_vpx+m_vpwidth, bbmaxx); |
|
767 int sy = RI_INT_MAX(m_vpy, bbminy); |
|
768 int ey = RI_INT_MIN(m_vpy+m_vpheight, bbmaxy); |
|
769 if(sx < m_covMinx) m_covMinx = sx; |
|
770 if(sy < m_covMiny) m_covMiny = sy; |
|
771 if(ex > m_covMaxx) m_covMaxx = ex; |
|
772 if(ey > m_covMaxy) m_covMaxy = ey; |
|
773 |
|
774 #if 0 |
|
775 // Dump edges: |
|
776 static bool dump = true; |
|
777 if (dump) |
|
778 { |
|
779 RI_PRINTF("lines = []\n"); |
|
780 for (int ie = 0; dump && ie < m_edgePool.size(); ie++) |
|
781 { |
|
782 RI_PRINTF("lines += [[%d, %d], [%d, %d]]\n",m_edgePool[ie].v0.x, m_edgePool[ie].v0.y, m_edgePool[ie].v1.x, m_edgePool[ie].v1.y); |
|
783 } |
|
784 dump = false; |
|
785 } |
|
786 |
|
787 #endif |
|
788 int debugMagic = 0; |
|
789 |
|
790 m_aet.clear(); |
|
791 |
|
792 #if defined(RI_DEBUG) |
|
793 maybeDumpEdges(m_edgePool); |
|
794 #endif |
|
795 |
|
796 //fill the screen |
|
797 for(int j = sy; j < ey; j++) |
|
798 { |
|
799 Windings scanlineWinding; |
|
800 const int cminy = j << Y_BITS; |
|
801 |
|
802 if (m_scissor) |
|
803 { |
|
804 // Gather scissor edges intersecting this scanline |
|
805 // \todo Don't clear, remove unused instead! |
|
806 m_scissorAet.clear(); |
|
807 |
|
808 for(int e = 0; e < m_scissorEdges.size(); e++) |
|
809 { |
|
810 const ScissorEdge& se = m_scissorEdges[e]; |
|
811 |
|
812 if(j >= se.miny && j < se.maxy) |
|
813 m_scissorAet.push_back(m_scissorEdges[e]); //throws bad_alloc |
|
814 } |
|
815 |
|
816 //sort scissor AET by edge x |
|
817 if (m_scissor) |
|
818 m_scissorAet.sort(); |
|
819 } |
|
820 |
|
821 // Drop unused edges, update remaining. |
|
822 // \todo Combine with full sweep. Use a sort-friendly edge-discard. |
|
823 for (int iae = firstAe; iae < m_aet.size(); iae++) |
|
824 { |
|
825 ActiveEdge& ae = m_aet[iae]; |
|
826 |
|
827 if (cminy >= ae.yEnd) |
|
828 { |
|
829 m_aet[iae] = m_aet[firstAe]; |
|
830 firstAe++; |
|
831 continue; |
|
832 } |
|
833 |
|
834 /* Update existing coordinates */ |
|
835 // \todo AND instead of shift. See other places also. |
|
836 const int y0 = (ae.yStart & ~Y_MASK); |
|
837 const int x = ae.xRef + ((j << Y_BITS) - y0) * ae.slope; |
|
838 ae.minx = x >> RASTERIZER_BITS; |
|
839 ae.maxx = (x + ae.slope * (1<<Y_BITS)) >> RASTERIZER_BITS; |
|
840 |
|
841 if (ae.minx > ae.maxx) |
|
842 RI_ANY_SWAP(ActiveEdge::XCoord, ae.minx, ae.maxx); |
|
843 |
|
844 // If the edge is not visible, "mark" it as immediately applicable |
|
845 // \todo Verify that this is the correct procedure. |
|
846 |
|
847 if (ae.maxx < 0) |
|
848 ae.minx = ae.maxx = LEFT_DISCARD_SHORT; |
|
849 } |
|
850 |
|
851 /* Add new edges */ |
|
852 |
|
853 RIuint32 aeIndex = m_edges[j]; |
|
854 while (aeIndex != EDGE_TERMINATOR) |
|
855 { |
|
856 const ActiveEdge& ae = m_edgePool[aeIndex]; |
|
857 m_aet.push_back(ae); // \todo Just copy pointers? |
|
858 aeIndex = ae.next; |
|
859 } |
|
860 |
|
861 if (firstAe >= m_aet.size()) |
|
862 { |
|
863 RI_ASSERT(firstAe == m_aet.size()); |
|
864 continue; //no edges on the whole scanline, skip it |
|
865 } |
|
866 |
|
867 //sort AET by edge minx |
|
868 m_aet.sort(firstAe, m_aet.size() - 1); |
|
869 |
|
870 // \todo Optimize adding and updating the edges? |
|
871 if (m_scissor && !m_scissorAet.size()) |
|
872 continue; // Scissoring is on, but there are no scissor rectangles on this scanline. |
|
873 |
|
874 //fill the scanline |
|
875 int scissorWinding = m_scissor ? 0 : 1; //if scissoring is off, winding is always 1 |
|
876 int scissorIndex = 0; |
|
877 int aes = firstAe; |
|
878 int aen = firstAe; |
|
879 |
|
880 RI_ASSERT(sx >= 0); |
|
881 |
|
882 #if 1 |
|
883 if (m_aa) |
|
884 { |
|
885 while ((aen < m_aet.size()) && (m_aet[aen].maxx < 0)) |
|
886 { |
|
887 applyLeftEdge(m_aet[aen], scanlineWinding, j); |
|
888 aen++; |
|
889 } |
|
890 } |
|
891 else |
|
892 { |
|
893 while ((aen < m_aet.size()) && (m_aet[aen].maxx < 0)) |
|
894 { |
|
895 applyLeftEdgeNoAA(m_aet[aen], scanlineWinding, j); |
|
896 aen++; |
|
897 } |
|
898 } |
|
899 |
|
900 #if defined(RI_DEBUG) |
|
901 for (int a = aen; a < m_aet.size(); a++) |
|
902 { |
|
903 RI_ASSERT(m_aet[a].maxx >= 0); |
|
904 } |
|
905 #endif |
|
906 #endif |
|
907 |
|
908 // \todo Combine this with the first check or reorganize the "clipping". |
|
909 if (aen >= m_aet.size()) |
|
910 continue; // No edges within viewport. Can happen atm. when all edges are "left". |
|
911 |
|
912 for(int i = sx; i < ex;) |
|
913 { |
|
914 //find edges that intersect or are to the left of the pixel antialiasing filter |
|
915 while(aes < m_aet.size() && (i + 1) >= m_aet[aes].minx) |
|
916 aes++; |
|
917 //edges [0,aes[ may have an effect on winding, and need to be evaluated while sampling |
|
918 |
|
919 // RIint8 winding[SF_SAMPLES]; |
|
920 Windings pixelWinding; |
|
921 |
|
922 pixelWinding = scanlineWinding; |
|
923 |
|
924 if (m_aa) |
|
925 { |
|
926 for(int e = aen; e < aes; e++) |
|
927 { |
|
928 const ActiveEdge& currAe = m_aet[e]; |
|
929 calculateAEWinding(currAe, pixelWinding, scanlineWinding, j, i << RASTERIZER_BITS); |
|
930 } |
|
931 } |
|
932 else |
|
933 { |
|
934 for(int e = aen; e < aes; e++) |
|
935 { |
|
936 const ActiveEdge& currAe = m_aet[e]; |
|
937 calculateAEWindingNoAA(currAe, pixelWinding, scanlineWinding, j, i << RASTERIZER_BITS); |
|
938 } |
|
939 } |
|
940 |
|
941 //compute coverage |
|
942 int coverageSamples = 0; |
|
943 #if !defined(USE_SSE2) |
|
944 |
|
945 for (int s = 0; s < SF_SAMPLES; s++) |
|
946 { |
|
947 if(pixelWinding.winding[s]) |
|
948 { |
|
949 coverageSamples++; |
|
950 } |
|
951 } |
|
952 #else |
|
953 coverageSamples = mm_winding_to_coverage(pixelWinding, fillRuleMask); |
|
954 _mm_empty(); |
|
955 #endif |
|
956 |
|
957 //constant coverage optimization: |
|
958 //scan AET from left to right and skip all the edges that are completely to the left of the pixel filter. |
|
959 //since AET is sorted by minx, the edge we stop at is the leftmost of the edges we haven't passed yet. |
|
960 //if that edge is to the right of this pixel, coverage is constant between this pixel and the start of the edge. |
|
961 while(aen < m_aet.size() && m_aet[aen].maxx < i) |
|
962 aen++; |
|
963 |
|
964 int endSpan = m_vpx + m_vpwidth; // endSpan is the first pixel NOT part of the span |
|
965 |
|
966 if(aen < m_aet.size()) |
|
967 { |
|
968 endSpan = RI_INT_MAX(i+1, RI_INT_MIN(endSpan, m_aet[aen].minx)); |
|
969 } |
|
970 |
|
971 //fill a run of pixels with constant coverage |
|
972 if(coverageSamples) |
|
973 { |
|
974 |
|
975 if (!m_scissor) |
|
976 { |
|
977 int fillStartX = i; /* Inclusive */ |
|
978 pushSpan(fillStartX, j, (endSpan - fillStartX), coverageSamples); |
|
979 } |
|
980 else // (scissor) |
|
981 { |
|
982 int fillStartX = i; |
|
983 //update scissor winding number |
|
984 |
|
985 /* \todo Sort the scissor edges and skip unnecessary checks when scissors are used */ |
|
986 while (scissorIndex < m_scissorAet.size() && m_scissorAet[scissorIndex].x <= fillStartX) |
|
987 { |
|
988 scissorWinding += m_scissorAet[scissorIndex++].direction; |
|
989 } |
|
990 |
|
991 while (!scissorWinding && scissorIndex < m_scissorAet.size() && m_scissorAet[scissorIndex].x < endSpan) |
|
992 { |
|
993 fillStartX = m_scissorAet[scissorIndex].x; |
|
994 scissorWinding += m_scissorAet[scissorIndex++].direction; |
|
995 RI_ASSERT(fillStartX >= i); |
|
996 } |
|
997 |
|
998 RI_ASSERT(scissorWinding >= 0); |
|
999 |
|
1000 int endScissorSpan = endSpan; |
|
1001 |
|
1002 while (scissorWinding && fillStartX < endSpan && (scissorIndex < m_scissorAet.size())) |
|
1003 { |
|
1004 |
|
1005 // Determine the end of renderable area: |
|
1006 while (scissorWinding && scissorIndex < m_scissorAet.size() && m_scissorAet[scissorIndex].x <= endSpan) |
|
1007 { |
|
1008 endScissorSpan = m_scissorAet[scissorIndex].x; |
|
1009 scissorWinding += m_scissorAet[scissorIndex++].direction; |
|
1010 } |
|
1011 |
|
1012 RI_ASSERT(fillStartX >= i); |
|
1013 RI_ASSERT(endScissorSpan <= endSpan); |
|
1014 |
|
1015 pushSpan(fillStartX, j, (endScissorSpan - fillStartX), coverageSamples); |
|
1016 fillStartX = endScissorSpan; |
|
1017 endScissorSpan = endSpan; |
|
1018 |
|
1019 // Skip until within drawable area |
|
1020 while (!scissorWinding && scissorIndex < m_scissorAet.size() && m_scissorAet[scissorIndex].x < endSpan) |
|
1021 { |
|
1022 fillStartX = m_scissorAet[scissorIndex].x; |
|
1023 scissorWinding += m_scissorAet[scissorIndex++].direction; |
|
1024 } |
|
1025 |
|
1026 } |
|
1027 } |
|
1028 } |
|
1029 i = endSpan; |
|
1030 } |
|
1031 } |
|
1032 commitSpans(); |
|
1033 #if defined(USE_SSE2) |
|
1034 _mm_empty(); |
|
1035 #endif |
|
1036 clear(); |
|
1037 } |
|
1038 |
|
1039 RI_INLINE void Rasterizer::commitSpans() |
|
1040 { |
|
1041 if (!m_nSpans) |
|
1042 return; |
|
1043 |
|
1044 m_pixelPipe->fillSpans(m_ppVariants, m_spanCache, m_nSpans); |
|
1045 m_nSpans = 0; |
|
1046 |
|
1047 } |
|
1048 |
|
1049 RI_INLINE void Rasterizer::pushSpan(int x, int y, int len, int coverage) |
|
1050 { |
|
1051 //printf("x: %d, y: %d, len: %d, coverage: %d\n", x, y, len, coverage); |
|
1052 // \todo Check what causes this with scissors |
|
1053 if (len <= 0) return; |
|
1054 //RI_ASSERT(len > 0); |
|
1055 |
|
1056 Span& span = m_spanCache[m_nSpans]; |
|
1057 |
|
1058 span.x0 = x; |
|
1059 span.y = y; |
|
1060 span.len = (RIuint16)len; |
|
1061 span.coverage = coverage; |
|
1062 |
|
1063 m_nSpans++; |
|
1064 |
|
1065 if (m_nSpans == N_CACHED_SPANS) |
|
1066 { |
|
1067 commitSpans(); |
|
1068 } |
|
1069 } |
|
1070 |
|
1071 //======================================================================= |
|
1072 |
|
1073 } //namespace OpenVGRI |