|
1 /* Copyright (c) 2009 The Khronos Group Inc. |
|
2 * |
|
3 * Permission is hereby granted, free of charge, to any person obtaining a |
|
4 * copy of this software and/or associated documentation files (the |
|
5 * "Materials"), to deal in the Materials without restriction, including |
|
6 * without limitation the rights to use, copy, modify, merge, publish, |
|
7 * distribute, sublicense, and/or sell copies of the Materials, and to |
|
8 * permit persons to whom the Materials are furnished to do so, subject to |
|
9 * 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 |
|
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
|
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
20 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. |
|
21 */ |
|
22 |
|
23 /*! \ingroup wfc |
|
24 * \file wfcpipeline.c |
|
25 * |
|
26 * \brief SI Composition pipeline stages |
|
27 * |
|
28 * Each pipeline stage is implemented in their respective functions |
|
29 * that take context and element as parameter. Composition status is |
|
30 * stored in elements state variable (struct WFC_ELEMENT_STATE.) |
|
31 * State has no strict input/output variables, each stage reads/writes |
|
32 * those variables it needs |
|
33 */ |
|
34 #include <string.h> |
|
35 #include <stdlib.h> |
|
36 #include <math.h> |
|
37 |
|
38 #include "WF/wfc.h" |
|
39 #include "wfccontext.h" |
|
40 #include "wfcelement.h" |
|
41 #include "wfcimageprovider.h" |
|
42 #include "wfcstructs.h" |
|
43 #include "wfcscene.h" |
|
44 |
|
45 #include "owfobject.h" |
|
46 |
|
47 #include "owfnativestream.h" |
|
48 #include "owfmemory.h" |
|
49 #include "owfimage.h" |
|
50 #include "owfdebug.h" |
|
51 |
|
52 #define EXTRA_PIXEL_BOUNDARY 2 |
|
53 |
|
54 /*! |
|
55 * \brief Check element destination visibility |
|
56 * |
|
57 * Check if element's destination rectangle is |
|
58 * inside context's visible limits. |
|
59 * |
|
60 * \param context Context |
|
61 * \param element Element |
|
62 * |
|
63 * \return Boolean value indicating whether element is visible or not |
|
64 */ |
|
65 |
|
66 static WFCboolean |
|
67 WFC_Pipeline_ElementIsVisible(WFC_CONTEXT* context, WFC_ELEMENT* element) |
|
68 { |
|
69 OWF_RECTANGLE bounds, rect, drect; |
|
70 |
|
71 if ((context->rotation == WFC_ROTATION_90) || (context->rotation == WFC_ROTATION_270)) |
|
72 { |
|
73 OWF_Rect_Set(&bounds, 0, 0, context->targetHeight, context->targetWidth); |
|
74 } |
|
75 else |
|
76 { |
|
77 OWF_Rect_Set(&bounds, 0, 0, context->targetWidth, context->targetHeight); |
|
78 } |
|
79 |
|
80 OWF_Rect_Set(&rect, element->dstRect[0], element->dstRect[1], |
|
81 element->dstRect[2], element->dstRect[3]); |
|
82 |
|
83 /* check destination rectangle against bounds - exit if not visible */ |
|
84 if (!OWF_Rect_Clip(&drect, &rect, &bounds)) |
|
85 { |
|
86 return WFC_FALSE; |
|
87 } |
|
88 |
|
89 return WFC_TRUE; |
|
90 } |
|
91 |
|
92 static void |
|
93 WFC_Pipeline_BlendInfo(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state) |
|
94 { |
|
95 |
|
96 OWF_ASSERT(state); |
|
97 |
|
98 /* setup blending parameters */ |
|
99 state->blendInfo.destination.image = context->state.internalTargetImage; |
|
100 state->blendInfo.destination.rectangle = &state->dstRect; |
|
101 state->blendInfo.source.image = state->scaledSourceImage; |
|
102 state->blendInfo.source.rectangle = &state->scaledSrcRect; |
|
103 state->blendInfo.mask = state->originalMaskImage ? state->maskImage : NULL; |
|
104 state->blendInfo.globalAlpha = state->globalAlpha; |
|
105 |
|
106 /* composition does not use these values ever */ |
|
107 state->blendInfo.tsColor = NULL; |
|
108 state->blendInfo.destinationFullyOpaque = OWF_FALSE; |
|
109 |
|
110 DPRINT((" globalAplha = %f", state->globalAlpha)); |
|
111 /* no need to check with OWF_ALPHA_MIN_VALUE as it is zero */ |
|
112 OWF_ASSERT(state->blendInfo.globalAlpha <= OWF_ALPHA_MAX_VALUE); |
|
113 } |
|
114 |
|
115 /*! Transform the source rectangle to represent the floating point viewport |
|
116 as an offset in the final rotation stage image */ |
|
117 static void |
|
118 WFC_Pipeline_TransformSource(WFC_ELEMENT_STATE* state) |
|
119 { |
|
120 OWFfloat width, height, totalWidth, totalHeight, |
|
121 leftMargin, rightMargin, |
|
122 topMargin, bottomMargin, |
|
123 temp; |
|
124 OWF_FLIP_DIRECTION flipping; |
|
125 WFCRotation rotation; |
|
126 |
|
127 |
|
128 OWF_ASSERT(state); |
|
129 |
|
130 width = state->sourceRect[2]; |
|
131 totalWidth = state->sourceRect[0] + state->sourceRect[2]; |
|
132 |
|
133 height = state->sourceRect[3]; |
|
134 totalHeight = state->sourceRect[1] + state->sourceRect[3]; |
|
135 |
|
136 /* X margins - includes 1 pixel border */ |
|
137 leftMargin = (state->sourceRect[0] - ((float) floor(state->sourceRect[0]))) + 1.0f; |
|
138 rightMargin = (((float) ceil(totalWidth)) - totalWidth) + 1.0f; |
|
139 |
|
140 /* Y margins - includes 1 pixel border */ |
|
141 topMargin = (state->sourceRect[1] - ((float) floor(state->sourceRect[1]))) + 1.0f; |
|
142 bottomMargin = (((float) ceil(totalHeight)) - totalHeight) + 1.0f; |
|
143 |
|
144 /* flip stages */ |
|
145 flipping = state->sourceFlip > 0.0f ? OWF_FLIP_VERTICALLY |
|
146 : OWF_FLIP_NONE; |
|
147 |
|
148 /* top margin needs to be the bottom margin */ |
|
149 if (flipping & OWF_FLIP_VERTICALLY) |
|
150 { |
|
151 temp = topMargin; |
|
152 topMargin = bottomMargin; |
|
153 bottomMargin = temp; |
|
154 } |
|
155 |
|
156 /* rotation stages */ |
|
157 rotation = state->rotation; |
|
158 |
|
159 switch (rotation) |
|
160 { |
|
161 case WFC_ROTATION_0: |
|
162 { |
|
163 break; |
|
164 } |
|
165 |
|
166 case WFC_ROTATION_90: |
|
167 { |
|
168 /* switch width and height */ |
|
169 temp = width; |
|
170 width = height; |
|
171 height = temp; |
|
172 |
|
173 topMargin = leftMargin; |
|
174 leftMargin = bottomMargin; |
|
175 |
|
176 break; |
|
177 } |
|
178 |
|
179 case WFC_ROTATION_180: |
|
180 { |
|
181 leftMargin = rightMargin; |
|
182 topMargin = bottomMargin; |
|
183 |
|
184 break; |
|
185 } |
|
186 |
|
187 case WFC_ROTATION_270: |
|
188 { |
|
189 /* switch width and height */ |
|
190 temp = width; |
|
191 width = height; |
|
192 height = temp; |
|
193 |
|
194 leftMargin = topMargin; |
|
195 topMargin = rightMargin; |
|
196 |
|
197 break; |
|
198 } |
|
199 |
|
200 default: |
|
201 { |
|
202 OWF_ASSERT(0); |
|
203 } |
|
204 } |
|
205 |
|
206 /* X offset */ |
|
207 state->transformedSourceRect[0] = leftMargin; |
|
208 /* Y offset */ |
|
209 state->transformedSourceRect[1] = topMargin; |
|
210 /* width */ |
|
211 state->transformedSourceRect[2] = width; |
|
212 /* height */ |
|
213 state->transformedSourceRect[3] = height; |
|
214 } |
|
215 |
|
216 /*! Calculate the oversized integer crop region */ |
|
217 static void |
|
218 WFC_Pipeline_OversizedViewport(WFC_ELEMENT_STATE* state) |
|
219 { |
|
220 OWFint width, height; |
|
221 |
|
222 state->oversizedCropRect.x = (int) floor(state->sourceRect[0]); |
|
223 state->oversizedCropRect.y = (int) floor(state->sourceRect[1]); |
|
224 |
|
225 width = (int) ceil(state->sourceRect[0] + state->sourceRect[2]); |
|
226 state->oversizedCropRect.width = (width - state->oversizedCropRect.x) + EXTRA_PIXEL_BOUNDARY; |
|
227 |
|
228 height = (int) ceil(state->sourceRect[1] + state->sourceRect[3]); |
|
229 state->oversizedCropRect.height = (height - state->oversizedCropRect.y) + EXTRA_PIXEL_BOUNDARY; |
|
230 } |
|
231 |
|
232 /*-----------------------------------------------------------* |
|
233 * Initial creation of element state object created just once per context |
|
234 *-----------------------------------------------------------*/ |
|
235 OWF_API_CALL void WFC_Pipeline_DestroyState(WFC_CONTEXT* context) |
|
236 { |
|
237 WFC_ELEMENT_STATE* state; |
|
238 state= &context->prototypeElementState; |
|
239 OWF_Image_Destroy(state->scaledSourceImage); |
|
240 OWF_Image_Destroy(state->croppedSourceImage); |
|
241 OWF_Image_Destroy(state->convertedSourceImage); |
|
242 OWF_Image_Destroy(state->rotatedSourceIntermediateImage); |
|
243 OWF_Image_Destroy(state->flippedSourceImage); |
|
244 OWF_Image_Destroy(state->rotatedSourceImage); |
|
245 OWF_Image_Destroy(state->maskImage); |
|
246 state->scaledSourceImage=NULL; |
|
247 state->croppedSourceImage=NULL; |
|
248 state->convertedSourceImage=NULL; |
|
249 state->rotatedSourceIntermediateImage=NULL; |
|
250 state->flippedSourceImage=NULL; |
|
251 state->rotatedSourceImage=NULL; |
|
252 state->maskImage=NULL; |
|
253 } |
|
254 |
|
255 OWF_API_CALL OWFboolean WFC_Pipeline_CreateState(WFC_CONTEXT* context) |
|
256 { |
|
257 WFC_ELEMENT_STATE* state; |
|
258 OWF_IMAGE_FORMAT fmt; |
|
259 |
|
260 fmt.pixelFormat = OWF_IMAGE_ARGB_INTERNAL; |
|
261 fmt.linear = OWF_FALSE; |
|
262 fmt.premultiplied = OWF_FALSE; |
|
263 fmt.rowPadding = 1; |
|
264 state= &context->prototypeElementState; |
|
265 /* All buffers are initially created the full size of the scratch buffers, whicgh records the buffer size in bytes */ |
|
266 state->convertedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[1], 0); |
|
267 state->croppedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[2], 0); |
|
268 state->flippedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[2], 0); |
|
269 |
|
270 state->rotatedSourceIntermediateImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[1], 0); |
|
271 state->rotatedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[2], 0); |
|
272 state->scaledSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[3], 0); |
|
273 fmt.pixelFormat = OWF_IMAGE_L32; |
|
274 state->maskImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[4], 0); |
|
275 if (!state->convertedSourceImage||!state->croppedSourceImage||!state->flippedSourceImage |
|
276 ||!state->rotatedSourceIntermediateImage||!state->rotatedSourceImage |
|
277 ||!state->scaledSourceImage||!state->maskImage |
|
278 ) |
|
279 { |
|
280 WFC_Pipeline_DestroyState(context); |
|
281 return OWF_FALSE; |
|
282 } |
|
283 return OWF_TRUE; |
|
284 } |
|
285 |
|
286 |
|
287 /*--------------------------------------------------------------------------- |
|
288 * Composition pipeline preparation |
|
289 * |
|
290 * \param context Context |
|
291 * \param element Element |
|
292 * |
|
293 * \return Boolean value indicating whether preparation succeeded |
|
294 *----------------------------------------------------------------------------*/ |
|
295 #ifdef DEBUG |
|
296 /* reset size to original extent then try to set it to the target size */ |
|
297 #define CREATE_WITH_LIMITS(img, imgW, imgH, fmt, maxW, maxH) \ |
|
298 { \ |
|
299 OWFboolean resized; \ |
|
300 OWF_Image_SetSize(img, maxW, maxH); \ |
|
301 OWF_Image_SetFlags(img,(fmt)->premultiplied,(fmt)->linear); \ |
|
302 resized = OWF_Image_SetSize(img, imgW, imgH); \ |
|
303 OWF_ASSERT(resized); \ |
|
304 } |
|
305 #else |
|
306 #define CREATE_WITH_LIMITS(img, imgW, imgH, fmt, maxW, maxH) \ |
|
307 { \ |
|
308 OWF_Image_SetSize(img, maxW, maxH); \ |
|
309 OWF_Image_SetFlags(img,(fmt)->premultiplied,(fmt)->linear); \ |
|
310 OWF_Image_SetSize(img, imgW, imgH); \ |
|
311 } |
|
312 #endif |
|
313 OWF_API_CALL WFC_ELEMENT_STATE* |
|
314 WFC_Pipeline_BeginComposition(WFC_CONTEXT* context, WFC_ELEMENT* element) |
|
315 { |
|
316 WFC_ELEMENT_STATE* state = &context->prototypeElementState; |
|
317 OWF_IMAGE_FORMAT imgf; |
|
318 OWFint sourceWidth; |
|
319 OWFint sourceHeight; |
|
320 OWFint x; |
|
321 OWFint tempWidth, tempHeight; |
|
322 |
|
323 |
|
324 DPRINT(("WFC_Element_BeginComposition(%x,%x)", |
|
325 context ? context->handle : 0, element ? element->handle : 0)); |
|
326 |
|
327 if (!context || !element) |
|
328 { |
|
329 DPRINT((" context == NULL || element == NULL")); |
|
330 return NULL; |
|
331 } |
|
332 |
|
333 if (!WFC_Pipeline_ElementIsVisible(context, element)) |
|
334 { |
|
335 DPRINT((" element [%x] totally outside of target - skipped", |
|
336 element ? element->handle : 0)); |
|
337 return NULL; |
|
338 } |
|
339 |
|
340 |
|
341 /* setup temporary images used in composition. since the original |
|
342 source data must not be altered, we must copy it to scratch buffer |
|
343 and work it there. another scratch buffer is needed for scaling |
|
344 the image to its final size. same applies for masks; thus a grand total |
|
345 of 4 scratch buffers are needed. */ |
|
346 OWF_ASSERT(element->source); |
|
347 OWF_ASSERT(element->source->streamHandle); |
|
348 |
|
349 state->originalSourceImage = element->source->lockedStream.image; |
|
350 state->rotation = element->sourceRotation; |
|
351 state->sourceFlip = element->sourceFlip; |
|
352 state->globalAlpha = element->globalAlpha; |
|
353 state->sourceScaleFilter = element->sourceScaleFilter; |
|
354 state->transparencyTypes = element->transparencyTypes; |
|
355 /* replicate the source viewport rectangle and target extent rectangle */ |
|
356 for (x = 0; x < 4; x++) |
|
357 { |
|
358 state->sourceRect[x] = element->srcRect[x]; |
|
359 state->destinationRect[x] = element->dstRect[x]; |
|
360 } |
|
361 OWF_Rect_Set(&state->dstRect, element->dstRect[0], element->dstRect[1], |
|
362 element->dstRect[2], element->dstRect[3]); |
|
363 |
|
364 /* transform the source rectangle to represent the floating point viewport |
|
365 as an offset in the final rotation stage image */ |
|
366 WFC_Pipeline_TransformSource(state); |
|
367 |
|
368 imgf.pixelFormat = OWF_IMAGE_ARGB_INTERNAL; |
|
369 imgf.linear = element->source->lockedStream.image->format.linear; |
|
370 imgf.premultiplied = element->source->lockedStream.image->format.premultiplied; |
|
371 imgf.rowPadding = 1; |
|
372 |
|
373 /* add a 1 pixel boundary so we can replicate the edges */ |
|
374 sourceWidth = element->source->lockedStream.image->width + EXTRA_PIXEL_BOUNDARY; |
|
375 sourceHeight = element->source->lockedStream.image->height + EXTRA_PIXEL_BOUNDARY; |
|
376 |
|
377 CREATE_WITH_LIMITS(state->convertedSourceImage, |
|
378 sourceWidth, |
|
379 sourceHeight, |
|
380 &imgf, |
|
381 MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT); |
|
382 |
|
383 /* calculate the oversized integer crop region (inc. 1 pixel boundary) |
|
384 so edge replication can be performed */ |
|
385 WFC_Pipeline_OversizedViewport(state); |
|
386 |
|
387 /* subsequent temporary renderstage pipeline images need to use the oversized |
|
388 integer crop region */ |
|
389 CREATE_WITH_LIMITS(state->croppedSourceImage, |
|
390 state->oversizedCropRect.width, state->oversizedCropRect.height, |
|
391 &imgf, |
|
392 MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT); |
|
393 |
|
394 CREATE_WITH_LIMITS(state->flippedSourceImage, |
|
395 state->oversizedCropRect.width, state->oversizedCropRect.height, |
|
396 &imgf, |
|
397 MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT); |
|
398 |
|
399 |
|
400 if (state->rotation == WFC_ROTATION_90 || state->rotation == WFC_ROTATION_270) |
|
401 { |
|
402 tempHeight = state->oversizedCropRect.width; |
|
403 tempWidth = state->oversizedCropRect.height; |
|
404 } |
|
405 else |
|
406 { |
|
407 tempWidth = state->oversizedCropRect.width; |
|
408 tempHeight = state->oversizedCropRect.height; |
|
409 } |
|
410 |
|
411 CREATE_WITH_LIMITS(state->rotatedSourceIntermediateImage, |
|
412 tempWidth, tempHeight, |
|
413 &imgf, |
|
414 MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT); |
|
415 |
|
416 |
|
417 /* no rotation required - just use the previous stages (flip) buffer */ |
|
418 CREATE_WITH_LIMITS(state->rotatedSourceImage, |
|
419 tempWidth, tempHeight, |
|
420 &imgf, |
|
421 MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT); |
|
422 |
|
423 /* finally, scaled image uses destination width and height */ |
|
424 OWF_Rect_Set(&state->scaledSrcRect, 0, 0, element->dstRect[2], element->dstRect[3]); |
|
425 CREATE_WITH_LIMITS(state->scaledSourceImage, |
|
426 state->scaledSrcRect.width, |
|
427 state->scaledSrcRect.height, |
|
428 &imgf, |
|
429 MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT); |
|
430 |
|
431 if (!(state->convertedSourceImage && state->croppedSourceImage && |
|
432 state->scaledSourceImage && state->rotatedSourceIntermediateImage && |
|
433 state->flippedSourceImage && state->rotatedSourceImage)) |
|
434 { |
|
435 DPRINT((" Preparation of intermediate pipeline image buffers failed" |
|
436 " (May be caused by overflow or out-of-memory situation)")); |
|
437 DPRINT((" convertedSourceImage = %p", state->convertedSourceImage)); |
|
438 DPRINT((" croppedSourceImage = %p", state->croppedSourceImage)); |
|
439 DPRINT((" scaledSourceImage = %p", state->scaledSourceImage)); |
|
440 DPRINT((" rotatedSourceIntermediateImage = %p", state->rotatedSourceIntermediateImage)); |
|
441 DPRINT((" flippedSourceImage = %p", state->flippedSourceImage)); |
|
442 DPRINT((" rotatedSourceImage = %p", state->rotatedSourceImage)); |
|
443 |
|
444 |
|
445 return (WFC_ELEMENT_STATE*)WFC_FALSE; |
|
446 } |
|
447 |
|
448 #ifdef DEBUG |
|
449 OWF_Image_Clear(state->convertedSourceImage, 0, 0, 0, 0); |
|
450 OWF_Image_Clear(state->croppedSourceImage, 0, 0, 0, 0); |
|
451 OWF_Image_Clear(state->scaledSourceImage, 0, 0, 0, 0); |
|
452 OWF_Image_Clear(state->rotatedSourceIntermediateImage, 0, 0, 0, 0); |
|
453 OWF_Image_Clear(state->flippedSourceImage, 0, 0, 0, 0); |
|
454 OWF_Image_Clear(state->rotatedSourceImage, 0, 0, 0, 0); |
|
455 #endif |
|
456 |
|
457 /* setup mask in case the element has one */ |
|
458 if (element->maskComposed) |
|
459 { |
|
460 OWF_IMAGE* image = NULL; |
|
461 OWFsubpixel* pix = NULL; |
|
462 WFCint i = 0; |
|
463 |
|
464 DPRINT(("Processing element mask")); |
|
465 OWF_ASSERT(&element->mask); |
|
466 OWF_ASSERT(&element->mask->streamHandle); |
|
467 image = element->mask->lockedStream.image; |
|
468 OWF_ASSERT(image); |
|
469 |
|
470 state->originalMaskImage = element->mask->lockedStream.image; |
|
471 |
|
472 imgf.pixelFormat = OWF_IMAGE_L32; |
|
473 imgf.linear = image->format.linear; |
|
474 imgf.premultiplied = image->format.premultiplied; |
|
475 |
|
476 /* mask size is always same as destination rect's */ |
|
477 DPRINT(("Binding stream image to scratch buffer")); |
|
478 CREATE_WITH_LIMITS(state->maskImage, |
|
479 state->scaledSrcRect.width, |
|
480 state->scaledSrcRect.height, |
|
481 &imgf, |
|
482 MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT); |
|
483 |
|
484 /* initialize mask */ |
|
485 DPRINT(("Initializing mask, size = %dx%d", state->scaledSrcRect.width, |
|
486 state->scaledSrcRect.height)); |
|
487 pix = (OWFsubpixel*) state->maskImage->data; |
|
488 for (i = 0; i < state->scaledSrcRect.width * state->scaledSrcRect.height; i++) |
|
489 { |
|
490 pix[i] = OWF_FULLY_OPAQUE; |
|
491 } |
|
492 } |
|
493 else |
|
494 { |
|
495 state->originalMaskImage=NULL; |
|
496 } |
|
497 |
|
498 WFC_Pipeline_BlendInfo(context, state); |
|
499 |
|
500 DPRINT((" Cropped source image size is %dx%d", |
|
501 state->croppedSourceImage->width, state->croppedSourceImage->height)); |
|
502 DPRINT((" Scaled source image size is %dx%d", |
|
503 state->scaledSourceImage->width, state->scaledSourceImage->height)); |
|
504 DPRINT((" Mirrored source intermediate image size is %dx%d", |
|
505 state->rotatedSourceIntermediateImage->width, state->rotatedSourceIntermediateImage->height)); |
|
506 DPRINT((" Mirrored source image size is %dx%d", |
|
507 state->flippedSourceImage->width, state->flippedSourceImage->height)); |
|
508 DPRINT((" Rotated source image size is %dx%d", |
|
509 state->rotatedSourceImage->width, state->rotatedSourceImage->height)); |
|
510 |
|
511 return state; |
|
512 } |
|
513 |
|
514 /*--------------------------------------------------------------------------- |
|
515 * Composition pipeline cleanup |
|
516 * |
|
517 * \param context Context |
|
518 * \param element Element |
|
519 *----------------------------------------------------------------------------*/ |
|
520 OWF_API_CALL void |
|
521 WFC_Pipeline_EndComposition(WFC_CONTEXT* context, WFC_ELEMENT* element, WFC_ELEMENT_STATE* state) |
|
522 { |
|
523 |
|
524 if (!context || !element) |
|
525 { |
|
526 DPRINT(("WFC_Element_EndComposition: context == NULL || " |
|
527 "element == NULL")); |
|
528 } |
|
529 |
|
530 |
|
531 OWF_ASSERT(state); |
|
532 state->originalSourceImage=NULL; |
|
533 state->originalMaskImage=NULL; |
|
534 |
|
535 } |
|
536 |
|
537 /*--------------------------------------------------------------------------- |
|
538 * \brief Source conversion stage |
|
539 * |
|
540 * \param context Context |
|
541 * \param element Element |
|
542 *----------------------------------------------------------------------------*/ |
|
543 OWF_API_CALL void |
|
544 WFC_Pipeline_ExecuteSourceConversionStage(WFC_CONTEXT* context, |
|
545 WFC_ELEMENT_STATE* state) |
|
546 { |
|
547 /* this stage could be embedded in cropping stage */ |
|
548 |
|
549 |
|
550 if (NULL == context || NULL == state) |
|
551 { |
|
552 DPRINT(("WFC_Context_ExecuteSourceConversionStage: context = %p, " |
|
553 "state = %p", |
|
554 context, state)); |
|
555 return; |
|
556 } |
|
557 |
|
558 OWF_ASSERT(state->originalSourceImage); |
|
559 |
|
560 OWF_Image_SourceFormatConversion(state->convertedSourceImage, |
|
561 state->originalSourceImage); |
|
562 |
|
563 /* convert mask from stream format to internal format */ |
|
564 if (state->originalMaskImage) |
|
565 { |
|
566 if (!OWF_Image_ConvertMask(state->maskImage, state->originalMaskImage)) |
|
567 { |
|
568 state->originalMaskImage=NULL; |
|
569 } |
|
570 } |
|
571 } |
|
572 |
|
573 /*--------------------------------------------------------------------------- |
|
574 * \brief Crop stage |
|
575 * |
|
576 * \param context Context |
|
577 * \param element Element |
|
578 *----------------------------------------------------------------------------*/ |
|
579 OWF_API_CALL void |
|
580 WFC_Pipeline_ExecuteCropStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state) |
|
581 { |
|
582 OWF_RECTANGLE sourceRect, |
|
583 cropRect; |
|
584 |
|
585 DPRINT(("WFC_Pipeline_ExecuteCropStage")); |
|
586 |
|
587 if (NULL == context || NULL == state) |
|
588 { |
|
589 DPRINT(("WFC_Context_ExecuteCropStage: context = %p, state = %p", |
|
590 context, state)); |
|
591 } |
|
592 else |
|
593 { |
|
594 |
|
595 /* Source rectangle */ |
|
596 OWF_Rect_Set(&sourceRect, |
|
597 state->oversizedCropRect.x, state->oversizedCropRect.y, |
|
598 state->oversizedCropRect.width, state->oversizedCropRect.height); |
|
599 |
|
600 /* cropped source size - supports oversized integer and 1 pixel boundary */ |
|
601 OWF_Rect_Set(&cropRect, |
|
602 0, 0, |
|
603 state->oversizedCropRect.width, state->oversizedCropRect.height); |
|
604 |
|
605 OWF_Image_Blit(state->croppedSourceImage, &cropRect, |
|
606 state->convertedSourceImage, &sourceRect); |
|
607 } |
|
608 } |
|
609 |
|
610 /*--------------------------------------------------------------------------- |
|
611 * \brief Flip stage |
|
612 * |
|
613 * \param context Context |
|
614 * \param element Element |
|
615 *----------------------------------------------------------------------------*/ |
|
616 OWF_API_CALL void |
|
617 WFC_Pipeline_ExecuteFlipStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state) |
|
618 { |
|
619 OWF_FLIP_DIRECTION flipping; |
|
620 |
|
621 if (NULL == context || NULL == state) |
|
622 { |
|
623 DPRINT(("WFC_Context_ExecuteFlipStage: context = %p, state = %p", |
|
624 context, state)); |
|
625 } |
|
626 else |
|
627 { |
|
628 OWF_ASSERT(state); |
|
629 flipping = state->sourceFlip > 0.0f ? OWF_FLIP_VERTICALLY |
|
630 : OWF_FLIP_NONE; |
|
631 |
|
632 OWF_Image_Flip(state->flippedSourceImage, flipping); |
|
633 } |
|
634 } |
|
635 |
|
636 /*--------------------------------------------------------------------------- |
|
637 * \brief Rotation stage |
|
638 * |
|
639 * \param context Context |
|
640 * \param element Element |
|
641 *----------------------------------------------------------------------------*/ |
|
642 OWF_API_CALL void |
|
643 WFC_Pipeline_ExecuteRotationStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state) |
|
644 { |
|
645 OWF_ROTATION rot = OWF_ROTATION_0; |
|
646 OWF_RECTANGLE rect; |
|
647 WFCRotation rotation; |
|
648 |
|
649 |
|
650 if (NULL == context || NULL == state) |
|
651 { |
|
652 DPRINT(("WFC_Context_ExecuteRotationStage: context = %p, state = %p", |
|
653 context, state)); |
|
654 return; |
|
655 } |
|
656 OWF_ASSERT(state); |
|
657 |
|
658 rotation = state->rotation; |
|
659 DPRINT((" Element rotation = %d", rotation)); |
|
660 |
|
661 switch (rotation) |
|
662 { |
|
663 case WFC_ROTATION_0: |
|
664 { |
|
665 return; /* Rotate copies back into input buffer so just skip */ |
|
666 } |
|
667 |
|
668 case WFC_ROTATION_90: |
|
669 { |
|
670 rot = OWF_ROTATION_90; |
|
671 break; |
|
672 } |
|
673 |
|
674 case WFC_ROTATION_180: |
|
675 { |
|
676 rot = OWF_ROTATION_180; |
|
677 break; |
|
678 } |
|
679 |
|
680 case WFC_ROTATION_270: |
|
681 { |
|
682 rot = OWF_ROTATION_270; |
|
683 break; |
|
684 } |
|
685 |
|
686 default: |
|
687 { |
|
688 OWF_ASSERT(0); |
|
689 } |
|
690 } |
|
691 |
|
692 /* rotate the the image using rotatedSourceIntermediateImage */ |
|
693 OWF_Image_Rotate(state->rotatedSourceIntermediateImage, |
|
694 state->flippedSourceImage, |
|
695 rot); |
|
696 |
|
697 /* blit rotated image back to original image buffer */ |
|
698 rect.x = 0; |
|
699 rect.y = 0; |
|
700 rect.width = state->rotatedSourceIntermediateImage->width; |
|
701 rect.height = state->rotatedSourceIntermediateImage->height; |
|
702 |
|
703 DPRINT((" Source image dimensions after rotation = %dx%d", |
|
704 rect.width, rect.height)); |
|
705 |
|
706 OWF_Image_Blit(state->rotatedSourceImage, |
|
707 &rect, |
|
708 state->rotatedSourceIntermediateImage, |
|
709 &rect); |
|
710 |
|
711 } |
|
712 |
|
713 /*--------------------------------------------------------------------------- |
|
714 * \brief Scaling stage |
|
715 * |
|
716 * \param context Context |
|
717 * \param element Element |
|
718 *----------------------------------------------------------------------------*/ |
|
719 OWF_API_CALL void |
|
720 WFC_Pipeline_ExecuteScalingStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state) |
|
721 { |
|
722 OWF_RECTANGLE scaledRect, |
|
723 cropRect; |
|
724 OWF_FILTERING filteringMode = OWF_FILTER_POINT_SAMPLING; |
|
725 WFCScaleFilter filter; |
|
726 |
|
727 DPRINT(("WFC_Context_ExecuteScalingStage(%p,%p)", context, state)); |
|
728 |
|
729 if (NULL == context || NULL == state) |
|
730 { |
|
731 DPRINT(("WFC_Context_ExecuteScalingStage: context = %p, state = %p", |
|
732 context, state)); |
|
733 return; |
|
734 } |
|
735 |
|
736 OWF_ASSERT(state); |
|
737 |
|
738 filter = state->sourceScaleFilter; |
|
739 |
|
740 switch (filter) |
|
741 { |
|
742 case WFC_SCALE_FILTER_NONE: |
|
743 case WFC_SCALE_FILTER_FASTER: |
|
744 { |
|
745 filteringMode = OWF_FILTER_POINT_SAMPLING; |
|
746 DPRINT((" Using point-sampling filter")); |
|
747 break; |
|
748 } |
|
749 case WFC_SCALE_FILTER_BETTER: |
|
750 { |
|
751 filteringMode = OWF_FILTER_BILINEAR; |
|
752 DPRINT((" Using bilinear filter")); |
|
753 break; |
|
754 } |
|
755 |
|
756 case WFC_SCALE_FILTER_FORCE_32BIT: |
|
757 { |
|
758 /* To shut the compiler up -- not a valid filtering mode. |
|
759 * Validity is ensured when the filter attribute value |
|
760 * is set, thus it shouldn't have this value ever. */ |
|
761 OWF_ASSERT(0); |
|
762 break; |
|
763 } |
|
764 } |
|
765 |
|
766 OWF_Rect_Set(&cropRect, 1, 1, |
|
767 state->rotatedSourceImage->width - EXTRA_PIXEL_BOUNDARY, |
|
768 state->rotatedSourceImage->height - EXTRA_PIXEL_BOUNDARY); |
|
769 |
|
770 OWF_Rect_Set(&scaledRect, 0, 0, state->destinationRect[2], state->destinationRect[3]); |
|
771 |
|
772 if ( scaledRect.width != state->transformedSourceRect[2] |
|
773 || scaledRect.height != state->transformedSourceRect[3] |
|
774 || state->sourceRect[0] != floor(state->sourceRect[0]) |
|
775 || state->sourceRect[1] != floor(state->sourceRect[1]) |
|
776 ) |
|
777 { |
|
778 /* scale the image */ |
|
779 OWF_Image_Stretch(state->scaledSourceImage, &scaledRect, |
|
780 state->rotatedSourceImage, state->transformedSourceRect, |
|
781 filteringMode); |
|
782 } |
|
783 else |
|
784 { |
|
785 /* 1:1 copy, no need to scale */ |
|
786 OWF_Image_Blit(state->scaledSourceImage, &scaledRect, |
|
787 state->rotatedSourceImage, &cropRect); |
|
788 } |
|
789 |
|
790 } |
|
791 |
|
792 /*--------------------------------------------------------------------------- |
|
793 * \brief Blending stage |
|
794 * |
|
795 * \param context Context |
|
796 * \param element Element |
|
797 *----------------------------------------------------------------------------*/ |
|
798 OWF_API_CALL void |
|
799 WFC_Pipeline_ExecuteBlendingStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state) |
|
800 { |
|
801 OWF_TRANSPARENCY blendMode = OWF_TRANSPARENCY_NONE; |
|
802 WFCbitfield transparency = 0; |
|
803 |
|
804 DPRINT(("WFC_Pipeline_ExecuteBlendingStage")); |
|
805 |
|
806 if (NULL == context || NULL == state) |
|
807 { |
|
808 return; |
|
809 } |
|
810 |
|
811 DPRINT((" context = %d, state = %d", |
|
812 context->handle, state)); |
|
813 |
|
814 OWF_ASSERT(state); |
|
815 |
|
816 transparency = state->transparencyTypes; |
|
817 blendMode = OWF_TRANSPARENCY_NONE; |
|
818 |
|
819 if (transparency & WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA) |
|
820 { |
|
821 blendMode = (OWF_TRANSPARENCY)(blendMode|OWF_TRANSPARENCY_GLOBAL_ALPHA); |
|
822 } |
|
823 |
|
824 if (transparency & WFC_TRANSPARENCY_SOURCE) |
|
825 { |
|
826 OWF_Image_PremultiplyAlpha(state->scaledSourceImage); |
|
827 blendMode = (OWF_TRANSPARENCY)(blendMode|OWF_TRANSPARENCY_SOURCE_ALPHA); |
|
828 } |
|
829 |
|
830 if ((transparency & WFC_TRANSPARENCY_MASK) && state->originalMaskImage) |
|
831 { |
|
832 blendMode = (OWF_TRANSPARENCY)(blendMode|OWF_TRANSPARENCY_MASK); |
|
833 } |
|
834 |
|
835 OWF_Image_Blend(&state->blendInfo, blendMode); |
|
836 } |