| // Copyright 2025 The Dawn & Tint Authors | |
| // | |
| // Redistribution and use in source and binary forms, with or without | |
| // modification, are permitted provided that the following conditions are met: | |
| // | |
| // 1. Redistributions of source code must retain the above copyright notice, this | |
| // list of conditions and the following disclaimer. | |
| // | |
| // 2. Redistributions in binary form must reproduce the above copyright notice, | |
| // this list of conditions and the following disclaimer in the documentation | |
| // and/or other materials provided with the distribution. | |
| // | |
| // 3. Neither the name of the copyright holder nor the names of its | |
| // contributors may be used to endorse or promote products derived from | |
| // this software without specific prior written permission. | |
| // | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| #include "src/dawn/native/webgpu/DeviceWGPU.h" | |
| #include <string> | |
| #include <utility> | |
| #include "src/dawn/common/Constants.h" | |
| #include "src/dawn/common/StringViewUtils.h" | |
| #include "src/dawn/native/BackendConnection.h" | |
| #include "src/dawn/native/BindGroupLayoutInternal.h" | |
| #include "src/dawn/native/Buffer.h" | |
| #include "src/dawn/native/ChainUtils.h" | |
| #include "src/dawn/native/CommandBuffer.h" | |
| #include "src/dawn/native/CommandEncoder.h" | |
| #include "src/dawn/native/ErrorData.h" | |
| #include "src/dawn/native/Instance.h" | |
| #include "src/dawn/native/PhysicalDevice.h" | |
| #include "src/dawn/native/QuerySet.h" | |
| #include "src/dawn/native/Queue.h" | |
| #include "src/dawn/native/Surface.h" | |
| #include "src/dawn/native/SwapChain.h" | |
| #include "src/dawn/native/Texture.h" | |
| #include "src/dawn/native/webgpu/BackendWGPU.h" | |
| #include "src/dawn/native/webgpu/BindGroupLayoutWGPU.h" | |
| #include "src/dawn/native/webgpu/BindGroupWGPU.h" | |
| #include "src/dawn/native/webgpu/BufferWGPU.h" | |
| #include "src/dawn/native/webgpu/CaptureContext.h" | |
| #include "src/dawn/native/webgpu/CommandBufferWGPU.h" | |
| #include "src/dawn/native/webgpu/ComputePipelineWGPU.h" | |
| #include "src/dawn/native/webgpu/ExternalTextureWGPU.h" | |
| #include "src/dawn/native/webgpu/PhysicalDeviceWGPU.h" | |
| #include "src/dawn/native/webgpu/PipelineLayoutWGPU.h" | |
| #include "src/dawn/native/webgpu/QuerySetWGPU.h" | |
| #include "src/dawn/native/webgpu/QueueWGPU.h" | |
| #include "src/dawn/native/webgpu/RenderBundleWGPU.h" | |
| #include "src/dawn/native/webgpu/RenderPipelineWGPU.h" | |
| #include "src/dawn/native/webgpu/SamplerWGPU.h" | |
| #include "src/dawn/native/webgpu/ShaderModuleWGPU.h" | |
| #include "src/dawn/native/webgpu/SharedFenceWGPU.h" | |
| #include "src/dawn/native/webgpu/SharedTextureMemoryWGPU.h" | |
| #include "src/dawn/native/webgpu/SwapChainWGPU.h" | |
| #include "src/dawn/native/webgpu/TextureWGPU.h" | |
| #include "src/dawn/native/webgpu/ToWGPU.h" | |
| #include "src/utils/log.h" | |
| #include "tint/tint.h" | |
| namespace dawn::native::webgpu { | |
| namespace { | |
| // Toggles in this list are the only ones with ToggleStage::Device that enabled in webgpu::Device. | |
| // Other toggles are only passed down to the inner device. | |
| constexpr Toggle kOuterToggles[] = { | |
| // Toggles webgpu::Device needs | |
| Toggle::SkipValidation, | |
| Toggle::DisableBaseVertex, | |
| Toggle::DisableBindGroupLayoutEntryArraySize, | |
| Toggle::EnableImmediateErrorHandling, | |
| Toggle::EnableTintIRValidationAsserts, | |
| // Toggles enabled by default for all backend, do not force set them to avoid warnings. | |
| Toggle::LazyClearResourceOnFirstUse, | |
| Toggle::TimestampQuantization, | |
| Toggle::BlobCacheHashValidation, | |
| Toggle::UseUserDefinedLabelsInBackend, | |
| }; | |
| } // namespace | |
| // static | |
| ResultOrError<Ref<Device>> Device::Create(AdapterBase* adapter, | |
| WGPUAdapter innerAdapter, | |
| const UnpackedPtr<DeviceDescriptor>& descriptor, | |
| const TogglesState& deviceToggles, | |
| Ref<DeviceBase::DeviceLostEvent>&& lostEvent) { | |
| TogglesState outerDeviceToggles = deviceToggles; | |
| // For the inner device, we want to enable the toggles if they are enabled in deviceToggles. | |
| // TogglesState deviceToggles already has them resolved. | |
| // For outer (this webgpu::Device), we want to disable everything else. | |
| for (size_t i : deviceToggles.GetEnabledToggles()) { | |
| Toggle t = static_cast<Toggle>(i); | |
| const ToggleInfo* info = TogglesInfo::GetToggleInfo(t); | |
| if (info->stage != ToggleStage::Device) { | |
| // Bypass any force settings if not a device stage toggle. | |
| continue; | |
| } | |
| bool isOuter = false; | |
| for (Toggle outer : kOuterToggles) { | |
| if (t == outer) { | |
| isOuter = true; | |
| break; | |
| } | |
| } | |
| if (!isOuter) { | |
| outerDeviceToggles.ForceSet(t, false); | |
| } | |
| } | |
| Ref<Device> device = | |
| AcquireRef(new Device(adapter, innerAdapter, descriptor, outerDeviceToggles, deviceToggles, | |
| std::move(lostEvent))); | |
| DAWN_TRY(device->Initialize(descriptor)); | |
| return device; | |
| } | |
| Device::Device(AdapterBase* adapter, | |
| WGPUAdapter innerAdapter, | |
| const UnpackedPtr<DeviceDescriptor>& descriptor, | |
| const TogglesState& deviceToggles, | |
| const TogglesState& innerDeviceToggles, | |
| Ref<DeviceBase::DeviceLostEvent>&& lostEvent) | |
| : DeviceBase(adapter, descriptor, deviceToggles, std::move(lostEvent)), | |
| ObjectWGPU(ToBackend(adapter->GetPhysicalDevice())->GetFunctions().deviceRelease), | |
| wgpu(ToBackend(adapter->GetPhysicalDevice())->GetFunctions()) { | |
| DAWN_ASSERT(adapter->GetPhysicalDevice()->GetBackendType() == wgpu::BackendType::WebGPU); | |
| WGPUDeviceDescriptor apiDesc = *(ToAPI(*descriptor)); | |
| std::string label = "Inner Device on " + adapter->GetPhysicalDevice()->GetName(); | |
| apiDesc.label = ToOutputStringView(label); | |
| WGPUDawnTogglesDescriptor apiToggleDescriptor = WGPU_DAWN_TOGGLES_DESCRIPTOR_INIT; | |
| apiDesc.nextInChain = nullptr; | |
| auto enabledTogglesName = innerDeviceToggles.GetEnabledToggleNames(); | |
| // enable so we can capture the depth aspect of depth24plus and depth24plusStencil8 | |
| enabledTogglesName.push_back("use_blit_for_depth24plus_texture_to_buffer_copy"); | |
| apiToggleDescriptor.enabledToggleCount = enabledTogglesName.size(); | |
| apiToggleDescriptor.enabledToggles = enabledTogglesName.data(); | |
| auto disabledTogglesName = innerDeviceToggles.GetDisabledToggleNames(); | |
| apiToggleDescriptor.disabledToggleCount = disabledTogglesName.size(); | |
| apiToggleDescriptor.disabledToggles = disabledTogglesName.data(); | |
| apiDesc.nextInChain = &apiToggleDescriptor.chain; | |
| // Acquire a Ref to the outer webgpu::Device to avoid possible dangling pointer in the callback. | |
| Ref<Device>* outerDeviceRef = new Ref<Device>(this); | |
| apiDesc.deviceLostCallbackInfo = { | |
| nullptr, WGPUCallbackMode_AllowProcessEvents, | |
| [](WGPUDevice const*, WGPUDeviceLostReason reason, WGPUStringView message, void*, | |
| void* outerDeviceRef) { | |
| Ref<Device>* deviceWGPURef = reinterpret_cast<Ref<Device>*>(outerDeviceRef); | |
| Device* deviceWGPU = deviceWGPURef->Get(); | |
| if (reason == WGPUDeviceLostReason_Unknown) { | |
| // Internal crash of the implementation device, call device lost callback of the | |
| // upper DeviceWGPU | |
| if (!deviceWGPU->IsLost()) { | |
| deviceWGPU->APIForceLoss(FromAPI(reason), message); | |
| } | |
| } | |
| delete deviceWGPURef; | |
| }, | |
| nullptr, reinterpret_cast<void*>(outerDeviceRef)}; | |
| // TODO(crbug.com/413053623): revisit for error scope. | |
| apiDesc.uncapturedErrorCallbackInfo = { | |
| nullptr, | |
| [](WGPUDevice const*, WGPUErrorType errorType, WGPUStringView message, void*, | |
| void* outerDeviceRef) { | |
| Ref<Device>* deviceWGPURef = reinterpret_cast<Ref<Device>*>(outerDeviceRef); | |
| Device* deviceWGPU = deviceWGPURef->Get(); | |
| if (!deviceWGPU || deviceWGPU->IsLost()) { | |
| return; | |
| } | |
| deviceWGPU->EmitLog(wgpu::LoggingType::Error, ToString(message)); | |
| }, | |
| nullptr, reinterpret_cast<void*>(outerDeviceRef)}; | |
| // TODO(crbug.com/413053623): use adapterRequestDevice instead as dawn_wire doesn't support | |
| // adapterCreateDevice. | |
| mInnerHandle = wgpu->adapterCreateDevice(innerAdapter, &apiDesc); | |
| } | |
| Device::~Device() { | |
| Destroy(DestroyReason::CppDestructor); | |
| } | |
| WGPUInstance Device::GetInnerInstance() const { | |
| return ToBackend(GetPhysicalDevice())->GetBackend()->GetInnerInstance(); | |
| } | |
| MaybeError Device::Initialize(const UnpackedPtr<DeviceDescriptor>& descriptor) { | |
| Ref<Queue> queue; | |
| DAWN_TRY_ASSIGN(queue, Queue::Create(this, &descriptor->defaultQueue)); | |
| return DeviceBase::Initialize(descriptor, std::move(queue)); | |
| } | |
| ResultOrError<Ref<BindGroupBase>> Device::CreateBindGroupImpl( | |
| const UnpackedPtr<BindGroupDescriptor>& descriptor) { | |
| return BindGroup::Create(this, descriptor); | |
| } | |
| ResultOrError<Ref<BindGroupLayoutInternalBase>> Device::CreateBindGroupLayoutImpl( | |
| const UnpackedPtr<BindGroupLayoutDescriptor>& descriptor) { | |
| return BindGroupLayout::Create(this, descriptor); | |
| } | |
| ResultOrError<Ref<BufferBase>> Device::CreateBufferImpl( | |
| const UnpackedPtr<BufferDescriptor>& descriptor) { | |
| return Buffer::Create(this, descriptor); | |
| } | |
| ResultOrError<Ref<ExternalTextureBase>> Device::CreateExternalTextureImpl( | |
| const ExternalTextureDescriptor* descriptor) { | |
| return ExternalTexture::Create(this, descriptor); | |
| } | |
| ResultOrError<Ref<CommandBufferBase>> Device::CreateCommandBuffer( | |
| CommandEncoder* encoder, | |
| const CommandBufferDescriptor* descriptor) { | |
| // This is called by CommandEncoder::Finish | |
| // TODO(crbug.com/413053623): Store CommandEncoderDescriptor and assign here. | |
| return CommandBuffer::Create(encoder, descriptor); | |
| } | |
| ResultOrError<Ref<RenderBundleBase>> Device::CreateRenderBundle( | |
| RenderBundleEncoderBase* encoder, | |
| const RenderBundleDescriptor* descriptor) { | |
| return RenderBundle::Create(encoder, descriptor, encoder->AcquireRenderPassUsages(), | |
| encoder->AcquireIndirectDrawMetadata()); | |
| } | |
| Ref<ComputePipelineBase> Device::CreateUninitializedComputePipelineImpl( | |
| const UnpackedPtr<ComputePipelineDescriptor>& descriptor) { | |
| return ComputePipeline::CreateUninitialized(this, descriptor); | |
| } | |
| ResultOrError<Ref<PipelineLayoutBase>> Device::CreatePipelineLayoutImpl( | |
| const UnpackedPtr<PipelineLayoutDescriptor>& descriptor) { | |
| return PipelineLayout::Create(this, descriptor); | |
| } | |
| ResultOrError<Ref<QuerySetBase>> Device::CreateQuerySetImpl(const QuerySetDescriptor* descriptor) { | |
| return QuerySet::Create(this, descriptor); | |
| } | |
| Ref<RenderPipelineBase> Device::CreateUninitializedRenderPipelineImpl( | |
| const UnpackedPtr<RenderPipelineDescriptor>& descriptor) { | |
| return RenderPipeline::CreateUninitialized(this, descriptor); | |
| } | |
| ResultOrError<Ref<ResourceTableBase>> Device::CreateResourceTableImpl( | |
| const ResourceTableDescriptor* descriptor) { | |
| // TODO(https://issues.chromium.org/473442434): Implement resource tables in WebGPUOnWebGPU. | |
| return DAWN_UNIMPLEMENTED_ERROR("ResourceTable is not implemented in WebGPUOnWebGPU"); | |
| } | |
| ResultOrError<Ref<SamplerBase>> Device::CreateSamplerImpl(const SamplerDescriptor* descriptor) { | |
| return Sampler::Create(this, descriptor); | |
| } | |
| ResultOrError<Ref<ShaderModuleBase>> Device::CreateShaderModuleImpl( | |
| const UnpackedPtr<ShaderModuleDescriptor>& descriptor, | |
| const std::vector<tint::wgsl::Extension>& internalExtensions) { | |
| return ShaderModule::Create(this, descriptor, internalExtensions); | |
| } | |
| ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(Surface* surface, | |
| SwapChainBase* previousSwapChain, | |
| const SurfaceConfiguration* config) { | |
| return SwapChain::Create(this, surface, previousSwapChain, config); | |
| } | |
| ResultOrError<Ref<TextureBase>> Device::CreateTextureImpl( | |
| const UnpackedPtr<TextureDescriptor>& descriptor) { | |
| return Texture::Create(this, descriptor); | |
| } | |
| ResultOrError<Ref<TextureViewBase>> Device::CreateTextureViewImpl( | |
| TextureBase* texture, | |
| const UnpackedPtr<TextureViewDescriptor>& descriptor) { | |
| return TextureView::Create(texture, descriptor); | |
| } | |
| ResultOrError<Ref<SharedTextureMemoryBase>> Device::ImportSharedTextureMemoryImpl( | |
| const SharedTextureMemoryDescriptor* baseDescriptor) { | |
| UnpackedPtr<SharedTextureMemoryDescriptor> unpacked; | |
| DAWN_TRY_ASSIGN(unpacked, ValidateAndUnpack(baseDescriptor)); | |
| // TODO(crbug.com/483147423): Handle all possible chained structures. | |
| if (unpacked.Get<SharedTextureMemoryIOSurfaceDescriptor>()) { | |
| auto feature = Feature::SharedTextureMemoryIOSurface; | |
| DAWN_INVALID_IF(!HasFeature(feature), "%s is not enabled.", ToAPI(feature)); | |
| } else if (unpacked.Get<SharedTextureMemoryAHardwareBufferDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedTextureMemory in WebGPU backend has not been implemented for all platforms."); | |
| } else if (unpacked.Get<SharedTextureMemoryDXGISharedHandleDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedTextureMemory in WebGPU backend has not been implemented for all platforms."); | |
| } else if (unpacked.Get<SharedTextureMemoryEGLImageDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedTextureMemory in WebGPU backend has not been implemented for all platforms."); | |
| } else if (unpacked.Get<SharedTextureMemoryOpaqueFDDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedTextureMemory in WebGPU backend has not been implemented for all platforms."); | |
| } else if (unpacked.Get<SharedTextureMemoryVkDedicatedAllocationDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedTextureMemory in WebGPU backend has not been implemented for all platforms."); | |
| } else if (unpacked.Get<SharedTextureMemoryZirconHandleDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedTextureMemory in WebGPU backend has not been implemented for all platforms."); | |
| } else if (unpacked.Get<SharedTextureMemoryDmaBufDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedTextureMemory in WebGPU backend has not been implemented for all platforms."); | |
| } else { | |
| return DAWN_VALIDATION_ERROR("SharedTextureMemory chain is missing."); | |
| } | |
| // ValidateSubset pass for none, fail for invalid if exists. | |
| DAWN_TRY((unpacked.ValidateSubset< | |
| SharedTextureMemoryIOSurfaceDescriptor, SharedTextureMemoryAHardwareBufferDescriptor, | |
| SharedTextureMemoryDXGISharedHandleDescriptor, SharedTextureMemoryEGLImageDescriptor, | |
| SharedTextureMemoryOpaqueFDDescriptor, | |
| SharedTextureMemoryVkDedicatedAllocationDescriptor, | |
| SharedTextureMemoryZirconHandleDescriptor, SharedTextureMemoryDmaBufDescriptor>())); | |
| return SharedTextureMemory::Create(this, unpacked); | |
| } | |
| ResultOrError<Ref<SharedFenceBase>> Device::ImportSharedFenceImpl( | |
| const SharedFenceDescriptor* baseDescriptor) { | |
| UnpackedPtr<SharedFenceDescriptor> unpacked; | |
| DAWN_TRY_ASSIGN(unpacked, ValidateAndUnpack(baseDescriptor)); | |
| // TODO(crbug.com/483147423): Handle all possible chained structures. | |
| if (unpacked.Get<SharedFenceMTLSharedEventDescriptor>()) { | |
| auto feature = Feature::SharedFenceMTLSharedEvent; | |
| DAWN_INVALID_IF(!HasFeature(feature), "%s is not enabled.", ToAPI(feature)); | |
| } else if (unpacked.Get<SharedFenceDXGISharedHandleDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedFence in WebGPU backend has not been implemented for all platforms."); | |
| } else if (unpacked.Get<SharedFenceEGLSyncDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedFence in WebGPU backend has not been implemented for all platforms."); | |
| } else if (unpacked.Get<SharedFenceSyncFDDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedFence in WebGPU backend has not been implemented for all platforms."); | |
| } else if (unpacked.Get<SharedFenceVkSemaphoreOpaqueFDDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedFence in WebGPU backend has not been implemented for all platforms."); | |
| } else if (unpacked.Get<SharedFenceVkSemaphoreZirconHandleDescriptor>()) { | |
| return DAWN_UNIMPLEMENTED_ERROR( | |
| "SharedFence in WebGPU backend has not been implemented for all platforms."); | |
| } else { | |
| return DAWN_VALIDATION_ERROR("SharedFence chain is missing."); | |
| } | |
| // ValidateSubset pass for none, fail for invalid if exists. | |
| DAWN_TRY(( | |
| unpacked.ValidateSubset<SharedFenceMTLSharedEventDescriptor, | |
| SharedFenceDXGISharedHandleDescriptor, SharedFenceEGLSyncDescriptor, | |
| SharedFenceVkSemaphoreOpaqueFDDescriptor, | |
| SharedFenceVkSemaphoreZirconHandleDescriptor>())); | |
| return SharedFence::Create(this, unpacked); | |
| } | |
| void Device::DestroyImpl(DestroyReason reason) { | |
| DAWN_ASSERT(GetState() == State::Disconnected); | |
| // TODO(crbug.com/dawn/831): DestroyImpl is called from two places. | |
| // - It may be called if the device is explicitly destroyed with APIDestroy. | |
| // This case is NOT thread-safe and needs proper synchronization with other | |
| // simultaneous uses of the device. | |
| // - It may be called when the last ref to the device is dropped and the device | |
| // is implicitly destroyed. This case is thread-safe because there are no | |
| // other threads using the device since there are no other live refs. | |
| if (ToBackend(GetQueue())->IsCapturing()) { | |
| EndCapture(); | |
| } | |
| if (mInnerHandle) { | |
| wgpu->deviceDestroy(mInnerHandle); | |
| } | |
| } | |
| void Device::SetLabelImpl() { | |
| CaptureSetLabel(this, GetLabel()); | |
| } | |
| MaybeError Device::CopyFromStagingToBuffer(BufferBase* source, | |
| uint64_t sourceOffset, | |
| BufferBase* destination, | |
| uint64_t destinationOffset, | |
| uint64_t size) { | |
| wgpu->queueWriteBuffer( | |
| ToBackend(GetQueue())->GetInnerHandle(), ToBackend(destination)->GetInnerHandle(), | |
| sourceOffset, | |
| // The staging buffers in the DynamicUploader are assumed in Dawn to be persistently mapped | |
| // buffers that always have the mapped pointer accessible. n the WebGPU backend, to use the | |
| // buffers in a copyB2B we would need to unmap them but the DynamicUploader doesn't support | |
| // that. Instead keep the buffers mapped and use queueWriteBuffer to read directly from the | |
| // mapped staging memory. | |
| wgpu->bufferGetConstMappedRange(ToBackend(source)->GetInnerHandle(), 0, source->GetSize()), | |
| size); | |
| return {}; | |
| } | |
| MaybeError Device::CopyFromStagingToTextureImpl(BufferBase* source, | |
| const TexelCopyBufferLayout& src, | |
| const TextureCopy& dst, | |
| const Extent3D& copySizePixels) { | |
| WGPUTexelCopyBufferLayout innerSource = ToWGPU(src); | |
| WGPUTexelCopyTextureInfo innerDestination = ToWGPU(dst); | |
| size_t bufferSize = source->GetSize(); | |
| WGPUExtent3D size = ToWGPU(copySizePixels); | |
| wgpu->queueWriteTexture( | |
| ToBackend(GetQueue())->GetInnerHandle(), &innerDestination, | |
| // The staging buffers in the DynamicUploader are assumed in Dawn to be persistently mapped | |
| // buffers that always have the mapped pointer accessible. n the WebGPU backend, to use the | |
| // buffers in a copyB2T we would need to unmap them but the DynamicUploader doesn't support | |
| // that. Instead keep the buffers mapped and use queueWriteTexture to read directly from the | |
| // mapped staging memory. | |
| wgpu->bufferGetConstMappedRange(ToBackend(source)->GetInnerHandle(), 0, bufferSize), | |
| bufferSize, &innerSource, &size); | |
| return {}; | |
| } | |
| MaybeError Device::TickImpl() { | |
| wgpu->deviceTick(mInnerHandle); | |
| return {}; | |
| } | |
| uint32_t Device::GetOptimalBytesPerRowAlignment() const { | |
| return kTextureBytesPerRowAlignment; | |
| } | |
| uint64_t Device::GetOptimalBufferToTextureCopyOffsetAlignment() const { | |
| return 1; | |
| } | |
| float Device::GetTimestampPeriodInNS() const { | |
| return 1.0f; | |
| } | |
| bool Device::AreTimestampsQuantized() const { | |
| return true; | |
| } | |
| bool Device::CanResolveSubRect() const { | |
| // Related code in src/dawn/native/RenderPassWorkaroundsHelper.cpp | |
| // WebGPU backend will pass down cmd->resolveRect to the inner layer backend to handle it | |
| // anyways, so return true and do not apply any workarounds here. | |
| return true; | |
| } | |
| bool Device::NeedsIndirectGPUValidation() const { | |
| // WebGPU backend never actually dispatch compute pass to validate indirect draw cmds, | |
| // since the inner backend will take care of it. | |
| return false; | |
| } | |
| void Device::StartCapture(CaptureStream& commandStream, CaptureStream& contentStream) { | |
| MaybeError result = ToBackend(GetQueue()) | |
| ->SetCaptureContext(std::unique_ptr<CaptureContext>( | |
| new CaptureContext(this, commandStream, contentStream))); | |
| [[maybe_unused]] bool hadError = | |
| ConsumedError(std::move(result), "calling %s.StartCapture()", this); | |
| } | |
| void Device::EndCapture() { | |
| if (ToBackend(GetQueue())->IsCapturing()) { | |
| MaybeError result = ToBackend(GetQueue())->SetCaptureContext(nullptr); | |
| [[maybe_unused]] bool hadError = | |
| ConsumedError(std::move(result), "calling %s.EndCapture()", this); | |
| } | |
| } | |
| } // namespace dawn::native::webgpu |