@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.
- package/LICENSE +21 -0
- package/README.md +574 -0
- package/package.json +30 -0
- package/src/AtlasManager.d.ts +23 -0
- package/src/AtlasManager.js +123 -0
- package/src/AttachmentManager/service/AttachmentManagerCreateAttachmentObjectService.d.ts +13 -0
- package/src/AttachmentManager/service/AttachmentManagerCreateAttachmentObjectService.js +24 -0
- package/src/AttachmentManager/service/AttachmentManagerCreateColorBufferService.d.ts +15 -0
- package/src/AttachmentManager/service/AttachmentManagerCreateColorBufferService.js +31 -0
- package/src/AttachmentManager/service/AttachmentManagerCreateRenderPassDescriptorService.d.ts +5 -0
- package/src/AttachmentManager/service/AttachmentManagerCreateRenderPassDescriptorService.js +42 -0
- package/src/AttachmentManager/service/AttachmentManagerCreateStencilBufferService.d.ts +16 -0
- package/src/AttachmentManager/service/AttachmentManagerCreateStencilBufferService.js +28 -0
- package/src/AttachmentManager/service/AttachmentManagerCreateTextureObjectService.d.ts +17 -0
- package/src/AttachmentManager/service/AttachmentManagerCreateTextureObjectService.js +33 -0
- package/src/AttachmentManager/service/AttachmentManagerGetColorBufferService.d.ts +16 -0
- package/src/AttachmentManager/service/AttachmentManagerGetColorBufferService.js +28 -0
- package/src/AttachmentManager/service/AttachmentManagerGetStencilBufferService.d.ts +17 -0
- package/src/AttachmentManager/service/AttachmentManagerGetStencilBufferService.js +27 -0
- package/src/AttachmentManager/service/AttachmentManagerGetTextureService.d.ts +18 -0
- package/src/AttachmentManager/service/AttachmentManagerGetTextureService.js +27 -0
- package/src/AttachmentManager/service/AttachmentManagerReleaseTextureService.d.ts +12 -0
- package/src/AttachmentManager/service/AttachmentManagerReleaseTextureService.js +17 -0
- package/src/AttachmentManager/usecase/AttachmentManagerGetAttachmentObjectUseCase.d.ts +26 -0
- package/src/AttachmentManager/usecase/AttachmentManagerGetAttachmentObjectUseCase.js +43 -0
- package/src/AttachmentManager/usecase/AttachmentManagerReleaseAttachmentUseCase.d.ts +18 -0
- package/src/AttachmentManager/usecase/AttachmentManagerReleaseAttachmentUseCase.js +33 -0
- package/src/AttachmentManager.d.ts +19 -0
- package/src/AttachmentManager.js +105 -0
- package/src/BezierConverter/BezierConverter.d.ts +16 -0
- package/src/BezierConverter/BezierConverter.js +15 -0
- package/src/BezierConverter/service/BezierConverterCalculateFlatnessService.d.ts +15 -0
- package/src/BezierConverter/service/BezierConverterCalculateFlatnessService.js +37 -0
- package/src/BezierConverter/service/BezierConverterSplitCubicService.d.ts +15 -0
- package/src/BezierConverter/service/BezierConverterSplitCubicService.js +47 -0
- package/src/BezierConverter/usecase/BezierConverterAdaptiveCubicToQuadUseCase.d.ts +29 -0
- package/src/BezierConverter/usecase/BezierConverterAdaptiveCubicToQuadUseCase.js +80 -0
- package/src/Blend/BlendInstancedManager.d.ts +35 -0
- package/src/Blend/BlendInstancedManager.js +147 -0
- package/src/Blend/service/BlendAddService.d.ts +1 -0
- package/src/Blend/service/BlendAddService.js +8 -0
- package/src/Blend/service/BlendAlphaService.d.ts +1 -0
- package/src/Blend/service/BlendAlphaService.js +8 -0
- package/src/Blend/service/BlendEraseService.d.ts +1 -0
- package/src/Blend/service/BlendEraseService.js +8 -0
- package/src/Blend/service/BlendGetStateService.d.ts +12 -0
- package/src/Blend/service/BlendGetStateService.js +13 -0
- package/src/Blend/service/BlendOneZeroService.d.ts +1 -0
- package/src/Blend/service/BlendOneZeroService.js +8 -0
- package/src/Blend/service/BlendResetService.d.ts +1 -0
- package/src/Blend/service/BlendResetService.js +8 -0
- package/src/Blend/service/BlendScreenService.d.ts +1 -0
- package/src/Blend/service/BlendScreenService.js +8 -0
- package/src/Blend/service/BlendSetModeService.d.ts +2 -0
- package/src/Blend/service/BlendSetModeService.js +4 -0
- package/src/Blend/usecase/BlendApplyComplexBlendUseCase.d.ts +6 -0
- package/src/Blend/usecase/BlendApplyComplexBlendUseCase.js +79 -0
- package/src/Blend/usecase/BlendOperationUseCase.d.ts +11 -0
- package/src/Blend/usecase/BlendOperationUseCase.js +31 -0
- package/src/Blend.d.ts +8 -0
- package/src/Blend.js +91 -0
- package/src/BufferManager/service/BufferManagerCreateIndirectBufferService.d.ts +15 -0
- package/src/BufferManager/service/BufferManagerCreateIndirectBufferService.js +37 -0
- package/src/BufferManager/service/BufferManagerCreateRectVerticesService.d.ts +13 -0
- package/src/BufferManager/service/BufferManagerCreateRectVerticesService.js +23 -0
- package/src/BufferManager/service/BufferManagerCreateStorageBufferService.d.ts +17 -0
- package/src/BufferManager/service/BufferManagerCreateStorageBufferService.js +23 -0
- package/src/BufferManager/service/BufferManagerReleaseUniformBufferService.d.ts +12 -0
- package/src/BufferManager/service/BufferManagerReleaseUniformBufferService.js +32 -0
- package/src/BufferManager/service/BufferManagerReleaseVertexBufferService.d.ts +12 -0
- package/src/BufferManager/service/BufferManagerReleaseVertexBufferService.js +32 -0
- package/src/BufferManager/service/BufferManagerUpdateIndirectBufferService.d.ts +12 -0
- package/src/BufferManager/service/BufferManagerUpdateIndirectBufferService.js +20 -0
- package/src/BufferManager/service/BufferManagerUpperPowerOfTwoService.d.ts +10 -0
- package/src/BufferManager/service/BufferManagerUpperPowerOfTwoService.js +18 -0
- package/src/BufferManager/usecase/BufferManagerAcquireStorageBufferUseCase.d.ts +15 -0
- package/src/BufferManager/usecase/BufferManagerAcquireStorageBufferUseCase.js +51 -0
- package/src/BufferManager/usecase/BufferManagerAcquireUniformBufferUseCase.d.ts +13 -0
- package/src/BufferManager/usecase/BufferManagerAcquireUniformBufferUseCase.js +26 -0
- package/src/BufferManager/usecase/BufferManagerAcquireVertexBufferUseCase.d.ts +14 -0
- package/src/BufferManager/usecase/BufferManagerAcquireVertexBufferUseCase.js +46 -0
- package/src/BufferManager/usecase/BufferManagerCleanupStorageBuffersUseCase.d.ts +12 -0
- package/src/BufferManager/usecase/BufferManagerCleanupStorageBuffersUseCase.js +20 -0
- package/src/BufferManager/usecase/BufferManagerReleaseStorageBufferUseCase.d.ts +9 -0
- package/src/BufferManager/usecase/BufferManagerReleaseStorageBufferUseCase.js +15 -0
- package/src/BufferManager.d.ts +93 -0
- package/src/BufferManager.js +487 -0
- package/src/Compute/ComputePipelineManager.d.ts +61 -0
- package/src/Compute/ComputePipelineManager.js +313 -0
- package/src/Compute/service/ComputeExecuteBlurService.d.ts +21 -0
- package/src/Compute/service/ComputeExecuteBlurService.js +81 -0
- package/src/Context/service/ContextComputeBitmapMatrixService.d.ts +1 -0
- package/src/Context/service/ContextComputeBitmapMatrixService.js +74 -0
- package/src/Context/service/ContextComputeGradientMatrixService.d.ts +4 -0
- package/src/Context/service/ContextComputeGradientMatrixService.js +88 -0
- package/src/Context/service/ContextFillSimpleService.d.ts +2 -0
- package/src/Context/service/ContextFillSimpleService.js +28 -0
- package/src/Context/service/ContextFillWithStencilMainService.d.ts +2 -0
- package/src/Context/service/ContextFillWithStencilMainService.js +19 -0
- package/src/Context/service/ContextFillWithStencilService.d.ts +2 -0
- package/src/Context/service/ContextFillWithStencilService.js +19 -0
- package/src/Context/usecase/ContextApplyFilterUseCase.d.ts +5 -0
- package/src/Context/usecase/ContextApplyFilterUseCase.js +668 -0
- package/src/Context/usecase/ContextBitmapFillUseCase.d.ts +4 -0
- package/src/Context/usecase/ContextBitmapFillUseCase.js +210 -0
- package/src/Context/usecase/ContextBitmapStrokeUseCase.d.ts +4 -0
- package/src/Context/usecase/ContextBitmapStrokeUseCase.js +119 -0
- package/src/Context/usecase/ContextClipUseCase.d.ts +5 -0
- package/src/Context/usecase/ContextClipUseCase.js +101 -0
- package/src/Context/usecase/ContextContainerEndLayerUseCase.d.ts +5 -0
- package/src/Context/usecase/ContextContainerEndLayerUseCase.js +476 -0
- package/src/Context/usecase/ContextDrawArraysInstancedUseCase.d.ts +6 -0
- package/src/Context/usecase/ContextDrawArraysInstancedUseCase.js +135 -0
- package/src/Context/usecase/ContextDrawIndirectUseCase.d.ts +6 -0
- package/src/Context/usecase/ContextDrawIndirectUseCase.js +154 -0
- package/src/Context/usecase/ContextGradientFillUseCase.d.ts +4 -0
- package/src/Context/usecase/ContextGradientFillUseCase.js +230 -0
- package/src/Context/usecase/ContextGradientStrokeUseCase.d.ts +4 -0
- package/src/Context/usecase/ContextGradientStrokeUseCase.js +138 -0
- package/src/Context/usecase/ContextProcessComplexBlendQueueUseCase.d.ts +6 -0
- package/src/Context/usecase/ContextProcessComplexBlendQueueUseCase.js +213 -0
- package/src/Context.d.ts +430 -0
- package/src/Context.js +2453 -0
- package/src/FillTexturePool.d.ts +6 -0
- package/src/FillTexturePool.js +72 -0
- package/src/Filter/BevelFilter/FilterApplyBevelFilterUseCase.d.ts +10 -0
- package/src/Filter/BevelFilter/FilterApplyBevelFilterUseCase.js +214 -0
- package/src/Filter/BevelFilterShader.d.ts +2 -0
- package/src/Filter/BevelFilterShader.js +107 -0
- package/src/Filter/BitmapFilterShader.d.ts +2 -0
- package/src/Filter/BitmapFilterShader.js +207 -0
- package/src/Filter/BlurFilter/FilterApplyBlurFilterUseCase.d.ts +16 -0
- package/src/Filter/BlurFilter/FilterApplyBlurFilterUseCase.js +243 -0
- package/src/Filter/BlurFilter/service/BlurFilterComputeShaderService.d.ts +40 -0
- package/src/Filter/BlurFilter/service/BlurFilterComputeShaderService.js +51 -0
- package/src/Filter/BlurFilter/usecase/FilterApplyBlurComputeUseCase.d.ts +25 -0
- package/src/Filter/BlurFilter/usecase/FilterApplyBlurComputeUseCase.js +180 -0
- package/src/Filter/BlurFilterShader.d.ts +5 -0
- package/src/Filter/BlurFilterShader.js +109 -0
- package/src/Filter/BlurFilterUseCase.d.ts +36 -0
- package/src/Filter/BlurFilterUseCase.js +85 -0
- package/src/Filter/ColorMatrixFilter/FilterApplyColorMatrixFilterUseCase.d.ts +12 -0
- package/src/Filter/ColorMatrixFilter/FilterApplyColorMatrixFilterUseCase.js +90 -0
- package/src/Filter/ColorMatrixFilterShader.d.ts +4 -0
- package/src/Filter/ColorMatrixFilterShader.js +51 -0
- package/src/Filter/ConvolutionFilter/FilterApplyConvolutionFilterUseCase.d.ts +6 -0
- package/src/Filter/ConvolutionFilter/FilterApplyConvolutionFilterUseCase.js +144 -0
- package/src/Filter/ConvolutionFilterShader.d.ts +2 -0
- package/src/Filter/ConvolutionFilterShader.js +115 -0
- package/src/Filter/DisplacementMapFilter/FilterApplyDisplacementMapFilterUseCase.d.ts +6 -0
- package/src/Filter/DisplacementMapFilter/FilterApplyDisplacementMapFilterUseCase.js +172 -0
- package/src/Filter/DisplacementMapFilterShader.d.ts +2 -0
- package/src/Filter/DisplacementMapFilterShader.js +114 -0
- package/src/Filter/DropShadowFilter/FilterApplyDropShadowFilterUseCase.d.ts +24 -0
- package/src/Filter/DropShadowFilter/FilterApplyDropShadowFilterUseCase.js +179 -0
- package/src/Filter/DropShadowFilterShader.d.ts +4 -0
- package/src/Filter/DropShadowFilterShader.js +93 -0
- package/src/Filter/FilterGradientLUTCache.d.ts +29 -0
- package/src/Filter/FilterGradientLUTCache.js +84 -0
- package/src/Filter/FilterOffset.d.ts +8 -0
- package/src/Filter/FilterOffset.js +10 -0
- package/src/Filter/GlowFilter/FilterApplyGlowFilterUseCase.d.ts +24 -0
- package/src/Filter/GlowFilter/FilterApplyGlowFilterUseCase.js +143 -0
- package/src/Filter/GlowFilterShader.d.ts +4 -0
- package/src/Filter/GlowFilterShader.js +66 -0
- package/src/Filter/GradientBevelFilter/FilterApplyGradientBevelFilterUseCase.d.ts +29 -0
- package/src/Filter/GradientBevelFilter/FilterApplyGradientBevelFilterUseCase.js +216 -0
- package/src/Filter/GradientGlowFilter/FilterApplyGradientGlowFilterUseCase.d.ts +29 -0
- package/src/Filter/GradientGlowFilter/FilterApplyGradientGlowFilterUseCase.js +164 -0
- package/src/FrameBufferManager/service/FrameBufferManagerCreateRenderPassDescriptorService.d.ts +4 -0
- package/src/FrameBufferManager/service/FrameBufferManagerCreateRenderPassDescriptorService.js +23 -0
- package/src/FrameBufferManager/service/FrameBufferManagerCreateStencilRenderPassDescriptorService.d.ts +4 -0
- package/src/FrameBufferManager/service/FrameBufferManagerCreateStencilRenderPassDescriptorService.js +28 -0
- package/src/FrameBufferManager/service/FrameBufferManagerFlushPendingReleasesService.d.ts +11 -0
- package/src/FrameBufferManager/service/FrameBufferManagerFlushPendingReleasesService.js +19 -0
- package/src/FrameBufferManager/usecase/FrameBufferManagerCreateAttachmentUseCase.d.ts +23 -0
- package/src/FrameBufferManager/usecase/FrameBufferManagerCreateAttachmentUseCase.js +125 -0
- package/src/FrameBufferManager/usecase/FrameBufferManagerReleaseTemporaryAttachmentUseCase.d.ts +14 -0
- package/src/FrameBufferManager/usecase/FrameBufferManagerReleaseTemporaryAttachmentUseCase.js +23 -0
- package/src/FrameBufferManager.d.ts +24 -0
- package/src/FrameBufferManager.js +161 -0
- package/src/Gradient/GradientLUTCache.d.ts +61 -0
- package/src/Gradient/GradientLUTCache.js +153 -0
- package/src/Gradient/GradientLUTGenerator.d.ts +30 -0
- package/src/Gradient/GradientLUTGenerator.js +202 -0
- package/src/Grid.d.ts +18 -0
- package/src/Grid.js +21 -0
- package/src/Mask/service/MaskBeginMaskService.d.ts +9 -0
- package/src/Mask/service/MaskBeginMaskService.js +22 -0
- package/src/Mask/service/MaskEndMaskService.d.ts +15 -0
- package/src/Mask/service/MaskEndMaskService.js +36 -0
- package/src/Mask/service/MaskSetMaskBoundsService.d.ts +13 -0
- package/src/Mask/service/MaskSetMaskBoundsService.js +36 -0
- package/src/Mask/service/MaskUnionMaskService.d.ts +4 -0
- package/src/Mask/service/MaskUnionMaskService.js +74 -0
- package/src/Mask/usecase/MaskBindUseCase.d.ts +10 -0
- package/src/Mask/usecase/MaskBindUseCase.js +20 -0
- package/src/Mask/usecase/MaskLeaveMaskUseCase.d.ts +13 -0
- package/src/Mask/usecase/MaskLeaveMaskUseCase.js +51 -0
- package/src/Mask.d.ts +12 -0
- package/src/Mask.js +41 -0
- package/src/Mesh/service/MeshFillGenerateService.d.ts +19 -0
- package/src/Mesh/service/MeshFillGenerateService.js +76 -0
- package/src/Mesh/service/MeshLerpService.d.ts +13 -0
- package/src/Mesh/service/MeshLerpService.js +17 -0
- package/src/Mesh/service/MeshStrokeFillGenerateService.d.ts +19 -0
- package/src/Mesh/service/MeshStrokeFillGenerateService.js +76 -0
- package/src/Mesh/usecase/MeshBitmapStrokeGenerateUseCase.d.ts +13 -0
- package/src/Mesh/usecase/MeshBitmapStrokeGenerateUseCase.js +65 -0
- package/src/Mesh/usecase/MeshFillGenerateUseCase.d.ts +12 -0
- package/src/Mesh/usecase/MeshFillGenerateUseCase.js +48 -0
- package/src/Mesh/usecase/MeshGradientStrokeGenerateUseCase.d.ts +13 -0
- package/src/Mesh/usecase/MeshGradientStrokeGenerateUseCase.js +65 -0
- package/src/Mesh/usecase/MeshSplitQuadraticBezierUseCase.d.ts +14 -0
- package/src/Mesh/usecase/MeshSplitQuadraticBezierUseCase.js +28 -0
- package/src/Mesh/usecase/MeshStrokeFillGenerateUseCase.d.ts +18 -0
- package/src/Mesh/usecase/MeshStrokeFillGenerateUseCase.js +54 -0
- package/src/Mesh/usecase/MeshStrokeGenerateUseCase.d.ts +25 -0
- package/src/Mesh/usecase/MeshStrokeGenerateUseCase.js +608 -0
- package/src/PathCommand.d.ts +123 -0
- package/src/PathCommand.js +317 -0
- package/src/SamplerCache/service/SamplerCacheCreateCommonSamplersService.d.ts +11 -0
- package/src/SamplerCache/service/SamplerCacheCreateCommonSamplersService.js +35 -0
- package/src/SamplerCache/service/SamplerCacheGenerateKeyService.d.ts +13 -0
- package/src/SamplerCache/service/SamplerCacheGenerateKeyService.js +15 -0
- package/src/SamplerCache/service/SamplerCacheGetOrCreateService.d.ts +15 -0
- package/src/SamplerCache/service/SamplerCacheGetOrCreateService.js +30 -0
- package/src/SamplerCache.d.ts +18 -0
- package/src/SamplerCache.js +61 -0
- package/src/Shader/BlendModeShader.d.ts +51 -0
- package/src/Shader/BlendModeShader.js +71 -0
- package/src/Shader/GradientLUTGenerator/service/GradientLUTCalculateResolutionService.d.ts +12 -0
- package/src/Shader/GradientLUTGenerator/service/GradientLUTCalculateResolutionService.js +28 -0
- package/src/Shader/GradientLUTGenerator/service/GradientLUTGeneratePixelsService.d.ts +13 -0
- package/src/Shader/GradientLUTGenerator/service/GradientLUTGeneratePixelsService.js +61 -0
- package/src/Shader/GradientLUTGenerator/service/GradientLUTInterpolateColorService.d.ts +19 -0
- package/src/Shader/GradientLUTGenerator/service/GradientLUTInterpolateColorService.js +37 -0
- package/src/Shader/GradientLUTGenerator/service/GradientLUTParseStopsService.d.ts +11 -0
- package/src/Shader/GradientLUTGenerator/service/GradientLUTParseStopsService.js +24 -0
- package/src/Shader/GradientLUTGenerator/usecase/GradientLUTGenerateDataUseCase.d.ts +14 -0
- package/src/Shader/GradientLUTGenerator/usecase/GradientLUTGenerateDataUseCase.js +24 -0
- package/src/Shader/PipelineManager.d.ts +57 -0
- package/src/Shader/PipelineManager.js +2868 -0
- package/src/Shader/ShaderInstancedManager.d.ts +8 -0
- package/src/Shader/ShaderInstancedManager.js +18 -0
- package/src/Shader/ShaderSource.d.ts +60 -0
- package/src/Shader/ShaderSource.js +518 -0
- package/src/Shader/wgsl/common/SharedWgsl.d.ts +5 -0
- package/src/Shader/wgsl/common/SharedWgsl.js +37 -0
- package/src/Shader/wgsl/fragment/BasicFragment.d.ts +2 -0
- package/src/Shader/wgsl/fragment/BasicFragment.js +28 -0
- package/src/Shader/wgsl/fragment/BitmapFragment.d.ts +1 -0
- package/src/Shader/wgsl/fragment/BitmapFragment.js +43 -0
- package/src/Shader/wgsl/fragment/BlendFragment.d.ts +8 -0
- package/src/Shader/wgsl/fragment/BlendFragment.js +63 -0
- package/src/Shader/wgsl/fragment/EffectFragment.d.ts +6 -0
- package/src/Shader/wgsl/fragment/EffectFragment.js +324 -0
- package/src/Shader/wgsl/fragment/FillFragment.d.ts +1 -0
- package/src/Shader/wgsl/fragment/FillFragment.js +28 -0
- package/src/Shader/wgsl/fragment/FilterFragment.d.ts +10 -0
- package/src/Shader/wgsl/fragment/FilterFragment.js +212 -0
- package/src/Shader/wgsl/fragment/GradientFragment.d.ts +3 -0
- package/src/Shader/wgsl/fragment/GradientFragment.js +118 -0
- package/src/Shader/wgsl/fragment/InstancedFragment.d.ts +1 -0
- package/src/Shader/wgsl/fragment/InstancedFragment.js +20 -0
- package/src/Shader/wgsl/fragment/MaskFragment.d.ts +1 -0
- package/src/Shader/wgsl/fragment/MaskFragment.js +17 -0
- package/src/Shader/wgsl/fragment/StencilFragment.d.ts +2 -0
- package/src/Shader/wgsl/fragment/StencilFragment.js +33 -0
- package/src/Shader/wgsl/vertex/BasicVertex.d.ts +1 -0
- package/src/Shader/wgsl/vertex/BasicVertex.js +37 -0
- package/src/Shader/wgsl/vertex/BitmapVertex.d.ts +1 -0
- package/src/Shader/wgsl/vertex/BitmapVertex.js +43 -0
- package/src/Shader/wgsl/vertex/FillVertex.d.ts +1 -0
- package/src/Shader/wgsl/vertex/FillVertex.js +35 -0
- package/src/Shader/wgsl/vertex/FilterVertex.d.ts +12 -0
- package/src/Shader/wgsl/vertex/FilterVertex.js +193 -0
- package/src/Shader/wgsl/vertex/GradientVertex.d.ts +1 -0
- package/src/Shader/wgsl/vertex/GradientVertex.js +44 -0
- package/src/Shader/wgsl/vertex/InstancedVertex.d.ts +1 -0
- package/src/Shader/wgsl/vertex/InstancedVertex.js +48 -0
- package/src/Shader/wgsl/vertex/MaskVertex.d.ts +1 -0
- package/src/Shader/wgsl/vertex/MaskVertex.js +36 -0
- package/src/Shader/wgsl/vertex/StencilVertex.d.ts +2 -0
- package/src/Shader/wgsl/vertex/StencilVertex.js +66 -0
- package/src/TextureManager/service/TextureManagerInitializeSamplersService.d.ts +11 -0
- package/src/TextureManager/service/TextureManagerInitializeSamplersService.js +48 -0
- package/src/TextureManager/usecase/TextureManagerCreateTextureFromImageBitmapUseCase.d.ts +13 -0
- package/src/TextureManager/usecase/TextureManagerCreateTextureFromImageBitmapUseCase.js +30 -0
- package/src/TextureManager/usecase/TextureManagerCreateTextureFromPixelsUseCase.d.ts +15 -0
- package/src/TextureManager/usecase/TextureManagerCreateTextureFromPixelsUseCase.js +26 -0
- package/src/TextureManager.d.ts +15 -0
- package/src/TextureManager.js +87 -0
- package/src/TexturePool/service/TexturePoolCleanupService.d.ts +14 -0
- package/src/TexturePool/service/TexturePoolCleanupService.js +28 -0
- package/src/TexturePool/service/TexturePoolEvictOldestService.d.ts +11 -0
- package/src/TexturePool/service/TexturePoolEvictOldestService.js +24 -0
- package/src/TexturePool/service/TexturePoolReleaseService.d.ts +13 -0
- package/src/TexturePool/service/TexturePoolReleaseService.js +22 -0
- package/src/TexturePool/usecase/TexturePoolAcquireUseCase.d.ts +19 -0
- package/src/TexturePool/usecase/TexturePoolAcquireUseCase.js +90 -0
- package/src/TexturePool.d.ts +69 -0
- package/src/TexturePool.js +151 -0
- package/src/WebGPUUtil.d.ts +102 -0
- package/src/WebGPUUtil.js +157 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/interface/IAttachmentObject.d.ts +41 -0
- package/src/interface/IAttachmentObject.js +1 -0
- package/src/interface/IBlendMode.d.ts +1 -0
- package/src/interface/IBlendMode.js +1 -0
- package/src/interface/IBlendState.d.ts +8 -0
- package/src/interface/IBlendState.js +1 -0
- package/src/interface/IBounds.d.ts +6 -0
- package/src/interface/IBounds.js +1 -0
- package/src/interface/ICachedBindGroup.d.ts +8 -0
- package/src/interface/ICachedBindGroup.js +1 -0
- package/src/interface/IColorBufferObject.d.ts +17 -0
- package/src/interface/IColorBufferObject.js +1 -0
- package/src/interface/IComplexBlendItem.d.ts +19 -0
- package/src/interface/IComplexBlendItem.js +1 -0
- package/src/interface/IFilterConfig.d.ts +29 -0
- package/src/interface/IFilterConfig.js +1 -0
- package/src/interface/IGradientLUTData.d.ts +8 -0
- package/src/interface/IGradientLUTData.js +1 -0
- package/src/interface/IGradientStop.d.ts +11 -0
- package/src/interface/IGradientStop.js +1 -0
- package/src/interface/ILocalFilterConfig.d.ts +21 -0
- package/src/interface/ILocalFilterConfig.js +1 -0
- package/src/interface/IMeshResult.d.ts +8 -0
- package/src/interface/IMeshResult.js +1 -0
- package/src/interface/IPath.d.ts +8 -0
- package/src/interface/IPath.js +1 -0
- package/src/interface/IPoint.d.ts +4 -0
- package/src/interface/IPoint.js +1 -0
- package/src/interface/IPooledBuffer.d.ts +8 -0
- package/src/interface/IPooledBuffer.js +1 -0
- package/src/interface/IPooledTexture.d.ts +17 -0
- package/src/interface/IPooledTexture.js +1 -0
- package/src/interface/IQuadraticSegment.d.ts +9 -0
- package/src/interface/IQuadraticSegment.js +1 -0
- package/src/interface/IRectangleInfo.d.ts +13 -0
- package/src/interface/IRectangleInfo.js +1 -0
- package/src/interface/IStencilBufferObject.d.ts +16 -0
- package/src/interface/IStencilBufferObject.js +1 -0
- package/src/interface/IStorageBufferConfig.d.ts +40 -0
- package/src/interface/IStorageBufferConfig.js +1 -0
- package/src/interface/ITextureObject.d.ts +16 -0
- 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
|
+
}
|