/**************************************************************************** * * The MIT License (MIT) * * Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * 'Software'), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject * to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS 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 NON-INFRINGEMENT. * IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS 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 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * *****************************************************************************/ #include #include #include #include #include #include #include "vg_lite.h" #include "vg_lite_kernel.h" #if !defined(VG_DRIVER_SINGLE_THREAD) #include "vg_lite_os.h" #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ #if (VG_RENDER_TEXT==1) #include "vg_lite_text.h" #endif /* VG_RENDER_TEXT */ #include "vg_lite_flat.h" /* * Stop IAR compiler from warning about implicit conversions from float to * double */ #if (defined(__ICCARM__)) #pragma diag_suppress = Pa205 #endif /* This is the function to call from the VGLite driver to interface with the GPU. */ vg_lite_error_t vg_lite_kernel(vg_lite_kernel_command_t command, void * data); /*** Command buffer dump ***/ #ifndef DUMP_COMMAND #define DUMP_COMMAND 0 #endif #ifndef DUMP_IMAGE #define DUMP_IMAGE 0 #else #ifndef DUMP_COMMAND #define DUMP_COMMAND 0 #endif #ifndef DUMP_IMAGE #define DUMP_IMAGE 0 #endif #endif #define VG_TARGET_FC_DUMP 0 /* Fast clear is not used by default,if SOC should use this ,set this macro to 1. */ #ifndef VG_TARGET_FAST_CLEAR #define VG_TARGET_FAST_CLEAR 0 #endif /* VG_TARGET_FAST_CLEAR */ #if DUMP_COMMAND || DUMP_IMAGE #ifdef __linux__ #include #endif #endif #if defined(VG_DRIVER_SINGLE_THREAD) /*** Global Context Access ***/ #define GET_CONTEXT() &s_context #endif /* VG_DRIVER_SINGLE_THREAD */ /*** Command buffer configurations, double buffer support ***/ #define VG_LITE_COMMAND_BUFFER_SIZE (64 << 10) #define CMDBUF_BUFFER(context) (context).command_buffer[(context).command_buffer_current] #define CMDBUF_INDEX(context) (context).command_buffer_current #define CMDBUF_SIZE(context) (context).command_buffer_size #define CMDBUF_OFFSET(context) (context).command_offset[(context).command_buffer_current] #define CMDBUF_SWAP(context) (context).command_buffer_current = \ ((context).command_buffer_current + 1) % CMDBUF_COUNT #if !defined(VG_DRIVER_SINGLE_THREAD) #ifndef CMDBUF_IN_QUEUE #define CMDBUF_IN_QUEUE(context, id) \ (vg_lite_os_event_state(&(context)->async_event[(id)]) == VG_LITE_IN_QUEUE) #endif #define RESERVE_BYTES_IN_CMDBUF(context) \ {\ ((uint32_t *) (CMDBUF_BUFFER((context)) + CMDBUF_OFFSET((context))))[0] = VG_LITE_STATE(0x0a00);\ ((uint32_t *) (CMDBUF_BUFFER((context)) + CMDBUF_OFFSET((context))))[1] = 0;\ CMDBUF_OFFSET((context)) += 8;\ } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ #define VG_LITE_RETURN_ERROR(func) \ if ((error = func) != VG_LITE_SUCCESS) \ return error #define VG_LITE_BREAK_ERROR(func) \ if ((error = func) != VG_LITE_SUCCESS) \ break #define VG_LITE_ERROR_HANDLER(func) \ if ((error = func) != VG_LITE_SUCCESS) \ goto ErrorHandler /*** Command macros ***/ #define VG_LITE_END(interrupt) (0x00000000 | interrupt) #define VG_LITE_SEMAPHORE(id) (0x10000000 | id) #define VG_LITE_STALL(id) (0x20000000 | id) #define VG_LITE_STATE(address) (0x30010000 | address) #define VG_LITE_STATES(count, address) (0x30000000 | ((count) << 16) | address) #define VG_LITE_DATA(count) (0x40000000 | count) #define VG_LITE_CALL(count) (0x60000000 | count) #define VG_LITE_RETURN() (0x70000000) #define VG_LITE_NOP() (0x80000000) /*** Shortcuts. ***/ #define A(color) (color) >> 24 #define R(color) ((color) & 0x00ff0000) >> 16 #define G(color) ((color) & 0x0000ff00) >> 8 #define B(color) ((color) & 0xff) #define ARGB(a, r, g, b) ((a) << 24) | ((r) << 16) | ((g) << 8 ) | (b) #define ARGB4(a, r, g, b) (((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | (((g) & 0xf0)) | ((b) >> 4) #define FC_BURST_BYTES 64 #define FC_BIT_TO_BYTES 64 #define MIN(a, b) ((a) > (b) ? (b) : (a)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) static uint32_t command_buffer_size = VG_LITE_COMMAND_BUFFER_SIZE; #define FORMAT_ALIGNMENT(stride,align) \ { \ if((stride) % (align) != 0) \ return VG_LITE_INVALID_ARGUMENT; \ return VG_LITE_SUCCESS; \ } #define DEST_ALIGNMENT_LIMITATION 64 /* To match hardware alignment requirement */ #if !defined(VG_DRIVER_SINGLE_THREAD) #define TS_STATE_COUNT 20 /* Initial state count for tessellation buffer. */ #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ #define MATRIX_ROWS 3 #define GET_MATRIX_VALUES(Pointer) ((float *) (Pointer)) #define MAT(Matrix, Row, Column) (GET_MATRIX_VALUES(Matrix)[Row * MATRIX_ROWS + Column]) #define COLOR_FROM_RAMP(ColorRamp) (((vg_lite_float_t *) ColorRamp) + 1) #define CLAMP(x, min, max) (((x) < (min)) ? (min) : \ ((x) > (max)) ? (max) : (x)) #define LERP(v1, v2, w) ((v1) * (w) + (v2) * (1.0f - (w))) #define PI 3.141592653589793238462643383279502f #define SINF(x) ((vg_lite_float_t) sin(x)) #define COSF(x) ((vg_lite_float_t) cos(x)) #define FABSF(x) ((vg_lite_float_t) fabs(x)) #define SQRTF(x) ((vg_lite_float_t) sqrt(x)) #define CLAMP(x, min, max) (((x) < (min)) ? (min) : \ ((x) > (max)) ? (max) : (x)) #define ACOSF(x) ((vg_lite_float_t) acos(x)) #define FMODF(x, y) ((vg_lite_float_t) fmod((x), (y))) #define CEILF(x) ((vg_lite_float_t) ceil(x)) #define FALSE 0 #define TURE 1 #define SIZEOF(a) \ ( \ (size_t) (sizeof(a)) \ ) typedef uintptr_t UINTPTR_T; #define PTR2SIZE(p) \ ( \ (UINTPTR_T) (p) \ ) #define GETINCREMENT(pointer, datatype_size) \ (datatype_size - (PTR2SIZE(pointer) & (datatype_size - 1))) #define SKIPTODATA(pointer, datatype_size, SIZE) \ /* Determine the increment value. */ \ increment = GETINCREMENT(pointer, datatype_size); \ /* Skip to the data. */ \ pointer += increment; \ SIZE -= increment #define VGSL_GETVALUE(X) \ X = get_value(data_pointer); \ data_pointer += data_type_size; \ size -= data_type_size #define VGSL_GETCOORDXY(X, Y) \ VGSL_GETVALUE(X); \ VGSL_GETVALUE(Y); \ if (is_relative) { X += ox; Y += oy; } #define FLOAT_EPSILON 0.001f #define SWING_NO 0 #define SWING_OUT 1 #define SWING_IN 2 /* Point curve type for generated stroke path. */ #define CURVE_LINE 0 #define CURVE_QUAD_CONTROL 1 #define CURVE_QUAD_ANCHOR 2 #define CURVE_ARC_SCCW 3 #define CURVE_ARC_SCCW_HALF 4 #define FLOAT_PI 3.141592654f #define FLOAT_PI_TWO 6.283185307f #define FLOAT_PI_THREE_QUARTER 2.356194490f #define FLOAT_PI_HALF 1.570796327f #define FLOAT_PI_QUARTER 0.7853981634f #define FLOAT_PI_EIGHTH 0.3926990817f /* cos(PI/8) */ #define FLOAT_COS_PI_EIGHTH 0.9238795325f #define centerX tangentX #define centerY tangentY #define FLOAT_DIFF_EPSILON 0.125f #define FLOAT_SWING_CENTER_RANGE 0.125f #define FLOAT_ANGLE_EPSILON 0.0045f #define FLOAT_ANGLE_EPSILON_COS 0.99999f #define FLOAT_MIN_ARC_ANGLE 0.044f #define FLOAT_MIN_ARC_ANGLE_COS 0.999f /* Float constants. */ #define gcvMAX_POS_FLOAT ((vg_lite_float_t) 3.4028235e+038) #define gcvMAX_NEG_FLOAT ((vg_lite_float_t) -3.4028235e+038) #define FLOAT_MIN gcvMAX_NEG_FLOAT #define FLOAT_MAX gcvMAX_POS_FLOAT #define FLOAT_FAT_LINE_WIDTH 2.5f /* Point flatten type for flattened line segments. */ #define vgcFLATTEN_NO 0 #define vgcFLATTEN_START 1 #define vgcFLATTEN_MIDDLE 2 #define vgcFLATTEN_END 3 /* Command size calculation shortcuts. */ #define COMMANDSIZE(CoordinateCount, CoordinateType) \ ((1+CoordinateCount) * SIZEOF(CoordinateType)) #define ABS(x) (((x) < 0) ? -(x) : (x)) #define EPS 2.2204460492503131e-14 #if !defined(VG_DRIVER_SINGLE_THREAD) /* VG:24 + TS:28 + IM:345 + PE:9 + RS:16 +Debug:2 */ #define STATES_COUNT 424 /* STATES_COUNT size + return command size */ #define CONTEXT_BUFFER_SIZE STATES_COUNT * 2 * 4 + 8 #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ #define UPDATE_BOUNDING_BOX(bbx, point) \ do { \ if ((point).x < (bbx).x) { \ (bbx).width += (bbx).x - (point).x; \ (bbx).x = (point).x; \ } \ if ((point).y < (bbx).y) { \ (bbx).height += (bbx).y - (point).y; \ (bbx).y = (point).y; \ } \ if ((point).x > (bbx).x + (bbx).width) \ (bbx).width = (point).x - (bbx).x; \ if ((point).y > (bbx).y + (bbx).height) \ (bbx).height = (point).y - (bbx).y; \ } while(0) typedef vg_lite_float_t FLOATVECTOR4[4]; typedef struct vg_lite_ftable { uint32_t ftable[gcFEATURE_COUNT]; uint32_t ftflag; } vg_lite_ftable_t; #if !defined(VG_DRIVER_SINGLE_THREAD) typedef struct vg_lite_states { uint32_t state; uint8_t init; }vg_lite_states_t; typedef struct vg_lite_hardware { vg_lite_states_t hw_states[STATES_COUNT]; } vg_lite_hardware_t; static vg_lite_hardware_t hw = {0}; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ typedef struct vg_lite_context { vg_lite_kernel_context_t context; vg_lite_capabilities_t capabilities; uint8_t * command_buffer[CMDBUF_COUNT]; uint32_t command_buffer_size; uint32_t command_offset[CMDBUF_COUNT]; uint32_t command_buffer_current; #if !defined(VG_DRIVER_SINGLE_THREAD) uint8_t * context_buffer[CMDBUF_COUNT]; uint32_t context_buffer_size; uint32_t context_buffer_offset[CMDBUF_COUNT]; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ vg_lite_tsbuffer_info_t tsbuffer; vg_lite_buffer_t * rtbuffer; /* DDRLess: this is used as composing buffer. */ #if VG_TARGET_FAST_CLEAR vg_lite_buffer_t fcBuffer; /* Buffer used for fast clear cache. */ uint32_t clearValue; #endif uint32_t scissor_enabled; #if defined(VG_DRIVER_SINGLE_THREAD) uint32_t scissor_dirty; /* Indicates whether scissor states are changed or not. e.g., scissors[4] or scissor_enabled. */ #endif /* VG_DRIVER_SINGLE_THREAD */ int32_t scissor[4]; /* Scissor area: x, y, width, height. */ #if !defined(VG_DRIVER_SINGLE_THREAD) uint32_t start_offset; uint32_t end_offset; uint32_t ts_init; /* Indicates whether tessellation buffer states are initialized or not. */ uint32_t ts_record[TS_STATE_COUNT]; /* Tessellation buffer initial states record. */ uint32_t ts_init_used; uint32_t ts_init_use; uint32_t ts_dirty; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ uint32_t chip_id; uint32_t chip_rev; uint32_t premultiply_enabled; #if defined(VG_DRIVER_SINGLE_THREAD) uint32_t premultiply_dirty; uint8_t init; #else uint32_t semaphore_id; uint32_t * colors[4]; /* index colors. */ uint32_t clut_dirty[4]; /* clut dirty flag. */ uint32_t index_format; /* check if use index. */ uint32_t clut_used[4]; /* check if used index. */ #endif /* VG_DRIVER_SINGLE_THREAD */ vg_lite_ftable_t s_ftable; } vg_lite_context_t; #if !defined(VG_DRIVER_SINGLE_THREAD) typedef struct vg_lite_tls{ /* currently just contains struct vg_lite_context_t */ vg_lite_context_t t_context; }vg_lite_tls_t; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ typedef struct vg_lite_feature_database{ uint32_t chip_id; uint32_t chip_version; uint32_t cid; uint32_t vg_im_index_format:1; uint32_t vg_pe_premultiply:1; uint32_t vg_border_culling:1; uint32_t vg_rgba2_format:1; uint32_t vg_quality_8x:1; uint32_t vg_radial_gradient:1; uint32_t vg_linear_gradient_ext:1; uint32_t vg_dither:1; uint32_t vg_color_key:1; } vg_lite_feature_database_t; static vg_lite_feature_database_t VGFeatureInfos[] = { /* vg255 */ { GPU_CHIP_ID_GCNanoliteV, /* ChipID */ 0x1311, /* ChipRevision */ 0x404, /* CID */ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ 0x0, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ 0x1, /* gcFEATURE_BIT_VG_BORDER_CULLING */ 0x1, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ 0X0, /* gcFEATURE_BIT_VG_QUALITY_8X */ 0X0, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ 0x0, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ 0x0, /* gcFEATURE_BIT_VG_DITHER */ 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ }, /* vg255 */ { GPU_CHIP_ID_GCNanoliteV, /* ChipID */ 0x1311, /* ChipRevision */ 0x40a, /* CID */ 0x1, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ 0x0, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ 0x1, /* gcFEATURE_BIT_VG_BORDER_CULLING */ 0x1, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ 0X1, /* gcFEATURE_BIT_VG_QUALITY_8X */ 0X0, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ 0x0, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ 0x0, /* gcFEATURE_BIT_VG_DITHER */ 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ }, /* vg255 */ { GPU_CHIP_ID_GCNanoliteV, /* ChipID */ 0x1311, /* ChipRevision */ 0x40b, /* CID */ 0x1, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ 0x0, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ 0x1, /* gcFEATURE_BIT_VG_BORDER_CULLING */ 0x1, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ 0X1, /* gcFEATURE_BIT_VG_QUALITY_8X */ 0X0, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ 0x0, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ 0x0, /* gcFEATURE_BIT_VG_DITHER */ 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ }, /* vg255 */ { GPU_CHIP_ID_GCNanoliteV, /* ChipID */ 0x1311, /* ChipRevision */ 0x40d, /* CID */ 0x1, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ 0x0, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ 0x1, /* gcFEATURE_BIT_VG_BORDER_CULLING */ 0x1, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ 0X1, /* gcFEATURE_BIT_VG_QUALITY_8X */ 0X0, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ 0x0, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ 0x0, /* gcFEATURE_BIT_VG_DITHER */ 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ }, /* vg255 */ { GPU_CHIP_ID_GCNanoliteV, /* ChipID */ 0x1322, /* ChipRevision */ 0x403, /* CID */ 0x1, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ 0x0, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ 0x1, /* gcFEATURE_BIT_VG_BORDER_CULLING */ 0x1, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ 0X1, /* gcFEATURE_BIT_VG_QUALITY_8X */ 0X0, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ 0x0, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ 0x0, /* gcFEATURE_BIT_VG_DITHER */ 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ }, /* vg355 */ { GPU_CHIP_ID_GC355, /* ChipID */ 0x1217, /* ChipRevision */ 0x408, /* CID */ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ 0x1, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ 0x0, /* gcFEATURE_BIT_VG_BORDER_CULLING */ 0x0, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ 0X0, /* gcFEATURE_BIT_VG_QUALITY_8X */ 0X1, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ 0x1, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ 0x1, /* gcFEATURE_BIT_VG_DITHER */ 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ }, /* vg355 */ { GPU_CHIP_ID_GC355, /* ChipID */ 0x1216, /* ChipRevision */ 0x0, /* CID */ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ 0x1, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ 0x0, /* gcFEATURE_BIT_VG_BORDER_CULLING */ 0x0, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ 0X0, /* gcFEATURE_BIT_VG_QUALITY_8X */ 0X1, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ 0x1, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ 0x1, /* gcFEATURE_BIT_VG_DITHER */ 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ }, /* vg355 */ { GPU_CHIP_ID_GC355, /* ChipID */ 0x1215, /* ChipRevision */ 0x0, /* CID */ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ 0x1, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ 0x0, /* gcFEATURE_BIT_VG_BORDER_CULLING */ 0x0, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ 0X0, /* gcFEATURE_BIT_VG_QUALITY_8X */ 0X1, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ 0x1, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ 0x1, /* gcFEATURE_BIT_VG_DITHER */ 0x1, /* gcFEATURE_BIT_VG_COLOR_KEY */ } }; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t s_context = {0}; #endif /* VG_DRIVER_SINGLE_THREAD */ #if DUMP_COMMAND FILE * fp; char filename[30]; #endif int submit_flag = 0; static vg_lite_float_t _GetS8_NS_NB(int8_t * Data) { int8_t x0 = *((int8_t *) Data); vg_lite_float_t x = (vg_lite_float_t) x0; return x; } static vg_lite_float_t _GetS16_NS_NB(int8_t * Data) { int16_t x0 = *((int16_t *) Data); vg_lite_float_t x = (vg_lite_float_t) x0; return x; } static vg_lite_float_t _GetS32_NS_NB(int8_t * Data) { int32_t x0 = *((int32_t *) Data); vg_lite_float_t x = (vg_lite_float_t) x0; return x; } static vg_lite_float_t _GetF_NS_NB(int8_t * Data) { vg_lite_float_t x = *((vg_lite_float_t *) Data); return x; } typedef vg_lite_float_t (* vg_value_getter) (int8_t * Data); typedef struct vg_lite_control_coord { vg_lite_float_t startX; vg_lite_float_t startY; vg_lite_float_t lastX; vg_lite_float_t lastY; vg_lite_float_t controlX; vg_lite_float_t controlY; } vg_lite_control_coord_t; static uint32_t _commandSize_float[] = { COMMANDSIZE(0, vg_lite_float_t), /* 0: END */ COMMANDSIZE(0, vg_lite_float_t), /* 1: CLOSE */ COMMANDSIZE(2, vg_lite_float_t), /* 2: MOVE */ COMMANDSIZE(2, vg_lite_float_t), /* 3: MOVE_REL */ COMMANDSIZE(2, vg_lite_float_t), /* 4: LINE */ COMMANDSIZE(2, vg_lite_float_t), /* 5: LINE_REL */ COMMANDSIZE(4, vg_lite_float_t), /* 6: QUAD */ COMMANDSIZE(4, vg_lite_float_t), /* 7: QUAD_REL */ COMMANDSIZE(6, vg_lite_float_t), /* 8: CUBIC */ COMMANDSIZE(6, vg_lite_float_t), /* 9: CUBIC_REL */ COMMANDSIZE(5, vg_lite_float_t), /* 10: SCCWARC */ COMMANDSIZE(5, vg_lite_float_t), /* 11: SCCWARC_REL */ COMMANDSIZE(5, vg_lite_float_t), /* 12: SCWARC */ COMMANDSIZE(5, vg_lite_float_t), /* 13: SCWARC_REL */ COMMANDSIZE(5, vg_lite_float_t), /* 14: LCCWARC */ COMMANDSIZE(5, vg_lite_float_t), /* 15: LCCWARC_REL */ COMMANDSIZE(5, vg_lite_float_t), /* 16: LCWARC */ COMMANDSIZE(5, vg_lite_float_t), /* 17: LCWARC_REL */ }; /* Special sqrt(1.0f + x) for quick calculation when 0 <= x <= 1. */ static vg_lite_float_t _Sqrt( vg_lite_float_t X ) { vg_lite_float_t x = X; vg_lite_float_t s = 1.0f; s += x * 0.5f; x *= X; s -= x * 0.12445995211601257f; x *= X; s += x * 0.058032196015119553f; x *= X; s -= x * 0.025314478203654289f; x *= X; s += x * 0.0059584137052297592f; return s; } static vg_lite_error_t _set_point_tangent( vg_lite_path_point_ptr Point, vg_lite_float_t Dx, vg_lite_float_t Dy ) { if(!Point) return VG_LITE_INVALID_ARGUMENT; if (Dx == 0.0f) { if (Dy == 0.0f) { if (Point->prev) { Point->length = 0.0f; Point->tangentX = Point->prev->tangentX; Point->tangentY = Point->prev->tangentY; } else { Point->length = 0.0f; Point->tangentX = 0.0f; Point->tangentY = 0.0f; } } else { Point->tangentX = 0.0f; if (Dy > 0.0f) { Point->length = Dy; Point->tangentY = 1.0f; } else { Point->length = -Dy; Point->tangentY = -1.0f; } } } else if (Dy == 0.0f) { Point->tangentY = 0.0f; if (Dx > 0.0f) { Point->length = Dx; Point->tangentX = 1.0f; } else { Point->length = -Dx; Point->tangentX = -1.0f; } } else { vg_lite_float_t l, tx, ty; vg_lite_float_t dx, dy; vg_lite_float_t t, t2; dx = (Dx >= 0.0f ? Dx : -Dx); dy = (Dy >= 0.0f ? Dy : -Dy); if (dx >= dy) { t = dy / dx; t2 = t * t; l = _Sqrt(t2); Point->length = l * dx; tx = 1.0f / l; ty = tx * t; } else { t = dx / dy; t2 = t * t; l = _Sqrt(t2); Point->length = l * dy; ty = 1.0f / l; tx = ty * t; } if (Dx < 0.0f) tx = -tx; if (Dy < 0.0f) ty = -ty; tx = CLAMP(tx, -1.0f, 1.0f); ty = CLAMP(ty, -1.0f, 1.0f); Point->tangentX = tx; Point->tangentY = ty; } return VG_LITE_SUCCESS; } vg_lite_error_t _add_point_to_point_list_wdelta( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_float_t X, vg_lite_float_t Y, vg_lite_float_t DX, vg_lite_float_t DY, uint8_t flatten_flag ) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_path_point_ptr last_point; vg_lite_path_point_ptr point; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; last_point = stroke_conversion->path_last_point; point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); if(!point) return VG_LITE_OUT_OF_RESOURCES; memset(point, 0, sizeof(*point)); point->x = X; point->y = Y; point->flatten_flag = flatten_flag; /* Calculate tangent for last_point. */ VG_LITE_ERROR_HANDLER(_set_point_tangent(last_point, DX, DY)); last_point->next = point; stroke_conversion->path_last_point = point; point->prev = last_point; stroke_conversion->point_count++; return error; ErrorHandler: vg_lite_os_free(point); point = NULL; return error; } vg_lite_error_t _add_point_to_point_list( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_float_t X, vg_lite_float_t Y, uint8_t flatten_flag ) { vg_lite_error_t status = VG_LITE_SUCCESS; vg_lite_path_point_ptr last_point; vg_lite_path_point_ptr point; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; last_point = stroke_conversion->path_last_point; if (last_point == NULL) { point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); if(!point) return VG_LITE_OUT_OF_RESOURCES; memset(point, 0, sizeof(*point)); point->x = X; point->y = Y; point->flatten_flag = flatten_flag; point->prev = NULL; stroke_conversion->path_last_point = stroke_conversion->path_point_list = point; stroke_conversion->point_count++; status = VG_LITE_SUCCESS; } else { vg_lite_float_t dX = X - last_point->x; vg_lite_float_t dY = Y - last_point->y; vg_lite_float_t deltaX = (dX >= 0.0f ? dX : -dX); vg_lite_float_t deltaY = (dY >= 0.0f ? dY : -dY); /* Check for degenerated line. */ if (deltaX == 0.0f && deltaY == 0.0f) { /* Skip degenerated line. */ status = VG_LITE_SUCCESS; goto ErrorHandler; } if (deltaX < FLOAT_EPSILON && deltaY < FLOAT_EPSILON) { vg_lite_float_t ratioX, ratioY; if (deltaX == 0.0f) { ratioX = 0.0f; } else if (X == 0.0f) { ratioX = deltaX; } else { ratioX = deltaX / X; if (ratioX < 0.0f) ratioX = -ratioX; } if (deltaY == 0.0f) { ratioY = 0.0f; } else if (Y == 0.0f) { ratioY = deltaY; } else { ratioY = deltaY / Y; if (ratioY < 0.0f) ratioY = -ratioY; } if (ratioX < 1.0e-6f && ratioY < 1.0e-6f) { /* Skip degenerated line. */ status = VG_LITE_SUCCESS; goto ErrorHandler; } } status = _add_point_to_point_list_wdelta(stroke_conversion, X, Y, dX, dY, flatten_flag); } ErrorHandler: return status; } static vg_lite_error_t _flatten_path( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_path_t *path ) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t increment; uint8_t is_relative; uint32_t size; uint32_t path_command; uint32_t prev_command; uint8_t data_type_size; int8_t* data_pointer = NULL; vg_lite_float_t sx, sy; vg_lite_float_t ox, oy; vg_lite_float_t x0, y0, x1, y1, x2, y2; vg_value_getter get_value = NULL; if(!stroke_conversion || !path) return VG_LITE_INVALID_ARGUMENT; sx = sy = ox = oy = 0.0f; prev_command = VLC_OP_MOVE; /* Determine the data size. */ size = path->path_length; /* Determine the beginning of the path data. */ data_pointer = (int8_t*)path->path; /* Select the data picker. */ switch (path->format) { case VG_LITE_S8: data_type_size = 1; get_value = _GetS8_NS_NB; break; case VG_LITE_S16: data_type_size = 2; get_value = _GetS16_NS_NB; break; case VG_LITE_S32: data_type_size = 4; get_value = _GetS32_NS_NB; break; case VG_LITE_FP32: data_type_size = 4; get_value = _GetF_NS_NB; break; default: error = VG_LITE_INVALID_ARGUMENT; goto ErrorHandler; } /* Add an extra gcvVGCMD_MOVE 0.0 0.0 to handle the case the first command is not gcvVGCMD_MOVE. */ if (*data_pointer != VLC_OP_MOVE) { /* Add first point to subpath. */ VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, sx, sy, vgcFLATTEN_NO)); } while (size > 0) { /* Get the command. */ path_command = *data_pointer & 0x1F; /* Assume absolute. */ is_relative = FALSE; switch (path_command) { case VLC_OP_END: /* Skip the command. */ size -= 1; if (prev_command == VLC_OP_END) { /* Continuous gcvVGCMD_CLOSE - do nothing. */ break; } /* Check if subPath is already closed. */ if (ox != sx || oy != sy) { /* Add a line from current point to the first point of current subpath. */ VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, sx, sy,vgcFLATTEN_NO)); } if (stroke_conversion->path_point_list != stroke_conversion->path_last_point) { /* Copy tangent data from first point to last_point. */ vg_lite_path_point_ptr first_point = stroke_conversion->path_point_list; vg_lite_path_point_ptr last_point = stroke_conversion->path_last_point; last_point->length = first_point->length; last_point->tangentX = first_point->tangentX; last_point->tangentY = first_point->tangentY; } else { /* Single point path. */ vg_lite_path_point_ptr point = stroke_conversion->path_point_list; point->tangentX = 0.0f; point->tangentY = 0.0f; point->length = 0.0f; } stroke_conversion->closed = 1; stroke_conversion->path_last_point->next = NULL; break; case VLC_OP_MOVE_REL: is_relative = 1; case VLC_OP_MOVE: /* Indicate the beginning of a new sub-path. */ /* Skip to the data. */ SKIPTODATA(data_pointer, data_type_size, size); VGSL_GETCOORDXY(x0, y0); /* First command is gcvVGCMD_MOVE. */ /* Add first point to subpath. */ VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, x0, y0, vgcFLATTEN_NO)); sx = ox = x0; sy = oy = y0; break; case VLC_OP_LINE_REL: is_relative = 1; case VLC_OP_LINE: /* Skip to the data. */ SKIPTODATA(data_pointer, data_type_size, size); VGSL_GETCOORDXY(x0, y0); /* Add a point to subpath. */ VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, x0, y0, vgcFLATTEN_NO)); ox = x0; oy = y0; break; case VLC_OP_QUAD_REL: is_relative = 1; case VLC_OP_QUAD: /* Skip to the data. */ SKIPTODATA(data_pointer, data_type_size, size); VGSL_GETCOORDXY(x0, y0); VGSL_GETCOORDXY(x1, y1); if ((ox == x0 && oy == y0) && (ox == x1 && oy == y1)) { /* Degenerated Bezier curve. Becomes a point. */ /* Discard zero-length segments. */ } else if ((ox == x0 && oy == y0) || (x0 == x1 && y0 == y1)) { /* Degenerated Bezier curve. Becomes a line. */ /* Add a point to subpath. */ VG_LITE_ERROR_HANDLER(_add_point_to_point_list( stroke_conversion, x1, y1, vgcFLATTEN_NO)); } else { VG_LITE_ERROR_HANDLER(_flatten_quad_bezier(stroke_conversion, ox, oy, x0, y0, x1, y1)); } ox = x1; oy = y1; break; case VLC_OP_CUBIC_REL: is_relative = 1; case VLC_OP_CUBIC: /* Skip to the data. */ SKIPTODATA(data_pointer, data_type_size, size); VGSL_GETCOORDXY(x0, y0); VGSL_GETCOORDXY(x1, y1); VGSL_GETCOORDXY(x2, y2); if ((ox == x0 && oy == y0) && (ox == x1 && oy == y1) && (ox == x2 && oy == y2)) { /* Degenerated Bezier curve. Becomes a point. */ /* Discard zero-length segments. */ } else { VG_LITE_ERROR_HANDLER(_flatten_cubic_bezier(stroke_conversion, ox, oy, x0, y0, x1, y1, x2, y2)); } ox = x2; oy = y2; break; default: error = VG_LITE_INVALID_ARGUMENT; goto ErrorHandler; } prev_command = path_command; } if ((prev_command != VLC_OP_END)) { stroke_conversion->path_last_point->next = NULL; if (stroke_conversion->point_count == 1) { /* Single point path. */ vg_lite_path_point_ptr point = stroke_conversion->path_point_list; point->tangentX = 0.0f; point->tangentY = 0.0f; point->length = 0.0f; } } ErrorHandler: return error; } static vg_lite_error_t _add_point_to_right_stroke_point_list_tail( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_float_t X, vg_lite_float_t Y ) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_path_point_ptr point; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); if(!point) return VG_LITE_OUT_OF_RESOURCES; memset(point, 0, sizeof(*point)); point->x = X; point->y = Y; point->curve_type = CURVE_LINE; point->prev = stroke_conversion->last_right_stroke_point; point->next = NULL; stroke_conversion->last_right_stroke_point->next = point; stroke_conversion->last_right_stroke_point = point; stroke_conversion->stroke_point_count++; stroke_conversion->last_stroke_sub_path->point_count++; return error; } static vg_lite_error_t _add_point_to_left_stroke_point_list_head( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_float_t X, vg_lite_float_t Y ) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_path_point_ptr point; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); if(!point) return VG_LITE_OUT_OF_RESOURCES; memset(point, 0, sizeof(*point)); point->x = X; point->y = Y; point->curve_type = CURVE_LINE; point->next = stroke_conversion->left_stroke_point; point->prev = NULL; stroke_conversion->left_stroke_point->prev = point; stroke_conversion->left_stroke_point = point; stroke_conversion->stroke_point_count++; stroke_conversion->last_stroke_sub_path->point_count++; return error; } static vg_lite_error_t _add_stroke_sub_path( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_sub_path_ptr *sub_path ) { vg_lite_error_t error = VG_LITE_SUCCESS; if(!stroke_conversion || !sub_path) return VG_LITE_INVALID_ARGUMENT; *sub_path = (vg_lite_sub_path_ptr)vg_lite_os_malloc(sizeof(**sub_path)); if(!*sub_path) return VG_LITE_OUT_OF_RESOURCES; memset(*sub_path, 0, sizeof(**sub_path)); if (stroke_conversion->last_stroke_sub_path != NULL) { stroke_conversion->last_stroke_sub_path->next = *sub_path; stroke_conversion->last_stroke_sub_path = *sub_path; } else { stroke_conversion->last_stroke_sub_path = stroke_conversion->stroke_sub_path_list = *sub_path; } return error; } static vg_lite_error_t _add_zero_length_stroke_sub_path( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_sub_path_ptr *stroke_subpath ) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_path_point_ptr new_point,Point; vg_lite_sub_path_ptr stroke_sub_path; vg_lite_float_t half_width; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; half_width = stroke_conversion->half_line_width; Point = stroke_conversion->path_point_list; if (stroke_conversion->stroke_cap_style == VG_LITE_CAP_BUTT) { /* No need to draw zero-length subPath for gcvCAP_BUTT. */ error = VG_LITE_SUCCESS; goto ErrorHandler; } VG_LITE_ERROR_HANDLER(_add_stroke_sub_path(stroke_conversion, &stroke_sub_path)); if (stroke_conversion->stroke_cap_style == VG_LITE_CAP_SQUARE) { /* Draw a square along the point's direction. */ vg_lite_float_t dx, dy; if (Point->tangentX == 0.0f || Point->tangentY == 0.0f) { dx = half_width; dy = 0.0f; } else { dx = Point->tangentY * half_width; dy = -Point->tangentX * half_width; } new_point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*new_point)); if(!new_point) return VG_LITE_OUT_OF_RESOURCES; memset(new_point, 0, sizeof(*new_point)); new_point->x = Point->x + dx + dy; new_point->y = Point->y - dx + dy; new_point->curve_type = CURVE_LINE; stroke_sub_path->point_list = stroke_conversion->last_right_stroke_point = new_point; stroke_sub_path->point_count = 1; VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, Point->x + dx - dy, Point->y + dx + dy)); VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, Point->x - dx - dy, Point->y + dx - dy)); VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, Point->x - dx + dy, Point->y - dx - dy)); } else { /* Draw a circle. */ new_point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*new_point)); if(!new_point) return VG_LITE_OUT_OF_RESOURCES; memset(new_point, 0, sizeof(*new_point)); new_point->x = Point->x + half_width; new_point->y = Point->y; new_point->curve_type = CURVE_LINE; stroke_sub_path->point_list = stroke_conversion->last_right_stroke_point = new_point; stroke_sub_path->point_count = 1; /* Add upper half circle. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, Point->x - half_width, Point->y)); stroke_conversion->last_right_stroke_point->curve_type = CURVE_ARC_SCCW_HALF; stroke_conversion->last_right_stroke_point->centerX = Point->x; stroke_conversion->last_right_stroke_point->centerY = Point->y; /* Add lower half circle. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, Point->x + half_width, Point->y)); stroke_conversion->last_right_stroke_point->curve_type = CURVE_ARC_SCCW_HALF; stroke_conversion->last_right_stroke_point->centerX = Point->x; stroke_conversion->last_right_stroke_point->centerY = Point->y; } stroke_sub_path->last_point = stroke_conversion->last_right_stroke_point; stroke_sub_path->last_point->next = NULL; ErrorHandler: return error; } /* Special asin(x) for quick calculation when -sqrt(0.5) <= x <= sqrt(0.5). */ static vg_lite_float_t _Asin( vg_lite_float_t X ) { vg_lite_float_t x = X; vg_lite_float_t x2 = X * X; vg_lite_float_t s = X; x *= x2; s += x * 0.1660510562575219f; x *= x2; s += x * 0.084044676143618186f; x *= x2; s += x * 0.0023776176698039313f; x *= x2; s += x * 0.10211922020091345f; return s; } /* Special cos(x) for quick calculation when -PI <= x <= PI. */ static vg_lite_float_t _Cos( vg_lite_float_t X ) { vg_lite_float_t x2 = X * X; vg_lite_float_t x = x2; vg_lite_float_t s = 1.0f; s -= x * 0.49985163079668843f; x *= x2; s += x * 0.041518066216932693f; x *= x2; s -= x * 0.0013422997970712939f; x *= x2; s += x * 0.000018930111278021357f; return s; } /* Special sin(x) for quick calculation when -PI <= x <= PI. */ static vg_lite_float_t _Sine( vg_lite_float_t X ) { vg_lite_float_t x = X; vg_lite_float_t x2 = X * X; vg_lite_float_t s = X; x *= x2; s -= x * 0.16664527099620879f; x *= x2; s += x * 0.0083154803736487041f; x *= x2; s -= x * 0.00019344151251408578f; x *= x2; s += x * 0.0000021810214160988925f; return s; } static vg_lite_float_t _Angle( vg_lite_float_t X, vg_lite_float_t Y, vg_lite_float_t Length ) { vg_lite_float_t angle; vg_lite_float_t ux = (X >= 0.0f ? X : -X); vg_lite_float_t uy = (Y >= 0.0f ? Y : -Y); if (ux > uy) { angle = ((uy > 0.0f && ux < Length) ? _Asin(uy / Length) : 0.0f); } else { angle = ((ux > 0.0f && uy < Length) ? (FLOAT_PI_HALF - _Asin(ux / Length)) : FLOAT_PI_HALF); } if (X < 0.0f) angle = FLOAT_PI - angle; if (Y < 0.0f) angle = -angle; return angle; } /* The arc is always counter clockwise and less than half circle (small). */ static vg_lite_error_t _convert_circle_arc( vg_lite_stroke_conversion_t *stroke_conversion, vg_lite_float_t Radius, vg_lite_float_t CenterX, vg_lite_float_t CenterY, vg_lite_float_t StartX, vg_lite_float_t StartY, vg_lite_float_t EndX, vg_lite_float_t EndY, uint8_t Half_circle, vg_lite_path_point_ptr *point_list ) { vg_lite_error_t error = VG_LITE_SUCCESS; /*gceVGCMD segmentCommand;*/ vg_lite_float_t theta1, theta_span; uint32_t segs; vg_lite_float_t theta, theta_half, theta2; vg_lite_float_t cos_theta_half; vg_lite_float_t control_ratio; vg_lite_float_t controlX, controlY, anchorX, anchorY; /*gctFLOAT lastX, lastY;*/ vg_lite_path_point_ptr point, start_point, last_point; if(!stroke_conversion || !point_list) return VG_LITE_INVALID_ARGUMENT; /* Converting. */ theta1 = _Angle(StartX - CenterX, StartY - CenterY, Radius); if (Half_circle) { theta_span = FLOAT_PI; segs = 4; theta = FLOAT_PI_QUARTER; theta_half = FLOAT_PI_EIGHTH; cos_theta_half = FLOAT_COS_PI_EIGHTH; } else { theta_span = _Angle(EndX - CenterX, EndY - CenterY, Radius) - theta1; if (theta_span == 0.0f) { /* Handle specail case for huge scaling. */ *point_list = NULL; error = VG_LITE_SUCCESS; return error; } if ((theta_span < 0)) { theta_span += FLOAT_PI_TWO; } /* Calculate the number of quadratic Bezier curves. */ /* Assumption: most of angles are small angles. */ if (theta_span <= FLOAT_PI_QUARTER) segs = 1; else if (theta_span <= FLOAT_PI_HALF) segs = 2; else if (theta_span <= FLOAT_PI_THREE_QUARTER) segs = 3; else segs = 4; theta = theta_span / segs; theta_half = theta / 2.0f; cos_theta_half = _Cos(theta_half); } /* Determine the segment command. */ /*egmentCommand = gcvVGCMD_ARC_QUAD;*/ /* Generate quadratic Bezier curves. */ start_point = last_point = NULL; control_ratio = Radius / cos_theta_half; while (segs-- > 0) { theta1 += theta; theta2 = theta1 - theta_half; if (theta2 > FLOAT_PI) theta2 -= FLOAT_PI_TWO; controlX = CenterX + _Cos(theta2) * control_ratio; controlY = CenterY + _Sine(theta2) * control_ratio; theta2 = theta1; if (theta2 > FLOAT_PI) theta2 -= FLOAT_PI_TWO; anchorX = CenterX + _Cos(theta2) * Radius; anchorY = CenterY + _Sine(theta2) * Radius; if (segs == 0) { /* Use end point directly to avoid accumulated errors. */ anchorX = EndX; anchorY = EndY; } /* Add control point. */ point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); if(!point) return VG_LITE_OUT_OF_RESOURCES; memset(point, 0, sizeof(*point)); point->x = controlX; point->y = controlY; point->curve_type = CURVE_QUAD_CONTROL; if (last_point) { last_point->next = point; last_point = point; } else { start_point = last_point = point; } /* Add anchor point. */ point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); if(!point) { error = VG_LITE_OUT_OF_RESOURCES; goto ErrorHandler; } memset(point, 0, sizeof(*point)); point->x = anchorX; point->y = anchorY; point->curve_type = CURVE_QUAD_ANCHOR; last_point->next = point; last_point = point; } last_point->next = NULL; *point_list = start_point; return error; ErrorHandler: /* Return status. */ while (start_point) { point = start_point; start_point = start_point->next; vg_lite_os_free(point); } start_point = last_point = point = NULL; return error; } static vg_lite_error_t _start_new_stroke_sub_path( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_float_t X, vg_lite_float_t Y, vg_lite_float_t Dx, vg_lite_float_t Dy, uint8_t add_end_cap, vg_lite_sub_path_ptr *stroke_subpath ) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_sub_path_ptr stroke_sub_path; vg_lite_path_point_ptr new_point; if(!stroke_conversion || !stroke_subpath) return VG_LITE_INVALID_ARGUMENT; VG_LITE_ERROR_HANDLER(_add_stroke_sub_path(stroke_conversion, &stroke_sub_path)); new_point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*new_point)); if(!new_point) return VG_LITE_OUT_OF_RESOURCES; memset(new_point, 0, sizeof(*new_point)); new_point->x = X + Dx; new_point->y = Y + Dy; new_point->prev = NULL; new_point->curve_type = CURVE_LINE; stroke_conversion->stroke_point_list = stroke_conversion->last_right_stroke_point = new_point; stroke_sub_path->point_list = stroke_conversion->last_right_stroke_point = new_point; new_point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*new_point)); if(!new_point) return VG_LITE_OUT_OF_RESOURCES; memset(new_point, 0, sizeof(*new_point)); new_point->x = X - Dx; new_point->y = Y - Dy; new_point->curve_type = CURVE_LINE; new_point->next = NULL; stroke_conversion->stroke_last_point = stroke_conversion->left_stroke_point = new_point; stroke_conversion->stroke_point_count = 2; stroke_sub_path->last_point = stroke_conversion->left_stroke_point = new_point; stroke_sub_path->point_count = 2; if (add_end_cap) { /* Add end cap if the subPath is not closed. */ switch (stroke_conversion->stroke_cap_style) { case VG_LITE_CAP_BUTT: /* No adjustment needed. */ break; case VG_LITE_CAP_ROUND: /* Add curve. */ /* Add the starting point again as arc. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, stroke_sub_path->point_list->x, stroke_sub_path->point_list->y)); stroke_conversion->last_right_stroke_point->curve_type = CURVE_ARC_SCCW_HALF; stroke_conversion->last_right_stroke_point->centerX = X; stroke_conversion->last_right_stroke_point->centerY = Y; /* Change the starting point to end point. */ stroke_sub_path->point_list->x = stroke_sub_path->last_point->x; stroke_sub_path->point_list->y = stroke_sub_path->last_point->y; break; case VG_LITE_CAP_SQUARE: stroke_conversion->last_right_stroke_point->x += Dy; stroke_conversion->last_right_stroke_point->y -= Dx; stroke_conversion->left_stroke_point->x += Dy; stroke_conversion->left_stroke_point->y -= Dx; break; } } *stroke_subpath = stroke_sub_path; ErrorHandler: return error; } static void _adjust_joint_point( vg_lite_path_point_ptr Point, vg_lite_path_point_ptr join_point, vg_lite_float_t X, vg_lite_float_t Y, vg_lite_float_t Ratio ) { vg_lite_float_t mx = (join_point->x + X) / 2.0f; vg_lite_float_t my = (join_point->y + Y) / 2.0f; vg_lite_float_t dx = mx - Point->x; vg_lite_float_t dy = my - Point->y; dx = dx * Ratio; dy = dy * Ratio; join_point->x = Point->x + dx; join_point->y = Point->y + dy; } static uint8_t _is_angle_span_acute( vg_lite_float_t Ux, vg_lite_float_t Uy, vg_lite_float_t Vx, vg_lite_float_t Vy ) { return ((Ux * Vx + Uy * Vy) > 0.0f ? 1 : 0); } static vg_lite_error_t _draw_swing_pie_area( vg_lite_stroke_conversion_t *stroke_conversion, vg_lite_path_point_ptr center_point, uint8_t end_at_prev_point ) { vg_lite_error_t error = VG_LITE_SUCCESS; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; if (stroke_conversion->swing_counter_clockwise) { vg_lite_path_point_ptr start_point = stroke_conversion->swing_start_stroke_point; vg_lite_path_point_ptr end_point = NULL, real_end_point = NULL; vg_lite_path_point_ptr point, prev_point; uint32_t count = 0; { if (end_at_prev_point) { /* Detach the end point from leftStrokePoint. */ /* The end point will be added back later. */ real_end_point = stroke_conversion->left_stroke_point; stroke_conversion->left_stroke_point = real_end_point->next; stroke_conversion->left_stroke_point->prev = NULL; } VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, center_point->x, center_point->y)); end_point = stroke_conversion->left_stroke_point; /* Reverse the point list from startPoint to endPoint. */ for (point = start_point; point; point = prev_point) { prev_point = point->prev; point->prev = point->next; point->next = prev_point; count++; } end_point->next = start_point->prev; start_point->prev->prev = end_point; start_point->prev = NULL; stroke_conversion->left_stroke_point = start_point; VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, center_point->x, center_point->y)); VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, stroke_conversion->swing_start_point->x, stroke_conversion->swing_start_point->y)); VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, end_point->prev->x, end_point->prev->y)); if (end_at_prev_point) { real_end_point->next = stroke_conversion->left_stroke_point; stroke_conversion->left_stroke_point->prev = real_end_point; stroke_conversion->left_stroke_point = real_end_point; } } } else { vg_lite_path_point_ptr start_point = stroke_conversion->swing_start_stroke_point; vg_lite_path_point_ptr end_point = NULL, real_end_point = NULL; vg_lite_path_point_ptr point, next_point; uint32_t count = 0; { if (end_at_prev_point) { /* Detach the end point from leftStrokePoint. */ /* The end point will be added back later. */ real_end_point = stroke_conversion->last_right_stroke_point; stroke_conversion->last_right_stroke_point = real_end_point->prev; stroke_conversion->last_right_stroke_point->next = NULL; } VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, center_point->x, center_point->y)); end_point = stroke_conversion->last_right_stroke_point; /* Reverse the point list from startPoint to endPoint. */ for (point = start_point; point; point = next_point) { next_point = point->next; point->next = point->prev; point->prev = next_point; count++; } end_point->prev = start_point->next; start_point->next->next = end_point; start_point->next = NULL; stroke_conversion->last_right_stroke_point = start_point; VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, center_point->x, center_point->y)); VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, stroke_conversion->swing_start_point->x, stroke_conversion->swing_start_point->y)); VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, end_point->next->x, end_point->next->y)); if (end_at_prev_point) { real_end_point->prev = stroke_conversion->last_right_stroke_point; stroke_conversion->last_right_stroke_point->next = real_end_point; stroke_conversion->last_right_stroke_point = real_end_point; } } } stroke_conversion->swing_handling = SWING_NO; ErrorHandler: return error; } static vg_lite_error_t _process_line_joint( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_path_point_ptr Point, vg_lite_float_t Length, vg_lite_float_t prev_length, uint32_t Swing_handling, vg_lite_float_t X1, vg_lite_float_t Y1, vg_lite_float_t X2, vg_lite_float_t Y2 ) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_join_style_t stroke_join_style = stroke_conversion->stroke_join_style; vg_lite_float_t half_width = stroke_conversion->half_line_width; vg_lite_float_t ratio; vg_lite_float_t min_length_square; vg_lite_float_t cos_theta; uint8_t counter_clockwise; uint8_t fat_line = stroke_conversion->is_fat; uint32_t swing_handling = SWING_NO; uint8_t handle_short_line = 0; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; if (stroke_conversion->swing_accu_length < half_width) { if (stroke_conversion->swing_need_to_handle) { swing_handling = SWING_OUT; } else { handle_short_line = 1; } } else if (stroke_conversion->stroke_path_length - stroke_conversion->swing_accu_length < half_width) { if (stroke_conversion->swing_need_to_handle) { swing_handling = SWING_IN; } else { handle_short_line = 1; } } if (swing_handling != Swing_handling) { error = VG_LITE_INVALID_ARGUMENT; goto ErrorHandler; } /* For flattened curves/arcs, the join style is always round. */ if ((Point->flatten_flag != vgcFLATTEN_NO) && fat_line) { stroke_join_style = VG_LITE_JOIN_ROUND; } /* First, determine the turn is clockwise or counter-clockwise. */ cos_theta = Point->prev->tangentX * Point->tangentX + Point->prev->tangentY * Point->tangentY; if (cos_theta > FLOAT_ANGLE_EPSILON_COS) { /* Straight line or semi-straight line--no need to handle join. */ if (stroke_conversion->swing_handling !=SWING_NO) { /* Begin to swing to the opposite direction. */ /* Draw the swing area (pie area). */ VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point->prev, 1)); } /* Add the new stroke points. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); if (stroke_conversion->swing_handling != SWING_NO) { stroke_conversion->swing_count++; } goto endCheck; } else if (cos_theta < -FLOAT_ANGLE_EPSILON_COS) { /* Almost 180 degree turn. */ counter_clockwise = 1; ratio = FLOAT_MAX; min_length_square = FLOAT_MAX; } else { vg_lite_float_t angleSign = Point->prev->tangentX * Point->tangentY - Point->prev->tangentY * Point->tangentX; counter_clockwise = (angleSign >= 0.0f ? 1 : 0); ratio = 2.0f / (1.0f + cos_theta); min_length_square = half_width * half_width * (1.0f - cos_theta) / (1.0f + cos_theta) + 0.02f; } if (stroke_conversion->swing_handling != SWING_NO) { if (counter_clockwise != stroke_conversion->swing_counter_clockwise) { /* Swing to the opposite direction. */ /* Draw the swing area (pie area). */ VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point->prev, 1)); } } if (counter_clockwise) { if (stroke_conversion->swing_handling != SWING_NO) { vg_lite_path_point_ptr prev_point = stroke_conversion->left_stroke_point->next; /* Skip the line segment movement. */ vg_lite_float_t deltaX = X2 - prev_point->x; vg_lite_float_t deltaY = Y2 - prev_point->y; if (_is_angle_span_acute(stroke_conversion->swing_stroke_deltax, stroke_conversion->swing_stroke_deltay, deltaX, deltaY)) { /* Continue swinging. */ stroke_conversion->swing_stroke_deltax = deltaX; stroke_conversion->swing_stroke_deltay = deltaY; } else { /* Swing to the max. */ /* Draw the swing area (pie area). */ VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point->prev, 1)); } } /* Check if the miter length is too long for inner intersection. */ if (stroke_conversion->swing_handling == SWING_NO && ! handle_short_line && min_length_square <= Length * Length && min_length_square <= prev_length * prev_length) { /* Adjust leftStrokePoint to the intersection point. */ _adjust_joint_point(Point, stroke_conversion->left_stroke_point, X2, Y2, ratio); } else if (stroke_conversion->swing_handling == SWING_NO && Point->flatten_flag == vgcFLATTEN_NO) { /* Add the point to avoid incorrect sharp angle. */ VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, Point->x, Point->y)); /* Add the point to form a loop to avoid out-of-bound problem. */ VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); } else if (stroke_conversion->swing_handling == SWING_NO && (! fat_line || Swing_handling == SWING_NO)) { /* Flattened line segments should not have sharp angle. */ /* Add the point to form a loop to avoid out-of-bound problem. */ VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); } else { if (stroke_conversion->swing_handling == SWING_NO) { vg_lite_path_point_ptr prev_point = stroke_conversion->left_stroke_point; /* Start swing handling. */ stroke_conversion->swing_handling = Swing_handling; stroke_conversion->swing_counter_clockwise = 1; stroke_conversion->swing_start_point = Point; stroke_conversion->swing_center_length = 0.0f; stroke_conversion->swing_count= 0; /* Save stroking path delta. */ stroke_conversion->swing_stroke_deltax = X2 - prev_point->x; stroke_conversion->swing_stroke_deltay = Y2 - prev_point->y; /* Add extra center point for swing out pie area. */ /* VIV: [todo] Should adjust prev_point, instead of adding new point? */ VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, Point->x, Point->y)); /* Add extra start stroke point for swing out pie area. */ VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, prev_point->x, prev_point->y)); stroke_conversion->swing_start_stroke_point = stroke_conversion->left_stroke_point; } #if USE_MIN_ARC_FILTER if (cosTheta > FLOAT_MIN_ARC_ANGLE_COS) { /* Add a point. */ gcmERR_GOTO(_add_point_to_left_stroke_point_list_head(Context, stroke_conversion, X2, Y2)); VGSL_STAT_COUNTER_INCREASE(vgStrokeFilteredByMinArcAngleCount); } else #endif { /* Add curve. */ /* Note that the curve will be reversed, so the direction is CW. */ /* Then, left side is in reversed order, so the direction is CCW. */ VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); stroke_conversion->left_stroke_point->curve_type = CURVE_ARC_SCCW; stroke_conversion->left_stroke_point->centerX = Point->x; stroke_conversion->left_stroke_point->centerY = Point->y; } stroke_conversion->swing_count++; } switch (stroke_join_style) { case VG_LITE_JOIN_ROUND: if (cos_theta > FLOAT_MIN_ARC_ANGLE_COS) { /* Add a point. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); } else { /* Add curve. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); stroke_conversion->last_right_stroke_point->curve_type = CURVE_ARC_SCCW; stroke_conversion->last_right_stroke_point->centerX = Point->x; stroke_conversion->last_right_stroke_point->centerY = Point->y; } break; case VG_LITE_JOIN_MITER: if (ratio <= stroke_conversion->stroke_miter_limit_square) { /* Adjust lastRightStrokePoint to the outer intersection point. */ _adjust_joint_point(Point, stroke_conversion->last_right_stroke_point, X1, Y1, ratio); break; } /* Else use Bevel join style. */ case VG_LITE_JOIN_BEVEL: VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); break; } } else { if (stroke_conversion->swing_handling != SWING_NO) { vg_lite_path_point_ptr prev_point = stroke_conversion->last_right_stroke_point->prev; /* Skip the line segment movement. */ vg_lite_float_t deltaX = X1 - prev_point->x; vg_lite_float_t deltaY = Y1 - prev_point->y; if (_is_angle_span_acute(stroke_conversion->swing_stroke_deltax, stroke_conversion->swing_stroke_deltay, deltaX, deltaY)) { /* Continue swinging. */ stroke_conversion->swing_stroke_deltax = deltaX; stroke_conversion->swing_stroke_deltay = deltaY; } else { /* Swing to the max. */ /* Draw the swing area (pie area). */ VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point->prev, 1)); } } /* Check if the miter length is too long for inner intersection. */ if (stroke_conversion->swing_handling == SWING_NO && ! handle_short_line && min_length_square <= Length * Length && min_length_square <= prev_length * prev_length) { /* Adjust lastRightStrokePoint to the intersection point. */ _adjust_joint_point(Point, stroke_conversion->last_right_stroke_point, X1, Y1, ratio); } else if (stroke_conversion->swing_handling == SWING_NO && Point->flatten_flag == vgcFLATTEN_NO) { /* Add the point to avoid incorrect sharp angle. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, Point->x, Point->y)); /* Add the point to form a loop to avoid out-of-bound problem. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); } else if (stroke_conversion->swing_handling == SWING_NO && (! fat_line || Swing_handling == SWING_NO)) { /* Flattened line segments should not have sharp angle. */ /* Add the point to form a loop to avoid out-of-bound problem. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); } else { if (stroke_conversion->swing_handling == SWING_NO) { vg_lite_path_point_ptr prev_point = stroke_conversion->last_right_stroke_point; /* Start swing handling. */ stroke_conversion->swing_handling = Swing_handling; stroke_conversion->swing_counter_clockwise = 0; stroke_conversion->swing_start_point = Point; stroke_conversion->swing_center_length = 0.0f; stroke_conversion->swing_count= 0; /* Save stroking path delta. */ stroke_conversion->swing_stroke_deltax = X1 - prev_point->x; stroke_conversion->swing_stroke_deltay = Y1 - prev_point->y; /* Add extra center point for swing out pie area. */ /* VIV: [todo] Should adjust prev_point, instead of adding new point? */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, Point->x, Point->y)); /* Add extra start stroke point for swing out pie area. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, prev_point->x, prev_point->y)); stroke_conversion->swing_start_stroke_point = stroke_conversion->last_right_stroke_point; } if (cos_theta > FLOAT_MIN_ARC_ANGLE_COS) { /* Add a point. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); } else { /* Add curve. */ /* Note that the curve will be reversed, so the direction is CCW. */ stroke_conversion->last_right_stroke_point->curve_type = CURVE_ARC_SCCW; stroke_conversion->last_right_stroke_point->centerX = Point->x; stroke_conversion->last_right_stroke_point->centerY = Point->y; VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); } stroke_conversion->swing_count++; } switch (stroke_join_style) { case VG_LITE_JOIN_ROUND: if (cos_theta > FLOAT_MIN_ARC_ANGLE_COS) { /* Add a point. */ VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); } else { /* Add curve. */ stroke_conversion->left_stroke_point->curve_type = CURVE_ARC_SCCW; stroke_conversion->left_stroke_point->centerX = Point->x; stroke_conversion->left_stroke_point->centerY = Point->y; VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); } break; case VG_LITE_JOIN_MITER: if (ratio <= stroke_conversion->stroke_miter_limit_square) { /* Adjust leftStrokePoint to the outer intersection point. */ _adjust_joint_point(Point, stroke_conversion->left_stroke_point, X2, Y2, ratio); break; } /* Else use Bevel join style. */ case VG_LITE_JOIN_BEVEL: VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); break; } } endCheck: if (stroke_conversion->swing_need_to_handle) { stroke_conversion->swing_accu_length += Point->length; } if (stroke_conversion->swing_handling != SWING_NO) { if (Point->flatten_flag == vgcFLATTEN_END || (stroke_conversion->swing_handling == SWING_OUT && stroke_conversion->swing_accu_length > half_width)) { /* Draw the swing area (pie area). */ VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point, 0)); } else { /* Check if center line will move too far. */ stroke_conversion->swing_center_length += Point->length; if (stroke_conversion->swing_center_length > FLOAT_SWING_CENTER_RANGE) { #if USE_NEW_SWING_HANDLE_FOR_END if (stroke_conversion->currentSubPath->length < half_width || Point->next->flatten_flag == vgcFLATTEN_END) #endif { /* Draw the swing area (pie area). */ VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point, 0)); } } } } ErrorHandler: return error; } static vg_lite_error_t _close_stroke_sub_path( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_path_point_ptr Point, vg_lite_float_t Length, vg_lite_float_t prev_length, uint8_t Swing_handling, vg_lite_path_point_ptr first_stroke_point, vg_lite_path_point_ptr last_stroke_point ) { vg_lite_error_t error = VG_LITE_SUCCESS; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; /* Handle line joint style for the first/last point in closed path. */ VG_LITE_ERROR_HANDLER(_process_line_joint( stroke_conversion, Point, Length, prev_length, Swing_handling, first_stroke_point->x, first_stroke_point->y, last_stroke_point->x, last_stroke_point->y )); /* Adjust the two end ponts of the first point. */ first_stroke_point->x = stroke_conversion->last_right_stroke_point->x; first_stroke_point->y = stroke_conversion->last_right_stroke_point->y; last_stroke_point->x = stroke_conversion->left_stroke_point->x; last_stroke_point->y = stroke_conversion->left_stroke_point->y; /* Concatnate right and left point lists. */ stroke_conversion->last_right_stroke_point->next = stroke_conversion->left_stroke_point; stroke_conversion->left_stroke_point->prev = stroke_conversion->last_right_stroke_point; /*gcmERROR_RETURN(_CheckStrokeSubPath(stroke_conversion->lastStrokeSubPath));*/ ErrorHandler: return error; } static vg_lite_error_t _end_stroke_sub_path( vg_lite_stroke_conversion_t *stroke_conversion, vg_lite_float_t X, vg_lite_float_t Y, vg_lite_float_t Dx, vg_lite_float_t Dy ) { vg_lite_error_t error = VG_LITE_SUCCESS; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; /* Add points for end of line. */ VG_LITE_RETURN_ERROR(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X + Dx, Y + Dy)); VG_LITE_RETURN_ERROR(_add_point_to_left_stroke_point_list_head(stroke_conversion, X - Dx, Y - Dy)); /* Add end cap if the subPath is not closed. */ switch (stroke_conversion->stroke_cap_style) { case VG_LITE_CAP_BUTT: /* No adjustment needed. */ break; case VG_LITE_CAP_ROUND: /* Add curve. */ stroke_conversion->left_stroke_point->curve_type = CURVE_ARC_SCCW_HALF; stroke_conversion->left_stroke_point->centerX = X; stroke_conversion->left_stroke_point->centerY = Y; break; case VG_LITE_CAP_SQUARE: stroke_conversion->last_right_stroke_point->x -= Dy; stroke_conversion->last_right_stroke_point->y += Dx; stroke_conversion->left_stroke_point->x -= Dy; stroke_conversion->left_stroke_point->y += Dx; break; } /* Concatnate right and left point lists. */ stroke_conversion->last_right_stroke_point->next = stroke_conversion->left_stroke_point; stroke_conversion->left_stroke_point->prev = stroke_conversion->last_right_stroke_point; /*gcmERROR_RETURN(_CheckStrokeSubPath(stroke_conversion->lastStrokeSubPath));*/ return error; } static vg_lite_error_t _get_next_dash_length( vg_lite_stroke_conversion_t * stroke_conversion, uint32_t * dash_index, vg_lite_float_t * dash_length ) { if(!stroke_conversion || !dash_index || !dash_length) return VG_LITE_INVALID_ARGUMENT; (*dash_index)++; if (*dash_index == stroke_conversion->stroke_dash_pattern_count) { *dash_index = 0; } *dash_length = stroke_conversion->stroke_dash_pattern[*dash_index]; return VG_LITE_SUCCESS; } static vg_lite_error_t _create_stroke_path( vg_lite_stroke_conversion_t * stroke_conversion ) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_sub_path_ptr stroke_sub_path = NULL,first_stroke_sub_path = NULL; vg_lite_path_point_ptr point, next_point; vg_lite_float_t half_width; vg_lite_float_t x, y; vg_lite_float_t dx, dy, ux, uy; vg_lite_float_t length, prev_length, first_length; vg_lite_float_t dash_length; uint32_t dash_index; uint8_t dashing; uint8_t add_end_cap; uint8_t need_to_handle_swing = 1 /* (stroke_conversion->strokeCapStyle == gcvCAP_BUTT) */; vg_lite_path_point_ptr first_right_point = NULL; vg_lite_path_point_ptr last_left_point = NULL; vg_lite_float_t first_dx = 0.0f, first_dy = 0.0f; uint8_t drawing = 0; vg_lite_float_t total_length = 0.0f; vg_lite_float_t accu_length = 0.0f; uint32_t swing_handling = SWING_NO; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; half_width = stroke_conversion->half_line_width; dashing = stroke_conversion->stroke_dash_pattern_count > 0 ? 1 : 0; dash_index = stroke_conversion->stroke_dash_initial_index; dash_length = stroke_conversion->stroke_dash_initial_length; /* VIV: [todo] Need to check/debug closed stroke path. */ need_to_handle_swing = (stroke_conversion->stroke_cap_style == VG_LITE_CAP_BUTT || stroke_conversion->closed); if (need_to_handle_swing) { uint8_t reallyneed_to_handle_swing = 0; /* Calculate the total length. */ for (point = stroke_conversion->path_point_list; point; point = point->next) { total_length += point->length; if (point->flatten_flag != vgcFLATTEN_NO) { reallyneed_to_handle_swing = 1; } } stroke_conversion->stroke_path_length = total_length; if (reallyneed_to_handle_swing) { swing_handling = SWING_OUT; } else { need_to_handle_swing = 0; swing_handling = SWING_NO; } } stroke_conversion->swing_need_to_handle = need_to_handle_swing; point = stroke_conversion->path_point_list; next_point = point->next; if (next_point == NULL) { if (!dashing || ((dash_index & 0x1) == 0)) { /* Single point (zero-length) subpath. */ /* Note that one-MOVE_TO subpaths are removed during parsing. */ VG_LITE_ERROR_HANDLER(_add_zero_length_stroke_sub_path(stroke_conversion, &stroke_sub_path)); } goto ErrorHandler; } /* Adjust closed status for dashing. */ if (dashing && stroke_conversion->closed && ((dash_index & 0x1) == 1)) { stroke_conversion->closed = FALSE; } /* Set add_end_cap. */ add_end_cap = dashing ? 1: (stroke_conversion->closed ? 0 : 1); /* Process first line. */ first_length = point->length; ux = point->tangentX; uy = point->tangentY; dx = uy * half_width; dy = -ux * half_width; if (need_to_handle_swing) { stroke_conversion->swing_accu_length = first_length; } if (dashing) { vg_lite_float_t delta_length; /* Draw dashes. */ x = point->x; y = point->y; do { if ((dash_index & 0x1) == 0) { VG_LITE_ERROR_HANDLER(_start_new_stroke_sub_path( stroke_conversion, x, y, dx, dy, add_end_cap, &stroke_sub_path )); drawing = 1; add_end_cap = 1; if (stroke_conversion->closed && (first_stroke_sub_path == NULL)) { first_stroke_sub_path = stroke_conversion->last_stroke_sub_path; first_right_point = stroke_conversion->last_right_stroke_point; last_left_point = stroke_conversion->left_stroke_point; first_dx = dx; first_dy = dy; } } delta_length = first_length - dash_length; if (delta_length >= FLOAT_EPSILON) { /* Move (x, y) forward along the line by dash_length. */ x += ux * dash_length; y += uy * dash_length; if ((dash_index & 0x1) == 0) { VG_LITE_ERROR_HANDLER(_end_stroke_sub_path( stroke_conversion, x, y, dx, dy )); drawing = 0; } VG_LITE_ERROR_HANDLER(_get_next_dash_length(stroke_conversion, &dash_index, &dash_length)); first_length = delta_length; } else if (delta_length <= -FLOAT_EPSILON) { dash_length = -delta_length; break; } else { if ((dash_index & 0x1) == 0) { VG_LITE_ERROR_HANDLER(_end_stroke_sub_path( stroke_conversion, next_point->x, next_point->y, dx, dy )); drawing = 0; } VG_LITE_ERROR_HANDLER(_get_next_dash_length(stroke_conversion, &dash_index, &dash_length)); first_length = 0; break; } } while (1); } else { VG_LITE_ERROR_HANDLER(_start_new_stroke_sub_path( stroke_conversion, point->x, point->y, dx, dy, add_end_cap, &stroke_sub_path )); drawing = 1; add_end_cap = 1; } /* Process the rest of lines. */ prev_length = first_length; for (point = next_point, next_point = point->next; next_point; point = next_point, next_point = point->next) { if (!dashing || ((dash_index & 0x1) == 0 && drawing)) { /* Add points for end of line for line join process with next line. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, point->x + dx, point->y + dy)); VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, point->x - dx, point->y - dy)); } length = point->length; ux = point->tangentX; uy = point->tangentY; dx = uy * half_width; dy = -ux * half_width; if (need_to_handle_swing) { accu_length += point->prev->length; stroke_conversion->swing_accu_length = accu_length; if (accu_length < half_width) { swing_handling = SWING_OUT; } else if (total_length - accu_length < half_width) { swing_handling = SWING_IN; } else { swing_handling = SWING_NO; } } if (!dashing) { /* Handle line joint style. */ VG_LITE_ERROR_HANDLER(_process_line_joint( stroke_conversion, point, length, prev_length, swing_handling, point->x + dx, point->y + dy, point->x - dx, point->y - dy )); } else { vg_lite_float_t delta_length; /* Draw dashes. */ x = point->x; y = point->y; if ((dash_index & 0x1) == 0) { if (drawing) { /* Handle line joint style. */ VG_LITE_ERROR_HANDLER(_process_line_joint( stroke_conversion, point, dash_length, prev_length, swing_handling, x + dx, y + dy, x - dx, y - dy )); } else { /* Start a new sub path. */ VG_LITE_ERROR_HANDLER(_start_new_stroke_sub_path( stroke_conversion, x, y, dx, dy, add_end_cap, &stroke_sub_path )); drawing = 1; add_end_cap = 1; } } do { delta_length = length - dash_length; if (delta_length >= FLOAT_EPSILON) { /* Move (x, y) forward along the line by dash_length. */ x += ux * dash_length; y += uy * dash_length; if ((dash_index & 0x1) == 0) { VG_LITE_ERROR_HANDLER(_end_stroke_sub_path( stroke_conversion, x, y, dx, dy )); drawing = 0; } VG_LITE_ERROR_HANDLER(_get_next_dash_length(stroke_conversion, &dash_index, &dash_length)); length = delta_length; } else if (delta_length <= -FLOAT_EPSILON) { dash_length = -delta_length; break; } else { if ((dash_index & 0x1) == 0) { VG_LITE_ERROR_HANDLER(_end_stroke_sub_path( stroke_conversion, next_point->x, next_point->y, dx, dy )); drawing = 0; } VG_LITE_ERROR_HANDLER(_get_next_dash_length(stroke_conversion, &dash_index, &dash_length)); length = 0; break; } if ((dash_index & 0x1) == 0) { VG_LITE_ERROR_HANDLER(_start_new_stroke_sub_path( stroke_conversion, x, y, dx, dy, add_end_cap, &stroke_sub_path )); drawing = 1; add_end_cap = 1; } } while (1); } prev_length = length; } if (need_to_handle_swing) { accu_length += point->prev->length; stroke_conversion->swing_accu_length = accu_length; if (accu_length < half_width) { swing_handling = SWING_OUT; } else if (total_length - accu_length < half_width) { swing_handling = SWING_IN; } else { swing_handling = SWING_NO; } } if (stroke_conversion->swing_handling != SWING_NO) { /* Draw the swing area (pie area). */ VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, stroke_conversion->path_last_point, FALSE)); } if (stroke_conversion->closed) { if (! dashing || drawing) { /* Add points for end of line. */ VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, point->x + dx, point->y + dy)); VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, point->x - dx, point->y - dy)); if (! dashing) { /* Handle line joint style for the first/last point in closed path. */ VG_LITE_ERROR_HANDLER(_close_stroke_sub_path( stroke_conversion, point, first_length, prev_length, swing_handling, stroke_sub_path->point_list, stroke_sub_path->last_point )); } else { /* Handle line joint style for the first/last point in closed path. */ VG_LITE_ERROR_HANDLER(_close_stroke_sub_path( stroke_conversion, point, first_length, prev_length, swing_handling, first_right_point, last_left_point )); } } else if (stroke_conversion->stroke_cap_style != VG_LITE_CAP_BUTT) { /* No closing join need. Add end cap for the starting point. */ if (stroke_conversion->stroke_cap_style == VG_LITE_CAP_SQUARE) { first_right_point->x += first_dy; first_right_point->y -= first_dx; last_left_point->x += first_dy; last_left_point->y -= first_dx; } else { vg_lite_sub_path_ptr last_stroke_sub_path = stroke_conversion->last_stroke_sub_path; vg_lite_path_point_ptr start_point = last_stroke_sub_path->point_list; vg_lite_path_point_ptr point; /* Add curve. */ /* Add extra point to the beginning with end point's coordinates. */ point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); if(!point) return VG_LITE_INVALID_ARGUMENT; memset(point, 0, sizeof(*point)); point->x = last_stroke_sub_path->last_point->x; point->y = last_stroke_sub_path->last_point->y; point->next = start_point; start_point->prev = point; start_point->curve_type = CURVE_ARC_SCCW; start_point->centerX = stroke_conversion->path_point_list->x; start_point->centerY = stroke_conversion->path_point_list->y; last_stroke_sub_path->point_list = point; } } } else if (! dashing || (((dash_index & 0x1) == 0) && (dash_length < stroke_conversion->stroke_dash_pattern[dash_index]))) { /* Add end cap if the subPath is not closed. */ VG_LITE_ERROR_HANDLER(_end_stroke_sub_path( stroke_conversion, point->x, point->y, dx, dy )); drawing = 0; } ErrorHandler: return error; } static vg_lite_error_t _copy_stroke_path( vg_lite_stroke_conversion_t * stroke_conversion, vg_lite_path_t *path ) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_path_point_ptr point,prev_point,tmp_point; uint32_t totalsize = 0,real_size = 0; float *pfloat; char *cpath = NULL; char last_opcode = 0; void *temp_stroke_path_data = NULL; uint32_t temp_stroke_path_size; vg_lite_sub_path_ptr sub_path; vg_lite_float_t half_width; if(!stroke_conversion || !path) return VG_LITE_INVALID_ARGUMENT; half_width = stroke_conversion->half_line_width; sub_path = stroke_conversion->stroke_sub_path_list; if(!stroke_conversion || !path || !sub_path) return VG_LITE_INVALID_ARGUMENT; while (sub_path) { tmp_point = prev_point = point = sub_path->point_list; totalsize += _commandSize_float[VLC_OP_LINE] * sub_path->point_count + _commandSize_float[VLC_OP_CLOSE]; for(;tmp_point;tmp_point = tmp_point->next) { if(tmp_point->curve_type == CURVE_ARC_SCCW || tmp_point->curve_type == CURVE_ARC_SCCW_HALF) { totalsize += 4 * _commandSize_float[VLC_OP_QUAD]; } } temp_stroke_path_data = path->stroke_path_data; temp_stroke_path_size = path->stroke_path_size; path->stroke_path_size += totalsize; if(path->stroke_path_size == 0) { error = VG_LITE_INVALID_ARGUMENT; goto ErrorHandler; } path->stroke_path_data = (void *)vg_lite_os_malloc(path->stroke_path_size); if(!path->stroke_path_data) { error = VG_LITE_OUT_OF_RESOURCES; goto ErrorHandler; } memset(path->stroke_path_data, 0, path->stroke_path_size); if(temp_stroke_path_data) { memcpy(path->stroke_path_data,temp_stroke_path_data,temp_stroke_path_size); vg_lite_os_free(temp_stroke_path_data); temp_stroke_path_data = NULL; } pfloat = (vg_lite_float_t *)((char *)path->stroke_path_data + temp_stroke_path_size); if(last_opcode == VLC_OP_CLOSE) { cpath = (char *)(pfloat - 1) + 1; *cpath++ = VLC_OP_MOVE; cpath = (char *)pfloat; } else { cpath = (char *)pfloat; *cpath = VLC_OP_MOVE; pfloat++; } *pfloat++ = point->x; *pfloat++ = point->y; real_size += _commandSize_float[VLC_OP_MOVE]; if(last_opcode == VLC_OP_CLOSE) real_size -= 4; for (point = point->next; point; prev_point = point, point = point->next) { if (point->curve_type == CURVE_LINE) { if (point->x == prev_point->x && point->y == prev_point->y) { path->stroke_path_size -= _commandSize_float[VLC_OP_LINE]; /* Skip zero-length lines. */ continue; } /* Add new command. */ cpath = (char *)pfloat; *cpath = VLC_OP_LINE; pfloat++; /* Set the coordinates. */ *pfloat++ = point->x; *pfloat++ = point->y; real_size += _commandSize_float[VLC_OP_LINE]; } else if (point->curve_type == CURVE_QUAD_CONTROL) { /* Add new command. */ cpath = (char *)pfloat; *cpath = VLC_OP_QUAD; pfloat++; /* Set the coordinates. */ prev_point = point, point = point->next; *pfloat++ = prev_point->x; *pfloat++ = prev_point->y; *pfloat++ = point->x; *pfloat++ = point->y; real_size += _commandSize_float[VLC_OP_QUAD]; } else { vg_lite_path_point_ptr point_list, p, nextP; vg_lite_path_point_ptr p2; if (point->curve_type == CURVE_ARC_SCCW) { /* Convert an arc to Bezier curves. */ VG_LITE_ERROR_HANDLER(_convert_circle_arc(stroke_conversion, half_width, point->centerX, point->centerY, prev_point->x, prev_point->y, point->x, point->y, 0, &point_list)); } else { /* Convert a half circle to Bezier curves. */ VG_LITE_ERROR_HANDLER(_convert_circle_arc(stroke_conversion, half_width, point->centerX, point->centerY, prev_point->x, prev_point->y, point->x, point->y, 1, &point_list)); } if (point_list) { for (p = point_list; p; p = nextP) { /* Add new command. */ cpath = (char *)pfloat; *cpath = VLC_OP_QUAD; pfloat++; /* Set the coordinates. */ p2 = p->next; nextP = p2->next; *pfloat++ = p->x; *pfloat++ = p->y; *pfloat++ = p2->x; *pfloat++ = p2->y; real_size += _commandSize_float[VLC_OP_QUAD]; vg_lite_os_free(p); vg_lite_os_free(p2); } } else { /* Handle special case of huge scaling. */ /* Add new command. */ cpath = (char *)pfloat; *cpath = VLC_OP_LINE; pfloat++; /* Set the coordinates. */ *pfloat++ = point->x; *pfloat++ = point->y; real_size += _commandSize_float[VLC_OP_LINE]; } } } /* Create a CLOSE_PATH command at the end. */ cpath = (char *)pfloat; if(sub_path->next) *cpath = VLC_OP_CLOSE; else *cpath = VLC_OP_END; real_size += _commandSize_float[VLC_OP_CLOSE]; path->stroke_path_size = temp_stroke_path_size + real_size; totalsize = 0; real_size = 0; sub_path = sub_path->next; last_opcode = *cpath; } ErrorHandler: if(temp_stroke_path_data) { vg_lite_os_free(temp_stroke_path_data); temp_stroke_path_data = NULL; } return error; } static vg_lite_error_t _initialize_stroke_dash_parameters( vg_lite_stroke_conversion_t * stroke_conversion ) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t count; uint32_t i; vg_lite_float_t *pattern_src; vg_lite_float_t *pattern,*temp_pattern; vg_lite_float_t length; if(!stroke_conversion) return VG_LITE_INVALID_ARGUMENT; count = stroke_conversion->stroke_dash_pattern_count; if (count == 0 || !stroke_conversion->stroke_dash_pattern) return error; length = stroke_conversion->stroke_dash_phase; /* The last pattern is ignored if the number is odd. */ if (count & 0x1) count--; pattern = (vg_lite_float_t *)vg_lite_os_malloc(count * sizeof(vg_lite_float_t)); if(!pattern) return VG_LITE_OUT_OF_RESOURCES; temp_pattern = pattern; stroke_conversion->stroke_dash_pattern_length = 0.0f; pattern_src = stroke_conversion->stroke_dash_pattern; for (i = 0; i < count; i++, pattern++, pattern_src++) { if (*pattern_src < 0.0f) { *pattern = 0.0f; } else { *pattern = *pattern_src; } stroke_conversion->stroke_dash_pattern_length += *pattern; } if (stroke_conversion->stroke_dash_pattern_length < FLOAT_EPSILON) { stroke_conversion->stroke_dash_pattern_count = 0; vg_lite_os_free(temp_pattern); temp_pattern = NULL; return error; } while (length < 0.0f) { length += stroke_conversion->stroke_dash_pattern_length; } while (length >= stroke_conversion->stroke_dash_pattern_length) { length -= stroke_conversion->stroke_dash_pattern_length; } pattern = stroke_conversion->stroke_dash_pattern; for (i = 0; i < stroke_conversion->stroke_dash_pattern_count; i++, pattern++) { if (length <= *pattern) break; length -= *pattern; } stroke_conversion->stroke_dash_initial_index = i; stroke_conversion->stroke_dash_initial_length = *pattern - length; vg_lite_os_free(temp_pattern); temp_pattern = NULL; return error; } vg_lite_error_t vg_lite_update_stroke( vg_lite_path_t *path ) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_stroke_conversion_t * stroke_conversion; if(!path) return VG_LITE_INVALID_ARGUMENT; if(!path->path_length) return VG_LITE_SUCCESS; if(!path->path) return VG_LITE_INVALID_ARGUMENT; if (!path->stroke_conversion) return VG_LITE_INVALID_ARGUMENT; stroke_conversion = path->stroke_conversion; /* Free the stroke. */ if (path->stroke_path_data) { vg_lite_os_free(path->stroke_path_data); /* Reset the stroke. */ path->stroke_path_data = NULL; } if (stroke_conversion->stroke_line_width >= FLOAT_FAT_LINE_WIDTH && stroke_conversion->stroke_line_width >= 1.0f) { stroke_conversion->is_fat = 1; } VG_LITE_RETURN_ERROR(_initialize_stroke_dash_parameters(stroke_conversion)); VG_LITE_RETURN_ERROR(_flatten_path(stroke_conversion, path)); VG_LITE_RETURN_ERROR(_create_stroke_path(stroke_conversion)); VG_LITE_RETURN_ERROR(_copy_stroke_path(stroke_conversion, path)); return error; } vg_lite_error_t vg_lite_set_stroke( vg_lite_path_t *path, vg_lite_cap_style_t stroke_cap_style, vg_lite_join_style_t stroke_join_style, vg_lite_float_t stroke_line_width, vg_lite_float_t stroke_miter_limit, vg_lite_float_t *stroke_dash_pattern, uint32_t stroke_dash_pattern_count, vg_lite_float_t stroke_dash_phase, vg_lite_color_t stroke_color ) { if(!path || stroke_line_width <= 0) return VG_LITE_INVALID_ARGUMENT; if(stroke_miter_limit < 1.0f) stroke_miter_limit = 1.0f; if (!path->stroke_conversion) { path->stroke_conversion = (vg_lite_stroke_conversion_t *)vg_lite_os_malloc(sizeof(vg_lite_stroke_conversion_t)); if (!path->stroke_conversion) return VG_LITE_OUT_OF_RESOURCES; memset(path->stroke_conversion, 0, sizeof(vg_lite_stroke_conversion_t)); } path->stroke_conversion->stroke_cap_style = stroke_cap_style; path->stroke_conversion->stroke_join_style = stroke_join_style; path->stroke_conversion->stroke_line_width = stroke_line_width; path->stroke_conversion->stroke_miter_limit = stroke_miter_limit; path->stroke_conversion->half_line_width = stroke_line_width / 2.0f; path->stroke_conversion->stroke_miter_limit_square = path->stroke_conversion->stroke_miter_limit * path->stroke_conversion->stroke_miter_limit; path->stroke_conversion->stroke_dash_pattern = stroke_dash_pattern; path->stroke_conversion->stroke_dash_pattern_count = stroke_dash_pattern_count; path->stroke_conversion->stroke_dash_phase = stroke_dash_phase; path->stroke_color = stroke_color; return VG_LITE_SUCCESS; } static inline vg_lite_error_t transform_bounding_box(vg_lite_rectangle_t *in_bbx, vg_lite_matrix_t *matrix, vg_lite_rectangle_t *clip, vg_lite_rectangle_t *out_bbx, vg_lite_point_t *origin); #if (VG_BLIT_WORKAROUND == 1) /* * Calculates the minimal possible target buffer starting from a given target * buffer and considering a source texture (to blit), graphic transformations * and clipping window. */ static vg_lite_error_t config_new_target(vg_lite_buffer_t *target, vg_lite_buffer_t *source, vg_lite_matrix_t *matrix, vg_lite_rectangle_t *clip, vg_lite_buffer_t *new_target); #endif /* VG_BLIT_WORKAROUND */ static vg_lite_error_t swap(float *a,float *b) { float temp; if(a == NULL || b == NULL) return VG_LITE_INVALID_ARGUMENT; temp = *a; *a = *b; *b = temp; return VG_LITE_SUCCESS; } static vg_lite_float_t _angle( vg_lite_float_t Ux, vg_lite_float_t Uy, vg_lite_float_t Vx, vg_lite_float_t Vy ) { vg_lite_float_t dot, length, angle, cosVal; int32_t sign; dot = Ux * Vx + Uy * Vy; length = SQRTF(Ux * Ux + Uy * Uy) * SQRTF(Vx * Vx + Vy * Vy); sign = (Ux * Vy - Uy * Vx < 0) ? -1 : 1; cosVal = dot / length; cosVal = CLAMP(cosVal, -1.0f, 1.0f); angle = sign * ACOSF(cosVal); return angle; } /*! @discussion Convert arc to multi-segment bezier curve. @param HorRadius Major axis radius. @param VerRadius minor axis radius. @param RotAngle Rotation angle. @param EndX End coordinate x. @param EndX End coordinate y. @param CounterClockwise If this is 0,anticlockwise rotation,if this is 1,clockwise rotation. @param Large 1 means big arc,0 means little arc. @param Relative 1 means absolute coordinates,0 means relative coordinates. @param coords Including the start point coordinates of the path,the control point of the last segment of the path, and the end point of the last segment of the path. @param path_data Path data usr for internal conversion. @param offset The offset of path_data. @param last_size The remain unconverted size of the original path data. @result Error code. VG_LITE_INVALID_ARGUMENTS to indicate the parameters are wrong. */ vg_lite_error_t _convert_arc( vg_lite_float_t HorRadius, vg_lite_float_t VerRadius, vg_lite_float_t RotAngle, vg_lite_float_t EndX, vg_lite_float_t EndY, uint8_t CounterClockwise, uint8_t Large, uint8_t Relative, vg_lite_control_coord_t* coords, void ** path_data, uint32_t *offset, uint32_t last_size ) { vg_lite_float_t endX, endY; uint8_t segmentCommand; vg_lite_float_t phi, cosPhi, sinPhi; vg_lite_float_t dxHalf, dyHalf; vg_lite_float_t x1Prime, y1Prime; vg_lite_float_t rx, ry; vg_lite_float_t x1PrimeSquare, y1PrimeSquare; vg_lite_float_t lambda; vg_lite_float_t rxSquare, rySquare; int32_t sign; vg_lite_float_t sq, signedSq; vg_lite_float_t cxPrime, cyPrime; vg_lite_float_t theta1, thetaSpan; int32_t segs; vg_lite_float_t theta, ax, ay, x, y; vg_lite_float_t controlX, controlY, anchorX, anchorY; vg_lite_float_t lastX, lastY; uint32_t bufferSize; char *pchar, *arcPath; vg_lite_float_t *pfloat; /******************************************************************* ** Converting. */ if(path_data == NULL || *path_data == NULL || offset == NULL || coords == NULL) return VG_LITE_INVALID_ARGUMENT; if (Relative) { endX = EndX + coords->lastX; endY = EndY + coords->lastY; } else { endX = EndX; endY = EndY; } phi = RotAngle / 180.0f * PI; cosPhi = COSF(phi); sinPhi = SINF(phi); if (Relative) { dxHalf = - EndX / 2.0f; dyHalf = - EndY / 2.0f; } else { dxHalf = (coords->lastX - endX) / 2.0f; dyHalf = (coords->lastY - endY) / 2.0f; } x1Prime = cosPhi * dxHalf + sinPhi * dyHalf; y1Prime = -sinPhi * dxHalf + cosPhi * dyHalf; rx = FABSF(HorRadius); ry = FABSF(VerRadius); x1PrimeSquare = x1Prime * x1Prime; y1PrimeSquare = y1Prime * y1Prime; lambda = x1PrimeSquare / (rx * rx) + y1PrimeSquare / (ry * ry); if (lambda > 1.0f) { rx *= SQRTF(lambda); ry *= SQRTF(lambda); } rxSquare = rx * rx; rySquare = ry * ry; sign = (Large == CounterClockwise) ? -1 : 1; sq = ( rxSquare * rySquare - rxSquare * y1PrimeSquare - rySquare * x1PrimeSquare ) / ( rxSquare * y1PrimeSquare + rySquare * x1PrimeSquare ); signedSq = sign * ((sq < 0) ? 0 : SQRTF(sq)); cxPrime = signedSq * (rx * y1Prime / ry); cyPrime = signedSq * -(ry * x1Prime / rx); theta1 = _angle(1, 0, (x1Prime - cxPrime) / rx, (y1Prime - cyPrime) / ry); theta1 = FMODF(theta1, 2 * PI); thetaSpan = _angle(( x1Prime - cxPrime) / rx, ( y1Prime - cyPrime) / ry, (-x1Prime - cxPrime) / rx, (-y1Prime - cyPrime) / ry); if (!CounterClockwise && (thetaSpan > 0)) { thetaSpan -= 2 * PI; } else if (CounterClockwise && (thetaSpan < 0)) { thetaSpan += 2 * PI; } thetaSpan = FMODF(thetaSpan, 2 * PI); /******************************************************************* ** Drawing. */ segs = (int32_t) (CEILF(FABSF(thetaSpan) / (45.0f / 180.0f * PI))); theta = thetaSpan / segs; ax = coords->lastX - COSF(theta1) * rx; ay = coords->lastY - SINF(theta1) * ry; /* Determine the segment command. */ segmentCommand = Relative ? VLC_OP_QUAD_REL : VLC_OP_QUAD; /* Determine the size of the buffer required. */ bufferSize = (1 + 2 * 2) * SIZEOF(vg_lite_float_t) * segs; arcPath = (char *)vg_lite_os_malloc(*offset + bufferSize + last_size); if (arcPath == NULL) return VG_LITE_OUT_OF_MEMORY; memset(arcPath, 0, *offset + bufferSize + last_size); memcpy(arcPath,(char *)*path_data,*offset); vg_lite_os_free(*path_data); *path_data = arcPath; pchar = arcPath + *offset; pfloat = (vg_lite_float_t *)pchar; /* Set initial last point. */ lastX = coords->lastX; lastY = coords->lastY; while (segs-- > 0) { theta1 += theta; controlX = ax + COSF(theta1 - (theta / 2.0f)) * rx / COSF(theta / 2.0f); controlY = ay + SINF(theta1 - (theta / 2.0f)) * ry / COSF(theta / 2.0f); anchorX = ax + COSF(theta1) * rx; anchorY = ay + SINF(theta1) * ry; if (RotAngle != 0) { x = coords->lastX + cosPhi * (controlX - coords->lastX) - sinPhi * (controlY - coords->lastY); y = coords->lastY + sinPhi * (controlX - coords->lastX) + cosPhi * (controlY - coords->lastY); controlX = x; controlY = y; x = coords->lastX + cosPhi * (anchorX - coords->lastX) - sinPhi * (anchorY - coords->lastY); y = coords->lastY + sinPhi * (anchorX - coords->lastX) + cosPhi * (anchorY - coords->lastY); anchorX = x; anchorY = y; } if (segs == 0) { /* Use end point directly to avoid accumulated errors. */ anchorX = endX; anchorY = endY; } /* Adjust relative coordinates. */ if (Relative) { vg_lite_float_t nextLastX = anchorX; vg_lite_float_t nextLastY = anchorY; controlX -= lastX; controlY -= lastY; anchorX -= lastX; anchorY -= lastY; lastX = nextLastX; lastY = nextLastY; } pchar = (char*)pfloat; *pchar = segmentCommand ; pfloat++; *pfloat++ = controlX; *pfloat++ = controlY; *pfloat++ = anchorX; *pfloat++ = anchorY; *offset += (1 + 2 * 2) * SIZEOF(vg_lite_float_t); } /* Update the control coordinates. */ coords->lastX = endX; coords->lastY = endY; coords->controlX = endX; coords->controlY = endY; return VG_LITE_SUCCESS; } vg_lite_error_t _allocate_command_buffer(uint32_t size) { vg_lite_kernel_allocate_t allocate; vg_lite_error_t error = VG_LITE_SUCCESS; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t *tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif if(size == 0) return VG_LITE_SUCCESS; allocate.bytes = size; allocate.contiguous = 1; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); ctx->context.command_buffer[0] = allocate.memory_handle; ctx->context.command_buffer_logical[0] = allocate.memory; ctx->context.command_buffer_physical[0] = allocate.memory_gpu; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); ctx->context.command_buffer[1] = allocate.memory_handle; ctx->context.command_buffer_logical[1] = allocate.memory; ctx->context.command_buffer_physical[1] = allocate.memory_gpu; ctx->command_buffer[0] = ctx->context.command_buffer_logical[0]; ctx->command_buffer[1] = ctx->context.command_buffer_logical[1]; ctx->command_buffer_size = size; ctx->command_offset[0] = 0; ctx->command_offset[1] = 0; ctx->command_buffer_current = 0; #if !defined(VG_DRIVER_SINGLE_THREAD) ctx->start_offset = 0; ctx->end_offset = 0; ctx->ts_init = 0; memset(ctx->ts_record, 0, sizeof(ctx->ts_record)); #endif return error; } vg_lite_error_t _free_command_buffer() { vg_lite_kernel_free_t free; vg_lite_error_t error = VG_LITE_SUCCESS; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif if(ctx->context.command_buffer[0]){ free.memory_handle = ctx->context.command_buffer[0]; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &free)); ctx->context.command_buffer[0] = 0; ctx->context.command_buffer_logical[0] = 0; } if(ctx->context.command_buffer[1]){ free.memory_handle = ctx->context.command_buffer[1]; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &free)); ctx->context.command_buffer[1] = 0; ctx->context.command_buffer_logical[1] = 0; } return error; } static void ClampColor(FLOATVECTOR4 Source,FLOATVECTOR4 Target,uint8_t Premultiplied) { vg_lite_float_t colorMax; /* Clamp the alpha channel. */ Target[3] = CLAMP(Source[3], 0.0f, 1.0f); /* Determine the maximum value for the color channels. */ colorMax = Premultiplied ? Target[3] : 1.0f; /* Clamp the color channels. */ Target[0] = CLAMP(Source[0], 0.0f, colorMax); Target[1] = CLAMP(Source[1], 0.0f, colorMax); Target[2] = CLAMP(Source[2], 0.0f, colorMax); } static uint8_t PackColorComponent(vg_lite_float_t value) { /* Compute the rounded normalized value. */ vg_lite_float_t rounded = value * 255.0f + 0.5f; /* Get the integer part. */ int32_t roundedInt = (int32_t) rounded; /* Clamp to 0..1 range. */ uint8_t clamped = (uint8_t) CLAMP(roundedInt, 0, 255); /* Return result. */ return clamped; } #if !defined(VG_DRIVER_SINGLE_THREAD) static void command_buffer_copy(void *new_cmd, void *old_cmd, uint32_t start, uint32_t end, uint32_t *cmd_count) { uint32_t i = start,j; uint32_t *p_new_cmd32,*p_cmd32,*temp; uint32_t data_count = 0; memset(&hw,0,sizeof(vg_lite_hardware_t)); temp = NULL; p_new_cmd32 = (uint32_t *)new_cmd; p_cmd32 = (uint32_t *)old_cmd; while(i < end) { /* data command is 0x40000000 | count, and count = databytes / 8 ,and data command and databytes should align to 8 */ if((*p_cmd32 & 0xF0000000) == 0x40000000) { data_count = *p_cmd32 & 0x0FFFFFFF; data_count++; p_cmd32 += 2 * data_count; i += data_count * 8; /* SEMAPHORE command is 0x10000000 | id,stall command is 0x20000000 | id , call command is is 0x20000000 | count, and this three command should occupy 8bytes*/ }else if((*p_cmd32 & 0xF0000000) == 0x20000000 || (*p_cmd32 & 0xF0000000) == 0x10000000 || (*p_cmd32 & 0xF0000000) == 0x60000000 || (*p_cmd32 & 0xF0000000) == 0x80000000){ p_cmd32 += 2; i += 8; /* register command is 0x30000000 | ((count) << 16) | address, and the bytes of this command add register count should align to 8 */ }else if((*p_cmd32 & 0xF0000000) == 0x30000000) { /* get register data count */ data_count = (*p_cmd32 & 0x0FFFFFFF) >> 16; if(data_count == 1) { temp = p_cmd32 + 1; if(hw.hw_states[*p_cmd32 & 0xff].state != *temp || !hw.hw_states[*p_cmd32 & 0xff].init){ hw.hw_states[*p_cmd32 & 0xff].state = *temp; hw.hw_states[*p_cmd32 & 0xff].init = 1; for(j = 0; j < 2; j++) { *p_new_cmd32 = *p_cmd32; p_new_cmd32++; p_cmd32++; *cmd_count += 4; i += 4; } } else { p_cmd32 += 2; i += 8; } }else{ /* the bytes of register count add register command */ data_count++; if(data_count % 2 != 0) data_count++; for(j = 0; j < data_count; j++) { *p_new_cmd32 = *p_cmd32; p_new_cmd32++; p_cmd32++; *cmd_count += 4; i += 4; } } } } } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ static void _memset(void *p, unsigned char value, int size) { int i; for (i = 0; i < size; i++) { ((unsigned char*) p)[i] = value; } } static int has_valid_command_buffer(vg_lite_context_t *context) { if(context == NULL) return 0; if(context->command_buffer_current >= CMDBUF_COUNT) return 0; if(context->command_buffer[context->command_buffer_current] == NULL) return 0; return 1; } #if !defined(VG_DRIVER_SINGLE_THREAD) static int has_valid_context_buffer(vg_lite_context_t *context) { if(context == NULL) return 0; if(context->context_buffer == NULL) return 0; return 1; } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ #if DUMP_IMAGE static void dump_img(void * memory, int width, int height, vg_lite_buffer_format_t format) { FILE * fp; char imgname[255] = {'\0'}; int i; static int num = 1; unsigned int* pt = (unsigned int*) memory; sprintf(imgname, "img_pid%d_%d.txt", getpid(), num++); fp = fopen(imgname, "w"); if (fp == NULL) printf("error!\n"); switch (format) { case VG_LITE_INDEX_1: for(i = 0; i < width * height / 32; ++i) { fprintf(fp, "0x%08x\n",pt[i]); } break; case VG_LITE_INDEX_2: for(i = 0; i < width * height / 16; ++i) { fprintf(fp, "0x%08x\n",pt[i]); } break; case VG_LITE_INDEX_4: for(i = 0; i < width * height / 8; ++i) { fprintf(fp, "0x%08x\n",pt[i]); } break; case VG_LITE_INDEX_8: for(i = 0; i < width * height / 4; ++i) { fprintf(fp, "0x%08x\n",pt[i]); } break; case VG_LITE_RGBA2222: for(i = 0; i < width * height / 4; ++i) { fprintf(fp, "0x%08x\n",pt[i]); } break; case VG_LITE_RGBA4444: case VG_LITE_BGRA4444: case VG_LITE_RGB565: case VG_LITE_BGR565: for(i = 0; i < width * height / 2; ++i) { fprintf(fp, "0x%08x\n",pt[i]); } break; case VG_LITE_RGBA8888: case VG_LITE_BGRA8888: case VG_LITE_RGBX8888: case VG_LITE_BGRX8888: for(i = 0; i < width * height; ++i) { fprintf(fp, "0x%08x\n",pt[i]); } break; default: break; } fclose(fp); fp = NULL; } #endif /* Convert VGLite data format to HW value. */ static uint32_t convert_path_format(vg_lite_format_t format) { switch (format) { case VG_LITE_S8: return 0; case VG_LITE_S16: return 0x100000; case VG_LITE_S32: return 0x200000; case VG_LITE_FP32: return 0x300000; default: return 0; } } /* Convert VGLite quality enums to HW values. */ static uint32_t convert_path_quality(vg_lite_quality_t quality) { switch (quality) { case VG_LITE_HIGH: return 0x3; case VG_LITE_UPPER: return 0x2; case VG_LITE_MEDIUM: return 0x1; default: return 0x0; } } static uint32_t rgb_to_l(uint32_t color) { uint32_t l = (uint32_t)((0.2126f * (vg_lite_float_t)(color & 0xFF)) + (0.7152f * (vg_lite_float_t)((color >> 8) & 0xFF)) + (0.0722f * (vg_lite_float_t)((color >> 16) & 0xFF))); return l | (l << 24); } /* Get the bpp information of a color format. */ static void get_format_bytes(vg_lite_buffer_format_t format, uint32_t *mul, uint32_t *div, uint32_t *bytes_align) { *mul = *div = 1; *bytes_align = 4; switch (format) { case VG_LITE_L8: case VG_LITE_A8: *bytes_align = 16; break; case VG_LITE_A4: *div = 2; *bytes_align = 8; break; case VG_LITE_ABGR1555: case VG_LITE_ARGB1555: case VG_LITE_BGRA5551: case VG_LITE_RGBA5551: case VG_LITE_RGBA4444: case VG_LITE_BGRA4444: case VG_LITE_ABGR4444: case VG_LITE_ARGB4444: case VG_LITE_RGB565: case VG_LITE_BGR565: case VG_LITE_YUYV: case VG_LITE_YUY2: case VG_LITE_YUY2_TILED: /* AYUY2 buffer memory = YUY2 + alpha. */ case VG_LITE_AYUY2: case VG_LITE_AYUY2_TILED: *mul = 2; *bytes_align = 32; break; case VG_LITE_RGBA8888: case VG_LITE_BGRA8888: case VG_LITE_ABGR8888: case VG_LITE_ARGB8888: case VG_LITE_RGBX8888: case VG_LITE_BGRX8888: case VG_LITE_XBGR8888: case VG_LITE_XRGB8888: *mul = 4; *bytes_align = 64; break; case VG_LITE_NV12: case VG_LITE_NV12_TILED: *mul = 3; *bytes_align = 32; break; case VG_LITE_ANV12: case VG_LITE_ANV12_TILED: *mul = 4; *bytes_align = 64; break; case VG_LITE_INDEX_1: *div = 8; *bytes_align = 8; break; case VG_LITE_INDEX_2: *div = 4; *bytes_align = 8; break; case VG_LITE_INDEX_4: *div = 2; *bytes_align = 8; break; case VG_LITE_INDEX_8: *bytes_align = 16; break; case VG_LITE_RGBA2222: case VG_LITE_BGRA2222: case VG_LITE_ABGR2222: case VG_LITE_ARGB2222: *mul = 1; *bytes_align = 8; break; default: break; } } /* Convert VGLite target color format to HW value. */ static uint32_t convert_target_format(vg_lite_buffer_format_t format, vg_lite_capabilities_t caps) { switch (format) { case VG_LITE_A8: return 0x0; case VG_LITE_L8: return 0x6; case VG_LITE_ABGR4444: return 0x14; case VG_LITE_ARGB4444: return 0x34; case VG_LITE_RGBA4444: return 0x24; case VG_LITE_BGRA4444: return 0x4; case VG_LITE_RGB565: return 0x21; case VG_LITE_BGR565: return 0x1; case VG_LITE_ABGR8888: return 0x13; case VG_LITE_ARGB8888: return 0x33; case VG_LITE_RGBA8888: return 0x23; case VG_LITE_BGRA8888: return 0x3; case VG_LITE_RGBX8888: return 0x22; case VG_LITE_BGRX8888: return 0x2; case VG_LITE_XBGR8888: return 0x12; case VG_LITE_XRGB8888: return 0x32; case VG_LITE_ABGR1555: return 0x15; case VG_LITE_RGBA5551: return 0x25; case VG_LITE_ARGB1555: return 0x35; case VG_LITE_BGRA5551: return 0x5; case VG_LITE_YUYV: case VG_LITE_YUY2: case VG_LITE_YUY2_TILED: return 0x8; case VG_LITE_NV12: case VG_LITE_NV12_TILED: return 0xB; case VG_LITE_ANV12: case VG_LITE_ANV12_TILED: return 0xE; case VG_LITE_BGRA2222: return 0x7; case VG_LITE_RGBA2222: return 0x27; case VG_LITE_ABGR2222: return 0x17; case VG_LITE_ARGB2222: return 0x37; case VG_LITE_AYUY2: case VG_LITE_AYUY2_TILED: default: return 0xF; } } /* determine source IM is aligned by specified bytes */ static vg_lite_error_t _check_source_aligned(vg_lite_buffer_format_t format,uint32_t stride) { switch (format) { case VG_LITE_A4: case VG_LITE_INDEX_1: case VG_LITE_INDEX_2: case VG_LITE_INDEX_4: FORMAT_ALIGNMENT(stride,8); break; case VG_LITE_L8: case VG_LITE_A8: case VG_LITE_INDEX_8: case VG_LITE_RGBA2222: case VG_LITE_BGRA2222: case VG_LITE_ABGR2222: case VG_LITE_ARGB2222: FORMAT_ALIGNMENT(stride,16); break; case VG_LITE_RGBA4444: case VG_LITE_BGRA4444: case VG_LITE_ABGR4444: case VG_LITE_ARGB4444: case VG_LITE_RGB565: case VG_LITE_BGR565: case VG_LITE_BGRA5551: case VG_LITE_RGBA5551: case VG_LITE_ABGR1555: case VG_LITE_ARGB1555: case VG_LITE_YUYV: case VG_LITE_YUY2: case VG_LITE_NV12: case VG_LITE_YV12: case VG_LITE_YV24: case VG_LITE_YV16: case VG_LITE_NV16: FORMAT_ALIGNMENT(stride,32); break; case VG_LITE_RGBA8888: case VG_LITE_BGRA8888: case VG_LITE_ABGR8888: case VG_LITE_ARGB8888: case VG_LITE_RGBX8888: case VG_LITE_BGRX8888: case VG_LITE_XBGR8888: case VG_LITE_XRGB8888: FORMAT_ALIGNMENT(stride,64); break; default: return VG_LITE_SUCCESS; } } /* Convert VGLite source color format to HW values. */ static uint32_t convert_source_format(vg_lite_buffer_format_t format) { switch (format) { case VG_LITE_L8: return 0x0; case VG_LITE_A4: return 0x1; case VG_LITE_A8: return 0x2; case VG_LITE_RGBA4444: return 0x23; case VG_LITE_BGRA4444: return 0x3; case VG_LITE_ABGR4444: return 0x13; case VG_LITE_ARGB4444: return 0x33; case VG_LITE_RGB565: return 0x25; case VG_LITE_BGR565: return 0x5; case VG_LITE_RGBA8888: return 0x27; case VG_LITE_BGRA8888: return 0x7; case VG_LITE_ABGR8888: return 0x17; case VG_LITE_ARGB8888: return 0x37; case VG_LITE_RGBX8888: return 0x26; case VG_LITE_BGRX8888: return 0x6; case VG_LITE_XBGR8888: return 0x16; case VG_LITE_XRGB8888: return 0x36; case VG_LITE_BGRA5551: return 0x4; case VG_LITE_RGBA5551: return 0x24; case VG_LITE_ABGR1555: return 0x14; case VG_LITE_ARGB1555: return 0x34; case VG_LITE_YUYV: return 0x8; case VG_LITE_YUY2: case VG_LITE_YUY2_TILED: return 0x8; case VG_LITE_NV12: case VG_LITE_NV12_TILED: return 0xB; case VG_LITE_ANV12: case VG_LITE_ANV12_TILED: return 0xE; case VG_LITE_YV12: return 0x9; case VG_LITE_YV24: return 0xD; case VG_LITE_YV16: return 0xC; case VG_LITE_NV16: return 0xA; case VG_LITE_AYUY2: case VG_LITE_AYUY2_TILED: default: return 0xF; case VG_LITE_INDEX_1: return 0x200; case VG_LITE_INDEX_2: return 0x400; case VG_LITE_INDEX_4: return 0x600; case VG_LITE_INDEX_8: return 0x800; case VG_LITE_RGBA2222: return 0xA20; case VG_LITE_BGRA2222: return 0xA00; case VG_LITE_ABGR2222: return 0xA10; case VG_LITE_ARGB2222: return 0xA30; } } /* Convert VGLite blend modes to HW values. */ static uint32_t convert_blend(vg_lite_blend_t blend) { switch (blend) { case VG_LITE_BLEND_SRC_OVER: return 0x00000100; case VG_LITE_BLEND_DST_OVER: return 0x00000200; case VG_LITE_BLEND_SRC_IN: return 0x00000300; case VG_LITE_BLEND_DST_IN: return 0x00000400; case VG_LITE_BLEND_SCREEN: return 0x00000600; case VG_LITE_BLEND_MULTIPLY: return 0x00000500; case VG_LITE_BLEND_ADDITIVE: return 0x00000900; case VG_LITE_BLEND_SUBTRACT: return 0x00000A00; default: return 0; } } /* Convert VGLite uv swizzle enums to HW values. */ static uint32_t convert_uv_swizzle(vg_lite_swizzle_t swizzle) { switch (swizzle) { case VG_LITE_SWIZZLE_UV: return 0x00000040; break; case VG_LITE_SWIZZLE_VU: return 0x00000050; default: return 0; break; } } /* Convert VGLite yuv standard enums to HW values. */ static uint32_t convert_yuv2rgb(vg_lite_yuv2rgb_t yuv) { switch (yuv) { case VG_LITE_YUV601: return 0; break; case VG_LITE_YUV709: return 0x00008000; default: return 0; break; } } /* Initialize the feature table of a chip. */ static vg_lite_error_t fill_feature_table(uint32_t * feature) { uint16_t size = sizeof(VGFeatureInfos) / sizeof(VGFeatureInfos[0]); uint16_t i; uint32_t cid = 0; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* Clear all bits. */ _memset(feature, 0, sizeof(uint32_t) * gcFEATURE_COUNT); vg_lite_get_product_info(NULL,&ctx->chip_id,&ctx->chip_rev); if(ctx->chip_id == GPU_CHIP_ID_GC355) ctx->premultiply_enabled = 1; vg_lite_get_register(0x30, &cid); for(i = 0;i < size; i++){ if ((VGFeatureInfos[i].chip_id == ctx->chip_id) && (VGFeatureInfos[i].chip_version == ctx->chip_rev) && (VGFeatureInfos[i].cid == cid) ) { feature[gcFEATURE_BIT_VG_IM_INDEX_FORMAT] = VGFeatureInfos[i].vg_im_index_format; feature[gcFEATURE_BIT_VG_PE_PREMULTIPLY] = VGFeatureInfos[i].vg_pe_premultiply; feature[gcFEATURE_BIT_VG_BORDER_CULLING] = VGFeatureInfos[i].vg_border_culling; feature[gcFEATURE_BIT_VG_RGBA2_FORMAT] = VGFeatureInfos[i].vg_rgba2_format; feature[gcFEATURE_BIT_VG_QUALITY_8X] = VGFeatureInfos[i].vg_quality_8x; feature[gcFEATURE_BIT_VG_RADIAL_GRADIENT] = VGFeatureInfos[i].vg_radial_gradient; feature[gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT] = VGFeatureInfos[i].vg_linear_gradient_ext; feature[gcFEATURE_BIT_VG_DITHER] = VGFeatureInfos[i].vg_dither; feature[gcFEATURE_BIT_VG_COLOR_KEY] = VGFeatureInfos[i].vg_color_key; break; } } if(i == size) { return VG_LITE_INVALID_ARGUMENT; } ctx->s_ftable.ftflag = 1; return VG_LITE_SUCCESS; } #if !defined(VG_DRIVER_SINGLE_THREAD) static vg_lite_error_t flush(vg_lite_context_t *context); #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ static vg_lite_error_t submit(vg_lite_context_t * context); #if defined(VG_DRIVER_SINGLE_THREAD) static vg_lite_error_t stall(vg_lite_context_t * context, uint32_t time_ms, uint32_t mask); #else static vg_lite_error_t stall(vg_lite_context_t * context, uint32_t time_ms); #endif /* VG_DRIVER_SINGLE_THREAD */ #if !defined(VG_DRIVER_SINGLE_THREAD) /* Push a state array into context buffer. */ static vg_lite_error_t push_states_to_context(vg_lite_context_t * context, uint32_t address, uint32_t count, uint32_t *data) { uint32_t i, command_id; vg_lite_error_t error; if (!has_valid_context_buffer(context)) return VG_LITE_NO_CONTEXT; command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); /* Reserve enough space in the context buffer for flush and submit */ if (context->context_buffer_offset[command_id] + 8 >= context->context_buffer_size) { return VG_LITE_OUT_OF_RESOURCES; } ((uint32_t *) (context->context_buffer[command_id] + context->context_buffer_offset[command_id]))[0] = VG_LITE_STATES(count, address); for (i = 0; i < count; i++) { ((uint32_t *) (context->context_buffer[command_id] + context->context_buffer_offset[command_id]))[1 + i] = data[i]; } if (i%2 == 0) { ((uint32_t *) (context->context_buffer[command_id] + context->context_buffer_offset[command_id]))[1 + i] = VG_LITE_NOP(); } context->context_buffer_offset[command_id] += VG_LITE_ALIGN(count + 1, 2) * 4; return VG_LITE_SUCCESS; } static vg_lite_error_t update_context_buffer() { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_kernel_context_switch_t check; vg_lite_tls_t* tls; uint32_t command_id; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; command_id = CMDBUF_INDEX(tls->t_context); check.context =(uint32_t)&tls->t_context.context; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_QUERY_CONTEXT_SWITCH, &check)); /* if context have been switched and this task need use index. */ if(check.isContextSwitched && tls->t_context.index_format) { uint32_t clut_addr[4]={0x0A98,0x0A9C,0x0AA0,0x0B00}; uint32_t clut_count[4]={2,4,16,256}; for(int i = 0; i < 4; i++) { /* check which index colors would be use in this task. */ if(tls->t_context.colors[i] && tls->t_context.clut_used[i]){ VG_LITE_RETURN_ERROR(push_states_to_context(&tls->t_context, clut_addr[i], clut_count[i], tls->t_context.colors[i])); tls->t_context.clut_used[i] = 0; } } tls->t_context.index_format = 0; } /* Set tessellation buffer states */ if(check.isContextSwitched && tls->t_context.ts_init && !tls->t_context.ts_init_used && tls->t_context.ts_init_use){ /* Reserve enough space in the context buffer for flush and submit */ if (tls->t_context.context_buffer_offset[command_id] + 80 >= tls->t_context.context_buffer_size) { return VG_LITE_OUT_OF_RESOURCES; } memcpy(tls->t_context.context_buffer[command_id] + tls->t_context.context_buffer_offset[command_id], tls->t_context.ts_record, 80); tls->t_context.ts_init = 0; tls->t_context.ts_init_used = 0; tls->t_context.ts_init_use = 0; tls->t_context.context_buffer_offset[command_id] += 80; } if(tls->t_context.context_buffer_offset[command_id]){ ((uint32_t *) (tls->t_context.context_buffer[command_id] + tls->t_context.context_buffer_offset[command_id]))[0] = VG_LITE_RETURN(); ((uint32_t *) (tls->t_context.context_buffer[command_id] + tls->t_context.context_buffer_offset[command_id]))[1] = 0; tls->t_context.context_buffer_offset[command_id] += 8; ((uint32_t *) CMDBUF_BUFFER(tls->t_context))[0] = VG_LITE_CALL((tls->t_context.context_buffer_offset[command_id] + 7) / 8); ((uint32_t *) CMDBUF_BUFFER(tls->t_context))[1] = tls->t_context.context.context_buffer_physical[command_id]; tls->t_context.context_buffer_offset[command_id] = 0; } return error; } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ #if defined(VG_DRIVER_SINGLE_THREAD) /* Push a state array into current command buffer. */ static vg_lite_error_t push_states(vg_lite_context_t * context, uint32_t address, uint32_t count, uint32_t *data) { uint32_t i; vg_lite_error_t error; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; if (CMDBUF_OFFSET(*context) + 8 + VG_LITE_ALIGN(count + 1, 2) * 4 >= CMDBUF_SIZE(*context)) { VG_LITE_RETURN_ERROR(submit(context)); VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATES(count, address); for (i = 0; i < count; i++) { ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1 + i] = data[i]; } if (i%2 == 0) { ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1 + i] = VG_LITE_NOP(); } CMDBUF_OFFSET(*context) += VG_LITE_ALIGN(count + 1, 2) * 4; return VG_LITE_SUCCESS; } /* Push a single state command into the current command buffer. */ static vg_lite_error_t push_state(vg_lite_context_t * context, uint32_t address, uint32_t data) { vg_lite_error_t error; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; if (CMDBUF_OFFSET(*context) + 16 >= CMDBUF_SIZE(*context)) { VG_LITE_RETURN_ERROR(submit(context)); VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATE(address); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = data; CMDBUF_OFFSET(*context) += 8; return VG_LITE_SUCCESS; } /* Push a single state command with given address. */ static vg_lite_error_t push_state_ptr(vg_lite_context_t * context, uint32_t address, void * data_ptr) { vg_lite_error_t error; uint32_t data = *(uint32_t *) data_ptr; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; if (CMDBUF_OFFSET(*context) + 16 >= CMDBUF_SIZE(*context)) { VG_LITE_RETURN_ERROR(submit(context)); VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATE(address); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = data; CMDBUF_OFFSET(*context) += 8; return VG_LITE_SUCCESS; } /* Push a "call" command into the current command buffer. */ static vg_lite_error_t push_call(vg_lite_context_t * context, uint32_t address, uint32_t bytes) { vg_lite_error_t error; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; if (CMDBUF_OFFSET(*context) + 16 >= CMDBUF_SIZE(*context)) { VG_LITE_RETURN_ERROR(submit(context)); VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_CALL((bytes + 7) / 8); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = address; CMDBUF_OFFSET(*context) += 8; return VG_LITE_SUCCESS; } /* Push a rectangle command into the current command buffer. */ static vg_lite_error_t push_rectangle(vg_lite_context_t * context, int x, int y, int width, int height) { vg_lite_error_t error; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; if (CMDBUF_OFFSET(*context) + 16 >= CMDBUF_SIZE(*context)) { VG_LITE_RETURN_ERROR(submit(context)); VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_DATA(1); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[4] = (uint16_t)x; ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[5] = (uint16_t)y; ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[6] = (uint16_t)width; ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[7] = (uint16_t)height; CMDBUF_OFFSET(*context) += 16; return VG_LITE_SUCCESS; } /* Push a data array into the current command buffer. */ static vg_lite_error_t push_data(vg_lite_context_t * context, int size, void * data) { vg_lite_error_t error; int bytes = VG_LITE_ALIGN(size, 8); if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; if (CMDBUF_OFFSET(*context) + 16 + bytes >= CMDBUF_SIZE(*context)) { VG_LITE_RETURN_ERROR(submit(context)); VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); } ((uint64_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(bytes / 8)] = 0; ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_DATA(bytes / 8); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context) + 8, data, size); CMDBUF_OFFSET(*context) += 8 + bytes; return VG_LITE_SUCCESS; } /* Push a "stall" command into the current command buffer. */ static vg_lite_error_t push_stall(vg_lite_context_t * context, uint32_t module) { vg_lite_error_t error; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; if (CMDBUF_OFFSET(*context) + 16 >= CMDBUF_SIZE(*context)) { VG_LITE_RETURN_ERROR(submit(context)); VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_SEMAPHORE(module); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[2] = VG_LITE_STALL(module); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[3] = 0; CMDBUF_OFFSET(*context) += 16; return VG_LITE_SUCCESS; } #else /* Push a state array into current command buffer. */ static vg_lite_error_t push_states(vg_lite_context_t * context, uint32_t address, uint32_t count, uint32_t *data) { uint32_t i, command_id, index; vg_lite_error_t error; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); /* Reserve enough space in the command buffer for flush and submit */ if (CMDBUF_OFFSET(*context) + 40 + VG_LITE_ALIGN(count + 1, 2) * 4 >= CMDBUF_SIZE(*context)) { uint32_t cmd_count = 0,start_offset = 0; context->end_offset = CMDBUF_OFFSET(*context); start_offset = context->start_offset; VG_LITE_RETURN_ERROR(flush(context)); VG_LITE_RETURN_ERROR(submit(context)); CMDBUF_SWAP(*context); command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); RESERVE_BYTES_IN_CMDBUF(*context); if(context->ts_init){ memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); CMDBUF_OFFSET(*context) += 80; context->ts_init_used = 1; } /* update start offset */ context->start_offset = CMDBUF_OFFSET(*context); index = (command_id? 0 : 1); command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), start_offset, context->end_offset, &cmd_count); CMDBUF_OFFSET(*context) += cmd_count; } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATES(count, address); for (i = 0; i < count; i++) { ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1 + i] = data[i]; } if (i%2 == 0) { ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1 + i] = VG_LITE_NOP(); } #if DUMP_COMMAND { uint32_t loops; if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, ", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0]); for (loops = 0; loops < count / 2; loops++) { fprintf(fp, "0x%08x,\nCommand buffer: 0x%08x, ", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(loops + 1) * 2 - 1], ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(loops + 1) * 2]); } fprintf(fp, "0x%08x,\n", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(loops + 1) * 2 - 1]); fclose(fp); fp = NULL; } #endif CMDBUF_OFFSET(*context) += VG_LITE_ALIGN(count + 1, 2) * 4; return VG_LITE_SUCCESS; } /* Push a single state command into the current command buffer. */ static vg_lite_error_t push_state(vg_lite_context_t * context, uint32_t address, uint32_t data) { vg_lite_error_t error; uint32_t command_id, index; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); /* Reserve enough space in the command buffer for flush and submit */ if (CMDBUF_OFFSET(*context) + 56 >= CMDBUF_SIZE(*context)) { uint32_t cmd_count = 0,start_offset = 0; context->end_offset = CMDBUF_OFFSET(*context); start_offset = context->start_offset; VG_LITE_RETURN_ERROR(flush(context)); VG_LITE_RETURN_ERROR(submit(context)); CMDBUF_SWAP(*context); command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); RESERVE_BYTES_IN_CMDBUF(*context); if(context->ts_init){ memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); CMDBUF_OFFSET(*context) += 80; context->ts_init_used = 1; } /* update start offset */ context->start_offset = CMDBUF_OFFSET(*context); index = (command_id? 0 : 1); command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), start_offset, context->end_offset, &cmd_count); CMDBUF_OFFSET(*context) += cmd_count; } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATE(address); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = data; #if DUMP_COMMAND if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1]); fclose(fp); fp = NULL; #endif CMDBUF_OFFSET(*context) += 8; return VG_LITE_SUCCESS; } /* Push a single state command with given address. */ static vg_lite_error_t push_state_ptr(vg_lite_context_t * context, uint32_t address, void * data_ptr) { vg_lite_error_t error; uint32_t command_id, index; uint32_t data = *(uint32_t *) data_ptr; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); /* Reserve enough space in the command buffer for flush and submit */ if (CMDBUF_OFFSET(*context) + 56 >= CMDBUF_SIZE(*context)) { uint32_t cmd_count = 0,start_offset = 0; context->end_offset = CMDBUF_OFFSET(*context); start_offset = context->start_offset; VG_LITE_RETURN_ERROR(flush(context)); VG_LITE_RETURN_ERROR(submit(context)); CMDBUF_SWAP(*context); command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); RESERVE_BYTES_IN_CMDBUF(*context); if(context->ts_init){ memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); CMDBUF_OFFSET(*context) += 80; context->ts_init_used = 1; } /* update start offset */ context->start_offset = CMDBUF_OFFSET(*context); index = (command_id? 0 : 1); command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), start_offset, context->end_offset, &cmd_count); CMDBUF_OFFSET(*context) += cmd_count; } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATE(address); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = data; #if DUMP_COMMAND if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1]); fclose(fp); fp = NULL; #endif CMDBUF_OFFSET(*context) += 8; return VG_LITE_SUCCESS; } /* Push a "call" command into the current command buffer. */ static vg_lite_error_t push_call(vg_lite_context_t * context, uint32_t address, uint32_t bytes) { vg_lite_error_t error; uint32_t command_id, index; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); /* Reserve enough space in the command buffer for flush and submit */ if (CMDBUF_OFFSET(*context) + 56 >= CMDBUF_SIZE(*context)) { uint32_t cmd_count = 0,start_offset = 0; context->end_offset = CMDBUF_OFFSET(*context); start_offset = context->start_offset; VG_LITE_RETURN_ERROR(flush(context)); VG_LITE_RETURN_ERROR(submit(context)); CMDBUF_SWAP(*context); command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); RESERVE_BYTES_IN_CMDBUF(*context); if(context->ts_init){ memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); CMDBUF_OFFSET(*context) += 80; context->ts_init_used = 1; } /* update start offset */ context->start_offset = CMDBUF_OFFSET(*context); index = (command_id? 0 : 1); command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), start_offset, context->end_offset, &cmd_count); CMDBUF_OFFSET(*context) += cmd_count; } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_CALL((bytes + 7) / 8); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = address; #if DUMP_COMMAND if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1]); fclose(fp); fp = NULL; #endif CMDBUF_OFFSET(*context) += 8; return VG_LITE_SUCCESS; } /* Push a rectangle command into the current command buffer. */ static vg_lite_error_t push_rectangle(vg_lite_context_t * context, int x, int y, int width, int height) { vg_lite_error_t error; uint32_t command_id, index; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); /* Reserve enough space in the command buffer for flush and submit */ if (CMDBUF_OFFSET(*context) + 56 >= CMDBUF_SIZE(*context)) { uint32_t cmd_count = 0,start_offset = 0; context->end_offset = CMDBUF_OFFSET(*context); start_offset = context->start_offset; VG_LITE_RETURN_ERROR(flush(context)); VG_LITE_RETURN_ERROR(submit(context)); CMDBUF_SWAP(*context); command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); RESERVE_BYTES_IN_CMDBUF(*context); if(context->ts_init){ memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); CMDBUF_OFFSET(*context) += 80; context->ts_init_used = 1; } /* update start offset */ context->start_offset = CMDBUF_OFFSET(*context); index = (command_id? 0 : 1); command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), start_offset, context->end_offset, &cmd_count); CMDBUF_OFFSET(*context) += cmd_count; } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_DATA(1); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[4] = (uint16_t)x; ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[5] = (uint16_t)y; ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[6] = (uint16_t)width; ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[7] = (uint16_t)height; #if DUMP_COMMAND if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], 0); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[5] << 16 | ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[4], ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[7] << 16 | ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[6]); fclose(fp); fp = NULL; #endif CMDBUF_OFFSET(*context) += 16; return VG_LITE_SUCCESS; } /* Push a data array into the current command buffer. */ static vg_lite_error_t push_data(vg_lite_context_t * context, int size, void * data) { vg_lite_error_t error; uint32_t command_id, index; int bytes = VG_LITE_ALIGN(size, 8); if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); /* Reserve enough space in the command buffer for flush and submit */ if (CMDBUF_OFFSET(*context) + 48 + bytes >= CMDBUF_SIZE(*context)) { uint32_t cmd_count = 0,start_offset = 0; context->end_offset = CMDBUF_OFFSET(*context); start_offset = context->start_offset; VG_LITE_RETURN_ERROR(flush(context)); VG_LITE_RETURN_ERROR(submit(context)); CMDBUF_SWAP(*context); command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); RESERVE_BYTES_IN_CMDBUF(*context); if(context->ts_init){ memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); CMDBUF_OFFSET(*context) += 80; context->ts_init_used = 1; } /* update start offset */ context->start_offset = CMDBUF_OFFSET(*context); index = (command_id? 0 : 1); command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), start_offset, context->end_offset, &cmd_count); CMDBUF_OFFSET(*context) += cmd_count; } ((uint64_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(bytes / 8)] = 0; ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_DATA(bytes / 8); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context) + 8, data, size); #if DUMP_COMMAND { int loops; if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], 0); for (loops = 0; loops < bytes / 8; loops++) { fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(loops + 1) * 2], ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(loops + 1) * 2 + 1]); } fclose(fp); fp = NULL; } #endif CMDBUF_OFFSET(*context) += 8 + bytes; return VG_LITE_SUCCESS; } /* Push a "stall" command into the current command buffer. */ static vg_lite_error_t push_stall(vg_lite_context_t * context, uint32_t module) { vg_lite_error_t error; uint32_t command_id, index; if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); /* Reserve enough space in the command buffer for flush and submit */ if (CMDBUF_OFFSET(*context) + 56 >= CMDBUF_SIZE(*context)) { uint32_t cmd_count = 0,start_offset = 0; context->end_offset = CMDBUF_OFFSET(*context); start_offset = context->start_offset; VG_LITE_RETURN_ERROR(flush(context)); VG_LITE_RETURN_ERROR(submit(context)); CMDBUF_SWAP(*context); command_id = CMDBUF_INDEX(*context); if(CMDBUF_IN_QUEUE(&context->context, command_id)) VG_LITE_RETURN_ERROR(stall(context, 0)); RESERVE_BYTES_IN_CMDBUF(*context); if(context->ts_init){ memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); CMDBUF_OFFSET(*context) += 80; context->ts_init_used = 1; } /* update start offset */ context->start_offset = CMDBUF_OFFSET(*context); index = (command_id? 0 : 1); command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), start_offset, context->end_offset, &cmd_count); CMDBUF_OFFSET(*context) += cmd_count; } ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_SEMAPHORE(module); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[2] = VG_LITE_STALL(module); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[3] = 0; #if DUMP_COMMAND if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], 0); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[2], 0); fclose(fp); fp = NULL; #endif CMDBUF_OFFSET(*context) += 16; return VG_LITE_SUCCESS; } static vg_lite_error_t flush(vg_lite_context_t *context) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t address0 = 0x0A34; uint32_t address1 = 0x0A1B; uint32_t data0 = 0; uint32_t data1 = 0x00000001; uint32_t module = 7; /* Check if there is a valid context and an allocated command buffer. */ if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; /* Check if there is anything to flush. */ if (CMDBUF_OFFSET(*context) == 0) return VG_LITE_INVALID_ARGUMENT; /* Check if there is enough space in the command buffer. */ if (CMDBUF_OFFSET(*context) + 32 > CMDBUF_SIZE(*context)) { return VG_LITE_OUT_OF_RESOURCES; } /* Finialize command buffer. */ ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATE(address0); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = data0; /* flush target */ ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[2] = VG_LITE_STATE(address1); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[3] = data1; ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[4] = VG_LITE_SEMAPHORE(module); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[5] = 0; ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[6] = VG_LITE_STALL(module); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[7] = 0; CMDBUF_OFFSET(*context) += 32; return error; } #endif /* VG_DRIVER_SINGLE_THREAD */ /* Submit the current command buffer to HW and reset the current command buffer offset. */ static vg_lite_error_t submit(vg_lite_context_t *context) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_kernel_submit_t submit; /* Check if there is a valid context and an allocated command buffer. */ if (!has_valid_command_buffer(context)) return VG_LITE_NO_CONTEXT; /* Check if there is anything to submit. */ if (CMDBUF_OFFSET(*context) == 0) return VG_LITE_INVALID_ARGUMENT; /* Check if there is enough space in the command buffer for the END. */ if (CMDBUF_OFFSET(*context) + 8 > CMDBUF_SIZE(*context)) { /* Reset command buffer offset. */ CMDBUF_OFFSET(*context) = 0; return VG_LITE_OUT_OF_RESOURCES; } /* Append END command into the command buffer. */ ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_END(0); ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; #if DUMP_COMMAND if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], 0); fprintf(fp, "Command buffer addr is : %p,\n", CMDBUF_BUFFER(*context)); fprintf(fp, "Command buffer offset is : %d,\n", CMDBUF_OFFSET(*context) + 8); fclose(fp); fp = NULL; #endif CMDBUF_OFFSET(*context) += 8; /* Submit the command buffer. */ submit.context = &context->context; submit.commands = CMDBUF_BUFFER(*context); submit.command_size = CMDBUF_OFFSET(*context); submit.command_id = CMDBUF_INDEX(*context); #if defined(VG_DRIVER_SINGLE_THREAD) /* Wait if GPU has not completed previous CMD buffer */ if (submit_flag) { VG_LITE_RETURN_ERROR(stall(&s_context, 0, (uint32_t)~0)); } #endif /* VG_DRIVER_SINGLE_THREAD */ VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_SUBMIT, &submit)); #if defined(VG_DRIVER_SINGLE_THREAD) submit_flag = 1; #endif /* VG_DRIVER_SINGLE_THREAD */ vglitemDUMP_BUFFER("command", (unsigned int)CMDBUF_BUFFER(*context), submit.context->command_buffer_logical[CMDBUF_INDEX(*context)], 0, submit.command_size); vglitemDUMP("@[commit]"); /* Reset command buffer. */ CMDBUF_OFFSET(*context) = 0; return error; } /* Wait for the HW to finish the current execution. */ #if defined(VG_DRIVER_SINGLE_THREAD) static vg_lite_error_t stall(vg_lite_context_t *context, uint32_t time_ms, uint32_t mask) #else static vg_lite_error_t stall(vg_lite_context_t *context, uint32_t time_ms) #endif /* VG_DRIVER_SINGLE_THREAD */ { vg_lite_error_t error; vg_lite_kernel_wait_t wait; vglitemDUMP("@[stall]"); /* Wait until GPU is ready. */ wait.context = &context->context; #if defined(VG_DRIVER_SINGLE_THREAD) wait.timeout_ms = time_ms > 0 ? time_ms : VG_LITE_INFINITE; wait.event_mask = mask; #else wait.timeout_ms = time_ms > 0 ? time_ms : VG_LITE_MAX_WAIT_TIME; wait.command_id = CMDBUF_INDEX(*context); #endif /* VG_DRIVER_SINGLE_THREAD */ VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_WAIT, &wait)); #if defined(VG_DRIVER_SINGLE_THREAD) submit_flag = 0; #endif /* VG_DRIVER_SINGLE_THREAD */ return VG_LITE_SUCCESS; } /* Get the inversion of a matrix. */ VG_LITE_OPTIMIZE(LOW) static int inverse(vg_lite_matrix_t * result, vg_lite_matrix_t * matrix) { vg_lite_float_t det00, det01, det02; vg_lite_float_t d; int isAffine; /* Test for identity matrix. */ if (matrix == NULL) { result->m[0][0] = 1.0f; result->m[0][1] = 0.0f; result->m[0][2] = 0.0f; result->m[1][0] = 0.0f; result->m[1][1] = 1.0f; result->m[1][2] = 0.0f; result->m[2][0] = 0.0f; result->m[2][1] = 0.0f; result->m[2][2] = 1.0f; /* Success. */ return 1; } det00 = (matrix->m[1][1] * matrix->m[2][2]) - (matrix->m[2][1] * matrix->m[1][2]); det01 = (matrix->m[2][0] * matrix->m[1][2]) - (matrix->m[1][0] * matrix->m[2][2]); det02 = (matrix->m[1][0] * matrix->m[2][1]) - (matrix->m[2][0] * matrix->m[1][1]); /* Compute determinant. */ d = (matrix->m[0][0] * det00) + (matrix->m[0][1] * det01) + (matrix->m[0][2] * det02); /* Return 0 if there is no inverse matrix. */ if (d == 0.0f) return 0; /* Compute reciprocal. */ d = 1.0f / d; /* Determine if the matrix is affine. */ isAffine = (matrix->m[2][0] == 0.0f) && (matrix->m[2][1] == 0.0f) && (matrix->m[2][2] == 1.0f); result->m[0][0] = d * det00; result->m[0][1] = d * ((matrix->m[2][1] * matrix->m[0][2]) - (matrix->m[0][1] * matrix->m[2][2])); result->m[0][2] = d * ((matrix->m[0][1] * matrix->m[1][2]) - (matrix->m[1][1] * matrix->m[0][2])); result->m[1][0] = d * det01; result->m[1][1] = d * ((matrix->m[0][0] * matrix->m[2][2]) - (matrix->m[2][0] * matrix->m[0][2])); result->m[1][2] = d * ((matrix->m[1][0] * matrix->m[0][2]) - (matrix->m[0][0] * matrix->m[1][2])); result->m[2][0] = isAffine ? 0.0f : d * det02; result->m[2][1] = isAffine ? 0.0f : d * ((matrix->m[2][0] * matrix->m[0][1]) - (matrix->m[0][0] * matrix->m[2][1])); result->m[2][2] = isAffine ? 1.0f : d * ((matrix->m[0][0] * matrix->m[1][1]) - (matrix->m[1][0] * matrix->m[0][1])); /* Success. */ return 1; } /* Transform a 2D point by a given matrix. */ static int transform(vg_lite_point_t * result, vg_lite_float_t x, vg_lite_float_t y, vg_lite_matrix_t * matrix) { vg_lite_float_t pt_x; vg_lite_float_t pt_y; vg_lite_float_t pt_w; /* Test for identity matrix. */ if (matrix == NULL) { result->x = (int)x; result->y = (int)y; /* Success. */ return 1; } /* Transform x, y, and w. */ pt_x = (x * matrix->m[0][0]) + (y * matrix->m[0][1]) + matrix->m[0][2]; pt_y = (x * matrix->m[1][0]) + (y * matrix->m[1][1]) + matrix->m[1][2]; pt_w = (x * matrix->m[2][0]) + (y * matrix->m[2][1]) + matrix->m[2][2]; if (pt_w <= 0.0f) return 0; /* Compute projected x and y. */ result->x = (int)(pt_x / pt_w); result->y = (int)(pt_y / pt_w); /* Success. */ return 1; } /*! Flush specific VG module. */ static vg_lite_error_t flush_target() { vg_lite_error_t error = VG_LITE_SUCCESS; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ do { VG_LITE_BREAK_ERROR(push_state(ctx, 0x0A1B, 0x00000001)); VG_LITE_BREAK_ERROR(push_stall(ctx, 7)); } while (0); return error; } /****************** FAST_CLEAR feature implementation. ***************/ #if VG_TARGET_FAST_CLEAR static vg_lite_error_t convert_color(vg_lite_buffer_format_t format, uint32_t value, uint32_t *result, int *bpp) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t r, g, b, a; int Bpp = 0; r = B(value); g = G(value); b = R(value); a = A(value); do { switch (format) { case VG_LITE_RGBA8888: *result = ARGB(a, b, g, r); Bpp = 32; break; case VG_LITE_BGRA8888: *result = ARGB(a, r, g, b); Bpp = 32; break; case VG_LITE_RGBX8888: *result = ARGB(0xff, b, g, r); Bpp = 32; break; case VG_LITE_BGRX8888: *result = ARGB(0xff, r, g, b); Bpp = 32; break; case VG_LITE_RGBA4444: *result = ARGB4(a, b, g, r); Bpp = 16; break; case VG_LITE_BGRA4444: *result = ARGB4(a, r, g, b); Bpp = 16; break; case VG_LITE_RGB565: *result = ((b & 0xf8) << 8) | ((g & 0xfc) << 3) | ((r & 0xf8) >> 3); Bpp = 16; break; case VG_LITE_BGR565: *result = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3); Bpp = 16; break; case VG_LITE_BGRA5551: *result = ((b & 0xf8) << 8) | ((g & 0xf8) << 3) | ((r & 0xf8) >> 2) | ((a & 0x80) >> 7); Bpp = 16; break; case VG_LITE_A8: *result = ARGB(a, a, a, a); Bpp = 8; break; case VG_LITE_L8: *result = ARGB(r, r, r, r); Bpp = 8; break; default: error = VG_LITE_NOT_SUPPORT; break; } } while (0); if (bpp != NULL) { *bpp = Bpp; } if (Bpp == 16) { *result = ((*result) << 16) | (*result); } return error; } /* Fill Target buffer by FC buffer. Only used in cmodel/fpga for verification. */ #if defined(DEBUG) || defined(_DEBUG) static vg_lite_error_t fill_fc_target(vg_lite_buffer_t *target, vg_lite_buffer_t *fcb) { vg_lite_error_t error = VG_LITE_SUCCESS; uint8_t *fc = (uint8_t *)fcb->memory; uint16_t *target16; uint32_t *target32; uint8_t *target8; uint32_t clear32; int byte_done = 0; int i, j, k; int bpp; do { convert_color(target->format, s_context.clearValue, &clear32, &bpp); if (bpp == 32) { target32 = (uint32_t *)target->memory; for (i = 0; i < fcb->width; i++) { for (j = 0; j < 8; j++) { /* Loop the bits*/ if (!(((*fc) >> j) & 1)) { for (k = 0; k < 64 / 4; k++) { target32[k] = clear32; byte_done+=4; if (byte_done >= target->stride * target->height) { return error; } } } target32 += 64/4; } fc++; } } else if (bpp == 16){ target16 = (uint16_t *)target->memory; for (i = 0; i < fcb->width; i++) { for (j = 0; j < 8; j++) { /* Loop the bits*/ if (!(((*fc) >> j) & 1)) { for (k = 0; k < 64 / 2; k++) { target16[k] = (uint16_t)clear32; byte_done+=2; if (byte_done >= target->stride * target->height) { return error; } } } target16 += 64/2; } fc++; } } else if (bpp == 8) { target8 = (uint8_t *)target->memory; for (i = 0; i < fcb->width; i++) { for (j = 0; j < 8; j++) { /* Loop the bits*/ if (!(((*fc) >> j) & 1)) { for (k = 0; k < 64; k++) { target8[k] = (uint8_t)clear32; byte_done++; if (byte_done >= target->stride * target->height) { return error; } } } target8 += 64; } fc++; } } } while (0); return error; } #endif /* Update the fast_clear buffer when render target switched. */ static vg_lite_error_t update_fc_buffer(vg_lite_buffer_t *target) { int rt_bytes; vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_context_t *context = GET_CONTEXT(); vg_lite_kernel_allocate_t allocate; do { if (target == NULL) { error = VG_LITE_INVALID_ARGUMENT; break; } rt_bytes = target->stride * target->height; rt_bytes = VG_LITE_ALIGN(rt_bytes, (FC_BIT_TO_BYTES * 8)); rt_bytes = rt_bytes / FC_BIT_TO_BYTES / 8; /* Only allocate new buffer when the allocated is not big enough. Yes*/ if (rt_bytes > context->fcBuffer.stride ) { vg_lite_free(&context->fcBuffer); context->fcBuffer.width = rt_bytes; /* The actually used bytes. */ rt_bytes = VG_LITE_ALIGN(rt_bytes, FC_BURST_BYTES); /* The allocated aligned bytes. */ context->fcBuffer.stride = rt_bytes; allocate.bytes = rt_bytes; allocate.contiguous = 1; VG_LITE_BREAK_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); context->fcBuffer.handle = allocate.memory_handle; context->fcBuffer.memory = allocate.memory; context->fcBuffer.address = allocate.memory_gpu; } else { /* Just update the fc buffer size. */ context->fcBuffer.width = rt_bytes; } memset(context->fcBuffer.memory, 0xff, context->fcBuffer.stride); } while (0); return error; } /* Update FC registers and clear FC buffer. */ static vg_lite_error_t clear_fc(uint32_t value) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_context_t *context = GET_CONTEXT(); uint32_t bytes_to_clear = context->fcBuffer.stride / FC_BURST_BYTES; do { VG_LITE_BREAK_ERROR(push_state(context, 0x0A9A, context->fcBuffer.address)); /* FC buffer address. */ VG_LITE_BREAK_ERROR(push_state(context, 0x0A9B, value)); /* FC clear value. */ VG_LITE_BREAK_ERROR(push_state(context, 0x0AB0, 0x80000000 | bytes_to_clear)); /* FC clear command. */ } while (0); return error; } #if VG_TARGET_FC_DUMP static int fc_buf_dump(vg_lite_buffer_t *target, vg_lite_buffer_t *fcb) { int error = VG_LITE_SUCCESS; uint8_t *fc = (uint8_t *)fcb->memory; uint8_t *target8; int byte_done = 0; int target_bytes; int i, j; static unsigned s_cnt; unsigned cnt = s_cnt; FILE *fpFCBuf; FILE *fpTargetBuf; FILE *fpTargetBufInfo; char buf[256]; s_cnt++; sprintf(buf, "vg255v2.fc_buf.f%04d.txt", cnt); fpFCBuf = fopen(buf, "wt"); if (NULL == fpFCBuf) { fprintf(stderr, "[Warning] Open file \'%s\' fail.\n", buf); return -1; } sprintf(buf, "vg255v2.target_buf_info.f%04d.txt", cnt); fpTargetBufInfo = fopen(buf, "wt"); if (NULL == fpTargetBufInfo) { fprintf(stderr, "[Warning] Open file \'%s\' fail.\n", buf); fclose(fpFCBuf); return -1; } else { fprintf(fpTargetBufInfo, "%-12s: %d\n", "format", target->format); fprintf(fpTargetBufInfo, "%-12s: %d\n", "tiled", target->tiled); fprintf(fpTargetBufInfo, "%-12s: %d\n", "width", target->width); fprintf(fpTargetBufInfo, "%-12s: %d\n", "height", target->height); fprintf(fpTargetBufInfo, "%-12s: %d\n", "stride", target->stride); fclose(fpTargetBufInfo); } sprintf(buf, "vg255v2.target_buf.f%04d.txt", cnt); fpTargetBuf = fopen(buf, "wt"); if (NULL == fpTargetBuf) { fprintf(stderr, "[Warning] Open file \'%s\' fail.\n", buf); fclose(fpFCBuf); return -1; } /* Dump FC buffer & Dump target buffer */ target8 = (uint8_t *)target->memory; target_bytes = target->stride * target->height; for (i = 0; i < fcb->width; ++i) { fprintf(fpFCBuf, "%02x\n", fc[i]); /* 1 byte of fc related with 512 bytes of target buffer */ for (j = 0; j < 128; ++j) { fprintf(fpTargetBuf, "%02x", byte_done < target_bytes ? target8[0] : 0); byte_done++; fprintf(fpTargetBuf, "%02x", byte_done < target_bytes ? target8[1] : 0); byte_done++; fprintf(fpTargetBuf, "%02x", byte_done < target_bytes ? target8[2] : 0); byte_done++; fprintf(fpTargetBuf, "%02x\n", byte_done < target_bytes ? target8[3] : 0); byte_done++; target8 += 4; } } fclose(fpFCBuf); fclose(fpTargetBuf); return error; } #endif /* VG_TARGET_FC_DUMP */ #endif /* Set the current render target. */ #if defined(VG_DRIVER_SINGLE_THREAD) static vg_lite_error_t set_render_target(vg_lite_buffer_t *target) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t yuv2rgb = 0; uint32_t uv_swiz = 0; int32_t tiled; int32_t dst_align_width; uint32_t mul, div, align; if(target == NULL) { return VG_LITE_INVALID_ARGUMENT; } else if(s_context.scissor_enabled && (s_context.scissor[2] <= 0 || s_context.scissor[3] <= 0)) { /* Check scissoring rectangle dimensions A scissoring rectangle with width <= 0 or height <= 0 must be ignored. If scissoring is enabled and no valid scissoring rectangles are present, no drawing occurs. */ return VG_LITE_NO_CONTEXT; } /* Skip if render target and scissor are not changed. */ if ((s_context.rtbuffer != NULL) && !(memcmp(s_context.rtbuffer,target,sizeof(vg_lite_buffer_t))) && (s_context.scissor_dirty == 0) && (s_context.premultiply_dirty == 0)) { return VG_LITE_SUCCESS; } if ((target != NULL) && (target->format == VG_LITE_YUY2 || target->format == VG_LITE_AYUY2 || target->format == VG_LITE_YUY2_TILED || target->format == VG_LITE_AYUY2_TILED)) { return VG_LITE_NOT_SUPPORT; } #if VG_TARGET_FAST_CLEAR /* Flush target if necessary when switching. */ if (s_context.rtbuffer&& s_context.rtbuffer->memory) { /* If it's not the first time to set target. */ vg_lite_finish(); } update_fc_buffer(target); #else if (s_context.rtbuffer && s_context.rtbuffer->memory) { /* Flush the old target. */ vg_lite_finish(); } #endif tiled = (target->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0; if (((target->format >= VG_LITE_YUY2) && (target->format <= VG_LITE_AYUY2)) || ((target->format >= VG_LITE_YUY2_TILED) && (target->format <= VG_LITE_AYUY2_TILED))) { yuv2rgb = convert_yuv2rgb(target->yuv.yuv2rgb); uv_swiz = convert_uv_swizzle(target->yuv.swizzle); } /* Program render target. */ if (s_context.premultiply_dirty || s_context.rtbuffer != target || memcmp(s_context.rtbuffer,target,sizeof(vg_lite_buffer_t)) ) { if(target->tiled == VG_LITE_TILED) { if((target->stride % DEST_ALIGNMENT_LIMITATION) != 0) return VG_LITE_INVALID_ARGUMENT; } if(s_context.premultiply_enabled) { VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A10, convert_target_format(target->format, s_context.capabilities) | 0x00010000 | uv_swiz | yuv2rgb)); }else { VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A10, convert_target_format(target->format, s_context.capabilities) | 0x00010000 | uv_swiz | yuv2rgb | 0x100)); } if (target->yuv.uv_planar) { /* Program uv plane address if necessary. */ VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A5C, target->yuv.uv_planar)); } if (target->yuv.alpha_planar) { VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A5D, target->yuv.alpha_planar)); } VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A11, target->address)); VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A12, target->stride | tiled)); s_context.premultiply_dirty = 0; } get_format_bytes(target->format, &mul, &div, &align); dst_align_width = target->stride * div / mul; if (s_context.scissor_dirty != 0) { if (s_context.scissor_enabled) { VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A13, (s_context.scissor[0] + s_context.scissor[2]) | ((s_context.scissor[1] + s_context.scissor[3]) << 16))); } else { VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A13, dst_align_width | (target->height << 16))); } s_context.scissor_dirty = 0; } else { VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A13, dst_align_width | (target->height << 16))); } memcpy(s_context.rtbuffer, target, sizeof(vg_lite_buffer_t)); return error; } #else static vg_lite_error_t set_render_target(vg_lite_buffer_t *target) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t yuv2rgb = 0; uint32_t uv_swiz = 0; int32_t tiled; vg_lite_tls_t* tls; int32_t dst_align_width; uint32_t mul, div, align; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; if(target == NULL) { return VG_LITE_INVALID_ARGUMENT; } else if(tls->t_context.scissor_enabled && (tls->t_context.scissor[2] <= 0 || tls->t_context.scissor[3] <= 0)) { /* Check scissoring rectangle dimensions A scissoring rectangle with width <= 0 or height <= 0 must be ignored. If scissoring is enabled and no valid scissoring rectangles are present, no drawing occurs. */ return VG_LITE_NO_CONTEXT; } tls->t_context.start_offset = CMDBUF_OFFSET(tls->t_context); if ((target != NULL) && (target->format == VG_LITE_YUY2 || target->format == VG_LITE_AYUY2 || target->format == VG_LITE_YUY2_TILED || target->format == VG_LITE_AYUY2_TILED)) { return VG_LITE_NOT_SUPPORT; } #if VG_TARGET_FAST_CLEAR /* Flush target if necessary when switching. */ if (tls->t_context.rtbuffer != NULL) { /* If it's not the first time to set target. */ vg_lite_finish(); } update_fc_buffer(target); #endif tiled = (target->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0; if (((target->format >= VG_LITE_YUY2) && (target->format <= VG_LITE_AYUY2)) || ((target->format >= VG_LITE_YUY2_TILED) && (target->format <= VG_LITE_AYUY2_TILED))) { yuv2rgb = convert_yuv2rgb(target->yuv.yuv2rgb); uv_swiz = convert_uv_swizzle(target->yuv.swizzle); } /* Program render target. */ if(target->tiled == VG_LITE_TILED) { if((target->stride % DEST_ALIGNMENT_LIMITATION) != 0) return VG_LITE_INVALID_ARGUMENT; } if(tls->t_context.premultiply_enabled) { VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A10, convert_target_format(target->format, tls->t_context.capabilities) | 0x00010000 | uv_swiz | yuv2rgb)); } else { VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A10, convert_target_format(target->format, tls->t_context.capabilities) | 0x00010000 | uv_swiz | yuv2rgb | 0x100)); } if (target->yuv.uv_planar) { /* Program uv plane address if necessary. */ VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A5C, target->yuv.uv_planar)); } if (target->yuv.alpha_planar) { VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A5D, target->yuv.alpha_planar)); } VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A11, target->address)); VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A12, target->stride | tiled)); get_format_bytes(target->format, &mul, &div, &align); dst_align_width = target->stride * div / mul; if (tls->t_context.scissor_enabled) { VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A13, (tls->t_context.scissor[0] + tls->t_context.scissor[2]) | ((tls->t_context.scissor[1] + tls->t_context.scissor[3]) << 16))); } else { VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A13, dst_align_width | (target->height << 16))); } tls->t_context.rtbuffer = target; return error; } #endif /* VG_DRIVER_SINGLE_THREAD */ static inline vg_lite_error_t transform_bounding_box(vg_lite_rectangle_t *in_bbx, vg_lite_matrix_t *matrix, vg_lite_rectangle_t *clip, vg_lite_rectangle_t *out_bbx, vg_lite_point_t *origin) { vg_lite_point_t temp; memset(out_bbx, 0, sizeof(vg_lite_rectangle_t)); /* Transform image point (x, y). */ if (!transform(&temp, in_bbx->x, in_bbx->y, matrix)) return VG_LITE_INVALID_ARGUMENT; out_bbx->x = temp.x; out_bbx->y = temp.y; /* Provide position of the new origin to the caller if requested. */ if (origin != NULL) { origin->x = temp.x; origin->y = temp.y; } /* Transform image point (x, y+height). */ if (!transform(&temp, in_bbx->x, (in_bbx->y + in_bbx->height), matrix)) return VG_LITE_INVALID_ARGUMENT; UPDATE_BOUNDING_BOX(*out_bbx, temp); /* Transform image point (x+width, y+height). */ if (!transform(&temp, (in_bbx->x + in_bbx->width), (in_bbx->y + in_bbx->height), matrix)) return VG_LITE_INVALID_ARGUMENT; UPDATE_BOUNDING_BOX(*out_bbx, temp); /* Transform image point (x+width, y). */ if (!transform(&temp, (in_bbx->x + in_bbx->width), in_bbx->y, matrix)) return VG_LITE_INVALID_ARGUMENT; UPDATE_BOUNDING_BOX(*out_bbx, temp); /* Clip is required */ if (clip) { out_bbx->x = MAX(out_bbx->x, clip->x); out_bbx->y = MAX(out_bbx->y, clip->y); out_bbx->width = MIN((out_bbx->x + out_bbx->width), (clip->x + clip->width)) - out_bbx->x; out_bbx->height = MIN((out_bbx->y + out_bbx->height), (clip->y + clip->height)) - out_bbx->y; } return VG_LITE_SUCCESS; } #if (VG_BLIT_WORKAROUND == 1) /* * Calculates the minimal possible target buffer starting from a given target * buffer and considering a source texture (to blit), graphic transformations * and clipping window. */ static vg_lite_error_t config_new_target(vg_lite_buffer_t *target, vg_lite_buffer_t *source, vg_lite_matrix_t *matrix, vg_lite_rectangle_t *bbx, vg_lite_buffer_t *new_target) { uint8_t *p; vg_lite_point_t origin; vg_lite_rectangle_t src_bbx, bounding_box, clip; int tx, ty; uint32_t mul, div, required_align, align; /* * Acquire the bounding box of the transformed source image and the location * of its origin. */ memset(&src_bbx, 0, sizeof(vg_lite_rectangle_t)); src_bbx.width = source->width; src_bbx.height = source->height; if (bbx == NULL) { /* * If no clipping rectangle provided, just configure the clip bounds to * be as big as the target */ memset(&clip, 0, sizeof(vg_lite_rectangle_t)); clip.width = target->width; clip.height = target->height; } else { /* Otherwise clip according to the bounding box specified by the caller */ memcpy(&clip, bbx, sizeof(vg_lite_rectangle_t)); } transform_bounding_box(&src_bbx, matrix, &clip, &bounding_box, &origin); /* Calculate the data address of the new target */ get_format_bytes(target->format, &mul, &div, &required_align); p = target->memory; p += bounding_box.y * target->stride + bounding_box.x * (mul / div); align = (uint32_t)p & (required_align - 1); p -= align; /* * Update pixel coordinate of the base address. The width of the target will * increase, since the x coordinate of the bounding box decreases to * accomodate the image data alignment. */ tx = align / (mul / div); bounding_box.x -= tx; bounding_box.width += tx; /* Update bounding box if provided by the caller */ if (bbx) { bbx->x = tx; bbx->y = 0; } /* Calculate translation from the source image origin to the target origin. */ tx = origin.x - bounding_box.x; ty = origin.y - bounding_box.y; /* Copy content of the target buffer descriptor into the new target. */ memcpy(new_target, target, sizeof(vg_lite_buffer_t)); /* Update the new buffer */ new_target->memory = p; new_target->address = (uint32_t) p; new_target->width = bounding_box.width; new_target->height = bounding_box.height; /* Update matrix */ matrix->m[0][2] = tx; matrix->m[1][2] = ty; return VG_LITE_SUCCESS; } #endif /* VG_BLIT_WORKAROUND */ static vg_lite_error_t set_interpolation_steps(vg_lite_buffer_t *target, vg_lite_float_t s_width, vg_lite_float_t s_height, vg_lite_matrix_t *matrix) { vg_lite_matrix_t im; vg_lite_rectangle_t src_bbx, bounding_box, clip; vg_lite_float_t xs[3], ys[3], cs[3]; vg_lite_error_t error = VG_LITE_SUCCESS; float dx = 0.0f, dy = 0.0f; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t *tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ #define ERR_LIMIT 0.0000610351562f /* Get bounding box. */ memset(&src_bbx, 0, sizeof(vg_lite_rectangle_t)); memset(&clip, 0, sizeof(vg_lite_rectangle_t)); src_bbx.width = (int32_t)s_width; src_bbx.height = (int32_t)s_height; if (ctx->scissor_enabled) { clip.x = ctx->scissor[0]; clip.y = ctx->scissor[1]; clip.width = ctx->scissor[2]; clip.height = ctx->scissor[3]; } else { clip.x = clip.y = 0; clip.width = ctx->rtbuffer->width; clip.height = ctx->rtbuffer->height; } transform_bounding_box(&src_bbx, matrix, &clip, &bounding_box, NULL); /* Compute inverse matrix. */ if (!inverse(&im, matrix)) return VG_LITE_INVALID_ARGUMENT; /* Compute interpolation steps. */ /* X step */ xs[0] = im.m[0][0] / s_width; xs[1] = im.m[1][0] / s_height; xs[2] = im.m[2][0]; /* Y step */ ys[0] = im.m[0][1] / s_width; ys[1] = im.m[1][1] / s_height; ys[2] = im.m[2][1]; /* C step 2 */ cs[2] = 0.5f * (im.m[2][0] + im.m[2][1]) + im.m[2][2]; /* Keep track of the rounding errors (underflow) */ if (ctx->chip_id == GPU_CHIP_ID_GCNanoliteV) { /* Check if matrix has rotation or perspective transformations */ if (matrix != NULL && (matrix->m[0][1] != 0.0f || matrix->m[1][0] != 0.0f || matrix->m[2][0] != 0.0f || matrix->m[2][1] != 0.0f || matrix->m[2][2] != 1.0f)) { if (xs[0] != 0.0f && -ERR_LIMIT < xs[0] && xs[0] < ERR_LIMIT) dx = 0.5f * (2 * bounding_box.x + bounding_box.width) * im.m[0][0]; else if (ys[0] != 0.0f && -ERR_LIMIT < ys[0] && ys[0] < ERR_LIMIT) dx = 0.5f * (2 * bounding_box.y + bounding_box.height) * im.m[0][1]; if (xs[1] != 0.0f && -ERR_LIMIT < xs[1] && xs[1] < ERR_LIMIT) dy = 0.5f * (2 * bounding_box.x + bounding_box.width) * im.m[1][0]; else if (ys[1] != 0.0f && -ERR_LIMIT < ys[1] && ys[1] < ERR_LIMIT) dy = 0.5f * (2 * bounding_box.y + bounding_box.height) * im.m[1][1]; } } /* C step 0, 1*/ cs[0] = (0.5f * (im.m[0][0] + im.m[0][1]) + im.m[0][2] + dx) / s_width; cs[1] = (0.5f * (im.m[1][0] + im.m[1][1]) + im.m[1][2] + dy) / s_height; /* Set command buffer */ VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A18, (void *)&cs[0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A19, (void *)&cs[1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A1A, (void *)&cs[2])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A1C, (void *)&xs[0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A1D, (void *)&xs[1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A1E, (void *)&xs[2])); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1F, 0x00000001)); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A20, (void *)&ys[0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A21, (void *)&ys[1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A22, (void *)&ys[2])); return VG_LITE_SUCCESS; } /*************** API Functions ***********************************************/ vg_lite_error_t vg_lite_get_transform_matrix(vg_lite_point4_t src, vg_lite_point4_t dst,vg_lite_matrix_t *mat) { float a[8][8],b[9],A[64]; int i, j, k, m = 8, n = 1; int astep = 8,bstep = 1; float d; if(src == NULL || dst == NULL || mat == NULL) return VG_LITE_INVALID_ARGUMENT; for(i = 0; i < 4; ++i ) { a[i][0] = a[i+4][3] = src[i].x; a[i][1] = a[i+4][4] = src[i].y; a[i][2] = a[i+4][5] = 1; a[i][3] = a[i][4] = a[i][5] = a[i+4][0] = a[i+4][1] = a[i+4][2] = 0; a[i][6] = -src[i].x*dst[i].x; a[i][7] = -src[i].y*dst[i].x; a[i+4][6] = -src[i].x*dst[i].y; a[i+4][7] = -src[i].y*dst[i].y; b[i] = dst[i].x; b[i+4] = dst[i].y; } for(i = 0; i < 8; ++i ) { for(j = 0; j < 8; ++j ) { A[8 * i + j] = a[i][j]; } } for (i = 0; i < m; i++) { k = i; for (j = i + 1; j < m; j++) if (ABS(A[j*astep + i]) > ABS(A[k*astep + i])) k = j; if (ABS(A[k*astep + i]) < EPS) return VG_LITE_INVALID_ARGUMENT; if (k != i) { for (j = i; j < m; j++) swap(&A[i*astep + j], &A[k*astep + j]); for (j = 0; j < n; j++) swap(&b[i*bstep + j], &b[k*bstep + j]); } d = -1 / A[i*astep + i]; for (j = i + 1; j < m; j++) { float alpha = A[j*astep + i] * d; for (k = i + 1; k < m; k++) A[j*astep + k] += alpha * A[i*astep + k]; for (k = 0; k < n; k++) b[j*bstep + k] += alpha * b[i*bstep + k]; } } for (i = m - 1; i >= 0; i--) for (j = 0; j < n; j++) { float s = b[i*bstep + j]; for (k = i + 1; k < m; k++) s -= A[i*astep + k] * b[k*bstep + j]; b[i*bstep + j] = s / A[i*astep + i]; } b[8] = 1; for(i = 0; i < 3; ++i ) { for(j = 0; j < 3; ++j ) { mat->m[i][j] = b[i* 3 + j]; } } return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_clear(vg_lite_buffer_t * target, vg_lite_rectangle_t * rectangle, vg_lite_color_t color) { vg_lite_error_t error; int32_t x, y, width, height; uint32_t color32; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ error = set_render_target(target); if (error != VG_LITE_SUCCESS) { return error; } else if (error == VG_LITE_NO_CONTEXT) { /* If scissoring is enabled and no valid scissoring rectangles are present, no drawing occurs */ return VG_LITE_SUCCESS; } /* Get rectangle. */ x = (rectangle != NULL) ? rectangle->x : 0; y = (rectangle != NULL) ? rectangle->y : 0; width = (rectangle != NULL) ? rectangle->width : ctx->rtbuffer->width; height = (rectangle != NULL) ? rectangle->height : ctx->rtbuffer->height; /* Compute the valid rectangle. */ if (x < 0) { width += x; x = 0; } if (y < 0) { height += y; y = 0; } if (ctx->scissor_enabled) { int right, bottom; right = x + width; bottom = y + height; /* Bounds check. */ if ((ctx->scissor[0] >= x + width) || (ctx->scissor[0] + ctx->scissor[2] <= x) || (ctx->scissor[1] >= y + height) || (ctx->scissor[1] + ctx->scissor[3] <= y)) { /* Do nothing. */ return VG_LITE_SUCCESS; } /* Intersects the scissor and the rectangle. */ x = (x > ctx->scissor[0] ? x : ctx->scissor[0]); y = (y > ctx->scissor[1] ? y : ctx->scissor[1]); right = (right < ctx->scissor[0] + ctx->scissor[2] ? right : ctx->scissor[0] + ctx->scissor[2]); bottom = (bottom < ctx->scissor[1] + ctx->scissor[3] ? bottom : ctx->scissor[1] + ctx->scissor[3]); width = right - x; height = bottom - y; } /* Get converted color when target is in L8 format. */ color32 = (target->format == VG_LITE_L8) ? rgb_to_l(color) : color; #if VG_TARGET_FAST_CLEAR if ((rectangle == NULL) || ((x == 0) && (y == 0) && (width == ctx->rtbuffer->width) && (height == ctx->rtbuffer->height))) { ctx->clearValue = color32; convert_color(ctx->rtbuffer->format, color32, &color32, NULL); clear_fc((uint32_t)color32); } else #endif { /* Setup the command buffer. */ if(ctx->premultiply_enabled) { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x00000001)); } else { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x10000001)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, color32)); VG_LITE_RETURN_ERROR(push_rectangle(ctx, x, y, width, height)); VG_LITE_RETURN_ERROR(flush_target()); } /* Success. */ return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_blit(vg_lite_buffer_t * target, vg_lite_buffer_t * source, vg_lite_matrix_t * matrix, vg_lite_blend_t blend, vg_lite_color_t color, vg_lite_filter_t filter) { vg_lite_error_t error; vg_lite_rectangle_t src_bbx, bounding_box, clip; uint32_t imageMode; uint32_t blend_mode; uint32_t transparency_mode = 0; vg_lite_blend_t forced_blending = blend; uint32_t conversion = 0; uint32_t tiled_source; #if (VG_BLIT_WORKAROUND == 1) vg_lite_matrix_t new_matrix; vg_lite_buffer_t new_target; #endif /* VG_BLIT_WORKAROUND */ #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t *tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ /* Calculate bounding box */ memset(&src_bbx, 0, sizeof(vg_lite_rectangle_t)); memset(&clip, 0, sizeof(vg_lite_rectangle_t)); src_bbx.width = source->width; src_bbx.height = source->height; if (ctx->scissor_enabled) { clip.x = ctx->scissor[0]; clip.y = ctx->scissor[1]; clip.width = ctx->scissor[2]; clip.height = ctx->scissor[3]; } else { clip.width = target->width; clip.height = target->height; } transform_bounding_box(&src_bbx, matrix, &clip, &bounding_box, NULL); #if (VG_BLIT_WORKAROUND==1) /* * The blit output quality workaround works only for afine transformations * because it is based on the process of cumulating translations into the * matrix. This process is not possible for non-affine transformations, such * as the perspective projections. */ if ((matrix->m[2][0] == 0) && (matrix->m[2][1] == 0)) { /* * Make a local copy of the transformation matrix in order not to mess * up the user's matrix. */ memcpy(&new_matrix, matrix, sizeof(vg_lite_matrix_t)); matrix = &new_matrix; config_new_target(target, source, matrix, &bounding_box, &new_target); target = &new_target; } #endif /* VG_BLIT_WORKAROUND */ error = set_render_target(target); if (error != VG_LITE_SUCCESS) { return error; } else if (error == VG_LITE_NO_CONTEXT) { /* If scissoring is enabled and no valid scissoring rectangles are present, no drawing occurs */ return VG_LITE_SUCCESS; } transparency_mode = (source->transparency_mode == VG_LITE_IMAGE_TRANSPARENT ? 0x8000:0); /* Check if the specified matrix has rotation or perspective. */ if ( (matrix != NULL) && ( (matrix->m[0][1] != 0.0f) || (matrix->m[1][0] != 0.0f) || (matrix->m[2][0] != 0.0f) || (matrix->m[2][1] != 0.0f) || (matrix->m[2][2] != 1.0f) ) && ( blend == VG_LITE_BLEND_NONE || blend == VG_LITE_BLEND_SRC_IN || blend == VG_LITE_BLEND_DST_IN ) ) { if(vg_lite_query_feature(gcFEATURE_BIT_VG_BORDER_CULLING)) { /* Mark that we have rotation. */ transparency_mode = 0x8000; }else { blend_mode = VG_LITE_BLEND_SRC_OVER; } } /* Check whether L8 is supported or not. */ if ((target->format == VG_LITE_L8) && ((source->format != VG_LITE_L8) && (source->format != VG_LITE_A8))) { conversion = 0x80000000; } /* determine if source specify bytes are aligned */ error = _check_source_aligned(source->format,source->stride); if (error != VG_LITE_SUCCESS) { return error; } /* Determine image mode (NORMAL, NONE or MULTIPLY) depending on the color. */ imageMode = (source->image_mode == VG_LITE_NONE_IMAGE_MODE) ? 0 : (source->image_mode == VG_LITE_MULTIPLY_IMAGE_MODE) ? 0x00002000 : 0x00001000; blend_mode = convert_blend(forced_blending); tiled_source = (source->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0 ; #if !defined(VG_DRIVER_SINGLE_THREAD) /* Setup the command buffer. */ if(source->format >= VG_LITE_INDEX_1 && source->format <= VG_LITE_INDEX_8) { /* this task will use index format,set index_flag to 1. */ ctx->index_format = 1; switch (source->format) { case VG_LITE_INDEX_8: if(ctx->clut_dirty[3]){ VG_LITE_RETURN_ERROR(push_states(ctx, 0x0B00, 256, tls->t_context.colors[3])); tls->t_context.clut_dirty[3] = 0; } else { ctx->clut_used[3] = 1; } break; case VG_LITE_INDEX_4: if(ctx->clut_dirty[2]){ VG_LITE_RETURN_ERROR(push_states(ctx, 0x0AA0, 16, ctx->colors[2])); ctx->clut_dirty[2] = 0; } else { ctx->clut_used[2] = 1; } break; case VG_LITE_INDEX_2: if(ctx->clut_dirty[1]){ VG_LITE_RETURN_ERROR(push_states(ctx, 0x0A9C, 4, ctx->colors[1])); ctx->clut_dirty[1] = 0; } else { ctx->clut_used[1] = 1; } break; default: if(ctx->clut_dirty[0]){ VG_LITE_RETURN_ERROR(push_states(ctx, 0x0A98, 2, ctx->colors[0])); ctx->clut_dirty[0] = 0; } else { ctx->clut_used[0] = 1; } } } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x10000001 | imageMode | blend_mode | transparency_mode)); } else { /* enable pre-multiplied from VG to VGPE */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x00000001 | imageMode | blend_mode | transparency_mode)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, color)); VG_LITE_RETURN_ERROR(set_interpolation_steps(target, source->width, source->height, matrix)); if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { if(source->transparency_mode == VG_LITE_IMAGE_OPAQUE){ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion | 0x01000100)); } else { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion | 0x00000100)); } } else { /* enable pre-multiplied in imager unit */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A27, 0)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A29, source->address)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2B, source->stride | tiled_source)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2D, 0)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2F, source->width | (source->height << 16))); VG_LITE_RETURN_ERROR(push_rectangle(ctx, bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height)); error = flush_target(); vglitemDUMP_BUFFER("image", source->address, source->memory, 0, (source->stride)*(source->height)); #if DUMP_IMAGE dump_img(source->memory, source->width, source->height, source->format); #endif return error; } vg_lite_error_t vg_lite_blit_rect(vg_lite_buffer_t * target, vg_lite_buffer_t * source, uint32_t * rect, vg_lite_matrix_t * matrix, vg_lite_blend_t blend, vg_lite_color_t color, vg_lite_filter_t filter) { vg_lite_error_t error; vg_lite_rectangle_t src_bbx, bounding_box, clip; uint32_t imageMode; uint32_t transparency_mode = 0; uint32_t blend_mode; vg_lite_blend_t forced_blending = blend; uint32_t conversion = 0; uint32_t tiled_source; uint32_t rect_x = 0, rect_y = 0, rect_w = 0, rect_h = 0; int32_t src_align_width; uint32_t mul, div, align; #if (VG_BLIT_WORKAROUND == 1) vg_lite_matrix_t new_matrix; vg_lite_buffer_t new_target; #endif /* VG_BLIT_WORKAROUND */ #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t *tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ transparency_mode = (source->transparency_mode == VG_LITE_IMAGE_TRANSPARENT ? 0x8000:0); /* Check if the specified matrix has rotation or perspective. */ if ( (matrix != NULL) && ( (matrix->m[0][1] != 0.0f) || (matrix->m[1][0] != 0.0f) || (matrix->m[2][0] != 0.0f) || (matrix->m[2][1] != 0.0f) || (matrix->m[2][2] != 1.0f) ) && ( blend == VG_LITE_BLEND_NONE || blend == VG_LITE_BLEND_SRC_IN || blend == VG_LITE_BLEND_DST_IN ) ) { if(vg_lite_query_feature(gcFEATURE_BIT_VG_BORDER_CULLING)) { /* Mark that we have rotation. */ transparency_mode = 0x8000; }else { blend_mode = VG_LITE_BLEND_SRC_OVER; } } /* Check whether L8 is supported or not. */ if ((target->format == VG_LITE_L8) && ((source->format != VG_LITE_L8) && (source->format != VG_LITE_A8))) { conversion = 0x80000000; } /* determine if source specify bytes are aligned */ error = _check_source_aligned(source->format,source->stride); if (error != VG_LITE_SUCCESS) { return error; } get_format_bytes(source->format, &mul, &div, &align); src_align_width = source->stride * div / mul; memset(&src_bbx, 0, sizeof(vg_lite_rectangle_t)); /* Set source region. */ if (rect != NULL) { rect_x = rect[0]; rect_y = rect[1]; rect_w = rect[2]; rect_h = rect[3]; if ((rect_x > (uint32_t)src_align_width) || (rect_y > (uint32_t)source->height) || (rect_w == 0) || (rect_h == 0)) { /*No intersection*/ return VG_LITE_INVALID_ARGUMENT; } if (rect_x + rect_w > (uint32_t)src_align_width) { rect_w = src_align_width - rect_x; } if (rect_y + rect_h > (uint32_t)source->height) { rect_h = source->height - rect_y; } src_bbx.width = rect_w; src_bbx.height = rect_h; } else { rect_x = rect_y = 0; rect_w = src_bbx.width = src_align_width; rect_h = src_bbx.height = source->height; } /* Calculate bounding box. */ memset(&clip, 0, sizeof(vg_lite_rectangle_t)); if (ctx->scissor_enabled) { clip.x = ctx->scissor[0]; clip.y = ctx->scissor[1]; clip.width = ctx->scissor[2]; clip.height = ctx->scissor[3]; } else { clip.x = clip.y = 0; clip.width = target->width; clip.height = target->height; } transform_bounding_box(&src_bbx, matrix, &clip, &bounding_box, NULL); #if (VG_BLIT_WORKAROUND==1) /* * The blit output quality workaround works only for afine transformations * because it is based on the process of cumulating translations into the * matrix. This process is not possible for non-affine transformations, such * as the perspective projections. */ if ((matrix->m[2][0] == 0) && (matrix->m[2][1] == 0)) { /* * Make a local copy of the transformation matrix in order not to mess * up the user's matrix. */ memcpy(&new_matrix, matrix, sizeof(vg_lite_matrix_t)); matrix = &new_matrix; config_new_target(target, source, matrix, &bounding_box, &new_target); target = &new_target; } #endif /* VG_BLIT_WORKAROUND */ error = set_render_target(target); if (error != VG_LITE_SUCCESS) { return error; } else if (error == VG_LITE_NO_CONTEXT) { /* If scissoring is enabled and no valid scissoring rectangles are present, no drawing occurs */ return VG_LITE_SUCCESS; } /* Determine image mode (NORMAL, NONE or MULTIPLY) depending on the color. */ imageMode = (source->image_mode == VG_LITE_NONE_IMAGE_MODE) ? 0 : (source->image_mode == VG_LITE_MULTIPLY_IMAGE_MODE) ? 0x00002000 : 0x00001000; blend_mode = convert_blend(forced_blending); tiled_source = (source->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0 ; #if !defined(VG_DRIVER_SINGLE_THREAD) /* Setup the command buffer. */ if(source->format >= VG_LITE_INDEX_1 && source->format <= VG_LITE_INDEX_8) { /* this task will use index format,set index_flag to 1. */ ctx->index_format = 1; switch (source->format) { case VG_LITE_INDEX_8: if(tls->t_context.clut_dirty[3]){ VG_LITE_RETURN_ERROR(push_states(ctx, 0x0B00, 256, ctx->colors[3])); ctx->clut_dirty[3] = 0; } else { tls->t_context.clut_used[3] = 1; } break; case VG_LITE_INDEX_4: if(tls->t_context.clut_dirty[2]){ VG_LITE_RETURN_ERROR(push_states(&tls->t_context, 0x0AA0, 16, tls->t_context.colors[2])); tls->t_context.clut_dirty[2] = 0; } else { tls->t_context.clut_used[2] = 1; } break; case VG_LITE_INDEX_2: if(tls->t_context.clut_dirty[1]){ VG_LITE_RETURN_ERROR(push_states(&tls->t_context, 0x0A9C, 4, tls->t_context.colors[1])); tls->t_context.clut_dirty[1] = 0; } else { tls->t_context.clut_used[1] = 1; } break; default: if(tls->t_context.clut_dirty[0]){ VG_LITE_RETURN_ERROR(push_states(&tls->t_context, 0x0A98, 2, tls->t_context.colors[0])); tls->t_context.clut_dirty[0] = 0; } else { tls->t_context.clut_used[0] = 1; } } } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x10000001 | imageMode | blend_mode | transparency_mode)); } else { /* enable pre-multiplied from VG to VGPE */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x00000001 | imageMode | blend_mode | transparency_mode)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, color)); VG_LITE_RETURN_ERROR(set_interpolation_steps(target, rect_w, rect_h, matrix)); if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { if(source->transparency_mode == VG_LITE_IMAGE_OPAQUE){ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion | 0x01000100)); } else { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion | 0x00000100)); } } else { /* enable pre-multiplied in imager unit */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A27, 0)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A29, source->address)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2B, source->stride | tiled_source)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2D, rect_x | (rect_y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2F, rect_w | (rect_h << 16))); VG_LITE_RETURN_ERROR(push_rectangle(ctx, bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height)); error = flush_target(); vglitemDUMP_BUFFER("image", source->address, source->memory, 0, (source->stride)*(source->height)); #if DUMP_IMAGE dump_img(source->memory, src_align_width, source->height, source->format); #endif return error; } /* Program initial states for tessellation buffer. */ static vg_lite_error_t program_tessellation(vg_lite_context_t *context) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t tessellation_size; #if !defined(VG_DRIVER_SINGLE_THREAD) uint32_t offset; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ tessellation_size = ( context->tsbuffer.tessellation_buffer_size[2] ? context->tsbuffer.tessellation_buffer_size[2] : context->tsbuffer.tessellation_buffer_size[1] ); #if !defined(VG_DRIVER_SINGLE_THREAD) offset = CMDBUF_OFFSET(*context); #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ /* Since TS buffer won't change during runtime, we program it here in initialization. */ /* Program tessellation buffer: input for VG module. */ VG_LITE_RETURN_ERROR(push_state(context, 0x0A30, context->tsbuffer.tessellation_buffer_gpu[0])); /* Tessellation buffer address. */ VG_LITE_RETURN_ERROR(push_state(context, 0x0A31, context->tsbuffer.tessellation_buffer_gpu[1])); /* L1 address of tessellation buffer. */ VG_LITE_RETURN_ERROR(push_state(context, 0x0A32, context->tsbuffer.tessellation_buffer_gpu[2])); /* L2 address of tessellation buffer. */ VG_LITE_RETURN_ERROR(push_state(context, 0x0A33, context->tsbuffer.tessellation_stride)); /* Program tessellation control: for TS module. */ VG_LITE_RETURN_ERROR(push_state(context, 0x0A35, context->tsbuffer.tessellation_buffer_gpu[0])); VG_LITE_RETURN_ERROR(push_state(context, 0x0A36, context->tsbuffer.tessellation_buffer_gpu[1])); VG_LITE_RETURN_ERROR(push_state(context, 0x0A37, context->tsbuffer.tessellation_buffer_gpu[2])); VG_LITE_RETURN_ERROR(push_state(context, 0x0A38, context->tsbuffer.tessellation_stride)); VG_LITE_RETURN_ERROR(push_state(context, 0x0A3A, context->tsbuffer.tessellation_width_height)); VG_LITE_RETURN_ERROR(push_state(context, 0x0A3D, tessellation_size / 64)); #if !defined(VG_DRIVER_SINGLE_THREAD) /* Backup tessellation buffer states. */ context->ts_init_used = 0; context->ts_init_use = 0; context->ts_dirty = 1; memcpy(context->ts_record, (CMDBUF_BUFFER(*context) + offset), 80); CMDBUF_OFFSET(*context) = 0; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ return error; } #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_error_t vg_lite_init(int32_t tessellation_width, int32_t tessellation_height) { vg_lite_error_t error; vg_lite_kernel_initialize_t initialize; s_context.rtbuffer = (vg_lite_buffer_t *)malloc(sizeof(vg_lite_buffer_t)); if(!s_context.rtbuffer) return VG_LITE_OUT_OF_RESOURCES; memset(s_context.rtbuffer, 0, sizeof(vg_lite_buffer_t)); if (tessellation_width <= 0) { tessellation_width = 0; tessellation_height = 0; } if (tessellation_height <= 0) { tessellation_height = 0; tessellation_width = 0; } tessellation_width = VG_LITE_ALIGN(tessellation_width, 16); #if VG_TARGET_FAST_CLEAR vg_lite_get_product_info(NULL,&s_context.chip_id,&s_context.chip_rev); vg_lite_get_register(0x30, &cid); if(s_context.chip_id == 0x255 && s_context.chip_rev == 0x1311 && cid == 0x404) { tessellation_width = 64; tessellation_height = 64; } #endif /* Allocate a command buffer and a tessellation buffer. */ initialize.command_buffer_size = command_buffer_size; initialize.tessellation_width = tessellation_width; initialize.tessellation_height = tessellation_height; initialize.context = &s_context.context; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_INITIALIZE, &initialize)); /* Save draw context. */ s_context.capabilities = initialize.capabilities; s_context.command_buffer[0] = (uint8_t *)initialize.command_buffer[0]; s_context.command_buffer[1] = (uint8_t *)initialize.command_buffer[1]; s_context.command_buffer_size = initialize.command_buffer_size; s_context.command_offset[0] = 0; s_context.command_offset[1] = 0; if ((tessellation_width > 0) && (tessellation_height > 0)) { /* Set and Program Tessellation Buffer states. */ s_context.tsbuffer.tessellation_buffer_gpu[0] = initialize.tessellation_buffer_gpu[0]; s_context.tsbuffer.tessellation_buffer_gpu[1] = initialize.tessellation_buffer_gpu[1]; s_context.tsbuffer.tessellation_buffer_gpu[2] = initialize.tessellation_buffer_gpu[2]; s_context.tsbuffer.tessellation_buffer_logic[0] = initialize.tessellation_buffer_logic[0]; s_context.tsbuffer.tessellation_buffer_logic[1] = initialize.tessellation_buffer_logic[1]; s_context.tsbuffer.tessellation_buffer_logic[2] = initialize.tessellation_buffer_logic[2]; s_context.tsbuffer.tessellation_stride = initialize.tessellation_stride; s_context.tsbuffer.tessellation_width_height = initialize.tessellation_width_height; s_context.tsbuffer.tessellation_buffer_size[0] = initialize.tessellation_buffer_size[0]; s_context.tsbuffer.tessellation_buffer_size[1] = initialize.tessellation_buffer_size[1]; s_context.tsbuffer.tessellation_buffer_size[2] = initialize.tessellation_buffer_size[2]; s_context.tsbuffer.tessellation_shift = initialize.tessellation_shift; VG_LITE_RETURN_ERROR(program_tessellation(&s_context)); } /* Fill feature table. */ if (!s_context.s_ftable.ftflag){ VG_LITE_RETURN_ERROR(fill_feature_table(s_context.s_ftable.ftable)); } #if VG_TARGET_FAST_CLEAR /* Reset the FAST_CLEAR buffer. */ memset(&s_context.fcBuffer, 0, sizeof(s_context.fcBuffer)); s_context.fcBuffer.format = VG_LITE_A8; s_context.fcBuffer.height = 1; s_context.clearValue = 0; #endif /* Init scissor rect. */ s_context.scissor[0] = s_context.scissor[1] = s_context.scissor[2] = s_context.scissor[3] = 0; #if DUMP_CAPTURE _SetDumpFileInfo(); #endif #if (VG_RENDER_TEXT==1) vg_lite_text_init(); #endif /* VG_RENDER_TEXT */ return VG_LITE_SUCCESS; } #else vg_lite_error_t vg_lite_init(int32_t tessellation_width, int32_t tessellation_height) { vg_lite_error_t error; vg_lite_kernel_initialize_t initialize; vg_lite_tls_t* task_tls; error = (vg_lite_error_t)vg_lite_os_init_tls_array(); if(error != VG_LITE_SUCCESS) return error; task_tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(task_tls) return VG_LITE_SUCCESS; task_tls = (vg_lite_tls_t *) vg_lite_os_malloc(sizeof(vg_lite_tls_t)); if(!task_tls) return VG_LITE_OUT_OF_RESOURCES; memset(task_tls,0,sizeof(vg_lite_tls_t)); error = (vg_lite_error_t)vg_lite_os_set_tls((void *) task_tls); if(error != VG_LITE_SUCCESS) return error; task_tls->t_context.rtbuffer = NULL; if (tessellation_width <= 0) { tessellation_width = 0; tessellation_height = 0; } if (tessellation_height <= 0) { tessellation_height = 0; tessellation_width = 0; } tessellation_width = VG_LITE_ALIGN(tessellation_width, 16); /* Allocate a command buffer and a tessellation buffer. */ initialize.command_buffer_size = command_buffer_size; initialize.context_buffer_size = CONTEXT_BUFFER_SIZE; initialize.tessellation_width = tessellation_width; initialize.tessellation_height = tessellation_height; initialize.context = &task_tls->t_context.context; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_INITIALIZE, &initialize)); /* Save draw context. */ task_tls->t_context.capabilities = initialize.capabilities; task_tls->t_context.command_buffer[0] = (uint8_t *)initialize.command_buffer[0]; task_tls->t_context.command_buffer[1] = (uint8_t *)initialize.command_buffer[1]; task_tls->t_context.command_buffer_size = initialize.command_buffer_size; task_tls->t_context.command_offset[0] = 0; task_tls->t_context.command_offset[1] = 0; task_tls->t_context.command_buffer_current = 0; task_tls->t_context.context_buffer[0] = (uint8_t *)initialize.context_buffer[0]; task_tls->t_context.context_buffer[1] = (uint8_t *)initialize.context_buffer[1]; task_tls->t_context.context_buffer_size = initialize.context_buffer_size; task_tls->t_context.context_buffer_offset[0] = 0; task_tls->t_context.context_buffer_offset[1] = 0; task_tls->t_context.start_offset = 0; task_tls->t_context.end_offset = 0; task_tls->t_context.ts_init = 0; memset(task_tls->t_context.ts_record, 0, sizeof(task_tls->t_context.ts_record)); if ((tessellation_width > 0) && (tessellation_height > 0)) { /* Set and Program Tessellation Buffer states. */ task_tls->t_context.tsbuffer.tessellation_buffer_gpu[0] = initialize.tessellation_buffer_gpu[0]; task_tls->t_context.tsbuffer.tessellation_buffer_gpu[1] = initialize.tessellation_buffer_gpu[1]; task_tls->t_context.tsbuffer.tessellation_buffer_gpu[2] = initialize.tessellation_buffer_gpu[2]; task_tls->t_context.tsbuffer.tessellation_buffer_logic[0] = initialize.tessellation_buffer_logic[0]; task_tls->t_context.tsbuffer.tessellation_buffer_logic[1] = initialize.tessellation_buffer_logic[1]; task_tls->t_context.tsbuffer.tessellation_buffer_logic[2] = initialize.tessellation_buffer_logic[2]; task_tls->t_context.tsbuffer.tessellation_stride = initialize.tessellation_stride; task_tls->t_context.tsbuffer.tessellation_width_height = initialize.tessellation_width_height; task_tls->t_context.tsbuffer.tessellation_buffer_size[0] = initialize.tessellation_buffer_size[0]; task_tls->t_context.tsbuffer.tessellation_buffer_size[1] = initialize.tessellation_buffer_size[1]; task_tls->t_context.tsbuffer.tessellation_buffer_size[2] = initialize.tessellation_buffer_size[2]; task_tls->t_context.tsbuffer.tessellation_shift = initialize.tessellation_shift; VG_LITE_RETURN_ERROR(program_tessellation(&task_tls->t_context)); } VG_LITE_RETURN_ERROR(push_state(&task_tls->t_context, 0x0A00, 0x0)); VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_LOCK, NULL)); /* Fill feature table. */ if (!task_tls->t_context.s_ftable.ftflag){ VG_LITE_RETURN_ERROR(fill_feature_table(task_tls->t_context.s_ftable.ftable)); } VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_UNLOCK, NULL)); #if VG_TARGET_FAST_CLEAR /* Reset the FAST_CLEAR buffer. */ memset(&task_tls->t_context.fcBuffer, 0, sizeof(task_tls->t_context.fcBuffer)); task_tls->t_context.fcBuffer.format = VG_LITE_A8; task_tls->t_context.fcBuffer.height = 1; task_tls->t_context.clearValue = 0; #endif /* Init scissor rect. */ task_tls->t_context.scissor[0] = task_tls->t_context.scissor[1] = task_tls->t_context.scissor[2] = task_tls->t_context.scissor[3] = 0; #if DUMP_CAPTURE _SetDumpFileInfo(); #endif #if (VG_RENDER_TEXT==1) vg_lite_text_init(); #endif /* VG_RENDER_TEXT */ return VG_LITE_SUCCESS; } #endif /* VG_DRIVER_SINGLE_THREAD */ vg_lite_error_t vg_lite_set_draw_path_type(vg_lite_path_t * path,vg_lite_draw_path_type_t path_type) { if(!path || (path_type > VG_LITE_DRAW_STROKE_PATH + 1)) return VG_LITE_INVALID_ARGUMENT; path->path_type = path_type; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_draw(vg_lite_buffer_t * target, vg_lite_path_t * path, vg_lite_fill_t fill_rule, vg_lite_matrix_t * matrix, vg_lite_blend_t blend, vg_lite_color_t color) { uint32_t blend_mode; uint32_t format, quality, tiling, fill; uint32_t tessellation_size; vg_lite_error_t error; vg_lite_point_t point_min = {0}, point_max = {0}, temp = {0}; int x, y, width, height; uint8_t ts_is_fullscreen = 0; #if DUMP_COMMAND uint32_t return_offset = 0; vg_lite_kernel_allocate_t memory; #endif int32_t dst_align_width; uint32_t mul, div, align; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t *tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ if(!path) return VG_LITE_INVALID_ARGUMENT; if(!path->path_length) return VG_LITE_SUCCESS; if(!path->path) return VG_LITE_INVALID_ARGUMENT; if(!vg_lite_query_feature(gcFEATURE_BIT_VG_QUALITY_8X) && path->quality == VG_LITE_UPPER){ return VG_LITE_NOT_SUPPORT; } error = set_render_target(target); if (error != VG_LITE_SUCCESS) { return error; } else if (error == VG_LITE_NO_CONTEXT) { /* If scissoring is enabled and no valid scissoring rectangles are present, no drawing occurs */ return VG_LITE_SUCCESS; } width = ctx->tsbuffer.tessellation_width_height & 0xFFFF; height = ctx->tsbuffer.tessellation_width_height >> 16; get_format_bytes(target->format, &mul, &div, &align); dst_align_width = target->stride * div / mul; if(width == 0 || height == 0) return VG_LITE_NO_CONTEXT; if ((dst_align_width <= width) && (target->height <= height)) { ts_is_fullscreen = 1; point_min.x = 0; point_min.y = 0; point_max.x = dst_align_width; point_max.y = target->height; } if (ts_is_fullscreen == 0){ transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[1], matrix); point_min = point_max = temp; transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[1], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[3], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[3], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; if (point_min.x < 0) point_min.x = 0; if (point_min.y < 0) point_min.y = 0; if (point_max.x > dst_align_width) point_max.x = dst_align_width; if (point_max.y > target->height) point_max.y = target->height; } if (ctx->scissor_enabled) { point_min.x = MAX(point_min.x, ctx->scissor[0]); point_min.y = MAX(point_min.y, ctx->scissor[1]); point_max.x = MIN(point_max.x, ctx->scissor[0] + ctx->scissor[2]); point_max.y = MIN(point_max.y, ctx->scissor[1] + ctx->scissor[3]); } /* Convert states into hardware values. */ blend_mode = convert_blend(blend); format = convert_path_format(path->format); quality = convert_path_quality(path->quality); tiling = (ctx->capabilities.cap.tiled == 2) ? 0x2000000 : 0; fill = (fill_rule == VG_LITE_FILL_EVEN_ODD) ? 0x10 : 0; tessellation_size = ( ctx->tsbuffer.tessellation_buffer_size[2] ? ctx->tsbuffer.tessellation_buffer_size[2] : ctx->tsbuffer.tessellation_buffer_size[1] ); #if !defined(VG_DRIVER_SINGLE_THREAD) if(ctx->ts_dirty){ memcpy(CMDBUF_BUFFER(*ctx) + CMDBUF_OFFSET(*ctx), ctx->ts_record, 80); CMDBUF_OFFSET(*ctx) += 80; ctx->ts_dirty = 0; ctx->ts_init_used = 1; } else { ctx->ts_init_use = 1; } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ /* Setup the command buffer. */ /* Program color register. */ if(ctx->premultiply_enabled) { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, ctx->capabilities.cap.tiled | blend_mode)); } else { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x10000000 | ctx->capabilities.cap.tiled | blend_mode)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, color)); /* Program tessellation control: for TS module. */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000200 | format | quality | tiling | fill)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3B, 0x3F800000)); /* Path tessellation SCALE. */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3C, 0x00000000)); /* Path tessellation BIAS. */ /* Program matrix. */ VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A40, (void *) &matrix->m[0][0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A41, (void *) &matrix->m[0][1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A42, (void *) &matrix->m[0][2])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A43, (void *) &matrix->m[1][0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A44, (void *) &matrix->m[1][1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A45, (void *) &matrix->m[1][2])); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { vglitemDUMP_BUFFER("path", path->uploaded.address, (uint8_t *)(path->uploaded.memory), 0, path->uploaded.bytes); } vglitemDUMP("@[memory 0x%08X 0x%08X]", ctx->tsbuffer.tessellation_buffer_gpu[0], ctx->tsbuffer.tessellation_buffer_size[0]); /* Setup tessellation loop. */ if((path->path_type & 0x1) == VG_LITE_DRAW_FILL_PATH) { for (y = point_min.y; y < point_max.y; y += height) { for (x = point_min.x; x < point_max.x; x += width) { /* Tessellate path. */ VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); #if (DUMP_COMMAND) if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[0], 0); unsigned char* pt = (unsigned char*) memory.memory; for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) { if (i % 8 == 0) fprintf(fp, "Command buffer: "); if (i % 4 == 0) fprintf(fp, "0x"); for (int j = 3; j >= 0; --j) fprintf(fp, "%02x", pt[i + j]); if ((i / 4 + 1) % 2 == 0) fprintf(fp, ",\n"); else fprintf(fp, ", "); } fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[return_offset], 0); fclose(fp); fp = NULL; #endif } else { push_data(ctx, path->path_length, path->path); } } } } /* Setup tessellation loop. */ if(path->path_type == VG_LITE_DRAW_STROKE_PATH || path->path_type == VG_LITE_DRAW_FILL_STROKE_PATH) { for (y = point_min.y; y < point_max.y; y += height) { for (x = point_min.x; x < point_max.x; x += width) { /* Tessellate path. */ VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); #if (DUMP_COMMAND) if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[0], 0); unsigned char* pt = (unsigned char*) memory.memory; for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) { if (i % 8 == 0) fprintf(fp, "Command buffer: "); if (i % 4 == 0) fprintf(fp, "0x"); for (int j = 3; j >= 0; --j) fprintf(fp, "%02x", pt[i + j]); if ((i / 4 + 1) % 2 == 0) fprintf(fp, ",\n"); else fprintf(fp, ", "); } fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[return_offset], 0); fclose(fp); fp = NULL; #endif } else { format = convert_path_format(VG_LITE_FP32); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000200 | format | quality | tiling | 0x0)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, path->stroke_color)); push_data(ctx, path->stroke_path_size, path->stroke_path_data); } } } } /* Finialize command buffer. */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0)); VG_LITE_RETURN_ERROR(flush_target()); #if !defined(VG_DRIVER_SINGLE_THREAD) ctx->ts_init = 1; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ return error; } vg_lite_error_t vg_lite_close(void) { vg_lite_error_t error; vg_lite_kernel_terminate_t terminate; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ #if VG_TARGET_FAST_CLEAR if (ctx->fcBuffer.handle != NULL) { vg_lite_free(&ctx->fcBuffer); } #endif /* Termnate the draw context. */ terminate.context = &ctx->context; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_TERMINATE, &terminate)); #if defined(VG_DRIVER_SINGLE_THREAD) if(ctx->rtbuffer) free(ctx->rtbuffer); submit_flag = 0; /* Reset the draw context. */ _memset(ctx, 0, sizeof(s_context)); /* Reset the s_ftable. */ _memset(&ctx->s_ftable, 0, sizeof(ctx->s_ftable)); ctx->init = 0; #else /* Reset the draw context. */ if(tls->t_context.colors){ free(ctx->colors[0]); free(ctx->colors[1]); free(ctx->colors[2]); free(ctx->colors[3]); } _memset(ctx, 0, sizeof(*ctx)); vg_lite_os_reset_tls(); vg_lite_os_free((void *) tls); vg_lite_os_deinit_tls_array(); #endif /* VG_DRIVER_SINGLE_THREAD */ #if DUMP_CAPTURE _SetDumpFileInfo(); #endif return VG_LITE_SUCCESS; } /* Handle tiled & yuv allocation. Currently including NV12, ANV12, YV12, YV16, NV16, YV24. */ static vg_lite_error_t _allocate_tiled_yuv_planar(vg_lite_buffer_t *buffer) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t yplane_size = 0; vg_lite_kernel_allocate_t allocate, uv_allocate, v_allocate; if ((buffer->format < VG_LITE_NV12) || (buffer->format > VG_LITE_ANV12_TILED) || (buffer->format == VG_LITE_AYUY2) || (buffer->format == VG_LITE_YUY2_TILED)) { return error; } /* For NV12, there are 2 planes (Y, UV); For ANV12, there are 3 planes (Y, UV, Alpha). Each plane must be aligned by (4, 8). Then Y plane must be aligned by (8, 8). For YVxx, there are 3 planes (Y, U, V). YV12 is similar to NV12, both YUV420 format. YV16 and NV16 are YUV422 format. YV24 is YUV444 format. */ buffer->width = VG_LITE_ALIGN(buffer->width, 8); buffer->height = VG_LITE_ALIGN(buffer->height, 8); buffer->stride = VG_LITE_ALIGN(buffer->width, 128); switch (buffer->format) { case VG_LITE_NV12: case VG_LITE_ANV12: case VG_LITE_NV12_TILED: case VG_LITE_ANV12_TILED: buffer->yuv.uv_stride = buffer->stride; buffer->yuv.alpha_stride = buffer->stride; buffer->yuv.uv_height = buffer->height / 2; break; case VG_LITE_NV16: buffer->yuv.uv_stride = buffer->stride; buffer->yuv.uv_height = buffer->height; break; case VG_LITE_YV12: buffer->yuv.uv_stride = buffer->yuv.v_stride = buffer->stride / 2; buffer->yuv.uv_height = buffer->yuv.v_height = buffer->height / 2; break; case VG_LITE_YV16: buffer->yuv.uv_stride = buffer->yuv.v_stride = buffer->stride; buffer->yuv.uv_height = buffer->yuv.v_height = buffer->height / 2; break; case VG_LITE_YV24: buffer->yuv.uv_stride = buffer->yuv.v_stride = buffer->stride; buffer->yuv.uv_height = buffer->yuv.v_height = buffer->height; break; default: return error; } yplane_size = buffer->stride * buffer->height; /* Allocate buffer memory: Y. */ allocate.bytes = yplane_size; allocate.contiguous = 1; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); /* Save the allocation. */ buffer->handle = allocate.memory_handle; buffer->memory = allocate.memory; buffer->address = allocate.memory_gpu; if ((buffer->format == VG_LITE_NV12) || (buffer->format == VG_LITE_ANV12) || (buffer->format == VG_LITE_NV16) || (buffer->format == VG_LITE_NV12_TILED) || (buffer->format == VG_LITE_ANV12_TILED)) { /* Allocate buffer memory: UV. */ uv_allocate.bytes = buffer->yuv.uv_stride * buffer->yuv.uv_height; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &uv_allocate)); buffer->yuv.uv_handle = uv_allocate.memory_handle; buffer->yuv.uv_memory = uv_allocate.memory; buffer->yuv.uv_planar = uv_allocate.memory_gpu; if ((buffer->format == VG_LITE_ANV12) || (buffer->format == VG_LITE_ANV12_TILED)) { uv_allocate.bytes = yplane_size; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &uv_allocate)); buffer->yuv.alpha_planar = uv_allocate.memory_gpu; } } else { /* Allocate buffer memory: U, V. */ uv_allocate.bytes = buffer->yuv.uv_stride * buffer->yuv.uv_height; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &uv_allocate)); buffer->yuv.uv_handle = uv_allocate.memory_handle; buffer->yuv.uv_memory = uv_allocate.memory; buffer->yuv.uv_planar = uv_allocate.memory_gpu; v_allocate.bytes = buffer->yuv.v_stride * buffer->yuv.v_height; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &v_allocate)); buffer->yuv.v_handle = v_allocate.memory_handle; buffer->yuv.v_memory = v_allocate.memory; buffer->yuv.v_planar = v_allocate.memory_gpu; } return error; } vg_lite_error_t vg_lite_allocate(vg_lite_buffer_t * buffer) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_kernel_allocate_t allocate; /* Reset planar. */ buffer->yuv.uv_planar = buffer->yuv.v_planar = buffer->yuv.alpha_planar = 0; /* Align height in case format is tiled. */ if (buffer->format >= VG_LITE_YUY2 && buffer->format <= VG_LITE_NV16) { buffer->height = VG_LITE_ALIGN(buffer->height, 4); buffer->yuv.swizzle = VG_LITE_SWIZZLE_UV; } if (buffer->format >= VG_LITE_YUY2_TILED && buffer->format <= VG_LITE_AYUY2_TILED) { buffer->height = VG_LITE_ALIGN(buffer->height, 4); buffer->tiled = VG_LITE_TILED; buffer->yuv.swizzle = VG_LITE_SWIZZLE_UV; } if ((buffer->format >= VG_LITE_NV12 && buffer->format <= VG_LITE_ANV12_TILED && buffer->format != VG_LITE_AYUY2 && buffer->format != VG_LITE_YUY2_TILED)) { _allocate_tiled_yuv_planar(buffer); } else { /* Driver need compute the stride always with RT500 project. */ uint32_t mul, div, align; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ get_format_bytes(buffer->format, &mul, &div, &align); vg_lite_get_product_info(NULL,&ctx->chip_id,NULL); buffer->stride = VG_LITE_ALIGN((buffer->width * mul / div), align); /* Allocate the buffer. */ allocate.bytes = buffer->stride * buffer->height; #if VG_TARGET_FAST_CLEAR allocate.bytes = VG_LITE_ALIGN(allocate.bytes, 64); #endif allocate.contiguous = 1; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); /* Save the buffer allocation. */ buffer->handle = allocate.memory_handle; buffer->memory = allocate.memory; buffer->address = allocate.memory_gpu; if ((buffer->format == VG_LITE_AYUY2) || (buffer->format == VG_LITE_AYUY2_TILED)) { allocate.bytes = buffer->stride * buffer->height; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); buffer->yuv.alpha_planar = allocate.memory_gpu; } } return VG_LITE_SUCCESS; } #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_error_t vg_lite_free(vg_lite_buffer_t * buffer) { vg_lite_error_t error; vg_lite_kernel_free_t free, uv_free, v_free; if(buffer == NULL) return VG_LITE_INVALID_ARGUMENT; if (!(memcmp(s_context.rtbuffer,buffer,sizeof(vg_lite_buffer_t))) ) { if (VG_LITE_SUCCESS == submit(&s_context)) { VG_LITE_RETURN_ERROR(stall(&s_context, 0, ~0)); } vglitemDUMP("@[swap 0x%08X %dx%d +%u]", s_context.rtbuffer->address, s_context.rtbuffer->width, s_context.rtbuffer->height, s_context.rtbuffer->stride); vglitemDUMP_BUFFER( "framebuffer", s_context.rtbuffer->address,s_context.rtbuffer->memory, 0, s_context.rtbuffer->stride*(s_context.rtbuffer->height)); memset(s_context.rtbuffer, 0, sizeof(vg_lite_buffer_t)); } if (buffer->yuv.uv_planar) { /* Free UV(U) planar buffer. */ uv_free.memory_handle = buffer->yuv.uv_handle; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &uv_free)); /* Mark the buffer as freed. */ buffer->yuv.uv_handle = NULL; buffer->yuv.uv_memory = NULL; } if (buffer->yuv.v_planar) { /* Free V planar buffer. */ v_free.memory_handle = buffer->yuv.v_handle; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &v_free)); /* Mark the buffer as freed. */ buffer->yuv.v_handle = NULL; buffer->yuv.v_memory = NULL; } /* Make sure we have a valid memory handle. */ if (buffer->handle == NULL) { return VG_LITE_INVALID_ARGUMENT; } /* Free the buffer. */ free.memory_handle = buffer->handle; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &free)); /* Mark the buffer as freed. */ buffer->handle = NULL; buffer->memory = NULL; return VG_LITE_SUCCESS; } #else vg_lite_error_t vg_lite_free(vg_lite_buffer_t * buffer) { vg_lite_error_t error; vg_lite_kernel_free_t free, uv_free, v_free; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; if(buffer == NULL) return VG_LITE_INVALID_ARGUMENT; if (tls->t_context.rtbuffer == buffer && !(memcmp(tls->t_context.rtbuffer,buffer,sizeof(vg_lite_buffer_t))) ) { if (VG_LITE_SUCCESS == submit(&tls->t_context)) { VG_LITE_RETURN_ERROR(stall(&tls->t_context, 0)); } vglitemDUMP("@[swap 0x%08X %dx%d +%u]", tls->t_context.rtbuffer->address, tls->t_context.rtbuffer->width, tls->t_context.rtbuffer->height, tls->t_context.rtbuffer->stride); vglitemDUMP_BUFFER( "framebuffer", tls->t_context.rtbuffer->address,tls->t_context.rtbuffer->memory, 0, tls->t_context.rtbuffer->stride*(tls->t_context.rtbuffer->height)); memset(tls->t_context.rtbuffer, 0, sizeof(vg_lite_buffer_t)); } if (buffer->yuv.uv_planar) { /* Free UV(U) planar buffer. */ uv_free.memory_handle = buffer->yuv.uv_handle; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &uv_free)); /* Mark the buffer as freed. */ buffer->yuv.uv_handle = NULL; buffer->yuv.uv_memory = NULL; } if (buffer->yuv.v_planar) { /* Free V planar buffer. */ v_free.memory_handle = buffer->yuv.v_handle; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &v_free)); /* Mark the buffer as freed. */ buffer->yuv.v_handle = NULL; buffer->yuv.v_memory = NULL; } /* Make sure we have a valid memory handle. */ if (buffer->handle == NULL) { return VG_LITE_INVALID_ARGUMENT; } /* Free the buffer. */ free.memory_handle = buffer->handle; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &free)); /* Mark the buffer as freed. */ buffer->handle = NULL; buffer->memory = NULL; return VG_LITE_SUCCESS; } #endif /* VG_DRIVER_SINGLE_THREAD */ vg_lite_error_t vg_lite_map(vg_lite_buffer_t * buffer) { vg_lite_error_t error; vg_lite_kernel_map_t map; /* We either need a logical or physical address. */ if (buffer->memory == NULL && buffer->address == 0) { return VG_LITE_INVALID_ARGUMENT; } /* Check if we need to compute the stride. Usually map a pre-allocated memory, so the stride usually should be set*/ if (buffer->stride == 0) { uint32_t mul, div, align; get_format_bytes(buffer->format, &mul, &div, &align); /* Compute the stride to be aligned. */ buffer->stride = VG_LITE_ALIGN((buffer->width * mul / div), align); } /* Map the buffer. */ map.bytes = buffer->stride * buffer->height; map.logical = buffer->memory; map.physical = buffer->address; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_MAP, &map)); /* Save the buffer allocation. */ buffer->handle = map.memory_handle; buffer->address = map.memory_gpu; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_unmap(vg_lite_buffer_t * buffer) { vg_lite_error_t error; vg_lite_kernel_unmap_t unmap; /* Make sure we have a valid memory handle. */ if (buffer->handle == NULL) { return VG_LITE_INVALID_ARGUMENT; } /* Unmap the buffer. */ unmap.memory_handle = buffer->handle; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_UNMAP, &unmap)); /* Mark the buffer as freed. */ buffer->handle = NULL; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_get_register(uint32_t address, uint32_t * result) { vg_lite_error_t error; vg_lite_kernel_info_t data; /* Get input register address. */ data.addr = address; /* Get register info. */ VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_CHECK, &data)); /* Return register info. */ *result = data.reg; return VG_LITE_SUCCESS; } void vg_lite_get_info(vg_lite_info_t *info) { if (info != NULL) { info->api_version = VGLITE_API_VERSION_2_0; info->header_version = VGLITE_HEADER_VERSION; info->release_version = VGLITE_RELEASE_VERSION; info->reserved = 0; } } uint32_t vg_lite_get_product_info(char *name, uint32_t *chip_id, uint32_t *chip_rev) { const char *product_name = "GCNanoLiteV"; uint32_t name_len; uint32_t rev = 0, id = 0; vg_lite_get_register(0x24, &rev); vg_lite_get_register(0x20, &id); name_len = strlen(product_name) + 1; if (name != NULL) { memcpy(name, product_name, name_len); } if (chip_id != NULL) { *chip_id = id; } if (chip_rev != NULL) { *chip_rev = rev; } return name_len; } uint32_t vg_lite_query_feature(vg_lite_feature_t feature) { uint32_t result; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t *tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if (tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ if (feature < gcFEATURE_COUNT) result = ctx->s_ftable.ftable[feature]; else result = 0; return result; } #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_error_t vg_lite_finish() { vg_lite_error_t error; /* Return if there is nothing to submit. */ if (CMDBUF_OFFSET(s_context) == 0) { if(submit_flag) VG_LITE_RETURN_ERROR(stall(&s_context, 0, (uint32_t)~0)); return VG_LITE_SUCCESS; } /* Flush is moved from each draw to here. */ VG_LITE_RETURN_ERROR(flush_target()); VG_LITE_RETURN_ERROR(submit(&s_context)); VG_LITE_RETURN_ERROR(stall(&s_context, 0, (uint32_t)~0)); #if VG_TARGET_FAST_CLEAR /*Only used in cmodel/fpga. In final SOC this SW FC decoder should be removed. */ if (s_context.rtbuffer != NULL) { #if VG_TARGET_FC_DUMP fc_buf_dump(s_context.rtbuffer, &s_context.fcBuffer); #endif /* VG_TARGET_FC_DUMP */ } #endif CMDBUF_SWAP(s_context); /* Reset command buffer. */ CMDBUF_OFFSET(s_context) = 0; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_flush(void) { vg_lite_error_t error; /* Return if there is nothing to submit. */ if (CMDBUF_OFFSET(s_context) == 0) return VG_LITE_SUCCESS; /* Wait if GPU has not completed previous CMD buffer */ if (submit_flag) { VG_LITE_RETURN_ERROR(stall(&s_context, 0, (uint32_t)~0)); } /* Submit the current command buffer. */ VG_LITE_RETURN_ERROR(flush_target()); VG_LITE_RETURN_ERROR(submit(&s_context)); CMDBUF_SWAP(s_context); /* Reset command buffer. */ CMDBUF_OFFSET(s_context) = 0; return VG_LITE_SUCCESS; } #else vg_lite_error_t vg_lite_finish() { vg_lite_error_t error; vg_lite_tls_t* tls; uint32_t command_id, index; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; command_id = CMDBUF_INDEX(tls->t_context); index = command_id ? 0 : 1; if (CMDBUF_OFFSET(tls->t_context) <= 8){ /* Return if there is nothing to submit. */ if (!CMDBUF_IN_QUEUE(&tls->t_context.context, 0) && !CMDBUF_IN_QUEUE(&tls->t_context.context, 1) ) return VG_LITE_SUCCESS; /* This frame has unfinished command. */ else if(CMDBUF_IN_QUEUE(&tls->t_context.context, index)) { CMDBUF_SWAP(tls->t_context); VG_LITE_RETURN_ERROR(stall(&tls->t_context, 0)); } /* This frame has unfinished command. */ else if(CMDBUF_IN_QUEUE(&tls->t_context.context, command_id)) { VG_LITE_RETURN_ERROR(stall(&tls->t_context, 0)); } CMDBUF_OFFSET(tls->t_context) = 0; VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A00, 0x0)); return VG_LITE_SUCCESS; } else { /* Flush is moved from each draw to here. */ VG_LITE_RETURN_ERROR(flush_target()); VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_LOCK, NULL)); /* if context have been switched and this task need use index. */ VG_LITE_RETURN_ERROR(update_context_buffer()); VG_LITE_RETURN_ERROR(submit(&tls->t_context)); VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_UNLOCK, NULL)); VG_LITE_RETURN_ERROR(stall(&tls->t_context, 0)); } #if VG_TARGET_FAST_CLEAR /*Only used in cmodel/fpga. In final SOC this SW FC decoder should be removed. */ if (tls->t_context.rtbuffer != NULL) { #if VG_TARGET_FC_DUMP fc_buf_dump(tls->t_context.rtbuffer, &tls->t_context.fcBuffer); #endif /* VG_TARGET_FC_DUMP */ } #endif CMDBUF_SWAP(tls->t_context); CMDBUF_OFFSET(tls->t_context) = 0; VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A00, 0x0)); tls->t_context.ts_init_used = 0; tls->t_context.ts_init_use = 0; tls->t_context.ts_init = 0; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_flush(void) { vg_lite_error_t error; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; /* Return if there is nothing to submit. */ if (CMDBUF_OFFSET(tls->t_context) == 0) return VG_LITE_SUCCESS; /* Submit the current command buffer. */ VG_LITE_RETURN_ERROR(flush_target()); VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_LOCK, NULL)); /* if context have been switched and this task need use index. */ VG_LITE_RETURN_ERROR(update_context_buffer()); VG_LITE_RETURN_ERROR(submit(&tls->t_context)); VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_UNLOCK, NULL)); CMDBUF_SWAP(tls->t_context); CMDBUF_OFFSET(tls->t_context) = 0; VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A00, 0x0)); tls->t_context.ts_init_used = 0; tls->t_context.ts_init_use = 0; tls->t_context.ts_init = 0; return VG_LITE_SUCCESS; } #endif /* VG_DRIVER_SINGLE_THREAD */ vg_lite_error_t vg_lite_init_arc_path(vg_lite_path_t * path, vg_lite_format_t data_format, vg_lite_quality_t quality, uint32_t path_length, void * path_data, vg_lite_float_t min_x, vg_lite_float_t min_y, vg_lite_float_t max_x, vg_lite_float_t max_y) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t i = 0,command = 0,offset = 0; vg_lite_float_t moveToX,moveToY,lineToX,lineToY,controlX, controlY,quadToX, quadToY; vg_lite_float_t controlX1, controlY1,controlX2, controlY2,cubicToX, cubicToY; vg_lite_float_t horRadius,verRadius,rotAngle,endX,endY; float *pfloat,*fpath; char *cpath,*pathdata; vg_lite_control_coord_t coords; if(path == NULL || path_data == NULL || data_format != VG_LITE_FP32) return VG_LITE_INVALID_ARGUMENT; memset(path, 0, sizeof(*path)); if(!path_length) { path->format = data_format; path->quality = quality; path->bounding_box[0] = min_x; path->bounding_box[1] = min_y; path->bounding_box[2] = max_x; path->bounding_box[3] = max_y; path->path_length = 0; path->path = NULL; path->pdata_internal = 1; path->path_changed = 1; path->uploaded.address = 0; path->uploaded.bytes = 0; path->uploaded.handle = NULL; path->uploaded.memory = NULL; return VG_LITE_SUCCESS; } memset(&coords, 0, sizeof(vg_lite_control_coord_t)); pathdata = (char *)vg_lite_os_malloc(path_length); if (pathdata == NULL) return VG_LITE_OUT_OF_MEMORY; memset(pathdata, 0, path_length); pfloat = (vg_lite_float_t *)path_data; while(i < path_length) { cpath = (char *)pfloat; command = (uint32_t)*cpath; pfloat++; switch (command) { case VLC_OP_END: cpath = (char *)pathdata + offset; fpath = (vg_lite_float_t *)cpath; *cpath = VLC_OP_END; offset += _commandSize_float[VLC_OP_END]; i += _commandSize_float[VLC_OP_END]; break; case VLC_OP_CLOSE: /* Update the control coordinates. */ coords.lastX = coords.startX; coords.lastY = coords.startY; coords.controlX = coords.startX; coords.controlY = coords.startY; cpath = (char *)pathdata + offset; fpath = (vg_lite_float_t *)cpath; *cpath = VLC_OP_CLOSE; offset += _commandSize_float[VLC_OP_CLOSE]; i += _commandSize_float[VLC_OP_CLOSE]; break; case VLC_OP_MOVE: moveToX = *pfloat++; moveToY = *pfloat++; /* Update the control coordinates. */ coords.startX = moveToX; coords.startY = moveToY; coords.lastX = moveToX; coords.lastY = moveToY; coords.controlX = moveToX; coords.controlY = moveToY; cpath = (char *)pathdata + offset; fpath = (vg_lite_float_t *)cpath; *cpath = VLC_OP_MOVE; fpath++; *fpath++ = moveToX; *fpath++ = moveToY; offset += _commandSize_float[VLC_OP_MOVE]; i += _commandSize_float[VLC_OP_MOVE]; break; case VLC_OP_MOVE_REL: moveToX = *pfloat++; moveToY = *pfloat++; cpath = (char *)pathdata + offset; fpath = (vg_lite_float_t *)cpath; *cpath = VLC_OP_MOVE_REL; fpath++; *fpath++ = moveToX; *fpath++ = moveToY; offset += _commandSize_float[VLC_OP_MOVE_REL]; i += _commandSize_float[VLC_OP_MOVE_REL]; /* Determine the absolute coordinates. */ moveToX += coords.lastX; moveToY += coords.lastY; /* Update the control coordinates. */ coords.startX = moveToX; coords.startY = moveToY; coords.lastX = moveToX; coords.lastY = moveToY; coords.controlX = moveToX; coords.controlY = moveToY; break; case VLC_OP_LINE: lineToX = *pfloat++; lineToY = *pfloat++; /* Update the control coordinates. */ coords.lastX = lineToX; coords.lastY = lineToY; coords.controlX = lineToX; coords.controlY = lineToY; cpath = (char *)pathdata + offset; fpath = (vg_lite_float_t *)cpath; *cpath = VLC_OP_LINE; fpath++; *fpath++ = lineToX; *fpath++ = lineToY; offset += _commandSize_float[VLC_OP_LINE]; i += _commandSize_float[VLC_OP_LINE]; break; case VLC_OP_LINE_REL: lineToX = *pfloat++; lineToY = *pfloat++; cpath = (char *)pathdata + offset; fpath = (vg_lite_float_t *)cpath; *cpath = VLC_OP_LINE_REL; fpath++; *fpath++ = lineToX; *fpath++ = lineToY; offset += _commandSize_float[VLC_OP_LINE_REL]; i += _commandSize_float[VLC_OP_LINE_REL]; /* Determine the absolute coordinates. */ lineToX += coords.lastX; lineToY += coords.lastY; /* Update the control coordinates. */ coords.lastX = lineToX; coords.lastY = lineToY; coords.controlX = lineToX; coords.controlY = lineToY; break; case VLC_OP_QUAD: controlX = *pfloat++; controlY = *pfloat++; quadToX = *pfloat++; quadToY = *pfloat++; /* Update the control coordinates. */ coords.lastX = quadToX; coords.lastY = quadToY; coords.controlX = controlX; coords.controlY = controlY; cpath = (char *)pathdata + offset; fpath = (vg_lite_float_t *)cpath; *cpath = VLC_OP_QUAD; fpath++; *fpath++ = controlX; *fpath++ = controlY; *fpath++ = quadToX; *fpath++ = quadToY; offset += _commandSize_float[VLC_OP_QUAD]; i += _commandSize_float[VLC_OP_QUAD]; break; case VLC_OP_QUAD_REL: controlX = *pfloat++; controlY = *pfloat++; quadToX = *pfloat++; quadToY = *pfloat++; cpath = (char *)pathdata + offset; fpath = (vg_lite_float_t *)cpath; *cpath = VLC_OP_QUAD_REL; fpath++; *fpath++ = controlX; *fpath++ = controlY; *fpath++ = quadToX; *fpath++ = quadToY; offset += _commandSize_float[VLC_OP_QUAD_REL]; i += _commandSize_float[VLC_OP_QUAD_REL]; /* Determine the absolute coordinates. */ controlX += coords.lastX; controlY += coords.lastY; quadToX += coords.lastX; quadToY += coords.lastY; /* Update the control coordinates. */ coords.lastX = quadToX; coords.lastY = quadToY; coords.controlX = controlX; coords.controlY = controlY; break; case VLC_OP_CUBIC: controlX1 = *pfloat++; controlY1 = *pfloat++; controlX2 = *pfloat++; controlY2 = *pfloat++; cubicToX = *pfloat++; cubicToY = *pfloat++; /* Update the control coordinates. */ coords.lastX = cubicToX; coords.lastY = cubicToY; coords.controlX = controlX2; coords.controlY = controlY2; cpath = (char *)pathdata + offset; fpath = (vg_lite_float_t *)cpath; *cpath = VLC_OP_CUBIC; fpath++; *fpath++ = controlX1; *fpath++ = controlY1; *fpath++ = controlX2; *fpath++ = controlY2; *fpath++ = cubicToX; *fpath++ = cubicToY; offset += _commandSize_float[VLC_OP_CUBIC]; i += _commandSize_float[VLC_OP_CUBIC]; break; case VLC_OP_CUBIC_REL: controlX1 = *pfloat++; controlY1 = *pfloat++; controlX2 = *pfloat++; controlY2 = *pfloat++; cubicToX = *pfloat++; cubicToY = *pfloat++; cpath = (char *)pathdata + offset; fpath = (vg_lite_float_t *)cpath; *cpath = VLC_OP_CUBIC_REL; fpath++; *fpath++ = controlX1; *fpath++ = controlY1; *fpath++ = controlX2; *fpath++ = controlY2; *fpath++ = cubicToX; *fpath++ = cubicToY; offset += _commandSize_float[VLC_OP_CUBIC_REL]; i += _commandSize_float[VLC_OP_CUBIC_REL]; /* Determine the absolute coordinates. */ controlX2 += coords.lastX; controlY2 += coords.lastY; cubicToX += coords.lastX; cubicToY += coords.lastY; /* Update the control coordinates. */ coords.lastX = cubicToX; coords.lastY = cubicToY; coords.controlX = controlX2; coords.controlY = controlY2; break; case VLC_OP_SCCWARC: horRadius = *pfloat++; verRadius = *pfloat++; rotAngle = *pfloat++; endX = *pfloat++; endY = *pfloat++; i += _commandSize_float[VLC_OP_SCCWARC]; VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,FALSE,FALSE,FALSE,&coords,(void *)&pathdata,&offset,path_length - i)); break; case VLC_OP_SCCWARC_REL: horRadius = *pfloat++; verRadius = *pfloat++; rotAngle = *pfloat++; endX = *pfloat++; endY = *pfloat++; i += _commandSize_float[VLC_OP_SCCWARC_REL]; VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,FALSE,FALSE,TURE,&coords,(void *)&pathdata,&offset,path_length - i)); break; case VLC_OP_SCWARC: horRadius = *pfloat++; verRadius = *pfloat++; rotAngle = *pfloat++; endX = *pfloat++; endY = *pfloat++; i += _commandSize_float[VLC_OP_SCCWARC_REL]; VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,TURE,FALSE,FALSE,&coords,(void *)&pathdata,&offset,path_length - i)); break; case VLC_OP_SCWARC_REL: horRadius = *pfloat++; verRadius = *pfloat++; rotAngle = *pfloat++; endX = *pfloat++; endY = *pfloat++; i += _commandSize_float[VLC_OP_SCCWARC_REL]; VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,TURE,FALSE,TURE,&coords,(void *)&pathdata,&offset,path_length - i)); break; case VLC_OP_LCCWARC: horRadius = *pfloat++; verRadius = *pfloat++; rotAngle = *pfloat++; endX = *pfloat++; endY = *pfloat++; i += _commandSize_float[VLC_OP_SCCWARC_REL]; VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,FALSE,TURE,FALSE,&coords,(void *)&pathdata,&offset,path_length - i)); break; case VLC_OP_LCCWARC_REL: horRadius = *pfloat++; verRadius = *pfloat++; rotAngle = *pfloat++; endX = *pfloat++; endY = *pfloat++; i += _commandSize_float[VLC_OP_SCCWARC_REL]; VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,FALSE,TURE,TURE,&coords,(void *)&pathdata,&offset,path_length - i)); break; case VLC_OP_LCWARC: horRadius = *pfloat++; verRadius = *pfloat++; rotAngle = *pfloat++; endX = *pfloat++; endY = *pfloat++; i += _commandSize_float[VLC_OP_SCCWARC_REL]; VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,TURE,TURE,FALSE,&coords,(void *)&pathdata,&offset,path_length - i)); break; case VLC_OP_LCWARC_REL: horRadius = *pfloat++; verRadius = *pfloat++; rotAngle = *pfloat++; endX = *pfloat++; endY = *pfloat++; i += _commandSize_float[VLC_OP_SCCWARC_REL]; VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,TURE,TURE,TURE,&coords,(void *)&pathdata,&offset,path_length - i)); break; default: break; } } path->format = data_format; path->quality = quality; path->bounding_box[0] = min_x; path->bounding_box[1] = min_y; path->bounding_box[2] = max_x; path->bounding_box[3] = max_y; path->path_length = offset; path->path = pathdata; path->pdata_internal = 1; path->path_changed = 1; path->uploaded.address = 0; path->uploaded.bytes = 0; path->uploaded.handle = NULL; path->uploaded.memory = NULL; return VG_LITE_SUCCESS; ErrorHandler: vg_lite_os_free(pathdata); pathdata = NULL; return error; } vg_lite_error_t vg_lite_init_path(vg_lite_path_t * path, vg_lite_format_t data_format, vg_lite_quality_t quality, uint32_t path_length, void * path_data, vg_lite_float_t min_x, vg_lite_float_t min_y, vg_lite_float_t max_x, vg_lite_float_t max_y) { if(path == NULL) return VG_LITE_INVALID_ARGUMENT; memset(path, 0, sizeof(*path)); path->format = data_format; path->quality = quality; path->bounding_box[0] = min_x; path->bounding_box[1] = min_y; path->bounding_box[2] = max_x; path->bounding_box[3] = max_y; path->path_length = path_length; path->path = path_data; path->path_changed = 1; path->uploaded.address = 0; path->uploaded.bytes = 0; path->uploaded.handle = NULL; path->uploaded.memory = NULL; path->uploaded.property = 0; path->pdata_internal = 0; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_clear_path(vg_lite_path_t * path) { vg_lite_error_t error; if (path->uploaded.handle != NULL) { vg_lite_kernel_free_t free_cmd; free_cmd.memory_handle = path->uploaded.handle; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &free_cmd)); } path->uploaded.address = 0; path->uploaded.bytes = 0; path->uploaded.handle = NULL; path->uploaded.memory = NULL; if(path->pdata_internal == 1 && path->path != NULL){ vg_lite_os_free(path->path); } path->path = NULL; if(path->stroke_path_data) { vg_lite_os_free(path->stroke_path_data); path->stroke_path_data = NULL; } if (path->stroke_conversion) { if(path->stroke_conversion->path_point_list) { vg_lite_path_point_ptr temp_point; while(path->stroke_conversion->path_point_list) { temp_point = path->stroke_conversion->path_point_list->next; vg_lite_os_free(path->stroke_conversion->path_point_list); path->stroke_conversion->path_point_list = temp_point; } temp_point = NULL; } if(path->stroke_conversion->stroke_sub_path_list) { vg_lite_sub_path_ptr temp_sub_path; while(path->stroke_conversion->stroke_sub_path_list) { temp_sub_path = path->stroke_conversion->stroke_sub_path_list->next; if(path->stroke_conversion->stroke_sub_path_list->point_list) { vg_lite_path_point_ptr temp_point; while(path->stroke_conversion->stroke_sub_path_list->point_list) { temp_point = path->stroke_conversion->stroke_sub_path_list->point_list->next; vg_lite_os_free(path->stroke_conversion->stroke_sub_path_list->point_list); path->stroke_conversion->stroke_sub_path_list->point_list = temp_point; } temp_point = NULL; } vg_lite_os_free(path->stroke_conversion->stroke_sub_path_list); path->stroke_conversion->stroke_sub_path_list = temp_sub_path; } temp_sub_path = NULL; } vg_lite_os_free(path->stroke_conversion); path->stroke_conversion = NULL; } return VG_LITE_SUCCESS; } #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_error_t vg_lite_set_CLUT(uint32_t count, uint32_t * colors) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t addr = 0x0B00; if(!s_context.s_ftable.ftable[gcFEATURE_BIT_VG_IM_INDEX_FORMAT]) return VG_LITE_NOT_SUPPORT; switch (count) { case 256: addr = 0x0B00; break; case 16: addr = 0x0AA0; break; case 4: addr = 0x0A9C; break; case 2: addr = 0x0A98; break; default: error = VG_LITE_INVALID_ARGUMENT; return error; break; } VG_LITE_RETURN_ERROR(push_states(&s_context, addr, count, colors)); return error; } #else vg_lite_error_t vg_lite_set_CLUT(uint32_t count, uint32_t * colors) { vg_lite_tls_t* tls; vg_lite_error_t error = VG_LITE_SUCCESS; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; if(!tls->t_context.s_ftable.ftable[gcFEATURE_BIT_VG_IM_INDEX_FORMAT]) return VG_LITE_NOT_SUPPORT; switch (count) { case 2: tls->t_context.clut_dirty[0] = 1; tls->t_context.clut_used[0] = 0; if(!tls->t_context.colors[0]) tls->t_context.colors[0] = (uint32_t *)malloc(count * sizeof(uint32_t)); memcpy(tls->t_context.colors[0], colors, count * sizeof(uint32_t)); break; case 4: tls->t_context.clut_dirty[1] = 1; tls->t_context.clut_used[1] = 0; if(!tls->t_context.colors[1]) tls->t_context.colors[1] = (uint32_t *)malloc(count * sizeof(uint32_t)); memcpy(tls->t_context.colors[1], colors, count * sizeof(uint32_t)); break; case 16: tls->t_context.clut_dirty[2] = 1; tls->t_context.clut_used[2] = 0; if(!tls->t_context.colors[2]) tls->t_context.colors[2] = (uint32_t *)malloc(count * sizeof(uint32_t)); memcpy(tls->t_context.colors[2], colors, count * sizeof(uint32_t)); break; case 256: tls->t_context.clut_dirty[3] = 1; tls->t_context.clut_used[3] = 0; if(!tls->t_context.colors[3]) tls->t_context.colors[3] = (uint32_t *)malloc(count * sizeof(uint32_t)); memcpy(tls->t_context.colors[3], colors, count * sizeof(uint32_t)); break; default: error = VG_LITE_INVALID_ARGUMENT; return error; break; } return error; } #endif /* VG_DRIVER_SINGLE_THREAD */ vg_lite_error_t vg_lite_draw_pattern(vg_lite_buffer_t * target, vg_lite_path_t * path, vg_lite_fill_t fill_rule, vg_lite_matrix_t * matrix0, vg_lite_buffer_t * source, vg_lite_matrix_t * matrix1, vg_lite_blend_t blend, vg_lite_pattern_mode_t pattern_mode, vg_lite_color_t pattern_color, vg_lite_filter_t filter) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t imageMode; uint32_t blend_mode; uint32_t conversion = 0; uint32_t tiled_source; vg_lite_matrix_t * matrix = matrix1; uint32_t pattern_tile = 0; uint32_t transparency_mode = 0; int32_t dst_align_width; uint32_t mul, div, align; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t *tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ if(!path) return VG_LITE_INVALID_ARGUMENT; if(!path->path_length) return VG_LITE_SUCCESS; if(!path->path) return VG_LITE_INVALID_ARGUMENT; /* The following code is from "draw path" */ uint32_t format, quality, tiling, fill; uint32_t tessellation_size; #if DUMP_COMMAND vg_lite_kernel_allocate_t memory; uint32_t return_offset = 0; #endif vg_lite_point_t point_min = {0}, point_max = {0}, temp = {0}; int x, y, width, height; uint8_t ts_is_fullscreen = 0; if(!vg_lite_query_feature(gcFEATURE_BIT_VG_QUALITY_8X) && path->quality == VG_LITE_UPPER){ return VG_LITE_NOT_SUPPORT; } if(source->format == VG_LITE_A4 || source->format == VG_LITE_A8) { return VG_LITE_NOT_SUPPORT; } error = set_render_target(target); if (error != VG_LITE_SUCCESS) { return error; } else if (error == VG_LITE_NO_CONTEXT) { /* If scissoring is enabled and no valid scissoring rectangles are present, no drawing occurs */ return VG_LITE_SUCCESS; } transparency_mode = (source->transparency_mode == VG_LITE_IMAGE_TRANSPARENT ? 0x8000:0); width = ctx->tsbuffer.tessellation_width_height & 0xFFFF; height = ctx->tsbuffer.tessellation_width_height >> 16; get_format_bytes(target->format, &mul, &div, &align); dst_align_width = target->stride * div / mul; if(width == 0 || height == 0) return VG_LITE_NO_CONTEXT; if ((dst_align_width <= width) && (target->height <= height)) { ts_is_fullscreen = 1; point_min.x = 0; point_min.y = 0; point_max.x = dst_align_width; point_max.y = target->height; } /* If target is L8 and source is in YUV or RGB (not L8 or A8) then we have to convert RGB into L8. */ if ((target->format == VG_LITE_L8) && ((source->format != VG_LITE_L8) && (source->format != VG_LITE_A8))) { conversion = 0x80000000; } /* Determine image mode (NORMAL or MULTIPLY) depending on the color. */ imageMode = (source->image_mode == VG_LITE_NONE_IMAGE_MODE) ? 0 : (source->image_mode == VG_LITE_MULTIPLY_IMAGE_MODE) ? 0x00002000 : 0x00001000; tiled_source = (source->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0 ; if (pattern_mode == VG_LITE_PATTERN_COLOR) { uint8_t a,r,g,b; pattern_tile = 0; a = pattern_color >> 24; r = pattern_color >> 16; g = pattern_color >> 8; b = pattern_color; pattern_color = (a << 24) | (b << 16) | (g << 8) | r; } else if (pattern_mode == VG_LITE_PATTERN_PAD) { pattern_tile = 0x1000; } else { return VG_LITE_INVALID_ARGUMENT; } #if !defined(VG_DRIVER_SINGLE_THREAD) if(ctx->ts_dirty){ memcpy(CMDBUF_BUFFER(*ctx) + CMDBUF_OFFSET(*ctx), ctx->ts_record, 80); CMDBUF_OFFSET(*ctx) += 80; ctx->ts_dirty = 0; ctx->ts_init_used = 1; } else { ctx->ts_init_use = 1; } /* Setup the command buffer. */ if(source->format >= VG_LITE_INDEX_1 && source->format <= VG_LITE_INDEX_8) { /* this task will use index format,set index_flag to 1. */ ctx->index_format = 1; switch (source->format) { case VG_LITE_INDEX_8: if(ctx->clut_dirty[3]){ VG_LITE_RETURN_ERROR(push_states(ctx, 0x0B00, 256, ctx->colors[3])); ctx->clut_dirty[3] = 0; } else { ctx->clut_used[3] = 1; } break; case VG_LITE_INDEX_4: if(ctx->clut_dirty[2]){ VG_LITE_RETURN_ERROR(push_states(ctx, 0x0AA0, 16, ctx->colors[2])); ctx->clut_dirty[2] = 0; } else { ctx->clut_used[2] = 1; } break; case VG_LITE_INDEX_2: if(ctx->clut_dirty[1]){ VG_LITE_RETURN_ERROR(push_states(ctx, 0x0A9C, 4, ctx->colors[1])); ctx->clut_dirty[1] = 0; } else { ctx->clut_used[1] = 1; } break; default: if(ctx->clut_dirty[0]){ VG_LITE_RETURN_ERROR(push_states(ctx, 0x0A98, 2, ctx->colors[0])); ctx->clut_dirty[0] = 0; } else { ctx->clut_used[0] = 1; } } } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ VG_LITE_RETURN_ERROR(set_interpolation_steps(target, source->width, source->height, matrix)); if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { if(source->transparency_mode == VG_LITE_IMAGE_OPAQUE){ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | pattern_tile | conversion | 0x01000100)); } else { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | pattern_tile | conversion | 0x00000100)); } } else { /* enable pre-multiplied in imager unit */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | pattern_tile | conversion)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A27, pattern_color)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A29, source->address)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2B, source->stride | tiled_source)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2D, 0)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2F, source->width | (source->height << 16))); /* Work on path states. */ matrix = matrix0; if (ts_is_fullscreen == 0){ transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[1], matrix); point_min = point_max = temp; transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[1], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[3], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[3], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; point_min.x = MAX(point_min.x, 0); point_min.y = MAX(point_min.y, 0); point_max.x = MIN(point_max.x, dst_align_width); point_max.y = MIN(point_max.y, target->height); } if (ctx->scissor_enabled) { point_min.x = MAX(point_min.x, ctx->scissor[0]); point_min.y = MAX(point_min.y, ctx->scissor[1]); point_max.x = MIN(point_max.x, ctx->scissor[0] + ctx->scissor[2]); point_max.y = MIN(point_max.y, ctx->scissor[1] + ctx->scissor[3]); } /* Convert states into hardware values. */ blend_mode = convert_blend(blend); format = convert_path_format(path->format); quality = convert_path_quality(path->quality); tiling = (ctx->capabilities.cap.tiled == 2) ? 0x2000000 : 0; fill = (fill_rule == VG_LITE_FILL_EVEN_ODD) ? 0x10 : 0; tessellation_size = ( ctx->tsbuffer.tessellation_buffer_size[2] ? ctx->tsbuffer.tessellation_buffer_size[2] : ctx->tsbuffer.tessellation_buffer_size[1] ); /* Setup the command buffer. */ /* Program color register. */ if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x10000000 | ctx->capabilities.cap.tiled | 0x00000002 | imageMode | blend_mode | transparency_mode)); } else { /* enable pre-multiplied from VG to VGPE */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, ctx->capabilities.cap.tiled | 0x00000002 | imageMode | blend_mode | transparency_mode)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000400 | format | quality | tiling | fill)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3B, 0x3F800000)); /* Path tessellation SCALE. */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3C, 0x00000000)); /* Path tessellation BIAS. */ /* Program matrix. */ VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A40, (void *) &matrix->m[0][0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A41, (void *) &matrix->m[0][1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A42, (void *) &matrix->m[0][2])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A43, (void *) &matrix->m[1][0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A44, (void *) &matrix->m[1][1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A45, (void *) &matrix->m[1][2])); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { vglitemDUMP_BUFFER("path", path->uploaded.address, (uint8_t *)(path->uploaded.memory), 0, path->uploaded.bytes); } vglitemDUMP("@[memory 0x%08X 0x%08X]", ctx->tsbuffer.tessellation_buffer_gpu[0], ctx->tsbuffer.tessellation_buffer_size[0]); /* Setup tessellation loop. */ if((path->path_type & 0x1) == VG_LITE_DRAW_FILL_PATH) { for (y = point_min.y; y < point_max.y; y += height) { for (x = point_min.x; x < point_max.x; x += width) { /* Tessellate path. */ VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); #if (DUMP_COMMAND) if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[0], 0); unsigned char* pt = (unsigned char*) memory.memory; for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) { if (i % 8 == 0) fprintf(fp, "Command buffer: "); if (i % 4 == 0) fprintf(fp, "0x"); for (int j = 3; j >= 0; --j) fprintf(fp, "%02x", pt[i + j]); if ((i / 4 + 1) % 2 == 0) fprintf(fp, ",\n"); else fprintf(fp, ", "); } fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[return_offset], 0); fclose(fp); fp = NULL; #endif } else { push_data(ctx, path->path_length, path->path); } } } } /* Setup tessellation loop. */ if(path->path_type == VG_LITE_DRAW_STROKE_PATH || path->path_type == VG_LITE_DRAW_FILL_STROKE_PATH) { for (y = point_min.y; y < point_max.y; y += height) { for (x = point_min.x; x < point_max.x; x += width) { /* Tessellate path. */ VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); #if (DUMP_COMMAND) if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[0], 0); unsigned char* pt = (unsigned char*) memory.memory; for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) { if (i % 8 == 0) fprintf(fp, "Command buffer: "); if (i % 4 == 0) fprintf(fp, "0x"); for (int j = 3; j >= 0; --j) fprintf(fp, "%02x", pt[i + j]); if ((i / 4 + 1) % 2 == 0) fprintf(fp, ",\n"); else fprintf(fp, ", "); } fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[return_offset], 0); fclose(fp); fp = NULL; #endif } else { format = convert_path_format(VG_LITE_FP32); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000200 | format | quality | tiling | 0x0)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, path->stroke_color)); push_data(ctx, path->stroke_path_size, path->stroke_path_data); } } } } /* Finialize command buffer. */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0)); VG_LITE_RETURN_ERROR(flush_target()); vglitemDUMP_BUFFER("image", source->address, source->memory, 0, (source->stride)*(source->height)); #if DUMP_IMAGE dump_img(source->memory, source->width, source->height, source->format); #endif #if !defined(VG_DRIVER_SINGLE_THREAD) tls->t_context.ts_init = 1; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ return error; } vg_lite_error_t vg_lite_draw_linear_gradient(vg_lite_buffer_t * target, vg_lite_path_t * path, vg_lite_fill_t fill_rule, vg_lite_matrix_t * path_matrix, vg_lite_linear_gradient_ext_t *grad, vg_lite_color_t paint_color, vg_lite_blend_t blend, vg_lite_filter_t filter) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t image_mode; uint32_t blend_mode; uint32_t conversion = 0; uint32_t tiled_source; int32_t dst_align_width; uint32_t mul, div, align; vg_lite_matrix_t inverse_matrix; vg_lite_buffer_t * source = &grad->image; vg_lite_matrix_t * matrix = &grad->matrix; uint32_t linear_tile = 0; uint32_t transparency_mode = 0; void *data; /* The following code is from "draw path" */ uint32_t format, quality, tiling, fill; uint32_t tessellation_size; vg_lite_kernel_allocate_t memory; vg_lite_kernel_free_t free_memory; uint32_t return_offset = 0; vg_lite_point_t point_min = {0}, point_max = {0}, temp = {0}; int x, y, width, height; uint8_t ts_is_fullscreen = 0; vg_lite_float_t dx, dy, dxdx_dydy; vg_lite_float_t lg_step_x_lin, lg_step_y_lin, lg_constant_lin; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if (tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ if(!path) return VG_LITE_INVALID_ARGUMENT; if(!path->path_length) return VG_LITE_SUCCESS; if(!path->path) return VG_LITE_INVALID_ARGUMENT; if(!vg_lite_query_feature(gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT)) return VG_LITE_NOT_SUPPORT; if(!vg_lite_query_feature(gcFEATURE_BIT_VG_QUALITY_8X) && path->quality == VG_LITE_UPPER){ return VG_LITE_NOT_SUPPORT; } if(source->format == VG_LITE_A4 || source->format == VG_LITE_A8) { return VG_LITE_NOT_SUPPORT; } error = set_render_target(target); if (error != VG_LITE_SUCCESS) { return error; } else if (error == VG_LITE_NO_CONTEXT) { /* If scissoring is enabled and no valid scissoring rectangles are present, no drawing occurs */ return VG_LITE_SUCCESS; } transparency_mode = (source->transparency_mode == VG_LITE_IMAGE_TRANSPARENT ? 0x8000:0); width = ctx->tsbuffer.tessellation_width_height & 0xFFFF; height = ctx->tsbuffer.tessellation_width_height >> 16; get_format_bytes(target->format, &mul, &div, &align); dst_align_width = target->stride * div / mul; if(width == 0 || height == 0) return VG_LITE_NO_CONTEXT; if ((dst_align_width <= width) && (target->height <= height)) { ts_is_fullscreen = 1; point_min.x = 0; point_min.y = 0; point_max.x = dst_align_width; point_max.y = target->height; } /* If target is L8 and source is in YUV or RGB (not L8 or A8) then we have to convert RGB into L8. */ if ((target->format == VG_LITE_L8) && ((source->format != VG_LITE_L8) && (source->format != VG_LITE_A8))) { conversion = 0x80000000; } /* Determine image mode (NORMAL or MULTIPLY) depending on the color. */ image_mode = (source->image_mode == VG_LITE_NONE_IMAGE_MODE) ? 0 : (source->image_mode == VG_LITE_MULTIPLY_IMAGE_MODE) ? 0x00002000 : 0x00001000; tiled_source = (source->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0 ; linear_tile = (grad->spread_mode == VG_LITE_RADIAL_GRADIENT_SPREAD_FILL) ? 0 : (grad->spread_mode == VG_LITE_RADIAL_GRADIENT_SPREAD_PAD) ? 0x1000 : (grad->spread_mode == VG_LITE_RADIAL_GRADIENT_SPREAD_REPEAT) ? 0x2000 : 0x3000; if (grad->spread_mode == VG_LITE_RADIAL_GRADIENT_SPREAD_FILL) { uint8_t a,r,g,b; a = paint_color >> 24; r = paint_color >> 16; g = paint_color >> 8; b = paint_color; paint_color = (a << 24) | (b << 16) | (g << 8) | r; } /* compute radial gradient paremeters */ if (!inverse(&inverse_matrix, matrix)) return VG_LITE_INVALID_ARGUMENT; dx = grad->linear_gradient.X1 - grad->linear_gradient.X0; dy = grad->linear_gradient.Y1 - grad->linear_gradient.Y0; dxdx_dydy = dx * dx + dy * dy; /* ** dx (T(x) - x0) + dy (T(y) - y0) ** g = ------------------------------- ** dx^2 + dy^2 ** ** where ** ** dx := x1 - x0 ** dy := y1 - y1 ** T(x) := (x + 0.5) m00 + (y + 0.5) m01 + m02 ** = x m00 + y m01 + 0.5 (m00 + m01) + m02 ** T(y) := (x + 0.5) m10 + (y + 0.5) m11 + m12 ** = x m10 + y m11 + 0.5 (m10 + m11) + m12. ** ** We can factor the top line into: ** ** = dx (x m00 + y m01 + 0.5 (m00 + m01) + m02 - x0) ** + dy (x m10 + y m11 + 0.5 (m10 + m11) + m12 - y0) ** ** = x (dx m00 + dy m10) ** + y (dx m01 + dy m11) ** + dx (0.5 (m00 + m01) + m02 - x0) ** + dy (0.5 (m10 + m11) + m12 - y0). */ lg_step_x_lin = (dx * MAT(&inverse_matrix, 0, 0) + dy * MAT(&inverse_matrix, 1, 0)) / dxdx_dydy; lg_step_y_lin = (dx * MAT(&inverse_matrix, 0, 1) + dy * MAT(&inverse_matrix, 1, 1)) / dxdx_dydy; lg_constant_lin = ( ( 0.5f * ( MAT(&inverse_matrix, 0, 0) + MAT(&inverse_matrix, 0, 1) ) + MAT(&inverse_matrix, 0, 2) - grad->linear_gradient.X0 ) * dx + ( 0.5f * ( MAT(&inverse_matrix, 1, 0) + MAT(&inverse_matrix, 1, 1) ) + MAT(&inverse_matrix, 1, 2) - grad->linear_gradient.Y0 ) * dy ) / dxdx_dydy; #if !defined(VG_DRIVER_SINGLE_THREAD) if(ctx->ts_dirty){ memcpy(CMDBUF_BUFFER(*ctx) + CMDBUF_OFFSET(*ctx), ctx->ts_record, 80); CMDBUF_OFFSET(*ctx) += 80; ctx->ts_dirty = 0; ctx->ts_init_used = 1; } else { ctx->ts_init_use = 1; } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ /* Setup the command buffer. */ /* linear gradient parameters*/ data = &lg_constant_lin; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A04,*(uint32_t*) data)); data = &lg_step_x_lin; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A06,*(uint32_t*) data)); data = &lg_step_y_lin; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A08,*(uint32_t*) data)); VG_LITE_RETURN_ERROR(set_interpolation_steps(target, source->width, source->height, matrix)); if(!ctx->premultiply_enabled) { if(source->transparency_mode == VG_LITE_IMAGE_OPAQUE){ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | filter | linear_tile | conversion | 0x01000100)); } else { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | filter | linear_tile | conversion | 0x00000100)); } } else { /* enable pre-multiplied in imager unit */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | filter | linear_tile | conversion)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A26, paint_color)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A28, source->address)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2A, tiled_source)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2C, 0)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2E, source->width)); /* Work on path states. */ matrix = path_matrix; if (ts_is_fullscreen == 0){ transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[1], matrix); point_min = point_max = temp; transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[1], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[3], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[3], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; point_min.x = MAX(point_min.x, 0); point_min.y = MAX(point_min.y, 0); point_max.x = MIN(point_max.x, dst_align_width); point_max.y = MIN(point_max.y, target->height); } if (ctx->scissor_enabled) { point_min.x = MAX(point_min.x, ctx->scissor[0]); point_min.y = MAX(point_min.y, ctx->scissor[1]); point_max.x = MIN(point_max.x, ctx->scissor[0] + ctx->scissor[2]); point_max.y = MIN(point_max.y, ctx->scissor[1] + ctx->scissor[3]); } /* Convert states into hardware values. */ blend_mode = convert_blend(blend); format = convert_path_format(path->format); quality = convert_path_quality(path->quality); tiling = (ctx->capabilities.cap.tiled == 2) ? 0x2000000 : 0; fill = (fill_rule == VG_LITE_FILL_EVEN_ODD) ? 0x10 : 0; tessellation_size = ( ctx->tsbuffer.tessellation_buffer_size[2] ? ctx->tsbuffer.tessellation_buffer_size[2] : ctx->tsbuffer.tessellation_buffer_size[1] ); /* Setup the command buffer. */ /* Program color register. */ if(!ctx->premultiply_enabled) { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x11000000 | ctx->capabilities.cap.tiled | 0x00000002 | image_mode | blend_mode | transparency_mode)); } else { /* enable pre-multiplied from VG to VGPE */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x01000000 | ctx->capabilities.cap.tiled | 0x00000002 | image_mode | blend_mode | transparency_mode)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000400 | format | quality | tiling | fill)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3B, 0x3F800000)); /* Path tessellation SCALE. */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3C, 0x00000000)); /* Path tessellation BIAS. */ /* Program matrix. */ VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A40, (void *) &matrix->m[0][0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A41, (void *) &matrix->m[0][1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A42, (void *) &matrix->m[0][2])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A43, (void *) &matrix->m[1][0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A44, (void *) &matrix->m[1][1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A45, (void *) &matrix->m[1][2])); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { if (path->path_changed != 0) { if (path->uploaded.handle != NULL) { free_memory.memory_handle = path->uploaded.handle; vg_lite_kernel(VG_LITE_FREE, &free_memory); path->uploaded.address = 0; path->uploaded.memory = NULL; path->uploaded.handle = NULL; } /* Allocate memory for the path data. */ memory.bytes = 16 + VG_LITE_ALIGN(path->path_length, 8); return_offset = (8 + VG_LITE_ALIGN(path->path_length, 8)) / 4; memory.contiguous = 1; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &memory)); ((uint64_t *) memory.memory)[(path->path_length + 7) / 8] = 0; ((uint32_t *) memory.memory)[0] = VG_LITE_DATA((path->path_length + 7) / 8); ((uint32_t *) memory.memory)[1] = 0; memcpy((uint8_t *) memory.memory + 8, path->path, path->path_length); ((uint32_t *) memory.memory)[return_offset] = VG_LITE_RETURN(); ((uint32_t *) memory.memory)[return_offset + 1] = 0; path->uploaded.handle = memory.memory_handle; path->uploaded.memory = memory.memory; path->uploaded.address = memory.memory_gpu; path->uploaded.bytes = memory.bytes; path->path_changed = 0; } } if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { vglitemDUMP_BUFFER("path", path->uploaded.address, (uint8_t *)(path->uploaded.memory), 0, path->uploaded.bytes); } vglitemDUMP("@[memory 0x%08X 0x%08X]", ctx->tsbuffer.tessellation_buffer_gpu[0], ctx->tsbuffer.tessellation_buffer_size[0]); /* Setup tessellation loop. */ if((path->path_type & 0x1) == VG_LITE_DRAW_FILL_PATH) { for (y = point_min.y; y < point_max.y; y += height) { for (x = point_min.x; x < point_max.x; x += width) { /* Tessellate path. */ VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); #if (DUMP_COMMAND) if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[0], 0); unsigned char* pt = (unsigned char*) memory.memory; for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) { if (i % 8 == 0) fprintf(fp, "Command buffer: "); if (i % 4 == 0) fprintf(fp, "0x"); for (int j = 3; j >= 0; --j) fprintf(fp, "%02x", pt[i + j]); if ((i / 4 + 1) % 2 == 0) fprintf(fp, ",\n"); else fprintf(fp, ", "); } fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[return_offset], 0); fclose(fp); fp = NULL; #endif } else { push_data(ctx, path->path_length, path->path); } } } } /* Setup tessellation loop. */ if(path->path_type == VG_LITE_DRAW_STROKE_PATH || path->path_type == VG_LITE_DRAW_FILL_STROKE_PATH) { for (y = point_min.y; y < point_max.y; y += height) { for (x = point_min.x; x < point_max.x; x += width) { /* Tessellate path. */ VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); #if (DUMP_COMMAND) if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[0], 0); unsigned char* pt = (unsigned char*) memory.memory; for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) { if (i % 8 == 0) fprintf(fp, "Command buffer: "); if (i % 4 == 0) fprintf(fp, "0x"); for (int j = 3; j >= 0; --j) fprintf(fp, "%02x", pt[i + j]); if ((i / 4 + 1) % 2 == 0) fprintf(fp, ",\n"); else fprintf(fp, ", "); } fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[return_offset], 0); fclose(fp); fp = NULL; #endif } else { format = convert_path_format(VG_LITE_FP32); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000200 | format | quality | tiling | 0x0)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, path->stroke_color)); push_data(ctx, path->stroke_path_size, path->stroke_path_data); } } } } /* Finialize command buffer. */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0)); vglitemDUMP_BUFFER("image", source->address, source->memory, 0, (source->stride)*(source->height)); #if DUMP_IMAGE dump_img(source->memory, source->width, source->height, source->format); #endif #if !defined(VG_DRIVER_SINGLE_THREAD) tls->t_context.ts_init = 1; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ return error; } vg_lite_error_t vg_lite_draw_radial_gradient(vg_lite_buffer_t * target, vg_lite_path_t * path, vg_lite_fill_t fill_rule, vg_lite_matrix_t * path_matrix, vg_lite_radial_gradient_t *grad, vg_lite_color_t paint_color, vg_lite_blend_t blend, vg_lite_filter_t filter) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t imageMode; uint32_t blend_mode; uint32_t conversion = 0; uint32_t tiled_source; int32_t dst_align_width; uint32_t mul, div, align; vg_lite_matrix_t inverse_matrix; vg_lite_buffer_t * source = &grad->image; vg_lite_matrix_t * matrix = &grad->matrix; uint32_t rad_tile = 0; uint32_t transparency_mode = 0; void *data; /* The following code is from "draw path" */ uint32_t format, quality, tiling, fill; uint32_t tessellation_size; vg_lite_kernel_allocate_t memory; vg_lite_kernel_free_t free_memory; uint32_t return_offset = 0; vg_lite_point_t point_min = {0}, point_max = {0}, temp = {0}; int x, y, width, height; uint8_t ts_is_fullscreen = 0; vg_lite_float_t radius; vg_lite_float_t centerX, centerY; vg_lite_float_t focalX, focalY; vg_lite_float_t fx, fy; vg_lite_float_t fxfy_2; vg_lite_float_t radius2; vg_lite_float_t r2_fx2, r2_fy2; vg_lite_float_t r2_fx2_2, r2_fy2_2; vg_lite_float_t r2_fx2_fy2; vg_lite_float_t r2_fx2_fy2sq; vg_lite_float_t cx, cy; vg_lite_float_t rgConstantLin, rgStepXLin, rgStepYLin; vg_lite_float_t rgConstantRad, rgStepXRad, rgStepYRad; vg_lite_float_t rgStepXXRad, rgStepYYRad, rgStepXYRad; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ if(!path) return VG_LITE_INVALID_ARGUMENT; if(!path->path_length) return VG_LITE_SUCCESS; if(!path->path) return VG_LITE_INVALID_ARGUMENT; if(!vg_lite_query_feature(gcFEATURE_BIT_VG_RADIAL_GRADIENT)) return VG_LITE_NOT_SUPPORT; if(!vg_lite_query_feature(gcFEATURE_BIT_VG_QUALITY_8X) && path->quality == VG_LITE_UPPER){ return VG_LITE_NOT_SUPPORT; } if(source->format == VG_LITE_A4 || source->format == VG_LITE_A8) { return VG_LITE_NOT_SUPPORT; } radius = grad->radialGradient.r; if(radius <= 0) return VG_LITE_INVALID_ARGUMENT; error = set_render_target(target); if (error != VG_LITE_SUCCESS) { return error; } else if (error == VG_LITE_NO_CONTEXT) { /* If scissoring is enabled and no valid scissoring rectangles are present, no drawing occurs */ return VG_LITE_SUCCESS; } transparency_mode = (source->transparency_mode == VG_LITE_IMAGE_TRANSPARENT ? 0x8000:0); width = ctx->tsbuffer.tessellation_width_height & 0xFFFF; height = ctx->tsbuffer.tessellation_width_height >> 16; get_format_bytes(target->format, &mul, &div, &align); dst_align_width = target->stride * div / mul; if(width == 0 || height == 0) return VG_LITE_NO_CONTEXT; if ((dst_align_width <= width) && (target->height <= height)) { ts_is_fullscreen = 1; point_min.x = 0; point_min.y = 0; point_max.x = dst_align_width; point_max.y = target->height; } /* If target is L8 and source is in YUV or RGB (not L8 or A8) then we have to convert RGB into L8. */ if ((target->format == VG_LITE_L8) && ((source->format != VG_LITE_L8) && (source->format != VG_LITE_A8))) { conversion = 0x80000000; } /* Determine image mode (NORMAL or MULTIPLY) depending on the color. */ imageMode = (source->image_mode == VG_LITE_NONE_IMAGE_MODE) ? 0 : (source->image_mode == VG_LITE_MULTIPLY_IMAGE_MODE) ? 0x00002000 : 0x00001000; tiled_source = (source->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0 ; rad_tile = (grad->SpreadMode == VG_LITE_RADIAL_GRADIENT_SPREAD_FILL) ? 0 : (grad->SpreadMode == VG_LITE_RADIAL_GRADIENT_SPREAD_PAD) ? 0x1000 : (grad->SpreadMode == VG_LITE_RADIAL_GRADIENT_SPREAD_REPEAT) ? 0x2000 : 0x3000; if (grad->SpreadMode == VG_LITE_RADIAL_GRADIENT_SPREAD_FILL) { uint8_t a,r,g,b; a = paint_color >> 24; r = paint_color >> 16; g = paint_color >> 8; b = paint_color; paint_color = (a << 24) | (b << 16) | (g << 8) | r; } /* compute radial gradient paremeters */ /* Compute inverse matrix. */ if (!inverse(&inverse_matrix, matrix)) return VG_LITE_INVALID_ARGUMENT; /* Make shortcuts to the gradient information. */ centerX = grad->radialGradient.cx; centerY = grad->radialGradient.cy; focalX = grad->radialGradient.fx; focalY = grad->radialGradient.fy; /* Compute constants of the equation. */ fx = focalX - centerX; fy = focalY - centerY; radius2 = radius * radius; if (fx*fx + fy*fy > radius2) { /* If the focal point is outside the circle, let's move it to inside the circle. Per vg11 spec pg125 "If (fx, fy) lies outside ... For here, we set it at 0.9 ratio to the center. */ vg_lite_float_t fr = (vg_lite_float_t)sqrt(fx*fx + fy*fy); fx = radius * fx / fr * 0.9f; fy = radius * fy / fr * 0.9f; focalX = grad->radialGradient.fx + fx; focalY = grad->radialGradient.fy + fy; } fxfy_2 = 2.0f * fx * fy; r2_fx2 = radius2 - fx * fx; r2_fy2 = radius2 - fy * fy; r2_fx2_2 = 2.0f * r2_fx2; r2_fy2_2 = 2.0f * r2_fy2; r2_fx2_fy2 = r2_fx2 - fy * fy; r2_fx2_fy2sq = r2_fx2_fy2 * r2_fx2_fy2; /* _____________________________________ ** dx fx + dy fy + \/r^2 (dx^2 + dy^2) - (dx fy - dy fx)^2 ** g = ------------------------------------------------------- ** r^2 - fx^2 - fy^2 ** ** Where ** ** dx := F(x) - focalX ** dy := F(y) - focalY ** fx := focalX - centerX ** fy := focalX - centerY ** ** and ** ** F(x) := (x + 0.5) m00 + (y + 0.5) m01 + m02 ** F(y) := (x + 0.5) m10 + (y + 0.5) m11 + m12 ** ** So, dx can be factored into ** ** dx = (x + 0.5) m00 + (y + 0.5) m01 + m02 - focalX ** = x m00 + y m01 + 0.5 m00 + 0.5 m01 + m02 - focalX ** ** = x m00 + y m01 + cx ** ** where ** ** cx := 0.5 m00 + 0.5 m01 + m02 - focalX ** ** The same way we can factor dy into ** ** dy = x m10 + y m11 + cy ** ** where ** ** cy := 0.5 m10 + 0.5 m11 + m12 - focalY. ** ** Now we can rewrite g as ** ______________________________________ ** dx fx + dy fy / r^2 (dx^2 + dy^2) - (dx fy - dy fx)^2 ** g = ----------------- + \ / ------------------------------------- ** r^2 - fx^2 - fy^2 \/ (r^2 - fx^2 - fy^2)^2 ** ____ ** = gLin + \/gRad ** ** where ** ** dx fx + dy fy ** gLin := ----------------- ** r^2 - fx^2 - fy^2 ** ** r^2 (dx^2 + dy^2) - (dx fy - dy fx)^2 ** gRad := ------------------------------------- ** (r^2 - fx^2 - fy^2)^2 */ cx = 0.5f * ( MAT(&inverse_matrix, 0, 0) + MAT(&inverse_matrix, 0, 1) ) + MAT(&inverse_matrix, 0, 2) - focalX; cy = 0.5f * ( MAT(&inverse_matrix, 1, 0) + MAT(&inverse_matrix, 1, 1) ) + MAT(&inverse_matrix, 1, 2) - focalY; /* ** dx fx + dy fy ** gLin := ----------------- ** r^2 - fx^2 - fy^2 ** ** We can factor the top half into ** ** = (x m00 + y m01 + cx) fx + (x m10 + y m11 + cy) fy ** ** = x (m00 fx + m10 fy) ** + y (m01 fx + m11 fy) ** + cx fx + cy fy. */ rgStepXLin = ( MAT(&inverse_matrix, 0, 0) * fx + MAT(&inverse_matrix, 1, 0) * fy ) / r2_fx2_fy2; rgStepYLin = ( MAT(&inverse_matrix, 0, 1) * fx + MAT(&inverse_matrix, 1, 1) * fy ) / r2_fx2_fy2; rgConstantLin = ( cx * fx + cy * fy ) / r2_fx2_fy2; /* ** r^2 (dx^2 + dy^2) - (dx fy - dy fx)^2 ** gRad := ------------------------------------- ** (r^2 - fx^2 - fy^2)^2 ** ** r^2 (dx^2 + dy^2) - dx^2 fy^2 - dy^2 fx^2 + 2 dx dy fx fy ** := --------------------------------------------------------- ** (r^2 - fx^2 - fy^2)^2 ** ** dx^2 (r^2 - fy^2) + dy^2 (r^2 - fx^2) + 2 dx dy fx fy ** := ----------------------------------------------------- ** (r^2 - fx^2 - fy^2)^2 ** ** First, lets factor dx^2 into ** ** dx^2 = (x m00 + y m01 + cx)^2 ** = x^2 m00^2 + y^2 m01^2 + 2 x y m00 m01 ** + 2 x m00 cx + 2 y m01 cx + cx^2 ** ** = x^2 (m00^2) ** + y^2 (m01^2) ** + x y (2 m00 m01) ** + x (2 m00 cx) ** + y (2 m01 cx) ** + cx^2. ** ** The same can be done for dy^2: ** ** dy^2 = x^2 (m10^2) ** + y^2 (m11^2) ** + x y (2 m10 m11) ** + x (2 m10 cy) ** + y (2 m11 cy) ** + cy^2. ** ** Let's also factor dx dy into ** ** dx dy = (x m00 + y m01 + cx) (x m10 + y m11 + cy) ** = x^2 m00 m10 + y^2 m01 m11 + x y m00 m11 + x y m01 m10 ** + x m00 cy + x m10 cx + y m01 cy + y m11 cx + cx cy ** ** = x^2 (m00 m10) ** + y^2 (m01 m11) ** + x y (m00 m11 + m01 m10) ** + x (m00 cy + m10 cx) ** + y (m01 cy + m11 cx) ** + cx cy. ** ** Now that we have all this, lets look at the top of gRad. ** ** = dx^2 (r^2 - fy^2) + dy^2 (r^2 - fx^2) + 2 dx dy fx fy ** = x^2 m00^2 (r^2 - fy^2) + y^2 m01^2 (r^2 - fy^2) ** + x y 2 m00 m01 (r^2 - fy^2) + x 2 m00 cx (r^2 - fy^2) ** + y 2 m01 cx (r^2 - fy^2) + cx^2 (r^2 - fy^2) ** + x^2 m10^2 (r^2 - fx^2) + y^2 m11^2 (r^2 - fx^2) ** + x y 2 m10 m11 (r^2 - fx^2) + x 2 m10 cy (r^2 - fx^2) ** + y 2 m11 cy (r^2 - fx^2) + cy^2 (r^2 - fx^2) ** + x^2 m00 m10 2 fx fy + y^2 m01 m11 2 fx fy ** + x y (m00 m11 + m01 m10) 2 fx fy ** + x (m00 cy + m10 cx) 2 fx fy + y (m01 cy + m11 cx) 2 fx fy ** + cx cy 2 fx fy ** ** = x^2 ( m00^2 (r^2 - fy^2) ** + m10^2 (r^2 - fx^2) ** + m00 m10 2 fx fy ** ) ** + y^2 ( m01^2 (r^2 - fy^2) ** + m11^2 (r^2 - fx^2) ** + m01 m11 2 fx fy ** ) ** + x y ( 2 m00 m01 (r^2 - fy^2) ** + 2 m10 m11 (r^2 - fx^2) ** + (m00 m11 + m01 m10) 2 fx fy ** ) ** + x ( 2 m00 cx (r^2 - fy^2) ** + 2 m10 cy (r^2 - fx^2) ** + (m00 cy + m10 cx) 2 fx fy ** ) ** + y ( 2 m01 cx (r^2 - fy^2) ** + 2 m11 cy (r^2 - fx^2) ** + (m01 cy + m11 cx) 2 fx fy ** ) ** + cx^2 (r^2 - fy^2) + cy^2 (r^2 - fx^2) + cx cy 2 fx fy. */ rgStepXXRad = ( MAT(&inverse_matrix, 0, 0) * MAT(&inverse_matrix, 0, 0) * r2_fy2 + MAT(&inverse_matrix, 1, 0) * MAT(&inverse_matrix, 1, 0) * r2_fx2 + MAT(&inverse_matrix, 0, 0) * MAT(&inverse_matrix, 1, 0) * fxfy_2 ) / r2_fx2_fy2sq; rgStepYYRad = ( MAT(&inverse_matrix, 0, 1) * MAT(&inverse_matrix, 0, 1) * r2_fy2 + MAT(&inverse_matrix, 1, 1) * MAT(&inverse_matrix, 1, 1) * r2_fx2 + MAT(&inverse_matrix, 0, 1) * MAT(&inverse_matrix, 1, 1) * fxfy_2 ) / r2_fx2_fy2sq; rgStepXYRad = ( MAT(&inverse_matrix, 0, 0) * MAT(&inverse_matrix, 0, 1) * r2_fy2_2 + MAT(&inverse_matrix, 1, 0) * MAT(&inverse_matrix, 1, 1) * r2_fx2_2 + ( MAT(&inverse_matrix, 0, 0) * MAT(&inverse_matrix, 1, 1) + MAT(&inverse_matrix, 0, 1) * MAT(&inverse_matrix, 1, 0) ) * fxfy_2 ) / r2_fx2_fy2sq; rgStepXRad = ( MAT(&inverse_matrix, 0, 0) * cx * r2_fy2_2 + MAT(&inverse_matrix, 1, 0) * cy * r2_fx2_2 + ( MAT(&inverse_matrix, 0, 0) * cy + MAT(&inverse_matrix, 1, 0) * cx ) * fxfy_2 ) / r2_fx2_fy2sq; rgStepYRad = ( MAT(&inverse_matrix, 0, 1) * cx * r2_fy2_2 + MAT(&inverse_matrix, 1, 1) * cy * r2_fx2_2 + ( MAT(&inverse_matrix, 0, 1) * cy + MAT(&inverse_matrix, 1, 1) * cx ) * fxfy_2 ) / r2_fx2_fy2sq; rgConstantRad = ( cx * cx * r2_fy2 + cy * cy * r2_fx2 + cx * cy * fxfy_2 ) / r2_fx2_fy2sq; #if !defined(VG_DRIVER_SINGLE_THREAD) if(ctx->ts_dirty){ memcpy(CMDBUF_BUFFER(*ctx) + CMDBUF_OFFSET(*ctx), ctx->ts_record, 80); CMDBUF_OFFSET(*ctx) += 80; ctx->ts_dirty = 0; ctx->ts_init_used = 1; } else { ctx->ts_init_use = 1; } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ /* Setup the command buffer. */ /* rad gradient parameters*/ data = &rgConstantLin; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A04,*(uint32_t*) data)); data = &rgStepXLin; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A06,*(uint32_t*) data)); data = &rgStepYLin; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A08,*(uint32_t*) data)); data = &rgConstantRad; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A05,*(uint32_t*) data)); data = &rgStepXRad; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A07,*(uint32_t*) data)); data = &rgStepYRad; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A09,*(uint32_t*) data)); data = &rgStepXXRad; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A03,*(uint32_t*) data)); data = &rgStepYYRad; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A0A,*(uint32_t*) data)); data = &rgStepXYRad; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A0B,*(uint32_t*) data)); VG_LITE_RETURN_ERROR(set_interpolation_steps(target, source->width, source->height, matrix)); if(!ctx->premultiply_enabled) { if(source->transparency_mode == VG_LITE_IMAGE_OPAQUE){ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | filter | rad_tile | conversion | 0x01000100)); } else { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | filter | rad_tile | conversion | 0x00000100)); } } else { /* enable pre-multiplied in imager unit */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | filter | rad_tile | conversion)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A26, paint_color)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A28, source->address)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2A, tiled_source)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2C, 0)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2E, source->width)); /* Work on path states. */ matrix = path_matrix; if (ts_is_fullscreen == 0){ transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[1], matrix); point_min = point_max = temp; transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[1], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[3], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[3], matrix); if (temp.x < point_min.x) point_min.x = temp.x; if (temp.y < point_min.y) point_min.y = temp.y; if (temp.x > point_max.x) point_max.x = temp.x; if (temp.y > point_max.y) point_max.y = temp.y; point_min.x = MAX(point_min.x, 0); point_min.y = MAX(point_min.y, 0); point_max.x = MIN(point_max.x, dst_align_width); point_max.y = MIN(point_max.y, target->height); } if (ctx->scissor_enabled) { point_min.x = MAX(point_min.x, ctx->scissor[0]); point_min.y = MAX(point_min.y, ctx->scissor[1]); point_max.x = MIN(point_max.x, ctx->scissor[0] + ctx->scissor[2]); point_max.y = MIN(point_max.y, ctx->scissor[1] + ctx->scissor[3]); } /* Convert states into hardware values. */ blend_mode = convert_blend(blend); format = convert_path_format(path->format); quality = convert_path_quality(path->quality); tiling = (ctx->capabilities.cap.tiled == 2) ? 0x2000000 : 0; fill = (fill_rule == VG_LITE_FILL_EVEN_ODD) ? 0x10 : 0; tessellation_size = ( ctx->tsbuffer.tessellation_buffer_size[2] ? ctx->tsbuffer.tessellation_buffer_size[2] : ctx->tsbuffer.tessellation_buffer_size[1] ); /* Setup the command buffer. */ /* Program color register. */ if(!ctx->premultiply_enabled) { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x12000000 | ctx->capabilities.cap.tiled | 0x00000002 | imageMode | blend_mode | transparency_mode)); } else { /* enable pre-multiplied from VG to VGPE */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x02000000 | ctx->capabilities.cap.tiled | 0x00000002 | imageMode | blend_mode | transparency_mode)); } VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000400 | format | quality | tiling | fill)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3B, 0x3F800000)); /* Path tessellation SCALE. */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3C, 0x00000000)); /* Path tessellation BIAS. */ /* Program matrix. */ VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A40, (void *) &matrix->m[0][0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A41, (void *) &matrix->m[0][1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A42, (void *) &matrix->m[0][2])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A43, (void *) &matrix->m[1][0])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A44, (void *) &matrix->m[1][1])); VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A45, (void *) &matrix->m[1][2])); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { if (path->path_changed != 0) { if (path->uploaded.handle != NULL) { free_memory.memory_handle = path->uploaded.handle; vg_lite_kernel(VG_LITE_FREE, &free_memory); path->uploaded.address = 0; path->uploaded.memory = NULL; path->uploaded.handle = NULL; } /* Allocate memory for the path data. */ memory.bytes = 16 + VG_LITE_ALIGN(path->path_length, 8); return_offset = (8 + VG_LITE_ALIGN(path->path_length, 8)) / 4; memory.contiguous = 1; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &memory)); ((uint64_t *) memory.memory)[(path->path_length + 7) / 8] = 0; ((uint32_t *) memory.memory)[0] = VG_LITE_DATA((path->path_length + 7) / 8); ((uint32_t *) memory.memory)[1] = 0; memcpy((uint8_t *) memory.memory + 8, path->path, path->path_length); ((uint32_t *) memory.memory)[return_offset] = VG_LITE_RETURN(); ((uint32_t *) memory.memory)[return_offset + 1] = 0; path->uploaded.handle = memory.memory_handle; path->uploaded.memory = memory.memory; path->uploaded.address = memory.memory_gpu; path->uploaded.bytes = memory.bytes; path->path_changed = 0; } } if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { vglitemDUMP_BUFFER("path", path->uploaded.address, (uint8_t *)(path->uploaded.memory), 0, path->uploaded.bytes); } vglitemDUMP("@[memory 0x%08X 0x%08X]", ctx->tsbuffer.tessellation_buffer_gpu[0], ctx->tsbuffer.tessellation_buffer_size[0]); /* Setup tessellation loop. */ if((path->path_type & 0x1) == VG_LITE_DRAW_FILL_PATH) { for (y = point_min.y; y < point_max.y; y += height) { for (x = point_min.x; x < point_max.x; x += width) { /* Tessellate path. */ VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); #if (DUMP_COMMAND) if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[0], 0); unsigned char* pt = (unsigned char*) memory.memory; for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) { if (i % 8 == 0) fprintf(fp, "Command buffer: "); if (i % 4 == 0) fprintf(fp, "0x"); for (int j = 3; j >= 0; --j) fprintf(fp, "%02x", pt[i + j]); if ((i / 4 + 1) % 2 == 0) fprintf(fp, ",\n"); else fprintf(fp, ", "); } fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[return_offset], 0); fclose(fp); fp = NULL; #endif } else { push_data(ctx, path->path_length, path->path); } } } } /* Setup tessellation loop. */ if(path->path_type == VG_LITE_DRAW_STROKE_PATH || path->path_type == VG_LITE_DRAW_FILL_STROKE_PATH) { for (y = point_min.y; y < point_max.y; y += height) { for (x = point_min.x; x < point_max.x; x += width) { /* Tessellate path. */ VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); #if (DUMP_COMMAND) if (strncmp(filename, "Commandbuffer", 13)) { sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); } fp = fopen(filename, "a"); if (fp == NULL) printf("error!\n"); fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[0], 0); unsigned char* pt = (unsigned char*) memory.memory; for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) { if (i % 8 == 0) fprintf(fp, "Command buffer: "); if (i % 4 == 0) fprintf(fp, "0x"); for (int j = 3; j >= 0; --j) fprintf(fp, "%02x", pt[i + j]); if ((i / 4 + 1) % 2 == 0) fprintf(fp, ",\n"); else fprintf(fp, ", "); } fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", ((uint32_t *) memory.memory)[return_offset], 0); fclose(fp); fp = NULL; #endif } else { format = convert_path_format(VG_LITE_FP32); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000200 | format | quality | tiling | 0x0)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, path->stroke_color)); push_data(ctx, path->stroke_path_size, path->stroke_path_data); } } } } /* Finialize command buffer. */ VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0)); vglitemDUMP_BUFFER("image", source->address, source->memory, 0, (source->stride)*(source->height)); #if DUMP_IMAGE dump_img(source->memory, src_align_width, source->height, source->format); #endif #if !defined(VG_DRIVER_SINGLE_THREAD) tls->t_context.ts_init = 1; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ return error; } vg_lite_error_t vg_lite_init_grad(vg_lite_linear_gradient_t *grad) { vg_lite_error_t error = VG_LITE_SUCCESS; /* Set the member values according to driver defaults. */ grad->image.width = VLC_GRADBUFFER_WIDTH; grad->image.height = 1; grad->image.stride = 0; grad->image.format = VG_LITE_BGRA8888; /* Allocate the image for gradient. */ error = vg_lite_allocate(&grad->image); grad->count = 0; return error; } vg_lite_error_t vg_lite_set_linear_grad(vg_lite_linear_gradient_ext_t *grad, uint32_t count, vg_lite_color_ramp_t *vg_color_ramp, vg_lite_linear_gradient_parameter_t linear_gradient, vg_lite_radial_gradient_spreadmode_t spread_mode, uint8_t color_ramp_premultiplied) { int i; static vg_lite_color_ramp_t default_ramp[] = { { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f } }; uint32_t trg_count; vg_lite_float_t prev_stop; vg_lite_color_ramp_ptr src_ramp; vg_lite_color_ramp_ptr src_ramp_last; vg_lite_color_ramp_ptr trg_ramp; /* Reset the count. */ trg_count = 0; if ((linear_gradient.X0 == linear_gradient.X1) && (linear_gradient.Y0 == linear_gradient.Y1)) return VG_LITE_INVALID_ARGUMENT; grad->linear_gradient = linear_gradient; grad->color_ramp_premultiplied = color_ramp_premultiplied; grad->spread_mode = spread_mode; if (!count || count > MAX_COLOR_RAMP_STOPS || vg_color_ramp == NULL) goto Empty_sequence_handler; for(i = 0; i < count;i++) grad->vg_color_ramp[i] = vg_color_ramp[i]; grad->vg_color_ramp_length = count; /* Determine the last source ramp. */ src_ramp_last = grad->vg_color_ramp + grad->vg_color_ramp_length; /* Set the initial previous stop. */ prev_stop = -1; /* Reset the count. */ trg_count = 0; /* Walk through the source ramp. */ for ( src_ramp = grad->vg_color_ramp, trg_ramp = grad->int_color_ramp; (src_ramp < src_ramp_last) && (trg_count < MAX_COLOR_RAMP_STOPS + 2); src_ramp += 1 ) { /* Must be in increasing order. */ if (src_ramp->stop < prev_stop) { /* Ignore the entire sequence. */ trg_count = 0; break; } /* Update the previous stop value. */ prev_stop = src_ramp->stop; /* Must be within [0..1] range. */ if ((src_ramp->stop < 0.0f) || (src_ramp->stop > 1.0f)) { /* Ignore. */ continue; } /* Clamp color. */ ClampColor(COLOR_FROM_RAMP(src_ramp),COLOR_FROM_RAMP(trg_ramp),0); /* First stop greater then zero? */ if ((trg_count == 0) && (src_ramp->stop > 0.0f)) { /* Force the first stop to 0.0f. */ trg_ramp->stop = 0.0f; /* Replicate the entry. */ trg_ramp[1] = *trg_ramp; trg_ramp[1].stop = src_ramp->stop; /* Advance. */ trg_ramp += 2; trg_count += 2; } else { /* Set the stop value. */ trg_ramp->stop = src_ramp->stop; /* Advance. */ trg_ramp += 1; trg_count += 1; } } /* Empty sequence? */ if (trg_count == 0) { memcpy(grad->int_color_ramp,default_ramp,sizeof(default_ramp)); grad->int_color_ramp_length = sizeof(default_ramp) / 5; } else { /* The last stop must be at 1.0. */ if (trg_ramp[-1].stop != 1.0f) { /* Replicate the last entry. */ *trg_ramp = trg_ramp[-1]; /* Force the last stop to 1.0f. */ trg_ramp->stop = 1.0f; /* Update the final entry count. */ trg_count += 1; } /* Set new length. */ grad->int_color_ramp_length = trg_count; } return VG_LITE_SUCCESS; Empty_sequence_handler: memcpy(grad->int_color_ramp,default_ramp,sizeof(default_ramp)); grad->int_color_ramp_length = sizeof(default_ramp) / 5; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_update_linear_grad(vg_lite_linear_gradient_ext_t *grad) { uint32_t color_ramp_length; vg_lite_color_ramp_ptr color_ramp; uint32_t common, stop; uint32_t i, width; uint8_t* bits; vg_lite_float_t x0,y0,x1,y1,length; vg_lite_error_t error = VG_LITE_SUCCESS; /* Get shortcuts to the color ramp. */ color_ramp_length = grad->int_color_ramp_length; color_ramp = grad->int_color_ramp; x0 = grad->linear_gradient.X0; y0 = grad->linear_gradient.Y0; x1 = grad->linear_gradient.X1; y1 = grad->linear_gradient.Y1; length = (vg_lite_float_t)sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); if(length <= 0) return VG_LITE_INVALID_ARGUMENT; /* Find the common denominator of the color ramp stops. */ if (length < 1) { common = 1; } else { common = (uint32_t)length; } for (i = 0; i < color_ramp_length; ++i) { if (color_ramp[i].stop != 0.0f) { vg_lite_float_t mul = common * color_ramp[i].stop; vg_lite_float_t frac = mul - (vg_lite_float_t) floor(mul); if (frac > 0.00013f) /* Suppose error for zero is 0.00013 */ { common = MAX(common, (uint32_t) (1.0f / frac + 0.5f)); } } } /* Compute the width of the required color array. */ width = common + 1; /* Allocate the color ramp surface. */ memset(&grad->image, 0, sizeof(grad->image)); grad->image.width = width; grad->image.height = 1; grad->image.stride = 0; grad->image.image_mode = VG_LITE_NONE_IMAGE_MODE; grad->image.format = VG_LITE_ABGR8888; /* Allocate the image for gradient. */ VG_LITE_RETURN_ERROR(vg_lite_allocate(&grad->image)); grad->image.width = width; /* Set pointer to color array. */ bits = (uint8_t *)grad->image.memory; /* Start filling the color array. */ stop = 0; for (i = 0; i < width; ++i) { vg_lite_float_t gradient; vg_lite_float_t color[4]; vg_lite_float_t color1[4]; vg_lite_float_t color2[4]; vg_lite_float_t weight; /* Compute gradient for current color array entry. */ gradient = (vg_lite_float_t) i / (vg_lite_float_t) (width - 1); /* Find the entry in the color ramp that matches or exceeds this ** gradient. */ while ((stop < color_ramp_length - 1) && (gradient > color_ramp[stop].stop)) { ++stop; } if (gradient == color_ramp[stop].stop) { /* Perfect match weight 1.0. */ weight = 1.0f; /* Use color ramp color. */ color1[3] = color_ramp[stop].alpha; color1[2] = color_ramp[stop].blue; color1[1] = color_ramp[stop].green; color1[0] = color_ramp[stop].red; color2[3] = color2[2] = color2[1] = color2[0] = 0.0f; } else { /* Compute weight. */ weight = (color_ramp[stop].stop - gradient) / (color_ramp[stop].stop - color_ramp[stop - 1].stop); /* Grab color ramp color of previous stop. */ color1[3] = color_ramp[stop - 1].alpha; color1[2] = color_ramp[stop - 1].blue; color1[1] = color_ramp[stop - 1].green; color1[0] = color_ramp[stop - 1].red; /* Grab color ramp color of current stop. */ color2[3] = color_ramp[stop].alpha; color2[2] = color_ramp[stop].blue; color2[1] = color_ramp[stop].green; color2[0] = color_ramp[stop].red; } if (grad->color_ramp_premultiplied) { /* Pre-multiply the first color. */ color1[2] *= color1[3]; color1[1] *= color1[3]; color1[0] *= color1[3]; /* Pre-multiply the second color. */ color2[2] *= color2[3]; color2[1] *= color2[3]; color2[0] *= color2[3]; } /* Filter the colors per channel. */ color[3] = LERP(color1[3], color2[3], weight); color[2] = LERP(color1[2], color2[2], weight); color[1] = LERP(color1[1], color2[1], weight); color[0] = LERP(color1[0], color2[0], weight); /* Pack the final color. */ *bits++ = PackColorComponent(color[3]); *bits++ = PackColorComponent(color[2]); *bits++ = PackColorComponent(color[1]); *bits++ = PackColorComponent(color[0]); } return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_set_rad_grad(vg_lite_radial_gradient_t *grad, uint32_t count, vg_lite_color_ramp_t *vgColorRamp, vg_lite_radial_gradient_parameter_t radialGradient, vg_lite_radial_gradient_spreadmode_t SpreadMode, uint8_t colorRampPremultiplied) { int i; static vg_lite_color_ramp_t defaultRamp[] = { { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f } }; uint32_t trgCount; vg_lite_float_t prevStop; vg_lite_color_ramp_ptr srcRamp; vg_lite_color_ramp_ptr srcRampLast; vg_lite_color_ramp_ptr trgRamp; /* Reset the count. */ trgCount = 0; if(radialGradient.r <= 0) return VG_LITE_INVALID_ARGUMENT; grad->radialGradient = radialGradient; grad->colorRampPremultiplied = colorRampPremultiplied; grad->SpreadMode = SpreadMode; if (!count || count > MAX_COLOR_RAMP_STOPS || vgColorRamp == NULL) goto Empty_sequence_handler; for(i = 0; i < count;i++) grad->vgColorRamp[i] = vgColorRamp[i]; grad->vgColorRampLength = count; /* Determine the last source ramp. */ srcRampLast = grad->vgColorRamp + grad->vgColorRampLength; /* Set the initial previous stop. */ prevStop = -1; /* Reset the count. */ trgCount = 0; /* Walk through the source ramp. */ for ( srcRamp = grad->vgColorRamp, trgRamp = grad->intColorRamp; (srcRamp < srcRampLast) && (trgCount < MAX_COLOR_RAMP_STOPS + 2); srcRamp += 1 ) { /* Must be in increasing order. */ if (srcRamp->stop < prevStop) { /* Ignore the entire sequence. */ trgCount = 0; break; } /* Update the previous stop value. */ prevStop = srcRamp->stop; /* Must be within [0..1] range. */ if ((srcRamp->stop < 0.0f) || (srcRamp->stop > 1.0f)) { /* Ignore. */ continue; } /* Clamp color. */ ClampColor(COLOR_FROM_RAMP(srcRamp),COLOR_FROM_RAMP(trgRamp),0); /* First stop greater then zero? */ if ((trgCount == 0) && (srcRamp->stop > 0.0f)) { /* Force the first stop to 0.0f. */ trgRamp->stop = 0.0f; /* Replicate the entry. */ trgRamp[1] = *trgRamp; trgRamp[1].stop = srcRamp->stop; /* Advance. */ trgRamp += 2; trgCount += 2; } else { /* Set the stop value. */ trgRamp->stop = srcRamp->stop; /* Advance. */ trgRamp += 1; trgCount += 1; } } /* Empty sequence? */ if (trgCount == 0) { memcpy(grad->intColorRamp,defaultRamp,sizeof(defaultRamp)); grad->intColorRampLength = sizeof(defaultRamp) / 5; } else { /* The last stop must be at 1.0. */ if (trgRamp[-1].stop != 1.0f) { /* Replicate the last entry. */ *trgRamp = trgRamp[-1]; /* Force the last stop to 1.0f. */ trgRamp->stop = 1.0f; /* Update the final entry count. */ trgCount += 1; } /* Set new length. */ grad->intColorRampLength = trgCount; } return VG_LITE_SUCCESS; Empty_sequence_handler: memcpy(grad->intColorRamp,defaultRamp,sizeof(defaultRamp)); grad->intColorRampLength = sizeof(defaultRamp) / 5; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_update_rad_grad(vg_lite_radial_gradient_t *grad) { uint32_t colorRampLength; vg_lite_color_ramp_ptr colorRamp; uint32_t common, stop; uint32_t i, width; uint8_t* bits; vg_lite_float_t r; vg_lite_error_t error = VG_LITE_SUCCESS; /* Get shortcuts to the color ramp. */ colorRampLength = grad->intColorRampLength; colorRamp = grad->intColorRamp; r = grad->radialGradient.r; if(r <= 0) return VG_LITE_INVALID_ARGUMENT; /* Find the common denominator of the color ramp stops. */ if (r < 1) { common = 1; } else { common = (uint32_t)r; } for (i = 0; i < colorRampLength; ++i) { if (colorRamp[i].stop != 0.0f) { vg_lite_float_t mul = common * colorRamp[i].stop; vg_lite_float_t frac = mul - (vg_lite_float_t) floor(mul); if (frac > 0.00013f) /* Suppose error for zero is 0.00013 */ { common = MAX(common, (uint32_t) (1.0f / frac + 0.5f)); } } } /* Compute the width of the required color array. */ width = common + 1; /* Allocate the color ramp surface. */ memset(&grad->image, 0, sizeof(grad->image)); grad->image.width = width; grad->image.height = 1; grad->image.stride = 0; grad->image.image_mode = VG_LITE_NONE_IMAGE_MODE; grad->image.format = VG_LITE_ABGR8888; /* Allocate the image for gradient. */ VG_LITE_RETURN_ERROR(vg_lite_allocate(&grad->image)); grad->image.width = width; /* Set pointer to color array. */ bits = (uint8_t *)grad->image.memory; /* Start filling the color array. */ stop = 0; for (i = 0; i < width; ++i) { vg_lite_float_t gradient; vg_lite_float_t color[4]; vg_lite_float_t color1[4]; vg_lite_float_t color2[4]; vg_lite_float_t weight; /* Compute gradient for current color array entry. */ gradient = (vg_lite_float_t) i / (vg_lite_float_t) (width - 1); /* Find the entry in the color ramp that matches or exceeds this ** gradient. */ while ((stop < colorRampLength - 1) && (gradient > colorRamp[stop].stop)) { ++stop; } if (gradient == colorRamp[stop].stop) { /* Perfect match weight 1.0. */ weight = 1.0f; /* Use color ramp color. */ color1[3] = colorRamp[stop].alpha; color1[2] = colorRamp[stop].blue; color1[1] = colorRamp[stop].green; color1[0] = colorRamp[stop].red; color2[3] = color2[2] = color2[1] = color2[0] = 0.0f; } else { /* Compute weight. */ weight = (colorRamp[stop].stop - gradient) / (colorRamp[stop].stop - colorRamp[stop - 1].stop); /* Grab color ramp color of previous stop. */ color1[3] = colorRamp[stop - 1].alpha; color1[2] = colorRamp[stop - 1].blue; color1[1] = colorRamp[stop - 1].green; color1[0] = colorRamp[stop - 1].red; /* Grab color ramp color of current stop. */ color2[3] = colorRamp[stop].alpha; color2[2] = colorRamp[stop].blue; color2[1] = colorRamp[stop].green; color2[0] = colorRamp[stop].red; } if (grad->colorRampPremultiplied) { /* Pre-multiply the first color. */ color1[2] *= color1[3]; color1[1] *= color1[3]; color1[0] *= color1[3]; /* Pre-multiply the second color. */ color2[2] *= color2[3]; color2[1] *= color2[3]; color2[0] *= color2[3]; } /* Filter the colors per channel. */ color[3] = LERP(color1[3], color2[3], weight); color[2] = LERP(color1[2], color2[2], weight); color[1] = LERP(color1[1], color2[1], weight); color[0] = LERP(color1[0], color2[0], weight); /* Pack the final color. */ *bits++ = PackColorComponent(color[3]); *bits++ = PackColorComponent(color[2]); *bits++ = PackColorComponent(color[1]); *bits++ = PackColorComponent(color[0]); } return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_set_grad(vg_lite_linear_gradient_t *grad, uint32_t count, uint32_t * colors, uint32_t * stops) { uint32_t i; grad->count = 0; /* Opaque B&W gradient */ if (!count || count > VLC_MAX_GRAD || colors == NULL || stops == NULL) return VG_LITE_SUCCESS; /* Check stops validity */ for (i = 0; i < count; i++) if (stops[i] <= 255) { if (!grad->count || stops[i] > grad->stops[grad->count - 1]) { grad->stops[grad->count] = stops[i]; grad->colors[grad->count] = colors[i]; grad->count++; } else if (stops[i] == grad->stops[grad->count - 1]) { /* Equal stops : use the color corresponding to the last stop in the sequence */ grad->colors[grad->count - 1] = colors[i]; } } return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_update_grad(vg_lite_linear_gradient_t *grad) { vg_lite_error_t error = VG_LITE_SUCCESS; int32_t r0, g0, b0, a0; int32_t r1, g1, b1, a1; int32_t lr, lg, lb, la; uint32_t i; int32_t j; int32_t ds, dr, dg, db, da; uint32_t *buffer = (uint32_t *)grad->image.memory; if (grad->count == 0) { /* If no valid stops have been specified (e.g., due to an empty input * array, out-of-range, or out-of-order stops), a stop at 0 with color * 0xFF000000 (opaque black) and a stop at 255 with color 0xFFFFFFFF * (opaque white) are implicitly defined. */ grad->stops[0] = 0; grad->colors[0] = 0xFF000000; /* Opaque black */ grad->stops[1] = 255; grad->colors[1] = 0xFFFFFFFF; /* Opaque white */ grad->count = 2; } else if (grad->count && grad->stops[0] != 0) { /* If at least one valid stop has been specified, but none has been * defined with an offset of 0, an implicit stop is added with an * offset of 0 and the same color as the first user-defined stop. */ for (i = 0; i < grad->stops[0]; i++) buffer[i] = grad->colors[0]; } a0 = A(grad->colors[0]); r0 = R(grad->colors[0]); g0 = G(grad->colors[0]); b0 = B(grad->colors[0]); /* Calculate the colors for each pixel of the image. */ for (i = 0; i < grad->count - 1; i++) { buffer[grad->stops[i]] = grad->colors[i]; ds = grad->stops[i + 1] - grad->stops[i]; a1 = A(grad->colors[i + 1]); r1 = R(grad->colors[i + 1]); g1 = G(grad->colors[i + 1]); b1 = B(grad->colors[i + 1]); da = a1 - a0; dr = r1 - r0; dg = g1 - g0; db = b1 - b0; for (j = 1; j < ds; j++) { la = a0 + da * j / ds; lr = r0 + dr * j / ds; lg = g0 + dg * j / ds; lb = b0 + db * j / ds; buffer[grad->stops[i] + j] = ARGB(la, lr, lg, lb); } a0 = a1; r0 = r1; g0 = g1; b0 = b1; } /* If at least one valid stop has been specified, but none has been defined * with an offset of 255, an implicit stop is added with an offset of 255 * and the same color as the last user-defined stop. */ for (i = grad->stops[grad->count - 1]; i < 255; i++) buffer[i] = grad->colors[grad->count - 1]; /* Last pixel */ buffer[i] = grad->colors[grad->count - 1]; return error; } vg_lite_error_t vg_lite_clear_grad(vg_lite_linear_gradient_t *grad) { vg_lite_error_t error = VG_LITE_SUCCESS; grad->count = 0; /* Release the image resource. */ if (grad->image.handle != NULL) { error = vg_lite_free(&grad->image); } return error; } vg_lite_error_t vg_lite_clear_rad_grad(vg_lite_radial_gradient_t *grad) { vg_lite_error_t error = VG_LITE_SUCCESS; grad->count = 0; /* Release the image resource. */ if (grad->image.handle != NULL) { error = vg_lite_free(&grad->image); } return error; } vg_lite_error_t vg_lite_clear_linear_grad(vg_lite_linear_gradient_ext_t *grad) { vg_lite_error_t error = VG_LITE_SUCCESS; grad->count = 0; /* Release the image resource. */ if (grad->image.handle != NULL) { error = vg_lite_free(&grad->image); } return error; } vg_lite_matrix_t * vg_lite_get_linear_grad_matrix(vg_lite_linear_gradient_ext_t *grad) { return &grad->matrix; } vg_lite_matrix_t * vg_lite_get_grad_matrix(vg_lite_linear_gradient_t *grad) { return &grad->matrix; } vg_lite_matrix_t * vg_lite_get_rad_grad_matrix(vg_lite_radial_gradient_t *grad) { return &grad->matrix; } vg_lite_error_t vg_lite_draw_gradient(vg_lite_buffer_t * target, vg_lite_path_t * path, vg_lite_fill_t fill_rule, vg_lite_matrix_t * matrix, vg_lite_linear_gradient_t * grad, vg_lite_blend_t blend) { return vg_lite_draw_pattern(target, path, fill_rule, matrix, &grad->image, &grad->matrix, blend, VG_LITE_PATTERN_PAD, 0, VG_LITE_FILTER_LINEAR); } vg_lite_error_t vg_lite_set_command_buffer_size(uint32_t size) { vg_lite_error_t error = VG_LITE_SUCCESS; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ #if defined(VG_DRIVER_SINGLE_THREAD) if(!ctx->init){ if(!size) return VG_LITE_INVALID_ARGUMENT; command_buffer_size = size; } else{ #else if(CMDBUF_IN_QUEUE(&ctx->context, 0) || CMDBUF_IN_QUEUE(&ctx->context, 1)) return VG_LITE_INVALID_ARGUMENT; #endif /* VG_DRIVER_SINGLE_THREAD */ VG_LITE_RETURN_ERROR(_free_command_buffer()); VG_LITE_RETURN_ERROR(_allocate_command_buffer(size)); VG_LITE_RETURN_ERROR(program_tessellation(ctx)); #if defined(VG_DRIVER_SINGLE_THREAD) } #endif /* VG_DRIVER_SINGLE_THREAD */ return error; } vg_lite_error_t vg_lite_set_scissor(int32_t x, int32_t y, int32_t width, int32_t height) { vg_lite_error_t error = VG_LITE_SUCCESS; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; /* Scissor dirty. */ ctx->scissor_dirty = 1; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ /* Save scissor Box States. */ ctx->scissor[0] = x; ctx->scissor[1] = y; ctx->scissor[2] = width; ctx->scissor[3] = height; return error; } vg_lite_error_t vg_lite_enable_scissor(void) { #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; /* Scissor dirty. */ ctx->scissor_dirty = 1; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ /* Enable scissor Mode. */ ctx->scissor_enabled = 1; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_disable_scissor(void) { #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; /* Scissor dirty. */ ctx->scissor_dirty = 1; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ /* disable scissor Mode. */ ctx->scissor_enabled = 0; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_mem_avail(uint32_t *size) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_kernel_mem_t mem; VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_QUERY_MEM,&mem)); *size = mem.bytes; return error; } vg_lite_error_t vg_lite_enable_premultiply(void) { #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t *tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if (tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) return VG_LITE_NOT_SUPPORT; /* Enable premultiply Mode. */ ctx->premultiply_enabled = 1; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_disable_premultiply(void) { #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) return VG_LITE_NOT_SUPPORT; /* disable premultiply Mode. */ ctx->premultiply_enabled = 0; return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_set_dither(int enable) { vg_lite_error_t error = VG_LITE_SUCCESS; uint32_t table_low = 0x7B48F3C0; uint32_t table_high = 0x596AD1E2; int dither_enable = enable; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_tls_t* tls; vg_lite_context_t *ctx; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ if(!vg_lite_query_feature(gcFEATURE_BIT_VG_DITHER)) { return VG_LITE_NOT_SUPPORT; } if(dither_enable) { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A5A, table_low)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A5B, table_high)); } else { VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A5A, 0xFFFFFFFF)); VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A5B, 0xFFFFFFFF)); } return error; } vg_lite_error_t vg_lite_set_color_key(vg_lite_color_key4_t colorkey) { uint8_t i; uint32_t value_low = 0; uint32_t value_high = 0; uint8_t r, g, b, a, e; vg_lite_error_t error = VG_LITE_SUCCESS; #if defined(VG_DRIVER_SINGLE_THREAD) vg_lite_context_t *ctx = &s_context; #else vg_lite_context_t *ctx; vg_lite_tls_t* tls; tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); if(tls == NULL) return VG_LITE_NO_CONTEXT; ctx = &tls->t_context; #endif /* VG_DRIVER_SINGLE_THREAD */ if(!vg_lite_query_feature(gcFEATURE_BIT_VG_COLOR_KEY)) return VG_LITE_NOT_SUPPORT; /* Set color key states. */ for (i = 0; i < 4; i++) { /* Set gcregVGPEColorKeyLow. Layout "E/R/G/B". */ r = colorkey[i].low_r; g = colorkey[i].low_g; b = colorkey[i].low_b; e = colorkey[i].enable; value_low = (e << 24) | (r << 16) | (g << 8) | b; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A90 + i , value_low)); /* Set gcregVGPEColorKeyHigh. Layout "A/R/G/B". */ r = colorkey[i].hign_r; g = colorkey[i].hign_g; b = colorkey[i].hign_b; a = colorkey[i].alpha; value_high = (a << 24) | (r << 16) | (g << 8) | b; VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A94 + i , value_high)); } return error; }