diff -r e70851cd9e5e -r a3f46bb01be2 holdingarea/vg/2D_OpenVG_1_1_SF/ri/src/sfDynamicBlitter.cpp --- a/holdingarea/vg/2D_OpenVG_1_1_SF/ri/src/sfDynamicBlitter.cpp Thu Sep 16 12:43:44 2010 +0100 +++ b/holdingarea/vg/2D_OpenVG_1_1_SF/ri/src/sfDynamicBlitter.cpp Mon Sep 20 14:29:05 2010 +0100 @@ -1,217 +1,217 @@ -/* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and /or associated documentation files - * (the "Materials "), to deal in the Materials without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Materials, - * and to permit persons to whom the Materials are 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 Materials. - * - * THE MATERIALS ARE 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 MATERIALS OR - * THE USE OR OTHER DEALINGS IN THE MATERIALS. - */ - -#include "sfDynamicBlitter.h" - -#ifndef __SFBLITTER_H -# include "sfBlitter.h" -#endif - -#ifndef __SFMASK_H -# include "sfMask.h" -#endif - -namespace OpenVGRI { - -RI_INLINE static bool maskOperationRequiresLoad(VGMaskOperation op) -{ - switch(op) - { - case VG_CLEAR_MASK: - case VG_FILL_MASK: - case VG_SET_MASK: - return false; - default: - RI_ASSERT(op == VG_UNION_MASK || op == VG_INTERSECT_MASK || op == VG_SUBTRACT_MASK); - return true; - } -} - -/** - * \brief Blit rectangular areas between similar or different color format buffers. - * \note Implementation is structured so that the per-pixel branches are minimized - * even if dynamic compilation is not in use. - * \todo For some reason the completely generic integer conversion does not optimize - * fully run-time. Check what causes this! - */ -void executeBlitter(const DynamicBlitter::BlitSignatureState& state, const DynamicBlitter::BlitUniforms& uniforms) -{ - const void* srcPtr = Image::calculateAddress( - uniforms.src, state.srcDesc.bitsPerPixel, uniforms.srcX, uniforms.srcY, uniforms.srcStride); - void* dstPtr = Image::calculateAddress( - uniforms.dst, state.dstDesc.bitsPerPixel, uniforms.dstX, uniforms.dstY, uniforms.dstStride); - - // The following flag is useful for debugging. Enabling it will hurt performance. -//#define ALWAYS_FORCE_FULL_CONVERSION - - // Currently the data must be byte-aligned for memcpy optimizations: - const int minBpp = RI_INT_MIN(state.srcDesc.bitsPerPixel, state.dstDesc.bitsPerPixel); - const bool byteCopy = minBpp >= 8 ? true : false; - const bool forceFullConversion = state.isMaskOperation || state.unsafeInput || !byteCopy; - -#if !defined(ALWAYS_FORCE_FULL_CONVERSION) - if (state.srcDesc.isZeroConversion(state.dstDesc) && !forceFullConversion) - { - const int fullCopyStride = Image::descriptorToStride(state.srcDesc, uniforms.width); - - if ((uniforms.dstStride != uniforms.srcStride) || (fullCopyStride != uniforms.srcStride)) - { - // memcpy individual scanlines. - const size_t scanLength = (size_t)RI_INT_ABS(Image::descriptorToStride(state.srcDesc, uniforms.width)); - for (RIuint32 i = 0; i < uniforms.height; i++) - { - memcpy(dstPtr, srcPtr, scanLength); - dstPtr = (void*)((RIuint8*)dstPtr + uniforms.dstStride); - srcPtr = (void*)((RIuint8*)srcPtr + uniforms.srcStride); - } - } else - { - // memcpy the whole area - memcpy(dstPtr, srcPtr, uniforms.srcStride * uniforms.height); - } - } else if (state.srcDesc.isShiftConversion(state.dstDesc) && !forceFullConversion) - { - // \todo Separate to function? Replace with pointer read/write & advance. - if (state.srcDesc.isShiftConversionToLower(state.dstDesc)) - { - // Components can be immediately shifted down to lower bit-depth. - for (RIuint32 j = 0; j < uniforms.height; j++) - { - RIuint8* srcStart = (RIuint8*)srcPtr; - RIuint8* dstStart = (RIuint8*)dstPtr; - RIuint32 srcX = uniforms.srcX; - RIuint32 dstX = uniforms.dstX; - for (RIuint32 i = 0; i < uniforms.width; i++) - { - RIuint32 c = Image::readPackedPixelFromAddress(srcPtr, state.srcDesc.bitsPerPixel, srcX); // \todo srcX! - RIuint32 dc = Color::Descriptor::crossConvertToLower(c, state.srcDesc, state.dstDesc); - Image::writePackedPixelToAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX, dc); - - srcPtr = Image::incrementPointer(srcPtr, state.srcDesc.bitsPerPixel, srcX); - dstPtr = (void*)Image::incrementPointer(dstPtr, state.dstDesc.bitsPerPixel, dstX); - - srcX++; - dstX++; - } - srcPtr = (void*)(srcStart + uniforms.srcStride); - dstPtr = (void*)(dstStart + uniforms.dstStride); - } - } - else - { - // Color components require expansion before shifting to destination color-format */ - for (RIuint32 j = 0; j < uniforms.height; j++) - { - RIuint8* srcStart = (RIuint8*)srcPtr; - RIuint8* dstStart = (RIuint8*)dstPtr; - RIuint32 srcX = uniforms.srcX; - RIuint32 dstX = uniforms.dstX; - for (RIuint32 i = 0; i < uniforms.width; i++) - { - RIuint32 c = Image::readPackedPixelFromAddress(srcPtr, state.srcDesc.bitsPerPixel, srcX); - IntegerColor ic = IntegerColor(c, state.srcDesc); - ic.expandColor(state.srcDesc); - ic.truncateColor(state.dstDesc); - RIuint32 dc = ic.getPackedColor(state.dstDesc); - Image::writePackedPixelToAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX, dc); - - srcPtr = Image::incrementPointer(srcPtr, state.srcDesc.bitsPerPixel, srcX); - dstPtr = (void*)Image::incrementPointer(dstPtr, state.dstDesc.bitsPerPixel, dstX); - - srcX++; - dstX++; - } - srcPtr = (void*)(srcStart + uniforms.srcStride); - dstPtr = (void*)(dstStart + uniforms.dstStride); - } - } - } else -#endif - { - /* This block should handle the rest (and all) of the color-conversion cases. */ - for (RIuint32 j = 0; j < uniforms.height; j++) - { - RIuint8* srcStart = (RIuint8*)srcPtr; - RIuint8* dstStart = (RIuint8*)dstPtr; - RIuint32 srcX = uniforms.srcX; - RIuint32 dstX = uniforms.dstX; - for (RIuint32 i = 0; i < uniforms.width; i++) - { - RIuint32 c = Image::readPackedPixelFromAddress(srcPtr, state.srcDesc.bitsPerPixel, srcX); - IntegerColor ic; - RIuint32 dc; - - if (!state.isMaskOperation) - { - ic = IntegerColor(c, state.srcDesc); - if (state.unsafeInput) - ic.clampToAlpha(); - - ic.convertToFrom(state.dstDesc, state.srcDesc, false); - dc = ic.getPackedColor(state.dstDesc); - } - else - { - // Apply the given mask operation between two surfaces. - IntegerColor id; - - if (maskOperationRequiresLoad(state.maskOperation)) - { - ic.fromPackedMask(c, state.srcDesc); - ic.expandMask(state.srcDesc); - - IntegerColor id; - - RIuint32 d = Image::readPackedPixelFromAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX); - id.fromPackedMask(d, state.dstDesc); - id.expandColor(state.dstDesc); - - RIuint32 coverage = ic.a + (ic.a >> 7); - ic = intMaskOperation(coverage, id, state.maskOperation); - } - else - { - // Other ops handled with memset, not blitter - RI_ASSERT(state.maskOperation == VG_SET_MASK); - ic.fromPackedMask(c, state.srcDesc); - //ic.expandMask(state.srcDesc); - ic.convertToFrom(state.dstDesc, state.srcDesc, true); - } - dc = ic.getPackedMaskColor(state.dstDesc); - } - - Image::writePackedPixelToAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX, dc); - - srcPtr = Image::incrementPointer(srcPtr, state.srcDesc.bitsPerPixel, srcX); - dstPtr = (void*)Image::incrementPointer(dstPtr, state.dstDesc.bitsPerPixel, dstX); - - srcX++; - dstX++; - } - srcPtr = (void*)(srcStart + uniforms.srcStride); - dstPtr = (void*)(dstStart + uniforms.dstStride); - } - } -} - -} - +/* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and /or associated documentation files + * (the "Materials "), to deal in the Materials without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Materials, + * and to permit persons to whom the Materials are 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 Materials. + * + * THE MATERIALS ARE 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 MATERIALS OR + * THE USE OR OTHER DEALINGS IN THE MATERIALS. + */ + +#include "sfDynamicBlitter.h" + +#ifndef __SFBLITTER_H +# include "sfBlitter.h" +#endif + +#ifndef __SFMASK_H +# include "sfMask.h" +#endif + +namespace OpenVGRI { + +RI_INLINE static bool maskOperationRequiresLoad(VGMaskOperation op) +{ + switch(op) + { + case VG_CLEAR_MASK: + case VG_FILL_MASK: + case VG_SET_MASK: + return false; + default: + RI_ASSERT(op == VG_UNION_MASK || op == VG_INTERSECT_MASK || op == VG_SUBTRACT_MASK); + return true; + } +} + +/** + * \brief Blit rectangular areas between similar or different color format buffers. + * \note Implementation is structured so that the per-pixel branches are minimized + * even if dynamic compilation is not in use. + * \todo For some reason the completely generic integer conversion does not optimize + * fully run-time. Check what causes this! + */ +void executeBlitter(const DynamicBlitter::BlitSignatureState& state, const DynamicBlitter::BlitUniforms& uniforms) +{ + const void* srcPtr = Image::calculateAddress( + uniforms.src, state.srcDesc.bitsPerPixel, uniforms.srcX, uniforms.srcY, uniforms.srcStride); + void* dstPtr = Image::calculateAddress( + uniforms.dst, state.dstDesc.bitsPerPixel, uniforms.dstX, uniforms.dstY, uniforms.dstStride); + + // The following flag is useful for debugging. Enabling it will hurt performance. +//#define ALWAYS_FORCE_FULL_CONVERSION + + // Currently the data must be byte-aligned for memcpy optimizations: + const int minBpp = RI_INT_MIN(state.srcDesc.bitsPerPixel, state.dstDesc.bitsPerPixel); + const bool byteCopy = minBpp >= 8 ? true : false; + const bool forceFullConversion = state.isMaskOperation || state.unsafeInput || !byteCopy; + +#if !defined(ALWAYS_FORCE_FULL_CONVERSION) + if (state.srcDesc.isZeroConversion(state.dstDesc) && !forceFullConversion) + { + const int fullCopyStride = Image::descriptorToStride(state.srcDesc, uniforms.width); + + if ((uniforms.dstStride != uniforms.srcStride) || (fullCopyStride != uniforms.srcStride)) + { + // memcpy individual scanlines. + const size_t scanLength = (size_t)RI_INT_ABS(Image::descriptorToStride(state.srcDesc, uniforms.width)); + for (RIuint32 i = 0; i < uniforms.height; i++) + { + memcpy(dstPtr, srcPtr, scanLength); + dstPtr = (void*)((RIuint8*)dstPtr + uniforms.dstStride); + srcPtr = (void*)((RIuint8*)srcPtr + uniforms.srcStride); + } + } else + { + // memcpy the whole area + memcpy(dstPtr, srcPtr, uniforms.srcStride * uniforms.height); + } + } else if (state.srcDesc.isShiftConversion(state.dstDesc) && !forceFullConversion) + { + // \todo Separate to function? Replace with pointer read/write & advance. + if (state.srcDesc.isShiftConversionToLower(state.dstDesc)) + { + // Components can be immediately shifted down to lower bit-depth. + for (RIuint32 j = 0; j < uniforms.height; j++) + { + RIuint8* srcStart = (RIuint8*)srcPtr; + RIuint8* dstStart = (RIuint8*)dstPtr; + RIuint32 srcX = uniforms.srcX; + RIuint32 dstX = uniforms.dstX; + for (RIuint32 i = 0; i < uniforms.width; i++) + { + RIuint32 c = Image::readPackedPixelFromAddress(srcPtr, state.srcDesc.bitsPerPixel, srcX); // \todo srcX! + RIuint32 dc = Color::Descriptor::crossConvertToLower(c, state.srcDesc, state.dstDesc); + Image::writePackedPixelToAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX, dc); + + srcPtr = Image::incrementPointer(srcPtr, state.srcDesc.bitsPerPixel, srcX); + dstPtr = (void*)Image::incrementPointer(dstPtr, state.dstDesc.bitsPerPixel, dstX); + + srcX++; + dstX++; + } + srcPtr = (void*)(srcStart + uniforms.srcStride); + dstPtr = (void*)(dstStart + uniforms.dstStride); + } + } + else + { + // Color components require expansion before shifting to destination color-format */ + for (RIuint32 j = 0; j < uniforms.height; j++) + { + RIuint8* srcStart = (RIuint8*)srcPtr; + RIuint8* dstStart = (RIuint8*)dstPtr; + RIuint32 srcX = uniforms.srcX; + RIuint32 dstX = uniforms.dstX; + for (RIuint32 i = 0; i < uniforms.width; i++) + { + RIuint32 c = Image::readPackedPixelFromAddress(srcPtr, state.srcDesc.bitsPerPixel, srcX); + IntegerColor ic = IntegerColor(c, state.srcDesc); + ic.expandColor(state.srcDesc); + ic.truncateColor(state.dstDesc); + RIuint32 dc = ic.getPackedColor(state.dstDesc); + Image::writePackedPixelToAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX, dc); + + srcPtr = Image::incrementPointer(srcPtr, state.srcDesc.bitsPerPixel, srcX); + dstPtr = (void*)Image::incrementPointer(dstPtr, state.dstDesc.bitsPerPixel, dstX); + + srcX++; + dstX++; + } + srcPtr = (void*)(srcStart + uniforms.srcStride); + dstPtr = (void*)(dstStart + uniforms.dstStride); + } + } + } else +#endif + { + /* This block should handle the rest (and all) of the color-conversion cases. */ + for (RIuint32 j = 0; j < uniforms.height; j++) + { + RIuint8* srcStart = (RIuint8*)srcPtr; + RIuint8* dstStart = (RIuint8*)dstPtr; + RIuint32 srcX = uniforms.srcX; + RIuint32 dstX = uniforms.dstX; + for (RIuint32 i = 0; i < uniforms.width; i++) + { + RIuint32 c = Image::readPackedPixelFromAddress(srcPtr, state.srcDesc.bitsPerPixel, srcX); + IntegerColor ic; + RIuint32 dc; + + if (!state.isMaskOperation) + { + ic = IntegerColor(c, state.srcDesc); + if (state.unsafeInput) + ic.clampToAlpha(); + + ic.convertToFrom(state.dstDesc, state.srcDesc, false); + dc = ic.getPackedColor(state.dstDesc); + } + else + { + // Apply the given mask operation between two surfaces. + IntegerColor id; + + if (maskOperationRequiresLoad(state.maskOperation)) + { + ic.fromPackedMask(c, state.srcDesc); + ic.expandMask(state.srcDesc); + + IntegerColor id; + + RIuint32 d = Image::readPackedPixelFromAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX); + id.fromPackedMask(d, state.dstDesc); + id.expandColor(state.dstDesc); + + RIuint32 coverage = ic.a + (ic.a >> 7); + ic = intMaskOperation(coverage, id, state.maskOperation); + } + else + { + // Other ops handled with memset, not blitter + RI_ASSERT(state.maskOperation == VG_SET_MASK); + ic.fromPackedMask(c, state.srcDesc); + //ic.expandMask(state.srcDesc); + ic.convertToFrom(state.dstDesc, state.srcDesc, true); + } + dc = ic.getPackedMaskColor(state.dstDesc); + } + + Image::writePackedPixelToAddress(dstPtr, state.dstDesc.bitsPerPixel, dstX, dc); + + srcPtr = Image::incrementPointer(srcPtr, state.srcDesc.bitsPerPixel, srcX); + dstPtr = (void*)Image::incrementPointer(dstPtr, state.dstDesc.bitsPerPixel, dstX); + + srcX++; + dstX++; + } + srcPtr = (void*)(srcStart + uniforms.srcStride); + dstPtr = (void*)(dstStart + uniforms.dstStride); + } + } +} + +} +