10895 lines
363 KiB
C
10895 lines
363 KiB
C
|
/****************************************************************************
|
||
|
*
|
||
|
* 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 <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stddef.h>
|
||
|
#include <math.h>
|
||
|
#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 <unistd.h>
|
||
|
#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;
|
||
|
}
|