1 // Copyright 2017 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/CommandBufferGL.h" 16 17 #include "dawn_native/BindGroup.h" 18 #include "dawn_native/BindGroupTracker.h" 19 #include "dawn_native/CommandEncoder.h" 20 #include "dawn_native/Commands.h" 21 #include "dawn_native/ExternalTexture.h" 22 #include "dawn_native/RenderBundle.h" 23 #include "dawn_native/VertexFormat.h" 24 #include "dawn_native/opengl/BufferGL.h" 25 #include "dawn_native/opengl/ComputePipelineGL.h" 26 #include "dawn_native/opengl/DeviceGL.h" 27 #include "dawn_native/opengl/Forward.h" 28 #include "dawn_native/opengl/PersistentPipelineStateGL.h" 29 #include "dawn_native/opengl/PipelineLayoutGL.h" 30 #include "dawn_native/opengl/RenderPipelineGL.h" 31 #include "dawn_native/opengl/SamplerGL.h" 32 #include "dawn_native/opengl/TextureGL.h" 33 #include "dawn_native/opengl/UtilsGL.h" 34 35 #include <cstring> 36 37 namespace dawn_native { namespace opengl { 38 39 namespace { 40 IndexFormatType(wgpu::IndexFormat format)41 GLenum IndexFormatType(wgpu::IndexFormat format) { 42 switch (format) { 43 case wgpu::IndexFormat::Uint16: 44 return GL_UNSIGNED_SHORT; 45 case wgpu::IndexFormat::Uint32: 46 return GL_UNSIGNED_INT; 47 case wgpu::IndexFormat::Undefined: 48 break; 49 } 50 UNREACHABLE(); 51 } 52 VertexFormatType(wgpu::VertexFormat format)53 GLenum VertexFormatType(wgpu::VertexFormat format) { 54 switch (format) { 55 case wgpu::VertexFormat::Uint8x2: 56 case wgpu::VertexFormat::Uint8x4: 57 case wgpu::VertexFormat::Unorm8x2: 58 case wgpu::VertexFormat::Unorm8x4: 59 return GL_UNSIGNED_BYTE; 60 case wgpu::VertexFormat::Sint8x2: 61 case wgpu::VertexFormat::Sint8x4: 62 case wgpu::VertexFormat::Snorm8x2: 63 case wgpu::VertexFormat::Snorm8x4: 64 return GL_BYTE; 65 case wgpu::VertexFormat::Uint16x2: 66 case wgpu::VertexFormat::Uint16x4: 67 case wgpu::VertexFormat::Unorm16x2: 68 case wgpu::VertexFormat::Unorm16x4: 69 return GL_UNSIGNED_SHORT; 70 case wgpu::VertexFormat::Sint16x2: 71 case wgpu::VertexFormat::Sint16x4: 72 case wgpu::VertexFormat::Snorm16x2: 73 case wgpu::VertexFormat::Snorm16x4: 74 return GL_SHORT; 75 case wgpu::VertexFormat::Float16x2: 76 case wgpu::VertexFormat::Float16x4: 77 return GL_HALF_FLOAT; 78 case wgpu::VertexFormat::Float32: 79 case wgpu::VertexFormat::Float32x2: 80 case wgpu::VertexFormat::Float32x3: 81 case wgpu::VertexFormat::Float32x4: 82 return GL_FLOAT; 83 case wgpu::VertexFormat::Uint32: 84 case wgpu::VertexFormat::Uint32x2: 85 case wgpu::VertexFormat::Uint32x3: 86 case wgpu::VertexFormat::Uint32x4: 87 return GL_UNSIGNED_INT; 88 case wgpu::VertexFormat::Sint32: 89 case wgpu::VertexFormat::Sint32x2: 90 case wgpu::VertexFormat::Sint32x3: 91 case wgpu::VertexFormat::Sint32x4: 92 return GL_INT; 93 default: 94 UNREACHABLE(); 95 } 96 } 97 VertexFormatIsNormalized(wgpu::VertexFormat format)98 GLboolean VertexFormatIsNormalized(wgpu::VertexFormat format) { 99 switch (format) { 100 case wgpu::VertexFormat::Unorm8x2: 101 case wgpu::VertexFormat::Unorm8x4: 102 case wgpu::VertexFormat::Snorm8x2: 103 case wgpu::VertexFormat::Snorm8x4: 104 case wgpu::VertexFormat::Unorm16x2: 105 case wgpu::VertexFormat::Unorm16x4: 106 case wgpu::VertexFormat::Snorm16x2: 107 case wgpu::VertexFormat::Snorm16x4: 108 return GL_TRUE; 109 default: 110 return GL_FALSE; 111 } 112 } 113 VertexFormatIsInt(wgpu::VertexFormat format)114 bool VertexFormatIsInt(wgpu::VertexFormat format) { 115 switch (format) { 116 case wgpu::VertexFormat::Uint8x2: 117 case wgpu::VertexFormat::Uint8x4: 118 case wgpu::VertexFormat::Sint8x2: 119 case wgpu::VertexFormat::Sint8x4: 120 case wgpu::VertexFormat::Uint16x2: 121 case wgpu::VertexFormat::Uint16x4: 122 case wgpu::VertexFormat::Sint16x2: 123 case wgpu::VertexFormat::Sint16x4: 124 case wgpu::VertexFormat::Uint32: 125 case wgpu::VertexFormat::Uint32x2: 126 case wgpu::VertexFormat::Uint32x3: 127 case wgpu::VertexFormat::Uint32x4: 128 case wgpu::VertexFormat::Sint32: 129 case wgpu::VertexFormat::Sint32x2: 130 case wgpu::VertexFormat::Sint32x3: 131 case wgpu::VertexFormat::Sint32x4: 132 return true; 133 default: 134 return false; 135 } 136 } 137 138 // Vertex buffers and index buffers are implemented as part of an OpenGL VAO that 139 // corresponds to a VertexState. On the contrary in Dawn they are part of the global state. 140 // This means that we have to re-apply these buffers on a VertexState change. 141 class VertexStateBufferBindingTracker { 142 public: OnSetIndexBuffer(BufferBase * buffer)143 void OnSetIndexBuffer(BufferBase* buffer) { 144 mIndexBufferDirty = true; 145 mIndexBuffer = ToBackend(buffer); 146 } 147 OnSetVertexBuffer(VertexBufferSlot slot,BufferBase * buffer,uint64_t offset)148 void OnSetVertexBuffer(VertexBufferSlot slot, BufferBase* buffer, uint64_t offset) { 149 mVertexBuffers[slot] = ToBackend(buffer); 150 mVertexBufferOffsets[slot] = offset; 151 mDirtyVertexBuffers.set(slot); 152 } 153 OnSetPipeline(RenderPipelineBase * pipeline)154 void OnSetPipeline(RenderPipelineBase* pipeline) { 155 if (mLastPipeline == pipeline) { 156 return; 157 } 158 159 mIndexBufferDirty = true; 160 mDirtyVertexBuffers |= pipeline->GetVertexBufferSlotsUsed(); 161 162 mLastPipeline = pipeline; 163 } 164 Apply(const OpenGLFunctions & gl)165 void Apply(const OpenGLFunctions& gl) { 166 if (mIndexBufferDirty && mIndexBuffer != nullptr) { 167 gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->GetHandle()); 168 mIndexBufferDirty = false; 169 } 170 171 for (VertexBufferSlot slot : IterateBitSet( 172 mDirtyVertexBuffers & mLastPipeline->GetVertexBufferSlotsUsed())) { 173 for (VertexAttributeLocation location : IterateBitSet( 174 ToBackend(mLastPipeline)->GetAttributesUsingVertexBuffer(slot))) { 175 const VertexAttributeInfo& attribute = 176 mLastPipeline->GetAttribute(location); 177 178 GLuint attribIndex = static_cast<GLuint>(static_cast<uint8_t>(location)); 179 GLuint buffer = mVertexBuffers[slot]->GetHandle(); 180 uint64_t offset = mVertexBufferOffsets[slot]; 181 182 const VertexBufferInfo& vertexBuffer = mLastPipeline->GetVertexBuffer(slot); 183 uint32_t components = GetVertexFormatInfo(attribute.format).componentCount; 184 GLenum formatType = VertexFormatType(attribute.format); 185 186 GLboolean normalized = VertexFormatIsNormalized(attribute.format); 187 gl.BindBuffer(GL_ARRAY_BUFFER, buffer); 188 if (VertexFormatIsInt(attribute.format)) { 189 gl.VertexAttribIPointer( 190 attribIndex, components, formatType, vertexBuffer.arrayStride, 191 reinterpret_cast<void*>( 192 static_cast<intptr_t>(offset + attribute.offset))); 193 } else { 194 gl.VertexAttribPointer(attribIndex, components, formatType, normalized, 195 vertexBuffer.arrayStride, 196 reinterpret_cast<void*>(static_cast<intptr_t>( 197 offset + attribute.offset))); 198 } 199 } 200 } 201 202 mDirtyVertexBuffers.reset(); 203 } 204 205 private: 206 bool mIndexBufferDirty = false; 207 Buffer* mIndexBuffer = nullptr; 208 209 ityp::bitset<VertexBufferSlot, kMaxVertexBuffers> mDirtyVertexBuffers; 210 ityp::array<VertexBufferSlot, Buffer*, kMaxVertexBuffers> mVertexBuffers; 211 ityp::array<VertexBufferSlot, uint64_t, kMaxVertexBuffers> mVertexBufferOffsets; 212 213 RenderPipelineBase* mLastPipeline = nullptr; 214 }; 215 216 class BindGroupTracker : public BindGroupTrackerBase<false, uint64_t> { 217 public: OnSetPipeline(RenderPipeline * pipeline)218 void OnSetPipeline(RenderPipeline* pipeline) { 219 BindGroupTrackerBase::OnSetPipeline(pipeline); 220 mPipeline = pipeline; 221 } 222 OnSetPipeline(ComputePipeline * pipeline)223 void OnSetPipeline(ComputePipeline* pipeline) { 224 BindGroupTrackerBase::OnSetPipeline(pipeline); 225 mPipeline = pipeline; 226 } 227 Apply(const OpenGLFunctions & gl)228 void Apply(const OpenGLFunctions& gl) { 229 BeforeApply(); 230 for (BindGroupIndex index : 231 IterateBitSet(mDirtyBindGroupsObjectChangedOrIsDynamic)) { 232 ApplyBindGroup(gl, index, mBindGroups[index], mDynamicOffsetCounts[index], 233 mDynamicOffsets[index].data()); 234 } 235 AfterApply(); 236 } 237 238 private: ApplyBindGroup(const OpenGLFunctions & gl,BindGroupIndex index,BindGroupBase * group,uint32_t dynamicOffsetCount,uint64_t * dynamicOffsets)239 void ApplyBindGroup(const OpenGLFunctions& gl, 240 BindGroupIndex index, 241 BindGroupBase* group, 242 uint32_t dynamicOffsetCount, 243 uint64_t* dynamicOffsets) { 244 const auto& indices = ToBackend(mPipelineLayout)->GetBindingIndexInfo()[index]; 245 uint32_t currentDynamicOffsetIndex = 0; 246 247 for (BindingIndex bindingIndex{0}; 248 bindingIndex < group->GetLayout()->GetBindingCount(); ++bindingIndex) { 249 const BindingInfo& bindingInfo = 250 group->GetLayout()->GetBindingInfo(bindingIndex); 251 252 switch (bindingInfo.bindingType) { 253 case BindingInfoType::Buffer: { 254 BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex); 255 GLuint buffer = ToBackend(binding.buffer)->GetHandle(); 256 GLuint index = indices[bindingIndex]; 257 GLuint offset = binding.offset; 258 259 if (bindingInfo.buffer.hasDynamicOffset) { 260 offset += dynamicOffsets[currentDynamicOffsetIndex]; 261 ++currentDynamicOffsetIndex; 262 } 263 264 GLenum target; 265 switch (bindingInfo.buffer.type) { 266 case wgpu::BufferBindingType::Uniform: 267 target = GL_UNIFORM_BUFFER; 268 break; 269 case wgpu::BufferBindingType::Storage: 270 case kInternalStorageBufferBinding: 271 case wgpu::BufferBindingType::ReadOnlyStorage: 272 target = GL_SHADER_STORAGE_BUFFER; 273 break; 274 case wgpu::BufferBindingType::Undefined: 275 UNREACHABLE(); 276 } 277 278 gl.BindBufferRange(target, index, buffer, offset, binding.size); 279 break; 280 } 281 282 case BindingInfoType::Sampler: { 283 Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex)); 284 GLuint samplerIndex = indices[bindingIndex]; 285 286 for (PipelineGL::SamplerUnit unit : 287 mPipeline->GetTextureUnitsForSampler(samplerIndex)) { 288 // Only use filtering for certain texture units, because int 289 // and uint texture are only complete without filtering 290 if (unit.shouldUseFiltering) { 291 gl.BindSampler(unit.unit, sampler->GetFilteringHandle()); 292 } else { 293 gl.BindSampler(unit.unit, sampler->GetNonFilteringHandle()); 294 } 295 } 296 break; 297 } 298 299 case BindingInfoType::Texture: { 300 TextureView* view = 301 ToBackend(group->GetBindingAsTextureView(bindingIndex)); 302 GLuint handle = view->GetHandle(); 303 GLenum target = view->GetGLTarget(); 304 GLuint viewIndex = indices[bindingIndex]; 305 306 for (auto unit : mPipeline->GetTextureUnitsForTextureView(viewIndex)) { 307 gl.ActiveTexture(GL_TEXTURE0 + unit); 308 gl.BindTexture(target, handle); 309 if (ToBackend(view->GetTexture())->GetGLFormat().format == 310 GL_DEPTH_STENCIL) { 311 Aspect aspect = view->GetAspects(); 312 ASSERT(HasOneBit(aspect)); 313 switch (aspect) { 314 case Aspect::None: 315 case Aspect::Color: 316 case Aspect::CombinedDepthStencil: 317 case Aspect::Plane0: 318 case Aspect::Plane1: 319 UNREACHABLE(); 320 case Aspect::Depth: 321 gl.TexParameteri(target, GL_DEPTH_STENCIL_TEXTURE_MODE, 322 GL_DEPTH_COMPONENT); 323 break; 324 case Aspect::Stencil: 325 gl.TexParameteri(target, GL_DEPTH_STENCIL_TEXTURE_MODE, 326 GL_STENCIL_INDEX); 327 break; 328 } 329 } 330 } 331 break; 332 } 333 334 case BindingInfoType::StorageTexture: { 335 TextureView* view = 336 ToBackend(group->GetBindingAsTextureView(bindingIndex)); 337 Texture* texture = ToBackend(view->GetTexture()); 338 GLuint handle = texture->GetHandle(); 339 GLuint imageIndex = indices[bindingIndex]; 340 341 GLenum access; 342 switch (bindingInfo.storageTexture.access) { 343 case wgpu::StorageTextureAccess::WriteOnly: 344 access = GL_WRITE_ONLY; 345 break; 346 case wgpu::StorageTextureAccess::Undefined: 347 UNREACHABLE(); 348 } 349 350 // OpenGL ES only supports either binding a layer or the entire 351 // texture in glBindImageTexture(). 352 GLboolean isLayered; 353 if (view->GetLayerCount() == 1) { 354 isLayered = GL_FALSE; 355 } else if (texture->GetArrayLayers() == view->GetLayerCount()) { 356 isLayered = GL_TRUE; 357 } else { 358 UNREACHABLE(); 359 } 360 361 gl.BindImageTexture(imageIndex, handle, view->GetBaseMipLevel(), 362 isLayered, view->GetBaseArrayLayer(), access, 363 texture->GetGLFormat().internalFormat); 364 break; 365 } 366 367 case BindingInfoType::ExternalTexture: { 368 const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& 369 textureViews = mBindGroups[index] 370 ->GetBindingAsExternalTexture(bindingIndex) 371 ->GetTextureViews(); 372 373 // Only single-plane formats are supported right now, so assert only one 374 // view exists. 375 ASSERT(textureViews[1].Get() == nullptr); 376 ASSERT(textureViews[2].Get() == nullptr); 377 378 TextureView* view = ToBackend(textureViews[0].Get()); 379 GLuint handle = view->GetHandle(); 380 GLenum target = view->GetGLTarget(); 381 GLuint viewIndex = indices[bindingIndex]; 382 383 for (auto unit : mPipeline->GetTextureUnitsForTextureView(viewIndex)) { 384 gl.ActiveTexture(GL_TEXTURE0 + unit); 385 gl.BindTexture(target, handle); 386 } 387 break; 388 } 389 } 390 } 391 } 392 393 PipelineGL* mPipeline = nullptr; 394 }; 395 ResolveMultisampledRenderTargets(const OpenGLFunctions & gl,const BeginRenderPassCmd * renderPass)396 void ResolveMultisampledRenderTargets(const OpenGLFunctions& gl, 397 const BeginRenderPassCmd* renderPass) { 398 ASSERT(renderPass != nullptr); 399 400 GLuint readFbo = 0; 401 GLuint writeFbo = 0; 402 403 for (ColorAttachmentIndex i : 404 IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { 405 if (renderPass->colorAttachments[i].resolveTarget != nullptr) { 406 if (readFbo == 0) { 407 ASSERT(writeFbo == 0); 408 gl.GenFramebuffers(1, &readFbo); 409 gl.GenFramebuffers(1, &writeFbo); 410 } 411 412 const TextureBase* colorTexture = 413 renderPass->colorAttachments[i].view->GetTexture(); 414 ASSERT(colorTexture->IsMultisampledTexture()); 415 ASSERT(colorTexture->GetArrayLayers() == 1); 416 ASSERT(renderPass->colorAttachments[i].view->GetBaseMipLevel() == 0); 417 418 GLuint colorHandle = ToBackend(colorTexture)->GetHandle(); 419 gl.BindFramebuffer(GL_READ_FRAMEBUFFER, readFbo); 420 gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 421 ToBackend(colorTexture)->GetGLTarget(), colorHandle, 0); 422 423 const TextureBase* resolveTexture = 424 renderPass->colorAttachments[i].resolveTarget->GetTexture(); 425 GLuint resolveTextureHandle = ToBackend(resolveTexture)->GetHandle(); 426 GLuint resolveTargetMipmapLevel = 427 renderPass->colorAttachments[i].resolveTarget->GetBaseMipLevel(); 428 gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, writeFbo); 429 if (resolveTexture->GetArrayLayers() == 1) { 430 gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 431 GL_TEXTURE_2D, resolveTextureHandle, 432 resolveTargetMipmapLevel); 433 } else { 434 GLuint resolveTargetArrayLayer = 435 renderPass->colorAttachments[i].resolveTarget->GetBaseArrayLayer(); 436 gl.FramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 437 resolveTextureHandle, resolveTargetMipmapLevel, 438 resolveTargetArrayLayer); 439 } 440 441 gl.BlitFramebuffer(0, 0, renderPass->width, renderPass->height, 0, 0, 442 renderPass->width, renderPass->height, GL_COLOR_BUFFER_BIT, 443 GL_NEAREST); 444 } 445 } 446 447 gl.DeleteFramebuffers(1, &readFbo); 448 gl.DeleteFramebuffers(1, &writeFbo); 449 } 450 451 // OpenGL SPEC requires the source/destination region must be a region that is contained 452 // within srcImage/dstImage. Here the size of the image refers to the virtual size, while 453 // Dawn validates texture copy extent with the physical size, so we need to re-calculate the 454 // texture copy extent to ensure it should fit in the virtual size of the subresource. ComputeTextureCopyExtent(const TextureCopy & textureCopy,const Extent3D & copySize)455 Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, 456 const Extent3D& copySize) { 457 Extent3D validTextureCopyExtent = copySize; 458 const TextureBase* texture = textureCopy.texture.Get(); 459 Extent3D virtualSizeAtLevel = texture->GetMipLevelVirtualSize(textureCopy.mipLevel); 460 ASSERT(textureCopy.origin.x <= virtualSizeAtLevel.width); 461 ASSERT(textureCopy.origin.y <= virtualSizeAtLevel.height); 462 if (copySize.width > virtualSizeAtLevel.width - textureCopy.origin.x) { 463 ASSERT(texture->GetFormat().isCompressed); 464 validTextureCopyExtent.width = virtualSizeAtLevel.width - textureCopy.origin.x; 465 } 466 if (copySize.height > virtualSizeAtLevel.height - textureCopy.origin.y) { 467 ASSERT(texture->GetFormat().isCompressed); 468 validTextureCopyExtent.height = virtualSizeAtLevel.height - textureCopy.origin.y; 469 } 470 471 return validTextureCopyExtent; 472 } 473 CopyTextureToTextureWithBlit(const OpenGLFunctions & gl,const TextureCopy & src,const TextureCopy & dst,const Extent3D & copySize)474 void CopyTextureToTextureWithBlit(const OpenGLFunctions& gl, 475 const TextureCopy& src, 476 const TextureCopy& dst, 477 const Extent3D& copySize) { 478 Texture* srcTexture = ToBackend(src.texture.Get()); 479 Texture* dstTexture = ToBackend(dst.texture.Get()); 480 481 // Generate temporary framebuffers for the blits. 482 GLuint readFBO = 0, drawFBO = 0; 483 gl.GenFramebuffers(1, &readFBO); 484 gl.GenFramebuffers(1, &drawFBO); 485 gl.BindFramebuffer(GL_READ_FRAMEBUFFER, readFBO); 486 gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO); 487 488 // Reset state that may affect glBlitFramebuffer(). 489 gl.Disable(GL_SCISSOR_TEST); 490 GLenum blitMask = 0; 491 if (src.aspect & Aspect::Color) { 492 blitMask |= GL_COLOR_BUFFER_BIT; 493 } 494 if (src.aspect & Aspect::Depth) { 495 blitMask |= GL_DEPTH_BUFFER_BIT; 496 } 497 if (src.aspect & Aspect::Stencil) { 498 blitMask |= GL_STENCIL_BUFFER_BIT; 499 } 500 // Iterate over all layers, doing a single blit for each. 501 for (uint32_t layer = 0; layer < copySize.depthOrArrayLayers; ++layer) { 502 // Bind all required aspects for this layer. 503 for (Aspect aspect : IterateEnumMask(src.aspect)) { 504 GLenum glAttachment; 505 switch (aspect) { 506 case Aspect::Color: 507 glAttachment = GL_COLOR_ATTACHMENT0; 508 break; 509 case Aspect::Depth: 510 glAttachment = GL_DEPTH_ATTACHMENT; 511 break; 512 case Aspect::Stencil: 513 glAttachment = GL_STENCIL_ATTACHMENT; 514 break; 515 case Aspect::CombinedDepthStencil: 516 case Aspect::None: 517 case Aspect::Plane0: 518 case Aspect::Plane1: 519 UNREACHABLE(); 520 } 521 if (srcTexture->GetArrayLayers() == 1 && 522 srcTexture->GetDimension() == wgpu::TextureDimension::e2D) { 523 gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, glAttachment, 524 srcTexture->GetGLTarget(), srcTexture->GetHandle(), 525 src.mipLevel); 526 } else { 527 gl.FramebufferTextureLayer(GL_READ_FRAMEBUFFER, glAttachment, 528 srcTexture->GetHandle(), 529 static_cast<GLint>(src.mipLevel), 530 static_cast<GLint>(src.origin.z + layer)); 531 } 532 if (dstTexture->GetArrayLayers() == 1 && 533 dstTexture->GetDimension() == wgpu::TextureDimension::e2D) { 534 gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment, 535 dstTexture->GetGLTarget(), dstTexture->GetHandle(), 536 dst.mipLevel); 537 } else { 538 gl.FramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, glAttachment, 539 dstTexture->GetHandle(), 540 static_cast<GLint>(dst.mipLevel), 541 static_cast<GLint>(dst.origin.z + layer)); 542 } 543 } 544 gl.BlitFramebuffer(src.origin.x, src.origin.y, src.origin.x + copySize.width, 545 src.origin.y + copySize.height, dst.origin.x, dst.origin.y, 546 dst.origin.x + copySize.width, dst.origin.y + copySize.height, 547 blitMask, GL_NEAREST); 548 } 549 gl.Enable(GL_SCISSOR_TEST); 550 gl.DeleteFramebuffers(1, &readFBO); 551 gl.DeleteFramebuffers(1, &drawFBO); 552 } TextureFormatIsSnorm(wgpu::TextureFormat format)553 bool TextureFormatIsSnorm(wgpu::TextureFormat format) { 554 return format == wgpu::TextureFormat::RGBA8Snorm || 555 format == wgpu::TextureFormat::RG8Snorm || 556 format == wgpu::TextureFormat::R8Snorm; 557 } 558 } // namespace 559 CommandBuffer(CommandEncoder * encoder,const CommandBufferDescriptor * descriptor)560 CommandBuffer::CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor) 561 : CommandBufferBase(encoder, descriptor) { 562 } 563 Execute()564 MaybeError CommandBuffer::Execute() { 565 const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; 566 567 auto LazyClearSyncScope = [](const SyncScopeResourceUsage& scope) { 568 for (size_t i = 0; i < scope.textures.size(); i++) { 569 Texture* texture = ToBackend(scope.textures[i]); 570 571 // Clear subresources that are not render attachments. Render attachments will be 572 // cleared in RecordBeginRenderPass by setting the loadop to clear when the texture 573 // subresource has not been initialized before the render pass. 574 scope.textureUsages[i].Iterate( 575 [&](const SubresourceRange& range, wgpu::TextureUsage usage) { 576 if (usage & ~wgpu::TextureUsage::RenderAttachment) { 577 texture->EnsureSubresourceContentInitialized(range); 578 } 579 }); 580 } 581 582 for (BufferBase* bufferBase : scope.buffers) { 583 ToBackend(bufferBase)->EnsureDataInitialized(); 584 } 585 }; 586 587 size_t nextComputePassNumber = 0; 588 size_t nextRenderPassNumber = 0; 589 590 Command type; 591 while (mCommands.NextCommandId(&type)) { 592 switch (type) { 593 case Command::BeginComputePass: { 594 mCommands.NextCommand<BeginComputePassCmd>(); 595 for (const SyncScopeResourceUsage& scope : 596 GetResourceUsages().computePasses[nextComputePassNumber].dispatchUsages) { 597 LazyClearSyncScope(scope); 598 } 599 DAWN_TRY(ExecuteComputePass()); 600 601 nextComputePassNumber++; 602 break; 603 } 604 605 case Command::BeginRenderPass: { 606 auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>(); 607 LazyClearSyncScope(GetResourceUsages().renderPasses[nextRenderPassNumber]); 608 LazyClearRenderPassAttachments(cmd); 609 DAWN_TRY(ExecuteRenderPass(cmd)); 610 611 nextRenderPassNumber++; 612 break; 613 } 614 615 case Command::CopyBufferToBuffer: { 616 CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>(); 617 if (copy->size == 0) { 618 // Skip no-op copies. 619 break; 620 } 621 622 ToBackend(copy->source)->EnsureDataInitialized(); 623 ToBackend(copy->destination) 624 ->EnsureDataInitializedAsDestination(copy->destinationOffset, copy->size); 625 626 gl.BindBuffer(GL_PIXEL_PACK_BUFFER, ToBackend(copy->source)->GetHandle()); 627 gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 628 ToBackend(copy->destination)->GetHandle()); 629 gl.CopyBufferSubData(GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, 630 copy->sourceOffset, copy->destinationOffset, copy->size); 631 632 gl.BindBuffer(GL_PIXEL_PACK_BUFFER, 0); 633 gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 634 break; 635 } 636 637 case Command::CopyBufferToTexture: { 638 CopyBufferToTextureCmd* copy = mCommands.NextCommand<CopyBufferToTextureCmd>(); 639 if (copy->copySize.width == 0 || copy->copySize.height == 0 || 640 copy->copySize.depthOrArrayLayers == 0) { 641 // Skip no-op copies. 642 continue; 643 } 644 auto& src = copy->source; 645 auto& dst = copy->destination; 646 Buffer* buffer = ToBackend(src.buffer.Get()); 647 648 DAWN_INVALID_IF( 649 dst.aspect == Aspect::Stencil, 650 "Copies to stencil textures are unsupported on the OpenGL backend."); 651 652 ASSERT(dst.aspect == Aspect::Color); 653 654 buffer->EnsureDataInitialized(); 655 SubresourceRange range = GetSubresourcesAffectedByCopy(dst, copy->copySize); 656 if (IsCompleteSubresourceCopiedTo(dst.texture.Get(), copy->copySize, 657 dst.mipLevel)) { 658 dst.texture->SetIsSubresourceContentInitialized(true, range); 659 } else { 660 ToBackend(dst.texture)->EnsureSubresourceContentInitialized(range); 661 } 662 663 gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->GetHandle()); 664 665 TextureDataLayout dataLayout; 666 dataLayout.offset = 0; 667 dataLayout.bytesPerRow = src.bytesPerRow; 668 dataLayout.rowsPerImage = src.rowsPerImage; 669 670 DoTexSubImage(gl, dst, reinterpret_cast<void*>(src.offset), dataLayout, 671 copy->copySize); 672 gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 673 break; 674 } 675 676 case Command::CopyTextureToBuffer: { 677 CopyTextureToBufferCmd* copy = mCommands.NextCommand<CopyTextureToBufferCmd>(); 678 if (copy->copySize.width == 0 || copy->copySize.height == 0 || 679 copy->copySize.depthOrArrayLayers == 0) { 680 // Skip no-op copies. 681 continue; 682 } 683 auto& src = copy->source; 684 auto& dst = copy->destination; 685 auto& copySize = copy->copySize; 686 Texture* texture = ToBackend(src.texture.Get()); 687 Buffer* buffer = ToBackend(dst.buffer.Get()); 688 const Format& formatInfo = texture->GetFormat(); 689 const GLFormat& format = texture->GetGLFormat(); 690 GLenum target = texture->GetGLTarget(); 691 692 // TODO(crbug.com/dawn/667): Implement validation in WebGPU/Compat to 693 // avoid this codepath. OpenGL does not support readback from non-renderable 694 // texture formats. 695 if (formatInfo.isCompressed || 696 (TextureFormatIsSnorm(formatInfo.format) && 697 GetDevice()->IsToggleEnabled(Toggle::DisableSnormRead))) { 698 UNREACHABLE(); 699 } 700 701 buffer->EnsureDataInitializedAsDestination(copy); 702 703 ASSERT(texture->GetDimension() != wgpu::TextureDimension::e1D); 704 SubresourceRange subresources = 705 GetSubresourcesAffectedByCopy(src, copy->copySize); 706 texture->EnsureSubresourceContentInitialized(subresources); 707 // The only way to move data from a texture to a buffer in GL is via 708 // glReadPixels with a pack buffer. Create a temporary FBO for the copy. 709 gl.BindTexture(target, texture->GetHandle()); 710 711 GLuint readFBO = 0; 712 gl.GenFramebuffers(1, &readFBO); 713 gl.BindFramebuffer(GL_READ_FRAMEBUFFER, readFBO); 714 715 const TexelBlockInfo& blockInfo = formatInfo.GetAspectInfo(src.aspect).block; 716 717 gl.BindBuffer(GL_PIXEL_PACK_BUFFER, buffer->GetHandle()); 718 gl.PixelStorei(GL_PACK_ROW_LENGTH, dst.bytesPerRow / blockInfo.byteSize); 719 720 GLenum glAttachment; 721 GLenum glFormat; 722 GLenum glType; 723 switch (src.aspect) { 724 case Aspect::Color: 725 glAttachment = GL_COLOR_ATTACHMENT0; 726 glFormat = format.format; 727 glType = format.type; 728 break; 729 case Aspect::Depth: 730 glAttachment = GL_DEPTH_ATTACHMENT; 731 glFormat = GL_DEPTH_COMPONENT; 732 glType = GL_FLOAT; 733 break; 734 case Aspect::Stencil: 735 glAttachment = GL_STENCIL_ATTACHMENT; 736 glFormat = GL_STENCIL_INDEX; 737 glType = GL_UNSIGNED_BYTE; 738 break; 739 740 case Aspect::CombinedDepthStencil: 741 case Aspect::None: 742 case Aspect::Plane0: 743 case Aspect::Plane1: 744 UNREACHABLE(); 745 } 746 747 uint8_t* offset = 748 reinterpret_cast<uint8_t*>(static_cast<uintptr_t>(dst.offset)); 749 switch (texture->GetDimension()) { 750 case wgpu::TextureDimension::e2D: { 751 if (texture->GetArrayLayers() == 1) { 752 gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, glAttachment, target, 753 texture->GetHandle(), src.mipLevel); 754 gl.ReadPixels(src.origin.x, src.origin.y, copySize.width, 755 copySize.height, glFormat, glType, offset); 756 break; 757 } 758 // Implementation for 2D array is the same as 3D. 759 DAWN_FALLTHROUGH; 760 } 761 762 case wgpu::TextureDimension::e3D: { 763 const uint64_t bytesPerImage = dst.bytesPerRow * dst.rowsPerImage; 764 for (uint32_t z = 0; z < copySize.depthOrArrayLayers; ++z) { 765 gl.FramebufferTextureLayer(GL_READ_FRAMEBUFFER, glAttachment, 766 texture->GetHandle(), src.mipLevel, 767 src.origin.z + z); 768 gl.ReadPixels(src.origin.x, src.origin.y, copySize.width, 769 copySize.height, glFormat, glType, offset); 770 771 offset += bytesPerImage; 772 } 773 break; 774 } 775 776 case wgpu::TextureDimension::e1D: 777 UNREACHABLE(); 778 } 779 780 gl.PixelStorei(GL_PACK_ROW_LENGTH, 0); 781 782 gl.BindBuffer(GL_PIXEL_PACK_BUFFER, 0); 783 gl.DeleteFramebuffers(1, &readFBO); 784 break; 785 } 786 787 case Command::CopyTextureToTexture: { 788 CopyTextureToTextureCmd* copy = 789 mCommands.NextCommand<CopyTextureToTextureCmd>(); 790 if (copy->copySize.width == 0 || copy->copySize.height == 0 || 791 copy->copySize.depthOrArrayLayers == 0) { 792 // Skip no-op copies. 793 continue; 794 } 795 auto& src = copy->source; 796 auto& dst = copy->destination; 797 798 // TODO(crbug.com/dawn/817): add workaround for the case that imageExtentSrc 799 // is not equal to imageExtentDst. For example when copySize fits in the virtual 800 // size of the source image but does not fit in the one of the destination 801 // image. 802 Extent3D copySize = ComputeTextureCopyExtent(dst, copy->copySize); 803 Texture* srcTexture = ToBackend(src.texture.Get()); 804 Texture* dstTexture = ToBackend(dst.texture.Get()); 805 806 SubresourceRange srcRange = GetSubresourcesAffectedByCopy(src, copy->copySize); 807 SubresourceRange dstRange = GetSubresourcesAffectedByCopy(dst, copy->copySize); 808 809 srcTexture->EnsureSubresourceContentInitialized(srcRange); 810 if (IsCompleteSubresourceCopiedTo(dstTexture, copySize, dst.mipLevel)) { 811 dstTexture->SetIsSubresourceContentInitialized(true, dstRange); 812 } else { 813 dstTexture->EnsureSubresourceContentInitialized(dstRange); 814 } 815 if (gl.IsAtLeastGL(4, 3) || gl.IsAtLeastGLES(3, 2)) { 816 gl.CopyImageSubData(srcTexture->GetHandle(), srcTexture->GetGLTarget(), 817 src.mipLevel, src.origin.x, src.origin.y, src.origin.z, 818 dstTexture->GetHandle(), dstTexture->GetGLTarget(), 819 dst.mipLevel, dst.origin.x, dst.origin.y, dst.origin.z, 820 copySize.width, copySize.height, 821 copy->copySize.depthOrArrayLayers); 822 } else { 823 CopyTextureToTextureWithBlit(gl, src, dst, copySize); 824 } 825 break; 826 } 827 828 case Command::ClearBuffer: { 829 ClearBufferCmd* cmd = mCommands.NextCommand<ClearBufferCmd>(); 830 if (cmd->size == 0) { 831 // Skip no-op fills. 832 break; 833 } 834 Buffer* dstBuffer = ToBackend(cmd->buffer.Get()); 835 836 bool clearedToZero = 837 dstBuffer->EnsureDataInitializedAsDestination(cmd->offset, cmd->size); 838 839 if (!clearedToZero) { 840 const std::vector<uint8_t> clearValues(cmd->size, 0u); 841 gl.BindBuffer(GL_ARRAY_BUFFER, dstBuffer->GetHandle()); 842 gl.BufferSubData(GL_ARRAY_BUFFER, cmd->offset, cmd->size, 843 clearValues.data()); 844 } 845 846 break; 847 } 848 849 case Command::ResolveQuerySet: { 850 // TODO(crbug.com/dawn/434): Resolve non-precise occlusion query. 851 SkipCommand(&mCommands, type); 852 break; 853 } 854 855 case Command::WriteTimestamp: { 856 return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented"); 857 } 858 859 case Command::InsertDebugMarker: 860 case Command::PopDebugGroup: 861 case Command::PushDebugGroup: { 862 // Due to lack of linux driver support for GL_EXT_debug_marker 863 // extension these functions are skipped. 864 SkipCommand(&mCommands, type); 865 break; 866 } 867 868 case Command::WriteBuffer: { 869 WriteBufferCmd* write = mCommands.NextCommand<WriteBufferCmd>(); 870 uint64_t offset = write->offset; 871 uint64_t size = write->size; 872 if (size == 0) { 873 continue; 874 } 875 876 Buffer* dstBuffer = ToBackend(write->buffer.Get()); 877 uint8_t* data = mCommands.NextData<uint8_t>(size); 878 dstBuffer->EnsureDataInitializedAsDestination(offset, size); 879 880 gl.BindBuffer(GL_ARRAY_BUFFER, dstBuffer->GetHandle()); 881 gl.BufferSubData(GL_ARRAY_BUFFER, offset, size, data); 882 break; 883 } 884 885 default: 886 UNREACHABLE(); 887 } 888 } 889 890 return {}; 891 } 892 ExecuteComputePass()893 MaybeError CommandBuffer::ExecuteComputePass() { 894 const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; 895 ComputePipeline* lastPipeline = nullptr; 896 BindGroupTracker bindGroupTracker = {}; 897 898 Command type; 899 while (mCommands.NextCommandId(&type)) { 900 switch (type) { 901 case Command::EndComputePass: { 902 mCommands.NextCommand<EndComputePassCmd>(); 903 return {}; 904 } 905 906 case Command::Dispatch: { 907 DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>(); 908 bindGroupTracker.Apply(gl); 909 910 gl.DispatchCompute(dispatch->x, dispatch->y, dispatch->z); 911 gl.MemoryBarrier(GL_ALL_BARRIER_BITS); 912 break; 913 } 914 915 case Command::DispatchIndirect: { 916 DispatchIndirectCmd* dispatch = mCommands.NextCommand<DispatchIndirectCmd>(); 917 bindGroupTracker.Apply(gl); 918 919 uint64_t indirectBufferOffset = dispatch->indirectOffset; 920 Buffer* indirectBuffer = ToBackend(dispatch->indirectBuffer.Get()); 921 922 gl.BindBuffer(GL_DISPATCH_INDIRECT_BUFFER, indirectBuffer->GetHandle()); 923 gl.DispatchComputeIndirect(static_cast<GLintptr>(indirectBufferOffset)); 924 gl.MemoryBarrier(GL_ALL_BARRIER_BITS); 925 break; 926 } 927 928 case Command::SetComputePipeline: { 929 SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>(); 930 lastPipeline = ToBackend(cmd->pipeline).Get(); 931 lastPipeline->ApplyNow(); 932 933 bindGroupTracker.OnSetPipeline(lastPipeline); 934 break; 935 } 936 937 case Command::SetBindGroup: { 938 SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>(); 939 uint32_t* dynamicOffsets = nullptr; 940 if (cmd->dynamicOffsetCount > 0) { 941 dynamicOffsets = mCommands.NextData<uint32_t>(cmd->dynamicOffsetCount); 942 } 943 bindGroupTracker.OnSetBindGroup(cmd->index, cmd->group.Get(), 944 cmd->dynamicOffsetCount, dynamicOffsets); 945 break; 946 } 947 948 case Command::InsertDebugMarker: 949 case Command::PopDebugGroup: 950 case Command::PushDebugGroup: { 951 // Due to lack of linux driver support for GL_EXT_debug_marker 952 // extension these functions are skipped. 953 SkipCommand(&mCommands, type); 954 break; 955 } 956 957 case Command::WriteTimestamp: { 958 return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented"); 959 } 960 961 default: 962 UNREACHABLE(); 963 } 964 } 965 966 // EndComputePass should have been called 967 UNREACHABLE(); 968 } 969 ExecuteRenderPass(BeginRenderPassCmd * renderPass)970 MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass) { 971 const OpenGLFunctions& gl = ToBackend(GetDevice())->gl; 972 GLuint fbo = 0; 973 974 // Create the framebuffer used for this render pass and calls the correct glDrawBuffers 975 { 976 // TODO(kainino@chromium.org): This is added to possibly work around an issue seen on 977 // Windows/Intel. It should break any feedback loop before the clears, even if there 978 // shouldn't be any negative effects from this. Investigate whether it's actually 979 // needed. 980 gl.BindFramebuffer(GL_READ_FRAMEBUFFER, 0); 981 // TODO(kainino@chromium.org): possible future optimization: create these framebuffers 982 // at Framebuffer build time (or maybe CommandBuffer build time) so they don't have to 983 // be created and destroyed at draw time. 984 gl.GenFramebuffers(1, &fbo); 985 gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); 986 987 // Mapping from attachmentSlot to GL framebuffer attachment points. Defaults to zero 988 // (GL_NONE). 989 ityp::array<ColorAttachmentIndex, GLenum, kMaxColorAttachments> drawBuffers = {}; 990 991 // Construct GL framebuffer 992 993 ColorAttachmentIndex attachmentCount(uint8_t(0)); 994 for (ColorAttachmentIndex i : 995 IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { 996 TextureViewBase* textureView = renderPass->colorAttachments[i].view.Get(); 997 GLuint texture = ToBackend(textureView->GetTexture())->GetHandle(); 998 999 GLenum glAttachment = GL_COLOR_ATTACHMENT0 + static_cast<uint8_t>(i); 1000 1001 // Attach color buffers. 1002 if (textureView->GetTexture()->GetArrayLayers() == 1) { 1003 GLenum target = ToBackend(textureView->GetTexture())->GetGLTarget(); 1004 gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment, target, texture, 1005 textureView->GetBaseMipLevel()); 1006 } else { 1007 gl.FramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, glAttachment, texture, 1008 textureView->GetBaseMipLevel(), 1009 textureView->GetBaseArrayLayer()); 1010 } 1011 drawBuffers[i] = glAttachment; 1012 attachmentCount = i; 1013 attachmentCount++; 1014 } 1015 gl.DrawBuffers(static_cast<uint8_t>(attachmentCount), drawBuffers.data()); 1016 1017 if (renderPass->attachmentState->HasDepthStencilAttachment()) { 1018 TextureViewBase* textureView = renderPass->depthStencilAttachment.view.Get(); 1019 GLuint texture = ToBackend(textureView->GetTexture())->GetHandle(); 1020 const Format& format = textureView->GetTexture()->GetFormat(); 1021 1022 // Attach depth/stencil buffer. 1023 GLenum glAttachment = 0; 1024 if (format.aspects == (Aspect::Depth | Aspect::Stencil)) { 1025 glAttachment = GL_DEPTH_STENCIL_ATTACHMENT; 1026 } else if (format.aspects == Aspect::Depth) { 1027 glAttachment = GL_DEPTH_ATTACHMENT; 1028 } else if (format.aspects == Aspect::Stencil) { 1029 glAttachment = GL_STENCIL_ATTACHMENT; 1030 } else { 1031 UNREACHABLE(); 1032 } 1033 1034 if (textureView->GetTexture()->GetArrayLayers() == 1) { 1035 GLenum target = ToBackend(textureView->GetTexture())->GetGLTarget(); 1036 gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment, target, texture, 1037 textureView->GetBaseMipLevel()); 1038 } else { 1039 gl.FramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, glAttachment, texture, 1040 textureView->GetBaseMipLevel(), 1041 textureView->GetBaseArrayLayer()); 1042 } 1043 } 1044 } 1045 1046 ASSERT(gl.CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 1047 1048 // Set defaults for dynamic state before executing clears and commands. 1049 PersistentPipelineState persistentPipelineState; 1050 persistentPipelineState.SetDefaultState(gl); 1051 gl.BlendColor(0, 0, 0, 0); 1052 gl.Viewport(0, 0, renderPass->width, renderPass->height); 1053 gl.DepthRangef(0.0, 1.0); 1054 gl.Scissor(0, 0, renderPass->width, renderPass->height); 1055 1056 // Clear framebuffer attachments as needed 1057 { 1058 for (ColorAttachmentIndex index : 1059 IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { 1060 uint8_t i = static_cast<uint8_t>(index); 1061 auto* attachmentInfo = &renderPass->colorAttachments[index]; 1062 1063 // Load op - color 1064 if (attachmentInfo->loadOp == wgpu::LoadOp::Clear) { 1065 gl.ColorMask(true, true, true, true); 1066 1067 wgpu::TextureComponentType baseType = 1068 attachmentInfo->view->GetFormat().GetAspectInfo(Aspect::Color).baseType; 1069 switch (baseType) { 1070 case wgpu::TextureComponentType::Float: { 1071 const std::array<float, 4> appliedClearColor = 1072 ConvertToFloatColor(attachmentInfo->clearColor); 1073 gl.ClearBufferfv(GL_COLOR, i, appliedClearColor.data()); 1074 break; 1075 } 1076 case wgpu::TextureComponentType::Uint: { 1077 const std::array<uint32_t, 4> appliedClearColor = 1078 ConvertToUnsignedIntegerColor(attachmentInfo->clearColor); 1079 gl.ClearBufferuiv(GL_COLOR, i, appliedClearColor.data()); 1080 break; 1081 } 1082 case wgpu::TextureComponentType::Sint: { 1083 const std::array<int32_t, 4> appliedClearColor = 1084 ConvertToSignedIntegerColor(attachmentInfo->clearColor); 1085 gl.ClearBufferiv(GL_COLOR, i, appliedClearColor.data()); 1086 break; 1087 } 1088 1089 case wgpu::TextureComponentType::DepthComparison: 1090 UNREACHABLE(); 1091 } 1092 } 1093 1094 if (attachmentInfo->storeOp == wgpu::StoreOp::Discard) { 1095 // TODO(natlee@microsoft.com): call glDiscard to do optimization 1096 } 1097 } 1098 1099 if (renderPass->attachmentState->HasDepthStencilAttachment()) { 1100 auto* attachmentInfo = &renderPass->depthStencilAttachment; 1101 const Format& attachmentFormat = attachmentInfo->view->GetTexture()->GetFormat(); 1102 1103 // Load op - depth/stencil 1104 bool doDepthClear = attachmentFormat.HasDepth() && 1105 (attachmentInfo->depthLoadOp == wgpu::LoadOp::Clear); 1106 bool doStencilClear = attachmentFormat.HasStencil() && 1107 (attachmentInfo->stencilLoadOp == wgpu::LoadOp::Clear); 1108 1109 if (doDepthClear) { 1110 gl.DepthMask(GL_TRUE); 1111 } 1112 if (doStencilClear) { 1113 gl.StencilMask(GetStencilMaskFromStencilFormat(attachmentFormat.format)); 1114 } 1115 1116 if (doDepthClear && doStencilClear) { 1117 gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo->clearDepth, 1118 attachmentInfo->clearStencil); 1119 } else if (doDepthClear) { 1120 gl.ClearBufferfv(GL_DEPTH, 0, &attachmentInfo->clearDepth); 1121 } else if (doStencilClear) { 1122 const GLint clearStencil = attachmentInfo->clearStencil; 1123 gl.ClearBufferiv(GL_STENCIL, 0, &clearStencil); 1124 } 1125 } 1126 } 1127 1128 RenderPipeline* lastPipeline = nullptr; 1129 uint64_t indexBufferBaseOffset = 0; 1130 GLenum indexBufferFormat; 1131 uint32_t indexFormatSize; 1132 1133 VertexStateBufferBindingTracker vertexStateBufferBindingTracker; 1134 BindGroupTracker bindGroupTracker = {}; 1135 1136 auto DoRenderBundleCommand = [&](CommandIterator* iter, Command type) { 1137 switch (type) { 1138 case Command::Draw: { 1139 DrawCmd* draw = iter->NextCommand<DrawCmd>(); 1140 vertexStateBufferBindingTracker.Apply(gl); 1141 bindGroupTracker.Apply(gl); 1142 1143 if (draw->firstInstance > 0) { 1144 gl.DrawArraysInstancedBaseInstance( 1145 lastPipeline->GetGLPrimitiveTopology(), draw->firstVertex, 1146 draw->vertexCount, draw->instanceCount, draw->firstInstance); 1147 } else { 1148 // This branch is only needed on OpenGL < 4.2 1149 gl.DrawArraysInstanced(lastPipeline->GetGLPrimitiveTopology(), 1150 draw->firstVertex, draw->vertexCount, 1151 draw->instanceCount); 1152 } 1153 break; 1154 } 1155 1156 case Command::DrawIndexed: { 1157 DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>(); 1158 vertexStateBufferBindingTracker.Apply(gl); 1159 bindGroupTracker.Apply(gl); 1160 1161 if (draw->firstInstance > 0) { 1162 gl.DrawElementsInstancedBaseVertexBaseInstance( 1163 lastPipeline->GetGLPrimitiveTopology(), draw->indexCount, 1164 indexBufferFormat, 1165 reinterpret_cast<void*>(draw->firstIndex * indexFormatSize + 1166 indexBufferBaseOffset), 1167 draw->instanceCount, draw->baseVertex, draw->firstInstance); 1168 } else { 1169 // This branch is only needed on OpenGL < 4.2; ES < 3.2 1170 if (draw->baseVertex != 0) { 1171 gl.DrawElementsInstancedBaseVertex( 1172 lastPipeline->GetGLPrimitiveTopology(), draw->indexCount, 1173 indexBufferFormat, 1174 reinterpret_cast<void*>(draw->firstIndex * indexFormatSize + 1175 indexBufferBaseOffset), 1176 draw->instanceCount, draw->baseVertex); 1177 } else { 1178 // This branch is only needed on OpenGL < 3.2; ES < 3.2 1179 gl.DrawElementsInstanced( 1180 lastPipeline->GetGLPrimitiveTopology(), draw->indexCount, 1181 indexBufferFormat, 1182 reinterpret_cast<void*>(draw->firstIndex * indexFormatSize + 1183 indexBufferBaseOffset), 1184 draw->instanceCount); 1185 } 1186 } 1187 break; 1188 } 1189 1190 case Command::DrawIndirect: { 1191 DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>(); 1192 vertexStateBufferBindingTracker.Apply(gl); 1193 bindGroupTracker.Apply(gl); 1194 1195 uint64_t indirectBufferOffset = draw->indirectOffset; 1196 Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get()); 1197 1198 gl.BindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuffer->GetHandle()); 1199 gl.DrawArraysIndirect( 1200 lastPipeline->GetGLPrimitiveTopology(), 1201 reinterpret_cast<void*>(static_cast<intptr_t>(indirectBufferOffset))); 1202 break; 1203 } 1204 1205 case Command::DrawIndexedIndirect: { 1206 DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>(); 1207 1208 vertexStateBufferBindingTracker.Apply(gl); 1209 bindGroupTracker.Apply(gl); 1210 1211 Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get()); 1212 ASSERT(indirectBuffer != nullptr); 1213 1214 gl.BindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuffer->GetHandle()); 1215 gl.DrawElementsIndirect( 1216 lastPipeline->GetGLPrimitiveTopology(), indexBufferFormat, 1217 reinterpret_cast<void*>(static_cast<intptr_t>(draw->indirectOffset))); 1218 break; 1219 } 1220 1221 case Command::InsertDebugMarker: 1222 case Command::PopDebugGroup: 1223 case Command::PushDebugGroup: { 1224 // Due to lack of linux driver support for GL_EXT_debug_marker 1225 // extension these functions are skipped. 1226 SkipCommand(iter, type); 1227 break; 1228 } 1229 1230 case Command::SetRenderPipeline: { 1231 SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>(); 1232 lastPipeline = ToBackend(cmd->pipeline).Get(); 1233 lastPipeline->ApplyNow(persistentPipelineState); 1234 1235 vertexStateBufferBindingTracker.OnSetPipeline(lastPipeline); 1236 bindGroupTracker.OnSetPipeline(lastPipeline); 1237 break; 1238 } 1239 1240 case Command::SetBindGroup: { 1241 SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>(); 1242 uint32_t* dynamicOffsets = nullptr; 1243 if (cmd->dynamicOffsetCount > 0) { 1244 dynamicOffsets = iter->NextData<uint32_t>(cmd->dynamicOffsetCount); 1245 } 1246 bindGroupTracker.OnSetBindGroup(cmd->index, cmd->group.Get(), 1247 cmd->dynamicOffsetCount, dynamicOffsets); 1248 break; 1249 } 1250 1251 case Command::SetIndexBuffer: { 1252 SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>(); 1253 1254 indexBufferBaseOffset = cmd->offset; 1255 indexBufferFormat = IndexFormatType(cmd->format); 1256 indexFormatSize = IndexFormatSize(cmd->format); 1257 vertexStateBufferBindingTracker.OnSetIndexBuffer(cmd->buffer.Get()); 1258 break; 1259 } 1260 1261 case Command::SetVertexBuffer: { 1262 SetVertexBufferCmd* cmd = iter->NextCommand<SetVertexBufferCmd>(); 1263 vertexStateBufferBindingTracker.OnSetVertexBuffer(cmd->slot, cmd->buffer.Get(), 1264 cmd->offset); 1265 break; 1266 } 1267 1268 default: 1269 UNREACHABLE(); 1270 break; 1271 } 1272 }; 1273 1274 Command type; 1275 while (mCommands.NextCommandId(&type)) { 1276 switch (type) { 1277 case Command::EndRenderPass: { 1278 mCommands.NextCommand<EndRenderPassCmd>(); 1279 1280 if (renderPass->attachmentState->GetSampleCount() > 1) { 1281 ResolveMultisampledRenderTargets(gl, renderPass); 1282 } 1283 gl.DeleteFramebuffers(1, &fbo); 1284 return {}; 1285 } 1286 1287 case Command::SetStencilReference: { 1288 SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>(); 1289 persistentPipelineState.SetStencilReference(gl, cmd->reference); 1290 break; 1291 } 1292 1293 case Command::SetViewport: { 1294 SetViewportCmd* cmd = mCommands.NextCommand<SetViewportCmd>(); 1295 if (gl.IsAtLeastGL(4, 1)) { 1296 gl.ViewportIndexedf(0, cmd->x, cmd->y, cmd->width, cmd->height); 1297 } else { 1298 // Floating-point viewport coords are unsupported on OpenGL ES, but 1299 // truncation is ok because other APIs do not guarantee subpixel precision 1300 // either. 1301 gl.Viewport(static_cast<int>(cmd->x), static_cast<int>(cmd->y), 1302 static_cast<int>(cmd->width), static_cast<int>(cmd->height)); 1303 } 1304 gl.DepthRangef(cmd->minDepth, cmd->maxDepth); 1305 break; 1306 } 1307 1308 case Command::SetScissorRect: { 1309 SetScissorRectCmd* cmd = mCommands.NextCommand<SetScissorRectCmd>(); 1310 gl.Scissor(cmd->x, cmd->y, cmd->width, cmd->height); 1311 break; 1312 } 1313 1314 case Command::SetBlendConstant: { 1315 SetBlendConstantCmd* cmd = mCommands.NextCommand<SetBlendConstantCmd>(); 1316 const std::array<float, 4> blendColor = ConvertToFloatColor(cmd->color); 1317 gl.BlendColor(blendColor[0], blendColor[1], blendColor[2], blendColor[3]); 1318 break; 1319 } 1320 1321 case Command::ExecuteBundles: { 1322 ExecuteBundlesCmd* cmd = mCommands.NextCommand<ExecuteBundlesCmd>(); 1323 auto bundles = mCommands.NextData<Ref<RenderBundleBase>>(cmd->count); 1324 1325 for (uint32_t i = 0; i < cmd->count; ++i) { 1326 CommandIterator* iter = bundles[i]->GetCommands(); 1327 iter->Reset(); 1328 while (iter->NextCommandId(&type)) { 1329 DoRenderBundleCommand(iter, type); 1330 } 1331 } 1332 break; 1333 } 1334 1335 case Command::BeginOcclusionQuery: { 1336 return DAWN_UNIMPLEMENTED_ERROR("BeginOcclusionQuery unimplemented."); 1337 } 1338 1339 case Command::EndOcclusionQuery: { 1340 return DAWN_UNIMPLEMENTED_ERROR("EndOcclusionQuery unimplemented."); 1341 } 1342 1343 case Command::WriteTimestamp: 1344 return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented"); 1345 1346 default: { 1347 DoRenderBundleCommand(&mCommands, type); 1348 break; 1349 } 1350 } 1351 } 1352 1353 // EndRenderPass should have been called 1354 UNREACHABLE(); 1355 } 1356 DoTexSubImage(const OpenGLFunctions & gl,const TextureCopy & destination,const void * data,const TextureDataLayout & dataLayout,const Extent3D & copySize)1357 void DoTexSubImage(const OpenGLFunctions& gl, 1358 const TextureCopy& destination, 1359 const void* data, 1360 const TextureDataLayout& dataLayout, 1361 const Extent3D& copySize) { 1362 Texture* texture = ToBackend(destination.texture.Get()); 1363 ASSERT(texture->GetDimension() != wgpu::TextureDimension::e1D); 1364 1365 const GLFormat& format = texture->GetGLFormat(); 1366 GLenum target = texture->GetGLTarget(); 1367 data = static_cast<const uint8_t*>(data) + dataLayout.offset; 1368 gl.ActiveTexture(GL_TEXTURE0); 1369 gl.BindTexture(target, texture->GetHandle()); 1370 const TexelBlockInfo& blockInfo = 1371 texture->GetFormat().GetAspectInfo(destination.aspect).block; 1372 1373 uint32_t x = destination.origin.x; 1374 uint32_t y = destination.origin.y; 1375 uint32_t z = destination.origin.z; 1376 if (texture->GetFormat().isCompressed) { 1377 size_t rowSize = copySize.width / blockInfo.width * blockInfo.byteSize; 1378 Extent3D virtSize = texture->GetMipLevelVirtualSize(destination.mipLevel); 1379 uint32_t width = std::min(copySize.width, virtSize.width - x); 1380 1381 // In GLES glPixelStorei() doesn't affect CompressedTexSubImage*D() and 1382 // GL_UNPACK_COMPRESSED_BLOCK_* isn't defined, so we have to workaround 1383 // this limitation by copying the compressed texture data once per row. 1384 // See OpenGL ES 3.2 SPEC Chapter 8.4.1, "Pixel Storage Modes and Pixel 1385 // Buffer Objects" for more details. For Desktop GL, we use row-by-row 1386 // copies only for uploads where bytesPerRow is not a multiple of byteSize. 1387 if (dataLayout.bytesPerRow % blockInfo.byteSize == 0 && gl.GetVersion().IsDesktop()) { 1388 size_t imageSize = 1389 rowSize * (copySize.height / blockInfo.height) * copySize.depthOrArrayLayers; 1390 1391 uint32_t height = std::min(copySize.height, virtSize.height - y); 1392 1393 gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 1394 dataLayout.bytesPerRow / blockInfo.byteSize * blockInfo.width); 1395 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, blockInfo.byteSize); 1396 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, blockInfo.width); 1397 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, blockInfo.height); 1398 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 1); 1399 1400 if (texture->GetArrayLayers() == 1 && 1401 texture->GetDimension() == wgpu::TextureDimension::e2D) { 1402 gl.CompressedTexSubImage2D(target, destination.mipLevel, x, y, width, height, 1403 format.internalFormat, imageSize, data); 1404 } else { 1405 gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 1406 dataLayout.rowsPerImage * blockInfo.height); 1407 gl.CompressedTexSubImage3D(target, destination.mipLevel, x, y, z, width, height, 1408 copySize.depthOrArrayLayers, format.internalFormat, 1409 imageSize, data); 1410 gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); 1411 } 1412 1413 gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0); 1414 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, 0); 1415 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, 0); 1416 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, 0); 1417 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 0); 1418 } else { 1419 if (texture->GetArrayLayers() == 1 && 1420 texture->GetDimension() == wgpu::TextureDimension::e2D) { 1421 const uint8_t* d = static_cast<const uint8_t*>(data); 1422 1423 for (; y < destination.origin.y + copySize.height; y += blockInfo.height) { 1424 uint32_t height = std::min(blockInfo.height, virtSize.height - y); 1425 gl.CompressedTexSubImage2D(target, destination.mipLevel, x, y, width, 1426 height, format.internalFormat, rowSize, d); 1427 d += dataLayout.bytesPerRow; 1428 } 1429 } else { 1430 const uint8_t* slice = static_cast<const uint8_t*>(data); 1431 1432 for (; z < destination.origin.z + copySize.depthOrArrayLayers; ++z) { 1433 const uint8_t* d = slice; 1434 1435 for (y = destination.origin.y; y < destination.origin.y + copySize.height; 1436 y += blockInfo.height) { 1437 uint32_t height = std::min(blockInfo.height, virtSize.height - y); 1438 gl.CompressedTexSubImage3D(target, destination.mipLevel, x, y, z, width, 1439 height, 1, format.internalFormat, rowSize, 1440 d); 1441 d += dataLayout.bytesPerRow; 1442 } 1443 1444 slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow; 1445 } 1446 } 1447 } 1448 } else { 1449 uint32_t width = copySize.width; 1450 uint32_t height = copySize.height; 1451 if (dataLayout.bytesPerRow % blockInfo.byteSize == 0) { 1452 gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 1453 dataLayout.bytesPerRow / blockInfo.byteSize * blockInfo.width); 1454 if (texture->GetArrayLayers() == 1 && 1455 texture->GetDimension() == wgpu::TextureDimension::e2D) { 1456 gl.TexSubImage2D(target, destination.mipLevel, x, y, width, height, 1457 format.format, format.type, data); 1458 } else { 1459 gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 1460 dataLayout.rowsPerImage * blockInfo.height); 1461 gl.TexSubImage3D(target, destination.mipLevel, x, y, z, width, height, 1462 copySize.depthOrArrayLayers, format.format, format.type, data); 1463 gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); 1464 } 1465 gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0); 1466 } else { 1467 if (texture->GetArrayLayers() == 1 && 1468 texture->GetDimension() == wgpu::TextureDimension::e2D) { 1469 const uint8_t* d = static_cast<const uint8_t*>(data); 1470 for (; y < destination.origin.y + height; ++y) { 1471 gl.TexSubImage2D(target, destination.mipLevel, x, y, width, 1, 1472 format.format, format.type, d); 1473 d += dataLayout.bytesPerRow; 1474 } 1475 } else { 1476 const uint8_t* slice = static_cast<const uint8_t*>(data); 1477 for (; z < destination.origin.z + copySize.depthOrArrayLayers; ++z) { 1478 const uint8_t* d = slice; 1479 for (y = destination.origin.y; y < destination.origin.y + height; ++y) { 1480 gl.TexSubImage3D(target, destination.mipLevel, x, y, z, width, 1, 1, 1481 format.format, format.type, d); 1482 d += dataLayout.bytesPerRow; 1483 } 1484 slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow; 1485 } 1486 } 1487 } 1488 } 1489 } 1490 1491 }} // namespace dawn_native::opengl 1492