@next2d/webgpu 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (349) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +574 -0
  3. package/package.json +30 -0
  4. package/src/AtlasManager.d.ts +23 -0
  5. package/src/AtlasManager.js +123 -0
  6. package/src/AttachmentManager/service/AttachmentManagerCreateAttachmentObjectService.d.ts +13 -0
  7. package/src/AttachmentManager/service/AttachmentManagerCreateAttachmentObjectService.js +24 -0
  8. package/src/AttachmentManager/service/AttachmentManagerCreateColorBufferService.d.ts +15 -0
  9. package/src/AttachmentManager/service/AttachmentManagerCreateColorBufferService.js +31 -0
  10. package/src/AttachmentManager/service/AttachmentManagerCreateRenderPassDescriptorService.d.ts +5 -0
  11. package/src/AttachmentManager/service/AttachmentManagerCreateRenderPassDescriptorService.js +42 -0
  12. package/src/AttachmentManager/service/AttachmentManagerCreateStencilBufferService.d.ts +16 -0
  13. package/src/AttachmentManager/service/AttachmentManagerCreateStencilBufferService.js +28 -0
  14. package/src/AttachmentManager/service/AttachmentManagerCreateTextureObjectService.d.ts +17 -0
  15. package/src/AttachmentManager/service/AttachmentManagerCreateTextureObjectService.js +33 -0
  16. package/src/AttachmentManager/service/AttachmentManagerGetColorBufferService.d.ts +16 -0
  17. package/src/AttachmentManager/service/AttachmentManagerGetColorBufferService.js +28 -0
  18. package/src/AttachmentManager/service/AttachmentManagerGetStencilBufferService.d.ts +17 -0
  19. package/src/AttachmentManager/service/AttachmentManagerGetStencilBufferService.js +27 -0
  20. package/src/AttachmentManager/service/AttachmentManagerGetTextureService.d.ts +18 -0
  21. package/src/AttachmentManager/service/AttachmentManagerGetTextureService.js +27 -0
  22. package/src/AttachmentManager/service/AttachmentManagerReleaseTextureService.d.ts +12 -0
  23. package/src/AttachmentManager/service/AttachmentManagerReleaseTextureService.js +17 -0
  24. package/src/AttachmentManager/usecase/AttachmentManagerGetAttachmentObjectUseCase.d.ts +26 -0
  25. package/src/AttachmentManager/usecase/AttachmentManagerGetAttachmentObjectUseCase.js +43 -0
  26. package/src/AttachmentManager/usecase/AttachmentManagerReleaseAttachmentUseCase.d.ts +18 -0
  27. package/src/AttachmentManager/usecase/AttachmentManagerReleaseAttachmentUseCase.js +33 -0
  28. package/src/AttachmentManager.d.ts +19 -0
  29. package/src/AttachmentManager.js +105 -0
  30. package/src/BezierConverter/BezierConverter.d.ts +16 -0
  31. package/src/BezierConverter/BezierConverter.js +15 -0
  32. package/src/BezierConverter/service/BezierConverterCalculateFlatnessService.d.ts +15 -0
  33. package/src/BezierConverter/service/BezierConverterCalculateFlatnessService.js +37 -0
  34. package/src/BezierConverter/service/BezierConverterSplitCubicService.d.ts +15 -0
  35. package/src/BezierConverter/service/BezierConverterSplitCubicService.js +47 -0
  36. package/src/BezierConverter/usecase/BezierConverterAdaptiveCubicToQuadUseCase.d.ts +29 -0
  37. package/src/BezierConverter/usecase/BezierConverterAdaptiveCubicToQuadUseCase.js +80 -0
  38. package/src/Blend/BlendInstancedManager.d.ts +35 -0
  39. package/src/Blend/BlendInstancedManager.js +147 -0
  40. package/src/Blend/service/BlendAddService.d.ts +1 -0
  41. package/src/Blend/service/BlendAddService.js +8 -0
  42. package/src/Blend/service/BlendAlphaService.d.ts +1 -0
  43. package/src/Blend/service/BlendAlphaService.js +8 -0
  44. package/src/Blend/service/BlendEraseService.d.ts +1 -0
  45. package/src/Blend/service/BlendEraseService.js +8 -0
  46. package/src/Blend/service/BlendGetStateService.d.ts +12 -0
  47. package/src/Blend/service/BlendGetStateService.js +13 -0
  48. package/src/Blend/service/BlendOneZeroService.d.ts +1 -0
  49. package/src/Blend/service/BlendOneZeroService.js +8 -0
  50. package/src/Blend/service/BlendResetService.d.ts +1 -0
  51. package/src/Blend/service/BlendResetService.js +8 -0
  52. package/src/Blend/service/BlendScreenService.d.ts +1 -0
  53. package/src/Blend/service/BlendScreenService.js +8 -0
  54. package/src/Blend/service/BlendSetModeService.d.ts +2 -0
  55. package/src/Blend/service/BlendSetModeService.js +4 -0
  56. package/src/Blend/usecase/BlendApplyComplexBlendUseCase.d.ts +6 -0
  57. package/src/Blend/usecase/BlendApplyComplexBlendUseCase.js +79 -0
  58. package/src/Blend/usecase/BlendOperationUseCase.d.ts +11 -0
  59. package/src/Blend/usecase/BlendOperationUseCase.js +31 -0
  60. package/src/Blend.d.ts +8 -0
  61. package/src/Blend.js +91 -0
  62. package/src/BufferManager/service/BufferManagerCreateIndirectBufferService.d.ts +15 -0
  63. package/src/BufferManager/service/BufferManagerCreateIndirectBufferService.js +37 -0
  64. package/src/BufferManager/service/BufferManagerCreateRectVerticesService.d.ts +13 -0
  65. package/src/BufferManager/service/BufferManagerCreateRectVerticesService.js +23 -0
  66. package/src/BufferManager/service/BufferManagerCreateStorageBufferService.d.ts +17 -0
  67. package/src/BufferManager/service/BufferManagerCreateStorageBufferService.js +23 -0
  68. package/src/BufferManager/service/BufferManagerReleaseUniformBufferService.d.ts +12 -0
  69. package/src/BufferManager/service/BufferManagerReleaseUniformBufferService.js +32 -0
  70. package/src/BufferManager/service/BufferManagerReleaseVertexBufferService.d.ts +12 -0
  71. package/src/BufferManager/service/BufferManagerReleaseVertexBufferService.js +32 -0
  72. package/src/BufferManager/service/BufferManagerUpdateIndirectBufferService.d.ts +12 -0
  73. package/src/BufferManager/service/BufferManagerUpdateIndirectBufferService.js +20 -0
  74. package/src/BufferManager/service/BufferManagerUpperPowerOfTwoService.d.ts +10 -0
  75. package/src/BufferManager/service/BufferManagerUpperPowerOfTwoService.js +18 -0
  76. package/src/BufferManager/usecase/BufferManagerAcquireStorageBufferUseCase.d.ts +15 -0
  77. package/src/BufferManager/usecase/BufferManagerAcquireStorageBufferUseCase.js +51 -0
  78. package/src/BufferManager/usecase/BufferManagerAcquireUniformBufferUseCase.d.ts +13 -0
  79. package/src/BufferManager/usecase/BufferManagerAcquireUniformBufferUseCase.js +26 -0
  80. package/src/BufferManager/usecase/BufferManagerAcquireVertexBufferUseCase.d.ts +14 -0
  81. package/src/BufferManager/usecase/BufferManagerAcquireVertexBufferUseCase.js +46 -0
  82. package/src/BufferManager/usecase/BufferManagerCleanupStorageBuffersUseCase.d.ts +12 -0
  83. package/src/BufferManager/usecase/BufferManagerCleanupStorageBuffersUseCase.js +20 -0
  84. package/src/BufferManager/usecase/BufferManagerReleaseStorageBufferUseCase.d.ts +9 -0
  85. package/src/BufferManager/usecase/BufferManagerReleaseStorageBufferUseCase.js +15 -0
  86. package/src/BufferManager.d.ts +93 -0
  87. package/src/BufferManager.js +487 -0
  88. package/src/Compute/ComputePipelineManager.d.ts +61 -0
  89. package/src/Compute/ComputePipelineManager.js +313 -0
  90. package/src/Compute/service/ComputeExecuteBlurService.d.ts +21 -0
  91. package/src/Compute/service/ComputeExecuteBlurService.js +81 -0
  92. package/src/Context/service/ContextComputeBitmapMatrixService.d.ts +1 -0
  93. package/src/Context/service/ContextComputeBitmapMatrixService.js +74 -0
  94. package/src/Context/service/ContextComputeGradientMatrixService.d.ts +4 -0
  95. package/src/Context/service/ContextComputeGradientMatrixService.js +88 -0
  96. package/src/Context/service/ContextFillSimpleService.d.ts +2 -0
  97. package/src/Context/service/ContextFillSimpleService.js +28 -0
  98. package/src/Context/service/ContextFillWithStencilMainService.d.ts +2 -0
  99. package/src/Context/service/ContextFillWithStencilMainService.js +19 -0
  100. package/src/Context/service/ContextFillWithStencilService.d.ts +2 -0
  101. package/src/Context/service/ContextFillWithStencilService.js +19 -0
  102. package/src/Context/usecase/ContextApplyFilterUseCase.d.ts +5 -0
  103. package/src/Context/usecase/ContextApplyFilterUseCase.js +668 -0
  104. package/src/Context/usecase/ContextBitmapFillUseCase.d.ts +4 -0
  105. package/src/Context/usecase/ContextBitmapFillUseCase.js +210 -0
  106. package/src/Context/usecase/ContextBitmapStrokeUseCase.d.ts +4 -0
  107. package/src/Context/usecase/ContextBitmapStrokeUseCase.js +119 -0
  108. package/src/Context/usecase/ContextClipUseCase.d.ts +5 -0
  109. package/src/Context/usecase/ContextClipUseCase.js +101 -0
  110. package/src/Context/usecase/ContextContainerEndLayerUseCase.d.ts +5 -0
  111. package/src/Context/usecase/ContextContainerEndLayerUseCase.js +476 -0
  112. package/src/Context/usecase/ContextDrawArraysInstancedUseCase.d.ts +6 -0
  113. package/src/Context/usecase/ContextDrawArraysInstancedUseCase.js +135 -0
  114. package/src/Context/usecase/ContextDrawIndirectUseCase.d.ts +6 -0
  115. package/src/Context/usecase/ContextDrawIndirectUseCase.js +154 -0
  116. package/src/Context/usecase/ContextGradientFillUseCase.d.ts +4 -0
  117. package/src/Context/usecase/ContextGradientFillUseCase.js +230 -0
  118. package/src/Context/usecase/ContextGradientStrokeUseCase.d.ts +4 -0
  119. package/src/Context/usecase/ContextGradientStrokeUseCase.js +138 -0
  120. package/src/Context/usecase/ContextProcessComplexBlendQueueUseCase.d.ts +6 -0
  121. package/src/Context/usecase/ContextProcessComplexBlendQueueUseCase.js +213 -0
  122. package/src/Context.d.ts +430 -0
  123. package/src/Context.js +2453 -0
  124. package/src/FillTexturePool.d.ts +6 -0
  125. package/src/FillTexturePool.js +72 -0
  126. package/src/Filter/BevelFilter/FilterApplyBevelFilterUseCase.d.ts +10 -0
  127. package/src/Filter/BevelFilter/FilterApplyBevelFilterUseCase.js +214 -0
  128. package/src/Filter/BevelFilterShader.d.ts +2 -0
  129. package/src/Filter/BevelFilterShader.js +107 -0
  130. package/src/Filter/BitmapFilterShader.d.ts +2 -0
  131. package/src/Filter/BitmapFilterShader.js +207 -0
  132. package/src/Filter/BlurFilter/FilterApplyBlurFilterUseCase.d.ts +16 -0
  133. package/src/Filter/BlurFilter/FilterApplyBlurFilterUseCase.js +243 -0
  134. package/src/Filter/BlurFilter/service/BlurFilterComputeShaderService.d.ts +40 -0
  135. package/src/Filter/BlurFilter/service/BlurFilterComputeShaderService.js +51 -0
  136. package/src/Filter/BlurFilter/usecase/FilterApplyBlurComputeUseCase.d.ts +25 -0
  137. package/src/Filter/BlurFilter/usecase/FilterApplyBlurComputeUseCase.js +180 -0
  138. package/src/Filter/BlurFilterShader.d.ts +5 -0
  139. package/src/Filter/BlurFilterShader.js +109 -0
  140. package/src/Filter/BlurFilterUseCase.d.ts +36 -0
  141. package/src/Filter/BlurFilterUseCase.js +85 -0
  142. package/src/Filter/ColorMatrixFilter/FilterApplyColorMatrixFilterUseCase.d.ts +12 -0
  143. package/src/Filter/ColorMatrixFilter/FilterApplyColorMatrixFilterUseCase.js +90 -0
  144. package/src/Filter/ColorMatrixFilterShader.d.ts +4 -0
  145. package/src/Filter/ColorMatrixFilterShader.js +51 -0
  146. package/src/Filter/ConvolutionFilter/FilterApplyConvolutionFilterUseCase.d.ts +6 -0
  147. package/src/Filter/ConvolutionFilter/FilterApplyConvolutionFilterUseCase.js +144 -0
  148. package/src/Filter/ConvolutionFilterShader.d.ts +2 -0
  149. package/src/Filter/ConvolutionFilterShader.js +115 -0
  150. package/src/Filter/DisplacementMapFilter/FilterApplyDisplacementMapFilterUseCase.d.ts +6 -0
  151. package/src/Filter/DisplacementMapFilter/FilterApplyDisplacementMapFilterUseCase.js +172 -0
  152. package/src/Filter/DisplacementMapFilterShader.d.ts +2 -0
  153. package/src/Filter/DisplacementMapFilterShader.js +114 -0
  154. package/src/Filter/DropShadowFilter/FilterApplyDropShadowFilterUseCase.d.ts +24 -0
  155. package/src/Filter/DropShadowFilter/FilterApplyDropShadowFilterUseCase.js +179 -0
  156. package/src/Filter/DropShadowFilterShader.d.ts +4 -0
  157. package/src/Filter/DropShadowFilterShader.js +93 -0
  158. package/src/Filter/FilterGradientLUTCache.d.ts +29 -0
  159. package/src/Filter/FilterGradientLUTCache.js +84 -0
  160. package/src/Filter/FilterOffset.d.ts +8 -0
  161. package/src/Filter/FilterOffset.js +10 -0
  162. package/src/Filter/GlowFilter/FilterApplyGlowFilterUseCase.d.ts +24 -0
  163. package/src/Filter/GlowFilter/FilterApplyGlowFilterUseCase.js +143 -0
  164. package/src/Filter/GlowFilterShader.d.ts +4 -0
  165. package/src/Filter/GlowFilterShader.js +66 -0
  166. package/src/Filter/GradientBevelFilter/FilterApplyGradientBevelFilterUseCase.d.ts +29 -0
  167. package/src/Filter/GradientBevelFilter/FilterApplyGradientBevelFilterUseCase.js +216 -0
  168. package/src/Filter/GradientGlowFilter/FilterApplyGradientGlowFilterUseCase.d.ts +29 -0
  169. package/src/Filter/GradientGlowFilter/FilterApplyGradientGlowFilterUseCase.js +164 -0
  170. package/src/FrameBufferManager/service/FrameBufferManagerCreateRenderPassDescriptorService.d.ts +4 -0
  171. package/src/FrameBufferManager/service/FrameBufferManagerCreateRenderPassDescriptorService.js +23 -0
  172. package/src/FrameBufferManager/service/FrameBufferManagerCreateStencilRenderPassDescriptorService.d.ts +4 -0
  173. package/src/FrameBufferManager/service/FrameBufferManagerCreateStencilRenderPassDescriptorService.js +28 -0
  174. package/src/FrameBufferManager/service/FrameBufferManagerFlushPendingReleasesService.d.ts +11 -0
  175. package/src/FrameBufferManager/service/FrameBufferManagerFlushPendingReleasesService.js +19 -0
  176. package/src/FrameBufferManager/usecase/FrameBufferManagerCreateAttachmentUseCase.d.ts +23 -0
  177. package/src/FrameBufferManager/usecase/FrameBufferManagerCreateAttachmentUseCase.js +125 -0
  178. package/src/FrameBufferManager/usecase/FrameBufferManagerReleaseTemporaryAttachmentUseCase.d.ts +14 -0
  179. package/src/FrameBufferManager/usecase/FrameBufferManagerReleaseTemporaryAttachmentUseCase.js +23 -0
  180. package/src/FrameBufferManager.d.ts +24 -0
  181. package/src/FrameBufferManager.js +161 -0
  182. package/src/Gradient/GradientLUTCache.d.ts +61 -0
  183. package/src/Gradient/GradientLUTCache.js +153 -0
  184. package/src/Gradient/GradientLUTGenerator.d.ts +30 -0
  185. package/src/Gradient/GradientLUTGenerator.js +202 -0
  186. package/src/Grid.d.ts +18 -0
  187. package/src/Grid.js +21 -0
  188. package/src/Mask/service/MaskBeginMaskService.d.ts +9 -0
  189. package/src/Mask/service/MaskBeginMaskService.js +22 -0
  190. package/src/Mask/service/MaskEndMaskService.d.ts +15 -0
  191. package/src/Mask/service/MaskEndMaskService.js +36 -0
  192. package/src/Mask/service/MaskSetMaskBoundsService.d.ts +13 -0
  193. package/src/Mask/service/MaskSetMaskBoundsService.js +36 -0
  194. package/src/Mask/service/MaskUnionMaskService.d.ts +4 -0
  195. package/src/Mask/service/MaskUnionMaskService.js +74 -0
  196. package/src/Mask/usecase/MaskBindUseCase.d.ts +10 -0
  197. package/src/Mask/usecase/MaskBindUseCase.js +20 -0
  198. package/src/Mask/usecase/MaskLeaveMaskUseCase.d.ts +13 -0
  199. package/src/Mask/usecase/MaskLeaveMaskUseCase.js +51 -0
  200. package/src/Mask.d.ts +12 -0
  201. package/src/Mask.js +41 -0
  202. package/src/Mesh/service/MeshFillGenerateService.d.ts +19 -0
  203. package/src/Mesh/service/MeshFillGenerateService.js +76 -0
  204. package/src/Mesh/service/MeshLerpService.d.ts +13 -0
  205. package/src/Mesh/service/MeshLerpService.js +17 -0
  206. package/src/Mesh/service/MeshStrokeFillGenerateService.d.ts +19 -0
  207. package/src/Mesh/service/MeshStrokeFillGenerateService.js +76 -0
  208. package/src/Mesh/usecase/MeshBitmapStrokeGenerateUseCase.d.ts +13 -0
  209. package/src/Mesh/usecase/MeshBitmapStrokeGenerateUseCase.js +65 -0
  210. package/src/Mesh/usecase/MeshFillGenerateUseCase.d.ts +12 -0
  211. package/src/Mesh/usecase/MeshFillGenerateUseCase.js +48 -0
  212. package/src/Mesh/usecase/MeshGradientStrokeGenerateUseCase.d.ts +13 -0
  213. package/src/Mesh/usecase/MeshGradientStrokeGenerateUseCase.js +65 -0
  214. package/src/Mesh/usecase/MeshSplitQuadraticBezierUseCase.d.ts +14 -0
  215. package/src/Mesh/usecase/MeshSplitQuadraticBezierUseCase.js +28 -0
  216. package/src/Mesh/usecase/MeshStrokeFillGenerateUseCase.d.ts +18 -0
  217. package/src/Mesh/usecase/MeshStrokeFillGenerateUseCase.js +54 -0
  218. package/src/Mesh/usecase/MeshStrokeGenerateUseCase.d.ts +25 -0
  219. package/src/Mesh/usecase/MeshStrokeGenerateUseCase.js +608 -0
  220. package/src/PathCommand.d.ts +123 -0
  221. package/src/PathCommand.js +317 -0
  222. package/src/SamplerCache/service/SamplerCacheCreateCommonSamplersService.d.ts +11 -0
  223. package/src/SamplerCache/service/SamplerCacheCreateCommonSamplersService.js +35 -0
  224. package/src/SamplerCache/service/SamplerCacheGenerateKeyService.d.ts +13 -0
  225. package/src/SamplerCache/service/SamplerCacheGenerateKeyService.js +15 -0
  226. package/src/SamplerCache/service/SamplerCacheGetOrCreateService.d.ts +15 -0
  227. package/src/SamplerCache/service/SamplerCacheGetOrCreateService.js +30 -0
  228. package/src/SamplerCache.d.ts +18 -0
  229. package/src/SamplerCache.js +61 -0
  230. package/src/Shader/BlendModeShader.d.ts +51 -0
  231. package/src/Shader/BlendModeShader.js +71 -0
  232. package/src/Shader/GradientLUTGenerator/service/GradientLUTCalculateResolutionService.d.ts +12 -0
  233. package/src/Shader/GradientLUTGenerator/service/GradientLUTCalculateResolutionService.js +28 -0
  234. package/src/Shader/GradientLUTGenerator/service/GradientLUTGeneratePixelsService.d.ts +13 -0
  235. package/src/Shader/GradientLUTGenerator/service/GradientLUTGeneratePixelsService.js +61 -0
  236. package/src/Shader/GradientLUTGenerator/service/GradientLUTInterpolateColorService.d.ts +19 -0
  237. package/src/Shader/GradientLUTGenerator/service/GradientLUTInterpolateColorService.js +37 -0
  238. package/src/Shader/GradientLUTGenerator/service/GradientLUTParseStopsService.d.ts +11 -0
  239. package/src/Shader/GradientLUTGenerator/service/GradientLUTParseStopsService.js +24 -0
  240. package/src/Shader/GradientLUTGenerator/usecase/GradientLUTGenerateDataUseCase.d.ts +14 -0
  241. package/src/Shader/GradientLUTGenerator/usecase/GradientLUTGenerateDataUseCase.js +24 -0
  242. package/src/Shader/PipelineManager.d.ts +57 -0
  243. package/src/Shader/PipelineManager.js +2868 -0
  244. package/src/Shader/ShaderInstancedManager.d.ts +8 -0
  245. package/src/Shader/ShaderInstancedManager.js +18 -0
  246. package/src/Shader/ShaderSource.d.ts +60 -0
  247. package/src/Shader/ShaderSource.js +518 -0
  248. package/src/Shader/wgsl/common/SharedWgsl.d.ts +5 -0
  249. package/src/Shader/wgsl/common/SharedWgsl.js +37 -0
  250. package/src/Shader/wgsl/fragment/BasicFragment.d.ts +2 -0
  251. package/src/Shader/wgsl/fragment/BasicFragment.js +28 -0
  252. package/src/Shader/wgsl/fragment/BitmapFragment.d.ts +1 -0
  253. package/src/Shader/wgsl/fragment/BitmapFragment.js +43 -0
  254. package/src/Shader/wgsl/fragment/BlendFragment.d.ts +8 -0
  255. package/src/Shader/wgsl/fragment/BlendFragment.js +63 -0
  256. package/src/Shader/wgsl/fragment/EffectFragment.d.ts +6 -0
  257. package/src/Shader/wgsl/fragment/EffectFragment.js +324 -0
  258. package/src/Shader/wgsl/fragment/FillFragment.d.ts +1 -0
  259. package/src/Shader/wgsl/fragment/FillFragment.js +28 -0
  260. package/src/Shader/wgsl/fragment/FilterFragment.d.ts +10 -0
  261. package/src/Shader/wgsl/fragment/FilterFragment.js +212 -0
  262. package/src/Shader/wgsl/fragment/GradientFragment.d.ts +3 -0
  263. package/src/Shader/wgsl/fragment/GradientFragment.js +118 -0
  264. package/src/Shader/wgsl/fragment/InstancedFragment.d.ts +1 -0
  265. package/src/Shader/wgsl/fragment/InstancedFragment.js +20 -0
  266. package/src/Shader/wgsl/fragment/MaskFragment.d.ts +1 -0
  267. package/src/Shader/wgsl/fragment/MaskFragment.js +17 -0
  268. package/src/Shader/wgsl/fragment/StencilFragment.d.ts +2 -0
  269. package/src/Shader/wgsl/fragment/StencilFragment.js +33 -0
  270. package/src/Shader/wgsl/vertex/BasicVertex.d.ts +1 -0
  271. package/src/Shader/wgsl/vertex/BasicVertex.js +37 -0
  272. package/src/Shader/wgsl/vertex/BitmapVertex.d.ts +1 -0
  273. package/src/Shader/wgsl/vertex/BitmapVertex.js +43 -0
  274. package/src/Shader/wgsl/vertex/FillVertex.d.ts +1 -0
  275. package/src/Shader/wgsl/vertex/FillVertex.js +35 -0
  276. package/src/Shader/wgsl/vertex/FilterVertex.d.ts +12 -0
  277. package/src/Shader/wgsl/vertex/FilterVertex.js +193 -0
  278. package/src/Shader/wgsl/vertex/GradientVertex.d.ts +1 -0
  279. package/src/Shader/wgsl/vertex/GradientVertex.js +44 -0
  280. package/src/Shader/wgsl/vertex/InstancedVertex.d.ts +1 -0
  281. package/src/Shader/wgsl/vertex/InstancedVertex.js +48 -0
  282. package/src/Shader/wgsl/vertex/MaskVertex.d.ts +1 -0
  283. package/src/Shader/wgsl/vertex/MaskVertex.js +36 -0
  284. package/src/Shader/wgsl/vertex/StencilVertex.d.ts +2 -0
  285. package/src/Shader/wgsl/vertex/StencilVertex.js +66 -0
  286. package/src/TextureManager/service/TextureManagerInitializeSamplersService.d.ts +11 -0
  287. package/src/TextureManager/service/TextureManagerInitializeSamplersService.js +48 -0
  288. package/src/TextureManager/usecase/TextureManagerCreateTextureFromImageBitmapUseCase.d.ts +13 -0
  289. package/src/TextureManager/usecase/TextureManagerCreateTextureFromImageBitmapUseCase.js +30 -0
  290. package/src/TextureManager/usecase/TextureManagerCreateTextureFromPixelsUseCase.d.ts +15 -0
  291. package/src/TextureManager/usecase/TextureManagerCreateTextureFromPixelsUseCase.js +26 -0
  292. package/src/TextureManager.d.ts +15 -0
  293. package/src/TextureManager.js +87 -0
  294. package/src/TexturePool/service/TexturePoolCleanupService.d.ts +14 -0
  295. package/src/TexturePool/service/TexturePoolCleanupService.js +28 -0
  296. package/src/TexturePool/service/TexturePoolEvictOldestService.d.ts +11 -0
  297. package/src/TexturePool/service/TexturePoolEvictOldestService.js +24 -0
  298. package/src/TexturePool/service/TexturePoolReleaseService.d.ts +13 -0
  299. package/src/TexturePool/service/TexturePoolReleaseService.js +22 -0
  300. package/src/TexturePool/usecase/TexturePoolAcquireUseCase.d.ts +19 -0
  301. package/src/TexturePool/usecase/TexturePoolAcquireUseCase.js +90 -0
  302. package/src/TexturePool.d.ts +69 -0
  303. package/src/TexturePool.js +151 -0
  304. package/src/WebGPUUtil.d.ts +102 -0
  305. package/src/WebGPUUtil.js +157 -0
  306. package/src/index.d.ts +1 -0
  307. package/src/index.js +1 -0
  308. package/src/interface/IAttachmentObject.d.ts +41 -0
  309. package/src/interface/IAttachmentObject.js +1 -0
  310. package/src/interface/IBlendMode.d.ts +1 -0
  311. package/src/interface/IBlendMode.js +1 -0
  312. package/src/interface/IBlendState.d.ts +8 -0
  313. package/src/interface/IBlendState.js +1 -0
  314. package/src/interface/IBounds.d.ts +6 -0
  315. package/src/interface/IBounds.js +1 -0
  316. package/src/interface/ICachedBindGroup.d.ts +8 -0
  317. package/src/interface/ICachedBindGroup.js +1 -0
  318. package/src/interface/IColorBufferObject.d.ts +17 -0
  319. package/src/interface/IColorBufferObject.js +1 -0
  320. package/src/interface/IComplexBlendItem.d.ts +19 -0
  321. package/src/interface/IComplexBlendItem.js +1 -0
  322. package/src/interface/IFilterConfig.d.ts +29 -0
  323. package/src/interface/IFilterConfig.js +1 -0
  324. package/src/interface/IGradientLUTData.d.ts +8 -0
  325. package/src/interface/IGradientLUTData.js +1 -0
  326. package/src/interface/IGradientStop.d.ts +11 -0
  327. package/src/interface/IGradientStop.js +1 -0
  328. package/src/interface/ILocalFilterConfig.d.ts +21 -0
  329. package/src/interface/ILocalFilterConfig.js +1 -0
  330. package/src/interface/IMeshResult.d.ts +8 -0
  331. package/src/interface/IMeshResult.js +1 -0
  332. package/src/interface/IPath.d.ts +8 -0
  333. package/src/interface/IPath.js +1 -0
  334. package/src/interface/IPoint.d.ts +4 -0
  335. package/src/interface/IPoint.js +1 -0
  336. package/src/interface/IPooledBuffer.d.ts +8 -0
  337. package/src/interface/IPooledBuffer.js +1 -0
  338. package/src/interface/IPooledTexture.d.ts +17 -0
  339. package/src/interface/IPooledTexture.js +1 -0
  340. package/src/interface/IQuadraticSegment.d.ts +9 -0
  341. package/src/interface/IQuadraticSegment.js +1 -0
  342. package/src/interface/IRectangleInfo.d.ts +13 -0
  343. package/src/interface/IRectangleInfo.js +1 -0
  344. package/src/interface/IStencilBufferObject.d.ts +16 -0
  345. package/src/interface/IStencilBufferObject.js +1 -0
  346. package/src/interface/IStorageBufferConfig.d.ts +40 -0
  347. package/src/interface/IStorageBufferConfig.js +1 -0
  348. package/src/interface/ITextureObject.d.ts +16 -0
  349. package/src/interface/ITextureObject.js +1 -0
