From c379f58b06c2d0c7c4d3ab36b37b9ff0088ae490 Mon Sep 17 00:00:00 2001 From: Bob Cao Date: Thu, 19 Jan 2023 11:21:11 -0800 Subject: [PATCH] [gui] Fix wide line support on macOS (#7205) ### Brief Summary Changed the wide line rendering feature from rendering line primitives to expanded quads. Added a "prepare" pass in GGUI to run the compute shaders that expands & prepares the data. Screenshot from macOS: ![image](https://user-images.githubusercontent.com/11663476/213070106-35f1d560-7a81-4760-af71-411b529c275a.png) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- python/taichi/shaders/Lines_vk.frag | 12 +- python/taichi/shaders/Lines_vk.vert | 29 +--- python/taichi/shaders/Lines_vk_frag.spv | Bin 840 -> 568 bytes python/taichi/shaders/Lines_vk_vert.spv | Bin 1976 -> 1308 bytes python/taichi/shaders/SceneLines2quad_vk.comp | 124 ++++++++++++++++ .../shaders/SceneLines2quad_vk_comp.spv | Bin 0 -> 11088 bytes python/taichi/shaders/SceneLines_vk.frag | 6 +- python/taichi/shaders/SceneLines_vk.vert | 38 +---- python/taichi/shaders/SceneLines_vk_frag.spv | Bin 668 -> 568 bytes python/taichi/shaders/SceneLines_vk_vert.spv | Bin 2484 -> 1092 bytes python/taichi/shaders/lines2quad_vk.comp | 106 ++++++++++++++ python/taichi/shaders/lines2quad_vk_comp.spv | Bin 0 -> 9192 bytes taichi/rhi/vulkan/vulkan_device.cpp | 2 + taichi/rhi/vulkan/vulkan_device_creator.cpp | 6 - taichi/ui/backends/vulkan/renderable.cpp | 4 +- taichi/ui/backends/vulkan/renderable.h | 6 +- .../ui/backends/vulkan/renderables/lines.cpp | 138 +++++++++++++++--- taichi/ui/backends/vulkan/renderables/lines.h | 23 ++- .../vulkan/renderables/scene_lines.cpp | 131 ++++++++++++++--- .../backends/vulkan/renderables/scene_lines.h | 25 +++- taichi/ui/backends/vulkan/renderer.cpp | 6 + taichi/ui/backends/vulkan/swap_chain.cpp | 6 + tests/python/test_ggui.py | 24 +-- 23 files changed, 543 insertions(+), 143 deletions(-) create mode 100644 python/taichi/shaders/SceneLines2quad_vk.comp create mode 100644 python/taichi/shaders/SceneLines2quad_vk_comp.spv create mode 100644 python/taichi/shaders/lines2quad_vk.comp create mode 100644 python/taichi/shaders/lines2quad_vk_comp.spv diff --git a/python/taichi/shaders/Lines_vk.frag b/python/taichi/shaders/Lines_vk.frag index 4fa7c2817164d..c221ed6b4b1a0 100644 --- a/python/taichi/shaders/Lines_vk.frag +++ b/python/taichi/shaders/Lines_vk.frag @@ -1,17 +1,9 @@ #version 450 -layout(location = 0) in vec2 frag_texcoord; +layout(location = 0) in vec3 color; layout(location = 0) out vec4 out_color; -layout(binding = 0) uniform UniformBufferObject { - vec3 color; - int use_per_vertex_color; -} -ubo; - -layout(location = 1) in vec3 selected_color; - void main() { - out_color = vec4(selected_color, 1); + out_color = vec4(color, 1); } diff --git a/python/taichi/shaders/Lines_vk.vert b/python/taichi/shaders/Lines_vk.vert index 4176ecc3ea8cc..a2f709880562f 100644 --- a/python/taichi/shaders/Lines_vk.vert +++ b/python/taichi/shaders/Lines_vk.vert @@ -1,30 +1,11 @@ #version 450 -layout(location = 0) in vec3 in_position; -layout(location = 1) in vec3 in_normal; -layout(location = 2) in vec2 in_texcoord; -layout(location = 3) in vec4 in_color; +layout(location = 0) in vec2 in_position; +layout(location = 1) in uint in_color_encoded; -layout(location = 0) out vec2 frag_texcoord; - -layout(binding = 0) uniform UniformBufferObject { - vec3 color; - int use_per_vertex_color; -} -ubo; - -layout(location = 1) out vec3 selected_color; +layout(location = 0) out vec3 frag_color; void main() { - float x = in_position.x * 2.0 - 1.0; - float y = -(in_position.y * 2.0 - 1.0); - - gl_Position = vec4(x, y, 0.0, 1.0); - frag_texcoord = in_texcoord; - - if (ubo.use_per_vertex_color == 0) { - selected_color = ubo.color; - } else { - selected_color = in_color.rgb; - } + gl_Position = vec4(in_position.x * 2.0 - 1.0, -(in_position.y * 2.0 - 1.0), 0.0, 1.0); + frag_color = unpackUnorm4x8(in_color_encoded).rgb; } diff --git a/python/taichi/shaders/Lines_vk_frag.spv b/python/taichi/shaders/Lines_vk_frag.spv index 4e0e3968faf9fc0061f0e59d6a8889dec9e8dcae..c886d71ceef149e56734d3614d28dcd2b77bab73 100644 GIT binary patch delta 149 zcmX@Xwu6P2nMs+Qfq{{Mn}L@>cp|TCH9jXZFEu_TvnVyWB(p3Pq?rRrU1nZ#PH75~f{Eqoyeten aKvR?RbMlKA7$$2o%1&OxIA!t%rWpYGS|uI; literal 840 zcmYk3O-lk{6os#jqo(CYrdA8lTn5sjB8Upw*g~j?*5bz)MmjNSwCuO_tJ(yeXPgON zxO3lg?ztcD9Vgk&m?bP{Sv$1#DO*yES>Dp2@AjU0oyBt8IXyc;Q7|VIqA4mbC6CPp z(>Z}H*|w}ID@jXCO>}cq+3Z`1uGq~SR}6XnYS|z8Z+@V=tNzqkcyHcl>5bz6Jhdmm z;HAIxK1aSEj6;3K>hjO?>BJ9ax2ws-3+{)nN>+v&#uT==ep(&T^N!WR>%V(J|HBJZ zG48|+jvWvm`qtIN%-E1|z|04x2AH|x_}xa&ws=m=p@$>Cs~*h3Zm2=OBN->gtu?fY zROnjaHrF{d-P7WlvbyrwHJJT2_07uj$KWp`%sb%F=j73Y(dXq8GI;c0=7c*IMq7}X zecg~>(G8Bd$lsGk3r{|ny}(t4Yx2zqH-vdRz1Don_I0NgJo#XD0(Y*R;&~f~nSaE% z@>gQ1vm;~PN3qORj5xV}t`u?16zj?nNBswFi+%0N$VX3{cVDY3`y=+NS6#^d0M-pU AWB>pF diff --git a/python/taichi/shaders/Lines_vk_vert.spv b/python/taichi/shaders/Lines_vk_vert.spv index 179cd6ded218547cad56b481a634ba58b6d4f071..12231378dd5b3fd41751a7090c7049d124d7f333 100644 GIT binary patch literal 1308 zcmYk4+iTQ76voHhrdxZp*0x@1n_8`xO7THO5VfKb9~QPy@HH$+ECVrFvZ<&q3gSQJ zU*(J7_nTyDW;uJ#`OY`zHtF~F2F6@43uehYG|gExJt0Qetkco(WOz8O)5FJ49>G{P zeMf||VlFy+M*pA2w!m4ET$b!h?n(Ok^`w96!i zr?$$H+J4U9&2@OTNb<9^O9;g1)(q6^f@+-R@o`pt$f`Q~B3EdGV-qWXvtn;@J9%rT^|(l~^B5Z-c9!Sou|RV&J15YO9oQnC_?lqs#(XGKz`SxS!giZT<&YmYVW!^{2W(JwrD^E_-Yb`>dt4KETxf7=oc zKD~8)-VUD{Yr4g~UF9Gr_J*uk=}@w%`}&ZaPpx(NbJC%NbI|&HE#%vhKQGOFux(lN z=5r83Lh%-*{T$C*pFM+7XW8+Zywt&8k#Okik~DSbnS86#^Z-sie0Blm`&^UFfqzAs z7&(ZeHzhhp-oNJDAFsS0I={JpOE$eS8~xmtCI=Y#@3b~J{owDn81cKZsn0%%~BxPoAa(OH6=cLdSEa2CG2ET h(~#?dg#8>zh>gTzzXuXx2nP=PBPTm2{#WQT$v-<(WKsYC literal 1976 zcmYk6TTc{05QQ6dXSpee+`J&pf_D^efG8r%VuBAOk`R5}EXynzGt7|L#i%cu82^kv z!$0LEG4Xso-AI$7`kbmdUDI9JQtw=!F+FC`^qWmntWnb|#+V^fv3_fNcYC4J-CtN- zdO*goDcMAFM$8$zFYEtdGfn|RvQRcJyC++f)ns*9Nq@caKU5r;vi|bT(96Z5qd(`WPP+46DP-Hks* z^MnIV)PS=X9ddSd)s;QprKw`S(fixKCpM7?>J!t z^>SaaH)-6?^27RZyB+1P_ufUVu2cdWQ`oe!B+KP1X25dve%y%~M^WB*Z@;+VQ|#S5 zB)*r~Ubyp4lt?n#_gUO&O}u(JRTtQI5tpi$W}^6(UWL2oep#F|=Ruhgh;g~=);k+hyF)L%C39edHVD5)A z&>&uOm_EUEhl!6#72T@NAkKbLyNY~ht*jR{*5Ia8KOoPZ{7`sM9xeD)hyA@x2=fi0 zj5Y7@*#g@7VeP3$lQ@1voev{oIS2j1br$W_7ai_%Z$PJTUVCNBpjQ zkIcux%nRI%;>-YdT$Pc}4;I?+=z*C9IN$Fh?WrgKv5QeZuB>IpKa-~iw9x@GL%y%) z+N0^?ymw88F8ScP!^@g!a(N3D8o$H@^5im0{0`zh=64Ugp)6)$M8^CuBWtSR4$sNp zzbOZN-f_&ySI3Pzo>_UJlQ{>@>rQEpE_2~^FK7?%buVfUcUt$7Fg&`ST|bw#hvyvn z2Ybyq?K#`yYub~uqpxH(Zpg@iXMWJ7N9O02ER@a4&<2x_7IU#6V= ubo.num_vertices) return; + + uint vert0 = ubo.start_vertex; + uint vert1 = ubo.start_vertex; + if (ubo.is_indexed != 0) { + int index = thread_idx * 2 + ubo.start_index; + vert0 += ib_in[index]; + vert1 += ib_in[index + 1]; + } else { + vert0 += thread_idx * 2; + vert1 += thread_idx * 2 + 1; + } + + vec4 pos0 = vec4(vb_in[vert0 * ubo.vertex_stride ], + vb_in[vert0 * ubo.vertex_stride + 1], + vb_in[vert0 * ubo.vertex_stride + 2], + 1.0); + pos0 = ubo.scene.projection * ubo.scene.view * pos0; + vec4 color0 = vec4(ubo.color, 1.0); + vec4 pos1 = vec4(vb_in[vert1 * ubo.vertex_stride ], + vb_in[vert1 * ubo.vertex_stride + 1], + vb_in[vert1 * ubo.vertex_stride + 2], + 1.0); + pos1 = ubo.scene.projection * ubo.scene.view * pos1; + vec4 color1 = vec4(ubo.color, 1.0); + + if (ubo.per_vertex_color_offset > 0) { + color0 = vec4(vb_in[vert0 * ubo.vertex_stride + ubo.per_vertex_color_offset], + vb_in[vert0 * ubo.vertex_stride + ubo.per_vertex_color_offset + 1], + vb_in[vert0 * ubo.vertex_stride + ubo.per_vertex_color_offset + 2], + 1.0); + color1 = vec4(vb_in[vert1 * ubo.vertex_stride + ubo.per_vertex_color_offset], + vb_in[vert1 * ubo.vertex_stride + ubo.per_vertex_color_offset + 1], + vb_in[vert1 * ubo.vertex_stride + ubo.per_vertex_color_offset + 2], + 1.0); + } + + vec2 aspect_adjust = vec2(ubo.aspect_ratio, 1.0); + vec2 dir = normalize((pos1.xy / pos1.w - pos0.xy / pos0.w) * aspect_adjust); + vec2 tangent = vec2(-dir.y, dir.x) * ubo.line_width / aspect_adjust; + + vec4 out_pos00 = pos0; + vec4 out_pos01 = pos0; + out_pos00.xy += vec2(tangent * pos0.w); + out_pos01.xy -= vec2(tangent * pos0.w); + + vec4 out_pos10 = pos1; + vec4 out_pos11 = pos1; + out_pos10.xy += vec2(tangent * pos1.w); + out_pos11.xy -= vec2(tangent * pos1.w); + + vb_out[thread_idx * 4 ] = VertexOut(out_pos00, color0); + vb_out[thread_idx * 4 + 1] = VertexOut(out_pos01, color0); + + vb_out[thread_idx * 4 + 2] = VertexOut(out_pos10, color1); + vb_out[thread_idx * 4 + 3] = VertexOut(out_pos11, color1); + + ib_out[thread_idx * 6 ] = thread_idx * 4; + ib_out[thread_idx * 6 + 1] = thread_idx * 4 + 1; + ib_out[thread_idx * 6 + 2] = thread_idx * 4 + 2; + + ib_out[thread_idx * 6 + 3] = thread_idx * 4 + 2; + ib_out[thread_idx * 6 + 4] = thread_idx * 4 + 1; + ib_out[thread_idx * 6 + 5] = thread_idx * 4 + 3; +} diff --git a/python/taichi/shaders/SceneLines2quad_vk_comp.spv b/python/taichi/shaders/SceneLines2quad_vk_comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..534e1aa2d9906da26a7681b88117067d08a9fdd8 GIT binary patch literal 11088 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 literal 0 HcmV?d00001 diff --git a/python/taichi/shaders/SceneLines_vk.frag b/python/taichi/shaders/SceneLines_vk.frag index 74ef8ada1fc3b..c221ed6b4b1a0 100644 --- a/python/taichi/shaders/SceneLines_vk.frag +++ b/python/taichi/shaders/SceneLines_vk.frag @@ -1,11 +1,9 @@ #version 450 -layout(location = 0) in vec2 frag_texcoord; +layout(location = 0) in vec3 color; layout(location = 0) out vec4 out_color; -layout(location = 1) in vec3 selected_color; - void main() { - out_color = vec4(selected_color, 1); + out_color = vec4(color, 1); } diff --git a/python/taichi/shaders/SceneLines_vk.vert b/python/taichi/shaders/SceneLines_vk.vert index 2d760d73f5880..d1a868edd9b4f 100644 --- a/python/taichi/shaders/SceneLines_vk.vert +++ b/python/taichi/shaders/SceneLines_vk.vert @@ -1,38 +1,12 @@ #version 450 -layout(location = 0) in vec3 in_position; -layout(location = 1) in vec3 in_normal; -layout(location = 2) in vec2 in_texcoord; -layout(location = 3) in vec4 in_color; +layout(location = 0) in vec4 in_position; +layout(location = 1) in vec4 in_color; -layout(location = 0) out vec2 frag_texcoord; - -struct SceneUBO { - vec3 camera_pos; - mat4 view; - mat4 projection; - vec3 ambient_light; - int point_light_count; -}; - -layout(binding = 0) uniform UBO { - SceneUBO scene; - vec3 color; - int use_per_vertex_color; -} -ubo; - -layout(location = 1) out vec3 selected_color; +layout(location = 0) out vec3 frag_color; void main() { - gl_Position = ubo.scene.projection * ubo.scene.view * vec4(in_position, 1.0); - gl_Position.y *= -1.0; - - frag_texcoord = in_texcoord; - - if (ubo.use_per_vertex_color == 0) { - selected_color = ubo.color; - } else { - selected_color = in_color.rgb; - } + gl_Position = in_position; + gl_Position.y = -gl_Position.y; + frag_color = in_color.rgb; } diff --git a/python/taichi/shaders/SceneLines_vk_frag.spv b/python/taichi/shaders/SceneLines_vk_frag.spv index 4a94e07266a0b496347a1505e3c6d33d7776dbe1..c886d71ceef149e56734d3614d28dcd2b77bab73 100644 GIT binary patch delta 72 zcmbQkx`Tz6nMs+Qfq{{Mn}L@>cp|TYi*^gf_UY%ph$sNT}BTOiv-0&?uK-u=A4;1Gy8o6U!Gqn4{By5J2Kz;8-LuZ8>cEP7fDL&3nxNHh&IcgF(gUj zm+UopOS04s^pSjAEuP|s>^WQ6PK)++d&Pa1Fx>~IGz7_uW@aQ<9QCCdnUD)W>yxrgQ6r*+B Odp&5dJIb#%o(O+a?3a$av(~Ew>Yv6Bq8xoH=kt zdPdy$_^J*b|t;oEob>uAFOqTZVr-Q1SCvH_oH_$C-*{ZIk zI_U$arN8aE7ZR7dC->&S$OVj(beCM&jr+v_ytXBmmDIgJZ?@#nFN=TZi_#W8>U|Ku zyYwt|d8OVh{$2SuV_rvJ`h^OrHE~ib=jh3Ahi=j#COl_Aj=BvakEFc4y!+ zmF#*J1zYw>wvD(gzhA=gqFm}`(m#?Nd%&^VFzN#1HjKK!=%-=uVDzyg4Lo+}ZGMxI zIgexohR>Flf6Wq`t-oRV@B&u9!*BB)GVkU^77y&#yV^fFV)w3LN4{Y117`CD()RY!8b#CQsC&m-+6;8#1$Q%FGzq{4rl-^1$CrkcWfJZ-(i2 z=oRlKloNXR-Qw2jZj1KlJ-tDu{$2V%rn@cToDT9j@x(hQdA)Az!N$cgU-N+uYRisa zIbx!}8Dze1Fyd_1-4@}OILKQ>9P(oJ#KC^AK$3ORI<6Cqz;7<_`A9#Ze12;1B&t zk@TO@pAv^2ochlNp8U|C*Nq;Wc*qw5hW?^>Vw)bB-2p>?MK`|a$4+tA1OAt8{8}Bz z>=+pDZtLb9dgOb$@kt%zfjkp1>%+q!U)3yl%gi|V{3?WRc3PFv^=3}RtJ!=qb_ECT4Z{@DRL&qGeP$@f+UFCRB`bH2+z zx*MWt5p%8imfx8>!tiagVh(pj;N-%NA%D|5eDWSY} OFZ4}c`1~QO>!P2eOT`@k diff --git a/python/taichi/shaders/lines2quad_vk.comp b/python/taichi/shaders/lines2quad_vk.comp new file mode 100644 index 0000000000000..93362a57d7710 --- /dev/null +++ b/python/taichi/shaders/lines2quad_vk.comp @@ -0,0 +1,106 @@ +#version 450 + +/* + * struct Vertex { + * vec3 pos; + * vec3 normal; + * vec2 tex_coord; + * vec4 color; + * }; + * + * We will assume pos is always first in struct. + */ + +layout(binding = 0, std430) buffer InputVB { + float vb_in[]; +}; + +layout(binding = 1, std430) buffer InputIB { + int ib_in[]; +}; + +struct VertexOut { + vec2 out_pos; + uint out_color; // Encoded RGBA8 + uint pad; +}; + +layout(binding = 2, std430) buffer OutputVB { + VertexOut vb_out[]; +}; + +layout(binding = 3, std430) buffer OutputIB { + int ib_out[]; +}; + +layout(binding = 4) uniform UniformBufferObject { + vec3 color; + float line_width; + int per_vertex_color_offset; + int vertex_stride; + int start_vertex; + int start_index; + int num_vertices; + int is_indexed; + float aspect_ratio; +} +ubo; + +layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in; +void main() { + int thread_idx = int(gl_GlobalInvocationID.x); + if (thread_idx * 2 >= ubo.num_vertices) return; + + uint vert0 = ubo.start_vertex; + uint vert1 = ubo.start_vertex; + if (ubo.is_indexed != 0) { + int index = thread_idx * 2 + ubo.start_index; + vert0 += ib_in[index]; + vert1 += ib_in[index + 1]; + } else { + vert0 += thread_idx * 2; + vert1 += thread_idx * 2 + 1; + } + + vec2 pos0 = vec2(vb_in[vert0 * ubo.vertex_stride], + vb_in[vert0 * ubo.vertex_stride + 1]); + vec4 color0 = vec4(ubo.color, 1.0); + vec2 pos1 = vec2(vb_in[vert1 * ubo.vertex_stride], + vb_in[vert1 * ubo.vertex_stride + 1]); + vec4 color1 = vec4(ubo.color, 1.0); + + if (ubo.per_vertex_color_offset > 0) { + color0 = vec4(vb_in[vert0 * ubo.vertex_stride + ubo.per_vertex_color_offset], + vb_in[vert0 * ubo.vertex_stride + ubo.per_vertex_color_offset + 1], + vb_in[vert0 * ubo.vertex_stride + ubo.per_vertex_color_offset + 2], + 1.0); + color1 = vec4(vb_in[vert1 * ubo.vertex_stride + ubo.per_vertex_color_offset], + vb_in[vert1 * ubo.vertex_stride + ubo.per_vertex_color_offset + 1], + vb_in[vert1 * ubo.vertex_stride + ubo.per_vertex_color_offset + 2], + 1.0); + } + + vec2 aspect_adjust = vec2(ubo.aspect_ratio, 1.0); + vec2 dir = normalize((pos1 - pos0) * aspect_adjust); + vec2 tangent = vec2(-dir.y, dir.x) * (ubo.line_width * 0.5) / aspect_adjust; + + vec2 out_pos00 = pos0 + tangent; + vec2 out_pos01 = pos0 - tangent; + + vec2 out_pos10 = pos1 + tangent; + vec2 out_pos11 = pos1 - tangent; + + vb_out[thread_idx * 4 ] = VertexOut(out_pos00, packUnorm4x8(color0), 0); + vb_out[thread_idx * 4 + 1] = VertexOut(out_pos01, packUnorm4x8(color0), 0); + + vb_out[thread_idx * 4 + 2] = VertexOut(out_pos10, packUnorm4x8(color1), 0); + vb_out[thread_idx * 4 + 3] = VertexOut(out_pos11, packUnorm4x8(color1), 0); + + ib_out[thread_idx * 6 ] = thread_idx * 4; + ib_out[thread_idx * 6 + 1] = thread_idx * 4 + 1; + ib_out[thread_idx * 6 + 2] = thread_idx * 4 + 2; + + ib_out[thread_idx * 6 + 3] = thread_idx * 4 + 2; + ib_out[thread_idx * 6 + 4] = thread_idx * 4 + 1; + ib_out[thread_idx * 6 + 5] = thread_idx * 4 + 3; +} diff --git a/python/taichi/shaders/lines2quad_vk_comp.spv b/python/taichi/shaders/lines2quad_vk_comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..5b7aed00240b5e471abaa15e007c4c83566cec95 GIT binary patch literal 9192 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 o7P$JcMNU`2OTVpfwKAt|aP{`$?5>6 VulkanResourceSet::finalize() { std::forward_list image_infos; std::vector desc_writes; + set_->ref_binding_objs.clear(); + for (auto &pair : bindings_) { uint32_t binding = pair.first; VkDescriptorType type = pair.second.type; diff --git a/taichi/rhi/vulkan/vulkan_device_creator.cpp b/taichi/rhi/vulkan/vulkan_device_creator.cpp index 20c2e38088fdb..a6283a85e75d2 100644 --- a/taichi/rhi/vulkan/vulkan_device_creator.cpp +++ b/taichi/rhi/vulkan/vulkan_device_creator.cpp @@ -628,12 +628,6 @@ void VulkanDeviceCreator::create_logical_device(bool manual_create) { if (device_supported_features.wideLines) { device_features.wideLines = true; ti_device_->vk_caps().wide_line = true; - } else if (params_.is_for_ui) { - if (!device_features.wideLines) { - RHI_LOG_ERROR( - "Taichi GGUI wide lines feature unavailable due to lack of device " - "support"); - } } if (ti_device_->vk_caps().vk_api_version >= VK_API_VERSION_1_1) { diff --git a/taichi/ui/backends/vulkan/renderable.cpp b/taichi/ui/backends/vulkan/renderable.cpp index 076015521fd6b..d4b2a51826e82 100644 --- a/taichi/ui/backends/vulkan/renderable.cpp +++ b/taichi/ui/backends/vulkan/renderable.cpp @@ -234,7 +234,7 @@ void Renderable::create_vertex_buffer() { Device::AllocParams vb_params{buffer_size, false, false, app_context_->requires_export_sharing(), - AllocUsage::Vertex}; + AllocUsage::Storage | AllocUsage::Vertex}; vertex_buffer_ = app_context_->device().allocate_memory(vb_params); Device::AllocParams staging_vb_params{buffer_size, true, false, false, @@ -248,7 +248,7 @@ void Renderable::create_index_buffer() { Device::AllocParams ib_params{buffer_size, false, false, app_context_->requires_export_sharing(), - AllocUsage::Index}; + AllocUsage::Storage | AllocUsage::Index}; index_buffer_ = app_context_->device().allocate_memory(ib_params); Device::AllocParams staging_ib_params{buffer_size, true, false, false, diff --git a/taichi/ui/backends/vulkan/renderable.h b/taichi/ui/backends/vulkan/renderable.h index d06e8c08f337a..558d4b3d93800 100644 --- a/taichi/ui/backends/vulkan/renderable.h +++ b/taichi/ui/backends/vulkan/renderable.h @@ -56,6 +56,10 @@ class Renderable { virtual void record_this_frame_commands( taichi::lang::CommandList *command_list); + virtual void record_prepass_this_frame_commands( + taichi::lang::CommandList *command_list) { + } + virtual ~Renderable() = default; taichi::lang::Pipeline &pipeline(); @@ -92,7 +96,7 @@ class Renderable { virtual void create_bindings(); - void create_graphics_pipeline(); + virtual void create_graphics_pipeline(); void create_vertex_buffer(); diff --git a/taichi/ui/backends/vulkan/renderables/lines.cpp b/taichi/ui/backends/vulkan/renderables/lines.cpp index 2fdbb292640a7..afb74f45d04fb 100644 --- a/taichi/ui/backends/vulkan/renderables/lines.cpp +++ b/taichi/ui/backends/vulkan/renderables/lines.cpp @@ -11,14 +11,6 @@ namespace vulkan { using namespace taichi::lang; using namespace taichi::lang::vulkan; -void Lines::update_data(const LinesInfo &info) { - Renderable::update_data(info.renderable_info); - - update_ubo(info.color, info.renderable_info.has_per_vertex_color); - - curr_width_ = info.width; -} - void Lines::init_lines(AppContext *app_context, int vertices_count, int indices_count) { @@ -36,19 +28,89 @@ void Lines::init_lines(AppContext *app_context, true, app_context->config.package_path + "/shaders/Lines_vk_vert.spv", app_context->config.package_path + "/shaders/Lines_vk_frag.spv", - TopologyType::Lines, + TopologyType::Triangles, }; Renderable::init(config, app_context); Renderable::init_render_resources(); } +void Lines::create_graphics_pipeline() { + if (!pipeline_.get()) { + auto vert_code = read_file(config_.vertex_shader_path); + auto frag_code = read_file(config_.fragment_shader_path); + + std::vector source(2); + source[0] = {PipelineSourceType::spirv_binary, frag_code.data(), + frag_code.size(), PipelineStageType::fragment}; + source[1] = {PipelineSourceType::spirv_binary, vert_code.data(), + vert_code.size(), PipelineStageType::vertex}; + + RasterParams raster_params; + raster_params.prim_topology = TopologyType::Triangles; + raster_params.polygon_mode = config_.polygon_mode; + raster_params.depth_test = true; + raster_params.depth_write = true; + + if (config_.blending) { + raster_params.blending.push_back(BlendingParams()); + } + + std::vector vertex_inputs = {{/*binding=*/0, + sizeof(float) * 4, + /*instance=*/false}}; + // TODO: consider using uint8 for colors and normals + std::vector vertex_attribs; + vertex_attribs.push_back({/*location=*/0, /*binding=*/0, + /*format=*/BufferFormat::rg32f, + /*offset=*/0}); + vertex_attribs.push_back({/*location=*/1, /*binding=*/0, + /*format=*/BufferFormat::r32u, + /*offset=*/sizeof(float) * 2}); + + pipeline_ = app_context_->device().create_raster_pipeline( + source, raster_params, vertex_inputs, vertex_attribs); + } + + if (!quad_expand_pipeline_.get()) { + auto comp_code = read_file(app_context_->config.package_path + + "/shaders/lines2quad_vk_comp.spv"); + auto [pipeline, res] = app_context_->device().create_pipeline_unique( + {PipelineSourceType::spirv_binary, comp_code.data(), comp_code.size(), + PipelineStageType::compute}); + TI_ASSERT(res == RhiResult::success); + quad_expand_pipeline_ = std::move(pipeline); + } +} + Lines::Lines(AppContext *app_context, VertexAttributes vbo_attrs) { init_lines(app_context, 4, 6); } -void Lines::update_ubo(glm::vec3 color, bool use_per_vertex_color) { - UniformBufferObject ubo{color, (int)use_per_vertex_color}; +void Lines::update_data(const LinesInfo &info) { + Renderable::update_data(info.renderable_info); + + lines_count_ = + (indexed_ ? config_.indices_count : config_.vertices_count) / 2; + + update_ubo(info.color, info.renderable_info.has_per_vertex_color, info.width); +} + +void Lines::update_ubo(glm::vec3 color, + bool use_per_vertex_color, + float line_width) { + UniformBufferObject ubo{}; + ubo.color = color; + ubo.line_width = line_width; + ubo.per_vertex_color_offset = + use_per_vertex_color ? offsetof(Vertex, color) / sizeof(float) : 0; + ubo.vertex_stride = config_.vbo_size() / sizeof(float); + ubo.start_vertex = 0; + ubo.start_index = 0; + ubo.num_vertices = lines_count_ * 2; + ubo.is_indexed = indexed_ ? 1 : 0; + ubo.aspect_ratio = + float(app_context_->config.width) / float(app_context_->config.height); void *mapped{nullptr}; TI_ASSERT(app_context_->device().map(uniform_buffer_, &mapped) == @@ -58,25 +120,59 @@ void Lines::update_ubo(glm::vec3 color, bool use_per_vertex_color) { } void Lines::create_bindings() { - Renderable::create_bindings(); - resource_set_->buffer(0, uniform_buffer_); + if (!resource_set_) { + resource_set_ = app_context_->device().create_resource_set_unique(); + } + if (!raster_state_) { + raster_state_ = app_context_->device().create_raster_resources_unique(); + } +} + +void Lines::record_prepass_this_frame_commands(CommandList *command_list) { + vbo_translated_.reset(); + ibo_translated_.reset(); + + vbo_translated_ = app_context_->device().allocate_memory_unique( + {/*size=*/uint64_t(sizeof(glm::vec4) * 4 * lines_count_), + /*host_write=*/false, + /*host_read=*/false, + /*export_sharing=*/false, + /*usage=*/AllocUsage::Storage | AllocUsage::Vertex}); + + ibo_translated_ = app_context_->device().allocate_memory_unique( + {/*size=*/uint64_t(sizeof(int) * 6 * lines_count_), + /*host_write=*/false, + /*host_read=*/false, + /*export_sharing=*/false, + /*usage=*/AllocUsage::Storage | AllocUsage::Index}); + + raster_state_->vertex_buffer(vbo_translated_->get_ptr(0), 0); + raster_state_->index_buffer(ibo_translated_->get_ptr(0), 32); + + resource_set_->rw_buffer(0, vertex_buffer_.get_ptr(0)); + resource_set_->rw_buffer(1, index_buffer_.get_ptr(0)); + resource_set_->rw_buffer(2, vbo_translated_->get_ptr(0)); + resource_set_->rw_buffer(3, ibo_translated_->get_ptr(0)); + resource_set_->buffer(4, uniform_buffer_.get_ptr(0)); + + command_list->bind_pipeline(quad_expand_pipeline_.get()); + command_list->bind_shader_resources(resource_set_.get()); + command_list->dispatch(int(ceil(lines_count_ / 256.0f))); + command_list->buffer_barrier(*vbo_translated_); + command_list->buffer_barrier(*ibo_translated_); } void Lines::record_this_frame_commands(CommandList *command_list) { command_list->bind_pipeline(pipeline_.get()); command_list->bind_raster_resources(raster_state_.get()); - command_list->bind_shader_resources(resource_set_.get()); - command_list->set_line_width(curr_width_ * app_context_->config.height); - - if (indexed_) { - command_list->draw_indexed(config_.indices_count, 0, 0); - } else { - command_list->draw(config_.vertices_count, 0); - } + command_list->draw_indexed(lines_count_ * 6, 0, 0); } void Lines::cleanup() { Renderable::cleanup(); + + vbo_translated_.reset(); + ibo_translated_.reset(); } } // namespace vulkan diff --git a/taichi/ui/backends/vulkan/renderables/lines.h b/taichi/ui/backends/vulkan/renderables/lines.h index 6a45cdf5d2629..165554a616f96 100644 --- a/taichi/ui/backends/vulkan/renderables/lines.h +++ b/taichi/ui/backends/vulkan/renderables/lines.h @@ -31,26 +31,43 @@ class Lines final : public Renderable { void update_data(const LinesInfo &info); + void create_graphics_pipeline() final; + + void record_prepass_this_frame_commands( + taichi::lang::CommandList *command_list) override; + void record_this_frame_commands( taichi::lang::CommandList *command_list) override; private: struct UniformBufferObject { alignas(16) glm::vec3 color; - int use_per_vertex_color; + float line_width; + int per_vertex_color_offset; + int vertex_stride; + int start_vertex; + int start_index; + int num_vertices; + int is_indexed; + float aspect_ratio; }; void init_lines(AppContext *app_context, int vertices_count, int indices_count); - void update_ubo(glm::vec3 color, bool use_per_vertex_color); + void update_ubo(glm::vec3 color, bool use_per_vertex_color, float line_width); void cleanup() override; void create_bindings() override; - float curr_width_; + uint64_t lines_count_{0}; + + std::unique_ptr quad_expand_pipeline_{nullptr}; + + std::unique_ptr vbo_translated_{nullptr}; + std::unique_ptr ibo_translated_{nullptr}; }; } // namespace vulkan diff --git a/taichi/ui/backends/vulkan/renderables/scene_lines.cpp b/taichi/ui/backends/vulkan/renderables/scene_lines.cpp index d50d5bf90539f..9f6b88d7e209c 100644 --- a/taichi/ui/backends/vulkan/renderables/scene_lines.cpp +++ b/taichi/ui/backends/vulkan/renderables/scene_lines.cpp @@ -13,9 +13,59 @@ using namespace taichi::lang::vulkan; void SceneLines::update_data(const SceneLinesInfo &info, const Scene &scene) { Renderable::update_data(info.renderable_info); - update_ubo(info, scene); + lines_count_ = + (indexed_ ? config_.indices_count : config_.vertices_count) / 2; - curr_width_ = info.width; + // FIXME: Why is the width in pixel units? + update_ubo(info, scene, info.width / float(app_context_->config.height)); +} + +void SceneLines::create_graphics_pipeline() { + if (!pipeline_.get()) { + auto vert_code = read_file(config_.vertex_shader_path); + auto frag_code = read_file(config_.fragment_shader_path); + + std::vector source(2); + source[0] = {PipelineSourceType::spirv_binary, frag_code.data(), + frag_code.size(), PipelineStageType::fragment}; + source[1] = {PipelineSourceType::spirv_binary, vert_code.data(), + vert_code.size(), PipelineStageType::vertex}; + + RasterParams raster_params; + raster_params.prim_topology = TopologyType::Triangles; + raster_params.polygon_mode = config_.polygon_mode; + raster_params.depth_test = true; + raster_params.depth_write = true; + + if (config_.blending) { + raster_params.blending.push_back(BlendingParams()); + } + + std::vector vertex_inputs = {{/*binding=*/0, + sizeof(glm::vec4) * 2, + /*instance=*/false}}; + // TODO: consider using uint8 for colors and normals + std::vector vertex_attribs; + vertex_attribs.push_back({/*location=*/0, /*binding=*/0, + /*format=*/BufferFormat::rgba32f, + /*offset=*/0}); + vertex_attribs.push_back({/*location=*/1, /*binding=*/0, + /*format=*/BufferFormat::rgba32f, + /*offset=*/sizeof(glm::vec4)}); + + pipeline_ = app_context_->device().create_raster_pipeline( + source, raster_params, vertex_inputs, vertex_attribs); + } + + if (!quad_expand_pipeline_.get()) { + auto comp_code = read_file(app_context_->config.package_path + + "/shaders/SceneLines2quad_vk_comp.spv"); + auto [pipeline, res] = app_context_->device().create_pipeline_unique( + {PipelineSourceType::spirv_binary, comp_code.data(), comp_code.size(), + PipelineStageType::compute}); + TI_ASSERT(res == RhiResult::success); + quad_expand_pipeline_ = std::move(pipeline); + } } void SceneLines::init_scene_lines(AppContext *app_context, @@ -35,7 +85,7 @@ void SceneLines::init_scene_lines(AppContext *app_context, true, app_context->config.package_path + "/shaders/SceneLines_vk_vert.spv", app_context->config.package_path + "/shaders/SceneLines_vk_frag.spv", - TopologyType::Lines, + TopologyType::Triangles, }; Renderable::init(config, app_context); @@ -46,11 +96,24 @@ SceneLines::SceneLines(AppContext *app_context, VertexAttributes vbo_attrs) { init_scene_lines(app_context, 4, 6); } -void SceneLines::update_ubo(const SceneLinesInfo &info, const Scene &scene) { +void SceneLines::update_ubo(const SceneLinesInfo &info, + const Scene &scene, + float line_width) { UniformBufferObject ubo{}; ubo.scene = scene.current_ubo_; ubo.color = info.color; - ubo.use_per_vertex_color = info.renderable_info.has_per_vertex_color; + ubo.line_width = line_width; + ubo.per_vertex_color_offset = info.renderable_info.has_per_vertex_color + ? offsetof(Vertex, color) / sizeof(float) + : 0; + ubo.vertex_stride = config_.vbo_size() / sizeof(float); + ubo.start_vertex = config_.draw_first_vertex; + ubo.start_index = config_.draw_first_index; + ubo.num_vertices = lines_count_ * 2; + ubo.is_indexed = indexed_ ? 1 : 0; + ubo.aspect_ratio = + float(app_context_->config.width) / float(app_context_->config.height); + void *mapped{nullptr}; TI_ASSERT(app_context_->device().map(uniform_buffer_, &mapped) == RhiResult::success); @@ -59,23 +122,57 @@ void SceneLines::update_ubo(const SceneLinesInfo &info, const Scene &scene) { } void SceneLines::create_bindings() { - Renderable::create_bindings(); - resource_set_->buffer(0, uniform_buffer_); + if (!resource_set_) { + resource_set_ = app_context_->device().create_resource_set_unique(); + } + if (!raster_state_) { + raster_state_ = app_context_->device().create_raster_resources_unique(); + } +} + +void SceneLines::record_prepass_this_frame_commands(CommandList *command_list) { + vbo_translated_.reset(); + ibo_translated_.reset(); + + struct TransformedVertex { + glm::vec4 pos; + glm::vec4 color; + }; + + vbo_translated_ = app_context_->device().allocate_memory_unique( + {/*size=*/uint64_t(sizeof(TransformedVertex) * 4 * lines_count_), + /*host_write=*/false, + /*host_read=*/false, + /*export_sharing=*/false, + /*usage=*/AllocUsage::Storage | AllocUsage::Vertex}); + + ibo_translated_ = app_context_->device().allocate_memory_unique( + {/*size=*/uint64_t(sizeof(int) * 6 * lines_count_), + /*host_write=*/false, + /*host_read=*/false, + /*export_sharing=*/false, + /*usage=*/AllocUsage::Storage | AllocUsage::Index}); + + raster_state_->vertex_buffer(vbo_translated_->get_ptr(0), 0); + raster_state_->index_buffer(ibo_translated_->get_ptr(0), 32); + + resource_set_->rw_buffer(0, vertex_buffer_.get_ptr(0)); + resource_set_->rw_buffer(1, index_buffer_.get_ptr(0)); + resource_set_->rw_buffer(2, vbo_translated_->get_ptr(0)); + resource_set_->rw_buffer(3, ibo_translated_->get_ptr(0)); + resource_set_->buffer(4, uniform_buffer_.get_ptr(0)); + + command_list->bind_pipeline(quad_expand_pipeline_.get()); + command_list->bind_shader_resources(resource_set_.get()); + command_list->dispatch(int(ceil(lines_count_ / 256.0f))); + command_list->buffer_barrier(*vbo_translated_); + command_list->buffer_barrier(*ibo_translated_); } void SceneLines::record_this_frame_commands(CommandList *command_list) { command_list->bind_pipeline(pipeline_.get()); command_list->bind_raster_resources(raster_state_.get()); - command_list->bind_shader_resources(resource_set_.get()); - command_list->set_line_width(curr_width_); - - if (indexed_) { - command_list->draw_indexed(config_.draw_index_count, - config_.draw_first_vertex, - config_.draw_first_index); - } else { - command_list->draw(config_.draw_vertex_count, config_.draw_first_vertex); - } + command_list->draw_indexed(lines_count_ * 6, 0, 0); } void SceneLines::cleanup() { diff --git a/taichi/ui/backends/vulkan/renderables/scene_lines.h b/taichi/ui/backends/vulkan/renderables/scene_lines.h index cc2db6887d7a6..5c561ec997c6b 100644 --- a/taichi/ui/backends/vulkan/renderables/scene_lines.h +++ b/taichi/ui/backends/vulkan/renderables/scene_lines.h @@ -31,6 +31,9 @@ class SceneLines final : public Renderable { void update_data(const SceneLinesInfo &info, const Scene &scene); + void record_prepass_this_frame_commands( + taichi::lang::CommandList *command_list) override; + void record_this_frame_commands( taichi::lang::CommandList *command_list) override; @@ -38,20 +41,36 @@ class SceneLines final : public Renderable { struct UniformBufferObject { Scene::SceneUniformBuffer scene; alignas(16) glm::vec3 color; - int use_per_vertex_color; + float line_width; + int per_vertex_color_offset; + int vertex_stride; + int start_vertex; + int start_index; + int num_vertices; + int is_indexed; + float aspect_ratio; }; void init_scene_lines(AppContext *app_context, int vertices_count, int indices_count); - void update_ubo(const SceneLinesInfo &info, const Scene &scene); + void create_graphics_pipeline() final; + + void update_ubo(const SceneLinesInfo &info, + const Scene &scene, + float line_width); void cleanup() override; void create_bindings() override; - float curr_width_; + uint64_t lines_count_{0}; + + std::unique_ptr quad_expand_pipeline_{nullptr}; + + std::unique_ptr vbo_translated_{nullptr}; + std::unique_ptr ibo_translated_{nullptr}; }; } // namespace vulkan diff --git a/taichi/ui/backends/vulkan/renderer.cpp b/taichi/ui/backends/vulkan/renderer.cpp index 1cec7202e1418..65b697bdb5634 100644 --- a/taichi/ui/backends/vulkan/renderer.cpp +++ b/taichi/ui/backends/vulkan/renderer.cpp @@ -156,6 +156,7 @@ void Renderer::draw_frame(Gui *gui) { auto stream = app_context_.device().get_graphics_stream(); auto [cmd_list, res] = stream->new_command_list_unique(); assert(res == RhiResult::success && "Failed to allocate command list"); + bool color_clear = true; std::vector clear_colors = {background_color_[0], background_color_[1], background_color_[2], 1}; @@ -164,6 +165,11 @@ void Renderer::draw_frame(Gui *gui) { cmd_list->image_transition(image, ImageLayout::undefined, ImageLayout::color_attachment); auto depth_image = swap_chain_.depth_allocation(); + + for (int i = 0; i < next_renderable_; ++i) { + renderables_[i]->record_prepass_this_frame_commands(cmd_list.get()); + } + cmd_list->begin_renderpass( /*x0=*/0, /*y0=*/0, /*x1=*/swap_chain_.width(), /*y1=*/swap_chain_.height(), /*num_color_attachments=*/1, &image, diff --git a/taichi/ui/backends/vulkan/swap_chain.cpp b/taichi/ui/backends/vulkan/swap_chain.cpp index b9081dd8c421d..2bea93b915f5b 100644 --- a/taichi/ui/backends/vulkan/swap_chain.cpp +++ b/taichi/ui/backends/vulkan/swap_chain.cpp @@ -58,6 +58,8 @@ bool SwapChain::copy_depth_buffer_to_ndarray( auto *stream = device.get_graphics_stream(); std::unique_ptr cmd_list{nullptr}; + device.wait_idle(); + if (memcpy_cap == Device::MemcpyCapability::Direct) { Device::AllocParams params{copy_size, /*host_wrtie*/ false, /*host_read*/ false, /*export_sharing*/ true, @@ -121,6 +123,10 @@ taichi::lang::Surface &SwapChain::surface() { } std::vector &SwapChain::dump_image_buffer() { + app_context_->device().wait_idle(); + + TI_INFO("Dumping image buffer..."); + auto [w, h] = surface_->get_size(); curr_width_ = w; curr_height_ = h; diff --git a/tests/python/test_ggui.py b/tests/python/test_ggui.py index b1ac383cd2f63..8fcfd5d749c68 100644 --- a/tests/python/test_ggui.py +++ b/tests/python/test_ggui.py @@ -8,6 +8,7 @@ from tests import test_utils from tests.test_utils import verify_image +# FIXME: render(); get_image_buffer_as_numpy() loop does not actually redraw RENDER_REPEAT = 5 # FIXME: enable ggui tests on ti.cpu backend. It's blocked by macos10.15 supported_archs = [ti.vulkan, ti.cuda] @@ -108,12 +109,7 @@ def render(): window.get_image_buffer_as_numpy() render() - if (platform.system() == 'Darwin'): - # FIXME: Use lower tolerance when macOS ggui supports wide lines - verify_image(window.get_image_buffer_as_numpy(), 'test_geometry_2d', - 1.0) - else: - verify_image(window.get_image_buffer_as_numpy(), 'test_geometry_2d') + verify_image(window.get_image_buffer_as_numpy(), 'test_geometry_2d') window.destroy() @@ -454,13 +450,7 @@ def render(): window.get_image_buffer_as_numpy() render() - if (platform.system() == 'Darwin'): - # TODO:Fix the bug that mac not support wide lines - verify_image(window.get_image_buffer_as_numpy(), 'test_draw_lines.mac', - 0.2) - else: - verify_image(window.get_image_buffer_as_numpy(), 'test_draw_lines', - 0.2) + verify_image(window.get_image_buffer_as_numpy(), 'test_draw_lines') window.destroy() @@ -638,13 +628,7 @@ def render(): window.get_image_buffer_as_numpy() render() - if (platform.system() == 'Darwin'): - # TODO:Fix the bug that mac not support wide lines - verify_image(window.get_image_buffer_as_numpy(), - 'test_draw_part_of_lines.mac') - else: - verify_image(window.get_image_buffer_as_numpy(), - 'test_draw_part_of_lines') + verify_image(window.get_image_buffer_as_numpy(), 'test_draw_part_of_lines') window.destroy()