• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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