ComputePassEncoder.cpp (5689B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "ComputePassEncoder.h" 7 8 #include "BindGroup.h" 9 #include "CommandEncoder.h" 10 #include "ComputePipeline.h" 11 #include "ExternalTexture.h" 12 #include "Utility.h" 13 #include "mozilla/dom/WebGPUBinding.h" 14 #include "mozilla/webgpu/ffi/wgpu.h" 15 16 namespace mozilla::webgpu { 17 18 GPU_IMPL_CYCLE_COLLECTION(ComputePassEncoder, mParent, mUsedBindGroups, 19 mUsedBuffers, mUsedPipelines) 20 GPU_IMPL_JS_WRAP(ComputePassEncoder) 21 22 void ffiWGPUComputePassDeleter::operator()(ffi::WGPURecordedComputePass* raw) { 23 if (raw) { 24 ffi::wgpu_compute_pass_destroy(raw); 25 } 26 } 27 28 ffi::WGPURecordedComputePass* BeginComputePass( 29 RawId aEncoderId, const dom::GPUComputePassDescriptor& aDesc) { 30 MOZ_RELEASE_ASSERT(aEncoderId); 31 ffi::WGPUComputePassDescriptor desc = {}; 32 33 webgpu::StringHelper label(aDesc.mLabel); 34 desc.label = label.Get(); 35 36 ffi::WGPUPassTimestampWrites passTimestampWrites = {}; 37 if (aDesc.mTimestampWrites.WasPassed()) { 38 AssignPassTimestampWrites(aDesc.mTimestampWrites.Value(), 39 passTimestampWrites); 40 desc.timestamp_writes = &passTimestampWrites; 41 } 42 43 return ffi::wgpu_command_encoder_begin_compute_pass(&desc); 44 } 45 46 ComputePassEncoder::ComputePassEncoder( 47 CommandEncoder* const aParent, RawId aId, 48 const dom::GPUComputePassDescriptor& aDesc) 49 : ObjectBase(aParent->GetChild(), aId, 50 ffi::wgpu_client_drop_compute_pass_encoder), 51 ChildOf(aParent), 52 mPass(BeginComputePass(aParent->GetId(), aDesc)) {} 53 54 ComputePassEncoder::~ComputePassEncoder() = default; 55 56 void ComputePassEncoder::SetBindGroup(uint32_t aSlot, 57 BindGroup* const aBindGroup, 58 const uint32_t* aDynamicOffsets, 59 size_t aDynamicOffsetsLength) { 60 RawId bindGroup = 0; 61 if (aBindGroup) { 62 mUsedBindGroups.AppendElement(aBindGroup); 63 mUsedCanvasContexts.AppendElements(aBindGroup->GetCanvasContexts()); 64 bindGroup = aBindGroup->GetId(); 65 } 66 ffi::wgpu_recorded_compute_pass_set_bind_group( 67 mPass.get(), aSlot, bindGroup, {aDynamicOffsets, aDynamicOffsetsLength}); 68 } 69 70 void ComputePassEncoder::SetBindGroup( 71 uint32_t aSlot, BindGroup* const aBindGroup, 72 const dom::Sequence<uint32_t>& aDynamicOffsets, ErrorResult& aRv) { 73 if (!mValid) { 74 return; 75 } 76 this->SetBindGroup(aSlot, aBindGroup, aDynamicOffsets.Elements(), 77 aDynamicOffsets.Length()); 78 } 79 80 void ComputePassEncoder::SetBindGroup( 81 uint32_t aSlot, BindGroup* const aBindGroup, 82 const dom::Uint32Array& aDynamicOffsetsData, 83 uint64_t aDynamicOffsetsDataStart, uint64_t aDynamicOffsetsDataLength, 84 ErrorResult& aRv) { 85 if (!mValid) { 86 return; 87 } 88 89 auto dynamicOffsets = 90 GetDynamicOffsetsFromArray(aDynamicOffsetsData, aDynamicOffsetsDataStart, 91 aDynamicOffsetsDataLength, aRv); 92 93 if (dynamicOffsets.isSome()) { 94 this->SetBindGroup(aSlot, aBindGroup, dynamicOffsets->Elements(), 95 dynamicOffsets->Length()); 96 } 97 } 98 99 void ComputePassEncoder::SetPipeline(const ComputePipeline& aPipeline) { 100 if (!mValid) { 101 return; 102 } 103 mUsedPipelines.AppendElement(&aPipeline); 104 ffi::wgpu_recorded_compute_pass_set_pipeline(mPass.get(), aPipeline.GetId()); 105 } 106 107 void ComputePassEncoder::DispatchWorkgroups(uint32_t workgroupCountX, 108 uint32_t workgroupCountY, 109 uint32_t workgroupCountZ) { 110 if (!mValid) { 111 return; 112 } 113 ffi::wgpu_recorded_compute_pass_dispatch_workgroups( 114 mPass.get(), workgroupCountX, workgroupCountY, workgroupCountZ); 115 } 116 117 void ComputePassEncoder::DispatchWorkgroupsIndirect( 118 const Buffer& aIndirectBuffer, uint64_t aIndirectOffset) { 119 if (!mValid) { 120 return; 121 } 122 mUsedBuffers.AppendElement(&aIndirectBuffer); 123 ffi::wgpu_recorded_compute_pass_dispatch_workgroups_indirect( 124 mPass.get(), aIndirectBuffer.GetId(), aIndirectOffset); 125 } 126 127 void ComputePassEncoder::PushDebugGroup(const nsAString& aString) { 128 if (!mValid) { 129 return; 130 } 131 const NS_ConvertUTF16toUTF8 utf8(aString); 132 ffi::wgpu_recorded_compute_pass_push_debug_group(mPass.get(), utf8.get(), 0); 133 } 134 void ComputePassEncoder::PopDebugGroup() { 135 if (!mValid) { 136 return; 137 } 138 ffi::wgpu_recorded_compute_pass_pop_debug_group(mPass.get()); 139 } 140 void ComputePassEncoder::InsertDebugMarker(const nsAString& aString) { 141 if (!mValid) { 142 return; 143 } 144 const NS_ConvertUTF16toUTF8 utf8(aString); 145 ffi::wgpu_recorded_compute_pass_insert_debug_marker(mPass.get(), utf8.get(), 146 0); 147 } 148 149 void ComputePassEncoder::End() { 150 if (mParent->GetState() != CommandEncoderState::Locked) { 151 const auto* message = "Encoding must not have ended"; 152 ffi::wgpu_report_validation_error(GetClient(), 153 mParent->GetDevice()->GetId(), message); 154 } 155 if (!mValid) { 156 return; 157 } 158 nsTArray<RefPtr<ExternalTexture>> externalTextures; 159 for (const auto& bindGroup : mUsedBindGroups) { 160 externalTextures.AppendElements(bindGroup->GetExternalTextures()); 161 } 162 MOZ_ASSERT(!!mPass); 163 mParent->EndComputePass(*mPass, mUsedCanvasContexts, externalTextures); 164 165 mValid = false; 166 mPass.release(); 167 mUsedBindGroups.Clear(); 168 mUsedBuffers.Clear(); 169 mUsedPipelines.Clear(); 170 } 171 172 } // namespace mozilla::webgpu