package/src/Context.js ADDED
@@ -0,0 +1,2453 @@
1
+ import { TexturePacker } from "@next2d/texture-packer";
2
+ import { $cacheStore } from "@next2d/cache";
3
+ import { WebGPUUtil, $setContext } from "./WebGPUUtil";
4
+ import { PathCommand } from "./PathCommand";
5
+ import { BufferManager } from "./BufferManager";
6
+ import { TextureManager } from "./TextureManager";
7
+ import { FrameBufferManager } from "./FrameBufferManager";
8
+ import { AttachmentManager } from "./AttachmentManager";
9
+ import { PipelineManager } from "./Shader/PipelineManager";
10
+ import { ComputePipelineManager } from "./Compute/ComputePipelineManager";
11
+ import { $rootNodes, $resetAtlas, $getActiveAtlasIndex, $setActiveAtlasIndex, $setAtlasCreator, $getAtlasAttachmentObject, $getAtlasAttachmentObjectByIndex } from "./AtlasManager";
12
+ import { addDisplayObjectToInstanceArray, getInstancedShaderManager } from "./Blend/BlendInstancedManager";
13
+ import { execute as maskBeginMaskService } from "./Mask/service/MaskBeginMaskService";
14
+ import { execute as maskSetMaskBoundsService } from "./Mask/service/MaskSetMaskBoundsService";
15
+ import { execute as maskEndMaskService } from "./Mask/service/MaskEndMaskService";
16
+ import { execute as maskLeaveMaskUseCase } from "./Mask/usecase/MaskLeaveMaskUseCase";
17
+ import { $isMaskTestEnabled, $isMaskDrawing, $getMaskStencilReference, $resetMaskState } from "./Mask";
18
+ import { execute as meshFillGenerateUseCase } from "./Mesh/usecase/MeshFillGenerateUseCase";
19
+ import { generateStrokeMesh } from "./Mesh/usecase/MeshStrokeGenerateUseCase";
20
+ import { $gridDataMap, $fillBufferIndex, $terminateGrid } from "./Grid";
21
+ import { $setGradientLUTDevice, $clearGradientAttachmentObjects, $cleanupLUTCache, $clearLUTCache } from "./Gradient/GradientLUTCache";
22
+ import { $releaseFillTexture, $acquireRenderTexture, $releaseRenderTexture, $clearFillTexturePool, $getOrCreateView } from "./FillTexturePool";
23
+ import { $setFilterGradientLUTDevice, $clearFilterGradientAttachment } from "./Filter/FilterGradientLUTCache";
24
+ // Context services
25
+ import { execute as contextFillWithStencilService } from "./Context/service/ContextFillWithStencilService";
26
+ import { execute as contextFillWithStencilMainService } from "./Context/service/ContextFillWithStencilMainService";
27
+ import { execute as contextFillSimpleService } from "./Context/service/ContextFillSimpleService";
28
+ // Context usecases
29
+ import { execute as contextGradientFillUseCase } from "./Context/usecase/ContextGradientFillUseCase";
30
+ import { execute as contextBitmapFillUseCase } from "./Context/usecase/ContextBitmapFillUseCase";
31
+ import { execute as contextGradientStrokeUseCase } from "./Context/usecase/ContextGradientStrokeUseCase";
32
+ import { execute as contextBitmapStrokeUseCase } from "./Context/usecase/ContextBitmapStrokeUseCase";
33
+ import { execute as contextClipUseCase } from "./Context/usecase/ContextClipUseCase";
34
+ import { execute as contextDrawArraysInstancedUseCase } from "./Context/usecase/ContextDrawArraysInstancedUseCase";
35
+ import { execute as contextDrawIndirectUseCase } from "./Context/usecase/ContextDrawIndirectUseCase";
36
+ import { execute as contextProcessComplexBlendQueueUseCase } from "./Context/usecase/ContextProcessComplexBlendQueueUseCase";
37
+ import { execute as contextApplyFilterUseCase } from "./Context/usecase/ContextApplyFilterUseCase";
38
+ import { execute as contextContainerEndLayerUseCase } from "./Context/usecase/ContextContainerEndLayerUseCase";
39
+ /**
40
+ * @description スワップチェーン転送用のIdentity UV定数: scale=(1,1), offset=(0,0)
41
+ */
42
+ const $IDENTITY_UV = new Float32Array([1.0, 1.0, 0.0, 0.0]);
43
+ /**
44
+ * @description save()/restore()用の Float32Array プール
45
+ */
46
+ const $matrixPool = [];
47
+ /**
48
+ * @description leaveMask() 用フルスクリーンメッシュ定数
49
+ */
50
+ const $FULLSCREEN_MESH = new Float32Array([
51
+ // Triangle 1: (0,0), (1,0), (0,1)
52
+ 0, 0, 0.5, 0.5, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1,
53
+ 1, 0, 0.5, 0.5, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1,
54
+ 0, 1, 0.5, 0.5, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1,
55
+ // Triangle 2: (1,0), (1,1), (0,1)
56
+ 1, 0, 0.5, 0.5, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1,
57
+ 1, 1, 0.5, 0.5, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1,
58
+ 0, 1, 0.5, 0.5, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1
59
+ ]);
60
+ /**
61
+ * @description clearNodeArea() 用クワッド頂点定数
62
+ */
63
+ const $QUAD_VERTICES = new Float32Array([
64
+ 0, 0, // 左上
65
+ 1, 0, // 右上
66
+ 0, 1, // 左下
67
+ 1, 0, // 右上
68
+ 1, 1, // 右下
69
+ 0, 1 // 左下
70
+ ]);
71
+ /**
72
+ * @description containerDrawCachedFilter() 用 CT uniform プリアロケート
73
+ */
74
+ const $ctUniform8 = new Float32Array(8);
75
+ /**
76
+ * @description fill() 用 uniform プリアロケート (color + matrix = 16 floats = 64 bytes)
77
+ */
78
+ const $fillUniform16 = new Float32Array(16);
79
+ // present() 用 Static BindGroup キャッシュ
80
+ let $presentBindGroup = null;
81
+ let $presentBindGroupView = null;
82
+ let $presentUniformBuffer = null;
83
+ // present() 用 RenderPassDescriptor プリアロケート
84
+ const $presentClearValue = { "r": 0, "g": 0, "b": 0, "a": 0 };
85
+ const $presentColorAttachment = {
86
+ "view": null,
87
+ "clearValue": $presentClearValue,
88
+ "loadOp": "clear",
89
+ "storeOp": "store"
90
+ };
91
+ const $presentDescriptor = {
92
+ "colorAttachments": [$presentColorAttachment]
93
+ };
94
+ // BindGroup entries 事前割り当て
95
+ const $entries3 = [
96
+ { "binding": 0, "resource": { "buffer": null } },
97
+ { "binding": 1, "resource": null },
98
+ { "binding": 2, "resource": null }
99
+ ];
100
+ // fillBackgroundColor() 用 RenderPassDescriptor プリアロケート
101
+ const $bgClearValue = { "r": 0, "g": 0, "b": 0, "a": 0 };
102
+ const $bgColorAttachment = {
103
+ "view": null,
104
+ "clearValue": $bgClearValue,
105
+ "loadOp": "clear",
106
+ "storeOp": "store",
107
+ "resolveTarget": undefined
108
+ };
109
+ const $bgStencilAttachment = {
110
+ "view": null,
111
+ "stencilClearValue": 0,
112
+ "stencilLoadOp": "clear",
113
+ "stencilStoreOp": "store"
114
+ };
115
+ const $bgDescriptor = {
116
+ "colorAttachments": [$bgColorAttachment]
117
+ };
118
+ // MSAA描画用 RenderPassDescriptor プリアロケート
119
+ const $msaaColorAttachment = {
120
+ "view": null,
121
+ "resolveTarget": undefined,
122
+ "loadOp": "load",
123
+ "storeOp": "store"
124
+ };
125
+ const $msaaStencilAttachment = {
126
+ "view": null,
127
+ "stencilLoadOp": "load",
128
+ "stencilStoreOp": "store"
129
+ };
130
+ const $msaaDescriptor = {
131
+ "colorAttachments": [$msaaColorAttachment]
132
+ };
133
+ /**
134
+ * @description WebGPU版、Next2Dのコンテキスト
135
+ * WebGPU version, Next2D context
136
+ *
137
+ * @class
138
+ */
139
+ export class Context {
140
+ constructor(device, canvas_context, preferred_format, device_pixel_ratio = 1) {
141
+ Object.defineProperty(this, "$stack", {
142
+ enumerable: true,
143
+ configurable: true,
144
+ writable: true,
145
+ value: void 0
146
+ });
147
+ Object.defineProperty(this, "$matrix", {
148
+ enumerable: true,
149
+ configurable: true,
150
+ writable: true,
151
+ value: void 0
152
+ });
153
+ Object.defineProperty(this, "$clearColorR", {
154
+ enumerable: true,
155
+ configurable: true,
156
+ writable: true,
157
+ value: void 0
158
+ });
159
+ Object.defineProperty(this, "$clearColorG", {
160
+ enumerable: true,
161
+ configurable: true,
162
+ writable: true,
163
+ value: void 0
164
+ });
165
+ Object.defineProperty(this, "$clearColorB", {
166
+ enumerable: true,
167
+ configurable: true,
168
+ writable: true,
169
+ value: void 0
170
+ });
171
+ Object.defineProperty(this, "$clearColorA", {
172
+ enumerable: true,
173
+ configurable: true,
174
+ writable: true,
175
+ value: void 0
176
+ });
177
+ Object.defineProperty(this, "$mainAttachmentObject", {
178
+ enumerable: true,
179
+ configurable: true,
180
+ writable: true,
181
+ value: void 0
182
+ });
183
+ Object.defineProperty(this, "$stackAttachmentObject", {
184
+ enumerable: true,
185
+ configurable: true,
186
+ writable: true,
187
+ value: void 0
188
+ });
189
+ Object.defineProperty(this, "globalAlpha", {
190
+ enumerable: true,
191
+ configurable: true,
192
+ writable: true,
193
+ value: void 0
194
+ });
195
+ Object.defineProperty(this, "globalCompositeOperation", {
196
+ enumerable: true,
197
+ configurable: true,
198
+ writable: true,
199
+ value: void 0
200
+ });
201
+ Object.defineProperty(this, "imageSmoothingEnabled", {
202
+ enumerable: true,
203
+ configurable: true,
204
+ writable: true,
205
+ value: void 0
206
+ });
207
+ Object.defineProperty(this, "$fillStyle", {
208
+ enumerable: true,
209
+ configurable: true,
210
+ writable: true,
211
+ value: void 0
212
+ });
213
+ Object.defineProperty(this, "$strokeStyle", {
214
+ enumerable: true,
215
+ configurable: true,
216
+ writable: true,
217
+ value: void 0
218
+ });
219
+ Object.defineProperty(this, "maskBounds", {
220
+ enumerable: true,
221
+ configurable: true,
222
+ writable: true,
223
+ value: void 0
224
+ });
225
+ Object.defineProperty(this, "thickness", {
226
+ enumerable: true,
227
+ configurable: true,
228
+ writable: true,
229
+ value: void 0
230
+ });
231
+ Object.defineProperty(this, "caps", {
232
+ enumerable: true,
233
+ configurable: true,
234
+ writable: true,
235
+ value: void 0
236
+ });
237
+ Object.defineProperty(this, "joints", {
238
+ enumerable: true,
239
+ configurable: true,
240
+ writable: true,
241
+ value: void 0
242
+ });
243
+ Object.defineProperty(this, "miterLimit", {
244
+ enumerable: true,
245
+ configurable: true,
246
+ writable: true,
247
+ value: void 0
248
+ });
249
+ Object.defineProperty(this, "device", {
250
+ enumerable: true,
251
+ configurable: true,
252
+ writable: true,
253
+ value: void 0
254
+ });
255
+ Object.defineProperty(this, "canvasContext", {
256
+ enumerable: true,
257
+ configurable: true,
258
+ writable: true,
259
+ value: void 0
260
+ });
261
+ Object.defineProperty(this, "preferredFormat", {
262
+ enumerable: true,
263
+ configurable: true,
264
+ writable: true,
265
+ value: void 0
266
+ });
267
+ Object.defineProperty(this, "commandEncoder", {
268
+ enumerable: true,
269
+ configurable: true,
270
+ writable: true,
271
+ value: null
272
+ });
273
+ Object.defineProperty(this, "renderPassEncoder", {
274
+ enumerable: true,
275
+ configurable: true,
276
+ writable: true,
277
+ value: null
278
+ });
279
+ // Main canvas texture (for final display) - acquired once per frame
280
+ Object.defineProperty(this, "mainTexture", {
281
+ enumerable: true,
282
+ configurable: true,
283
+ writable: true,
284
+ value: null
285
+ });
286
+ Object.defineProperty(this, "mainTextureView", {
287
+ enumerable: true,
288
+ configurable: true,
289
+ writable: true,
290
+ value: null
291
+ });
292
+ Object.defineProperty(this, "frameStarted", {
293
+ enumerable: true,
294
+ configurable: true,
295
+ writable: true,
296
+ value: false
297
+ });
298
+ // フレームごとの一時テクスチャ(endFrame()でdestroy)
299
+ Object.defineProperty(this, "frameTextures", {
300
+ enumerable: true,
301
+ configurable: true,
302
+ writable: true,
303
+ value: []
304
+ });
305
+ // フレームごとのプール管理テクスチャ(endFrame()でプールに返却)
306
+ Object.defineProperty(this, "pooledTextures", {
307
+ enumerable: true,
308
+ configurable: true,
309
+ writable: true,
310
+ value: []
311
+ });
312
+ // フレームごとのレンダーテクスチャプール管理(endFrame()でプールに返却)
313
+ Object.defineProperty(this, "pooledRenderTextures", {
314
+ enumerable: true,
315
+ configurable: true,
316
+ writable: true,
317
+ value: []
318
+ });
319
+ // Current rendering target (could be main or atlas)
320
+ Object.defineProperty(this, "currentRenderTarget", {
321
+ enumerable: true,
322
+ configurable: true,
323
+ writable: true,
324
+ value: null
325
+ });
326
+ // Current viewport size (WebGL版と同じ: アトラス描画時はアトラスサイズを使用)
327
+ Object.defineProperty(this, "viewportWidth", {
328
+ enumerable: true,
329
+ configurable: true,
330
+ writable: true,
331
+ value: 0
332
+ });
333
+ Object.defineProperty(this, "viewportHeight", {
334
+ enumerable: true,
335
+ configurable: true,
336
+ writable: true,
337
+ value: 0
338
+ });
339
+ Object.defineProperty(this, "pathCommand", {
340
+ enumerable: true,
341
+ configurable: true,
342
+ writable: true,
343
+ value: void 0
344
+ });
345
+ Object.defineProperty(this, "bufferManager", {
346
+ enumerable: true,
347
+ configurable: true,
348
+ writable: true,
349
+ value: void 0
350
+ });
351
+ Object.defineProperty(this, "textureManager", {
352
+ enumerable: true,
353
+ configurable: true,
354
+ writable: true,
355
+ value: void 0
356
+ });
357
+ Object.defineProperty(this, "frameBufferManager", {
358
+ enumerable: true,
359
+ configurable: true,
360
+ writable: true,
361
+ value: void 0
362
+ });
363
+ Object.defineProperty(this, "pipelineManager", {
364
+ enumerable: true,
365
+ configurable: true,
366
+ writable: true,
367
+ value: void 0
368
+ });
369
+ Object.defineProperty(this, "computePipelineManager", {
370
+ enumerable: true,
371
+ configurable: true,
372
+ writable: true,
373
+ value: void 0
374
+ });
375
+ Object.defineProperty(this, "attachmentManager", {
376
+ enumerable: true,
377
+ configurable: true,
378
+ writable: true,
379
+ value: void 0
380
+ });
381
+ Object.defineProperty(this, "newDrawState", {
382
+ enumerable: true,
383
+ configurable: true,
384
+ writable: true,
385
+ value: false
386
+ });
387
+ // コンテナレイヤースタック(フィルター/ブレンド用)
388
+ Object.defineProperty(this, "$containerLayerStack", {
389
+ enumerable: true,
390
+ configurable: true,
391
+ writable: true,
392
+ value: []
393
+ });
394
+ Object.defineProperty(this, "containerLayerContentSizes", {
395
+ enumerable: true,
396
+ configurable: true,
397
+ writable: true,
398
+ value: []
399
+ });
400
+ // マスク描画モードフラグ(beginMask〜endMask間でtrue)
401
+ Object.defineProperty(this, "inMaskMode", {
402
+ enumerable: true,
403
+ configurable: true,
404
+ writable: true,
405
+ value: false
406
+ });
407
+ // ノード領域クリア済みフラグ(beginNodeRendering〜endNodeRendering間で使用)
408
+ Object.defineProperty(this, "nodeAreaCleared", {
409
+ enumerable: true,
410
+ configurable: true,
411
+ writable: true,
412
+ value: false
413
+ });
414
+ // 現在のノードのシザー範囲(クリア後に戻すため)
415
+ Object.defineProperty(this, "currentNodeScissor", {
416
+ enumerable: true,
417
+ configurable: true,
418
+ writable: true,
419
+ value: null
420
+ });
421
+ // アトラスレンダーパス統合: 同一アトラスへの連続描画でパスを再利用
422
+ Object.defineProperty(this, "nodeRenderPassAtlasIndex", {
423
+ enumerable: true,
424
+ configurable: true,
425
+ writable: true,
426
+ value: -1
427
+ });
428
+ // Dynamic Uniform BindGroup(fill/stencilパイプライン共有、フレームごとに1回作成)
429
+ Object.defineProperty(this, "fillDynamicBindGroup", {
430
+ enumerable: true,
431
+ configurable: true,
432
+ writable: true,
433
+ value: null
434
+ });
435
+ Object.defineProperty(this, "fillDynamicBindGroupBuffer", {
436
+ enumerable: true,
437
+ configurable: true,
438
+ writable: true,
439
+ value: null
440
+ });
441
+ // clearNodeArea() 用頂点バッファキャッシュ
442
+ Object.defineProperty(this, "nodeClearQuadBuffer", {
443
+ enumerable: true,
444
+ configurable: true,
445
+ writable: true,
446
+ value: null
447
+ });
448
+ // Storage Buffer + Indirect Drawing を使用するかどうか
449
+ Object.defineProperty(this, "useOptimizedInstancing", {
450
+ enumerable: true,
451
+ configurable: true,
452
+ writable: true,
453
+ value: true
454
+ });
455
+ // Hot Path 用の事前割り当てバッファ
456
+ Object.defineProperty(this, "$uniformData8", {
457
+ enumerable: true,
458
+ configurable: true,
459
+ writable: true,
460
+ value: new Float32Array(8)
461
+ });
462
+ Object.defineProperty(this, "$scissorRect", {
463
+ enumerable: true,
464
+ configurable: true,
465
+ writable: true,
466
+ value: { "x": 0, "y": 0, "w": 0, "h": 0 }
467
+ });
468
+ // フィルター/コンテナレイヤー用のプリアロケートされた設定オブジェクト
469
+ Object.defineProperty(this, "$filterConfig", {
470
+ enumerable: true,
471
+ configurable: true,
472
+ writable: true,
473
+ value: void 0
474
+ });
475
+ this.device = device;
476
+ this.canvasContext = canvas_context;
477
+ this.preferredFormat = preferred_format;
478
+ WebGPUUtil.setDevice(device);
479
+ WebGPUUtil.setDevicePixelRatio(device_pixel_ratio);
480
+ // Set render max size same as WebGL (half of max texture size, minimum 2048)
481
+ const maxTextureSize = device.limits.maxTextureDimension2D;
482
+ const renderMaxSize = Math.max(2048, maxTextureSize / 2);
483
+ WebGPUUtil.setRenderMaxSize(renderMaxSize);
484
+ this.$stack = WebGPUUtil.createArray();
485
+ this.$stackAttachmentObject = WebGPUUtil.createArray();
486
+ this.$matrix = WebGPUUtil.createFloat32Array(9);
487
+ this.$matrix.set([1, 0, 0, 0, 1, 0, 0, 0, 1]);
488
+ this.$clearColorR = 0;
489
+ this.$clearColorG = 0;
490
+ this.$clearColorB = 0;
491
+ this.$clearColorA = 0;
492
+ this.thickness = 1;
493
+ this.caps = 0;
494
+ this.joints = 2;
495
+ this.miterLimit = 0;
496
+ this.$mainAttachmentObject = null;
497
+ this.globalAlpha = 1;
498
+ this.globalCompositeOperation = "normal";
499
+ this.imageSmoothingEnabled = false;
500
+ this.$fillStyle = new Float32Array([1, 1, 1, 1]);
501
+ this.$strokeStyle = new Float32Array([1, 1, 1, 1]);
502
+ this.maskBounds = {
503
+ "xMin": 0,
504
+ "yMin": 0,
505
+ "xMax": 0,
506
+ "yMax": 0
507
+ };
508
+ canvas_context.configure({
509
+ "device": device,
510
+ "format": preferred_format,
511
+ "alphaMode": "premultiplied"
512
+ });
513
+ // 初期ビューポートサイズをキャンバスサイズに設定
514
+ this.viewportWidth = canvas_context.canvas.width;
515
+ this.viewportHeight = canvas_context.canvas.height;
516
+ this.pathCommand = new PathCommand();
517
+ this.bufferManager = new BufferManager(device);
518
+ this.textureManager = new TextureManager(device);
519
+ this.frameBufferManager = new FrameBufferManager(device, preferred_format);
520
+ this.pipelineManager = new PipelineManager(device, preferred_format);
521
+ // 遅延パイプライン群を即座に先行作成(初回アクセス時のレイテンシ解消)
522
+ this.pipelineManager.preloadLazyGroups();
523
+ this.computePipelineManager = new ComputePipelineManager(device);
524
+ this.attachmentManager = new AttachmentManager(device);
525
+ // グラデーションLUT共有アタッチメントにGPUDeviceを設定
526
+ $setGradientLUTDevice(device);
527
+ $setFilterGradientLUTDevice(device);
528
+ // アトラス生成関数を登録(複数アトラス対応)
529
+ $setAtlasCreator((index) => {
530
+ const maxSize = WebGPUUtil.getRenderMaxSize();
531
+ return this.frameBufferManager.createAttachment(`atlas_${index}`, maxSize, maxSize, false, true);
532
+ });
533
+ // フィルター/コンテナレイヤー用の設定オブジェクトを事前割り当て
534
+ this.$filterConfig = {
535
+ "device": this.device,
536
+ "commandEncoder": null,
537
+ "bufferManager": this.bufferManager,
538
+ "frameBufferManager": this.frameBufferManager,
539
+ "pipelineManager": this.pipelineManager,
540
+ "textureManager": this.textureManager,
541
+ "computePipelineManager": this.computePipelineManager,
542
+ "frameTextures": this.frameTextures
543
+ };
544
+ // コンテキストをグローバル変数にセット
545
+ $setContext(this);
546
+ }
547
+ /**
548
+ * @description 転送範囲をリセット(フレーム開始)
549
+ */
550
+ clearTransferBounds() {
551
+ // フレーム開始時に呼ばれる
552
+ // テクスチャを取得してフレームを開始
553
+ this.beginFrame();
554
+ }
555
+ /**
556
+ * @description 背景色を更新
557
+ */
558
+ updateBackgroundColor(red, green, blue, alpha) {
559
+ this.$clearColorR = red;
560
+ this.$clearColorG = green;
561
+ this.$clearColorB = blue;
562
+ this.$clearColorA = alpha;
563
+ }
564
+ /**
565
+ * @description 背景色で塗りつぶす(メインアタッチメント)
566
+ */
567
+ fillBackgroundColor() {
568
+ // メインアタッチメントがない場合はスキップ
569
+ if (!this.$mainAttachmentObject || !this.$mainAttachmentObject.texture) {
570
+ return;
571
+ }
572
+ // フレームが開始されていない場合は開始
573
+ if (!this.frameStarted) {
574
+ this.beginFrame();
575
+ }
576
+ // 既存のレンダーパスを終了
577
+ if (this.renderPassEncoder) {
578
+ this.renderPassEncoder.end();
579
+ this.renderPassEncoder = null;
580
+ }
581
+ // コマンドエンコーダーを確保
582
+ this.ensureCommandEncoder();
583
+ // メインアタッチメントにステンシルがある場合はステンシル付きレンダーパスを使用
584
+ // MSAA有効時はmsaaTextureをクリアしresolveTargetで非MSAAテクスチャにも反映
585
+ const clearUseMsaa = this.$mainAttachmentObject.msaa && this.$mainAttachmentObject.msaaTexture?.view;
586
+ $bgColorAttachment.view = clearUseMsaa
587
+ ? this.$mainAttachmentObject.msaaTexture.view
588
+ : this.$mainAttachmentObject.texture.view;
589
+ $bgColorAttachment.resolveTarget = clearUseMsaa
590
+ ? this.$mainAttachmentObject.texture.view : undefined;
591
+ $bgClearValue.r = this.$clearColorR;
592
+ $bgClearValue.g = this.$clearColorG;
593
+ $bgClearValue.b = this.$clearColorB;
594
+ $bgClearValue.a = this.$clearColorA;
595
+ // ステンシルバッファもクリア
596
+ const clearStencilView = clearUseMsaa && this.$mainAttachmentObject.msaaStencil?.view
597
+ ? this.$mainAttachmentObject.msaaStencil.view
598
+ : this.$mainAttachmentObject.stencil?.view;
599
+ if (clearStencilView) {
600
+ $bgStencilAttachment.view = clearStencilView;
601
+ $bgDescriptor.depthStencilAttachment = $bgStencilAttachment;
602
+ }
603
+ else {
604
+ $bgDescriptor.depthStencilAttachment = undefined;
605
+ }
606
+ // 背景クリア用のレンダーパスを開始して即座に終了
607
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass($bgDescriptor);
608
+ this.renderPassEncoder.end();
609
+ this.renderPassEncoder = null;
610
+ }
611
+ /**
612
+ * @description メインcanvasのサイズを変更
613
+ */
614
+ resize(width, height, cache_clear = true) {
615
+ // インスタンス配列をクリア(WebGL版と同じ)
616
+ this.clearArraysInstanced();
617
+ // フレームごとの一時テクスチャをクリア
618
+ for (const texture of this.frameTextures) {
619
+ texture.destroy();
620
+ }
621
+ this.frameTextures.length = 0;
622
+ // プール管理テクスチャをプールに返却し、プール自体もクリア
623
+ for (const texture of this.pooledTextures) {
624
+ $releaseFillTexture(texture);
625
+ }
626
+ this.pooledTextures.length = 0;
627
+ for (const texture of this.pooledRenderTextures) {
628
+ $releaseRenderTexture(texture);
629
+ }
630
+ this.pooledRenderTextures.length = 0;
631
+ $clearFillTexturePool();
632
+ // フレーム状態をリセット(リサイズ中は新しいフレームを開始できるようにする)
633
+ this.frameStarted = false;
634
+ this.commandEncoder = null;
635
+ this.renderPassEncoder = null;
636
+ this.currentRenderTarget = null;
637
+ // マスク状態をリセット
638
+ $resetMaskState();
639
+ // キャンバスのサイズを更新
640
+ const canvas = this.canvasContext.canvas;
641
+ // 型チェックを安全に実行(Worker環境対応)
642
+ if (canvas && "width" in canvas && "height" in canvas) {
643
+ canvas.width = width;
644
+ canvas.height = height;
645
+ }
646
+ // WebGL版と同じ: スタックにあるアタッチメントも解放
647
+ if (this.$stackAttachmentObject.length) {
648
+ for (let idx = 0; idx < this.$stackAttachmentObject.length; ++idx) {
649
+ const attachmentObject = this.$stackAttachmentObject[idx];
650
+ if (!attachmentObject) {
651
+ continue;
652
+ }
653
+ // アタッチメントのリソースを直接解放
654
+ // Note: スタック内のアタッチメントは名前で管理されていないため、
655
+ // リソースを直接破棄する
656
+ if (attachmentObject.texture) {
657
+ attachmentObject.texture.resource.destroy();
658
+ }
659
+ if (attachmentObject.stencil) {
660
+ attachmentObject.stencil.resource.destroy();
661
+ }
662
+ if (attachmentObject.msaaTexture) {
663
+ attachmentObject.msaaTexture.resource.destroy();
664
+ }
665
+ if (attachmentObject.msaaStencil) {
666
+ attachmentObject.msaaStencil.resource.destroy();
667
+ }
668
+ }
669
+ this.$stackAttachmentObject.length = 0;
670
+ }
671
+ // 既存のメインアタッチメントを破棄
672
+ if (this.$mainAttachmentObject) {
673
+ this.frameBufferManager.destroyAttachment("main");
674
+ }
675
+ // 共有アタッチメントをクリア
676
+ if (cache_clear) {
677
+ $clearGradientAttachmentObjects();
678
+ $clearLUTCache();
679
+ $clearFilterGradientAttachment();
680
+ // アトラスのパッキングデータをリセット(WebGL版と同じ)
681
+ $resetAtlas();
682
+ // FrameBufferManagerのアトラステクスチャを再作成(古いコンテンツをクリア)
683
+ // ステンシルバッファを有効にする(2パスステンシルフィル用)
684
+ this.frameBufferManager.destroyAttachment("atlas");
685
+ this.frameBufferManager.createAttachment("atlas", 4096, 4096, false, true);
686
+ }
687
+ // アンバインド(WebGL版と同じ)
688
+ this.frameBufferManager.setCurrentAttachment(null);
689
+ // canvasContextを再設定
690
+ this.canvasContext.configure({
691
+ "device": this.device,
692
+ "format": this.preferredFormat,
693
+ "alphaMode": "premultiplied"
694
+ });
695
+ // リサイズ時にスワップチェーンテクスチャをリセット
696
+ // 古いテクスチャ参照を解放して、次のフレームで新しいサイズのテクスチャを取得
697
+ this.mainTexture = null;
698
+ this.mainTextureView = null;
699
+ // メインアタッチメントを作成(MSAA + ステンシル付き、マスク描画用)
700
+ // WebGL版と同じ: $mainAttachmentObject = frameBufferManagerGetAttachmentObjectUseCase(width, height, true)
701
+ // msaa=true でMSAAを有効化(曲線のアンチエイリアス品質向上のため)
702
+ // mask=true でステンシルバッファを有効化
703
+ // グラデーション塗りつぶしの中抜き描画(hollow shape)にも必要
704
+ this.$mainAttachmentObject = this.frameBufferManager.createAttachment("main", width, height, true, true);
705
+ // メインアタッチメントをバインド
706
+ this.bind(this.$mainAttachmentObject);
707
+ }
708
+ /**
709
+ * @description 指定範囲をクリアする
710
+ */
711
+ clearRect(_x, _y, _w, _h) {
712
+ // WebGPU clear rect implementation
713
+ // WebGPUではclearはレンダーパス開始時に行うため、ここでは何もしない
714
+ // 実際のクリアはbeginNodeRenderingやbeginFrameで行われる
715
+ }
716
+ /**
717
+ * @description 現在の2D変換行列を保存
718
+ */
719
+ save() {
720
+ const matrix = $matrixPool.length > 0 ? $matrixPool.pop() : new Float32Array(9);
721
+ matrix.set(this.$matrix);
722
+ this.$stack.push(matrix);
723
+ }
724
+ /**
725
+ * @description 2D変換行列を復元
726
+ */
727
+ restore() {
728
+ const matrix = this.$stack.pop();
729
+ if (matrix) {
730
+ this.$matrix.set(matrix);
731
+ $matrixPool.push(matrix);
732
+ }
733
+ }
734
+ /**
735
+ * @description 2D変換行列を設定
736
+ */
737
+ setTransform(a, b, c, d, e, f) {
738
+ this.$matrix[0] = a;
739
+ this.$matrix[1] = b;
740
+ this.$matrix[3] = c;
741
+ this.$matrix[4] = d;
742
+ this.$matrix[6] = e;
743
+ this.$matrix[7] = f;
744
+ }
745
+ /**
746
+ * @description 現在の2D変換行列に対して乗算を行います
747
+ */
748
+ transform(a, b, c, d, e, f) {
749
+ const m = this.$matrix;
750
+ const m0 = m[0], m1 = m[1], m3 = m[3], m4 = m[4], m6 = m[6], m7 = m[7];
751
+ m[0] = a * m0 + b * m3;
752
+ m[1] = a * m1 + b * m4;
753
+ m[3] = c * m0 + d * m3;
754
+ m[4] = c * m1 + d * m4;
755
+ m[6] = e * m0 + f * m3 + m6;
756
+ m[7] = e * m1 + f * m4 + m7;
757
+ }
758
+ /**
759
+ * @description コンテキストの値を初期化する
760
+ */
761
+ reset() {
762
+ this.$matrix.set([1, 0, 0, 0, 1, 0, 0, 0, 1]);
763
+ this.$stack.length = 0;
764
+ this.$stackAttachmentObject.length = 0;
765
+ this.globalAlpha = 1;
766
+ this.globalCompositeOperation = "normal";
767
+ this.imageSmoothingEnabled = false;
768
+ }
769
+ /**
770
+ * @description パスを開始
771
+ */
772
+ beginPath() {
773
+ this.pathCommand.beginPath();
774
+ }
775
+ /**
776
+ * @description パスを移動
777
+ */
778
+ moveTo(x, y) {
779
+ this.pathCommand.moveTo(x, y);
780
+ }
781
+ /**
782
+ * @description パスを線で結ぶ
783
+ */
784
+ lineTo(x, y) {
785
+ this.pathCommand.lineTo(x, y);
786
+ }
787
+ /**
788
+ * @description 二次ベジェ曲線を描画
789
+ */
790
+ quadraticCurveTo(cx, cy, x, y) {
791
+ this.pathCommand.quadraticCurveTo(cx, cy, x, y);
792
+ }
793
+ /**
794
+ * @description 塗りつぶしスタイルを設定
795
+ */
796
+ fillStyle(red, green, blue, alpha) {
797
+ this.$fillStyle[0] = red;
798
+ this.$fillStyle[1] = green;
799
+ this.$fillStyle[2] = blue;
800
+ this.$fillStyle[3] = alpha;
801
+ }
802
+ /**
803
+ * @description 線のスタイルを設定
804
+ */
805
+ strokeStyle(red, green, blue, alpha) {
806
+ this.$strokeStyle[0] = red;
807
+ this.$strokeStyle[1] = green;
808
+ this.$strokeStyle[2] = blue;
809
+ this.$strokeStyle[3] = alpha;
810
+ }
811
+ /**
812
+ * @description パスを閉じる
813
+ */
814
+ closePath() {
815
+ this.pathCommand.closePath();
816
+ }
817
+ /**
818
+ * @description 円弧を描画
819
+ */
820
+ arc(x, y, radius) {
821
+ this.pathCommand.arc(x, y, radius);
822
+ }
823
+ /**
824
+ * @description 3次ベジェ曲線を描画
825
+ */
826
+ bezierCurveTo(cx1, cy1, cx2, cy2, x, y) {
827
+ this.pathCommand.bezierCurveTo(cx1, cy1, cx2, cy2, x, y);
828
+ }
829
+ /**
830
+ * @description 描画メソッド共通: レンダーパスの確保とノード領域クリア
831
+ * fill(), stroke(), gradientFill(), bitmapFill(), gradientStroke(), bitmapStroke() で使用
832
+ */
833
+ ensureFillRenderPass() {
834
+ // フレームが開始されていない場合は開始
835
+ if (!this.frameStarted) {
836
+ this.beginFrame();
837
+ }
838
+ // コマンドエンコーダーを確保
839
+ this.ensureCommandEncoder();
840
+ // 既存のレンダーパスがある場合はearlyリターン(ノード領域クリアのみ確認)
841
+ if (this.renderPassEncoder) {
842
+ if (this.currentRenderTarget) {
843
+ this.ensureNodeAreaCleared();
844
+ }
845
+ return;
846
+ }
847
+ // レンダーパスがない場合のみ新規作成
848
+ {
849
+ // 現在のレンダーターゲットを取得(メインまたはオフスクリーン)
850
+ const textureView = this.getCurrentTextureView();
851
+ const attachment = $getAtlasAttachmentObject();
852
+ // MSAAテクスチャを使用するかどうか
853
+ const useMsaa = attachment?.msaa && attachment?.msaaTexture?.view;
854
+ const colorView = useMsaa ? attachment.msaaTexture.view : textureView;
855
+ const resolveTarget = useMsaa ? textureView : null;
856
+ // アトラスへの描画でステンシルが必要な場合はステンシル付きレンダーパスを作成
857
+ if (this.currentRenderTarget && attachment?.stencil?.view) {
858
+ // MSAAステンシルテクスチャを使用
859
+ const stencilView = useMsaa && attachment?.msaaStencil?.view
860
+ ? attachment.msaaStencil.view
861
+ : attachment.stencil.view;
862
+ // ステンシルは常にクリア(2パスフィル描画のため)
863
+ // 各描画ごとにステンシルを0からスタートする必要がある
864
+ const renderPassDescriptor = this.frameBufferManager.createStencilRenderPassDescriptor(colorView, stencilView, "load", "clear", // ステンシルをクリア
865
+ resolveTarget);
866
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
867
+ }
868
+ else if (!this.currentRenderTarget && ($isMaskTestEnabled() || $isMaskDrawing()) && this.$mainAttachmentObject?.stencil?.view) {
869
+ // マスク描画時またはマスクテスト有効時のメインアタッチメントへの描画(ステンシル付き)
870
+ // マスク描画時: ステンシルバッファにマスク形状を書き込む
871
+ // マスクテスト時: ステンシル値をテストしてマスク領域のみ描画
872
+ const mainUseMsaa = this.$mainAttachmentObject.msaa && this.$mainAttachmentObject.msaaTexture?.view;
873
+ const mainColorView = mainUseMsaa ? this.$mainAttachmentObject.msaaTexture.view : this.$mainAttachmentObject.texture.view;
874
+ const mainStencilView = mainUseMsaa && this.$mainAttachmentObject.msaaStencil?.view
875
+ ? this.$mainAttachmentObject.msaaStencil.view
876
+ : this.$mainAttachmentObject.stencil.view;
877
+ const mainResolveTarget = mainUseMsaa ? this.$mainAttachmentObject.texture.view : null;
878
+ const renderPassDescriptor = this.frameBufferManager.createStencilRenderPassDescriptor(mainColorView, mainStencilView, "load", "load", // ステンシルは既存の値を保持(マスク情報)
879
+ mainResolveTarget);
880
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
881
+ // マスクテスト時はステンシル参照値を設定
882
+ if ($isMaskTestEnabled()) {
883
+ this.renderPassEncoder.setStencilReference($getMaskStencilReference());
884
+ }
885
+ }
886
+ else if (!this.currentRenderTarget && this.$mainAttachmentObject) {
887
+ // メインアタッチメントへの通常描画(MSAA対応)
888
+ // 2パスステンシルフィルを使用するため、常にステンシル付きレンダーパスを作成
889
+ const mainUseMsaa = this.$mainAttachmentObject.msaa && this.$mainAttachmentObject.msaaTexture?.view;
890
+ const mainColorView = mainUseMsaa ? this.$mainAttachmentObject.msaaTexture.view : this.$mainAttachmentObject.texture.view;
891
+ const mainResolveTarget = mainUseMsaa ? this.$mainAttachmentObject.texture.view : null;
892
+ if (this.$mainAttachmentObject.stencil?.view) {
893
+ // ステンシル付きレンダーパス(2パスステンシルフィル用)
894
+ const mainStencilView = mainUseMsaa && this.$mainAttachmentObject.msaaStencil?.view
895
+ ? this.$mainAttachmentObject.msaaStencil.view
896
+ : this.$mainAttachmentObject.stencil.view;
897
+ const renderPassDescriptor = this.frameBufferManager.createStencilRenderPassDescriptor(mainColorView, mainStencilView, "load", "clear", // ステンシルをクリア(各描画でステンシルを0からスタート)
898
+ mainResolveTarget);
899
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
900
+ }
901
+ else {
902
+ // ステンシルなし(フォールバック)
903
+ const renderPassDescriptor = this.frameBufferManager.createRenderPassDescriptor(mainColorView, 0, 0, 0, 0, "load", mainResolveTarget);
904
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
905
+ }
906
+ }
907
+ else {
908
+ const renderPassDescriptor = this.frameBufferManager.createRenderPassDescriptor(colorView, 0, 0, 0, 0, "load", resolveTarget);
909
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
910
+ }
911
+ }
912
+ // ノードレンダリング中の場合、最初の描画前にノード領域をクリア
913
+ // renderPassEncoder作成後に呼び出す必要がある
914
+ if (this.currentRenderTarget) {
915
+ this.ensureNodeAreaCleared();
916
+ }
917
+ }
918
+ /**
919
+ * @description 塗りつぶしを実行(Loop-Blinn方式対応)
920
+ */
921
+ fill() {
922
+ const pathVertices = this.pathCommand.$getVertices;
923
+ if (pathVertices.length === 0) {
924
+ return;
925
+ }
926
+ this.ensureFillRenderPass();
927
+ // WebGL版と同じ: 現在のビューポートサイズを使用(アトラス描画時はアトラスサイズ)
928
+ const viewportWidth = this.viewportWidth;
929
+ const viewportHeight = this.viewportHeight;
930
+ // MeshFillGenerateUseCaseで頂点データを生成(4 floats/vertex: position + bezier)
931
+ const mesh = meshFillGenerateUseCase(pathVertices);
932
+ if (mesh.indexCount === 0) {
933
+ return;
934
+ }
935
+ // 頂点バッファを取得(プールから再利用)
936
+ const vertexBuffer = this.bufferManager.acquireVertexBuffer(mesh.buffer.byteLength, mesh.buffer);
937
+ // color/matrixをDynamic Uniform Bufferに書き込み
938
+ const uniformOffset = this.writeFillUniform(this.$fillStyle[0], this.$fillStyle[1], this.$fillStyle[2], this.$fillStyle[3], this.$matrix[0], this.$matrix[1], this.$matrix[3], this.$matrix[4], this.$matrix[6], this.$matrix[7], viewportWidth, viewportHeight);
939
+ const bindGroup = this.getOrCreateFillDynamicBindGroup();
940
+ // アトラスへの描画(ステンシルあり)の場合は2パスステンシルフィル
941
+ const attachment = $getAtlasAttachmentObject();
942
+ if (this.currentRenderTarget && attachment?.stencil?.view) {
943
+ this.fillWithStencil(vertexBuffer, mesh.indexCount, bindGroup, uniformOffset);
944
+ }
945
+ else if (!this.currentRenderTarget && !this.inMaskMode && !$isMaskTestEnabled() && this.$mainAttachmentObject?.stencil?.view) {
946
+ this.fillWithStencilMain(vertexBuffer, mesh.indexCount, bindGroup, uniformOffset);
947
+ }
948
+ else {
949
+ const useStencilPipeline = (this.inMaskMode || $isMaskTestEnabled()) && !!this.$mainAttachmentObject?.stencil?.view && !this.currentRenderTarget;
950
+ this.fillSimple(vertexBuffer, mesh.indexCount, useStencilPipeline, bindGroup, uniformOffset);
951
+ }
952
+ // レンダーパスは終了しない(drawFill()またはendNodeRendering()で終了する)
953
+ }
954
+ /**
955
+ * @description Dynamic Uniform BindGroupを取得(フレーム内で初回呼び出し時に作成)
956
+ */
957
+ getOrCreateFillDynamicBindGroup() {
958
+ const currentBuffer = this.bufferManager.dynamicUniform.getBuffer();
959
+ if (!this.fillDynamicBindGroup || this.fillDynamicBindGroupBuffer !== currentBuffer) {
960
+ const layout = this.pipelineManager.getBindGroupLayout("fill_dynamic");
961
+ if (!layout) {
962
+ throw new Error("[WebGPU] fill_dynamic bind group layout not found");
963
+ }
964
+ this.fillDynamicBindGroup = this.device.createBindGroup({
965
+ "layout": layout,
966
+ "entries": [{
967
+ "binding": 0,
968
+ "resource": {
969
+ "buffer": currentBuffer,
970
+ "size": 256
971
+ }
972
+ }]
973
+ });
974
+ this.fillDynamicBindGroupBuffer = currentBuffer;
975
+ }
976
+ return this.fillDynamicBindGroup;
977
+ }
978
+ /**
979
+ * @description fill/stroke用のcolor/matrix uniformを書き込む
980
+ * FillUniforms構造体: color(vec4) + matrix0(vec4) + matrix1(vec4) + matrix2(vec4) = 64 bytes
981
+ * @return Dynamic Uniform Buffer内のアライメント済みオフセット
982
+ */
983
+ writeFillUniform(red, green, blue, alpha, a, b, c, d, tx, ty, viewportWidth, viewportHeight) {
984
+ // color
985
+ $fillUniform16[0] = red;
986
+ $fillUniform16[1] = green;
987
+ $fillUniform16[2] = blue;
988
+ $fillUniform16[3] = alpha;
989
+ // matrix0 (a, b, 0, pad) — ビューポート正規化
990
+ $fillUniform16[4] = a / viewportWidth;
991
+ $fillUniform16[5] = b / viewportHeight;
992
+ $fillUniform16[6] = 0;
993
+ $fillUniform16[7] = 0;
994
+ // matrix1 (c, d, 0, pad)
995
+ $fillUniform16[8] = c / viewportWidth;
996
+ $fillUniform16[9] = d / viewportHeight;
997
+ $fillUniform16[10] = 0;
998
+ $fillUniform16[11] = 0;
999
+ // matrix2 (tx, ty, 1, pad)
1000
+ $fillUniform16[12] = tx / viewportWidth;
1001
+ $fillUniform16[13] = ty / viewportHeight;
1002
+ $fillUniform16[14] = 1;
1003
+ $fillUniform16[15] = 0;
1004
+ return this.bufferManager.dynamicUniform.allocate($fillUniform16);
1005
+ }
1006
+ /**
1007
+ * @description 2パスステンシルフィル(アトラス用)
1008
+ */
1009
+ fillWithStencil(vertexBuffer, vertexCount, bindGroup, uniformOffset) {
1010
+ contextFillWithStencilService(this.renderPassEncoder, this.pipelineManager, vertexBuffer, vertexCount, bindGroup, uniformOffset);
1011
+ }
1012
+ /**
1013
+ * @description 2パスステンシルフィル(メインキャンバス用)
1014
+ */
1015
+ fillWithStencilMain(vertexBuffer, vertexCount, bindGroup, uniformOffset) {
1016
+ contextFillWithStencilMainService(this.renderPassEncoder, this.pipelineManager, vertexBuffer, vertexCount, bindGroup, uniformOffset);
1017
+ }
1018
+ /**
1019
+ * @description 単純なフィル(ステンシルなし、キャンバス描画用)
1020
+ */
1021
+ fillSimple(vertexBuffer, vertexCount, useStencilPipeline, bindGroup, uniformOffset) {
1022
+ const clipLevel = this.$mainAttachmentObject?.clipLevel ?? 1;
1023
+ contextFillSimpleService(this.renderPassEncoder, this.pipelineManager, vertexBuffer, vertexCount, bindGroup, uniformOffset, !!this.currentRenderTarget, useStencilPipeline, clipLevel);
1024
+ }
1025
+ /**
1026
+ * @description オフスクリーンアタッチメントにバインド
1027
+ * WebGL: FrameBufferManagerBindAttachmentObjectService
1028
+ */
1029
+ bindAttachment(attachment) {
1030
+ this.attachmentManager.bindAttachment(attachment);
1031
+ // 現在のレンダーターゲットをオフスクリーンに切り替え
1032
+ // color?.view または texture?.view を使用
1033
+ const view = attachment.color?.view ?? attachment.texture?.view;
1034
+ if (view) {
1035
+ this.currentRenderTarget = view;
1036
+ }
1037
+ }
1038
+ /**
1039
+ * @description メインキャンバスにバインド
1040
+ * WebGL: FrameBufferManagerUnBindAttachmentObjectService
1041
+ */
1042
+ unbindAttachment() {
1043
+ this.attachmentManager.unbindAttachment();
1044
+ this.currentRenderTarget = null;
1045
+ }
1046
+ /**
1047
+ * @description アタッチメントオブジェクトを取得
1048
+ * WebGL: FrameBufferManagerGetAttachmentObjectUseCase
1049
+ */
1050
+ getAttachmentObject(width, height, msaa = false) {
1051
+ return this.attachmentManager.getAttachmentObject(width, height, msaa);
1052
+ }
1053
+ /**
1054
+ * @description アタッチメントオブジェクトを解放
1055
+ * WebGL: FrameBufferManagerReleaseAttachmentObjectUseCase
1056
+ */
1057
+ releaseAttachment(attachment) {
1058
+ this.attachmentManager.releaseAttachment(attachment);
1059
+ }
1060
+ /**
1061
+ * @description 線の描画を実行(WebGL版と同じ仕様)
1062
+ * WebGL版と同様に、ストロークを塗りとして描画する
1063
+ */
1064
+ stroke() {
1065
+ // WebGL版と同じ: IPath[]形式で頂点を取得
1066
+ const vertices = this.pathCommand.getVerticesForStroke();
1067
+ if (vertices.length === 0) {
1068
+ return;
1069
+ }
1070
+ this.ensureFillRenderPass();
1071
+ const viewportWidth = this.viewportWidth;
1072
+ const viewportHeight = this.viewportHeight;
1073
+ const strokeOutlines = generateStrokeMesh(vertices, this.thickness);
1074
+ if (strokeOutlines.length === 0) {
1075
+ return;
1076
+ }
1077
+ // ストロークもmeshFillGenerateUseCaseを使用(4 floats/vertex)
1078
+ const mesh = meshFillGenerateUseCase(strokeOutlines);
1079
+ if (mesh.indexCount === 0) {
1080
+ return;
1081
+ }
1082
+ const vertexBuffer = this.bufferManager.acquireVertexBuffer(mesh.buffer.byteLength, mesh.buffer);
1083
+ // color/matrixをDynamic Uniform Bufferに書き込み
1084
+ const uniformOffset = this.writeFillUniform(this.$strokeStyle[0], this.$strokeStyle[1], this.$strokeStyle[2], this.$strokeStyle[3], this.$matrix[0], this.$matrix[1], this.$matrix[3], this.$matrix[4], this.$matrix[6], this.$matrix[7], viewportWidth, viewportHeight);
1085
+ const bindGroup = this.getOrCreateFillDynamicBindGroup();
1086
+ const attachment = $getAtlasAttachmentObject();
1087
+ if (this.currentRenderTarget && attachment?.stencil?.view) {
1088
+ this.fillWithStencil(vertexBuffer, mesh.indexCount, bindGroup, uniformOffset);
1089
+ }
1090
+ else if (!this.currentRenderTarget && !this.inMaskMode && !$isMaskTestEnabled() && this.$mainAttachmentObject?.stencil?.view) {
1091
+ this.fillWithStencilMain(vertexBuffer, mesh.indexCount, bindGroup, uniformOffset);
1092
+ }
1093
+ else {
1094
+ const useStencilPipeline = (this.inMaskMode || $isMaskTestEnabled()) && !!this.$mainAttachmentObject?.stencil?.view && !this.currentRenderTarget;
1095
+ this.fillSimple(vertexBuffer, mesh.indexCount, useStencilPipeline, bindGroup, uniformOffset);
1096
+ }
1097
+ // ストローク描画後はpathCommandをクリアする
1098
+ // 理由: drawFill()がfill()を呼び出すため、クリアしないと同じパスが白で塗りつぶされる
1099
+ this.pathCommand.reset();
1100
+ }
1101
+ /**
1102
+ * @description グラデーションの塗りつぶしを実行
1103
+ */
1104
+ gradientFill(type, stops, matrix, spread, interpolation, focal) {
1105
+ const pathVertices = this.pathCommand.$getVertices;
1106
+ if (pathVertices.length === 0) {
1107
+ return;
1108
+ }
1109
+ this.ensureFillRenderPass();
1110
+ // WebGL版と同じ: ビューポートサイズ
1111
+ const viewportWidth = this.viewportWidth;
1112
+ const viewportHeight = this.viewportHeight;
1113
+ // ステンシル付きパイプラインを使用するかどうかを判定
1114
+ // グラデーション塗りつぶしでは、マスクモード時のみステンシルテストが必要
1115
+ const useMainStencil = !!((this.inMaskMode || $isMaskTestEnabled()) && this.$mainAttachmentObject?.stencil?.view && !this.currentRenderTarget);
1116
+ const useStencilPipeline = useMainStencil;
1117
+ // アトラスへの描画かどうか
1118
+ const useAtlasTarget = !!this.currentRenderTarget;
1119
+ const lutTexture = contextGradientFillUseCase(this.device, this.renderPassEncoder, this.bufferManager, this.pipelineManager, pathVertices, this.$matrix, this.$fillStyle, type, stops, matrix, spread, interpolation, focal, viewportWidth, viewportHeight, useAtlasTarget, useStencilPipeline, this.$mainAttachmentObject?.clipLevel ?? 1);
1120
+ if (lutTexture) {
1121
+ this.addFrameTexture(lutTexture);
1122
+ }
1123
+ // グラデーション描画後にパスをクリア
1124
+ // これにより、後続のfill()呼び出しで同じパスが再描画されるのを防ぐ
1125
+ this.beginPath();
1126
+ }
1127
+ /**
1128
+ * @description ビットマップの塗りつぶしを実行
1129
+ */
1130
+ bitmapFill(pixels, matrix, width, height, repeat, smooth) {
1131
+ const pathVertices = this.pathCommand.$getVertices;
1132
+ if (pathVertices.length === 0) {
1133
+ return;
1134
+ }
1135
+ this.ensureFillRenderPass();
1136
+ // アトラスのアタッチメントを取得(ステンシル判定で使用)
1137
+ const atlasAttachment = $getAtlasAttachmentObject();
1138
+ // ステンシル付きレンダーパスかどうかを判定
1139
+ // - マスクモード時またはマスクテスト有効時(メインアタッチメントへの描画)
1140
+ // - アトラス描画時(ステンシル付きレンダーパス)
1141
+ const useAtlasStencil = !!(this.currentRenderTarget && atlasAttachment?.stencil?.view);
1142
+ const useMainStencil = !!((this.inMaskMode || $isMaskTestEnabled()) && this.$mainAttachmentObject?.stencil?.view && !this.currentRenderTarget);
1143
+ const useStencilPipeline = useAtlasStencil || useMainStencil;
1144
+ // マスク描画時のクリップレベルを取得
1145
+ const clipLevel = this.$mainAttachmentObject?.clipLevel ?? 1;
1146
+ const bitmapTexture = contextBitmapFillUseCase(this.device, this.renderPassEncoder, this.bufferManager, this.pipelineManager, pathVertices, this.$matrix, this.$fillStyle, pixels, matrix, width, height, repeat, smooth, this.viewportWidth, this.viewportHeight, !!this.currentRenderTarget, !!useStencilPipeline, clipLevel);
1147
+ // ビットマップテクスチャをフレーム終了時に解放するリストに追加
1148
+ if (bitmapTexture) {
1149
+ this.addFrameTexture(bitmapTexture);
1150
+ }
1151
+ // ビットマップ描画後にパスをクリア
1152
+ // これにより、後続のfill()呼び出しで同じパスが再描画されるのを防ぐ
1153
+ this.beginPath();
1154
+ }
1155
+ /**
1156
+ * @description グラデーション線の描画を実行
1157
+ */
1158
+ gradientStroke(type, stops, matrix, spread, interpolation, focal) {
1159
+ // WebGL版と同じ: IPath[]形式で頂点を取得
1160
+ const vertices = this.pathCommand.getVerticesForStroke();
1161
+ if (vertices.length === 0) {
1162
+ return;
1163
+ }
1164
+ this.ensureFillRenderPass();
1165
+ // アトラスのアタッチメントを取得(ステンシル判定で使用)
1166
+ const atlasAttachment = $getAtlasAttachmentObject();
1167
+ // レンダーパスがステンシルアタッチメントを持つ場合はステンシル互換パイプラインを使用
1168
+ const useAtlasStencil = !!(this.currentRenderTarget && atlasAttachment?.stencil?.view);
1169
+ const useMainStencil = !!(!this.currentRenderTarget && this.$mainAttachmentObject?.stencil?.view);
1170
+ const useStencilPipeline = useAtlasStencil || useMainStencil;
1171
+ // WebGL版と同じ: thicknessをそのまま渡し、内部で/2される
1172
+ const lutTexture = contextGradientStrokeUseCase(this.device, this.renderPassEncoder, this.bufferManager, this.pipelineManager, vertices, this.thickness, this.$matrix, this.$strokeStyle, type, stops, matrix, spread, interpolation, focal, this.viewportWidth, this.viewportHeight, !!this.currentRenderTarget, useStencilPipeline);
1173
+ // LUTテクスチャをフレーム終了時に解放するリストに追加
1174
+ if (lutTexture) {
1175
+ this.addFrameTexture(lutTexture);
1176
+ }
1177
+ // ストローク描画後はpathCommandをクリアする
1178
+ // 理由: drawFill()がfill()を呼び出すため、クリアしないと同じパスが白で塗りつぶされる
1179
+ this.pathCommand.reset();
1180
+ }
1181
+ /**
1182
+ * @description ビットマップ線の描画を実行
1183
+ */
1184
+ bitmapStroke(pixels, matrix, width, height, repeat, smooth) {
1185
+ // WebGL版と同じ: IPath[]形式で頂点を取得
1186
+ const vertices = this.pathCommand.getVerticesForStroke();
1187
+ if (vertices.length === 0) {
1188
+ return;
1189
+ }
1190
+ this.ensureFillRenderPass();
1191
+ // アトラスのアタッチメントを取得(ステンシル判定で使用)
1192
+ const atlasAttachment = $getAtlasAttachmentObject();
1193
+ // レンダーパスがステンシルアタッチメントを持つ場合はステンシル互換パイプラインを使用
1194
+ const useAtlasStencil = !!(this.currentRenderTarget && atlasAttachment?.stencil?.view);
1195
+ const useMainStencil = !!(!this.currentRenderTarget && this.$mainAttachmentObject?.stencil?.view);
1196
+ const useStencilPipeline = useAtlasStencil || useMainStencil;
1197
+ // WebGL版と同じ: thicknessをそのまま渡し、内部で/2される
1198
+ const bitmapTexture = contextBitmapStrokeUseCase(this.device, this.renderPassEncoder, this.bufferManager, this.pipelineManager, vertices, this.thickness, this.$matrix, this.$strokeStyle, pixels, matrix, width, height, repeat, smooth, this.viewportWidth, this.viewportHeight, !!this.currentRenderTarget, useStencilPipeline);
1199
+ // ビットマップテクスチャをフレーム終了時に解放するリストに追加
1200
+ if (bitmapTexture) {
1201
+ this.addFrameTexture(bitmapTexture);
1202
+ }
1203
+ // ストローク描画後はpathCommandをクリアする
1204
+ // 理由: drawFill()がfill()を呼び出すため、クリアしないと同じパスが白で塗りつぶされる
1205
+ this.pathCommand.reset();
1206
+ }
1207
+ /**
1208
+ * @description マスク処理を実行
1209
+ * WebGL版と同様にステンシルバッファを使用したクリッピング
1210
+ * メインアタッチメントとアトラス両方でマスク処理をサポート
1211
+ */
1212
+ clip() {
1213
+ // メインアタッチメントまたはアトラスのいずれかを使用
1214
+ // currentAttachmentがない場合はメインアタッチメントを使用(メインキャンバスでのマスク処理用)
1215
+ let currentAttachment = this.frameBufferManager.getCurrentAttachment();
1216
+ const isMainAttachment = !currentAttachment || currentAttachment === this.$mainAttachmentObject;
1217
+ if (!currentAttachment && this.$mainAttachmentObject) {
1218
+ currentAttachment = this.$mainAttachmentObject;
1219
+ }
1220
+ if (!currentAttachment) {
1221
+ return;
1222
+ }
1223
+ // ステンシルバッファがない場合はスキップ
1224
+ if (!currentAttachment.stencil) {
1225
+ return;
1226
+ }
1227
+ const pathVertices = this.pathCommand.$getVertices;
1228
+ if (pathVertices.length === 0) {
1229
+ return;
1230
+ }
1231
+ // レンダーパスがない場合は作成
1232
+ if (!this.renderPassEncoder) {
1233
+ this.ensureCommandEncoder();
1234
+ // メインアタッチメントの場合はステンシル付きレンダーパスを作成(MSAA対応)
1235
+ if (isMainAttachment && this.$mainAttachmentObject?.stencil?.view) {
1236
+ const clipUseMsaa = this.$mainAttachmentObject.msaa && this.$mainAttachmentObject.msaaTexture?.view;
1237
+ const clipColorView = clipUseMsaa
1238
+ ? this.$mainAttachmentObject.msaaTexture.view
1239
+ : this.$mainAttachmentObject.texture.view;
1240
+ const clipStencilView = clipUseMsaa && this.$mainAttachmentObject.msaaStencil?.view
1241
+ ? this.$mainAttachmentObject.msaaStencil.view
1242
+ : this.$mainAttachmentObject.stencil.view;
1243
+ // resolveTargetなし: clip()はwriteMask=0でcolorを変更しない
1244
+ const renderPassDescriptor = this.frameBufferManager.createStencilRenderPassDescriptor(clipColorView, clipStencilView, "load", "load");
1245
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
1246
+ }
1247
+ else {
1248
+ return;
1249
+ }
1250
+ }
1251
+ contextClipUseCase(this.device, this.renderPassEncoder, this.bufferManager, this.pipelineManager, currentAttachment, pathVertices, this.$matrix, this.$fillStyle, this.globalAlpha, isMainAttachment);
1252
+ }
1253
+ /**
1254
+ * @description アタッチメントオブジェクトをバインド
1255
+ */
1256
+ bind(attachment_object) {
1257
+ this.frameBufferManager.setCurrentAttachment(attachment_object);
1258
+ // WebGL版と同じ: ビューポートサイズをアタッチメントのサイズに設定
1259
+ this.viewportWidth = attachment_object.width;
1260
+ this.viewportHeight = attachment_object.height;
1261
+ }
1262
+ /**
1263
+ * @description 現在のアタッチメントオブジェクトを取得
1264
+ * アトラスがバインドされていない場合はメインアタッチメントを返す
1265
+ * When no atlas is bound, returns the main attachment
1266
+ */
1267
+ get currentAttachmentObject() {
1268
+ // WebGL版と同じ: currentAttachmentがない場合はmainAttachmentを返す
1269
+ // これによりマスク操作がメインキャンバスでも正しく動作する
1270
+ const current = this.frameBufferManager.getCurrentAttachment();
1271
+ return current || this.$mainAttachmentObject;
1272
+ }
1273
+ /**
1274
+ * @description アトラス専用のアタッチメントオブジェクトを取得
1275
+ */
1276
+ get atlasAttachmentObject() {
1277
+ return $getAtlasAttachmentObject();
1278
+ }
1279
+ /**
1280
+ * @description グリッドの描画データをセット
1281
+ */
1282
+ useGrid(grid_data) {
1283
+ $gridDataMap.set($fillBufferIndex, grid_data);
1284
+ }
1285
+ /**
1286
+ * @description 指定のノード範囲で描画を開始(アトラステクスチャへの描画)
1287
+ * 2パスステンシルフィル対応: ステンシルバッファ付きレンダーパスを使用
1288
+ */
1289
+ beginNodeRendering(node) {
1290
+ // ノード領域クリアフラグをリセット
1291
+ this.nodeAreaCleared = false;
1292
+ // フレームが開始されていない場合は開始
1293
+ if (!this.frameStarted) {
1294
+ this.beginFrame();
1295
+ }
1296
+ // アトラステクスチャの該当箇所をレンダーターゲットに設定
1297
+ const attachment = $getAtlasAttachmentObjectByIndex(node.index) || $getAtlasAttachmentObject();
1298
+ if (attachment && attachment.texture) {
1299
+ // 同一アトラスへの連続描画ならレンダーパスを再利用
1300
+ if (this.renderPassEncoder && this.nodeRenderPassAtlasIndex === node.index) {
1301
+ // レンダーパスを再利用 — シザーレクトのみ更新
1302
+ this.currentRenderTarget = attachment.texture.view;
1303
+ this.viewportWidth = attachment.width;
1304
+ this.viewportHeight = attachment.height;
1305
+ }
1306
+ else {
1307
+ // アトラスが変わった or パスがない → 新規作成
1308
+ if (this.renderPassEncoder) {
1309
+ this.renderPassEncoder.end();
1310
+ this.renderPassEncoder = null;
1311
+ }
1312
+ this.currentRenderTarget = attachment.texture.view;
1313
+ this.viewportWidth = attachment.width;
1314
+ this.viewportHeight = attachment.height;
1315
+ this.ensureCommandEncoder();
1316
+ const useMsaa = attachment.msaa && attachment.msaaTexture?.view;
1317
+ const colorView = useMsaa ? attachment.msaaTexture.view : attachment.texture.view;
1318
+ const resolveTarget = useMsaa ? attachment.texture.view : null;
1319
+ if (attachment.stencil?.view) {
1320
+ const stencilView = useMsaa && attachment.msaaStencil?.view
1321
+ ? attachment.msaaStencil.view
1322
+ : attachment.stencil.view;
1323
+ const renderPassDescriptor = this.frameBufferManager.createStencilRenderPassDescriptor(colorView, stencilView, "load", "load", resolveTarget);
1324
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
1325
+ }
1326
+ else {
1327
+ const renderPassDescriptor = this.frameBufferManager.createRenderPassDescriptor(colorView, 0, 0, 0, 0, "load", resolveTarget);
1328
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
1329
+ }
1330
+ this.nodeRenderPassAtlasIndex = node.index;
1331
+ }
1332
+ // シザーレクトで描画範囲を制限
1333
+ let scissorX = Math.max(0, node.x);
1334
+ let scissorY = Math.max(0, node.y);
1335
+ let scissorW = Math.min(node.w, attachment.width - scissorX);
1336
+ let scissorH = Math.min(node.h, attachment.height - scissorY);
1337
+ scissorX = Math.min(scissorX, attachment.width);
1338
+ scissorY = Math.min(scissorY, attachment.height);
1339
+ scissorW = Math.max(0, Math.min(scissorW, attachment.width - scissorX));
1340
+ scissorH = Math.max(0, Math.min(scissorH, attachment.height - scissorY));
1341
+ this.$scissorRect.x = scissorX;
1342
+ this.$scissorRect.y = scissorY;
1343
+ this.$scissorRect.w = scissorW;
1344
+ this.$scissorRect.h = scissorH;
1345
+ this.currentNodeScissor = this.$scissorRect;
1346
+ if (scissorW > 0 && scissorH > 0) {
1347
+ const clearW = Math.min(scissorW + 1, attachment.width - scissorX);
1348
+ const clearH = Math.min(scissorH + 1, attachment.height - scissorY);
1349
+ this.renderPassEncoder.setScissorRect(scissorX, scissorY, clearW, clearH);
1350
+ }
1351
+ }
1352
+ }
1353
+ /**
1354
+ * @description ノード領域がまだクリアされていない場合にクリアを実行
1355
+ * 最初の描画操作(fill, gradientFill, gradientStroke等)で呼び出される
1356
+ */
1357
+ ensureNodeAreaCleared() {
1358
+ if (this.nodeAreaCleared) {
1359
+ return;
1360
+ }
1361
+ this.nodeAreaCleared = true;
1362
+ this.clearNodeArea();
1363
+ }
1364
+ /**
1365
+ * @description ノード領域をクリア(透明色 + ステンシル=0)
1366
+ * WebGL版の gl.clear(COLOR_BUFFER_BIT | STENCIL_BUFFER_BIT) と同等
1367
+ */
1368
+ clearNodeArea() {
1369
+ if (!this.renderPassEncoder) {
1370
+ return;
1371
+ }
1372
+ // ノードクリア用パイプラインを取得
1373
+ const clearPipeline = this.pipelineManager.getPipeline("node_clear_atlas");
1374
+ if (!clearPipeline) {
1375
+ return;
1376
+ }
1377
+ // 初回のみ頂点バッファを作成、以降はキャッシュを再利用
1378
+ // clearFrameBuffers()で破棄されないよう、BufferManagerのMapに登録せず直接作成
1379
+ if (!this.nodeClearQuadBuffer) {
1380
+ const buf = this.device.createBuffer({
1381
+ "size": $QUAD_VERTICES.byteLength,
1382
+ "usage": GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
1383
+ "mappedAtCreation": true
1384
+ });
1385
+ new Float32Array(buf.getMappedRange()).set($QUAD_VERTICES);
1386
+ buf.unmap();
1387
+ this.nodeClearQuadBuffer = buf;
1388
+ }
1389
+ const vertexBuffer = this.nodeClearQuadBuffer;
1390
+ // クリア描画を実行(シザーは+1pxで設定済み)
1391
+ this.renderPassEncoder.setPipeline(clearPipeline);
1392
+ this.renderPassEncoder.setVertexBuffer(0, vertexBuffer);
1393
+ this.renderPassEncoder.draw(6);
1394
+ // WebGL版と同じ: クリア後にシザーを元のサイズに戻す
1395
+ if (this.currentNodeScissor) {
1396
+ this.renderPassEncoder.setScissorRect(this.currentNodeScissor.x, this.currentNodeScissor.y, this.currentNodeScissor.w, this.currentNodeScissor.h);
1397
+ }
1398
+ }
1399
+ /**
1400
+ * @description 指定のノード範囲で描画を終了
1401
+ * レンダーパスは終了しない(次のbeginNodeRenderingで再利用するため)
1402
+ */
1403
+ endNodeRendering() {
1404
+ // レンダーパスは終了しない(次のbeginNodeRenderingで同一アトラスなら再利用)
1405
+ // メインテクスチャに戻す
1406
+ this.currentRenderTarget = null;
1407
+ // ノードシザー範囲をクリア
1408
+ this.currentNodeScissor = null;
1409
+ // ビューポートをキャンバスサイズに戻す
1410
+ this.viewportWidth = this.canvasContext.canvas.width;
1411
+ this.viewportHeight = this.canvasContext.canvas.height;
1412
+ }
1413
+ /**
1414
+ * @description 塗りの描画を実行
1415
+ */
1416
+ drawFill() {
1417
+ // WebGL版ではfill()がバッファに蓄積し、drawFill()がまとめてGPU描画する
1418
+ // WebGPU版ではfill()が直接GPU描画するため、ここでfill()を再呼び出しする必要はない
1419
+ // (END_FILLコマンドからfill()は既に呼ばれている)
1420
+ // レンダーパスは終了しない(アトラスレンダーパス統合で次のノードと共有する)
1421
+ // stencil_fillパイプラインのpassOp: "zero"でステンシルは自動リセット済み
1422
+ // グリッドデータをクリア
1423
+ $terminateGrid();
1424
+ }
1425
+ /**
1426
+ * @description インスタンスを描画
1427
+ */
1428
+ drawDisplayObject(node, x_min, y_min, x_max, y_max, color_transform) {
1429
+ // WebGPU display object drawing
1430
+ // インスタンス配列に追加
1431
+ // WebGL版と同じ: ビューポートサイズを使用(コンテナレイヤー時はレイヤーサイズ)
1432
+ const renderMaxSize = WebGPUUtil.getRenderMaxSize();
1433
+ addDisplayObjectToInstanceArray(node, x_min, y_min, x_max, y_max, color_transform, this.$matrix, this.globalCompositeOperation, this.viewportWidth, this.viewportHeight, renderMaxSize, this.globalAlpha // WebGL版と同じ: globalAlphaを渡す
1434
+ );
1435
+ }
1436
+ /**
1437
+ * @description インスタンス配列を描画
1438
+ * Draw instanced arrays
1439
+ *
1440
+ * useOptimizedInstancingがtrueの場合、Storage BufferとIndirect Drawingを使用。
1441
+ * - Storage Buffer: メモリアロケーション削減、CPU負荷15-25%軽減
1442
+ * - Indirect Drawing: CPU-GPUオーバーヘッド5-15%削減
1443
+ *
1444
+ */
1445
+ drawArraysInstanced() {
1446
+ // フレームが開始されていない場合は開始
1447
+ if (!this.frameStarted) {
1448
+ this.beginFrame();
1449
+ }
1450
+ // 既存のレンダーパスを終了(アトラスパス統合をリセット)
1451
+ if (this.renderPassEncoder) {
1452
+ this.renderPassEncoder.end();
1453
+ this.renderPassEncoder = null;
1454
+ }
1455
+ this.nodeRenderPassAtlasIndex = -1;
1456
+ // コマンドエンコーダーを確保
1457
+ this.ensureCommandEncoder();
1458
+ // UseCaseでインスタンス描画を実行
1459
+ // メインアタッチメントがない場合は初期化が必要
1460
+ if (!this.$mainAttachmentObject) {
1461
+ return;
1462
+ }
1463
+ if (this.useOptimizedInstancing) {
1464
+ // 最適化版: Storage Buffer + Indirect Drawing
1465
+ this.renderPassEncoder = contextDrawIndirectUseCase(this.device, this.commandEncoder, this.renderPassEncoder, this.$mainAttachmentObject, this.bufferManager, this.frameBufferManager, this.textureManager, this.pipelineManager, true, // useIndirect
1466
+ true // useStorageBuffer
1467
+ );
1468
+ }
1469
+ else {
1470
+ // 従来版: 毎フレームVertex Buffer新規生成
1471
+ this.renderPassEncoder = contextDrawArraysInstancedUseCase(this.device, this.commandEncoder, this.renderPassEncoder, this.$mainAttachmentObject, this.bufferManager, this.frameBufferManager, this.textureManager, this.pipelineManager);
1472
+ }
1473
+ // 複雑なブレンドモードの処理
1474
+ this.processComplexBlendQueue();
1475
+ }
1476
+ /**
1477
+ * @description 最適化インスタンス描画の有効/無効を設定
1478
+ * Enable or disable optimized instancing
1479
+ *
1480
+ */
1481
+ setOptimizedInstancing(enabled) {
1482
+ this.useOptimizedInstancing = enabled;
1483
+ }
1484
+ /**
1485
+ * @description 最適化インスタンス描画が有効かどうか
1486
+ * Whether optimized instancing is enabled
1487
+ *
1488
+ */
1489
+ isOptimizedInstancingEnabled() {
1490
+ return this.useOptimizedInstancing;
1491
+ }
1492
+ /**
1493
+ * @description 複雑なブレンドモードのキューを処理
1494
+ */
1495
+ processComplexBlendQueue() {
1496
+ // コマンドエンコーダーを確保
1497
+ this.ensureCommandEncoder();
1498
+ // $mainAttachmentObjectを渡す(レンダーパスベースのコピーに必要)
1499
+ contextProcessComplexBlendQueueUseCase(this.device, this.commandEncoder, this.$mainAttachmentObject, this.frameBufferManager, this.textureManager, this.pipelineManager, this.bufferManager);
1500
+ }
1501
+ /**
1502
+ * @description インスタンス配列をクリア
1503
+ */
1504
+ clearArraysInstanced() {
1505
+ // WebGPU clear instanced arrays
1506
+ const shaderManager = getInstancedShaderManager();
1507
+ shaderManager.clear();
1508
+ }
1509
+ /**
1510
+ * @description ピクセルバッファをNodeの指定箇所に転送
1511
+ * WebGPUでは、Shapeのシェーダーが-ndc.yでY軸反転しているため、
1512
+ * Bitmapも同じ方向になるよう画像を上下反転して書き込む
1513
+ */
1514
+ drawPixels(node, pixels) {
1515
+ // WebGPU draw pixels
1516
+ // アトラステクスチャの指定位置にピクセルデータを描画
1517
+ // ノードのインデックスを使用して正しいアトラスを取得
1518
+ const attachment = $getAtlasAttachmentObjectByIndex(node.index) || $getAtlasAttachmentObject();
1519
+ if (!attachment || !attachment.texture) {
1520
+ return;
1521
+ }
1522
+ const width = node.w;
1523
+ const height = node.h;
1524
+ // レンダーパスがアクティブな場合はマージンクリアしてから終了
1525
+ if (this.renderPassEncoder) {
1526
+ this.ensureNodeAreaCleared();
1527
+ this.renderPassEncoder.end();
1528
+ this.renderPassEncoder = null;
1529
+ }
1530
+ // commandEncoderはsubmitしない — drawPixelsToMsaa()内で同じエンコーダを再利用
1531
+ // writeTexture()はキュー操作でありエンコーダ不要
1532
+ this.nodeRenderPassAtlasIndex = -1;
1533
+ // MSAAが有効な場合は一時テクスチャ経由でMSAAテクスチャに直接描画
1534
+ // MSAAが無効な場合は従来通りresolve targetに直接書き込み
1535
+ if (attachment.msaa && attachment.msaaTexture?.view) {
1536
+ this.drawPixelsToMsaa(attachment, node, pixels, width, height);
1537
+ }
1538
+ else {
1539
+ const rowBytes = width * 4;
1540
+ this.device.queue.writeTexture({
1541
+ "texture": attachment.texture.resource,
1542
+ "origin": { "x": node.x, "y": node.y, "z": 0 }
1543
+ }, pixels, {
1544
+ "bytesPerRow": rowBytes,
1545
+ "rowsPerImage": height,
1546
+ "offset": 0
1547
+ }, {
1548
+ "width": width,
1549
+ "height": height,
1550
+ "depthOrArrayLayers": 1
1551
+ });
1552
+ }
1553
+ }
1554
+ /**
1555
+ * @description 一時テクスチャ経由でピクセルデータをMSAAテクスチャに描画
1556
+ */
1557
+ drawPixelsToMsaa(attachment, node, pixels, width, height) {
1558
+ // 一時テクスチャをプールから取得
1559
+ const tempTexture = $acquireRenderTexture(this.device, width, height);
1560
+ // ピクセルデータを一時テクスチャに書き込む
1561
+ const rowBytes = width * 4;
1562
+ this.device.queue.writeTexture({ "texture": tempTexture }, pixels, {
1563
+ "bytesPerRow": rowBytes,
1564
+ "rowsPerImage": height
1565
+ }, {
1566
+ "width": width,
1567
+ "height": height
1568
+ });
1569
+ const pipeline = this.pipelineManager.getPipeline("bitmap_render_msaa");
1570
+ if (!pipeline) {
1571
+ $releaseRenderTexture(tempTexture);
1572
+ return;
1573
+ }
1574
+ const bindGroupLayout = this.pipelineManager.getBindGroupLayout("positioned_texture");
1575
+ if (!bindGroupLayout) {
1576
+ $releaseRenderTexture(tempTexture);
1577
+ return;
1578
+ }
1579
+ const uniformData = this.$uniformData8;
1580
+ uniformData[0] = node.x;
1581
+ uniformData[1] = node.y;
1582
+ uniformData[2] = width;
1583
+ uniformData[3] = height;
1584
+ uniformData[4] = attachment.width;
1585
+ uniformData[5] = attachment.height;
1586
+ uniformData[6] = 0.0;
1587
+ uniformData[7] = 0.0;
1588
+ const uniformBuffer = this.bufferManager.acquireAndWriteUniformBuffer(uniformData);
1589
+ const sampler = this.textureManager.createSampler("linear_sampler", true);
1590
+ const tempTextureView = $getOrCreateView(tempTexture);
1591
+ $entries3[0].resource.buffer = uniformBuffer;
1592
+ $entries3[1].resource = sampler;
1593
+ $entries3[2].resource = tempTextureView;
1594
+ const bindGroup = this.device.createBindGroup({
1595
+ "layout": bindGroupLayout,
1596
+ "entries": $entries3
1597
+ });
1598
+ // フレームエンコーダーを使用してMSAAテクスチャに描画
1599
+ this.ensureCommandEncoder();
1600
+ $msaaColorAttachment.view = attachment.msaaTexture.view;
1601
+ $msaaColorAttachment.resolveTarget = attachment.texture.view;
1602
+ const stencilView = attachment.msaaStencil?.view;
1603
+ if (stencilView) {
1604
+ $msaaStencilAttachment.view = stencilView;
1605
+ $msaaDescriptor.depthStencilAttachment = $msaaStencilAttachment;
1606
+ }
1607
+ else {
1608
+ $msaaDescriptor.depthStencilAttachment = undefined;
1609
+ }
1610
+ const renderPass = this.commandEncoder.beginRenderPass($msaaDescriptor);
1611
+ renderPass.setViewport(0, 0, attachment.width, attachment.height, 0, 1);
1612
+ renderPass.setScissorRect(node.x, node.y, width, height);
1613
+ renderPass.setPipeline(pipeline);
1614
+ renderPass.setBindGroup(0, bindGroup);
1615
+ renderPass.draw(6);
1616
+ renderPass.end();
1617
+ // endFrame()でプールに返却
1618
+ this.pooledRenderTextures.push(tempTexture);
1619
+ }
1620
+ /**
1621
+ * @description OffscreenCanvasをNodeの指定箇所に転送
1622
+ * WebGPUでは、Shapeのシェーダーが-ndc.yでY軸反転しているため、
1623
+ * Bitmapも同じ方向になるよう画像を上下反転して書き込む
1624
+ */
1625
+ drawElement(node, element, flipY = false) {
1626
+ // WebGPU draw element
1627
+ // OffscreenCanvasまたはImageBitmapをアトラステクスチャに描画
1628
+ // ノードのインデックスを使用して正しいアトラスを取得
1629
+ const attachment = $getAtlasAttachmentObjectByIndex(node.index) || $getAtlasAttachmentObject();
1630
+ if (!attachment || !attachment.texture) {
1631
+ return;
1632
+ }
1633
+ const width = node.w;
1634
+ const height = node.h;
1635
+ // レンダーパスがアクティブな場合は終了
1636
+ if (this.renderPassEncoder) {
1637
+ this.ensureNodeAreaCleared();
1638
+ this.renderPassEncoder.end();
1639
+ this.renderPassEncoder = null;
1640
+ }
1641
+ // commandEncoderはsubmitしない — drawElementToMsaa()/drawElementToTexture()内で同じエンコーダを再利用
1642
+ // copyExternalImageToTexture()はキュー操作でありエンコーダ不要
1643
+ this.nodeRenderPassAtlasIndex = -1;
1644
+ // MSAAが有効な場合は一時テクスチャ経由でMSAAテクスチャに直接描画
1645
+ // MSAAが無効な場合もシェーダー経由で描画(WebGLと同じ処理フロー)
1646
+ if (attachment.msaa && attachment.msaaTexture?.view) {
1647
+ this.drawElementToMsaa(attachment, node, element, width, height, flipY);
1648
+ }
1649
+ else {
1650
+ this.drawElementToTexture(attachment, node, element, width, height, flipY);
1651
+ }
1652
+ }
1653
+ /**
1654
+ * @description 一時テクスチャ経由でMSAAテクスチャに直接描画
1655
+ */
1656
+ drawElementToMsaa(attachment, node, element, width, height, flipY) {
1657
+ // 一時テクスチャをプールから取得
1658
+ const tempTexture = $acquireRenderTexture(this.device, width, height);
1659
+ this.device.queue.copyExternalImageToTexture({
1660
+ "source": element,
1661
+ "flipY": flipY
1662
+ }, {
1663
+ "texture": tempTexture,
1664
+ "premultipliedAlpha": true
1665
+ }, {
1666
+ "width": width,
1667
+ "height": height
1668
+ });
1669
+ const pipeline = this.pipelineManager.getPipeline("bitmap_render_msaa");
1670
+ if (!pipeline) {
1671
+ $releaseRenderTexture(tempTexture);
1672
+ return;
1673
+ }
1674
+ const bindGroupLayout = this.pipelineManager.getBindGroupLayout("positioned_texture");
1675
+ if (!bindGroupLayout) {
1676
+ $releaseRenderTexture(tempTexture);
1677
+ return;
1678
+ }
1679
+ const uniformData = this.$uniformData8;
1680
+ uniformData[0] = node.x;
1681
+ uniformData[1] = node.y;
1682
+ uniformData[2] = width;
1683
+ uniformData[3] = height;
1684
+ uniformData[4] = attachment.width;
1685
+ uniformData[5] = attachment.height;
1686
+ uniformData[6] = 0.0;
1687
+ uniformData[7] = 0.0;
1688
+ const uniformBuffer = this.bufferManager.acquireAndWriteUniformBuffer(uniformData);
1689
+ const sampler = this.textureManager.createSampler("linear_sampler", true);
1690
+ const tempTextureView = $getOrCreateView(tempTexture);
1691
+ $entries3[0].resource.buffer = uniformBuffer;
1692
+ $entries3[1].resource = sampler;
1693
+ $entries3[2].resource = tempTextureView;
1694
+ const bindGroup = this.device.createBindGroup({
1695
+ "layout": bindGroupLayout,
1696
+ "entries": $entries3
1697
+ });
1698
+ // フレームエンコーダーを使用してMSAAテクスチャに描画
1699
+ this.ensureCommandEncoder();
1700
+ $msaaColorAttachment.view = attachment.msaaTexture.view;
1701
+ $msaaColorAttachment.resolveTarget = attachment.texture.view;
1702
+ const stencilView = attachment.msaaStencil?.view;
1703
+ if (stencilView) {
1704
+ $msaaStencilAttachment.view = stencilView;
1705
+ $msaaDescriptor.depthStencilAttachment = $msaaStencilAttachment;
1706
+ }
1707
+ else {
1708
+ $msaaDescriptor.depthStencilAttachment = undefined;
1709
+ }
1710
+ const renderPass = this.commandEncoder.beginRenderPass($msaaDescriptor);
1711
+ renderPass.setViewport(0, 0, attachment.width, attachment.height, 0, 1);
1712
+ renderPass.setScissorRect(node.x, node.y, width, height);
1713
+ renderPass.setPipeline(pipeline);
1714
+ renderPass.setBindGroup(0, bindGroup);
1715
+ renderPass.draw(6);
1716
+ renderPass.end();
1717
+ // endFrame()でプールに返却
1718
+ this.pooledRenderTextures.push(tempTexture);
1719
+ }
1720
+ /**
1721
+ * @description 一時テクスチャ経由で通常テクスチャに描画(非MSAA版)
1722
+ */
1723
+ drawElementToTexture(attachment, node, element, width, height, flipY) {
1724
+ // 一時テクスチャをプールから取得
1725
+ const tempTexture = $acquireRenderTexture(this.device, width, height);
1726
+ // ImageBitmapを一時テクスチャにコピー
1727
+ // flipYパラメータで画像の上下反転を制御(Videoはtrue、TextFieldはfalse)
1728
+ this.device.queue.copyExternalImageToTexture({
1729
+ "source": element,
1730
+ "flipY": flipY
1731
+ }, {
1732
+ "texture": tempTexture,
1733
+ "premultipliedAlpha": true
1734
+ }, {
1735
+ "width": width,
1736
+ "height": height
1737
+ });
1738
+ const pipeline = this.pipelineManager.getPipeline("bitmap_render");
1739
+ if (!pipeline) {
1740
+ $releaseRenderTexture(tempTexture);
1741
+ return;
1742
+ }
1743
+ const bindGroupLayout = this.pipelineManager.getBindGroupLayout("positioned_texture");
1744
+ if (!bindGroupLayout) {
1745
+ $releaseRenderTexture(tempTexture);
1746
+ return;
1747
+ }
1748
+ const uniformData = this.$uniformData8;
1749
+ uniformData[0] = node.x;
1750
+ uniformData[1] = node.y;
1751
+ uniformData[2] = width;
1752
+ uniformData[3] = height;
1753
+ uniformData[4] = attachment.width;
1754
+ uniformData[5] = attachment.height;
1755
+ uniformData[6] = 0.0;
1756
+ uniformData[7] = 0.0;
1757
+ const uniformBuffer = this.bufferManager.acquireAndWriteUniformBuffer(uniformData);
1758
+ const sampler = this.textureManager.createSampler("linear_sampler", true);
1759
+ const tempTextureView = $getOrCreateView(tempTexture);
1760
+ $entries3[0].resource.buffer = uniformBuffer;
1761
+ $entries3[1].resource = sampler;
1762
+ $entries3[2].resource = tempTextureView;
1763
+ const bindGroup = this.device.createBindGroup({
1764
+ "layout": bindGroupLayout,
1765
+ "entries": $entries3
1766
+ });
1767
+ // フレームエンコーダーを使用して通常テクスチャに描画
1768
+ this.ensureCommandEncoder();
1769
+ $msaaColorAttachment.view = attachment.texture.view;
1770
+ $msaaColorAttachment.resolveTarget = undefined;
1771
+ const stencilView = attachment.stencil?.view;
1772
+ if (stencilView) {
1773
+ $msaaStencilAttachment.view = stencilView;
1774
+ $msaaDescriptor.depthStencilAttachment = $msaaStencilAttachment;
1775
+ }
1776
+ else {
1777
+ $msaaDescriptor.depthStencilAttachment = undefined;
1778
+ }
1779
+ const renderPass = this.commandEncoder.beginRenderPass($msaaDescriptor);
1780
+ renderPass.setViewport(0, 0, attachment.width, attachment.height, 0, 1);
1781
+ renderPass.setScissorRect(node.x, node.y, width, height);
1782
+ renderPass.setPipeline(pipeline);
1783
+ renderPass.setBindGroup(0, bindGroup);
1784
+ renderPass.draw(6);
1785
+ renderPass.end();
1786
+ // endFrame()でプールに返却
1787
+ this.pooledRenderTextures.push(tempTexture);
1788
+ }
1789
+ /**
1790
+ * @description フィルターを適用
1791
+ */
1792
+ applyFilter(node, _unique_key, _updated, width, height, _is_bitmap, matrix, color_transform, blend_mode, bounds, params) {
1793
+ // インスタンス配列を先に描画
1794
+ this.drawArraysInstanced();
1795
+ // フレームが開始されていない場合は開始
1796
+ if (!this.frameStarted) {
1797
+ this.beginFrame();
1798
+ }
1799
+ // 既存のレンダーパスを終了(アトラスパス統合をリセット)
1800
+ if (this.renderPassEncoder) {
1801
+ this.renderPassEncoder.end();
1802
+ this.renderPassEncoder = null;
1803
+ }
1804
+ this.nodeRenderPassAtlasIndex = -1;
1805
+ // コマンドエンコーダーを確保
1806
+ this.ensureCommandEncoder();
1807
+ this.$filterConfig.commandEncoder = this.commandEncoder;
1808
+ this.$filterConfig.mainAttachment = this.$mainAttachmentObject;
1809
+ contextApplyFilterUseCase(node, width, height, _is_bitmap, matrix, color_transform, blend_mode, bounds, params, this.$filterConfig, this.mainTextureView, this.bufferManager);
1810
+ }
1811
+ /**
1812
+ * @description コンテナのフィルター/ブレンド用のレイヤーを開始
1813
+ * Begin a container layer for filter/blend processing
1814
+ *
1815
+ */
1816
+ containerBeginLayer(width, height) {
1817
+ this.drawArraysInstanced();
1818
+ // フレームが開始されていない場合は開始
1819
+ if (!this.frameStarted) {
1820
+ this.beginFrame();
1821
+ }
1822
+ // 既存のレンダーパスを終了
1823
+ if (this.renderPassEncoder) {
1824
+ this.renderPassEncoder.end();
1825
+ this.renderPassEncoder = null;
1826
+ }
1827
+ const mainAttachment = this.$mainAttachmentObject;
1828
+ this.$containerLayerStack.push(mainAttachment);
1829
+ // コンテナのコンテンツサイズを保存(containerEndLayerでの抽出範囲計算に使用)
1830
+ this.containerLayerContentSizes.push({ width, height });
1831
+ // WebGL版と同じ: コンテンツサイズのbgra8unormアタッチメントを作成(mask=trueでステンシル付き)
1832
+ // children の transform は layerBounds で相対化されるため、コンテンツはレイヤー内の (0,0) から描画される
1833
+ const tempAttachment = this.frameBufferManager.createAttachment("container_layer", width, height, mainAttachment.msaa, true);
1834
+ this.$mainAttachmentObject = tempAttachment;
1835
+ this.bind(tempAttachment);
1836
+ }
1837
+ /**
1838
+ * @description コンテナのフィルター/ブレンド用レイヤーを終了し、結果を元のメインに合成
1839
+ * End the container layer and composite the result back to the original main
1840
+ *
1841
+ * @param {IBlendMode} blend_mode
1842
+ * @param {Float32Array} matrix
1843
+ * @param {Float32Array | null} color_transform
1844
+ * @param {boolean} use_filter
1845
+ * @param {Float32Array | null} filter_bounds
1846
+ * @param {Float32Array | null} filter_params
1847
+ * @param {string} unique_key
1848
+ * @param {string} filter_key
1849
+ */
1850
+ containerEndLayer(blend_mode, matrix, color_transform, use_filter, filter_bounds, filter_params, unique_key, filter_key) {
1851
+ this.drawArraysInstanced();
1852
+ // 既存のレンダーパスを終了
1853
+ if (this.renderPassEncoder) {
1854
+ this.renderPassEncoder.end();
1855
+ this.renderPassEncoder = null;
1856
+ }
1857
+ this.ensureCommandEncoder();
1858
+ const tempAttachment = this.$mainAttachmentObject;
1859
+ const contentSize = this.containerLayerContentSizes.pop() || { "width": tempAttachment.width, "height": tempAttachment.height };
1860
+ // mainを復元
1861
+ this.$mainAttachmentObject = this.$containerLayerStack.pop();
1862
+ this.$filterConfig.commandEncoder = this.commandEncoder;
1863
+ this.$filterConfig.mainAttachment = undefined;
1864
+ contextContainerEndLayerUseCase(tempAttachment, this.$mainAttachmentObject, "container_layer", blend_mode, matrix, color_transform, use_filter, filter_bounds, filter_params, unique_key, filter_key, contentSize.width, contentSize.height, this.$filterConfig, this.bufferManager);
1865
+ // メインのアタッチメントをバインド
1866
+ this.bind(this.$mainAttachmentObject);
1867
+ }
1868
+ /**
1869
+ * @description キャッシュされたコンテナフィルターテクスチャをメインに描画
1870
+ * Draw a cached container filter texture to the main attachment
1871
+ *
1872
+ * @param {IBlendMode} blend_mode
1873
+ * @param {Float32Array} matrix
1874
+ * @param {Float32Array} color_transform
1875
+ * @param {Float32Array} filter_bounds
1876
+ * @param {string} unique_key
1877
+ * @param {string} filter_key
1878
+ */
1879
+ containerDrawCachedFilter(blend_mode, matrix, color_transform, filter_bounds, unique_key, filter_key) {
1880
+ const cachedKey = $cacheStore.get(unique_key, "fKey");
1881
+ if (cachedKey !== filter_key) {
1882
+ return;
1883
+ }
1884
+ const cachedAttachment = $cacheStore.get(unique_key, "fTexture");
1885
+ if (!cachedAttachment || !cachedAttachment.texture) {
1886
+ return;
1887
+ }
1888
+ this.drawArraysInstanced();
1889
+ if (!this.frameStarted) {
1890
+ this.beginFrame();
1891
+ }
1892
+ if (this.renderPassEncoder) {
1893
+ this.renderPassEncoder.end();
1894
+ this.renderPassEncoder = null;
1895
+ }
1896
+ this.ensureCommandEncoder();
1897
+ const mainAttachment = this.$mainAttachmentObject;
1898
+ if (!mainAttachment || !mainAttachment.texture) {
1899
+ return;
1900
+ }
1901
+ // ColorTransformが恒等変換でない場合、キャッシュのコピーにCTを適用
1902
+ let drawAttachment = cachedAttachment;
1903
+ let ctAttachment = null;
1904
+ const isIdentityCt = color_transform[0] === 1 && color_transform[1] === 1
1905
+ && color_transform[2] === 1 && color_transform[3] === 1
1906
+ && color_transform[4] === 0 && color_transform[5] === 0
1907
+ && color_transform[6] === 0 && color_transform[7] === 0;
1908
+ if (!isIdentityCt) {
1909
+ ctAttachment = this.frameBufferManager.createTemporaryAttachment(cachedAttachment.width, cachedAttachment.height);
1910
+ const ctPipeline = this.pipelineManager.getPipeline("color_transform");
1911
+ const ctBindGroupLayout = this.pipelineManager.getBindGroupLayout("texture_copy");
1912
+ if (ctPipeline && ctBindGroupLayout && ctAttachment.texture) {
1913
+ $ctUniform8[0] = color_transform[0];
1914
+ $ctUniform8[1] = color_transform[1];
1915
+ $ctUniform8[2] = color_transform[2];
1916
+ $ctUniform8[3] = color_transform[3];
1917
+ $ctUniform8[4] = color_transform[4];
1918
+ $ctUniform8[5] = color_transform[5];
1919
+ $ctUniform8[6] = color_transform[6];
1920
+ $ctUniform8[7] = 0;
1921
+ const ctUniformData = $ctUniform8;
1922
+ const ctUniformBuffer = this.bufferManager.acquireAndWriteUniformBuffer(ctUniformData);
1923
+ const ctSampler = this.textureManager.createSampler("cached_ct_sampler", false);
1924
+ $entries3[0].resource.buffer = ctUniformBuffer;
1925
+ $entries3[1].resource = ctSampler;
1926
+ $entries3[2].resource = cachedAttachment.texture.view;
1927
+ const ctBindGroup = this.device.createBindGroup({
1928
+ "layout": ctBindGroupLayout,
1929
+ "entries": $entries3
1930
+ });
1931
+ const ctRenderPass = this.frameBufferManager.createRenderPassDescriptor(ctAttachment.texture.view, 0, 0, 0, 0, "clear");
1932
+ const ctPass = this.commandEncoder.beginRenderPass(ctRenderPass);
1933
+ ctPass.setPipeline(ctPipeline);
1934
+ ctPass.setBindGroup(0, ctBindGroup);
1935
+ ctPass.draw(6, 1, 0, 0);
1936
+ ctPass.end();
1937
+ drawAttachment = ctAttachment;
1938
+ }
1939
+ }
1940
+ const devicePixelRatio = WebGPUUtil.getDevicePixelRatio();
1941
+ const scaleX = Math.sqrt(matrix[0] * matrix[0] + matrix[1] * matrix[1]);
1942
+ const scaleY = Math.sqrt(matrix[2] * matrix[2] + matrix[3] * matrix[3]);
1943
+ const boundsXMin = filter_bounds[0] * (scaleX / devicePixelRatio);
1944
+ const boundsYMin = filter_bounds[1] * (scaleY / devicePixelRatio);
1945
+ // WebGL版と同じ: boundsXMin + matrix[4] で絶対位置($offsetは使わない)
1946
+ const drawX = Math.floor(boundsXMin + matrix[4]);
1947
+ const drawY = Math.floor(boundsYMin + matrix[5]);
1948
+ // シンプルなブレンドモード判定
1949
+ const useMsaa = mainAttachment.msaa && mainAttachment.msaaTexture?.view;
1950
+ let pipelineName;
1951
+ switch (blend_mode) {
1952
+ case "add":
1953
+ pipelineName = useMsaa ? "filter_output_add_msaa" : "filter_output_add";
1954
+ break;
1955
+ case "screen":
1956
+ pipelineName = useMsaa ? "filter_output_screen_msaa" : "filter_output_screen";
1957
+ break;
1958
+ case "alpha":
1959
+ pipelineName = useMsaa ? "filter_output_alpha_msaa" : "filter_output_alpha";
1960
+ break;
1961
+ case "erase":
1962
+ pipelineName = useMsaa ? "filter_output_erase_msaa" : "filter_output_erase";
1963
+ break;
1964
+ default:
1965
+ pipelineName = useMsaa ? "filter_output_msaa" : "filter_output";
1966
+ break;
1967
+ }
1968
+ const pipeline = this.pipelineManager.getPipeline(pipelineName);
1969
+ const bindGroupLayout = this.pipelineManager.getBindGroupLayout("texture_copy");
1970
+ if (!pipeline || !bindGroupLayout) {
1971
+ return;
1972
+ }
1973
+ const sampler = this.textureManager.createSampler("cached_filter_sampler", true);
1974
+ const uniformBuffer = this.bufferManager.acquireAndWriteUniformBuffer($IDENTITY_UV);
1975
+ $entries3[0].resource.buffer = uniformBuffer;
1976
+ $entries3[1].resource = sampler;
1977
+ $entries3[2].resource = drawAttachment.texture.view;
1978
+ const bindGroup = this.device.createBindGroup({
1979
+ "layout": bindGroupLayout,
1980
+ "entries": $entries3
1981
+ });
1982
+ const colorView = useMsaa ? mainAttachment.msaaTexture.view : mainAttachment.texture.view;
1983
+ const resolveTarget = useMsaa ? mainAttachment.texture.view : null;
1984
+ const renderPassDescriptor = this.frameBufferManager.createRenderPassDescriptor(colorView, 0, 0, 0, 0, "load", resolveTarget);
1985
+ const vpX = Math.max(0, drawX);
1986
+ const vpY = Math.max(0, drawY);
1987
+ const vpW = Math.max(1, drawAttachment.width);
1988
+ const vpH = Math.max(1, drawAttachment.height);
1989
+ const mainWidth = mainAttachment.width;
1990
+ const mainHeight = mainAttachment.height;
1991
+ const scissorW = Math.max(1, Math.min(vpW, mainWidth - vpX));
1992
+ const scissorH = Math.max(1, Math.min(vpH, mainHeight - vpY));
1993
+ if (scissorW <= 0 || scissorH <= 0 || vpX >= mainWidth || vpY >= mainHeight) {
1994
+ if (ctAttachment) {
1995
+ this.frameBufferManager.releaseTemporaryAttachment(ctAttachment);
1996
+ }
1997
+ return;
1998
+ }
1999
+ const passEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
2000
+ passEncoder.setPipeline(pipeline);
2001
+ passEncoder.setBindGroup(0, bindGroup);
2002
+ passEncoder.setViewport(vpX, vpY, vpW, vpH, 0, 1);
2003
+ passEncoder.setScissorRect(vpX, vpY, scissorW, scissorH);
2004
+ passEncoder.draw(6, 1, 0, 0);
2005
+ passEncoder.end();
2006
+ // CT一時アタッチメントを解放
2007
+ if (ctAttachment) {
2008
+ this.frameBufferManager.releaseTemporaryAttachment(ctAttachment);
2009
+ }
2010
+ this.bind(mainAttachment);
2011
+ }
2012
+ /**
2013
+ * @description メインテクスチャを確保(フレーム開始時に一度だけgetCurrentTexture呼び出し)
2014
+ */
2015
+ ensureMainTexture() {
2016
+ if (!this.mainTexture) {
2017
+ this.mainTexture = this.canvasContext.getCurrentTexture();
2018
+ this.mainTextureView = this.mainTexture.createView();
2019
+ }
2020
+ }
2021
+ /**
2022
+ * @description 現在の描画ターゲットのテクスチャビューを取得
2023
+ */
2024
+ getCurrentTextureView() {
2025
+ // アトラステクスチャへのレンダリング中の場合
2026
+ if (this.currentRenderTarget) {
2027
+ return this.currentRenderTarget;
2028
+ }
2029
+ // メインキャンバステクスチャを確保
2030
+ this.ensureMainTexture();
2031
+ return this.mainTextureView;
2032
+ }
2033
+ /**
2034
+ * @description コマンドエンコーダーが存在することを保証
2035
+ */
2036
+ ensureCommandEncoder() {
2037
+ // Note: RenderPassEncoderの終了はここでは行わない
2038
+ // 呼び出し側で適切に管理すること
2039
+ if (!this.commandEncoder) {
2040
+ this.commandEncoder = this.device.createCommandEncoder();
2041
+ }
2042
+ }
2043
+ /**
2044
+ * @description フレーム開始(レンダリング開始前に呼ぶ)
2045
+ */
2046
+ beginFrame() {
2047
+ if (!this.frameStarted) {
2048
+ this.ensureMainTexture();
2049
+ this.ensureCommandEncoder();
2050
+ this.frameStarted = true;
2051
+ this.frameBufferManager.beginFrame();
2052
+ // 注意: グラデーションLUTは共有テクスチャに描画されるため、
2053
+ // キャッシュは使用しません。各フレームで再描画が必要です。
2054
+ }
2055
+ }
2056
+ /**
2057
+ * @description フレームごとのプール管理テクスチャを追加(endFrame()でプールに返却)
2058
+ */
2059
+ addFrameTexture(texture) {
2060
+ this.pooledTextures.push(texture);
2061
+ }
2062
+ /**
2063
+ * @description フレーム終了とコマンド送信(レンダリング完了後に呼ぶ)
2064
+ */
2065
+ endFrame() {
2066
+ if (!this.frameStarted) {
2067
+ return;
2068
+ }
2069
+ // 開いているRenderPassEncoderがあれば終了
2070
+ if (this.renderPassEncoder) {
2071
+ this.renderPassEncoder.end();
2072
+ this.renderPassEncoder = null;
2073
+ }
2074
+ // DynamicUniformAllocatorのステージングバッファをGPUに一括書き込み
2075
+ this.bufferManager.dynamicUniform.flush();
2076
+ // コマンドをsubmit
2077
+ if (this.commandEncoder) {
2078
+ try {
2079
+ const commandBuffer = this.commandEncoder.finish();
2080
+ this.device.queue.submit([commandBuffer]);
2081
+ }
2082
+ catch (e) {
2083
+ console.error("Failed to submit frame commands:", e);
2084
+ }
2085
+ }
2086
+ // submit後に一時テクスチャを解放
2087
+ this.frameBufferManager.flushPendingReleases();
2088
+ // フレームごとの一時バッファを解放
2089
+ this.bufferManager.clearFrameBuffers();
2090
+ // フレームごとの一時テクスチャを解放
2091
+ for (const texture of this.frameTextures) {
2092
+ texture.destroy();
2093
+ }
2094
+ this.frameTextures.length = 0;
2095
+ // プール管理テクスチャをプールに返却
2096
+ for (const texture of this.pooledTextures) {
2097
+ $releaseFillTexture(texture);
2098
+ }
2099
+ this.pooledTextures.length = 0;
2100
+ // レンダーテクスチャをプールに返却
2101
+ for (const texture of this.pooledRenderTextures) {
2102
+ $releaseRenderTexture(texture);
2103
+ }
2104
+ this.pooledRenderTextures.length = 0;
2105
+ // Gradient LUTキャッシュのTTL超過エントリを解放
2106
+ $cleanupLUTCache();
2107
+ // Dynamic Uniform BindGroupをリセット(バッファオフセットがリセットされるため)
2108
+ this.fillDynamicBindGroup = null;
2109
+ this.fillDynamicBindGroupBuffer = null;
2110
+ // 次のフレーム用にクリア
2111
+ this.commandEncoder = null;
2112
+ this.renderPassEncoder = null;
2113
+ this.currentRenderTarget = null;
2114
+ this.nodeRenderPassAtlasIndex = -1;
2115
+ // テクスチャ参照をクリア(次フレームで新しく取得)
2116
+ this.mainTexture = null;
2117
+ this.mainTextureView = null;
2118
+ this.frameStarted = false;
2119
+ }
2120
+ /**
2121
+ * @description コマンドを送信(後方互換性のため残す)
2122
+ */
2123
+ submit() {
2124
+ this.endFrame();
2125
+ }
2126
+ /**
2127
+ * @description ノードを作成
2128
+ * アトラスがいっぱいの場合は新しいアトラスを作成して再試行
2129
+ */
2130
+ createNode(width, height) {
2131
+ // WebGPU node creation implementation using texture-packer
2132
+ const index = $getActiveAtlasIndex();
2133
+ if (!$rootNodes[index]) {
2134
+ const maxSize = WebGPUUtil.getRenderMaxSize();
2135
+ $rootNodes[index] = new TexturePacker(index, maxSize, maxSize);
2136
+ }
2137
+ const rootNode = $rootNodes[index];
2138
+ const node = rootNode.insert(width, height);
2139
+ if (!node) {
2140
+ // アトラスがいっぱいの場合、新しいアトラスインデックスに切り替えて再試行
2141
+ $setActiveAtlasIndex(index + 1);
2142
+ return this.createNode(width, height);
2143
+ }
2144
+ return node;
2145
+ }
2146
+ /**
2147
+ * @description ノードを削除
2148
+ */
2149
+ removeNode(node) {
2150
+ // WebGPU node removal implementation
2151
+ const index = node.index;
2152
+ const rootNode = $rootNodes[index];
2153
+ if (rootNode) {
2154
+ rootNode.dispose(node.x, node.y, node.w, node.h);
2155
+ }
2156
+ }
2157
+ /**
2158
+ * @description フレームバッファの描画情報をキャンバスに転送
2159
+ * スワップチェーンはCopyDstをサポートしないため、レンダーパスでブリット
2160
+ */
2161
+ transferMainCanvas() {
2162
+ // メインアタッチメントの内容をスワップチェーン(キャンバス)にコピー
2163
+ if (!this.$mainAttachmentObject || !this.$mainAttachmentObject.texture) {
2164
+ this.endFrame();
2165
+ return;
2166
+ }
2167
+ // 既存のレンダーパスを終了
2168
+ if (this.renderPassEncoder) {
2169
+ this.renderPassEncoder.end();
2170
+ this.renderPassEncoder = null;
2171
+ }
2172
+ // コマンドエンコーダーを確保
2173
+ this.ensureCommandEncoder();
2174
+ // メインテクスチャビューを確保
2175
+ this.ensureMainTexture();
2176
+ // スワップチェーンはCopyDstをサポートしないため、レンダーパスでブリット
2177
+ const pipeline = this.pipelineManager.getPipeline("texture_copy_bgra");
2178
+ const bindGroupLayout = this.pipelineManager.getBindGroupLayout("texture_copy");
2179
+ if (!pipeline || !bindGroupLayout) {
2180
+ console.error("[WebGPU] texture_copy_bgra pipeline not found");
2181
+ this.endFrame();
2182
+ return;
2183
+ }
2184
+ // Static BindGroup キャッシュ: mainAttachment.texture.viewが同じ間は再利用
2185
+ const currentView = this.$mainAttachmentObject.texture.view;
2186
+ if (!$presentBindGroup || $presentBindGroupView !== currentView) {
2187
+ if (!$presentUniformBuffer) {
2188
+ $presentUniformBuffer = this.device.createBuffer({
2189
+ "size": $IDENTITY_UV.byteLength,
2190
+ "usage": GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
2191
+ });
2192
+ this.device.queue.writeBuffer($presentUniformBuffer, 0, $IDENTITY_UV.buffer, $IDENTITY_UV.byteOffset, $IDENTITY_UV.byteLength);
2193
+ }
2194
+ const sampler = this.textureManager.createSampler("transfer_sampler", false);
2195
+ $entries3[0].resource = { "buffer": $presentUniformBuffer };
2196
+ $entries3[1].resource = sampler;
2197
+ $entries3[2].resource = currentView;
2198
+ $presentBindGroup = this.device.createBindGroup({
2199
+ "layout": bindGroupLayout,
2200
+ "entries": $entries3
2201
+ });
2202
+ $presentBindGroupView = currentView;
2203
+ }
2204
+ const bindGroup = $presentBindGroup;
2205
+ // スワップチェーンへのレンダーパスを作成(プリアロケート版)
2206
+ $presentColorAttachment.view = this.mainTextureView;
2207
+ const passEncoder = this.commandEncoder.beginRenderPass($presentDescriptor);
2208
+ passEncoder.setPipeline(pipeline);
2209
+ passEncoder.setBindGroup(0, bindGroup);
2210
+ passEncoder.draw(6, 1, 0, 0); // フルスクリーンクワッド(6頂点)
2211
+ passEncoder.end();
2212
+ // endFrame()でsubmitされる
2213
+ this.endFrame();
2214
+ }
2215
+ /**
2216
+ * @description ImageBitmapを生成
2217
+ */
2218
+ async createImageBitmap(width, height) {
2219
+ // アトラステクスチャから現在の描画内容を取得
2220
+ const attachment = $getAtlasAttachmentObject();
2221
+ if (!attachment) {
2222
+ throw new Error("[WebGPU] Atlas attachment not found");
2223
+ }
2224
+ // 描画を完了
2225
+ if (this.renderPassEncoder) {
2226
+ this.renderPassEncoder.end();
2227
+ this.renderPassEncoder = null;
2228
+ }
2229
+ // GPUバッファにピクセルデータを読み込み
2230
+ const bytesPerPixel = 4;
2231
+ const bytesPerRow = Math.ceil(width * bytesPerPixel / 256) * 256; // 256バイトアライメント
2232
+ const bufferSize = bytesPerRow * height;
2233
+ // ピクセルバッファを作成
2234
+ const pixelBuffer = this.device.createBuffer({
2235
+ "size": bufferSize,
2236
+ "usage": GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
2237
+ });
2238
+ // コマンドエンコーダーを作成
2239
+ const commandEncoder = this.device.createCommandEncoder();
2240
+ // アトラステクスチャからピクセルバッファにコピー
2241
+ if (!attachment.texture) {
2242
+ throw new Error("Attachment texture is null");
2243
+ }
2244
+ commandEncoder.copyTextureToBuffer({
2245
+ "texture": attachment.texture.resource,
2246
+ "mipLevel": 0,
2247
+ "origin": { "x": 0, "y": 0, "z": 0 }
2248
+ }, {
2249
+ "buffer": pixelBuffer,
2250
+ "bytesPerRow": bytesPerRow,
2251
+ "rowsPerImage": height
2252
+ }, {
2253
+ "width": width,
2254
+ "height": height,
2255
+ "depthOrArrayLayers": 1
2256
+ });
2257
+ // コマンドを送信
2258
+ this.device.queue.submit([commandEncoder.finish()]);
2259
+ // バッファをマップして読み込み
2260
+ await pixelBuffer.mapAsync(GPUMapMode.READ);
2261
+ const mappedRange = pixelBuffer.getMappedRange();
2262
+ const pixels = new Uint8Array(mappedRange);
2263
+ // ピクセルデータをコピー(アライメントを考慮)
2264
+ const resultPixels = new Uint8Array(width * height * 4);
2265
+ for (let y = 0; y < height; y++) {
2266
+ const srcOffset = y * bytesPerRow;
2267
+ const dstOffset = y * width * 4;
2268
+ resultPixels.set(pixels.subarray(srcOffset, srcOffset + width * 4), dstOffset);
2269
+ }
2270
+ pixelBuffer.unmap();
2271
+ pixelBuffer.destroy();
2272
+ // プリマルチプライドアルファをストレートアルファに変換
2273
+ const inv = new Float32Array(256);
2274
+ for (let a = 1; a < 256; a++) {
2275
+ inv[a] = 255 / a;
2276
+ }
2277
+ for (let idx = 0; idx < resultPixels.length; idx += 4) {
2278
+ const alpha = resultPixels[idx + 3];
2279
+ if (alpha === 0 || alpha === 255) {
2280
+ continue;
2281
+ }
2282
+ const f = inv[alpha];
2283
+ resultPixels[idx] = Math.min(255, Math.round(resultPixels[idx] * f));
2284
+ resultPixels[idx + 1] = Math.min(255, Math.round(resultPixels[idx + 1] * f));
2285
+ resultPixels[idx + 2] = Math.min(255, Math.round(resultPixels[idx + 2] * f));
2286
+ }
2287
+ // ImageBitmapを作成
2288
+ const imageData = new ImageData(new Uint8ClampedArray(resultPixels), width, height);
2289
+ // グローバルのcreateBitmapが存在するかチェック
2290
+ if (typeof createImageBitmap !== "undefined") {
2291
+ return await createImageBitmap(imageData, {
2292
+ "premultiplyAlpha": "none",
2293
+ "colorSpaceConversion": "none"
2294
+ });
2295
+ }
2296
+ // Fallback: createImageBitmapがない環境用
2297
+ throw new Error("[WebGPU] createImageBitmap not available in this environment");
2298
+ }
2299
+ /**
2300
+ * @description マスク描画の開始準備
2301
+ * Prepare to start drawing the mask
2302
+ *
2303
+ */
2304
+ beginMask() {
2305
+ // メインアタッチメントをバインド(マスクはメインアタッチメントのステンシルに書き込む)
2306
+ if (this.$mainAttachmentObject) {
2307
+ this.bind(this.$mainAttachmentObject);
2308
+ }
2309
+ // マスクモードではメインアタッチメントに描画するため、currentRenderTargetをnullに設定
2310
+ // これにより、fill()等がメイン用シェーダー(Y反転あり)を使用する
2311
+ this.currentRenderTarget = null;
2312
+ // 既存のレンダーパスを終了
2313
+ if (this.renderPassEncoder) {
2314
+ this.renderPassEncoder.end();
2315
+ this.renderPassEncoder = null;
2316
+ }
2317
+ // フレームが開始されていない場合は開始
2318
+ if (!this.frameStarted) {
2319
+ this.beginFrame();
2320
+ }
2321
+ // コマンドエンコーダーを確保
2322
+ this.ensureCommandEncoder();
2323
+ // ステンシル付きレンダーパスを開始(マスク描画用)
2324
+ if (this.$mainAttachmentObject?.texture && this.$mainAttachmentObject?.stencil?.view) {
2325
+ // 最初のマスク(clipLevel == 0)の場合はステンシルをクリア
2326
+ // ネストされたマスクの場合は既存のステンシル値を保持
2327
+ const isFirstMask = this.$mainAttachmentObject.clipLevel === 0;
2328
+ const stencilLoadOp = isFirstMask ? "clear" : "load";
2329
+ // MSAA有効時はmsaaTexture/msaaStencilを使用(sampleCount一致が必要)
2330
+ // resolveTargetは設定しない: clip()はwriteMask=0でcolorを変更しないため、
2331
+ // resolveでtexture.viewを上書きすると、先にtexture.viewに描画された内容が消える
2332
+ const mainUseMsaa = this.$mainAttachmentObject.msaa && this.$mainAttachmentObject.msaaTexture?.view;
2333
+ const colorView = mainUseMsaa
2334
+ ? this.$mainAttachmentObject.msaaTexture.view
2335
+ : this.$mainAttachmentObject.texture.view;
2336
+ const stencilView = mainUseMsaa && this.$mainAttachmentObject.msaaStencil?.view
2337
+ ? this.$mainAttachmentObject.msaaStencil.view
2338
+ : this.$mainAttachmentObject.stencil.view;
2339
+ const renderPassDescriptor = this.frameBufferManager.createStencilRenderPassDescriptor(colorView, stencilView, "load", // カラーは既存の内容を保持
2340
+ stencilLoadOp // 最初のマスク: クリア、ネスト: 保持
2341
+ );
2342
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
2343
+ // ビューポートサイズを更新
2344
+ this.viewportWidth = this.$mainAttachmentObject.width;
2345
+ this.viewportHeight = this.$mainAttachmentObject.height;
2346
+ }
2347
+ maskBeginMaskService();
2348
+ // マスクモードフラグを設定
2349
+ this.inMaskMode = true;
2350
+ }
2351
+ /**
2352
+ * @description マスクの描画範囲を設定
2353
+ * Set the mask drawing bounds
2354
+ *
2355
+ * @param {number} x_min
2356
+ * @param {number} y_min
2357
+ * @param {number} x_max
2358
+ * @param {number} y_max
2359
+ */
2360
+ setMaskBounds(x_min, y_min, x_max, y_max) {
2361
+ maskSetMaskBoundsService(x_min, y_min, x_max, y_max);
2362
+ }
2363
+ /**
2364
+ * @description マスクの描画を終了
2365
+ * End mask drawing
2366
+ *
2367
+ */
2368
+ endMask() {
2369
+ // マスク描画用のレンダーパスを終了
2370
+ if (this.renderPassEncoder) {
2371
+ this.renderPassEncoder.end();
2372
+ this.renderPassEncoder = null;
2373
+ }
2374
+ maskEndMaskService();
2375
+ // マスクモードフラグをクリア
2376
+ this.inMaskMode = false;
2377
+ }
2378
+ /**
2379
+ * @description マスクの終了処理
2380
+ * Mask end processing
2381
+ *
2382
+ */
2383
+ leaveMask() {
2384
+ this.drawArraysInstanced();
2385
+ // 現在のclipLevelを保存(leaveMaskUseCase内でデクリメントされる)
2386
+ const currentAttachment = this.frameBufferManager.getCurrentAttachment();
2387
+ const currentClipLevel = currentAttachment?.clipLevel ?? 0;
2388
+ const wasLastMask = currentClipLevel === 1;
2389
+ maskLeaveMaskUseCase();
2390
+ // 現在のレンダーパスを終了
2391
+ if (this.renderPassEncoder) {
2392
+ this.renderPassEncoder.end();
2393
+ this.renderPassEncoder = null;
2394
+ }
2395
+ // コマンドエンコーダーを確保
2396
+ this.ensureCommandEncoder();
2397
+ // MSAA有効時はmsaaTexture/msaaStencilを使用
2398
+ const leaveMsaa = this.$mainAttachmentObject?.msaa && this.$mainAttachmentObject?.msaaTexture?.view;
2399
+ const leaveColorView = leaveMsaa
2400
+ ? this.$mainAttachmentObject.msaaTexture.view
2401
+ : this.$mainAttachmentObject?.texture.view;
2402
+ const leaveStencilView = leaveMsaa && this.$mainAttachmentObject?.msaaStencil?.view
2403
+ ? this.$mainAttachmentObject.msaaStencil.view
2404
+ : this.$mainAttachmentObject?.stencil?.view;
2405
+ if (wasLastMask && leaveStencilView) {
2406
+ // 単体マスク(最後のマスク)の場合、ステンシルバッファをクリア
2407
+ // WebGL: gl.clear(STENCIL_BUFFER_BIT)
2408
+ // resolveTargetは設定しない(ステンシルクリアのみが目的で、カラーの上書きを防ぐ)
2409
+ const clearPassDescriptor = {
2410
+ "colorAttachments": [{
2411
+ "view": leaveColorView,
2412
+ "loadOp": "load",
2413
+ "storeOp": "store"
2414
+ }],
2415
+ "depthStencilAttachment": {
2416
+ "view": leaveStencilView,
2417
+ "stencilLoadOp": "clear", // ステンシルをクリア
2418
+ "stencilStoreOp": "store",
2419
+ "stencilClearValue": 0
2420
+ }
2421
+ };
2422
+ const clearPass = this.commandEncoder.beginRenderPass(clearPassDescriptor);
2423
+ clearPass.end();
2424
+ }
2425
+ else if (currentClipLevel > 1 && leaveStencilView) {
2426
+ // ネストされたマスクの場合、上位レベルのステンシルビットをクリア
2427
+ // WebGL: stencilMask(1 << clipLevel), stencilOp(REPLACE, REPLACE, REPLACE)
2428
+ // 全画面矩形を描画してステンシルビットをクリア
2429
+ const clearLevel = currentClipLevel; // デクリメント前のレベル
2430
+ const clampedLevel = Math.min(8, Math.max(1, clearLevel));
2431
+ const pipelineName = `clip_clear_main_${clampedLevel}`;
2432
+ const pipeline = this.pipelineManager.getPipeline(pipelineName);
2433
+ if (pipeline) {
2434
+ // ステンシル付きレンダーパスを開始
2435
+ // resolveTargetなし: clip_clear_mainはwriteMask=0でcolorを変更しない
2436
+ const renderPassDescriptor = this.frameBufferManager.createStencilRenderPassDescriptor(leaveColorView, leaveStencilView, "load", // カラーは保持
2437
+ "load" // ステンシルは保持(特定のビットのみクリア)
2438
+ );
2439
+ const passEncoder = this.commandEncoder.beginRenderPass(renderPassDescriptor);
2440
+ // 全画面矩形を描画(ステンシルビットをクリア)
2441
+ // 17-float vertex buffer format for clip pipelines
2442
+ // Format: position(2) + bezier(2) + color(4) + matrix(9) = 17 floats
2443
+ // Matrix is identity: row0=(1,0,0), row1=(0,1,0), row2=(0,0,1)
2444
+ const meshBuffer = this.bufferManager.acquireVertexBuffer($FULLSCREEN_MESH.byteLength, $FULLSCREEN_MESH);
2445
+ passEncoder.setPipeline(pipeline);
2446
+ passEncoder.setStencilReference(0); // 参照値0でREPLACE
2447
+ passEncoder.setVertexBuffer(0, meshBuffer);
2448
+ passEncoder.draw(6, 1, 0, 0);
2449
+ passEncoder.end();
2450
+ }
2451
+ }
2452
+ }
2453
+ }