// Copyright 2017 The Dawn Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "dawn_native/Device.h" #include "dawn_native/BindGroup.h" #include "dawn_native/BindGroupLayout.h" #include "dawn_native/Buffer.h" #include "dawn_native/CommandBuffer.h" #include "dawn_native/ComputePipeline.h" #include "dawn_native/ErrorData.h" #include "dawn_native/Fence.h" #include "dawn_native/FenceSignalTracker.h" #include "dawn_native/InputState.h" #include "dawn_native/PipelineLayout.h" #include "dawn_native/Queue.h" #include "dawn_native/RenderPassDescriptor.h" #include "dawn_native/RenderPipeline.h" #include "dawn_native/Sampler.h" #include "dawn_native/ShaderModule.h" #include "dawn_native/SwapChain.h" #include "dawn_native/Texture.h" #include namespace dawn_native { // DeviceBase::Caches // The caches are unordered_sets of pointers with special hash and compare functions // to compare the value of the objects, instead of the pointers. using BindGroupLayoutCache = std:: unordered_set; struct DeviceBase::Caches { BindGroupLayoutCache bindGroupLayouts; }; // DeviceBase DeviceBase::DeviceBase() { mCaches = std::make_unique(); mFenceSignalTracker = std::make_unique(this); } DeviceBase::~DeviceBase() { } void DeviceBase::HandleError(const char* message) { if (mErrorCallback) { mErrorCallback(message, mErrorUserdata); } } void DeviceBase::SetErrorCallback(dawn::DeviceErrorCallback callback, dawn::CallbackUserdata userdata) { mErrorCallback = callback; mErrorUserdata = userdata; } DeviceBase* DeviceBase::GetDevice() { return this; } FenceSignalTracker* DeviceBase::GetFenceSignalTracker() const { return mFenceSignalTracker.get(); } ResultOrError DeviceBase::GetOrCreateBindGroupLayout( const BindGroupLayoutDescriptor* descriptor) { BindGroupLayoutBase blueprint(this, descriptor, true); auto iter = mCaches->bindGroupLayouts.find(&blueprint); if (iter != mCaches->bindGroupLayouts.end()) { (*iter)->Reference(); return *iter; } BindGroupLayoutBase* backendObj; DAWN_TRY_ASSIGN(backendObj, CreateBindGroupLayoutImpl(descriptor)); mCaches->bindGroupLayouts.insert(backendObj); return backendObj; } void DeviceBase::UncacheBindGroupLayout(BindGroupLayoutBase* obj) { mCaches->bindGroupLayouts.erase(obj); } // Object creation API methods BindGroupBase* DeviceBase::CreateBindGroup(const BindGroupDescriptor* descriptor) { BindGroupBase* result = nullptr; if (ConsumedError(CreateBindGroupInternal(&result, descriptor))) { return nullptr; } return result; } BindGroupLayoutBase* DeviceBase::CreateBindGroupLayout( const BindGroupLayoutDescriptor* descriptor) { BindGroupLayoutBase* result = nullptr; if (ConsumedError(CreateBindGroupLayoutInternal(&result, descriptor))) { return nullptr; } return result; } BufferBase* DeviceBase::CreateBuffer(const BufferDescriptor* descriptor) { BufferBase* result = nullptr; if (ConsumedError(CreateBufferInternal(&result, descriptor))) { return nullptr; } return result; } CommandBufferBuilder* DeviceBase::CreateCommandBufferBuilder() { return new CommandBufferBuilder(this); } ComputePipelineBase* DeviceBase::CreateComputePipeline( const ComputePipelineDescriptor* descriptor) { ComputePipelineBase* result = nullptr; if (ConsumedError(CreateComputePipelineInternal(&result, descriptor))) { return nullptr; } return result; } FenceBase* DeviceBase::CreateFence(const FenceDescriptor* descriptor) { FenceBase* result = nullptr; if (ConsumedError(CreateFenceInternal(&result, descriptor))) { return nullptr; } return result; } InputStateBuilder* DeviceBase::CreateInputStateBuilder() { return new InputStateBuilder(this); } PipelineLayoutBase* DeviceBase::CreatePipelineLayout( const PipelineLayoutDescriptor* descriptor) { PipelineLayoutBase* result = nullptr; if (ConsumedError(CreatePipelineLayoutInternal(&result, descriptor))) { return nullptr; } return result; } QueueBase* DeviceBase::CreateQueue() { QueueBase* result = nullptr; if (ConsumedError(CreateQueueInternal(&result))) { return nullptr; } return result; } RenderPassDescriptorBuilder* DeviceBase::CreateRenderPassDescriptorBuilder() { return new RenderPassDescriptorBuilder(this); } SamplerBase* DeviceBase::CreateSampler(const SamplerDescriptor* descriptor) { SamplerBase* result = nullptr; if (ConsumedError(CreateSamplerInternal(&result, descriptor))) { return nullptr; } return result; } RenderPipelineBase* DeviceBase::CreateRenderPipeline( const RenderPipelineDescriptor* descriptor) { RenderPipelineBase* result = nullptr; if (ConsumedError(CreateRenderPipelineInternal(&result, descriptor))) { return nullptr; } return result; } ShaderModuleBase* DeviceBase::CreateShaderModule(const ShaderModuleDescriptor* descriptor) { ShaderModuleBase* result = nullptr; if (ConsumedError(CreateShaderModuleInternal(&result, descriptor))) { return nullptr; } return result; } SwapChainBuilder* DeviceBase::CreateSwapChainBuilder() { return new SwapChainBuilder(this); } TextureBase* DeviceBase::CreateTexture(const TextureDescriptor* descriptor) { TextureBase* result = nullptr; if (ConsumedError(CreateTextureInternal(&result, descriptor))) { return nullptr; } return result; } TextureViewBase* DeviceBase::CreateTextureView(TextureBase* texture, const TextureViewDescriptor* descriptor) { TextureViewBase* result = nullptr; if (ConsumedError(CreateTextureViewInternal(&result, texture, descriptor))) { return nullptr; } return result; } // Other Device API methods void DeviceBase::Tick() { TickImpl(); mFenceSignalTracker->Tick(GetCompletedCommandSerial()); } void DeviceBase::Reference() { ASSERT(mRefCount != 0); mRefCount++; } void DeviceBase::Release() { ASSERT(mRefCount != 0); mRefCount--; if (mRefCount == 0) { delete this; } } // Implementation details of object creation MaybeError DeviceBase::CreateBindGroupInternal(BindGroupBase** result, const BindGroupDescriptor* descriptor) { DAWN_TRY(ValidateBindGroupDescriptor(this, descriptor)); DAWN_TRY_ASSIGN(*result, CreateBindGroupImpl(descriptor)); return {}; } MaybeError DeviceBase::CreateBindGroupLayoutInternal( BindGroupLayoutBase** result, const BindGroupLayoutDescriptor* descriptor) { DAWN_TRY(ValidateBindGroupLayoutDescriptor(this, descriptor)); DAWN_TRY_ASSIGN(*result, GetOrCreateBindGroupLayout(descriptor)); return {}; } MaybeError DeviceBase::CreateBufferInternal(BufferBase** result, const BufferDescriptor* descriptor) { DAWN_TRY(ValidateBufferDescriptor(this, descriptor)); DAWN_TRY_ASSIGN(*result, CreateBufferImpl(descriptor)); return {}; } MaybeError DeviceBase::CreateComputePipelineInternal( ComputePipelineBase** result, const ComputePipelineDescriptor* descriptor) { DAWN_TRY(ValidateComputePipelineDescriptor(this, descriptor)); DAWN_TRY_ASSIGN(*result, CreateComputePipelineImpl(descriptor)); return {}; } MaybeError DeviceBase::CreateFenceInternal(FenceBase** result, const FenceDescriptor* descriptor) { DAWN_TRY(ValidateFenceDescriptor(this, descriptor)); *result = new FenceBase(this, descriptor); return {}; } MaybeError DeviceBase::CreatePipelineLayoutInternal( PipelineLayoutBase** result, const PipelineLayoutDescriptor* descriptor) { DAWN_TRY(ValidatePipelineLayoutDescriptor(this, descriptor)); DAWN_TRY_ASSIGN(*result, CreatePipelineLayoutImpl(descriptor)); return {}; } MaybeError DeviceBase::CreateQueueInternal(QueueBase** result) { DAWN_TRY_ASSIGN(*result, CreateQueueImpl()); return {}; } MaybeError DeviceBase::CreateRenderPipelineInternal( RenderPipelineBase** result, const RenderPipelineDescriptor* descriptor) { DAWN_TRY(ValidateRenderPipelineDescriptor(this, descriptor)); DAWN_TRY_ASSIGN(*result, CreateRenderPipelineImpl(descriptor)); return {}; } MaybeError DeviceBase::CreateSamplerInternal(SamplerBase** result, const SamplerDescriptor* descriptor) { DAWN_TRY(ValidateSamplerDescriptor(this, descriptor)); DAWN_TRY_ASSIGN(*result, CreateSamplerImpl(descriptor)); return {}; } MaybeError DeviceBase::CreateShaderModuleInternal(ShaderModuleBase** result, const ShaderModuleDescriptor* descriptor) { DAWN_TRY(ValidateShaderModuleDescriptor(this, descriptor)); DAWN_TRY_ASSIGN(*result, CreateShaderModuleImpl(descriptor)); return {}; } MaybeError DeviceBase::CreateTextureInternal(TextureBase** result, const TextureDescriptor* descriptor) { DAWN_TRY(ValidateTextureDescriptor(this, descriptor)); DAWN_TRY_ASSIGN(*result, CreateTextureImpl(descriptor)); return {}; } MaybeError DeviceBase::CreateTextureViewInternal(TextureViewBase** result, TextureBase* texture, const TextureViewDescriptor* descriptor) { DAWN_TRY(ValidateTextureViewDescriptor(this, texture, descriptor)); DAWN_TRY_ASSIGN(*result, CreateTextureViewImpl(texture, descriptor)); return {}; } // Other implementation details void DeviceBase::ConsumeError(ErrorData* error) { ASSERT(error != nullptr); HandleError(error->GetMessage().c_str()); delete error; } } // namespace dawn_native