/* * Copyright (c) 2018-2025 Jean-Philippe Bruyère * * 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, sublicense, 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 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 NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef VKVG_CONTEXT_INTERNAL_H #define VKVG_CONTEXT_INTERNAL_H #include "vkvg_internal.h" #include "vkvg_fonts.h" #if VKVG_RECORDING #include "recording/vkvg_record_internal.h" #else #define RECORD(ctx, cmd, ...) #define RECORD2(ctx, cmd, ...) #endif #define VKVG_PTS_SIZE 1024 #define VKVG_VBO_SIZE (VKVG_PTS_SIZE * 4) #define VKVG_IBO_SIZE (VKVG_VBO_SIZE * 6) #define VKVG_PATHES_SIZE 16 #define VKVG_ARRAY_THRESHOLD 8 #define VKVG_IBO_16 0 #define VKVG_IBO_32 1 #define VKVG_CUR_IBO_TYPE VKVG_IBO_32 // change this only #if VKVG_CUR_IBO_TYPE == VKVG_IBO_16 #define VKVG_IBO_MAX UINT16_MAX #define VKVG_IBO_INDEX_TYPE uint16_t #define VKVG_VK_INDEX_TYPE VK_INDEX_TYPE_UINT16 #else #define VKVG_IBO_MAX UINT32_MAX #define VKVG_IBO_INDEX_TYPE uint32_t #define VKVG_VK_INDEX_TYPE VK_INDEX_TYPE_UINT32 #endif #define FULLSCREEN_BIT 0x10000000 #define SRCTYPE_MASK 0x000000FF #define CreateRgba(r, g, b, a) (((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | b) #ifdef VKVG_PREMULT_ALPHA #define CreateRgbaf(r, g, b, a) \ ((((uint32_t)(a * 255.0f) & 0xFF) << 24) | (((uint32_t)(b * a * 255.0f) & 0xFF) << 16) | \ (((uint32_t)(g * a * 255.0f) & 0xFF) << 8) | ((uint32_t)(r * a * 255.0f) & 0xFF)) #else #define CreateRgbaf(r, g, b, a) \ (((int)(a * 255.0f) << 24) | ((int)(b * 255.0f) << 16) | ((int)(g * 255.0f) << 8) | (int)(r * 255.0f)) #endif typedef struct { vec2 pos; uint32_t color; vec3 uv; } Vertex; typedef struct { vec4 source; vec2 size; uint32_t fsq_patternType; float opacity; vkvg_matrix_t mat; vkvg_matrix_t matInv; } push_constants; /* context.curClipState may be one of the following, it's set * with check of the previous saved state: * - none: no clipping operation since the previous state * - clear: current has cleared the clip, or previous state is also clear. * - clip: current have been clipped with a new region since the last save. * * the saved context may have following savedState: * - clear: no clip * - clip: context is clipped, but not at this save/restore level, no stencil is saved at that level * - clip_saved: context is clipped and the clip region is saved at that level. */ typedef enum { vkvg_clip_state_none = 0x00, vkvg_clip_state_clear = 0x01, vkvg_clip_state_clip = 0x02, vkvg_clip_state_clip_saved = 0x06, } vkvg_clip_state_t; typedef struct _vkvg_context_save_t { struct _vkvg_context_save_t* pNext; float lineWidth; float miterLimit; float dashOffset; // an offset for dash float* dashes; // an array of alternate lengths of on and off stroke. uint32_t dashCount; // value count in dash array, 0 if dash not set. vkvg_operator_t curOperator; vkvg_line_cap_t lineCap; vkvg_line_join_t lineJoint; vkvg_fill_rule_t curFillRule; long selectedCharSize; /* Font size*/ char selectedFontName[FONT_NAME_MAX_SIZE]; _vkvg_font_identity_t selectedFont; // hold current face and size before cache addition _vkvg_font_identity_t* currentFont; // font ready for lookup vkvg_direction_t textDirection; push_constants pushConsts; uint32_t curColor; VkvgPattern pattern; vkvg_clip_state_t clippingState; } vkvg_context_save_t; typedef struct _vkvg_context_t { vkvg_status_t status; uint32_t references; // reference count VkvgDevice dev; VkvgSurface pSurf; // surface bound to context, set on creation of ctx #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE uint64_t timelineStep; // context cmd last submission timeline id. #else VkFence flushFence; // context fence #endif // VkDescriptorImageInfo sourceDescriptor; //Store view/sampler in context VkCommandPool cmdPool; // local pools ensure thread safety VkCommandBuffer cmdBuffers[2]; // double cmd buff for context operations VkCommandBuffer cmd; // current recording buffer VkDescriptorPool descriptorPool; // one pool per thread VkDescriptorSet dsFont; // fonts glyphs texture atlas descriptor (local for thread safety) VkDescriptorSet dsSrc; // source ds VkDescriptorSet dsGrad; // gradient uniform buffer VkhImage fontCacheImg; // current font cache, may not be the last one, updated only if new glyphs are // uploaded by the current context VkRect2D bounds; uint32_t curColor; #if VKVG_FILL_NZ_GLUTESS void (*vertex_cb)(VKVG_IBO_INDEX_TYPE, VkvgContext); // tesselator vertex callback VKVG_IBO_INDEX_TYPE tesselator_fan_start; uint32_t tesselator_idx_counter; #endif #if VKVG_RECORDING vkvg_recording_t* recording; #endif vkh_buffer_t uboGrad; // uniform buff obj holdings gradient infos // vk buffers, holds data until flush vkh_buffer_t indices; // index buffer with persistent map memory uint32_t sizeIBO; // size of vk ibo uint32_t sizeIndices; // reserved size uint32_t indCount; // current indice count uint32_t curIndStart; // last index recorded in cmd buff VKVG_IBO_INDEX_TYPE curVertOffset; // vertex offset in draw indexed command vkh_buffer_t vertices; // vertex buffer with persistent mapped memory uint32_t sizeVBO; // size of vk vbo size uint32_t sizeVertices; // reserved size uint32_t vertCount; // effective vertices count Vertex* vertexCache; VKVG_IBO_INDEX_TYPE* indexCache; // pathes, exists until stroke of fill vec2* points; // points array uint32_t sizePoints; // reserved size uint32_t pointCount; // effective points count // pathes array is a list of point count per segment uint32_t pathPtr; // pointer in the path array uint32_t* pathes; uint32_t sizePathes; uint32_t segmentPtr; // current segment count in current path having curves uint32_t subpathCount; // store count of subpath, not straight forward to retrieve from segmented path array bool simpleConvex; // true if path is single rect or concave closed curve. bool cmdStarted; // prevent flushing empty renderpass bool pushCstDirty; // prevent pushing to gpu if not requested float lineWidth; float miterLimit; uint32_t dashCount; // value count in dash array, 0 if dash not set. float dashOffset; // an offset for dash float* dashes; // an array of alternate lengths of on and off stroke. vkvg_operator_t curOperator; vkvg_line_cap_t lineCap; vkvg_line_join_t lineJoin; vkvg_fill_rule_t curFillRule; long selectedCharSize; /* Font size*/ char selectedFontName[FONT_NAME_MAX_SIZE]; //_vkvg_font_t selectedFont; //hold current face and size before cache addition _vkvg_font_identity_t* currentFont; // font pointing to cached fonts identity _vkvg_font_t* currentFontSize; // font structure by size ready for lookup vkvg_direction_t textDirection; push_constants pushConsts; VkvgPattern pattern; vkvg_context_save_t* pSavedCtxs; // last ctx saved ptr uint8_t curSavBit; // current stencil bit used to save context, 6 bits used by stencil for save/restore VkhImage* savedStencils; // additional image for saving contexes once more than 6 save/restore are reached vkvg_clip_state_t curClipState; // current clipping status relative to the previous saved one or clear state if // none. VkClearRect clearRect; VkRenderPassBeginInfo renderPassBeginInfo; } vkvg_context; typedef struct _ear_clip_point { vec2 pos; VKVG_IBO_INDEX_TYPE idx; struct _ear_clip_point* next; } ear_clip_point; typedef struct { bool dashOn; uint32_t curDash; // current dash index float curDashOffset; // cur dash offset between defined path point and last dash segment(on/off) start float totDashLength; // total length of dashes vec2 normal; } dash_context_t; typedef struct { uint32_t iL; uint32_t iR; uint32_t cp; // current point VKVG_IBO_INDEX_TYPE firstIdx; // save first point idx for closed path float hw; // stroke half width, computed once. float lhMax; // miter limit * line width float arcStep; // cached arcStep, prevent compute multiple times for same stroke, 0 if not yet computed } stroke_context_t; void _check_vertex_cache_size(VkvgContext ctx); void _ensure_vertex_cache_size(VkvgContext ctx, uint32_t addedVerticesCount); void _resize_vertex_cache(VkvgContext ctx, uint32_t newSize); void _check_index_cache_size(VkvgContext ctx); void _ensure_index_cache_size(VkvgContext ctx, uint32_t addedIndicesCount); void _resize_index_cache(VkvgContext ctx, uint32_t newSize); bool _check_pathes_array(VkvgContext ctx); bool _current_path_is_empty(VkvgContext ctx); void _finish_path(VkvgContext ctx); void _clear_path(VkvgContext ctx); void _remove_last_point(VkvgContext ctx); bool _path_is_closed(VkvgContext ctx, uint32_t ptrPath); void _set_curve_start(VkvgContext ctx); void _set_curve_end(VkvgContext ctx); bool _path_has_curves(VkvgContext ctx, uint32_t ptrPath); float _normalizeAngle(float a); float _get_arc_step(VkvgContext ctx, float radius); vec2 _get_current_position(VkvgContext ctx); void _add_point(VkvgContext ctx, float x, float y); void _resetMinMax(VkvgContext ctx); void _vkvg_path_extents(VkvgContext ctx, bool transformed, float* x1, float* y1, float* x2, float* y2); void _draw_stoke_cap(VkvgContext ctx, stroke_context_t* str, vec2 p0, vec2 n, bool isStart); void _draw_segment(VkvgContext ctx, stroke_context_t* str, dash_context_t* dc, bool isCurve); float _draw_dashed_segment(VkvgContext ctx, stroke_context_t* str, dash_context_t* dc, bool isCurve); bool _build_vb_step(VkvgContext ctx, stroke_context_t* str, bool isCurve); void _poly_fill(VkvgContext ctx, vec4* bounds); void _fill_non_zero(VkvgContext ctx); void _draw_full_screen_quad(VkvgContext ctx, vec4* scissor); void _create_gradient_buff(VkvgContext ctx); void _create_vertices_buff(VkvgContext ctx); void _add_vertex(VkvgContext ctx, Vertex v); void _add_vertexf(VkvgContext ctx, float x, float y); void _set_vertex(VkvgContext ctx, uint32_t idx, Vertex v); void _add_triangle_indices(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2); void _add_tri_indices_for_rect(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i); void _vao_add_rectangle(VkvgContext ctx, float x, float y, float width, float height); void _bind_draw_pipeline(VkvgContext ctx); void _create_cmd_buff(VkvgContext ctx); void _check_vao_size(VkvgContext ctx); void _flush_cmd_buff(VkvgContext ctx); void _ensure_renderpass_is_started(VkvgContext ctx); void _emit_draw_cmd_undrawn_vertices(VkvgContext ctx); void _flush_cmd_until_vx_base(VkvgContext ctx); bool _wait_ctx_flush_end(VkvgContext ctx); bool _wait_and_submit_cmd(VkvgContext ctx); void _update_push_constants(VkvgContext ctx); void _update_cur_pattern(VkvgContext ctx, VkvgPattern pat); void _set_mat_inv_and_vkCmdPush(VkvgContext ctx); void _start_cmd_for_render_pass(VkvgContext ctx); void _createDescriptorPool(VkvgContext ctx); void _init_descriptor_sets(VkvgContext ctx); void _update_descriptor_set(VkvgContext ctx, VkhImage img, VkDescriptorSet ds); void _update_gradient_desc_set(VkvgContext ctx); void _free_ctx_save(vkvg_context_save_t* sav); void _release_context_ressources(VkvgContext ctx); static inline float vec2_zcross(vec2 v1, vec2 v2) { return v1.x * v2.y - v1.y * v2.x; } static inline float ecp_zcross(ear_clip_point* p0, ear_clip_point* p1, ear_clip_point* p2) { return vec2_zcross(vec2_sub(p1->pos, p0->pos), vec2_sub(p2->pos, p0->pos)); } void _recursive_bezier(VkvgContext ctx, float distanceTolerance, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, unsigned level); void _bezier(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4); void _line_to(VkvgContext ctx, float x, float y); void _elliptic_arc(VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, float _rx, float _ry, float phi); void _select_font_face(VkvgContext ctx, const char* name); #endif