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