• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/opengl/DeviceGL.h"
16 
17 #include "dawn_native/BackendConnection.h"
18 #include "dawn_native/BindGroupLayout.h"
19 #include "dawn_native/ErrorData.h"
20 #include "dawn_native/StagingBuffer.h"
21 #include "dawn_native/opengl/BindGroupGL.h"
22 #include "dawn_native/opengl/BindGroupLayoutGL.h"
23 #include "dawn_native/opengl/BufferGL.h"
24 #include "dawn_native/opengl/CommandBufferGL.h"
25 #include "dawn_native/opengl/ComputePipelineGL.h"
26 #include "dawn_native/opengl/PipelineLayoutGL.h"
27 #include "dawn_native/opengl/QuerySetGL.h"
28 #include "dawn_native/opengl/QueueGL.h"
29 #include "dawn_native/opengl/RenderPipelineGL.h"
30 #include "dawn_native/opengl/SamplerGL.h"
31 #include "dawn_native/opengl/ShaderModuleGL.h"
32 #include "dawn_native/opengl/SwapChainGL.h"
33 #include "dawn_native/opengl/TextureGL.h"
34 
35 namespace dawn_native { namespace opengl {
36 
37     // static
Create(AdapterBase * adapter,const DawnDeviceDescriptor * descriptor,const OpenGLFunctions & functions)38     ResultOrError<Device*> Device::Create(AdapterBase* adapter,
39                                           const DawnDeviceDescriptor* descriptor,
40                                           const OpenGLFunctions& functions) {
41         Ref<Device> device = AcquireRef(new Device(adapter, descriptor, functions));
42         DAWN_TRY(device->Initialize());
43         return device.Detach();
44     }
45 
Device(AdapterBase * adapter,const DawnDeviceDescriptor * descriptor,const OpenGLFunctions & functions)46     Device::Device(AdapterBase* adapter,
47                    const DawnDeviceDescriptor* descriptor,
48                    const OpenGLFunctions& functions)
49         : DeviceBase(adapter, descriptor), gl(functions) {
50     }
51 
~Device()52     Device::~Device() {
53         Destroy();
54     }
55 
Initialize()56     MaybeError Device::Initialize() {
57         InitTogglesFromDriver();
58         mFormatTable = BuildGLFormatTable();
59 
60         return DeviceBase::Initialize(new Queue(this));
61     }
62 
InitTogglesFromDriver()63     void Device::InitTogglesFromDriver() {
64         bool supportsBaseVertex = gl.IsAtLeastGLES(3, 2) || gl.IsAtLeastGL(3, 2);
65 
66         bool supportsBaseInstance = gl.IsAtLeastGLES(3, 2) || gl.IsAtLeastGL(4, 2);
67 
68         // TODO(crbug.com/dawn/582): Use OES_draw_buffers_indexed where available.
69         bool supportsIndexedDrawBuffers = gl.IsAtLeastGLES(3, 2) || gl.IsAtLeastGL(3, 0);
70 
71         bool supportsSnormRead =
72             gl.IsAtLeastGL(4, 4) || gl.IsGLExtensionSupported("GL_EXT_render_snorm");
73 
74         bool supportsDepthStencilRead =
75             gl.IsAtLeastGL(3, 0) || gl.IsGLExtensionSupported("GL_NV_read_depth_stencil");
76 
77         bool supportsSampleVariables = gl.IsAtLeastGL(4, 0) || gl.IsAtLeastGLES(3, 2) ||
78                                        gl.IsGLExtensionSupported("GL_OES_sample_variables");
79 
80         // TODO(crbug.com/dawn/343): We can support the extension variants, but need to load the EXT
81         // procs without the extension suffix.
82         // We'll also need emulation of shader builtins gl_BaseVertex and gl_BaseInstance.
83 
84         // supportsBaseVertex |=
85         //     (gl.IsAtLeastGLES(2, 0) &&
86         //      (gl.IsGLExtensionSupported("OES_draw_elements_base_vertex") ||
87         //       gl.IsGLExtensionSupported("EXT_draw_elements_base_vertex"))) ||
88         //     (gl.IsAtLeastGL(3, 1) && gl.IsGLExtensionSupported("ARB_draw_elements_base_vertex"));
89 
90         // supportsBaseInstance |=
91         //     (gl.IsAtLeastGLES(3, 1) && gl.IsGLExtensionSupported("EXT_base_instance")) ||
92         //     (gl.IsAtLeastGL(3, 1) && gl.IsGLExtensionSupported("ARB_base_instance"));
93 
94         // TODO(crbug.com/dawn/343): Investigate emulation.
95         SetToggle(Toggle::DisableBaseVertex, !supportsBaseVertex);
96         SetToggle(Toggle::DisableBaseInstance, !supportsBaseInstance);
97         SetToggle(Toggle::DisableIndexedDrawBuffers, !supportsIndexedDrawBuffers);
98         SetToggle(Toggle::DisableSnormRead, !supportsSnormRead);
99         SetToggle(Toggle::DisableDepthStencilRead, !supportsDepthStencilRead);
100         SetToggle(Toggle::DisableSampleVariables, !supportsSampleVariables);
101         SetToggle(Toggle::FlushBeforeClientWaitSync, gl.GetVersion().IsES());
102         // For OpenGL ES, we must use dummy fragment shader for vertex-only render pipeline.
103         SetToggle(Toggle::UseDummyFragmentInVertexOnlyPipeline, gl.GetVersion().IsES());
104     }
105 
GetGLFormat(const Format & format)106     const GLFormat& Device::GetGLFormat(const Format& format) {
107         ASSERT(format.isSupported);
108         ASSERT(format.GetIndex() < mFormatTable.size());
109 
110         const GLFormat& result = mFormatTable[format.GetIndex()];
111         ASSERT(result.isSupportedOnBackend);
112         return result;
113     }
114 
CreateBindGroupImpl(const BindGroupDescriptor * descriptor)115     ResultOrError<Ref<BindGroupBase>> Device::CreateBindGroupImpl(
116         const BindGroupDescriptor* descriptor) {
117         DAWN_TRY(ValidateGLBindGroupDescriptor(descriptor));
118         return BindGroup::Create(this, descriptor);
119     }
CreateBindGroupLayoutImpl(const BindGroupLayoutDescriptor * descriptor,PipelineCompatibilityToken pipelineCompatibilityToken)120     ResultOrError<Ref<BindGroupLayoutBase>> Device::CreateBindGroupLayoutImpl(
121         const BindGroupLayoutDescriptor* descriptor,
122         PipelineCompatibilityToken pipelineCompatibilityToken) {
123         return AcquireRef(new BindGroupLayout(this, descriptor, pipelineCompatibilityToken));
124     }
CreateBufferImpl(const BufferDescriptor * descriptor)125     ResultOrError<Ref<BufferBase>> Device::CreateBufferImpl(const BufferDescriptor* descriptor) {
126         return AcquireRef(new Buffer(this, descriptor));
127     }
CreateCommandBuffer(CommandEncoder * encoder,const CommandBufferDescriptor * descriptor)128     ResultOrError<Ref<CommandBufferBase>> Device::CreateCommandBuffer(
129         CommandEncoder* encoder,
130         const CommandBufferDescriptor* descriptor) {
131         return AcquireRef(new CommandBuffer(encoder, descriptor));
132     }
CreateUninitializedComputePipelineImpl(const ComputePipelineDescriptor * descriptor)133     Ref<ComputePipelineBase> Device::CreateUninitializedComputePipelineImpl(
134         const ComputePipelineDescriptor* descriptor) {
135         return ComputePipeline::CreateUninitialized(this, descriptor);
136     }
CreatePipelineLayoutImpl(const PipelineLayoutDescriptor * descriptor)137     ResultOrError<Ref<PipelineLayoutBase>> Device::CreatePipelineLayoutImpl(
138         const PipelineLayoutDescriptor* descriptor) {
139         return AcquireRef(new PipelineLayout(this, descriptor));
140     }
CreateQuerySetImpl(const QuerySetDescriptor * descriptor)141     ResultOrError<Ref<QuerySetBase>> Device::CreateQuerySetImpl(
142         const QuerySetDescriptor* descriptor) {
143         return AcquireRef(new QuerySet(this, descriptor));
144     }
CreateUninitializedRenderPipelineImpl(const RenderPipelineDescriptor * descriptor)145     Ref<RenderPipelineBase> Device::CreateUninitializedRenderPipelineImpl(
146         const RenderPipelineDescriptor* descriptor) {
147         return RenderPipeline::CreateUninitialized(this, descriptor);
148     }
CreateSamplerImpl(const SamplerDescriptor * descriptor)149     ResultOrError<Ref<SamplerBase>> Device::CreateSamplerImpl(const SamplerDescriptor* descriptor) {
150         return AcquireRef(new Sampler(this, descriptor));
151     }
CreateShaderModuleImpl(const ShaderModuleDescriptor * descriptor,ShaderModuleParseResult * parseResult)152     ResultOrError<Ref<ShaderModuleBase>> Device::CreateShaderModuleImpl(
153         const ShaderModuleDescriptor* descriptor,
154         ShaderModuleParseResult* parseResult) {
155         return ShaderModule::Create(this, descriptor, parseResult);
156     }
CreateSwapChainImpl(const SwapChainDescriptor * descriptor)157     ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(
158         const SwapChainDescriptor* descriptor) {
159         return AcquireRef(new SwapChain(this, descriptor));
160     }
CreateSwapChainImpl(Surface * surface,NewSwapChainBase * previousSwapChain,const SwapChainDescriptor * descriptor)161     ResultOrError<Ref<NewSwapChainBase>> Device::CreateSwapChainImpl(
162         Surface* surface,
163         NewSwapChainBase* previousSwapChain,
164         const SwapChainDescriptor* descriptor) {
165         return DAWN_FORMAT_VALIDATION_ERROR("New swapchains not implemented.");
166     }
CreateTextureImpl(const TextureDescriptor * descriptor)167     ResultOrError<Ref<TextureBase>> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
168         return AcquireRef(new Texture(this, descriptor));
169     }
CreateTextureViewImpl(TextureBase * texture,const TextureViewDescriptor * descriptor)170     ResultOrError<Ref<TextureViewBase>> Device::CreateTextureViewImpl(
171         TextureBase* texture,
172         const TextureViewDescriptor* descriptor) {
173         return AcquireRef(new TextureView(texture, descriptor));
174     }
175 
SubmitFenceSync()176     void Device::SubmitFenceSync() {
177         GLsync sync = gl.FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
178         IncrementLastSubmittedCommandSerial();
179         mFencesInFlight.emplace(sync, GetLastSubmittedCommandSerial());
180     }
181 
ValidateEGLImageCanBeWrapped(const TextureDescriptor * descriptor,::EGLImage image)182     MaybeError Device::ValidateEGLImageCanBeWrapped(const TextureDescriptor* descriptor,
183                                                     ::EGLImage image) {
184         DAWN_INVALID_IF(descriptor->dimension != wgpu::TextureDimension::e2D,
185                         "Texture dimension (%s) is not %s.", descriptor->dimension,
186                         wgpu::TextureDimension::e2D);
187 
188         DAWN_INVALID_IF(descriptor->mipLevelCount != 1, "Mip level count (%u) is not 1.",
189                         descriptor->mipLevelCount);
190 
191         DAWN_INVALID_IF(descriptor->size.depthOrArrayLayers != 1,
192                         "Array layer count (%u) is not 1.", descriptor->size.depthOrArrayLayers);
193 
194         DAWN_INVALID_IF(descriptor->sampleCount != 1, "Sample count (%u) is not 1.",
195                         descriptor->sampleCount);
196 
197         DAWN_INVALID_IF(descriptor->usage & (wgpu::TextureUsage::TextureBinding |
198                                              wgpu::TextureUsage::StorageBinding),
199                         "Texture usage (%s) cannot have %s or %s.", descriptor->usage,
200                         wgpu::TextureUsage::TextureBinding, wgpu::TextureUsage::StorageBinding);
201 
202         return {};
203     }
CreateTextureWrappingEGLImage(const ExternalImageDescriptor * descriptor,::EGLImage image)204     TextureBase* Device::CreateTextureWrappingEGLImage(const ExternalImageDescriptor* descriptor,
205                                                        ::EGLImage image) {
206         const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
207 
208         if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) {
209             return nullptr;
210         }
211         if (ConsumedError(ValidateEGLImageCanBeWrapped(textureDescriptor, image))) {
212             return nullptr;
213         }
214 
215         GLuint tex;
216         gl.GenTextures(1, &tex);
217         gl.BindTexture(GL_TEXTURE_2D, tex);
218         gl.EGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
219 
220         GLint width, height, internalFormat;
221         gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
222         gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
223         gl.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat);
224 
225         if (textureDescriptor->size.width != static_cast<uint32_t>(width) ||
226             textureDescriptor->size.height != static_cast<uint32_t>(height) ||
227             textureDescriptor->size.depthOrArrayLayers != 1) {
228             ConsumedError(DAWN_FORMAT_VALIDATION_ERROR(
229                 "EGLImage size (width: %u, height: %u, depth: 1) doesn't match descriptor size %s.",
230                 width, height, &textureDescriptor->size));
231             gl.DeleteTextures(1, &tex);
232             return nullptr;
233         }
234 
235         // TODO(dawn:803): Validate the OpenGL texture format from the EGLImage against the format
236         // in the passed-in TextureDescriptor.
237         return new Texture(this, textureDescriptor, tex, TextureBase::TextureState::OwnedInternal);
238     }
239 
TickImpl()240     MaybeError Device::TickImpl() {
241         return {};
242     }
243 
CheckAndUpdateCompletedSerials()244     ResultOrError<ExecutionSerial> Device::CheckAndUpdateCompletedSerials() {
245         ExecutionSerial fenceSerial{0};
246         while (!mFencesInFlight.empty()) {
247             GLsync sync = mFencesInFlight.front().first;
248             ExecutionSerial tentativeSerial = mFencesInFlight.front().second;
249 
250             // Fence are added in order, so we can stop searching as soon
251             // as we see one that's not ready.
252 
253             // TODO(crbug.com/dawn/633): Remove this workaround after the deadlock issue is fixed.
254             if (IsToggleEnabled(Toggle::FlushBeforeClientWaitSync)) {
255                 gl.Flush();
256             }
257             GLenum result = gl.ClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
258             if (result == GL_TIMEOUT_EXPIRED) {
259                 return fenceSerial;
260             }
261             // Update fenceSerial since fence is ready.
262             fenceSerial = tentativeSerial;
263 
264             gl.DeleteSync(sync);
265 
266             mFencesInFlight.pop();
267 
268             ASSERT(fenceSerial > GetCompletedCommandSerial());
269         }
270         return fenceSerial;
271     }
272 
CreateStagingBuffer(size_t size)273     ResultOrError<std::unique_ptr<StagingBufferBase>> Device::CreateStagingBuffer(size_t size) {
274         return DAWN_UNIMPLEMENTED_ERROR("Device unable to create staging buffer.");
275     }
276 
CopyFromStagingToBuffer(StagingBufferBase * source,uint64_t sourceOffset,BufferBase * destination,uint64_t destinationOffset,uint64_t size)277     MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
278                                                uint64_t sourceOffset,
279                                                BufferBase* destination,
280                                                uint64_t destinationOffset,
281                                                uint64_t size) {
282         return DAWN_UNIMPLEMENTED_ERROR("Device unable to copy from staging buffer.");
283     }
284 
CopyFromStagingToTexture(const StagingBufferBase * source,const TextureDataLayout & src,TextureCopy * dst,const Extent3D & copySizePixels)285     MaybeError Device::CopyFromStagingToTexture(const StagingBufferBase* source,
286                                                 const TextureDataLayout& src,
287                                                 TextureCopy* dst,
288                                                 const Extent3D& copySizePixels) {
289         return DAWN_UNIMPLEMENTED_ERROR("Device unable to copy from staging buffer to texture.");
290     }
291 
DestroyImpl()292     void Device::DestroyImpl() {
293         ASSERT(GetState() == State::Disconnected);
294     }
295 
WaitForIdleForDestruction()296     MaybeError Device::WaitForIdleForDestruction() {
297         gl.Finish();
298         DAWN_TRY(CheckPassedSerials());
299         ASSERT(mFencesInFlight.empty());
300 
301         return {};
302     }
303 
GetOptimalBytesPerRowAlignment() const304     uint32_t Device::GetOptimalBytesPerRowAlignment() const {
305         return 1;
306     }
307 
GetOptimalBufferToTextureCopyOffsetAlignment() const308     uint64_t Device::GetOptimalBufferToTextureCopyOffsetAlignment() const {
309         return 1;
310     }
311 
GetTimestampPeriodInNS() const312     float Device::GetTimestampPeriodInNS() const {
313         return 1.0f;
314     }
315 
316 }}  // namespace dawn_native::opengl
317