RenderBundleEncoder.cpp (8385B)
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 "RenderBundleEncoder.h" 7 8 #include "BindGroup.h" 9 #include "Buffer.h" 10 #include "RenderBundle.h" 11 #include "RenderPipeline.h" 12 #include "Utility.h" 13 #include "ipc/WebGPUChild.h" 14 #include "mozilla/dom/WebGPUBinding.h" 15 #include "mozilla/webgpu/ffi/wgpu.h" 16 17 namespace mozilla::webgpu { 18 19 GPU_IMPL_CYCLE_COLLECTION(RenderBundleEncoder, mParent, mUsedBindGroups, 20 mUsedBuffers, mUsedPipelines) 21 GPU_IMPL_JS_WRAP(RenderBundleEncoder) 22 23 void ffiWGPURenderBundleEncoderDeleter::operator()( 24 ffi::WGPURenderBundleEncoder* raw) { 25 if (raw) { 26 ffi::wgpu_render_bundle_encoder_destroy(raw); 27 } 28 } 29 30 ffi::WGPURenderBundleEncoder* CreateRenderBundleEncoder( 31 RawId aDeviceId, const dom::GPURenderBundleEncoderDescriptor& aDesc, 32 WebGPUChild* const aChild) { 33 ffi::WGPURenderBundleEncoderDescriptor desc = {}; 34 desc.sample_count = aDesc.mSampleCount; 35 36 webgpu::StringHelper label(aDesc.mLabel); 37 desc.label = label.Get(); 38 39 ffi::WGPUTextureFormat depthStencilFormat = {ffi::WGPUTextureFormat_Sentinel}; 40 if (aDesc.mDepthStencilFormat.WasPassed()) { 41 depthStencilFormat = 42 ConvertTextureFormat(aDesc.mDepthStencilFormat.Value()); 43 desc.depth_stencil_format = &depthStencilFormat; 44 } 45 46 std::vector<ffi::WGPUTextureFormat> colorFormats = {}; 47 for (const auto i : IntegerRange(aDesc.mColorFormats.Length())) { 48 ffi::WGPUTextureFormat format = {ffi::WGPUTextureFormat_Sentinel}; 49 format = ConvertTextureFormat(aDesc.mColorFormats[i]); 50 colorFormats.push_back(format); 51 } 52 53 desc.color_formats = {colorFormats.data(), colorFormats.size()}; 54 55 auto* bundle = ffi::wgpu_device_create_render_bundle_encoder( 56 aChild->GetClient(), aDeviceId, &desc); 57 58 return bundle; 59 } 60 61 RenderBundleEncoder::RenderBundleEncoder( 62 Device* const aParent, RawId aId, 63 const dom::GPURenderBundleEncoderDescriptor& aDesc) 64 : ObjectBase(aParent->GetChild(), aId, 65 ffi::wgpu_client_drop_render_bundle_encoder), 66 ChildOf(aParent), 67 mEncoder(CreateRenderBundleEncoder(aParent->GetId(), aDesc, 68 aParent->GetChild())) { 69 mValid = !!mEncoder; 70 } 71 72 RenderBundleEncoder::~RenderBundleEncoder() = default; 73 74 void RenderBundleEncoder::SetBindGroup(uint32_t aSlot, 75 BindGroup* const aBindGroup, 76 const uint32_t* aDynamicOffsets, 77 size_t aDynamicOffsetsLength) { 78 RawId bindGroup = 0; 79 if (aBindGroup) { 80 mUsedBindGroups.AppendElement(aBindGroup); 81 mUsedCanvasContexts.AppendElements(aBindGroup->GetCanvasContexts()); 82 bindGroup = aBindGroup->GetId(); 83 } 84 ffi::wgpu_render_bundle_set_bind_group( 85 mEncoder.get(), aSlot, bindGroup, aDynamicOffsets, aDynamicOffsetsLength); 86 } 87 88 void RenderBundleEncoder::SetBindGroup( 89 uint32_t aSlot, BindGroup* const aBindGroup, 90 const dom::Sequence<uint32_t>& aDynamicOffsets, ErrorResult& aRv) { 91 if (!mValid) { 92 return; 93 } 94 this->SetBindGroup(aSlot, aBindGroup, aDynamicOffsets.Elements(), 95 aDynamicOffsets.Length()); 96 } 97 98 void RenderBundleEncoder::SetBindGroup( 99 uint32_t aSlot, BindGroup* const aBindGroup, 100 const dom::Uint32Array& aDynamicOffsetsData, 101 uint64_t aDynamicOffsetsDataStart, uint64_t aDynamicOffsetsDataLength, 102 ErrorResult& aRv) { 103 if (!mValid) { 104 return; 105 } 106 107 auto dynamicOffsets = 108 GetDynamicOffsetsFromArray(aDynamicOffsetsData, aDynamicOffsetsDataStart, 109 aDynamicOffsetsDataLength, aRv); 110 111 if (dynamicOffsets.isSome()) { 112 this->SetBindGroup(aSlot, aBindGroup, dynamicOffsets->Elements(), 113 dynamicOffsets->Length()); 114 } 115 } 116 117 void RenderBundleEncoder::SetPipeline(const RenderPipeline& aPipeline) { 118 if (!mValid) { 119 return; 120 } 121 mUsedPipelines.AppendElement(&aPipeline); 122 ffi::wgpu_render_bundle_set_pipeline(mEncoder.get(), aPipeline.GetId()); 123 } 124 125 void RenderBundleEncoder::SetIndexBuffer( 126 const Buffer& aBuffer, const dom::GPUIndexFormat& aIndexFormat, 127 uint64_t aOffset, const dom::Optional<uint64_t>& aSize) { 128 if (!mValid) { 129 return; 130 } 131 mUsedBuffers.AppendElement(&aBuffer); 132 const auto iformat = aIndexFormat == dom::GPUIndexFormat::Uint32 133 ? ffi::WGPUIndexFormat_Uint32 134 : ffi::WGPUIndexFormat_Uint16; 135 const uint64_t* sizeRef = aSize.WasPassed() ? &aSize.Value() : nullptr; 136 ffi::wgpu_render_bundle_set_index_buffer(mEncoder.get(), aBuffer.GetId(), 137 iformat, aOffset, sizeRef); 138 } 139 140 void RenderBundleEncoder::SetVertexBuffer( 141 uint32_t aSlot, const Buffer& aBuffer, uint64_t aOffset, 142 const dom::Optional<uint64_t>& aSize) { 143 if (!mValid) { 144 return; 145 } 146 mUsedBuffers.AppendElement(&aBuffer); 147 const uint64_t* sizeRef = aSize.WasPassed() ? &aSize.Value() : nullptr; 148 ffi::wgpu_render_bundle_set_vertex_buffer(mEncoder.get(), aSlot, 149 aBuffer.GetId(), aOffset, sizeRef); 150 } 151 152 void RenderBundleEncoder::Draw(uint32_t aVertexCount, uint32_t aInstanceCount, 153 uint32_t aFirstVertex, uint32_t aFirstInstance) { 154 if (!mValid) { 155 return; 156 } 157 ffi::wgpu_render_bundle_draw(mEncoder.get(), aVertexCount, aInstanceCount, 158 aFirstVertex, aFirstInstance); 159 } 160 161 void RenderBundleEncoder::DrawIndexed(uint32_t aIndexCount, 162 uint32_t aInstanceCount, 163 uint32_t aFirstIndex, int32_t aBaseVertex, 164 uint32_t aFirstInstance) { 165 if (!mValid) { 166 return; 167 } 168 ffi::wgpu_render_bundle_draw_indexed(mEncoder.get(), aIndexCount, 169 aInstanceCount, aFirstIndex, aBaseVertex, 170 aFirstInstance); 171 } 172 173 void RenderBundleEncoder::DrawIndirect(const Buffer& aIndirectBuffer, 174 uint64_t aIndirectOffset) { 175 if (!mValid) { 176 return; 177 } 178 mUsedBuffers.AppendElement(&aIndirectBuffer); 179 ffi::wgpu_render_bundle_draw_indirect(mEncoder.get(), aIndirectBuffer.GetId(), 180 aIndirectOffset); 181 } 182 183 void RenderBundleEncoder::DrawIndexedIndirect(const Buffer& aIndirectBuffer, 184 uint64_t aIndirectOffset) { 185 if (!mValid) { 186 return; 187 } 188 mUsedBuffers.AppendElement(&aIndirectBuffer); 189 ffi::wgpu_render_bundle_draw_indexed_indirect( 190 mEncoder.get(), aIndirectBuffer.GetId(), aIndirectOffset); 191 } 192 193 void RenderBundleEncoder::PushDebugGroup(const nsAString& aString) { 194 if (!mValid) { 195 return; 196 } 197 const NS_ConvertUTF16toUTF8 utf8(aString); 198 ffi::wgpu_render_bundle_push_debug_group(mEncoder.get(), utf8.get()); 199 } 200 void RenderBundleEncoder::PopDebugGroup() { 201 if (!mValid) { 202 return; 203 } 204 ffi::wgpu_render_bundle_pop_debug_group(mEncoder.get()); 205 } 206 void RenderBundleEncoder::InsertDebugMarker(const nsAString& aString) { 207 if (!mValid) { 208 return; 209 } 210 const NS_ConvertUTF16toUTF8 utf8(aString); 211 ffi::wgpu_render_bundle_insert_debug_marker(mEncoder.get(), utf8.get()); 212 } 213 214 already_AddRefed<RenderBundle> RenderBundleEncoder::Finish( 215 const dom::GPURenderBundleDescriptor& aDesc) { 216 RawId deviceId = mParent->GetId(); 217 218 ffi::WGPURenderBundleDescriptor desc = {}; 219 webgpu::StringHelper label(aDesc.mLabel); 220 desc.label = label.Get(); 221 222 RawId id; 223 if (mValid) { 224 id = ffi::wgpu_client_create_render_bundle(GetClient(), deviceId, 225 mEncoder.get(), &desc); 226 227 } else { 228 id = ffi::wgpu_client_create_render_bundle_error(GetClient(), deviceId, 229 label.Get()); 230 } 231 232 mValid = false; 233 mEncoder.release(); 234 mUsedBindGroups.Clear(); 235 mUsedBuffers.Clear(); 236 mUsedPipelines.Clear(); 237 238 auto canvasContexts = mUsedCanvasContexts.Clone(); 239 RefPtr<RenderBundle> bundle = 240 new RenderBundle(mParent, id, std::move(canvasContexts)); 241 return bundle.forget(); 242 } 243 244 } // namespace mozilla::webgpu