From 861758dd1e4c4f375c7a2597c12034932b0e5ead Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Sun, 19 Dec 2021 04:27:36 +0100 Subject: [PATCH] gradient stop count check, raise status if count < 2, simplify linear gradient shader --- CMakeLists.txt | 2 +- include/vkvg.h | 173 +- screenshot2.png | Bin 0 -> 91357 bytes shaders/vkvg_main.frag | 41 +- src/shaders.h | 3008 +++++++++++++++--------------- src/vkvg_context.c | 22 +- src/vkvg_context_internal.c | 47 +- src/vkvg_context_internal.h | 4 +- src/vkvg_device.c | 2 +- src/vkvg_experimental.c | 28 + src/vkvg_experimental.h | 28 + src/vkvg_internal.h | 4 +- src/vkvg_pattern.c | 75 +- src/vkvg_pattern.h | 3 +- tests/CMakeLists.txt | 19 +- tests/arcs.c | 4 +- tests/common/test.c | 2 +- tests/common/vkengine.c | 11 +- tests/fill.c | 1 + tests/gradient.c | 65 +- tests/gradient2.c | 174 ++ tests/inverse_colinear.c | 1 + tests/{ => perfs}/random_rects.c | 0 tests/{ => perfs}/randoms.c | 0 vkh | 2 +- 25 files changed, 2111 insertions(+), 1605 deletions(-) create mode 100644 screenshot2.png create mode 100644 src/vkvg_experimental.c create mode 100644 src/vkvg_experimental.h create mode 100644 tests/gradient2.c rename tests/{ => perfs}/random_rects.c (100%) rename tests/{ => perfs}/randoms.c (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb8fa15..6120417 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,7 +138,7 @@ IF(GLSLC AND XXD) ADD_CUSTOM_COMMAND ( OUTPUT ${shader-output} COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${SHADER_DIR}" - COMMAND ${GLSLC} ${shader-input} -o ${shader-output} + COMMAND ${GLSLC} ${shader-input} -o ${shader-output} --target-env=vulkan1.2 COMMENT "Compiling ${shader-input}" DEPENDS ${SHADER} VERBATIM diff --git a/include/vkvg.h b/include/vkvg.h index 5937bf5..1e0c58f 100644 --- a/include/vkvg.h +++ b/include/vkvg.h @@ -30,8 +30,6 @@ extern "C" { * Doxygen documentation *************************************************************************/ /** @mainpage VKVG: vulkan vector graphics - * - * Documentation of all members: vkvg.h * * VKVG is an open source 2d vector drawing library written in @b c and using [vulkan](https://www.khronos.org/vulkan/) for hardware acceleration. * Its api is modeled on the [cairo graphic library](https://www.cairographics.org/) with the following software components: @@ -100,6 +98,8 @@ extern uint8_t vkvg_log_level; * vkvg_status_t is used to indicates errors that can occur when using vkvg. Several vkvg function directely * return result, but when using a @ref context, the last error is stored in the context and can be accessed * with #vkvg_status. + * + * As soon as a status is not success, further operations will be canceled. */ typedef enum { VKVG_STATUS_SUCCESS = 0, /*!< no error occurred.*/ @@ -116,12 +116,14 @@ typedef enum { VKVG_STATUS_SURFACE_FINISHED, /*!< */ VKVG_STATUS_SURFACE_TYPE_MISMATCH, /*!< */ VKVG_STATUS_PATTERN_TYPE_MISMATCH, /*!< */ + VKVG_STATUS_PATTERN_INVALID_GRADIENT,/*!< occurs when stops count is zero */ VKVG_STATUS_INVALID_CONTENT, /*!< */ VKVG_STATUS_INVALID_FORMAT, /*!< */ VKVG_STATUS_INVALID_VISUAL, /*!< */ VKVG_STATUS_FILE_NOT_FOUND, /*!< */ VKVG_STATUS_INVALID_DASH, /*!< invalid value for a dash setting */ VKVG_STATUS_INVALID_RECT, /*!< rectangle with height or width equal to 0. */ + VKVG_STATUS_TIMEOUT, /*!< waiting for a vulkan operation to finish resulted in a fence timeout (5 seconds)*/ }vkvg_status_t; typedef enum { @@ -213,21 +215,32 @@ typedef struct { float a; } vkvg_color_t; +/** + * @brief font metrics + * + * structure defining global font metrics for a particular font. It can be retrieve by calling @ref vkvg_font_extents + * on a valid context. + */ typedef struct { - float ascent; - float descent; - float height; - float max_x_advance; - float max_y_advance; + float ascent; /*!< the distance that the font extends above the baseline. */ + float descent; /*!< the distance that the font extends below the baseline.*/ + float height; /*!< the recommended vertical distance between baselines. */ + float max_x_advance; /*!< the maximum distance in the X direction that the origin is advanced for any glyph in the font.*/ + float max_y_advance; /*!< the maximum distance in the Y direction that the origin is advanced for any glyph in the font. This will be zero for normal fonts used for horizontal writing.*/ } vkvg_font_extents_t; - +/** + * @brief text metrics + * + * structure defining metrics for a single or a string of glyphs. To measure text, call @ref vkvg_text_extents + * on a valid context. + */ typedef struct { - float x_bearing; - float y_bearing; - float width; - float height; - float x_advance; - float y_advance; + float x_bearing; /*!< the horizontal distance from the origin to the leftmost part of the glyphs as drawn. Positive if the glyphs lie entirely to the right of the origin. */ + float y_bearing; /*!< the vertical distance from the origin to the topmost part of the glyphs as drawn. Positive only if the glyphs lie completely below the origin; will usually be negative.*/ + float width; /*!< width of the glyphs as drawn*/ + float height; /*!< height of the glyphs as drawn*/ + float x_advance; /*!< distance to advance in the X direction after drawing these glyphs*/ + float y_advance; /*!< distance to advance in the Y direction after drawing these glyphs. Will typically be zero except for vertical text layout as found in East-Asian languages.*/ } vkvg_text_extents_t; /** @@ -1468,67 +1481,122 @@ uint32_t vkvg_pattern_get_reference_count (VkvgPattern pat); vkvg_public VkvgPattern vkvg_pattern_create_for_surface (VkvgSurface surf); /** - * @brief + * @brief create a new linear gradient. * - * @param x0 - * @param y0 - * @param x1 - * @param y1 - * @return VkvgPattern + * Create a new linear gradient along the line defined by (x0, y0) and (x1, y1). + * Before using the gradient pattern, a number of color stops should be defined using @ref vkvg_pattern_add_color_stop. + * + * @param x0 x coordinate of the start point + * @param y0 y coordinate of the start point + * @param x1 x coordinate of the end point + * @param y1 y coordinate of the end point + * @return VkvgPattern the newly created pattern, call @ref vkvg_pattern_destroy when finished with it. */ vkvg_public VkvgPattern vkvg_pattern_create_linear (float x0, float y0, float x1, float y1); /** - * @brief + * @brief edit an existing linear gradient. * - * @param cx0 - * @param cy0 - * @param radius0 - * @param cx1 - * @param cy1 - * @param radius1 - * @return VkvgPattern + * edit control points of an existing linear gradient. If supplied pattern is not a linear gradient, + * @ref VKVG_STATUS_PATTERN_TYPE_MISMATCH is set for pattern. + * + * @param x0 x coordinate of the start point + * @param y0 y coordinate of the start point + * @param x1 x coordinate of the end point + * @param y1 y coordinate of the end point + */ +vkvg_public +void vkvg_pattern_edit_linear (VkvgPattern pat, float x0, float y0, float x1, float y1); +/** + * @brief get the gradient end points for a linear gradient + * + * If supplied pattern is not a linear gradient, @ref VKVG_STATUS_PATTERN_TYPE_MISMATCH is set for pattern. + * + * @param x0 x coordinate of the start point + * @param y0 y coordinate of the start point + * @param x1 x coordinate of the end point + * @param y1 y coordinate of the end point + */ +vkvg_public +void vkvg_pattern_get_linear_points (VkvgPattern pat, float* x0, float* y0, float* x1, float* y1); +/** + * @brief create a new radial gradient. + * + * Creates a new radial gradient between the two circles defined by (cx0, cy0, radius0) and (cx1, cy1, radius1). + * Before using the gradient pattern, a number of color stops should be defined using vkvg_pattern_add_color_stop. + * + * @param cx0 x coordinate for the center of the start circle, the inner circle. Must stand inside outer circle. + * @param cy0 y coordinate for the center of the start circle, the inner circle. Must stand inside outer circle. + * @param radius0 radius for the center of the start circle, the inner circle. Can't be greater than radius1 + * @param cx1 x coordinate for the center of the end circle, the outer circle. + * @param cy1 y coordinate for the center of the end circle, the outer circle. + * @param radius1 radius for the center of the end circle, the outer circle. + * @return VkvgPattern the newly created pattern to be disposed when finished by calling @ref vkvg_pattern_destroy. */ vkvg_public VkvgPattern vkvg_pattern_create_radial (float cx0, float cy0, float radius0, - float cx1, float cy1, float radius1); + float cx1, float cy1, float radius1); /** - * @brief + * @brief edit an existing radial gradient. * - * @param pat + * Edit control points of an existing radial gradient + * + * @param pat the pattern to edit + * @param cx0 x coordinate for the center of the start circle, the inner circle. Must stand inside outer circle. + * @param cy0 y coordinate for the center of the start circle, the inner circle. Must stand inside outer circle. + * @param radius0 radius for the center of the start circle, the inner circle. Can't be greater than radius1 + * @param cx1 x coordinate for the center of the end circle, the outer circle. + * @param cy1 y coordinate for the center of the end circle, the outer circle. + * @param radius1 radius for the center of the end circle, the outer circle. + */ +vkvg_public +void vkvg_pattern_edit_radial (VkvgPattern pat, + float cx0, float cy0, float radius0, + float cx1, float cy1, float radius1); +/** + * @brief dispose pattern. + * + * When you have finished using a pattern, free its ressources by calling this method. + * + * @param pat the pattern to destroy. */ vkvg_public void vkvg_pattern_destroy (VkvgPattern pat); /** - * @brief + * @brief add colors to gradients + * + * for each color step in the gradient, call this method and provide an absolute position between 0 and 1 + * and a color. * - * @param pat - * @param offset - * @param r - * @param g - * @param b - * @param a + * @param pat the gradient pattern to add a color step. + * @param offset location along the gradient's control vector, value ranging from zero (start of the gradient) to one. + * @param r the red component of the color step + * @param g the green component of the color stop + * @param b the blue component of the color stop + * @param a the alpha chanel of the color stop */ vkvg_public void vkvg_pattern_add_color_stop (VkvgPattern pat, float offset, float r, float g, float b, float a); /** - * @brief + * @brief control the extend of the pattern + * + * control whether the pattern has to be repeated or extended when painted on a surface. * - * @param pat - * @param extend + * @param pat the pattern to set extend for. + * @param extend one value of the @ref vkvg_extend_t enumeration. */ vkvg_public void vkvg_pattern_set_extend (VkvgPattern pat, vkvg_extend_t extend); /** - * @brief + * @brief control the filtering when using this pattern on a surface. * - * @param pat - * @param filter + * @param pat pat the pattern to set filter for. + * @param filter one value of the @ref vkvg_filter_t enumeration. */ vkvg_public void vkvg_pattern_set_filter (VkvgPattern pat, vkvg_filter_t filter); /** - * @brief + * @brief query the current extend value for a pa * * @param pat * @return vkvg_extend_t @@ -1543,8 +1611,23 @@ vkvg_extend_t vkvg_pattern_get_extend (VkvgPattern pat); */ vkvg_public vkvg_filter_t vkvg_pattern_get_filter (VkvgPattern pat); +/** + * @brief get pattern type + * + * may be one of the @ref vkvg_pattern_type_t enumeration + * + * @param pat the pattern to query + * @return vkvg_pattern_type_t + */ +vkvg_public +vkvg_pattern_type_t vkvg_pattern_get_type (VkvgPattern pat); /** @}*/ +/********* EXPERIMENTAL **************/ +vkvg_public +void vkvg_set_source_color_name (VkvgContext ctx, const char* color); + +/*************************************/ #ifdef __cplusplus } diff --git a/screenshot2.png b/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..7fe3694de97c86c23c3efba7ae5dd1e9d18f4a15 GIT binary patch literal 91357 zcmeFZ1yq&m+Acf^0g*815)lFE?hwJCk#3lDgLH=os3-_1DPYizbR(#Uh)9FP1Sx5d z?*E>+_S$QmZ=Zes?;qb8;~(dI4AxqcIp6nrpSa_?uj`)cp{nvNLVPNG1Oh=QcUx8s zfxxasAh6W&aNwPr6&I5b2of0|4IMW%q$j9Sx3dMkg_n&b0^#+&Aj!&u zrrqWK@c?Vt{a=R^L1u9n!AP$G(Itt<{3zlX#-H*+1jvgO< z*lSocmL$)wJim^;;_3YE7Yg^7o&INM;y00rmE*;gOJk+vM_J=WA;_nwp|$|s=et8} zX)6K0KI5ec`nbw}>Ld-rTKV`Tt*B9Axm%^x7%R!{2Nz%XuFotgig%=7ZX$_vd7 zk^LdVD9YHGflSE?FVx+Mrm2asxLuBeD`WBd!#f3GKU2PxFP4R%=91Q{rmKF&Ei700 z8)qf6^Xx61DH>C$du=8_f;u4RAJ51(_Vhc=k*~To^1eR!&5cf4ZfJWM%G@*5_yfb(MS_j+s*W)gA&Pi!cV0udaU@^oBJUBYI+=wHdP?*R@ zz33q>^LWarBtsZ~pey*yg(9w}EDHh%Ce!8jrUp$|g0)W#JSx15@g9z|9nBGF_&*33 z$Bd6L&hKu$RzYH1KQoj1W4T;%ca}RL^s?HgSK~=!q79D_)NAUdSHgVouVy}TVa>^m z^C1$MdFINgJ3gSmQj#8{aJ9Uw+b+8#Gs!NeuUE@=odXe>Gp(iPP_X$mJtbPq)06Y3 z|IWFaG&WOrZqhnz$nAU)?)g&s#nv*}f0vX@xa1dWUSY+aN3!boyICooL++KM#IHP> zA2O%-ea^{BIhqr&qN_amwZCoTdeLZoK)t5e&*zE0!Y)PgY2_HduvR}euewiI*k$pZ z_U=4Bmj~LcD!kt^cxxq2y_lZj5vQnJpQ}b2aV~cT!d_qgG!;FEp%; z6b0-*8Hmg6D0^o>e3j5bgZg%3NB;u8YkH5toJUa=aY$2y^D_U8ok?Kxk@88YXXZ?Jw!??5z|L{*R`m-l1h!oS8*a;& zJDaE3Uc_O}OeD?56p@Q(t&5jq?}SkD6b$YySJ$LowRqM%b{V6$ZZu=)ZL^%eSuNJr z8Nqxf5BJtkhjl(CeZm&m1rH*zwYwc|Ok-`FyO^oZ9S%)GtZGL**=A)MMF&!{%?53K z>acK@lXSX9!wRuJ=iK!FLMKHa*6^h%VWKsmsdqSgrnPt{kLk(2d++)Oy5)szGgWK( zQQtVXI0Z{}%Q!plbIn(#vCM~5v&8J3alDjSoIY+Bs(q+XxFhBieyzQt)j`c|eIw&J z(RGvUuRfQAjAfX2d2GkZw~F;&G;Y2YXvdekMq}-s! znaIIk5jT!Ze-_0jps;lpHNS3_b1`H;>koG%DxE;g%PPq}buKZDxP9cQ6Ljt<`$1Wo z2s_Pi)PeW)mvsd>j3qJd1LX;px@0(UiOx8JQC1uT;+@upy7C!#)IN6`$)J3G*E)UlA;^Q?XtD_N5zu!-Ti z6ziZ)WAY%+cgdx-o^DCTUHvudtnm!z-k#x?GTy`jc_%!~b#G*vZ^?VEY<1zrY$YwVfP;#d5vP&k^C>5A?c0cy)JrlZL|s0U=8 zMcWQFZI>NJZ1AXndxTurl++pBAYK3b^rATxrzK<0!_D!cc;|m&m-B2e^x*bBC=3p`rj+iiAaPpqDc0uuM$9FWNy$hA7x}o`%*g(| zFzbO+r_*qn(s7$t;yAlgr{2#uFN+tvBny0Zo&M&TA(`)%*=MT_xEu2%)k<-R)-wvu zT!^lzV8aUI!osX=&Rf17KqWQ}vtVU0K10#a>w&5#pR0ZXpXJ!!L(el*C zzAF}cUpd6`)m1aCBIqn#7ZZPkEK|pWD_V;hdF@|u11}y}wY~^zRw^_$=+a4`NJt7M zadY&%ThBMHcWwXl2ph^>P5gUwyoAo#8axd#nU^u%6K9&)tCw67)qb#H%q;#ig)%CnSXyW`HX_W zZX$&}%Zzqf@BOdFAr9xB3|i({tBVlJoq2+PK~Ifj%4=4!CofVDx6)9k$`WVW)UMos zLR~k2;cEWucTVhI>4K_3(;i=_K3m^TDRg|Dtjl#_rSRTkdXsd#B8F|NON9ke55gI* zjZku*%AC-!3)yK^l%le_BuPh?f>BP#XWM+fuA5fAJZRT50o!P zU@^T@;~l=UiU}J=2J&a`L&-& zZV2{WB$_E)-{U7w{bCn_G5)JHk@HoElJeZpr)JLCzAg$Lg=Lc!M>ZPX(=(xY=6Chf zuF6OVM}HG}cqRaYLkmO8hwnW@z>^yBM*PstNU3YPG?eolZ?`z@CZuHiOeCJ3eJtmq zLjB;)Ros}tqniU!*;y5Lm~q+tL%-UXmZi{~#tIobJ!L@}okM>1oV|CZ;U2d2HyO4( z%*fTzyB@TLg32Frg5G%`aP7Fh)zrhU7yJH9dRnGe5`C86JaF|Z-Q9zM z;Qi<~Iqx%^cka&3Qic`TJ5mNkp3b@EF7iD7slyevJ;b94|CkpE@!uwu6{xVLChl2j zee|C9z$*X9GqxlUy8e>D52?T#!)4=$zx?UL+g1tkiN-q@a=oy}J@RfpR`0PoFDY~Q zlmNS5k>gqTBd4H?Y(YUX5vK~zQ9Pxc&+gr-u*l}nt#|8s>2kiR?@yBE(%!Y+$PZ{CXA^6@gcrZ+y zCb;sg$h`YKN*+@!=b0kG2X=u8{gSI!^!3@vd-e^^B~MMR1zlo$b@t`g-J{oy)icI)5A+tE zR@EzP^VPN7{gYL5U#y#&xNjjUHXR75U z7+rPm%l};7jOwABiA{{~iV2c&sJiJ=B;K5Md3H2@M#^)?n26*l&sHz@*|gJ3r}{CA zp2?p*e=4daD7vuljF+CPI?bh0dLG|f2%SX5j7!gof4+WiBJwSz={ny)&|uKot2eJ2 zZTs6Z1>TbBaClVFV&JytRqQh8vh&P41b1VGshTtOUD2OEo%OCZMb_k=-j68pIKEVs zwuemgHL)_1TsAM%qHQ|7KM5eJkS5q-3P0J;zhlRUeX&FR3IE{bz_+Qp4jA0muzS^K zBiOcTM7G57o2B~-wV$4A#Z_*`jblf+@Cs@sVcN;x*TQuf)RegT!9A(#siks(nB6=Uu zM>C%iQHw}DlOu`Yt!{y#hD8UVq_EtM&5GIGei|*zt^*kuMdNugn>C>$5!#GLQ5}*YB^eHS_k80dRp}~G@58K|qXdHqU8fsJKaRNt zJ>q6x8|iU>FFHl`t~5{j>?PXgG$-KS2X)v5!+74s9p0Be8U|@kGa88nH!ED656bBF52YkoTUn#5kJ5Ds7M!CBqbsA!DOt)XwBrmzAt2HulhM?EPWB-f~7awwO zCyM6*J%h{q#KYGr#@FwJ-r}X2in-h&pZRTsooZ?4{+j2ugtmJOb0Xb6Pdd_zLH=u6 z+4$*U%{-6NB|WCB@1lYuFF^N#kk+YWapK=<)@Xi8MjsVQ6(n%KLNBF)EQjU?(djpZjCZb-^gc;_HAAv= z{owZfJI20uZCO}D{B1{M^(#Oa_a1x;p$NvuZ^XNo-bc5XRY{ifC`{tB2OA!-Y0`XV^V7N%TPqKbhpl(y zTP`O&;Jr719BI~3LCDN9_I+9MP-r~FEwb6i&iHVXHnpSu`%+A7aK?=*Ce~Kl!Syl3Y)CcY8MA6a4< zw2CfU`r6;DRFSY_TE0tgFo$Q4w=X~zEG_6oqp!vyZ)s2#T__Uu|uWtoWBjTRdqz>%w@Do6wDkq0{SQSm8s8F=-h+dxpMA zEF^bIrhM}(r?Xzlg9wt<-o5KrX9jLh6bF8O#~NK#g>!|n&%=7YNn7G|+I+@34wYlG zgtkkaZ-C+Z)RP|BW3LNo=`@}WrOOUqpvSp-+gsYsM0-7)^oP(U$%n(Gm(SwV z2q)u$?u{V`o#S7tbJ0CWj+rUG&{n?x>CLI+@T5=?tVef@-y~N)UUSmBY=L8}t4d-U z=F`f`)LpI+74-hGL$9vM!Je9}*tLCCUyVC)96{!Gp*7eEK5K#rz1e34B*yB>FeMW9 z9$me>U+3oCr)_iX96muFu>kQ?WybT{r61=vQm(u#RincHnf3MlxWwJ|kxvGyY)<@* zq@O(SiyCM!-sqnth-WVAe<0_rzu|rk+gR5J;f~u?`sUK}LMNstss2bVX+;Hxz)hu1 z3bM~1M5vSRwE3C8uct;dUwHManmp~1osW6xMxEDK(cH^-!A-A^@LbYGJh}dQ3HR^>Y{p`WK>b+%9m4)Z{j4GzDNlt@3OgMg^veZOQOGHSLF5wFv=U8Pp4oq6}S$j>SKHPEU5Z)=#ad*Dk-}g@QEVk6Ok&zc9hUxE*uY{8E z(9vv9j@Gx1ie1Z&Pq1`@HPKYur_vA)LF}Km-*TgV$-q3TL&ck{OTiq zv9GuWMj8p&@iZ}?@8oUCKkIZ>#X*bU>;8MB)>F+Nu0QU?a^61pfq z^)~Mx+$9N4W*JX(-}OFVet0=IQ@!D-hwgOU2VFKz-SyOi(0BO_Z@;)F$viMSr|^{i zx-{vHXR6ZAv{FdU$bFCU-od49l;sRHxWVnh{*r+3?IiAT2x?TX`r%!ns}xwG#`gPW z6nKl6Pm&x0FAjT5Vy{YJY5TMr7h?6Kr4Q)oP2v3<#^Ef~PkM`Mu#CV`3A6tkIhA#F z%B5+a(qA11ZxnOX&e5sE|Ai#t>OAXREE*cj%if=jw!J*HeVvX|ZML?tqUBslHC&id z5D4N38{l_!loUnHoE$ij=1!&-oL&yj!2co;;!ORUEW+5;r>u1|20;dKo7d3wnM|eok(V8(uaZybO}~^x`h&mZEC1H~$y{{*qv@ zc5`zU<>K-L`p}b))5*n(i$_F6go~S(ic638}aX7kOMi23O3|R|TGZ!0Y zHybBMdi0n`Qzv&f2?hrEoc@o&;Zw64Uhw804?zEYGQ6vsIhP##!4KxrI5n zc{zARxc+)Se5$1M=iQF3f9xXcCzlt}nTv;$o6EuBZ+E!5-SGJ5^Zw->t{OnIbE#Rl zI=Q=;S={ijaCE!;*M~aWySx7NneMI@=(kShZEtSL1(P~?@?Y<{C8wnN=RN3cw6bw< zKDh&Z^p!)wkXV$Na4Cm_JVFCfgz zfwZtN06XN4Zh9ERfMv*6=46SUyq7eWei@LLF3 za+sQN!<3Nx=E6u}0W&@!!IPoT=O8MrDks6f%gO!EcU0|>ZkA3i4iXHCHjeII|NKD1 z#=%0}4T;_~9zi}4L1BJj0Ui-vJ`rKQe_o_z;o=HLjvkYTo0FIK!&*dTTr7}oPA(cwPWBQE=(*CPhdgm9dhtJ; zMO4wr?BvFii!IF2{`QB*T}N7Ro%|`z_3tkJ4VDm;O15w2PaklZ%~- zi;AhOg_+yGALn0P{O3q&5bIpsT)gG}7mNBIt`q-luD9V{Cl~L(JYU`7?(e^T2PAu& zldYnsKM4Y&NVDJD?~3%WFh4m0*vH==nOP$ptt=qg{^4r>c;Dt-M6iR&h(bOU#q;4BG(uU28T9D$%m$jM4;czs_S^>=1; z518Fm(d-YASJAwZvyrcMx}2Z?0o^S=p>w$T+w`177t9Ds33$juxW1Px{z$m;fP%}Q zllP+#56+4b-&hOL@BocW=~0M2E`fcqbdk`Y7+1yQ;Ff7qDPCN_v)ptoxs14ZY1Teh z&9RG1pYN2XFXQx%s?8rhqR)K(`AhdfZo_8BK`&P+jq(2X0YwZ%ar^Uji|SEF988$` z;N%Me4EQhnEZ!?V^ZQlBgr1&W3?r?$*VC@w?=%&D{KEPB8!v>knE|k#*EzC}}#S+}>sHV6#T4ca!=i{R{IXOvyQ+%e^ zR^aepRti;Imz8x33kxf)_K2C8`HGx!mO3phEq-_l0k3n&KCk=fMb2G6qtepS&(kiy zeCnyFsA7;5bzF$rbQD$CtFbYo&5aF%&8^Vu((CK%RFssjEFB)eH^w9f5ns`cjPdkoPJ7<0 zqgOD$I8;hSL7_^2R<%S&gEvv*)~!}TZ)3#j?n15(`+RSXI)3PN7tx|+%!qI{SlHC2 z59PISoa!<s-!AIE=O)u(_&x71pmAnqrVJ(`pYi(Z z*RNp>%g(~ReSJ3?aSAVmx1fJ}_=P0MJ*o{JeK7rO&Wn!|5<_L>VW<~Q7Zq;Q(0@MZ)ORZ%mjCF(YsdOcE!ZC=6_wcQSVEsZ zfBqciQ@1;l+}GXxdT2)TN!nrP=^CL!R+`Qet9s=d3yliCVS6*oJ>_0HM8c zBVl+8FM&)L(q5R{(ZNBpK&$8d`}-u?OWqwcvf#hzzwYXR30g^h63Zld+C=xS?g1w=%0CMJ*~ zG?9eEeOWpKwgMerzv`v2<6>e^hP|q&5X>tqD&s;7o0Znoxy`uMe-%<^Cle}|=Zvwk6V1;W>z}aDcX>c$>OG}GiN~)-^ zuu!Qpbkwm@(=PbhwKcDUTp!MQzio!aw>gSTW=ca}%z44;v?e*oBKjY?8ylw)w0s*M zf7$o)OeiK6-UvcTNePagaFa!@%UUBOBn0-&*2yWpWkNMWZRl;a7Aq;769*R;+gUs~ zB;9S!gp?GA!2ypkKk}x2*5{94gTN>>^ZK53Si){n&wC#>R^}p!9tAIHHxlq9DmqqK z4P*#Z>K1)9=hZVX(4aqC99Ldm4#uooqNCW-(z0PUPUQm5wtv_!8>yC4HeoQhu&F1| zP*am@TW;&ns7c%1?kUvFnXDuAp?kvlXPmy{9foLC*5_{v<>Jz3W-M>KxwDXJ2=RuM zEMjk?M+K%az2;Tsgp$M|sglMWt~MxqMYq4dZ$S}OQ&ThLQCl$Ax#{G#xUy0?kD7DK zg+Kxh1Xhu#cr!LO_LrA91TJ}|Sn4hJ>SPzponQXm{)ROMoZjMeO3KQ)Z{D=*RU36K z*!h~9%fh+53d1m<4nta_8vK(|Qu@Apd7PA##4jxD)mQIhYI=RhzF$wP(MtR9=1_^w z;{ZYfTnPz@{*qrAv&{jG#&d3Z@JM`YOo$7F?*2CDwMyM$JkN7Q7e#>XABLYrE#w_o7gRsn zA%rqN8$|o#RXCmLSy)w&!~4JFvH{NR9}!%(Zf+Zo7HGvh6epZ_l9n#ksxzMN!oBF{ z{9)6_*LSmxInAK-5DO7RZFYQgXlrZxy<{KD*Gj<_e4N)^+2zX_Qdq<9R<_wl@N;r<f&_Tg2~Tql5A~k?r3YrL-@|VU=qJY9o72g)vHUJTU+x7yX(fbY0N6A>5)h= zh)}-{);sOo+%%?LbisMK>NjE_hvlPC0sBin^Ep{l+xzZ6-k+{N_|=}P!3s9!v(a_S zeY^<+f-%*g+wMn0yiSXyQ z88=p2h!>)cenw5Lc|C(a-(OJq$#wLDtM~i&+!g;7-@O9V9tRFdQ>sRR)^quc-mWer zN9|I@@Wzl;nr>R%_V#w3R$kk}=I133J9~S@n6l#HZ>#GdIzi+W5Ef=h>&${Y6&iZV zf)|8sDN}S$IhPbfV%%A6hvzef{L- ziPf-yXb7C}>G$v7HS+q(%F5EukaOOS8F8%K+uuj0Bir)a-Cgg3{Cs}#09V)2u<&pJ zF)`l{qHA8_$qoJWMn#ai1tcU2{3M8PmXqGsr&(TEso%b}G@Jzi z2a+&sA>=Y$zN|W=hDcS>x(C|?dCmdqAH`KiNY{k^@<=mHP!?j8n69B%YHYMtDJZKv#& zNDpv=Nfk*Q_DJ>~=WK@6M(TI2~^}EhM83 zG94QaJyIlmwI0e|Z``tL%v@W$>pw}2GEv1?Y;(SJ63z|pj_R;iOz=j2{i?iR72fiy zq=cuSun^*??mOumjko0WIumSdV}E{xKWCT>rJ9?8AC%uLZr5xT^?)}KObM|rDru| z$}nw)=udG)o3aeAoQ3oGtiD=1JFDhsJbHP?Hx&-k*VnhjBFL&UwcM7Sg22|xOD9V? zCB|*ds0PBOy1KenlOb`@LZL>)hS*}R8E;rqfP6;GnD;ELNXpl+WTJ+(kJONHdVlLD+0zKi7PZj3r)dT zNeKz6+!Vdd&CL~c7i&iyIoR2=^$Kj=-8Es}!PlDfn4@oJYp~`3l(w)4r4D%$+&-;V zpru}}SHI|!Tpu}q48aEi3Tea*4i1jCmF;%e@X0k6x~Mz@&O8m)t8`KN`*u!F1F)3W zUDh%z<(er5bL9lKtMo?D8#My_VyS~<@?#V zsECM&+&)`?etL$6hu8hX1Huh^uqZM2tG35{-H#8^v94{pW~Ub?M0#P|%-JI=MfF=raDM3#509p%7$J<%Ncd=Q)vew$ElGe=V1x%68Sj49W|V^z-(M4b zTXxOM01`gzfKiclrj6e5sB5PL0ZWiXMgZ{zFukoU53raNN&oLPvQrVxwW9!Md6jzf zv{;{05v>k{QCmm%tawF0hVtD0Y2)PSHXP8a3w zIO|evPVq5QVC%*n(IHXoDP+9T#`g9?^ewtBz~_0^{NUvIZ*D~i)}6k8{ZfjU=hr3kPU!i2~dIlxrAi33)#>es)Di8_x5p+NyJZ}(~kC+tEcDxj9}D%F$R z#ztcq8JYQ&m4V&$*@7^9gm0ov5}XOTW>HXx_zg09b|cz0!jL-53-McHn^M1v12*fY zoB`L5EtFY`E1`7L%+uUGJnHnXR;f17sy66vi)9w7Q(h?LexW>@`K||02|5anjuw3Q z@PVygE=Qwg(QXvL4@{uVTy1o86f%?civpa%`hh7I5yL8HX@7tJ&z7ZthUS-+%9ow2 zk}@3|b}dC{h%{NBE7|3%ve;+u=PikW@3|R#w7#&=DF2m3;^&oHS3TzPsqdCYTCxOp@GtXF4n5I8gMKb5Z2efm{J=ZqsN;_yv+O1 zx!Q>0YT?#kC%YmC)g&NiC`BC{9MI@;4~Caa>)dNHIqZaL6#jxd4A~eyhU5tAC*UuX zhk^i#xV^nS5&|eOs;A(0dtZQ?+j+=geYfuO^jp9a1xxqdy#y$!!9t?J`W#)ERt|GO znm#%@3LAh*whTVL{^}d)!jyc`=Fw3A6ecNBfktd>Y}yCI!S$xz-nwA6@K_ho6sTzW zY&F4nU#Z@vi)ziC)hoz^{S!%1hK!R}P~gy0)A+qXrm;o2^$TZmLQ+z9?Mg%52 zP`(~+qfo0ILd?o9zVUU6zqv;L@&dE+&w|Ra7@H(fm#GItw4&+cMqbk0AE=)IQc7}j*qsd-9$J0 z^_}JbLiIXSjxx#B93Sm(PF_4tkUmwMb-x7}+Ja2X%z?PGKHI4u?+lTPkccQZFHZpw z5~0vqgY(2ausqnomtNux6SLqw!NC|ys77PhU1VcZUn+q%D{1KUON0aj=pgCfu#~&( zOB(T^cX&7tQkERL)*>S#Gf&DCX!rH=GeB2`{vmJ>fOVia7SiPt;M8W;ukVMF7gE35 z-iD1Fxl;+ZpkSs6_uwjFY?F~jqmcF?eyRp*2E@i32!<9GACjsyi-tDqtxM^18pfti z96j{%`G*Ocv4#lWmSm@fHhP5Edl_Ph_w;BaJ^Y}Z;y23v*VuadPc+V5`VSW7|0=Bh zKUr)O(Qi7betJbERlJQJy@yRGS03zIsCv~!Q{q}DyC93f!3j!8r>3P1eENikg|ql$ z&!cv)>8J&n|h}N-TynLC#@-t{ALH-Ib3E65n z);2aaJ;ixBIS*q^n{YNqhlb>ou*9wb`1sh`s>x2~4nW1--MwwjZLGKv%@KV`t^$tW8X=LAZeQ1rg&n2Lx8ycW_V#p+G=LC<{Cm&>3L# zUB3pxc2QALlBm}5vNA?sY~W3(8qwK2PZO|FSJ$0X#JK2y=PT8x8xe_ykQE^rK-u}u zfBjb%m!1q5ttZ9nJk z>pNCwOw2xf_)rNYG|$%n8QD)V4REYxj)oU8?6vQCDK(La`QibK83L* z(*}S-V4MSX3`nkiK?s$9vMW8GK79(a;EY#*wN{S#E6#bQRWn3ut!jLYns6h0`x#5BhL7f zY_zurF6~&mB$%glMR%A4pbi(8P_M(STj7|&L2%c!vv65e)!-_SI~7MnauA`l{4a`o zsb<=+K9>h{lU-UGyA3NWW_TgAHW$1(W{Sbu{&~P+3u-$NYsT z+^oj}<^d1{elu<4V{-d)!SaM}<2ai56B7~&95m>#v!2EK#7zMF6r9>Tc@@!oJaIqZ z*u0OBi#6jRXv2CTCqY7i=#Bn&H7A`%0cxhZh8Ex=FoTJFR=tqi08&HHhlsa_x|7$( zFD8~ZJ#7Io9nGFXXoR>Q(AYRp0xQ@$-&|UO_Ir1|Wl>Et#gR zq7qfEBr&eH(rxjZt)Zf!DI@x{zI%{4j9JyNS)V$vpb6-P{w(?sa{E{}&y3J-Qmy;c z>lqno0cz)rkL{Uz1{VQmVq313!*5@zJ1S3(#nr=K5M+1Q38PXUg+T!ZjFDkOLYp~Y z`ijM4n3~5e@GYoE(CN$7)fH$Opi9AGz*n^Rsmhm!0Ef+vIl+-;r3C<8!y47vawri* ztBQ(G9oah!0JjA9MQ`bnhk9cZQTC`J)0?(7IdBTd8{j1N*?nxAqp(*Uot^CfN9yYh z0ggb4TNbbdhH3E_(l^xAXgE}^r+GsA*jB|~gdk!x^+1*((``+Xc(DH0ZXFppIhg1d z6EKJt##lLcFq%3=Qz%UWC){_C-PB~1lvcSO&{bgKcv#@-&b0rG))VG@ejlOoE3EtiVgKLiiAl z59+HwE?EdFJ~MceF6tK8!mi(#9&oUIy}j?pPiE^(3*^eMuIkr_D?n72=WFHZwx6u9 zNkCG_3NL6$J+F_^uE zg0DJRCC?dVvJHh~(u)_*7y(oNh7Ek&O+;Ws?nejS0L`lnIDuTtMW+*N6Y_zL#l?J3 zlYa9$z;D$!;CB5MrI0U!9h_&rP!bXnqDjCQ$Tsf3rsPgE2Vt6lGETFS1TY$?A#reV z`}+GoUcmH=G#iN__5)%Q&3J%AIvy}jwcGukBs+OyzIn9FU{I=y7tt9X*n~e-sj|0k(S(}5Q@tjb0!UI+baWLJYd-Y^ zf~!{m9_PjN8@mV#3lFNM0l*^MtnJHq03gTA%q%9o)T%Q#BV#%jbzy4-RRoX-q^Mj~ z7M*>J)m_`~lWX=m4Vo7@N$}yZ@lY{(F28WBnad1Q@t1k^RIvwYTQ$hIK#P=jDpa~x z8*Dg?y8;wu75>fmx{QXKeP0jy#E4u_?l zUSTA8VesA+1z@p2N!H>uXk^bVC{O}kh_!j|q0`|uI0+c)UlCr7m-kJ7YJ@SciD)Ky zb0q|qSWoG0>0bVTQ$5qdyi{dbna<|i`YxV<@(Tnwz)gcFT#(qW zott(2RWVZPgoyZtUsI^j@;97XKxv`xu;5Wky=5#lRD_~FJD4|H@1ExOt1a%(qx5?L z_$W95Yyp6q%6b*`Nikw%e22#0B{?W#1WEG$jsSCkYy$oQn00GX1Ie^mY>L5~AT|Ml z11%6RD;mPaw^Prrckj8^j)Gc>CIT%>K}*+?VJC~ws&^D@nQ~b<4ciP@Qv-~^*LS~S zRES{EPQY*_XH(^|zMdZEaQFh$8&DpAsW8Qsa5`ig>)oBJS?H<^=F+YVL;lQ6cC5+u z(KF6luqzH|HfWUiq$Th|J_F(#DFKcqXFLdX7D+P}3&-7u11jUm$;nXm@4Unx{88my znyL#*!fi%0xf0%Tw{O_c0Ue&004Wzrru6(v)sC7o7}f?n4n%tZ!%*kMp;om2hE3}w zgB&a=!q7ZE&=qWC5fI|?N=wlY6Lvw%-$<_!*hzpIAj(0hR7_>o`3{^doW}HD9Qj304o*0)Zz|gZ^+?u#?SlP@ByhVmmAg9DICyD)Nzys3Mr69SBOl$)TmC zCD3N|`;RmBi%^}+K+ev&!R>b^?H0Y0X@#6DA>;u#gKJ{aZ!1`#{4$vO8|p1S1I}paj>b<-O#j7VqJeg;sfr5mn^TKt zAIjd7KEX657YaK|d6@^Bp4?g`062bFxAP-nuT3T3wd?FxLyvm1*2uYAQhU*smX?KW zM;Hk0sDH9BoMDKj>7By>bR`dEo>m@Idh^YpXP{f6`chygl($d`Gs62<(@u6V^m;J! z339qNc*?{M?T2%7T|o5#Uk&!Ft{w}7-m~^;jT{ZfPbdLCzBg{798kfJjTu3{p96|O z9Em`TC;1%h&I*W%qA6gYvf_<=2Zy7kN>t5QyJoj8j2&_lwUoWzI`OCy6!`WpPCy9XdF4?0JJc33*xV#CrROO0E8b zIMxj$TxO@_{ulf9?3wYQtD~=w1QosZFp-}TzP45A!KvN=> z(1yTxe(2X4IT;y{4R(`(2y;vqm^DJFx z%&SGz!~1Y^U^8XK@76`X)nEW*n_u`kVNq9;JLdn;e89lRsV*&I3cnjW=y*4+R<2hr zne!|i%@G1G8bk8rX2HG(I18jX^c&#u0K@>FfQ|zgDEQiVZgU}|Ftr@>!`jM9&z@o^ zd*D|g20|jl475yUxV0ABmJXnRAG&5>i4h<0Xq;uvy~S)=c3G+4o%OK+u*vOx)^6x7cC0pN*a`dL0@{+0fsYQb)4jcJno+ta6@RhH;rcnBOEW!;c?4=IMQF)xrouTpYEuW?lCBx&3M z)yvg&o%ABQ4+EYG2nO8JMpziCp{f^|nM_cjL6~g&|0*otBL?vJY7zF3*=zt-f}|0X z4n0}WS2Ege#|KE^x%`KkgJL*ckmdI7m+G)Xdxs2!QDFF}mQg)DZ~P=72fa#7 zrOW77rLEgeHUs~h%V5hh5lb|^z#ykN$WdW~BO_=98`KiEGGJ}`VTyoT-wx&5mM4J=ZaO@MJ@2m+wdAD)In*IxSqdyQ zt&@4~$CpBYogks>peU;QCM&^WfCvSPK~pF_bG;B?&p&)mDkEURJb-2pf^L3U#B|n8 zRGfK>`m_Uzjlh8c>vMhqf%3T;fVfs)Uktez1L%%F+`1tbKYHX6)%f8Pr4jj-zy zfOGM8=#*f>H}Ws|^Kqai#F{hWWlrkd)f@k0ZT_ef^}W_UkV9DZ`LG#DE0*aj?ANhH zjHvSYS4@sjHahhM<*oh~bWfn|>vub)L1;@ju|f>&?O&ySh|i32o@3rwslLl1cB9ad zqUzMJn+f4IKPTs^#L>yglC2Sh}{ zv{T($7$Cv&s;cY(<3K~tQTKRs4}-99wziS?4S?i;??eL*s+OxJiEz$Cn6Nx)3~JK+ zyQ1sG3g`=-cSVkz)1bJ&9t0XRXN@0<<~at8e3bxi!~h|~FCx+wgxMr;{ddce_BSx} zTXf#CkbLqXynzA}NhiVD!kzC98sFCxF{?u{D6XI&1B?_Uu?1PxoE~Fb6n%E^Q+4mZ z%$s4faePpJHkNBw=08PW1{CB2dNnk23>SYz`xHcama}+2-#@(Ivrte8?h#2N@>(XG zXfBl8=qaQB>N{MY%|2~P4Mf#Vnty;JBaaW@;AnbHQ#Xtk78&sqY%YLj?Ngk}q;E*B^dwjr=Zr!W@mC$5a^|%X& z<3E}%lz~UlYe#ua5<=Fry?gggQR7j~a?JuKAu%zUDl4k{^#~#ll-cNIjNWafC16A# zHmnd$oGYh%r+I=m6NW495*=Jng#)cea-}r(6x#Y56kbM`$j3rOJYC z$E@G_ZU>Zf3?oG6lhjxhoPbI6Ep4t7aY(swkE`d*)@L)!DMah1%09U4Z&rkxWOcB0&-Kl;v4x&Az7q_3^F4eC#pNUBalye z6HyBZaH&5#5kXv$0N72!k@&*D&zZc{;&Bsai^XHaiEo+M8GQVMb^pJipYh+*ng(fB z(-4Ag5)_}Fr$mQLlUx5FeE)n$`@eXB0IL08Ws~pbe#?2~n%4U{!h4%6y!0G)jE*u$-OyY}dfiZ0pAHQQk!Z zk6Pp7xyHtw0M$=(i^h#_8jl)}JlpswH9%aPU57?n@Zs2jg}!g!oMT(Sb|SeBOIyR z-0$DoR5{!2t|73Vz{x>C|h34u`ifiLk=&v0>4?GSI z4(Jwu@183%71<1yH_U41X`)-+0Pz5v62H_$lt0@M*>$?c0~e?ZhUAXFv76e!twCUg zdI37=p-TdQGqjIih30%{O@aggB_xdUM-6LjeH+?Y{-GDEc5}rnY!1t-WvF$bnax(6 z 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 JR$+QM?teEp6g~g| literal 0 HcmV?d00001 diff --git a/shaders/vkvg_main.frag b/shaders/vkvg_main.frag index a9025a4..f4aee07 100644 --- a/shaders/vkvg_main.frag +++ b/shaders/vkvg_main.frag @@ -23,7 +23,7 @@ #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable -#extension GL_EXT_scalar_block_layout : enable +#extension GL_EXT_scalar_block_layout : require layout (set=0, binding = 0) uniform sampler2DArray fontMap; layout (set=1, binding = 0) uniform sampler2D source; @@ -34,10 +34,10 @@ layout (std430, set=2, binding = 0) uniform _uboGrad { uint count; }uboGrad; -layout (location = 0) in vec3 inFontUV; //if it is a text drawing, inFontUV.z hold fontMap layer -layout (location = 1) in vec4 inSrc; //source bounds or color depending on pattern type -layout (location = 2) in flat int inPatType; //pattern type -layout (location = 3) in mat3x2 inMat; +layout (location = 0) in vec3 inFontUV; //if it is a text drawing, inFontUV.z hold fontMap layer +layout (location = 1) in vec4 inSrc; //source bounds or color depending on pattern type +layout (location = 2) in flat int inPatType; //pattern type +layout (location = 3) in mat3x2 inMat; layout (location = 0) out vec4 outFragColor; @@ -65,19 +65,30 @@ void main() c = texture (source, uv / inSrc.zw); break; case LINEAR: - //credit to Nikita Rokotyan for linear grad - float alpha = atan( -uboGrad.cp[0].w + uboGrad.cp[0].y, uboGrad.cp[0].z - uboGrad.cp[0].x ); - float gradientStartPosRotatedX = uboGrad.cp[0].x*cos(alpha) - uboGrad.cp[0].y*sin(alpha); - float gradientEndPosRotatedX = uboGrad.cp[0].z*cos(alpha) - uboGrad.cp[0].w*sin(alpha); - float d = gradientEndPosRotatedX - gradientStartPosRotatedX; + float dist = 1; + vec2 p0 = uboGrad.cp[0].xy / inSrc.xy; + vec2 p1 = uboGrad.cp[0].zw / inSrc.xy; + p = gl_FragCoord.xy / inSrc.xy; - float y = gl_FragCoord.y;//inSrc.y - gl_FragCoord.y; - float x = gl_FragCoord.x; - float xLocRotated = x*cos( alpha ) - y*sin( alpha ); + float l = length (p1 - p0); + vec2 u = normalize (p1 - p0); + + if (u.y == 0) + if (u.x < 0) + dist = -(p.x-p0.x) / l; + else + dist = (p.x-p0.x) / l; + else { + float m = -u.x / u.y; + float bb = p0.y - m * p0.x; + dist =((p.y - m * p.x - bb) / sqrt (1 + m * m)) / l; + if (u.y < 0) + dist = - dist; + } - c = mix(uboGrad.colors[0], uboGrad.colors[1], smoothstep( gradientStartPosRotatedX + uboGrad.stops[0]*d, gradientStartPosRotatedX + uboGrad.stops[1]*d, xLocRotated ) ); + c = mix(uboGrad.colors[0], uboGrad.colors[1], smoothstep(uboGrad.stops[0], uboGrad.stops[1], dist)); for ( int i=1; istatus) return; - _flush_cmd_buff(ctx); - _wait_flush_fence(ctx); + _flush_cmd_buff (ctx); + _wait_flush_fence (ctx); /* #ifdef DEBUG @@ -202,10 +202,10 @@ void vkvg_destroy (VkvgContext ctx) if (ctx->references > 0) return; - _flush_cmd_buff(ctx); - _wait_flush_fence(ctx); + LOG(VKVG_LOG_INFO, "DESTROY Context: ctx = %p (status:%d); surf = %p\n", ctx, ctx->status, ctx->pSurf); + + vkvg_flush (ctx); - LOG(VKVG_LOG_INFO, "DESTROY Context: ctx = %p; surf = %p\n", ctx, ctx->pSurf); LOG(VKVG_LOG_DBG_ARRAYS, "END\tctx = %p; pathes:%d pts:%d vch:%d vbo:%d ich:%d ibo:%d\n", ctx, ctx->sizePathes, ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, ctx->sizeIBO); if (ctx->pattern) @@ -982,7 +982,8 @@ void vkvg_save (VkvgContext ctx){ LOG(VKVG_LOG_INFO, "SAVE CONTEXT: ctx = %p\n", ctx); _flush_cmd_buff (ctx); - _wait_flush_fence (ctx); + if (!_wait_flush_fence (ctx)) + return; VkvgDevice dev = ctx->pSurf->dev; vkvg_context_save_t* sav = (vkvg_context_save_t*)calloc(1,sizeof(vkvg_context_save_t)); @@ -1098,7 +1099,8 @@ void vkvg_restore (VkvgContext ctx){ LOG(VKVG_LOG_INFO, "RESTORE CONTEXT: ctx = %p\n", ctx); _flush_cmd_buff (ctx); - _wait_flush_fence (ctx); + if (!_wait_flush_fence (ctx)) + return; vkvg_context_save_t* sav = ctx->pSavedCtxs; ctx->pSavedCtxs = sav->pNext; @@ -1134,7 +1136,8 @@ void vkvg_restore (VkvgContext ctx){ #endif _flush_cmd_buff (ctx); - _wait_flush_fence (ctx); + if (!_wait_flush_fence (ctx)) + return; uint8_t curSaveStencil = ctx->curSavBit / 6; if (ctx->curSavBit > 0 && ctx->curSavBit % 6 == 0){//addtional save/restore stencil image have to be copied back to surf stencil first @@ -1171,7 +1174,8 @@ void vkvg_restore (VkvgContext ctx){ VK_CHECK_RESULT(vkEndCommandBuffer(ctx->cmd)); _wait_and_submit_cmd (ctx); - _wait_flush_fence (ctx); + if (!_wait_flush_fence (ctx)) + return; vkh_image_destroy (savStencil); } diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index 489e592..1b0a468 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -247,7 +247,8 @@ void _create_vertices_buff (VkvgContext ctx){ ctx->sizeIBO * sizeof(VKVG_IBO_INDEX_TYPE), &ctx->indices); } void _resize_vbo (VkvgContext ctx, uint32_t new_size) { - _wait_flush_fence (ctx);//wait previous cmd if not completed + if (!_wait_flush_fence (ctx))//wait previous cmd if not completed + return; ctx->sizeVBO = new_size; uint32_t mod = ctx->sizeVBO % VKVG_VBO_SIZE; if (mod > 0) @@ -260,7 +261,8 @@ void _resize_vbo (VkvgContext ctx, uint32_t new_size) { ctx->sizeVBO * sizeof(Vertex), &ctx->vertices); } void _resize_ibo (VkvgContext ctx, size_t new_size) { - _wait_flush_fence (ctx);//wait previous cmd if not completed + if (!_wait_flush_fence (ctx))//wait previous cmd if not completed + return; ctx->sizeIBO = new_size; uint32_t mod = ctx->sizeIBO % VKVG_IBO_SIZE; if (mod > 0) @@ -348,17 +350,25 @@ void _create_cmd_buff (VkvgContext ctx){ void _clear_attachment (VkvgContext ctx) { } -void _wait_flush_fence (VkvgContext ctx) { - vkWaitForFences (ctx->pSurf->dev->vkDev, 1, &ctx->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT); +bool _wait_flush_fence (VkvgContext ctx) { + LOG(VKVG_LOG_INFO, "CTX: _wait_flush_fence\n"); + if (vkWaitForFences (ctx->pSurf->dev->vkDev, 1, &ctx->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) + return true; + ctx->status = VKVG_STATUS_TIMEOUT; + return false; } void _reset_flush_fence (VkvgContext ctx) { + LOG(VKVG_LOG_INFO, "CTX: _reset_flush_fence\n"); vkResetFences (ctx->pSurf->dev->vkDev, 1, &ctx->flushFence); } -void _wait_and_submit_cmd (VkvgContext ctx){ +bool _wait_and_submit_cmd (VkvgContext ctx){ if (!ctx->cmdStarted)//current cmd buff is empty, be aware that wait is also canceled!! - return; + return true; - _wait_flush_fence (ctx); + LOG(VKVG_LOG_INFO, "CTX: _wait_and_submit_cmd\n"); + + if (!_wait_flush_fence (ctx)) + return false; _reset_flush_fence(ctx); _submit_cmd (ctx->pSurf->dev, &ctx->cmd, ctx->flushFence); @@ -370,6 +380,7 @@ void _wait_and_submit_cmd (VkvgContext ctx){ vkResetCommandBuffer (ctx->cmd, 0); ctx->cmdStarted = false; + return true; } /*void _explicit_ms_resolve (VkvgContext ctx){//should init cmd before calling this (unused, using automatic resolve by renderpass) vkh_image_set_layout (ctx->cmd, ctx->pSurf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, @@ -414,7 +425,8 @@ void _flush_vertices_caches_until_vertex_base (VkvgContext ctx) { //copy vertex and index caches to the vbo and ibo vkbuffers used by gpu for drawing //current running cmd has to be completed to free usage of those void _flush_vertices_caches (VkvgContext ctx) { - _wait_flush_fence (ctx); + if (!_wait_flush_fence (ctx)) + return; memcpy(ctx->vertices.allocInfo.pMappedData, ctx->vertexCache, ctx->vertCount * sizeof (Vertex)); memcpy(ctx->indices.allocInfo.pMappedData, ctx->indexCache, ctx->indCount * sizeof (VKVG_IBO_INDEX_TYPE)); @@ -570,6 +582,8 @@ void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat) { uint32_t newPatternType = VKVG_PATTERN_TYPE_SOLID; + LOG(VKVG_LOG_INFO, "CTX: _update_cur_pattern: %p -> %p\n", lastPat, pat); + if (pat == NULL) {//solid color if (lastPat == NULL)//solid return;//solid to solid transition, no extra action requested @@ -579,7 +593,8 @@ void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat) { switch (newPatternType) { case VKVG_PATTERN_TYPE_SOLID: _flush_cmd_buff (ctx); - _wait_flush_fence (ctx); + if (!_wait_flush_fence (ctx)) + return; if (lastPat->type == VKVG_PATTERN_TYPE_SURFACE)//unbind current source surface by replacing it with empty texture _update_descriptor_set (ctx, ctx->pSurf->dev->emptyImg, ctx->dsSrc); break; @@ -605,7 +620,8 @@ void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat) { vkh_cmd_end (ctx->cmd); _wait_and_submit_cmd (ctx); - _wait_flush_fence (ctx); + if (!_wait_flush_fence (ctx)) + return; ctx->source = surf->img; @@ -646,7 +662,8 @@ void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat) { case VKVG_PATTERN_TYPE_LINEAR: case VKVG_PATTERN_TYPE_RADIAL: _flush_cmd_buff (ctx); - _wait_flush_fence(ctx); + if (!_wait_flush_fence (ctx)) + return; if (lastPat && lastPat->type == VKVG_PATTERN_TYPE_SURFACE) _update_descriptor_set (ctx, ctx->pSurf->dev->emptyImg, ctx->dsSrc); @@ -658,6 +675,11 @@ void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat) { vkvg_gradient_t grad = {0}; memcpy (&grad, pat->data, sizeof(vkvg_gradient_t)); + if (grad.count < 2) { + ctx->status = VKVG_STATUS_PATTERN_INVALID_GRADIENT; + return; + } + vkvg_matrix_transform_point (&ctx->pushConsts.mat, &grad.cp[0].x, &grad.cp[0].y); vkvg_matrix_transform_point (&ctx->pushConsts.mat, &grad.cp[0].z, &grad.cp[0].w); //to do, scale radial radiuses in cp[2] @@ -672,7 +694,8 @@ void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat) { vkvg_pattern_destroy (lastPat); } void _update_descriptor_set (VkvgContext ctx, VkhImage img, VkDescriptorSet ds){ - _wait_flush_fence(ctx);//descriptorSet update invalidate cmd buffs + if (!_wait_flush_fence(ctx))//descriptorSet update invalidate cmd buffs + return; VkDescriptorImageInfo descSrcTex = vkh_image_get_descriptor (img, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VkWriteDescriptorSet writeDescriptorSet = { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index 6a192d9..f3cad5c 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -254,9 +254,9 @@ void _ensure_renderpass_is_started (VkvgContext ctx); void _flush_cmd_buff (VkvgContext ctx); void _emit_draw_cmd_undrawn_vertices(VkvgContext ctx); void _flush_cmd_until_vx_base (VkvgContext ctx); -void _wait_flush_fence (VkvgContext ctx); +bool _wait_flush_fence (VkvgContext ctx); void _reset_flush_fence (VkvgContext ctx); -void _wait_and_submit_cmd (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); diff --git a/src/vkvg_device.c b/src/vkvg_device.c index e90edef..4de3436 100644 --- a/src/vkvg_device.c +++ b/src/vkvg_device.c @@ -40,7 +40,7 @@ VkvgDevice vkvg_device_create(VkSampleCountFlags samples, bool deferredResolve) _instance_extensions_check_release(); - VkhApp app = vkh_app_create("vkvg", 0, NULL, enabledExtsCount, enabledExts); + VkhApp app = vkh_app_create(1, 1, "vkvg", 0, NULL, enabledExtsCount, enabledExts); #if defined(DEBUG) && defined (VKVG_DBG_UTILS) if (dbgUtilsSupported) diff --git a/src/vkvg_experimental.c b/src/vkvg_experimental.c new file mode 100644 index 0000000..3e3e022 --- /dev/null +++ b/src/vkvg_experimental.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2021 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. + */ + +#include +#include "vkvg_experimental.h" +#include "vkvg_context_internal.h" + + + diff --git a/src/vkvg_experimental.h b/src/vkvg_experimental.h new file mode 100644 index 0000000..3439151 --- /dev/null +++ b/src/vkvg_experimental.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2021 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_EXPERIMENTAL_H +#define VKVG_EXPERIMENTAL_H + +#include "vkvg_internal.h" +#include "vkvg.h" + +#endif diff --git a/src/vkvg_internal.h b/src/vkvg_internal.h index 396925a..8c9fcc8 100644 --- a/src/vkvg_internal.h +++ b/src/vkvg_internal.h @@ -70,5 +70,7 @@ #define FB_COLOR_FORMAT VK_FORMAT_B8G8R8A8_UNORM #define VKVG_SURFACE_IMGS_REQUIREMENTS VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|\ VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_FORMAT_FEATURE_BLIT_SRC_BIT -#define VKVG_FENCE_TIMEOUT UINT64_MAX +//5 seconds fence timeout +#define VKVG_FENCE_TIMEOUT 5000000000 +//#define VKVG_FENCE_TIMEOUT 10000 #endif diff --git a/src/vkvg_pattern.c b/src/vkvg_pattern.c index 128c596..d8478b3 100644 --- a/src/vkvg_pattern.c +++ b/src/vkvg_pattern.c @@ -36,27 +36,65 @@ VkvgPattern vkvg_pattern_create_for_surface (VkvgSurface surf){ return pat; } +void vkvg_pattern_get_linear_points (VkvgPattern pat, float* x0, float* y0, float* x1, float* y1) { + if (pat->status) + return; + + if (pat->type != VKVG_PATTERN_TYPE_LINEAR) { + pat->status = VKVG_STATUS_PATTERN_TYPE_MISMATCH; + return; + } + vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; + + *x0 = grad->cp[0].x; + *y0 = grad->cp[0].y; + *x1 = grad->cp[0].z; + *y1 = grad->cp[0].w; +} +void vkvg_pattern_edit_linear (VkvgPattern pat, float x0, float y0, float x1, float y1){ + if (pat->status) + return; + + if (pat->type != VKVG_PATTERN_TYPE_LINEAR) { + pat->status = VKVG_STATUS_PATTERN_TYPE_MISMATCH; + return; + } + + vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; + + grad->cp[0] = (vec4){{x0}, {y0}, {x1}, {y1}}; +} VkvgPattern vkvg_pattern_create_linear (float x0, float y0, float x1, float y1){ VkvgPattern pat = (vkvg_pattern_t*)calloc(1, sizeof(vkvg_pattern_t)); + if (!pat) + return NULL; pat->type = VKVG_PATTERN_TYPE_LINEAR; pat->extend = VKVG_EXTEND_PAD; - vkvg_gradient_t* grad = (vkvg_gradient_t*)calloc(1,sizeof(vkvg_gradient_t)); - grad->cp[0] = (vec4){{x0}, {y0}, {x1}, {y1}}; + pat->data = (void*)calloc(1,sizeof(vkvg_gradient_t)); + if (!pat->data) { + pat->status = VKVG_STATUS_NO_MEMORY; + return pat; + } - pat->data = grad; + vkvg_pattern_edit_linear(pat, x0, y0, x1, y1); pat->references = 1; return pat; } -VkvgPattern vkvg_pattern_create_radial (float cx0, float cy0, float radius0, - float cx1, float cy1, float radius1){ - VkvgPattern pat = (vkvg_pattern_t*)calloc(1, sizeof(vkvg_pattern_t)); - pat->type = VKVG_PATTERN_TYPE_RADIAL; - pat->extend = VKVG_EXTEND_PAD; +void vkvg_pattern_edit_radial (VkvgPattern pat, + float cx0, float cy0, float radius0, + float cx1, float cy1, float radius1) { + if (pat->status) + return; - vkvg_gradient_t* grad = (vkvg_gradient_t*)calloc(1,sizeof(vkvg_gradient_t)); + if (pat->type != VKVG_PATTERN_TYPE_RADIAL) { + pat->status = VKVG_STATUS_PATTERN_TYPE_MISMATCH; + return; + } + + vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; vec2 c0 = {cx0, cy0}; vec2 c1 = {cx1, cy1}; @@ -72,13 +110,30 @@ VkvgPattern vkvg_pattern_create_radial (float cx0, float cy0, float radius0, grad->cp[0] = (vec4){{c0.x}, {c0.y},{radius0},{0}}; grad->cp[1] = (vec4){{c1.x}, {c1.y},{radius1},{0}}; +} +VkvgPattern vkvg_pattern_create_radial (float cx0, float cy0, float radius0, + float cx1, float cy1, float radius1){ + VkvgPattern pat = (vkvg_pattern_t*)calloc(1, sizeof(vkvg_pattern_t)); + if (!pat) + return NULL; + pat->type = VKVG_PATTERN_TYPE_RADIAL; + pat->extend = VKVG_EXTEND_PAD; + + pat->data = (void*)calloc(1,sizeof(vkvg_gradient_t)); + if (!pat->data) { + pat->status = VKVG_STATUS_NO_MEMORY; + return pat; + } - pat->data = grad; + vkvg_pattern_edit_radial (pat, cx0, cy0, radius0, cx1, cy1, radius1); pat->references = 1; return pat; } +vkvg_status_t vkvg_pattern_status (VkvgPattern pat) { + return pat->status; +} VkvgPattern vkvg_pattern_reference (VkvgPattern pat) { pat->references++; return pat; diff --git a/src/vkvg_pattern.h b/src/vkvg_pattern.h index 763d943..ea9a026 100644 --- a/src/vkvg_pattern.h +++ b/src/vkvg_pattern.h @@ -30,8 +30,9 @@ typedef struct _vkvg_pattern_t { vkvg_pattern_type_t type; vkvg_extend_t extend; vkvg_filter_t filter; - uint32_t references; void* data; + uint32_t references; + vkvg_status_t status; }vkvg_pattern_t; typedef struct _vkvg_gradient_t { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ce0d13f..40da768 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,9 +8,10 @@ IF (VKVG_TEST_OFFSCREEN) ADD_DEFINITIONS (-DVKVG_TEST_OFFSCREEN) ENDIF () -FUNCTION (buildtest TEST_NAME) - ADD_EXECUTABLE(test_${TEST_NAME} "${TEST_NAME}.c" ) - TARGET_INCLUDE_DIRECTORIES(test_${TEST_NAME} PRIVATE +FUNCTION (buildtest TEST_FILE) + GET_FILENAME_COMPONENT(TEST_NAME ${TEST_FILE} NAME_WE) + ADD_EXECUTABLE(${TEST_NAME} ${TEST_FILE}) + TARGET_INCLUDE_DIRECTORIES(${TEST_NAME} PRIVATE ${Vulkan_INCLUDE_DIRS} ${GLFW3_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../include @@ -19,7 +20,7 @@ FUNCTION (buildtest TEST_NAME) ${CMAKE_CURRENT_SOURCE_DIR}/../vkh/include ${CMAKE_CURRENT_SOURCE_DIR}/../vkh/src ) - TARGET_LINK_LIBRARIES(test_${TEST_NAME} + TARGET_LINK_LIBRARIES(${TEST_NAME} tests_common ) ENDFUNCTION (buildtest) @@ -38,7 +39,7 @@ TARGET_LINK_LIBRARIES(tests_common ${Vulkan_LIBRARIES} ${GLFW3_LIBRARY} vkvg_static - ) +) file(GLOB_RECURSE DATAS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "data/*") FOREACH(DATA_FILE ${DATAS}) @@ -56,10 +57,12 @@ ENDFOREACH() add_custom_target("${PROJECT_NAME}_DataCopy" ALL DEPENDS ${DATAS}) #build test apps -file(GLOB TESTS "*.c") +file(GLOB TESTS + "*.c" + "perfs/*.c" +) FOREACH(TEST ${TESTS}) -GET_FILENAME_COMPONENT(testname ${TEST} NAME_WE) -buildtest(${testname}) + buildtest(${TEST}) ENDFOREACH() diff --git a/tests/arcs.c b/tests/arcs.c index d3e1109..cfeb131 100644 --- a/tests/arcs.c +++ b/tests/arcs.c @@ -19,8 +19,8 @@ void scaled_up() { vkvg_paint(ctx); vkvg_set_source_rgb (ctx, 0,0,0); - vkvg_scale(ctx,100,100); - vkvg_arc(ctx, 2, 2, 0.5f, 0, M_PIF/2.f); + vkvg_scale(ctx,10,10); + vkvg_arc(ctx, 20, 20, 2.0f, 0, M_PIF/2.f); vkvg_stroke(ctx); vkvg_destroy(ctx); diff --git a/tests/common/test.c b/tests/common/test.c index bec0e4d..fc2daa5 100644 --- a/tests/common/test.c +++ b/tests/common/test.c @@ -399,7 +399,7 @@ void perform_test_offscreen (void(*testfunc)(void), const char *testName, int ar enabledExtsCount++; #endif - VkhApp app = vkh_app_create("vkvgTest", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); + VkhApp app = vkh_app_create(1, 1, "vkvgTest", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); #if defined(DEBUG) && defined (VKVG_DBG_UTILS) vkh_app_enable_debug_messenger(app , VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT diff --git a/tests/common/vkengine.c b/tests/common/vkengine.c index 78fcd3f..90884f1 100644 --- a/tests/common/vkengine.c +++ b/tests/common/vkengine.c @@ -142,14 +142,14 @@ vk_engine_t* vkengine_create (VkPhysicalDeviceType preferedGPU, VkPresentModeKHR free(instanceExtProps); - e->app = vkh_app_create("vkvgTest", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); + e->app = vkh_app_create(1 ,2 , "vkvgTest", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); #if defined(DEBUG) && defined (VKVG_DBG_UTILS) vkh_app_enable_debug_messenger(e->app , VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT //| VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT //| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT , VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT - //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT , NULL); @@ -191,10 +191,17 @@ vk_engine_t* vkengine_create (VkPhysicalDeviceType preferedGPU, VkPresentModeKHR enabledExtsCount=0; + VkPhysicalDeviceFeatures2 phyFeat2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; + VkPhysicalDeviceScalarBlockLayoutFeatures scalarBlockLayoutSupport = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES}; + phyFeat2.pNext = &scalarBlockLayoutSupport; + + vkGetPhysicalDeviceFeatures2(pi->phy, &phyFeat2); + TRY_LOAD_DEVICE_EXT (VK_KHR_swapchain) TRY_LOAD_DEVICE_EXT (VK_EXT_blend_operation_advanced) TRY_LOAD_DEVICE_EXT (VK_KHR_portability_subset) TRY_LOAD_DEVICE_EXT (VK_KHR_relaxed_block_layout) + TRY_LOAD_DEVICE_EXT (VK_EXT_scalar_block_layout) VkPhysicalDeviceFeatures enabledFeatures = { .fillModeNonSolid = true, diff --git a/tests/fill.c b/tests/fill.c index c2ab672..feeb5f1 100644 --- a/tests/fill.c +++ b/tests/fill.c @@ -2,6 +2,7 @@ void test(){ VkvgContext ctx = vkvg_create(surf); + vkvg_save(ctx); vkvg_set_line_width(ctx,30); vkvg_set_line_join(ctx,VKVG_LINE_JOIN_ROUND); diff --git a/tests/gradient.c b/tests/gradient.c index 27d956b..3fef7db 100644 --- a/tests/gradient.c +++ b/tests/gradient.c @@ -1,7 +1,7 @@ #include "test.h" -VkvgPattern create_grad (VkvgContext ctx) { - VkvgPattern pat = vkvg_pattern_create_linear(0,0,300,0); +VkvgPattern create_grad (VkvgContext ctx, float x) { + VkvgPattern pat = vkvg_pattern_create_linear(x,0,300,0); vkvg_pattern_add_color_stop(pat, 0, 1, 0, 0, 1); vkvg_pattern_add_color_stop(pat, 0.5f, 0, 1, 0, 1); vkvg_pattern_add_color_stop(pat, 1, 0, 0, 1, 1); @@ -10,28 +10,73 @@ VkvgPattern create_grad (VkvgContext ctx) { void paint(){ VkvgContext ctx = vkvg_create(surf); - VkvgPattern pat = create_grad(ctx); - vkvg_pattern_set_extend(pat,VKVG_EXTEND_NONE); + //vkvg_translate(ctx,100,100); + VkvgPattern pat = create_grad(ctx,0); + //vkvg_pattern_set_extend(pat,VKVG_EXTEND_NONE); + vkvg_rectangle(ctx, 0,0,400,460); vkvg_set_source (ctx, pat); - vkvg_paint(ctx); + vkvg_pattern_destroy (pat); + vkvg_fill(ctx); + + float x = 100; + pat = create_grad(ctx,x); + //vkvg_pattern_set_extend(pat,VKVG_EXTEND_NONE); + vkvg_rectangle(ctx, x,200,20,20); + vkvg_set_source (ctx, pat); + vkvg_pattern_destroy (pat); + vkvg_fill(ctx); + + x+=100; + + pat = create_grad(ctx,x); + //vkvg_pattern_set_extend(pat,VKVG_EXTEND_NONE); + vkvg_rectangle(ctx, x,200,20,20); + vkvg_set_source (ctx, pat); + vkvg_pattern_destroy (pat); + vkvg_fill(ctx); + + x+=100; + pat = create_grad(ctx,x); + //vkvg_pattern_set_extend(pat,VKVG_EXTEND_NONE); + vkvg_rectangle(ctx, x,200,20,20); + vkvg_set_source (ctx, pat); + vkvg_pattern_destroy (pat); + vkvg_fill(ctx); + + x+=100; + + pat = create_grad(ctx,x); + //vkvg_pattern_set_extend(pat,VKVG_EXTEND_NONE); + vkvg_rectangle(ctx, x,200,20,20); + vkvg_set_source (ctx, pat); vkvg_pattern_destroy (pat); + vkvg_fill(ctx); + + /*vkvg_set_source_rgb(ctx, 0,1,0); + vkvg_rectangle(ctx, 100,100,200,160); + vkvg_fill_preserve(ctx); + vkvg_set_source_rgb(ctx, 0,0,0); + vkvg_set_line_width(ctx,1.0f); + vkvg_stroke(ctx);*/ + + vkvg_destroy(ctx); } void paint_repeat(){ VkvgContext ctx = vkvg_create(surf); - VkvgPattern pat = create_grad(ctx); + VkvgPattern pat = create_grad(ctx,0); vkvg_pattern_set_extend(pat,VKVG_EXTEND_REPEAT); vkvg_set_source (ctx, pat); + vkvg_pattern_destroy (pat); vkvg_paint(ctx); - vkvg_pattern_destroy (pat); vkvg_destroy(ctx); } void test(){ VkvgContext ctx = vkvg_create(surf); - VkvgPattern pat = create_grad(ctx); + VkvgPattern pat = create_grad(ctx,0); vkvg_set_source (ctx, pat); vkvg_rectangle(ctx,100,100,200,200); vkvg_set_line_width(ctx, 20); @@ -89,7 +134,7 @@ void gradient_transform() { int main(int argc, char *argv[]) { no_test_size = true; PERFORM_TEST(paint, argc, argv); - PERFORM_TEST(paint_repeat, argc, argv); - PERFORM_TEST(gradient_transform, argc, argv); + /*PERFORM_TEST(paint_repeat, argc, argv); + PERFORM_TEST(gradient_transform, argc, argv);*/ return 0; } diff --git a/tests/gradient2.c b/tests/gradient2.c new file mode 100644 index 0000000..46439e6 --- /dev/null +++ b/tests/gradient2.c @@ -0,0 +1,174 @@ +#include "test.h" +#include "vectors.h" + +vkvg_fill_rule_t fillrule = VKVG_FILL_RULE_NON_ZERO; +static VkSampleCountFlags samples = VK_SAMPLE_COUNT_8_BIT; +float lineWidth = 50.0f; +vkvg_line_join_t lineJoin = VKVG_LINE_JOIN_MITER; +vkvg_line_cap_t lineCap = VKVG_LINE_CAP_BUTT; +bool isClosed = false; + +int ptsCount = 2; +int initPtsCount = 4; +vec2 pts[] = { + {150,150}, + {250,150}, + {125,125}, + {145,125}, +}; +int hoverPt = -1; +double pointSize = 7; + +static vkvg_pattern_type_t patternType = VKVG_PATTERN_TYPE_LINEAR; +static VkEngine e; + +void draw (){ + + VkvgContext ctx = vkvg_create(surf); + vkvg_clear(ctx); + + VkvgPattern pat; + + switch (patternType) { + case VKVG_PATTERN_TYPE_LINEAR: + pat = vkvg_pattern_create_linear(pts[0].x,pts[0].y, pts[1].x,pts[1].y); + break; + case VKVG_PATTERN_TYPE_RADIAL: + pat = vkvg_pattern_create_radial( + pts[2].x,pts[2].y, vec2_length(vec2_sub(pts[3], pts[2])), + pts[0].x,pts[0].y, vec2_length(vec2_sub(pts[1], pts[0])) + ); + break; + } + + /**/ + + vkvg_pattern_add_color_stop(pat, 0.0, 1 ,0 ,0, 0.5); + vkvg_pattern_add_color_stop(pat, 0.3, 0 ,1 ,0, 0.5); + vkvg_pattern_add_color_stop(pat, 0.6, 0 ,0 ,1, 0.5); + vkvg_pattern_add_color_stop(pat, 1.0, 0 ,0 ,0, 0.5); + + vkvg_set_source (ctx, pat); + vkvg_paint (ctx); + + vkvg_set_dash(ctx, NULL, 0, 0); + vkvg_set_line_width(ctx,1); + for (int i=0; i VKVG_PATTERN_TYPE_RADIAL) + patternType = VKVG_PATTERN_TYPE_LINEAR; + break; + case GLFW_KEY_S : + vkengine_wait_idle(e); + vkvg_surface_write_to_png(surf, "/home/jp/test.png"); + break; + case GLFW_KEY_KP_ADD : + if (ptsCount < initPtsCount) + ptsCount++; + break; + case GLFW_KEY_KP_SUBTRACT : + if (ptsCount > 1) + ptsCount--; + break; + } +} +static void mouse_move_callback(GLFWwindow* window, double x, double y){ + if (mouseDown) { + if (hoverPt < 0) + return; + pts[hoverPt].x = x; + pts[hoverPt].y = y; + } else { + for (int i=0; i pts[i].x - pointSize && + x < pts[i].x + pointSize && + y > pts[i].y - pointSize && + y < pts[i].y + pointSize) { + hoverPt = i; + return; + } + } + hoverPt = -1; + } +} +static void scroll_callback(GLFWwindow* window, double x, double y){ + if (y<0.f) + zoom *= 0.5f; + else + zoom *= 2.0f; +} +static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif){ + if (but != GLFW_MOUSE_BUTTON_1) + return; + if (state == GLFW_TRUE) + mouseDown = true; + else + mouseDown = false; +} + + + +int main(int argc, char* argv[]) { + + _parse_args (argc, argv); + + e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); + + VkhPresenter r = e->renderer; + vkengine_set_key_callback (e, key_callback); + vkengine_set_mouse_but_callback(e, mouse_button_callback); + vkengine_set_cursor_pos_callback(e, mouse_move_callback); + vkengine_set_scroll_callback(e, scroll_callback); + + bool deferredResolve = false; + + device = vkvg_device_create_from_vk_multisample(vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0, samples, deferredResolve); + surf = vkvg_surface_create(device, test_width, test_height); + + vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); + + while (!vkengine_should_close (e)) { + glfwPollEvents(); + + draw (); + + if (!vkh_presenter_draw (r)){ + vkh_presenter_get_size (r, &test_width, &test_height); + vkvg_surface_destroy (surf); + surf = vkvg_surface_create(device, test_width, test_height); + vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), test_width, test_height); + vkDeviceWaitIdle(r->dev->dev); + continue; + } + } + vkDeviceWaitIdle(e->dev->dev); + + vkvg_surface_destroy (surf); + + vkvg_device_destroy (device); + + vkengine_destroy (e); + + return 0; +} diff --git a/tests/inverse_colinear.c b/tests/inverse_colinear.c index b2559ed..f643d4e 100644 --- a/tests/inverse_colinear.c +++ b/tests/inverse_colinear.c @@ -137,6 +137,7 @@ static void mouse_button_callback(GLFWwindow* window, int but, int state, int mo int main(int argc, char* argv[]) { + _parse_args (argc, argv); VkEngine e; e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); diff --git a/tests/random_rects.c b/tests/perfs/random_rects.c similarity index 100% rename from tests/random_rects.c rename to tests/perfs/random_rects.c diff --git a/tests/randoms.c b/tests/perfs/randoms.c similarity index 100% rename from tests/randoms.c rename to tests/perfs/randoms.c diff --git a/vkh b/vkh index 1c88fc3..fc5623d 160000 --- a/vkh +++ b/vkh @@ -1 +1 @@ -Subproject commit 1c88fc341c41de58adcfd47e09435a7bba6c315a +Subproject commit fc5623d771907a94b0d68da221703a6ca6088885 -- 2.47.3