1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ContextVk.cpp:
7 // Implements the class methods for ContextVk.
8 //
9
10 #include "libANGLE/renderer/vulkan/ContextVk.h"
11
12 #include "common/bitset_utils.h"
13 #include "common/debug.h"
14 #include "common/utilities.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Display.h"
17 #include "libANGLE/Program.h"
18 #include "libANGLE/Semaphore.h"
19 #include "libANGLE/Surface.h"
20 #include "libANGLE/angletypes.h"
21 #include "libANGLE/renderer/renderer_utils.h"
22 #include "libANGLE/renderer/vulkan/BufferVk.h"
23 #include "libANGLE/renderer/vulkan/CompilerVk.h"
24 #include "libANGLE/renderer/vulkan/DisplayVk.h"
25 #include "libANGLE/renderer/vulkan/FenceNVVk.h"
26 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
27 #include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
28 #include "libANGLE/renderer/vulkan/OverlayVk.h"
29 #include "libANGLE/renderer/vulkan/ProgramPipelineVk.h"
30 #include "libANGLE/renderer/vulkan/ProgramVk.h"
31 #include "libANGLE/renderer/vulkan/QueryVk.h"
32 #include "libANGLE/renderer/vulkan/RenderbufferVk.h"
33 #include "libANGLE/renderer/vulkan/RendererVk.h"
34 #include "libANGLE/renderer/vulkan/SamplerVk.h"
35 #include "libANGLE/renderer/vulkan/SemaphoreVk.h"
36 #include "libANGLE/renderer/vulkan/ShaderVk.h"
37 #include "libANGLE/renderer/vulkan/SurfaceVk.h"
38 #include "libANGLE/renderer/vulkan/SyncVk.h"
39 #include "libANGLE/renderer/vulkan/TextureVk.h"
40 #include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
41 #include "libANGLE/renderer/vulkan/VertexArrayVk.h"
42
43 #include "libANGLE/trace.h"
44
45 #include <iostream>
46
47 namespace rx
48 {
49
50 namespace
51 {
52 // For DesciptorSetUpdates
53 constexpr size_t kDescriptorBufferInfosInitialSize = 8;
54 constexpr size_t kDescriptorImageInfosInitialSize = 4;
55 constexpr size_t kDescriptorWriteInfosInitialSize =
56 kDescriptorBufferInfosInitialSize + kDescriptorImageInfosInitialSize;
57
58 // For shader uniforms such as gl_DepthRange and the viewport size.
59 struct GraphicsDriverUniforms
60 {
61 std::array<float, 4> viewport;
62
63 // 32 bits for 32 clip planes
64 uint32_t enabledClipPlanes;
65
66 uint32_t advancedBlendEquation;
67 int32_t xfbVerticesPerInstance;
68
69 // Used to replace gl_NumSamples. Because gl_NumSamples cannot be recognized in SPIR-V.
70 int32_t numSamples;
71
72 std::array<int32_t, 4> xfbBufferOffsets;
73
74 // .xy contain packed 8-bit values for atomic counter buffer offsets. These offsets are
75 // within Vulkan's minStorageBufferOffsetAlignment limit and are used to support unaligned
76 // offsets allowed in GL.
77 //
78 // .zw are unused.
79 std::array<uint32_t, 4> acbBufferOffsets;
80
81 // We'll use x, y, z for near / far / diff respectively.
82 std::array<float, 4> depthRange;
83 };
84 static_assert(sizeof(GraphicsDriverUniforms) % (sizeof(uint32_t) * 4) == 0,
85 "GraphicsDriverUniforms should 16bytes aligned");
86
87 // TODO: http://issuetracker.google.com/173636783 Once the bug is fixed, we should remove this.
88 struct GraphicsDriverUniformsExtended
89 {
90 GraphicsDriverUniforms common;
91
92 // Used to flip gl_FragCoord (both .xy for Android pre-rotation; only .y for desktop)
93 std::array<float, 2> halfRenderArea;
94 std::array<float, 2> flipXY;
95 std::array<float, 2> negFlipXY;
96 uint32_t dither;
97 uint32_t padding;
98
99 // Used to pre-rotate gl_FragCoord for swapchain images on Android (a mat2, which is padded to
100 // the size of two vec4's).
101 std::array<float, 8> fragRotation;
102 };
103
104 struct ComputeDriverUniforms
105 {
106 // Atomic counter buffer offsets with the same layout as in GraphicsDriverUniforms.
107 std::array<uint32_t, 4> acbBufferOffsets;
108 };
109
DefaultGLErrorCode(VkResult result)110 GLenum DefaultGLErrorCode(VkResult result)
111 {
112 switch (result)
113 {
114 case VK_ERROR_OUT_OF_HOST_MEMORY:
115 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
116 case VK_ERROR_TOO_MANY_OBJECTS:
117 return GL_OUT_OF_MEMORY;
118 default:
119 return GL_INVALID_OPERATION;
120 }
121 }
122
123 constexpr gl::ShaderMap<vk::ImageLayout> kShaderReadOnlyImageLayouts = {
124 {gl::ShaderType::Vertex, vk::ImageLayout::VertexShaderReadOnly},
125 {gl::ShaderType::TessControl, vk::ImageLayout::PreFragmentShadersReadOnly},
126 {gl::ShaderType::TessEvaluation, vk::ImageLayout::PreFragmentShadersReadOnly},
127 {gl::ShaderType::Geometry, vk::ImageLayout::PreFragmentShadersReadOnly},
128 {gl::ShaderType::Fragment, vk::ImageLayout::FragmentShaderReadOnly},
129 {gl::ShaderType::Compute, vk::ImageLayout::ComputeShaderReadOnly}};
130
131 constexpr gl::ShaderMap<vk::ImageLayout> kShaderWriteImageLayouts = {
132 {gl::ShaderType::Vertex, vk::ImageLayout::VertexShaderWrite},
133 {gl::ShaderType::TessControl, vk::ImageLayout::PreFragmentShadersWrite},
134 {gl::ShaderType::TessEvaluation, vk::ImageLayout::PreFragmentShadersWrite},
135 {gl::ShaderType::Geometry, vk::ImageLayout::PreFragmentShadersWrite},
136 {gl::ShaderType::Fragment, vk::ImageLayout::FragmentShaderWrite},
137 {gl::ShaderType::Compute, vk::ImageLayout::ComputeShaderWrite}};
138
139 constexpr VkBufferUsageFlags kVertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
140 constexpr size_t kDynamicVertexDataSize = 16 * 1024;
141 constexpr size_t kDriverUniformsAllocatorPageSize = 4 * 1024;
142
CanMultiDrawIndirectUseCmd(ContextVk * contextVk,VertexArrayVk * vertexArray,gl::PrimitiveMode mode,GLsizei drawcount,GLsizei stride)143 bool CanMultiDrawIndirectUseCmd(ContextVk *contextVk,
144 VertexArrayVk *vertexArray,
145 gl::PrimitiveMode mode,
146 GLsizei drawcount,
147 GLsizei stride)
148 {
149 // Use the generic implementation if multiDrawIndirect is disabled, if line loop is being used
150 // for multiDraw, if drawcount is greater than maxDrawIndirectCount, or if there are streaming
151 // vertex attributes.
152 ASSERT(drawcount > 1);
153 const bool supportsMultiDrawIndirect =
154 contextVk->getFeatures().supportsMultiDrawIndirect.enabled;
155 const bool isMultiDrawLineLoop = (mode == gl::PrimitiveMode::LineLoop);
156 const bool isDrawCountBeyondLimit =
157 (static_cast<uint32_t>(drawcount) >
158 contextVk->getRenderer()->getPhysicalDeviceProperties().limits.maxDrawIndirectCount);
159 const bool isMultiDrawWithStreamingAttribs = vertexArray->getStreamingVertexAttribsMask().any();
160
161 const bool canMultiDrawIndirectUseCmd = supportsMultiDrawIndirect && !isMultiDrawLineLoop &&
162 !isDrawCountBeyondLimit &&
163 !isMultiDrawWithStreamingAttribs;
164 return canMultiDrawIndirectUseCmd;
165 }
166
GetCoverageSampleCount(const gl::State & glState,FramebufferVk * drawFramebuffer)167 uint32_t GetCoverageSampleCount(const gl::State &glState, FramebufferVk *drawFramebuffer)
168 {
169 if (!glState.isSampleCoverageEnabled())
170 {
171 return 0;
172 }
173
174 // Get a fraction of the samples based on the coverage parameters.
175 // There are multiple ways to obtain an integer value from a float -
176 // truncation, ceil and round
177 //
178 // round() provides a more even distribution of values but doesn't seem to play well
179 // with all vendors (AMD). A way to work around this is to increase the comparison threshold
180 // of deqp tests. Though this takes care of deqp tests other apps would still have issues.
181 //
182 // Truncation provides an uneven distribution near the edges of the interval but seems to
183 // play well with all vendors.
184 //
185 // We are going with truncation for expediency.
186 return static_cast<uint32_t>(glState.getSampleCoverageValue() * drawFramebuffer->getSamples());
187 }
188
ApplySampleCoverage(const gl::State & glState,uint32_t coverageSampleCount,uint32_t maskNumber,uint32_t * maskOut)189 void ApplySampleCoverage(const gl::State &glState,
190 uint32_t coverageSampleCount,
191 uint32_t maskNumber,
192 uint32_t *maskOut)
193 {
194 if (!glState.isSampleCoverageEnabled())
195 {
196 return;
197 }
198
199 uint32_t maskBitOffset = maskNumber * 32;
200 uint32_t coverageMask = coverageSampleCount >= (maskBitOffset + 32)
201 ? std::numeric_limits<uint32_t>::max()
202 : (1u << (coverageSampleCount - maskBitOffset)) - 1;
203
204 if (glState.getSampleCoverageInvert())
205 {
206 coverageMask = ~coverageMask;
207 }
208
209 *maskOut &= coverageMask;
210 }
211
IsRenderPassStartedAndUsesImage(const vk::RenderPassCommandBufferHelper & renderPassCommands,const vk::ImageHelper & image)212 bool IsRenderPassStartedAndUsesImage(const vk::RenderPassCommandBufferHelper &renderPassCommands,
213 const vk::ImageHelper &image)
214 {
215 return renderPassCommands.started() && renderPassCommands.usesImage(image);
216 }
217
218 // When an Android surface is rotated differently than the device's native orientation, ANGLE must
219 // rotate gl_Position in the last pre-rasterization shader and gl_FragCoord in the fragment shader.
220 // Rotation of gl_Position is done in SPIR-V. The following are the rotation matrices for the
221 // fragment shader.
222 //
223 // Note: these are mat2's that are appropriately padded (4 floats per row).
224 using PreRotationMatrixValues = std::array<float, 8>;
225 constexpr angle::PackedEnumMap<rx::SurfaceRotation, PreRotationMatrixValues> kFragRotationMatrices =
226 {{{SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
227 {SurfaceRotation::Rotated90Degrees, {{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
228 {SurfaceRotation::Rotated180Degrees, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
229 {SurfaceRotation::Rotated270Degrees, {{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
230 {SurfaceRotation::FlippedIdentity, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
231 {SurfaceRotation::FlippedRotated90Degrees,
232 {{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
233 {SurfaceRotation::FlippedRotated180Degrees,
234 {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
235 {SurfaceRotation::FlippedRotated270Degrees,
236 {{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}}}};
237
IsRotatedAspectRatio(SurfaceRotation rotation)238 bool IsRotatedAspectRatio(SurfaceRotation rotation)
239 {
240 return ((rotation == SurfaceRotation::Rotated90Degrees) ||
241 (rotation == SurfaceRotation::Rotated270Degrees) ||
242 (rotation == SurfaceRotation::FlippedRotated90Degrees) ||
243 (rotation == SurfaceRotation::FlippedRotated270Degrees));
244 }
245
DetermineSurfaceRotation(gl::Framebuffer * framebuffer,WindowSurfaceVk * windowSurface)246 SurfaceRotation DetermineSurfaceRotation(gl::Framebuffer *framebuffer,
247 WindowSurfaceVk *windowSurface)
248 {
249 if (windowSurface && framebuffer->isDefault())
250 {
251 switch (windowSurface->getPreTransform())
252 {
253 case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
254 // Do not rotate gl_Position (surface matches the device's orientation):
255 return SurfaceRotation::Identity;
256 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
257 // Rotate gl_Position 90 degrees:
258 return SurfaceRotation::Rotated90Degrees;
259 case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
260 // Rotate gl_Position 180 degrees:
261 return SurfaceRotation::Rotated180Degrees;
262 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
263 // Rotate gl_Position 270 degrees:
264 return SurfaceRotation::Rotated270Degrees;
265 default:
266 UNREACHABLE();
267 return SurfaceRotation::Identity;
268 }
269 }
270 else
271 {
272 // Do not rotate gl_Position (offscreen framebuffer):
273 return SurfaceRotation::Identity;
274 }
275 }
276
277 // Should not generate a copy with modern C++.
GetTraceEventName(const char * title,uint32_t counter)278 EventName GetTraceEventName(const char *title, uint32_t counter)
279 {
280 EventName buf;
281 snprintf(buf.data(), kMaxGpuEventNameLen - 1, "%s %u", title, counter);
282 return buf;
283 }
284
GetColorAccess(const gl::State & state,const gl::FramebufferState & framebufferState,const gl::DrawBufferMask & emulatedAlphaMask,bool hasFramebufferFetch,size_t colorIndexGL)285 vk::ResourceAccess GetColorAccess(const gl::State &state,
286 const gl::FramebufferState &framebufferState,
287 const gl::DrawBufferMask &emulatedAlphaMask,
288 bool hasFramebufferFetch,
289 size_t colorIndexGL)
290 {
291 // No access if draw buffer is disabled altogether
292 // Without framebuffer fetch:
293 // No access if color output is masked, or rasterizer discard is enabled
294 // With framebuffer fetch:
295 // Read access if color output is masked, or rasterizer discard is enabled
296
297 if (!framebufferState.getEnabledDrawBuffers().test(colorIndexGL))
298 {
299 return vk::ResourceAccess::Unused;
300 }
301
302 const gl::BlendStateExt &blendStateExt = state.getBlendStateExt();
303 uint8_t colorMask = gl::BlendStateExt::ColorMaskStorage::GetValueIndexed(
304 colorIndexGL, blendStateExt.mColorMask);
305 if (emulatedAlphaMask[colorIndexGL])
306 {
307 colorMask &= ~VK_COLOR_COMPONENT_A_BIT;
308 }
309 const bool isOutputMasked = colorMask == 0 || state.isRasterizerDiscardEnabled();
310
311 if (isOutputMasked)
312 {
313 return hasFramebufferFetch ? vk::ResourceAccess::ReadOnly : vk::ResourceAccess::Unused;
314 }
315
316 return vk::ResourceAccess::Write;
317 }
318
GetDepthAccess(const gl::DepthStencilState & dsState,UpdateDepthFeedbackLoopReason reason)319 vk::ResourceAccess GetDepthAccess(const gl::DepthStencilState &dsState,
320 UpdateDepthFeedbackLoopReason reason)
321 {
322 // Skip if depth/stencil not actually accessed.
323 if (reason == UpdateDepthFeedbackLoopReason::None)
324 {
325 return vk::ResourceAccess::Unused;
326 }
327
328 // Note that clear commands don't respect depth test enable, only the mask
329 // Note Other state can be stated here too in the future, such as rasterizer discard.
330 if (!dsState.depthTest && reason != UpdateDepthFeedbackLoopReason::Clear)
331 {
332 return vk::ResourceAccess::Unused;
333 }
334 return dsState.isDepthMaskedOut() ? vk::ResourceAccess::ReadOnly : vk::ResourceAccess::Write;
335 }
336
GetStencilAccess(const gl::DepthStencilState & dsState,UpdateDepthFeedbackLoopReason reason)337 vk::ResourceAccess GetStencilAccess(const gl::DepthStencilState &dsState,
338 UpdateDepthFeedbackLoopReason reason)
339 {
340 // Skip if depth/stencil not actually accessed.
341 if (reason == UpdateDepthFeedbackLoopReason::None)
342 {
343 return vk::ResourceAccess::Unused;
344 }
345
346 // Note that clear commands don't respect stencil test enable, only the mask
347 // Note Other state can be stated here too in the future, such as rasterizer discard.
348 if (!dsState.stencilTest && reason != UpdateDepthFeedbackLoopReason::Clear)
349 {
350 return vk::ResourceAccess::Unused;
351 }
352
353 return dsState.isStencilNoOp() && dsState.isStencilBackNoOp() ? vk::ResourceAccess::ReadOnly
354 : vk::ResourceAccess::Write;
355 }
356
GetContextPriority(const gl::State & state)357 egl::ContextPriority GetContextPriority(const gl::State &state)
358 {
359 return egl::FromEGLenum<egl::ContextPriority>(state.getContextPriority());
360 }
361
362 template <typename MaskT>
AppendBufferVectorToDesc(vk::DescriptorSetDesc * desc,const gl::BufferVector & buffers,const MaskT & buffersMask,bool isDynamicDescriptor,bool appendOffset)363 void AppendBufferVectorToDesc(vk::DescriptorSetDesc *desc,
364 const gl::BufferVector &buffers,
365 const MaskT &buffersMask,
366 bool isDynamicDescriptor,
367 bool appendOffset)
368 {
369 if (buffersMask.any())
370 {
371 typename MaskT::param_type lastBufferIndex = buffersMask.last();
372 for (typename MaskT::param_type bufferIndex = 0; bufferIndex <= lastBufferIndex;
373 ++bufferIndex)
374 {
375 const gl::OffsetBindingPointer<gl::Buffer> &binding = buffers[bufferIndex];
376 const gl::Buffer *bufferGL = binding.get();
377
378 if (!bufferGL)
379 {
380 desc->append32BitValue(0);
381 continue;
382 }
383
384 BufferVk *bufferVk = vk::GetImpl(bufferGL);
385 if (!bufferVk->isBufferValid())
386 {
387 desc->append32BitValue(0);
388 continue;
389 }
390
391 const vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
392
393 // If this is sub-allocated, we always use the buffer block's serial to increase the
394 // cache hit rate.
395 vk::BufferSerial bufferSerial = bufferHelper.getBlockSerial();
396 desc->appendBufferSerial(bufferSerial);
397
398 ASSERT(static_cast<uint64_t>(binding.getSize()) <=
399 static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()));
400 // binding's size could be 0 if it is bound by glBindBufferBase call. In this case, the
401 // spec says we should use the actual buffer size at the time buffer is been referenced.
402 GLint64 size = binding.getSize() == 0 ? bufferGL->getSize() : binding.getSize();
403 desc->append32BitValue(static_cast<uint32_t>(size));
404
405 if (appendOffset)
406 {
407 ASSERT(static_cast<uint64_t>(binding.getOffset()) <
408 static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()));
409 VkDeviceSize bufferOffset = bufferHelper.getOffset();
410 desc->append32BitValue(static_cast<uint32_t>(bufferOffset + binding.getOffset()));
411 }
412 }
413 }
414
415 desc->append32BitValue(std::numeric_limits<uint32_t>::max());
416 }
417
GetImageReadLayout(TextureVk * textureVk,const gl::ProgramExecutable * executable,size_t textureUnit,PipelineType pipelineType)418 vk::ImageLayout GetImageReadLayout(TextureVk *textureVk,
419 const gl::ProgramExecutable *executable,
420 size_t textureUnit,
421 PipelineType pipelineType)
422 {
423 vk::ImageHelper &image = textureVk->getImage();
424
425 if (textureVk->hasBeenBoundAsImage())
426 {
427 return pipelineType == PipelineType::Compute ? vk::ImageLayout::ComputeShaderWrite
428 : vk::ImageLayout::AllGraphicsShadersWrite;
429 }
430
431 gl::ShaderBitSet remainingShaderBits =
432 executable->getSamplerShaderBitsForTextureUnitIndex(textureUnit);
433 ASSERT(remainingShaderBits.any());
434 gl::ShaderType firstShader = remainingShaderBits.first();
435 gl::ShaderType lastShader = remainingShaderBits.last();
436 remainingShaderBits.reset(firstShader);
437 remainingShaderBits.reset(lastShader);
438
439 if (image.hasRenderPassUsageFlag(vk::RenderPassUsage::RenderTargetAttachment))
440 {
441 // Right now we set this flag only when RenderTargetAttachment is set since we do
442 // not track all textures in the renderpass.
443 image.setRenderPassUsageFlag(vk::RenderPassUsage::TextureSampler);
444
445 if (image.isDepthOrStencil())
446 {
447 if (image.hasRenderPassUsageFlag(vk::RenderPassUsage::ReadOnlyAttachment))
448 {
449 if (firstShader == gl::ShaderType::Fragment)
450 {
451 ASSERT(remainingShaderBits.none() && lastShader == firstShader);
452 return vk::ImageLayout::DSAttachmentReadAndFragmentShaderRead;
453 }
454 return vk::ImageLayout::DSAttachmentReadAndAllShadersRead;
455 }
456
457 return firstShader == gl::ShaderType::Fragment
458 ? vk::ImageLayout::DSAttachmentWriteAndFragmentShaderRead
459 : vk::ImageLayout::DSAttachmentWriteAndAllShadersRead;
460 }
461
462 return firstShader == gl::ShaderType::Fragment
463 ? vk::ImageLayout::ColorAttachmentAndFragmentShaderRead
464 : vk::ImageLayout::ColorAttachmentAndAllShadersRead;
465 }
466
467 if (image.isDepthOrStencil())
468 {
469 // We always use a depth-stencil read-only layout for any depth Textures to simplify
470 // our implementation's handling of depth-stencil read-only mode. We don't have to
471 // split a RenderPass to transition a depth texture from shader-read to read-only.
472 // This improves performance in Manhattan. Future optimizations are likely possible
473 // here including using specialized barriers without breaking the RenderPass.
474 if (firstShader == gl::ShaderType::Fragment)
475 {
476 ASSERT(remainingShaderBits.none() && lastShader == firstShader);
477 return vk::ImageLayout::DSAttachmentReadAndFragmentShaderRead;
478 }
479 return vk::ImageLayout::DSAttachmentReadAndAllShadersRead;
480 }
481
482 // We barrier against either:
483 // - Vertex only
484 // - Fragment only
485 // - Pre-fragment only (vertex, geometry and tessellation together)
486 if (remainingShaderBits.any() || firstShader != lastShader)
487 {
488 return lastShader == gl::ShaderType::Fragment ? vk::ImageLayout::AllGraphicsShadersReadOnly
489 : vk::ImageLayout::PreFragmentShadersReadOnly;
490 }
491
492 return kShaderReadOnlyImageLayouts[firstShader];
493 }
494
GetImageWriteLayoutAndSubresource(const gl::ImageUnit & imageUnit,vk::ImageHelper & image,gl::ShaderBitSet shaderStages,gl::LevelIndex * levelOut,uint32_t * layerStartOut,uint32_t * layerCountOut)495 vk::ImageLayout GetImageWriteLayoutAndSubresource(const gl::ImageUnit &imageUnit,
496 vk::ImageHelper &image,
497 gl::ShaderBitSet shaderStages,
498 gl::LevelIndex *levelOut,
499 uint32_t *layerStartOut,
500 uint32_t *layerCountOut)
501 {
502 *levelOut = gl::LevelIndex(static_cast<uint32_t>(imageUnit.level));
503
504 *layerStartOut = 0;
505 *layerCountOut = image.getLayerCount();
506 if (imageUnit.layered)
507 {
508 *layerStartOut = imageUnit.layered;
509 *layerCountOut = 1;
510 }
511
512 gl::ShaderType firstShader = shaderStages.first();
513 gl::ShaderType lastShader = shaderStages.last();
514 shaderStages.reset(firstShader);
515 shaderStages.reset(lastShader);
516 // We barrier against either:
517 // - Vertex only
518 // - Fragment only
519 // - Pre-fragment only (vertex, geometry and tessellation together)
520 if (shaderStages.any() || firstShader != lastShader)
521 {
522 return lastShader == gl::ShaderType::Fragment ? vk::ImageLayout::AllGraphicsShadersWrite
523 : vk::ImageLayout::PreFragmentShadersWrite;
524 }
525
526 return kShaderWriteImageLayouts[firstShader];
527 }
528
OnTextureBufferRead(ContextVk * contextVk,BufferVk * bufferVk,gl::ShaderBitSet stages,vk::CommandBufferHelperCommon * commandBufferHelper)529 void OnTextureBufferRead(ContextVk *contextVk,
530 BufferVk *bufferVk,
531 gl::ShaderBitSet stages,
532 vk::CommandBufferHelperCommon *commandBufferHelper)
533 {
534 vk::BufferHelper &buffer = bufferVk->getBuffer();
535
536 ASSERT(stages.any());
537
538 // TODO: accept multiple stages in bufferRead. http://anglebug.com/3573
539 for (gl::ShaderType stage : stages)
540 {
541 // Note: if another range of the same buffer is simultaneously used for storage,
542 // such as for transform feedback output, or SSBO, unnecessary barriers can be
543 // generated.
544 commandBufferHelper->bufferRead(contextVk, VK_ACCESS_SHADER_READ_BIT,
545 vk::GetPipelineStage(stage), &buffer);
546 }
547 }
548
OnImageBufferWrite(ContextVk * contextVk,BufferVk * bufferVk,gl::ShaderBitSet stages,vk::CommandBufferHelperCommon * commandBufferHelper)549 void OnImageBufferWrite(ContextVk *contextVk,
550 BufferVk *bufferVk,
551 gl::ShaderBitSet stages,
552 vk::CommandBufferHelperCommon *commandBufferHelper)
553 {
554 vk::BufferHelper &buffer = bufferVk->getBuffer();
555
556 // TODO: accept multiple stages in bufferWrite. http://anglebug.com/3573
557 for (gl::ShaderType stage : stages)
558 {
559 commandBufferHelper->bufferWrite(
560 contextVk, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
561 vk::GetPipelineStage(stage), vk::AliasingMode::Disallowed, &buffer);
562 }
563 }
564
565 constexpr angle::PackedEnumMap<RenderPassClosureReason, const char *> kRenderPassClosureReason = {{
566 {RenderPassClosureReason::AlreadySpecifiedElsewhere, nullptr},
567 {RenderPassClosureReason::ContextDestruction, "Render pass closed due to context destruction"},
568 {RenderPassClosureReason::ContextChange, "Render pass closed due to context change"},
569 {RenderPassClosureReason::GLFlush, "Render pass closed due to glFlush()"},
570 {RenderPassClosureReason::GLFinish, "Render pass closed due to glFinish()"},
571 {RenderPassClosureReason::EGLSwapBuffers, "Render pass closed due to eglSwapBuffers()"},
572 {RenderPassClosureReason::EGLWaitClient, "Render pass closed due to eglWaitClient()"},
573 {RenderPassClosureReason::FramebufferBindingChange,
574 "Render pass closed due to framebuffer binding change"},
575 {RenderPassClosureReason::FramebufferChange, "Render pass closed due to framebuffer change"},
576 {RenderPassClosureReason::NewRenderPass,
577 "Render pass closed due to starting a new render pass"},
578 {RenderPassClosureReason::BufferUseThenXfbWrite,
579 "Render pass closed due to buffer use as transform feedback output after prior use in render "
580 "pass"},
581 {RenderPassClosureReason::XfbWriteThenVertexIndexBuffer,
582 "Render pass closed due to transform feedback buffer use as vertex/index input"},
583 {RenderPassClosureReason::XfbWriteThenIndirectDrawBuffer,
584 "Render pass closed due to indirect draw buffer previously used as transform feedback output "
585 "in render pass"},
586 {RenderPassClosureReason::XfbResumeAfterDrawBasedClear,
587 "Render pass closed due to transform feedback resume after clear through draw"},
588 {RenderPassClosureReason::DepthStencilUseInFeedbackLoop,
589 "Render pass closed due to depth/stencil attachment use under feedback loop"},
590 {RenderPassClosureReason::DepthStencilWriteAfterFeedbackLoop,
591 "Render pass closed due to depth/stencil attachment write after feedback loop"},
592 {RenderPassClosureReason::PipelineBindWhileXfbActive,
593 "Render pass closed due to graphics pipeline change while transform feedback is active"},
594 {RenderPassClosureReason::BufferWriteThenMap,
595 "Render pass closed due to mapping buffer being written to by said render pass"},
596 {RenderPassClosureReason::BufferUseThenOutOfRPRead,
597 "Render pass closed due to non-render-pass read of buffer that was written to in render pass"},
598 {RenderPassClosureReason::BufferUseThenOutOfRPWrite,
599 "Render pass closed due to non-render-pass write of buffer that was used in render pass"},
600 {RenderPassClosureReason::ImageUseThenOutOfRPRead,
601 "Render pass closed due to non-render-pass read of image that was used in render pass"},
602 {RenderPassClosureReason::ImageUseThenOutOfRPWrite,
603 "Render pass closed due to non-render-pass write of image that was used in render pass"},
604 {RenderPassClosureReason::XfbWriteThenComputeRead,
605 "Render pass closed due to compute read of buffer previously used as transform feedback "
606 "output in render pass"},
607 {RenderPassClosureReason::XfbWriteThenIndirectDispatchBuffer,
608 "Render pass closed due to indirect dispatch buffer previously used as transform feedback "
609 "output in render pass"},
610 {RenderPassClosureReason::ImageAttachmentThenComputeRead,
611 "Render pass closed due to compute read of image previously used as framebuffer attachment in "
612 "render pass"},
613 {RenderPassClosureReason::GetQueryResult, "Render pass closed due to getting query result"},
614 {RenderPassClosureReason::BeginNonRenderPassQuery,
615 "Render pass closed due to non-render-pass query begin"},
616 {RenderPassClosureReason::EndNonRenderPassQuery,
617 "Render pass closed due to non-render-pass query end"},
618 {RenderPassClosureReason::TimestampQuery, "Render pass closed due to timestamp query"},
619 {RenderPassClosureReason::GLReadPixels, "Render pass closed due to glReadPixels()"},
620 {RenderPassClosureReason::BufferUseThenReleaseToExternal,
621 "Render pass closed due to buffer (used by render pass) release to external"},
622 {RenderPassClosureReason::ImageUseThenReleaseToExternal,
623 "Render pass closed due to image (used by render pass) release to external"},
624 {RenderPassClosureReason::BufferInUseWhenSynchronizedMap,
625 "Render pass closed due to mapping buffer in use by GPU without GL_MAP_UNSYNCHRONIZED_BIT"},
626 {RenderPassClosureReason::ImageOrphan, "Render pass closed due to EGL image being orphaned"},
627 {RenderPassClosureReason::GLMemoryBarrierThenStorageResource,
628 "Render pass closed due to glMemoryBarrier before storage output in render pass"},
629 {RenderPassClosureReason::StorageResourceUseThenGLMemoryBarrier,
630 "Render pass closed due to glMemoryBarrier after storage output in render pass"},
631 {RenderPassClosureReason::ExternalSemaphoreSignal,
632 "Render pass closed due to external semaphore signal"},
633 {RenderPassClosureReason::SyncObjectInit, "Render pass closed due to sync object insertion"},
634 {RenderPassClosureReason::SyncObjectWithFdInit,
635 "Render pass closed due to sync object with fd insertion"},
636 {RenderPassClosureReason::SyncObjectClientWait,
637 "Render pass closed due to sync object client wait"},
638 {RenderPassClosureReason::SyncObjectServerWait,
639 "Render pass closed due to sync object server wait"},
640 {RenderPassClosureReason::XfbPause, "Render pass closed due to transform feedback pause"},
641 {RenderPassClosureReason::FramebufferFetchEmulation,
642 "Render pass closed due to framebuffer fetch emulation"},
643 {RenderPassClosureReason::ColorBufferInvalidate,
644 "Render pass closed due to glInvalidateFramebuffer() on a color buffer"},
645 {RenderPassClosureReason::GenerateMipmapOnCPU,
646 "Render pass closed due to fallback to CPU when generating mipmaps"},
647 {RenderPassClosureReason::CopyTextureOnCPU,
648 "Render pass closed due to fallback to CPU when copying texture"},
649 {RenderPassClosureReason::TextureReformatToRenderable,
650 "Render pass closed due to reformatting texture to a renderable fallback"},
651 {RenderPassClosureReason::DeviceLocalBufferMap,
652 "Render pass closed due to mapping device local buffer"},
653 {RenderPassClosureReason::PrepareForBlit, "Render pass closed prior to draw-based blit"},
654 {RenderPassClosureReason::PrepareForImageCopy,
655 "Render pass closed prior to draw-based image copy"},
656 {RenderPassClosureReason::TemporaryForImageClear,
657 "Temporary render pass used for image clear closed"},
658 {RenderPassClosureReason::TemporaryForImageCopy,
659 "Temporary render pass used for image copy closed"},
660 {RenderPassClosureReason::TemporaryForOverlayDraw,
661 "Temporary render pass used for overlay draw closed"},
662 }};
663
GetLocalDependencyFlags(ContextVk * contextVk)664 VkDependencyFlags GetLocalDependencyFlags(ContextVk *contextVk)
665 {
666 VkDependencyFlags dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
667 if (contextVk->getCurrentViewCount() > 0)
668 {
669 dependencyFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
670 }
671 return dependencyFlags;
672 }
673 } // anonymous namespace
674
675 // Not necessary once upgraded to C++17.
676 constexpr ContextVk::DirtyBits ContextVk::kIndexAndVertexDirtyBits;
677 constexpr ContextVk::DirtyBits ContextVk::kPipelineDescAndBindingDirtyBits;
678 constexpr ContextVk::DirtyBits ContextVk::kTexturesAndDescSetDirtyBits;
679 constexpr ContextVk::DirtyBits ContextVk::kResourcesAndDescSetDirtyBits;
680 constexpr ContextVk::DirtyBits ContextVk::kXfbBuffersAndDescSetDirtyBits;
681 constexpr ContextVk::DirtyBits ContextVk::kDriverUniformsAndBindingDirtyBits;
682
flushDescriptorSetUpdates()683 void ContextVk::flushDescriptorSetUpdates()
684 {
685 mPerfCounters.writeDescriptorSets +=
686 mUpdateDescriptorSetsBuilder.flushDescriptorSetUpdates(getDevice());
687 }
688
onRenderPassFinished(RenderPassClosureReason reason)689 ANGLE_INLINE void ContextVk::onRenderPassFinished(RenderPassClosureReason reason)
690 {
691 pauseRenderPassQueriesIfActive();
692
693 if (mRenderPassCommandBuffer != nullptr)
694 {
695 // If reason is specified, add it to the command buffer right before ending the render pass,
696 // so it will show up in GPU debuggers.
697 const char *reasonText = kRenderPassClosureReason[reason];
698 if (reasonText)
699 {
700 insertEventMarkerImpl(GL_DEBUG_SOURCE_API, reasonText);
701 }
702 }
703
704 mRenderPassCommandBuffer = nullptr;
705 mGraphicsDirtyBits.set(DIRTY_BIT_RENDER_PASS);
706 }
707
DriverUniformsDescriptorSet()708 ContextVk::DriverUniformsDescriptorSet::DriverUniformsDescriptorSet()
709 : descriptorSet(VK_NULL_HANDLE), currentBuffer(nullptr)
710 {}
711
712 ContextVk::DriverUniformsDescriptorSet::~DriverUniformsDescriptorSet() = default;
713
init(RendererVk * rendererVk)714 void ContextVk::DriverUniformsDescriptorSet::init(RendererVk *rendererVk)
715 {
716 size_t minAlignment = static_cast<size_t>(
717 rendererVk->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
718 dynamicBuffer.init(rendererVk, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, minAlignment,
719 kDriverUniformsAllocatorPageSize, true);
720 descriptorSetCache.clear();
721 }
722
destroy(RendererVk * renderer)723 void ContextVk::DriverUniformsDescriptorSet::destroy(RendererVk *renderer)
724 {
725 descriptorSetLayout.reset();
726 descriptorPoolBinding.reset();
727 dynamicBuffer.destroy(renderer);
728 descriptorSetCache.clear();
729 descriptorSetCache.destroy(renderer);
730 }
731
732 // ContextVk implementation.
ContextVk(const gl::State & state,gl::ErrorSet * errorSet,RendererVk * renderer)733 ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk *renderer)
734 : ContextImpl(state, errorSet),
735 vk::Context(renderer),
736 mGraphicsDirtyBitHandlers{},
737 mComputeDirtyBitHandlers{},
738 mRenderPassCommandBuffer(nullptr),
739 mCurrentGraphicsPipeline(nullptr),
740 mCurrentComputePipeline(nullptr),
741 mCurrentDrawMode(gl::PrimitiveMode::InvalidEnum),
742 mCurrentWindowSurface(nullptr),
743 mCurrentRotationDrawFramebuffer(SurfaceRotation::Identity),
744 mCurrentRotationReadFramebuffer(SurfaceRotation::Identity),
745 mActiveRenderPassQueries{},
746 mLastIndexBufferOffset(nullptr),
747 mCurrentIndexBufferOffset(0),
748 mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum),
749 mXfbBaseVertex(0),
750 mXfbVertexCountPerInstance(0),
751 mClearColorValue{},
752 mClearDepthStencilValue{},
753 mClearColorMasks(0),
754 mFlipYForCurrentSurface(false),
755 mFlipViewportForDrawFramebuffer(false),
756 mFlipViewportForReadFramebuffer(false),
757 mIsAnyHostVisibleBufferWritten(false),
758 mEmulateSeamfulCubeMapSampling(false),
759 mOutsideRenderPassCommands(nullptr),
760 mRenderPassCommands(nullptr),
761 mQueryEventType(GraphicsEventCmdBuf::NotInQueryCmd),
762 mGpuEventsEnabled(false),
763 mHasDeferredFlush(false),
764 mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
765 mGpuEventTimestampOrigin(0),
766 mContextPriority(renderer->getDriverPriority(GetContextPriority(state))),
767 mShareGroupVk(vk::GetImpl(state.getShareGroup()))
768 {
769 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::ContextVk");
770 memset(&mClearColorValue, 0, sizeof(mClearColorValue));
771 memset(&mClearDepthStencilValue, 0, sizeof(mClearDepthStencilValue));
772 memset(&mViewport, 0, sizeof(mViewport));
773 memset(&mScissor, 0, sizeof(mScissor));
774
775 // Ensure viewport is within Vulkan requirements
776 vk::ClampViewport(&mViewport);
777
778 mNonIndexedDirtyBitsMask.set();
779 mNonIndexedDirtyBitsMask.reset(DIRTY_BIT_INDEX_BUFFER);
780
781 mIndexedDirtyBitsMask.set();
782
783 // Once a command buffer is ended, all bindings (through |vkCmdBind*| calls) are lost per Vulkan
784 // spec. Once a new command buffer is allocated, we must make sure every previously bound
785 // resource is bound again.
786 //
787 // Note that currently these dirty bits are set every time a new render pass command buffer is
788 // begun. However, using ANGLE's SecondaryCommandBuffer, the Vulkan command buffer (which is
789 // the primary command buffer) is not ended, so technically we don't need to rebind these.
790 mNewGraphicsCommandBufferDirtyBits = DirtyBits{DIRTY_BIT_RENDER_PASS,
791 DIRTY_BIT_COLOR_ACCESS,
792 DIRTY_BIT_DEPTH_STENCIL_ACCESS,
793 DIRTY_BIT_PIPELINE_BINDING,
794 DIRTY_BIT_TEXTURES,
795 DIRTY_BIT_VERTEX_BUFFERS,
796 DIRTY_BIT_INDEX_BUFFER,
797 DIRTY_BIT_SHADER_RESOURCES,
798 DIRTY_BIT_DESCRIPTOR_SETS,
799 DIRTY_BIT_DRIVER_UNIFORMS_BINDING,
800 DIRTY_BIT_VIEWPORT,
801 DIRTY_BIT_SCISSOR};
802 if (getFeatures().supportsTransformFeedbackExtension.enabled)
803 {
804 mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
805 }
806
807 mNewComputeCommandBufferDirtyBits =
808 DirtyBits{DIRTY_BIT_PIPELINE_BINDING, DIRTY_BIT_TEXTURES, DIRTY_BIT_SHADER_RESOURCES,
809 DIRTY_BIT_DESCRIPTOR_SETS, DIRTY_BIT_DRIVER_UNIFORMS_BINDING};
810
811 mGraphicsDirtyBitHandlers[DIRTY_BIT_MEMORY_BARRIER] =
812 &ContextVk::handleDirtyGraphicsMemoryBarrier;
813 mGraphicsDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] =
814 &ContextVk::handleDirtyGraphicsDefaultAttribs;
815 mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE_DESC] =
816 &ContextVk::handleDirtyGraphicsPipelineDesc;
817 mGraphicsDirtyBitHandlers[DIRTY_BIT_READ_ONLY_DEPTH_FEEDBACK_LOOP_MODE] =
818 &ContextVk::handleDirtyGraphicsReadOnlyDepthFeedbackLoopMode;
819 mGraphicsDirtyBitHandlers[DIRTY_BIT_RENDER_PASS] = &ContextVk::handleDirtyGraphicsRenderPass;
820 mGraphicsDirtyBitHandlers[DIRTY_BIT_EVENT_LOG] = &ContextVk::handleDirtyGraphicsEventLog;
821 mGraphicsDirtyBitHandlers[DIRTY_BIT_COLOR_ACCESS] = &ContextVk::handleDirtyGraphicsColorAccess;
822 mGraphicsDirtyBitHandlers[DIRTY_BIT_DEPTH_STENCIL_ACCESS] =
823 &ContextVk::handleDirtyGraphicsDepthStencilAccess;
824 mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE_BINDING] =
825 &ContextVk::handleDirtyGraphicsPipelineBinding;
826 mGraphicsDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyGraphicsTextures;
827 mGraphicsDirtyBitHandlers[DIRTY_BIT_VERTEX_BUFFERS] =
828 &ContextVk::handleDirtyGraphicsVertexBuffers;
829 mGraphicsDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyGraphicsIndexBuffer;
830 mGraphicsDirtyBitHandlers[DIRTY_BIT_UNIFORMS] = &ContextVk::handleDirtyGraphicsUniforms;
831 mGraphicsDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
832 &ContextVk::handleDirtyGraphicsDriverUniforms;
833 mGraphicsDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS_BINDING] =
834 &ContextVk::handleDirtyGraphicsDriverUniformsBinding;
835 mGraphicsDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
836 &ContextVk::handleDirtyGraphicsShaderResources;
837 mGraphicsDirtyBitHandlers[DIRTY_BIT_FRAMEBUFFER_FETCH_BARRIER] =
838 &ContextVk::handleDirtyGraphicsFramebufferFetchBarrier;
839 mGraphicsDirtyBitHandlers[DIRTY_BIT_BLEND_BARRIER] =
840 &ContextVk::handleDirtyGraphicsBlendBarrier;
841 if (getFeatures().supportsTransformFeedbackExtension.enabled)
842 {
843 mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
844 &ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension;
845 mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME] =
846 &ContextVk::handleDirtyGraphicsTransformFeedbackResume;
847 }
848 else if (getFeatures().emulateTransformFeedback.enabled)
849 {
850 mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
851 &ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation;
852 }
853
854 mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
855 &ContextVk::handleDirtyGraphicsDescriptorSets;
856
857 mGraphicsDirtyBitHandlers[DIRTY_BIT_VIEWPORT] = &ContextVk::handleDirtyGraphicsViewport;
858 mGraphicsDirtyBitHandlers[DIRTY_BIT_SCISSOR] = &ContextVk::handleDirtyGraphicsScissor;
859
860 mComputeDirtyBitHandlers[DIRTY_BIT_MEMORY_BARRIER] =
861 &ContextVk::handleDirtyComputeMemoryBarrier;
862 mComputeDirtyBitHandlers[DIRTY_BIT_EVENT_LOG] = &ContextVk::handleDirtyComputeEventLog;
863 mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE_DESC] = &ContextVk::handleDirtyComputePipelineDesc;
864 mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE_BINDING] =
865 &ContextVk::handleDirtyComputePipelineBinding;
866 mComputeDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyComputeTextures;
867 mComputeDirtyBitHandlers[DIRTY_BIT_UNIFORMS] = &ContextVk::handleDirtyComputeUniforms;
868 mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
869 &ContextVk::handleDirtyComputeDriverUniforms;
870 mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS_BINDING] =
871 &ContextVk::handleDirtyComputeDriverUniformsBinding;
872 mComputeDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
873 &ContextVk::handleDirtyComputeShaderResources;
874 mComputeDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
875 &ContextVk::handleDirtyComputeDescriptorSets;
876
877 mGraphicsDirtyBits = mNewGraphicsCommandBufferDirtyBits;
878 mComputeDirtyBits = mNewComputeCommandBufferDirtyBits;
879
880 mActiveTextures.fill({nullptr, nullptr, true});
881 mActiveImages.fill(nullptr);
882
883 // The following dirty bits don't affect the program pipeline:
884 //
885 // - READ_FRAMEBUFFER_BINDING only affects operations that read from said framebuffer,
886 // - CLEAR_* only affect following clear calls,
887 // - PACK/UNPACK_STATE only affect texture data upload/download,
888 // - *_BINDING only affect descriptor sets.
889 //
890 mPipelineDirtyBitsMask.set();
891 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
892 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_CLEAR_COLOR);
893 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_CLEAR_DEPTH);
894 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_CLEAR_STENCIL);
895 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_UNPACK_STATE);
896 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_UNPACK_BUFFER_BINDING);
897 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_PACK_STATE);
898 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_PACK_BUFFER_BINDING);
899 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_RENDERBUFFER_BINDING);
900 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING);
901 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING);
902 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_SAMPLER_BINDINGS);
903 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
904 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_IMAGE_BINDINGS);
905 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING);
906 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS);
907 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING);
908 mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
909
910 angle::PerfMonitorCounterGroup vulkanGroup;
911 vulkanGroup.name = "vulkan";
912
913 #define ANGLE_ADD_PERF_MONITOR_COUNTER_GROUP(COUNTER) \
914 { \
915 angle::PerfMonitorCounter counter; \
916 counter.name = #COUNTER; \
917 counter.value = 0; \
918 vulkanGroup.counters.push_back(counter); \
919 }
920
921 ANGLE_VK_PERF_COUNTERS_X(ANGLE_ADD_PERF_MONITOR_COUNTER_GROUP)
922
923 #undef ANGLE_ADD_PERF_MONITOR_COUNTER_GROUP
924
925 mPerfMonitorCounters.push_back(vulkanGroup);
926 }
927
928 ContextVk::~ContextVk() = default;
929
onDestroy(const gl::Context * context)930 void ContextVk::onDestroy(const gl::Context *context)
931 {
932 // Remove context from the share group
933 mShareGroupVk->removeContext(this);
934
935 // This will not destroy any resources. It will release them to be collected after finish.
936 mIncompleteTextures.onDestroy(context);
937
938 // Flush and complete current outstanding work before destruction.
939 (void)finishImpl(RenderPassClosureReason::ContextDestruction);
940
941 VkDevice device = getDevice();
942
943 for (DriverUniformsDescriptorSet &driverUniforms : mDriverUniforms)
944 {
945 driverUniforms.destroy(mRenderer);
946 }
947
948 for (vk::DynamicDescriptorPool &dynamicDescriptorPool : mDriverUniformsDescriptorPools)
949 {
950 dynamicDescriptorPool.destroy(device);
951 }
952
953 mDefaultUniformStorage.release(mRenderer);
954 mEmptyBuffer.release(mRenderer);
955
956 for (vk::DynamicBuffer &defaultBuffer : mStreamedVertexBuffers)
957 {
958 defaultBuffer.destroy(mRenderer);
959 }
960
961 for (vk::DynamicQueryPool &queryPool : mQueryPools)
962 {
963 queryPool.destroy(device);
964 }
965
966 // Recycle current commands buffers.
967 mRenderer->recycleOutsideRenderPassCommandBufferHelper(device, &mOutsideRenderPassCommands);
968 mRenderer->recycleRenderPassCommandBufferHelper(device, &mRenderPassCommands);
969
970 mRenderer->releaseSharedResources(&mResourceUseList);
971
972 mUtils.destroy(mRenderer);
973
974 mRenderPassCache.destroy(mRenderer);
975 mShaderLibrary.destroy(device);
976 mGpuEventQueryPool.destroy(device);
977 mCommandPools.outsideRenderPassPool.destroy(device);
978 mCommandPools.renderPassPool.destroy(device);
979
980 ASSERT(mCurrentGarbage.empty());
981 ASSERT(mResourceUseList.empty());
982 }
983
getVertexArray() const984 VertexArrayVk *ContextVk::getVertexArray() const
985 {
986 return vk::GetImpl(mState.getVertexArray());
987 }
988
getDrawFramebuffer() const989 FramebufferVk *ContextVk::getDrawFramebuffer() const
990 {
991 return vk::GetImpl(mState.getDrawFramebuffer());
992 }
993
getProgram() const994 ProgramVk *ContextVk::getProgram() const
995 {
996 return vk::SafeGetImpl(mState.getProgram());
997 }
998
getProgramPipeline() const999 ProgramPipelineVk *ContextVk::getProgramPipeline() const
1000 {
1001 return vk::SafeGetImpl(mState.getProgramPipeline());
1002 }
1003
getIncompleteTexture(const gl::Context * context,gl::TextureType type,gl::SamplerFormat format,gl::Texture ** textureOut)1004 angle::Result ContextVk::getIncompleteTexture(const gl::Context *context,
1005 gl::TextureType type,
1006 gl::SamplerFormat format,
1007 gl::Texture **textureOut)
1008 {
1009 return mIncompleteTextures.getIncompleteTexture(context, type, format, this, textureOut);
1010 }
1011
initialize()1012 angle::Result ContextVk::initialize()
1013 {
1014 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::initialize");
1015
1016 ANGLE_TRY(mQueryPools[gl::QueryType::AnySamples].init(this, VK_QUERY_TYPE_OCCLUSION,
1017 vk::kDefaultOcclusionQueryPoolSize));
1018 ANGLE_TRY(mQueryPools[gl::QueryType::AnySamplesConservative].init(
1019 this, VK_QUERY_TYPE_OCCLUSION, vk::kDefaultOcclusionQueryPoolSize));
1020
1021 // Only initialize the timestamp query pools if the extension is available.
1022 if (mRenderer->getQueueFamilyProperties().timestampValidBits > 0)
1023 {
1024 ANGLE_TRY(mQueryPools[gl::QueryType::Timestamp].init(this, VK_QUERY_TYPE_TIMESTAMP,
1025 vk::kDefaultTimestampQueryPoolSize));
1026 ANGLE_TRY(mQueryPools[gl::QueryType::TimeElapsed].init(this, VK_QUERY_TYPE_TIMESTAMP,
1027 vk::kDefaultTimestampQueryPoolSize));
1028 }
1029
1030 if (getFeatures().supportsTransformFeedbackExtension.enabled)
1031 {
1032 ANGLE_TRY(mQueryPools[gl::QueryType::TransformFeedbackPrimitivesWritten].init(
1033 this, VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT,
1034 vk::kDefaultTransformFeedbackQueryPoolSize));
1035 }
1036
1037 // The primitives generated query is provided through the Vulkan pipeline statistics query if
1038 // supported. TODO: If VK_EXT_primitives_generated_query is supported, use that instead.
1039 // http://anglebug.com/5430
1040 if (getFeatures().supportsPipelineStatisticsQuery.enabled)
1041 {
1042 ANGLE_TRY(mQueryPools[gl::QueryType::PrimitivesGenerated].init(
1043 this, VK_QUERY_TYPE_PIPELINE_STATISTICS, vk::kDefaultPrimitivesGeneratedQueryPoolSize));
1044 }
1045
1046 // Init GLES to Vulkan index type map.
1047 initIndexTypeMap();
1048
1049 // Init driver uniforms and get the descriptor set layouts.
1050 for (PipelineType pipeline : angle::AllEnums<PipelineType>())
1051 {
1052 mDriverUniforms[pipeline].init(mRenderer);
1053
1054 vk::DescriptorSetLayoutDesc desc = getDriverUniformsDescriptorSetDesc();
1055 ANGLE_TRY(getDescriptorSetLayoutCache().getDescriptorSetLayout(
1056 this, desc, &mDriverUniforms[pipeline].descriptorSetLayout));
1057
1058 vk::DescriptorSetLayoutBindingVector bindingVector;
1059 std::vector<VkSampler> immutableSamplers;
1060 desc.unpackBindings(&bindingVector, &immutableSamplers);
1061 std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
1062
1063 for (const VkDescriptorSetLayoutBinding &binding : bindingVector)
1064 {
1065 if (binding.descriptorCount > 0)
1066 {
1067 VkDescriptorPoolSize poolSize = {};
1068
1069 poolSize.type = binding.descriptorType;
1070 poolSize.descriptorCount = binding.descriptorCount;
1071 descriptorPoolSizes.emplace_back(poolSize);
1072 }
1073 }
1074 if (!descriptorPoolSizes.empty())
1075 {
1076 ANGLE_TRY(mDriverUniformsDescriptorPools[pipeline].init(
1077 this, descriptorPoolSizes.data(), descriptorPoolSizes.size(),
1078 mDriverUniforms[pipeline].descriptorSetLayout.get().getHandle()));
1079 }
1080 }
1081
1082 mGraphicsPipelineDesc.reset(new vk::GraphicsPipelineDesc());
1083 mGraphicsPipelineDesc->initDefaults(this);
1084
1085 // Initialize current value/default attribute buffers.
1086 for (vk::DynamicBuffer &buffer : mStreamedVertexBuffers)
1087 {
1088 buffer.init(mRenderer, kVertexBufferUsage, 1, kDynamicVertexDataSize, true);
1089 }
1090
1091 #if ANGLE_ENABLE_VULKAN_GPU_TRACE_EVENTS
1092 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
1093 ASSERT(platform);
1094
1095 // GPU tracing workaround for anglebug.com/2927. The renderer should not emit gpu events
1096 // during platform discovery.
1097 const unsigned char *gpuEventsEnabled =
1098 platform->getTraceCategoryEnabledFlag(platform, "gpu.angle.gpu");
1099 mGpuEventsEnabled = gpuEventsEnabled && *gpuEventsEnabled;
1100 #endif
1101
1102 mEmulateSeamfulCubeMapSampling = shouldEmulateSeamfulCubeMapSampling();
1103
1104 // Assign initial command buffers from queue
1105 ANGLE_TRY(vk::OutsideRenderPassCommandBuffer::InitializeCommandPool(
1106 this, &mCommandPools.outsideRenderPassPool, mRenderer->getDeviceQueueIndex(),
1107 hasProtectedContent()));
1108 ANGLE_TRY(vk::RenderPassCommandBuffer::InitializeCommandPool(
1109 this, &mCommandPools.renderPassPool, mRenderer->getDeviceQueueIndex(),
1110 hasProtectedContent()));
1111 ANGLE_TRY(mRenderer->getOutsideRenderPassCommandBufferHelper(
1112 this, &mCommandPools.outsideRenderPassPool, &mOutsideRenderPassCommands));
1113 ANGLE_TRY(mRenderer->getRenderPassCommandBufferHelper(this, &mCommandPools.renderPassPool,
1114 &mRenderPassCommands));
1115
1116 if (mGpuEventsEnabled)
1117 {
1118 // GPU events should only be available if timestamp queries are available.
1119 ASSERT(mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
1120 // Calculate the difference between CPU and GPU clocks for GPU event reporting.
1121 ANGLE_TRY(mGpuEventQueryPool.init(this, VK_QUERY_TYPE_TIMESTAMP,
1122 vk::kDefaultTimestampQueryPoolSize));
1123 ANGLE_TRY(synchronizeCpuGpuTime());
1124
1125 mPerfCounters.primaryBuffers++;
1126
1127 EventName eventName = GetTraceEventName("Primary", mPerfCounters.primaryBuffers);
1128 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
1129 TRACE_EVENT_PHASE_BEGIN, eventName));
1130 }
1131
1132 size_t minAlignment = static_cast<size_t>(
1133 mRenderer->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
1134 mDefaultUniformStorage.init(mRenderer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, minAlignment,
1135 mRenderer->getDefaultUniformBufferSize(), true);
1136
1137 // Initialize an "empty" buffer for use with default uniform blocks where there are no uniforms,
1138 // or atomic counter buffer array indices that are unused.
1139 constexpr VkBufferUsageFlags kEmptyBufferUsage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
1140 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
1141 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
1142 VkBufferCreateInfo emptyBufferInfo = {};
1143 emptyBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1144 emptyBufferInfo.flags = 0;
1145 emptyBufferInfo.size = 16;
1146 emptyBufferInfo.usage = kEmptyBufferUsage;
1147 emptyBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1148 emptyBufferInfo.queueFamilyIndexCount = 0;
1149 emptyBufferInfo.pQueueFamilyIndices = nullptr;
1150 constexpr VkMemoryPropertyFlags kMemoryType = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
1151 ANGLE_TRY(mEmptyBuffer.init(this, emptyBufferInfo, kMemoryType));
1152
1153 // Add context into the share group
1154 mShareGroupVk->addContext(this);
1155
1156 return angle::Result::Continue;
1157 }
1158
flush(const gl::Context * context)1159 angle::Result ContextVk::flush(const gl::Context *context)
1160 {
1161 const bool isSingleBuffer =
1162 (mCurrentWindowSurface != nullptr) && mCurrentWindowSurface->isSharedPresentMode();
1163
1164 // Don't defer flushes in single-buffer mode. In this mode, the application is not required to
1165 // call eglSwapBuffers(), and glFlush() is expected to ensure that work is submitted.
1166 if (mRenderer->getFeatures().deferFlushUntilEndRenderPass.enabled && hasStartedRenderPass() &&
1167 !isSingleBuffer)
1168 {
1169 mHasDeferredFlush = true;
1170 return angle::Result::Continue;
1171 }
1172
1173 if (mRenderer->getFeatures().swapbuffersOnFlushOrFinishWithSingleBuffer.enabled &&
1174 isSingleBuffer)
1175 {
1176 return mCurrentWindowSurface->onSharedPresentContextFlush(context);
1177 }
1178
1179 return flushImpl(nullptr, RenderPassClosureReason::GLFlush);
1180 }
1181
finish(const gl::Context * context)1182 angle::Result ContextVk::finish(const gl::Context *context)
1183 {
1184 if (mRenderer->getFeatures().swapbuffersOnFlushOrFinishWithSingleBuffer.enabled &&
1185 (mCurrentWindowSurface != nullptr) && mCurrentWindowSurface->isSharedPresentMode())
1186 {
1187 return mCurrentWindowSurface->onSharedPresentContextFlush(context);
1188 }
1189
1190 return finishImpl(RenderPassClosureReason::GLFinish);
1191 }
1192
setupDraw(const gl::Context * context,gl::PrimitiveMode mode,GLint firstVertexOrInvalid,GLsizei vertexOrIndexCount,GLsizei instanceCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,DirtyBits dirtyBitMask)1193 angle::Result ContextVk::setupDraw(const gl::Context *context,
1194 gl::PrimitiveMode mode,
1195 GLint firstVertexOrInvalid,
1196 GLsizei vertexOrIndexCount,
1197 GLsizei instanceCount,
1198 gl::DrawElementsType indexTypeOrInvalid,
1199 const void *indices,
1200 DirtyBits dirtyBitMask)
1201 {
1202 // Set any dirty bits that depend on draw call parameters or other objects.
1203 if (mode != mCurrentDrawMode)
1204 {
1205 invalidateCurrentGraphicsPipeline();
1206 mCurrentDrawMode = mode;
1207 mGraphicsPipelineDesc->updateTopology(&mGraphicsPipelineTransition, mCurrentDrawMode);
1208 }
1209
1210 // Must be called before the command buffer is started. Can call finish.
1211 VertexArrayVk *vertexArrayVk = getVertexArray();
1212 if (vertexArrayVk->getStreamingVertexAttribsMask().any())
1213 {
1214 // All client attribs & any emulated buffered attribs will be updated
1215 ANGLE_TRY(vertexArrayVk->updateStreamedAttribs(context, firstVertexOrInvalid,
1216 vertexOrIndexCount, instanceCount,
1217 indexTypeOrInvalid, indices));
1218
1219 mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
1220 }
1221
1222 ProgramExecutableVk *programExecutableVk = getExecutable();
1223 if (programExecutableVk->hasDirtyUniforms())
1224 {
1225 mGraphicsDirtyBits.set(DIRTY_BIT_UNIFORMS);
1226 }
1227
1228 // Update transform feedback offsets on every draw call when emulating transform feedback. This
1229 // relies on the fact that no geometry/tessellation, indirect or indexed calls are supported in
1230 // ES3.1 (and emulation is not done for ES3.2).
1231 if (getFeatures().emulateTransformFeedback.enabled &&
1232 mState.isTransformFeedbackActiveUnpaused())
1233 {
1234 ASSERT(firstVertexOrInvalid != -1);
1235 mXfbBaseVertex = firstVertexOrInvalid;
1236 mXfbVertexCountPerInstance = vertexOrIndexCount;
1237 invalidateGraphicsDriverUniforms();
1238 }
1239
1240 DirtyBits dirtyBits = mGraphicsDirtyBits & dirtyBitMask;
1241
1242 if (dirtyBits.none())
1243 {
1244 ASSERT(mRenderPassCommandBuffer);
1245 return angle::Result::Continue;
1246 }
1247
1248 // Flush any relevant dirty bits.
1249 for (DirtyBits::Iterator dirtyBitIter = dirtyBits.begin(); dirtyBitIter != dirtyBits.end();
1250 ++dirtyBitIter)
1251 {
1252 ASSERT(mGraphicsDirtyBitHandlers[*dirtyBitIter]);
1253 ANGLE_TRY((this->*mGraphicsDirtyBitHandlers[*dirtyBitIter])(&dirtyBitIter, dirtyBitMask));
1254 }
1255
1256 mGraphicsDirtyBits &= ~dirtyBitMask;
1257
1258 // Render pass must be always available at this point.
1259 ASSERT(mRenderPassCommandBuffer);
1260
1261 return angle::Result::Continue;
1262 }
1263
setupIndexedDraw(const gl::Context * context,gl::PrimitiveMode mode,GLsizei indexCount,GLsizei instanceCount,gl::DrawElementsType indexType,const void * indices)1264 angle::Result ContextVk::setupIndexedDraw(const gl::Context *context,
1265 gl::PrimitiveMode mode,
1266 GLsizei indexCount,
1267 GLsizei instanceCount,
1268 gl::DrawElementsType indexType,
1269 const void *indices)
1270 {
1271 ASSERT(mode != gl::PrimitiveMode::LineLoop);
1272
1273 if (indexType != mCurrentDrawElementsType)
1274 {
1275 mCurrentDrawElementsType = indexType;
1276 ANGLE_TRY(onIndexBufferChange(nullptr));
1277 }
1278
1279 VertexArrayVk *vertexArrayVk = getVertexArray();
1280 const gl::Buffer *elementArrayBuffer = vertexArrayVk->getState().getElementArrayBuffer();
1281 if (!elementArrayBuffer)
1282 {
1283 BufferBindingDirty bindingDirty;
1284 ANGLE_TRY(vertexArrayVk->convertIndexBufferCPU(this, indexType, indexCount, indices,
1285 &bindingDirty));
1286
1287 // We only set dirty bit when the bound buffer actually changed.
1288 if (bindingDirty == BufferBindingDirty::Yes)
1289 {
1290 mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
1291 mCurrentIndexBufferOffset = 0;
1292 }
1293 }
1294 else
1295 {
1296 mCurrentIndexBufferOffset = reinterpret_cast<VkDeviceSize>(indices);
1297
1298 if (indices != mLastIndexBufferOffset)
1299 {
1300 mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
1301 mLastIndexBufferOffset = indices;
1302 }
1303
1304 // When you draw with LineLoop mode or GL_UNSIGNED_BYTE type, we may allocate its own
1305 // element buffer and modify mCurrentElementArrayBuffer. When we switch out of that draw
1306 // mode, we must reset mCurrentElementArrayBuffer back to the vertexArray's element buffer.
1307 // Since in either case we set DIRTY_BIT_INDEX_BUFFER dirty bit, we use this bit to re-sync
1308 // mCurrentElementArrayBuffer.
1309 if (mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
1310 {
1311 vertexArrayVk->updateCurrentElementArrayBuffer();
1312 }
1313
1314 if (shouldConvertUint8VkIndexType(indexType) && mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
1315 {
1316 ANGLE_VK_PERF_WARNING(this, GL_DEBUG_SEVERITY_LOW,
1317 "Potential inefficiency emulating uint8 vertex attributes due to "
1318 "lack of hardware support");
1319
1320 BufferVk *bufferVk = vk::GetImpl(elementArrayBuffer);
1321 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
1322
1323 if (bufferHelper.isHostVisible() &&
1324 !bufferHelper.isCurrentlyInUse(getLastCompletedQueueSerial()))
1325 {
1326 uint8_t *src = nullptr;
1327 ANGLE_TRY(
1328 bufferVk->mapImpl(this, GL_MAP_READ_BIT, reinterpret_cast<void **>(&src)));
1329 // Note: bufferOffset is not added here because mapImpl already adds it.
1330 src += reinterpret_cast<uintptr_t>(indices);
1331 const size_t byteCount = static_cast<size_t>(elementArrayBuffer->getSize()) -
1332 reinterpret_cast<uintptr_t>(indices);
1333 BufferBindingDirty bindingDirty;
1334 ANGLE_TRY(vertexArrayVk->convertIndexBufferCPU(this, indexType, byteCount, src,
1335 &bindingDirty));
1336 ANGLE_TRY(bufferVk->unmapImpl(this));
1337 }
1338 else
1339 {
1340 ANGLE_TRY(vertexArrayVk->convertIndexBufferGPU(this, bufferVk, indices));
1341 }
1342
1343 mCurrentIndexBufferOffset = 0;
1344 }
1345 }
1346
1347 return setupDraw(context, mode, 0, indexCount, instanceCount, indexType, indices,
1348 mIndexedDirtyBitsMask);
1349 }
1350
setupIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,DirtyBits dirtyBitMask,vk::BufferHelper * indirectBuffer)1351 angle::Result ContextVk::setupIndirectDraw(const gl::Context *context,
1352 gl::PrimitiveMode mode,
1353 DirtyBits dirtyBitMask,
1354 vk::BufferHelper *indirectBuffer)
1355 {
1356 GLint firstVertex = -1;
1357 GLsizei vertexCount = 0;
1358 GLsizei instanceCount = 1;
1359
1360 // Break the render pass if the indirect buffer was previously used as the output from transform
1361 // feedback.
1362 if (mCurrentTransformFeedbackBuffers.contains(indirectBuffer))
1363 {
1364 ANGLE_TRY(
1365 flushCommandsAndEndRenderPass(RenderPassClosureReason::XfbWriteThenIndirectDrawBuffer));
1366 }
1367
1368 ANGLE_TRY(setupDraw(context, mode, firstVertex, vertexCount, instanceCount,
1369 gl::DrawElementsType::InvalidEnum, nullptr, dirtyBitMask));
1370
1371 // Process indirect buffer after render pass has started.
1372 mRenderPassCommands->bufferRead(this, VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
1373 vk::PipelineStage::DrawIndirect, indirectBuffer);
1374
1375 return angle::Result::Continue;
1376 }
1377
setupIndexedIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType indexType,vk::BufferHelper * indirectBuffer)1378 angle::Result ContextVk::setupIndexedIndirectDraw(const gl::Context *context,
1379 gl::PrimitiveMode mode,
1380 gl::DrawElementsType indexType,
1381 vk::BufferHelper *indirectBuffer)
1382 {
1383 ASSERT(mode != gl::PrimitiveMode::LineLoop);
1384
1385 if (indexType != mCurrentDrawElementsType)
1386 {
1387 mCurrentDrawElementsType = indexType;
1388 ANGLE_TRY(onIndexBufferChange(nullptr));
1389 }
1390
1391 return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBuffer);
1392 }
1393
setupLineLoopIndexedIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType indexType,vk::BufferHelper * srcIndirectBuf,VkDeviceSize indirectBufferOffset,vk::BufferHelper ** indirectBufferOut)1394 angle::Result ContextVk::setupLineLoopIndexedIndirectDraw(const gl::Context *context,
1395 gl::PrimitiveMode mode,
1396 gl::DrawElementsType indexType,
1397 vk::BufferHelper *srcIndirectBuf,
1398 VkDeviceSize indirectBufferOffset,
1399 vk::BufferHelper **indirectBufferOut)
1400 {
1401 ASSERT(mode == gl::PrimitiveMode::LineLoop);
1402
1403 vk::BufferHelper *dstIndirectBuf = nullptr;
1404
1405 VertexArrayVk *vertexArrayVk = getVertexArray();
1406 ANGLE_TRY(vertexArrayVk->handleLineLoopIndexIndirect(this, indexType, srcIndirectBuf,
1407 indirectBufferOffset, &dstIndirectBuf));
1408
1409 *indirectBufferOut = dstIndirectBuf;
1410
1411 if (indexType != mCurrentDrawElementsType)
1412 {
1413 mCurrentDrawElementsType = indexType;
1414 ANGLE_TRY(onIndexBufferChange(nullptr));
1415 }
1416
1417 return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, dstIndirectBuf);
1418 }
1419
setupLineLoopIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,vk::BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset,vk::BufferHelper ** indirectBufferOut)1420 angle::Result ContextVk::setupLineLoopIndirectDraw(const gl::Context *context,
1421 gl::PrimitiveMode mode,
1422 vk::BufferHelper *indirectBuffer,
1423 VkDeviceSize indirectBufferOffset,
1424 vk::BufferHelper **indirectBufferOut)
1425 {
1426 ASSERT(mode == gl::PrimitiveMode::LineLoop);
1427
1428 vk::BufferHelper *indirectBufferHelperOut = nullptr;
1429
1430 VertexArrayVk *vertexArrayVk = getVertexArray();
1431 ANGLE_TRY(vertexArrayVk->handleLineLoopIndirectDraw(
1432 context, indirectBuffer, indirectBufferOffset, &indirectBufferHelperOut));
1433
1434 *indirectBufferOut = indirectBufferHelperOut;
1435
1436 if (gl::DrawElementsType::UnsignedInt != mCurrentDrawElementsType)
1437 {
1438 mCurrentDrawElementsType = gl::DrawElementsType::UnsignedInt;
1439 ANGLE_TRY(onIndexBufferChange(nullptr));
1440 }
1441
1442 return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBufferHelperOut);
1443 }
1444
setupLineLoopDraw(const gl::Context * context,gl::PrimitiveMode mode,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,uint32_t * numIndicesOut)1445 angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
1446 gl::PrimitiveMode mode,
1447 GLint firstVertex,
1448 GLsizei vertexOrIndexCount,
1449 gl::DrawElementsType indexTypeOrInvalid,
1450 const void *indices,
1451 uint32_t *numIndicesOut)
1452 {
1453 mCurrentIndexBufferOffset = 0;
1454 VertexArrayVk *vertexArrayVk = getVertexArray();
1455 ANGLE_TRY(vertexArrayVk->handleLineLoop(this, firstVertex, vertexOrIndexCount,
1456 indexTypeOrInvalid, indices, numIndicesOut));
1457 ANGLE_TRY(onIndexBufferChange(nullptr));
1458 mCurrentDrawElementsType = indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum
1459 ? indexTypeOrInvalid
1460 : gl::DrawElementsType::UnsignedInt;
1461 return setupDraw(context, mode, firstVertex, vertexOrIndexCount, 1, indexTypeOrInvalid, indices,
1462 mIndexedDirtyBitsMask);
1463 }
1464
setupDispatch(const gl::Context * context)1465 angle::Result ContextVk::setupDispatch(const gl::Context *context)
1466 {
1467 // Note: numerous tests miss a glMemoryBarrier call between the initial texture data upload and
1468 // the dispatch call. Flush the outside render pass command buffer as a workaround.
1469 // TODO: Remove this and fix tests. http://anglebug.com/5070
1470 ANGLE_TRY(flushOutsideRenderPassCommands());
1471
1472 ProgramExecutableVk *programExecutableVk = getExecutable();
1473 if (programExecutableVk->hasDirtyUniforms())
1474 {
1475 mComputeDirtyBits.set(DIRTY_BIT_UNIFORMS);
1476 mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
1477 }
1478
1479 DirtyBits dirtyBits = mComputeDirtyBits;
1480
1481 // Flush any relevant dirty bits.
1482 for (size_t dirtyBit : dirtyBits)
1483 {
1484 ASSERT(mComputeDirtyBitHandlers[dirtyBit]);
1485 ANGLE_TRY((this->*mComputeDirtyBitHandlers[dirtyBit])());
1486 }
1487
1488 mComputeDirtyBits.reset();
1489
1490 return angle::Result::Continue;
1491 }
1492
handleDirtyGraphicsMemoryBarrier(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1493 angle::Result ContextVk::handleDirtyGraphicsMemoryBarrier(DirtyBits::Iterator *dirtyBitsIterator,
1494 DirtyBits dirtyBitMask)
1495 {
1496 return handleDirtyMemoryBarrierImpl(dirtyBitsIterator, dirtyBitMask);
1497 }
1498
handleDirtyComputeMemoryBarrier()1499 angle::Result ContextVk::handleDirtyComputeMemoryBarrier()
1500 {
1501 return handleDirtyMemoryBarrierImpl(nullptr, {});
1502 }
1503
renderPassUsesStorageResources() const1504 bool ContextVk::renderPassUsesStorageResources() const
1505 {
1506 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1507 ASSERT(executable);
1508
1509 // Storage images:
1510 for (size_t imageUnitIndex : executable->getActiveImagesMask())
1511 {
1512 const gl::Texture *texture = mState.getImageUnit(imageUnitIndex).texture.get();
1513 if (texture == nullptr)
1514 {
1515 continue;
1516 }
1517
1518 TextureVk *textureVk = vk::GetImpl(texture);
1519
1520 if (texture->getType() == gl::TextureType::Buffer)
1521 {
1522 vk::BufferHelper &buffer = vk::GetImpl(textureVk->getBuffer().get())->getBuffer();
1523 if (mRenderPassCommands->usesBuffer(buffer))
1524 {
1525 return true;
1526 }
1527 }
1528 else
1529 {
1530 vk::ImageHelper &image = textureVk->getImage();
1531 // Images only need to close the render pass if they need a layout transition. Outside
1532 // render pass command buffer doesn't need closing as the layout transition barriers are
1533 // recorded in sequence with the rest of the commands.
1534 if (IsRenderPassStartedAndUsesImage(*mRenderPassCommands, image))
1535 {
1536 return true;
1537 }
1538 }
1539 }
1540
1541 // Storage buffers:
1542 const std::vector<gl::InterfaceBlock> &blocks = executable->getShaderStorageBlocks();
1543 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1544 {
1545 uint32_t binding = blocks[bufferIndex].binding;
1546 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1547 mState.getIndexedShaderStorageBuffer(binding);
1548
1549 if (bufferBinding.get() == nullptr)
1550 {
1551 continue;
1552 }
1553
1554 vk::BufferHelper &buffer = vk::GetImpl(bufferBinding.get())->getBuffer();
1555 if (mRenderPassCommands->usesBuffer(buffer))
1556 {
1557 return true;
1558 }
1559 }
1560
1561 // Atomic counters:
1562 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers =
1563 executable->getAtomicCounterBuffers();
1564 for (uint32_t bufferIndex = 0; bufferIndex < atomicCounterBuffers.size(); ++bufferIndex)
1565 {
1566 uint32_t binding = atomicCounterBuffers[bufferIndex].binding;
1567 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1568 mState.getIndexedAtomicCounterBuffer(binding);
1569
1570 if (bufferBinding.get() == nullptr)
1571 {
1572 continue;
1573 }
1574
1575 vk::BufferHelper &buffer = vk::GetImpl(bufferBinding.get())->getBuffer();
1576 if (mRenderPassCommands->usesBuffer(buffer))
1577 {
1578 return true;
1579 }
1580 }
1581
1582 return false;
1583 }
1584
handleDirtyMemoryBarrierImpl(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1585 angle::Result ContextVk::handleDirtyMemoryBarrierImpl(DirtyBits::Iterator *dirtyBitsIterator,
1586 DirtyBits dirtyBitMask)
1587 {
1588 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1589 ASSERT(executable);
1590
1591 const bool hasImages = executable->hasImages();
1592 const bool hasStorageBuffers = executable->hasStorageBuffers();
1593 const bool hasAtomicCounters = executable->hasAtomicCounterBuffers();
1594
1595 if (!hasImages && !hasStorageBuffers && !hasAtomicCounters)
1596 {
1597 return angle::Result::Continue;
1598 }
1599
1600 // Break the render pass if necessary. This is only needed for write-after-read situations, and
1601 // is done by checking whether current storage buffers and images are used in the render pass.
1602 if (renderPassUsesStorageResources())
1603 {
1604 // Either set later bits (if called during handling of graphics dirty bits), or set the
1605 // dirty bits directly (if called during handling of compute dirty bits).
1606 if (dirtyBitsIterator)
1607 {
1608 return flushDirtyGraphicsRenderPass(
1609 dirtyBitsIterator, dirtyBitMask,
1610 RenderPassClosureReason::GLMemoryBarrierThenStorageResource);
1611 }
1612 else
1613 {
1614 return flushCommandsAndEndRenderPass(
1615 RenderPassClosureReason::GLMemoryBarrierThenStorageResource);
1616 }
1617 }
1618
1619 // Flushing outside render pass commands is cheap. If a memory barrier has been issued in its
1620 // life time, just flush it instead of wasting time trying to figure out if it's necessary.
1621 if (mOutsideRenderPassCommands->hasGLMemoryBarrierIssued())
1622 {
1623 ANGLE_TRY(flushOutsideRenderPassCommands());
1624 }
1625
1626 return angle::Result::Continue;
1627 }
1628
handleDirtyGraphicsEventLog(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1629 angle::Result ContextVk::handleDirtyGraphicsEventLog(DirtyBits::Iterator *dirtyBitsIterator,
1630 DirtyBits dirtyBitMask)
1631 {
1632 return handleDirtyEventLogImpl(mRenderPassCommandBuffer);
1633 }
1634
handleDirtyComputeEventLog()1635 angle::Result ContextVk::handleDirtyComputeEventLog()
1636 {
1637 return handleDirtyEventLogImpl(&mOutsideRenderPassCommands->getCommandBuffer());
1638 }
1639
1640 template <typename CommandBufferT>
handleDirtyEventLogImpl(CommandBufferT * commandBuffer)1641 angle::Result ContextVk::handleDirtyEventLogImpl(CommandBufferT *commandBuffer)
1642 {
1643 // This method is called when a draw or dispatch command is being processed. It's purpose is
1644 // to call the vkCmd*DebugUtilsLabelEXT functions in order to communicate to debuggers
1645 // (e.g. AGI) the OpenGL ES commands that the application uses.
1646
1647 // Exit early if no OpenGL ES commands have been logged, or if no command buffer (for a no-op
1648 // draw), or if calling the vkCmd*DebugUtilsLabelEXT functions is not enabled.
1649 if (mEventLog.empty() || commandBuffer == nullptr || !mRenderer->angleDebuggerMode())
1650 {
1651 return angle::Result::Continue;
1652 }
1653
1654 // Insert OpenGL ES commands into debug label. We create a 3-level cascade here for
1655 // OpenGL-ES-first debugging in AGI. Here's the general outline of commands:
1656 // -glDrawCommand
1657 // --vkCmdBeginDebugUtilsLabelEXT() #1 for "glDrawCommand"
1658 // --OpenGL ES Commands
1659 // ---vkCmdBeginDebugUtilsLabelEXT() #2 for "OpenGL ES Commands"
1660 // ---Individual OpenGL ES Commands leading up to glDrawCommand
1661 // ----vkCmdBeginDebugUtilsLabelEXT() #3 for each individual OpenGL ES Command
1662 // ----vkCmdEndDebugUtilsLabelEXT() #3 for each individual OpenGL ES Command
1663 // ----...More Individual OGL Commands...
1664 // ----Final Individual OGL command will be the same glDrawCommand shown in #1 above
1665 // ---vkCmdEndDebugUtilsLabelEXT() #2 for "OpenGL ES Commands"
1666 // --VK SetupDraw & Draw-related commands will be embedded here under glDraw #1
1667 // --vkCmdEndDebugUtilsLabelEXT() #1 is called after each vkDraw* or vkDispatch* call
1668
1669 // AGI desires no parameters on the top-level of the hierarchy.
1670 std::string topLevelCommand = mEventLog.back();
1671 size_t startOfParameters = topLevelCommand.find("(");
1672 if (startOfParameters != std::string::npos)
1673 {
1674 topLevelCommand = topLevelCommand.substr(0, startOfParameters);
1675 }
1676 VkDebugUtilsLabelEXT label = {VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
1677 nullptr,
1678 topLevelCommand.c_str(),
1679 {0.0f, 0.0f, 0.0f, 0.0f}};
1680 // This is #1 from comment above
1681 commandBuffer->beginDebugUtilsLabelEXT(label);
1682 std::string oglCmds = "OpenGL ES Commands";
1683 label.pLabelName = oglCmds.c_str();
1684 // This is #2 from comment above
1685 commandBuffer->beginDebugUtilsLabelEXT(label);
1686 for (uint32_t i = 0; i < mEventLog.size(); ++i)
1687 {
1688 label.pLabelName = mEventLog[i].c_str();
1689 // NOTE: We have to use a begin/end pair here because AGI does not promote the
1690 // pLabelName from an insertDebugUtilsLabelEXT() call to the Commands panel.
1691 // Internal bug b/169243237 is tracking this and once the insert* call shows the
1692 // pLabelName similar to begin* call, we can switch these to insert* calls instead.
1693 // This is #3 from comment above.
1694 commandBuffer->beginDebugUtilsLabelEXT(label);
1695 commandBuffer->endDebugUtilsLabelEXT();
1696 }
1697 commandBuffer->endDebugUtilsLabelEXT();
1698 // The final end* call for #1 above is made in the ContextVk::draw* or
1699 // ContextVk::dispatch* function calls.
1700
1701 mEventLog.clear();
1702 return angle::Result::Continue;
1703 }
1704
handleDirtyGraphicsDefaultAttribs(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1705 angle::Result ContextVk::handleDirtyGraphicsDefaultAttribs(DirtyBits::Iterator *dirtyBitsIterator,
1706 DirtyBits dirtyBitMask)
1707 {
1708 ASSERT(mDirtyDefaultAttribsMask.any());
1709
1710 VertexArrayVk *vertexArrayVk = getVertexArray();
1711 for (size_t attribIndex : mDirtyDefaultAttribsMask)
1712 {
1713 ANGLE_TRY(vertexArrayVk->updateDefaultAttrib(this, attribIndex));
1714 }
1715
1716 mDirtyDefaultAttribsMask.reset();
1717 return angle::Result::Continue;
1718 }
1719
handleDirtyGraphicsPipelineDesc(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1720 angle::Result ContextVk::handleDirtyGraphicsPipelineDesc(DirtyBits::Iterator *dirtyBitsIterator,
1721 DirtyBits dirtyBitMask)
1722 {
1723 const VkPipeline previousPipeline = mCurrentGraphicsPipeline
1724 ? mCurrentGraphicsPipeline->getPipeline().getHandle()
1725 : VK_NULL_HANDLE;
1726
1727 ASSERT(mState.getProgramExecutable() != nullptr);
1728 const gl::ProgramExecutable &glExecutable = *mState.getProgramExecutable();
1729 ProgramExecutableVk *executableVk = getExecutable();
1730 ASSERT(executableVk);
1731
1732 if (!mCurrentGraphicsPipeline)
1733 {
1734 const vk::GraphicsPipelineDesc *descPtr;
1735
1736 // The desc's specialization constant depends on program's
1737 // specConstUsageBits. We need to update it if program has changed.
1738 SpecConstUsageBits usageBits = getCurrentProgramSpecConstUsageBits();
1739 updateGraphicsPipelineDescWithSpecConstUsageBits(usageBits);
1740
1741 // Draw call shader patching, shader compilation, and pipeline cache query.
1742 ANGLE_TRY(executableVk->getGraphicsPipeline(this, mCurrentDrawMode, *mGraphicsPipelineDesc,
1743 glExecutable, &descPtr,
1744 &mCurrentGraphicsPipeline));
1745 mGraphicsPipelineTransition.reset();
1746 }
1747 else if (mGraphicsPipelineTransition.any())
1748 {
1749 ASSERT(mCurrentGraphicsPipeline->valid());
1750 if (!mCurrentGraphicsPipeline->findTransition(
1751 mGraphicsPipelineTransition, *mGraphicsPipelineDesc, &mCurrentGraphicsPipeline))
1752 {
1753 vk::PipelineHelper *oldPipeline = mCurrentGraphicsPipeline;
1754 const vk::GraphicsPipelineDesc *descPtr;
1755
1756 ANGLE_TRY(executableVk->getGraphicsPipeline(this, mCurrentDrawMode,
1757 *mGraphicsPipelineDesc, glExecutable,
1758 &descPtr, &mCurrentGraphicsPipeline));
1759
1760 oldPipeline->addTransition(mGraphicsPipelineTransition, descPtr,
1761 mCurrentGraphicsPipeline);
1762 }
1763
1764 mGraphicsPipelineTransition.reset();
1765 }
1766 // Update the queue serial for the pipeline object.
1767 ASSERT(mCurrentGraphicsPipeline && mCurrentGraphicsPipeline->valid());
1768
1769 mCurrentGraphicsPipeline->retain(&mResourceUseList);
1770
1771 const VkPipeline newPipeline = mCurrentGraphicsPipeline->getPipeline().getHandle();
1772
1773 // If there's no change in pipeline, avoid rebinding it later. If the rebind is due to a new
1774 // command buffer or UtilsVk, it will happen anyway with DIRTY_BIT_PIPELINE_BINDING.
1775 if (newPipeline == previousPipeline)
1776 {
1777 return angle::Result::Continue;
1778 }
1779
1780 // VK_EXT_transform_feedback disallows binding pipelines while transform feedback is active.
1781 // If a new pipeline needs to be bound, the render pass should necessarily be broken (which
1782 // implicitly pauses transform feedback), as resuming requires a barrier on the transform
1783 // feedback counter buffer.
1784 if (mRenderPassCommands->started() && mRenderPassCommands->isTransformFeedbackActiveUnpaused())
1785 {
1786 ANGLE_TRY(flushDirtyGraphicsRenderPass(
1787 dirtyBitsIterator, dirtyBitMask, RenderPassClosureReason::PipelineBindWhileXfbActive));
1788
1789 dirtyBitsIterator->setLaterBit(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
1790 }
1791
1792 // The pipeline needs to rebind because it's changed.
1793 dirtyBitsIterator->setLaterBit(DIRTY_BIT_PIPELINE_BINDING);
1794
1795 return angle::Result::Continue;
1796 }
1797
updateRenderPassDepthFeedbackLoopMode(UpdateDepthFeedbackLoopReason depthReason,UpdateDepthFeedbackLoopReason stencilReason)1798 angle::Result ContextVk::updateRenderPassDepthFeedbackLoopMode(
1799 UpdateDepthFeedbackLoopReason depthReason,
1800 UpdateDepthFeedbackLoopReason stencilReason)
1801 {
1802 return updateRenderPassDepthFeedbackLoopModeImpl(nullptr, {}, depthReason, stencilReason);
1803 }
1804
updateRenderPassDepthFeedbackLoopModeImpl(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask,UpdateDepthFeedbackLoopReason depthReason,UpdateDepthFeedbackLoopReason stencilReason)1805 angle::Result ContextVk::updateRenderPassDepthFeedbackLoopModeImpl(
1806 DirtyBits::Iterator *dirtyBitsIterator,
1807 DirtyBits dirtyBitMask,
1808 UpdateDepthFeedbackLoopReason depthReason,
1809 UpdateDepthFeedbackLoopReason stencilReason)
1810 {
1811 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
1812 if (!hasStartedRenderPass() || drawFramebufferVk->getDepthStencilRenderTarget() == nullptr)
1813 {
1814 return angle::Result::Continue;
1815 }
1816
1817 const gl::DepthStencilState &dsState = mState.getDepthStencilState();
1818 vk::ResourceAccess depthAccess = GetDepthAccess(dsState, depthReason);
1819 vk::ResourceAccess stencilAccess = GetStencilAccess(dsState, stencilReason);
1820
1821 if ((depthAccess == vk::ResourceAccess::Write || stencilAccess == vk::ResourceAccess::Write) &&
1822 drawFramebufferVk->isReadOnlyDepthFeedbackLoopMode())
1823 {
1824 // If we are switching out of read only mode and we are in feedback loop, we must end
1825 // renderpass here. Otherwise, updating it to writeable layout will produce a writable
1826 // feedback loop that is illegal in vulkan and will trigger validation errors that depth
1827 // texture is using the writable layout.
1828 if (dirtyBitsIterator)
1829 {
1830 ANGLE_TRY(flushDirtyGraphicsRenderPass(
1831 dirtyBitsIterator, dirtyBitMask,
1832 RenderPassClosureReason::DepthStencilWriteAfterFeedbackLoop));
1833 }
1834 else
1835 {
1836 ANGLE_TRY(flushCommandsAndEndRenderPass(
1837 RenderPassClosureReason::DepthStencilWriteAfterFeedbackLoop));
1838 }
1839 // Clear read-only depth feedback mode.
1840 drawFramebufferVk->setReadOnlyDepthFeedbackLoopMode(false);
1841 }
1842
1843 return angle::Result::Continue;
1844 }
1845
handleDirtyGraphicsReadOnlyDepthFeedbackLoopMode(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1846 angle::Result ContextVk::handleDirtyGraphicsReadOnlyDepthFeedbackLoopMode(
1847 DirtyBits::Iterator *dirtyBitsIterator,
1848 DirtyBits dirtyBitMask)
1849 {
1850 return updateRenderPassDepthFeedbackLoopModeImpl(dirtyBitsIterator, dirtyBitMask,
1851 UpdateDepthFeedbackLoopReason::Draw,
1852 UpdateDepthFeedbackLoopReason::Draw);
1853 }
1854
handleDirtyGraphicsRenderPass(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1855 angle::Result ContextVk::handleDirtyGraphicsRenderPass(DirtyBits::Iterator *dirtyBitsIterator,
1856 DirtyBits dirtyBitMask)
1857 {
1858 // If the render pass needs to be recreated, close it using the special mid-dirty-bit-handling
1859 // function, so later dirty bits can be set.
1860 if (mRenderPassCommands->started())
1861 {
1862 ANGLE_TRY(flushDirtyGraphicsRenderPass(dirtyBitsIterator,
1863 dirtyBitMask & ~DirtyBits{DIRTY_BIT_RENDER_PASS},
1864 RenderPassClosureReason::AlreadySpecifiedElsewhere));
1865 }
1866
1867 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
1868 gl::Rectangle scissoredRenderArea = drawFramebufferVk->getRotatedScissoredRenderArea(this);
1869 bool renderPassDescChanged = false;
1870
1871 ANGLE_TRY(startRenderPass(scissoredRenderArea, nullptr, &renderPassDescChanged));
1872
1873 // The render pass desc can change when starting the render pass, for example due to
1874 // multisampled-render-to-texture needs based on loadOps. In that case, recreate the graphics
1875 // pipeline.
1876 if (renderPassDescChanged)
1877 {
1878 ANGLE_TRY(handleDirtyGraphicsPipelineDesc(dirtyBitsIterator, dirtyBitMask));
1879 }
1880
1881 return angle::Result::Continue;
1882 }
1883
handleDirtyGraphicsColorAccess(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1884 angle::Result ContextVk::handleDirtyGraphicsColorAccess(DirtyBits::Iterator *dirtyBitsIterator,
1885 DirtyBits dirtyBitMask)
1886 {
1887 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
1888 const gl::FramebufferState &framebufferState = drawFramebufferVk->getState();
1889
1890 // Update color attachment accesses
1891 vk::PackedAttachmentIndex colorIndexVk(0);
1892 for (size_t colorIndexGL : framebufferState.getColorAttachmentsMask())
1893 {
1894 if (framebufferState.getEnabledDrawBuffers().test(colorIndexGL))
1895 {
1896 vk::ResourceAccess colorAccess = GetColorAccess(
1897 mState, framebufferState, drawFramebufferVk->getEmulatedAlphaAttachmentMask(),
1898 drawFramebufferVk->hasFramebufferFetch(), colorIndexGL);
1899 mRenderPassCommands->onColorAccess(colorIndexVk, colorAccess);
1900 }
1901 ++colorIndexVk;
1902 }
1903
1904 return angle::Result::Continue;
1905 }
1906
handleDirtyGraphicsDepthStencilAccess(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1907 angle::Result ContextVk::handleDirtyGraphicsDepthStencilAccess(
1908 DirtyBits::Iterator *dirtyBitsIterator,
1909 DirtyBits dirtyBitMask)
1910 {
1911 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
1912 if (drawFramebufferVk->getDepthStencilRenderTarget() == nullptr)
1913 {
1914 return angle::Result::Continue;
1915 }
1916
1917 // Update depth/stencil attachment accesses
1918 const gl::DepthStencilState &dsState = mState.getDepthStencilState();
1919 vk::ResourceAccess depthAccess = GetDepthAccess(dsState, UpdateDepthFeedbackLoopReason::Draw);
1920 vk::ResourceAccess stencilAccess =
1921 GetStencilAccess(dsState, UpdateDepthFeedbackLoopReason::Draw);
1922 mRenderPassCommands->onDepthAccess(depthAccess);
1923 mRenderPassCommands->onStencilAccess(stencilAccess);
1924
1925 drawFramebufferVk->updateRenderPassReadOnlyDepthMode(this, mRenderPassCommands);
1926
1927 return angle::Result::Continue;
1928 }
1929
handleDirtyGraphicsPipelineBinding(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1930 angle::Result ContextVk::handleDirtyGraphicsPipelineBinding(DirtyBits::Iterator *dirtyBitsIterator,
1931 DirtyBits dirtyBitMask)
1932 {
1933 ASSERT(mCurrentGraphicsPipeline);
1934
1935 mRenderPassCommandBuffer->bindGraphicsPipeline(mCurrentGraphicsPipeline->getPipeline());
1936
1937 return angle::Result::Continue;
1938 }
1939
handleDirtyComputePipelineDesc()1940 angle::Result ContextVk::handleDirtyComputePipelineDesc()
1941 {
1942 if (!mCurrentComputePipeline)
1943 {
1944 ProgramExecutableVk *executableVk = getExecutable();
1945 ASSERT(executableVk);
1946 ANGLE_TRY(executableVk->getComputePipeline(this, &mCurrentComputePipeline));
1947 }
1948
1949 ASSERT(mComputeDirtyBits.test(DIRTY_BIT_PIPELINE_BINDING));
1950
1951 return angle::Result::Continue;
1952 }
1953
handleDirtyComputePipelineBinding()1954 angle::Result ContextVk::handleDirtyComputePipelineBinding()
1955 {
1956 ASSERT(mCurrentComputePipeline);
1957
1958 mOutsideRenderPassCommands->getCommandBuffer().bindComputePipeline(
1959 mCurrentComputePipeline->getPipeline());
1960 mCurrentComputePipeline->retain(&mResourceUseList);
1961
1962 return angle::Result::Continue;
1963 }
1964
1965 template <typename CommandBufferHelperT>
handleDirtyTexturesImpl(CommandBufferHelperT * commandBufferHelper,PipelineType pipelineType)1966 ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(
1967 CommandBufferHelperT *commandBufferHelper,
1968 PipelineType pipelineType)
1969 {
1970 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1971 ASSERT(executable);
1972 const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
1973
1974 for (size_t textureUnit : activeTextures)
1975 {
1976 const vk::TextureUnit &unit = mActiveTextures[textureUnit];
1977 TextureVk *textureVk = unit.texture;
1978
1979 // If it's a texture buffer, get the attached buffer.
1980 if (textureVk->getBuffer().get() != nullptr)
1981 {
1982 BufferVk *bufferVk = vk::GetImpl(textureVk->getBuffer().get());
1983 const gl::ShaderBitSet stages =
1984 executable->getSamplerShaderBitsForTextureUnitIndex(textureUnit);
1985
1986 OnTextureBufferRead(this, bufferVk, stages, commandBufferHelper);
1987
1988 textureVk->retainBufferViews(&mResourceUseList);
1989 continue;
1990 }
1991
1992 // The image should be flushed and ready to use at this point. There may still be
1993 // lingering staged updates in its staging buffer for unused texture mip levels or
1994 // layers. Therefore we can't verify it has no staged updates right here.
1995 vk::ImageHelper &image = textureVk->getImage();
1996
1997 // Select the appropriate vk::ImageLayout depending on whether the texture is also bound as
1998 // a GL image, and whether the program is a compute or graphics shader.
1999 const vk::ImageLayout imageLayout =
2000 GetImageReadLayout(textureVk, executable, textureUnit, pipelineType);
2001
2002 // Ensure the image is in the desired layout
2003 commandBufferHelper->imageRead(this, image.getAspectFlags(), imageLayout, &image);
2004 }
2005
2006 if (executable->hasTextures())
2007 {
2008 ProgramExecutableVk *executableVk = getExecutable();
2009 ANGLE_TRY(executableVk->updateTexturesDescriptorSet(
2010 this, &mUpdateDescriptorSetsBuilder, &mResourceUseList, *executable, mActiveTextures,
2011 mActiveTexturesDesc, mEmulateSeamfulCubeMapSampling));
2012 }
2013
2014 return angle::Result::Continue;
2015 }
2016
handleDirtyGraphicsTextures(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2017 angle::Result ContextVk::handleDirtyGraphicsTextures(DirtyBits::Iterator *dirtyBitsIterator,
2018 DirtyBits dirtyBitMask)
2019 {
2020 return handleDirtyTexturesImpl(mRenderPassCommands, PipelineType::Graphics);
2021 }
2022
handleDirtyComputeTextures()2023 angle::Result ContextVk::handleDirtyComputeTextures()
2024 {
2025 return handleDirtyTexturesImpl(mOutsideRenderPassCommands, PipelineType::Compute);
2026 }
2027
handleDirtyGraphicsVertexBuffers(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2028 angle::Result ContextVk::handleDirtyGraphicsVertexBuffers(DirtyBits::Iterator *dirtyBitsIterator,
2029 DirtyBits dirtyBitMask)
2030 {
2031 VertexArrayVk *vertexArrayVk = getVertexArray();
2032 uint32_t maxAttrib = mState.getProgramExecutable()->getMaxActiveAttribLocation();
2033 const gl::AttribArray<VkBuffer> &bufferHandles = vertexArrayVk->getCurrentArrayBufferHandles();
2034 const gl::AttribArray<VkDeviceSize> &bufferOffsets =
2035 vertexArrayVk->getCurrentArrayBufferOffsets();
2036
2037 mRenderPassCommandBuffer->bindVertexBuffers(0, maxAttrib, bufferHandles.data(),
2038 bufferOffsets.data());
2039
2040 const gl::AttribArray<vk::BufferHelper *> &arrayBufferResources =
2041 vertexArrayVk->getCurrentArrayBuffers();
2042
2043 // Mark all active vertex buffers as accessed.
2044 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2045 gl::AttributesMask attribsMask = executable->getActiveAttribLocationsMask();
2046 for (size_t attribIndex : attribsMask)
2047 {
2048 vk::BufferHelper *arrayBuffer = arrayBufferResources[attribIndex];
2049 if (arrayBuffer)
2050 {
2051 mRenderPassCommands->bufferRead(this, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
2052 vk::PipelineStage::VertexInput, arrayBuffer);
2053 }
2054 }
2055
2056 return angle::Result::Continue;
2057 }
2058
handleDirtyGraphicsIndexBuffer(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2059 angle::Result ContextVk::handleDirtyGraphicsIndexBuffer(DirtyBits::Iterator *dirtyBitsIterator,
2060 DirtyBits dirtyBitMask)
2061 {
2062 VertexArrayVk *vertexArrayVk = getVertexArray();
2063 vk::BufferHelper *elementArrayBuffer = vertexArrayVk->getCurrentElementArrayBuffer();
2064 ASSERT(elementArrayBuffer != nullptr);
2065
2066 VkDeviceSize bufferOffset;
2067 const vk::Buffer &buffer = elementArrayBuffer->getBufferForVertexArray(
2068 this, elementArrayBuffer->getSize(), &bufferOffset);
2069
2070 mRenderPassCommandBuffer->bindIndexBuffer(buffer, bufferOffset + mCurrentIndexBufferOffset,
2071 getVkIndexType(mCurrentDrawElementsType));
2072
2073 mRenderPassCommands->bufferRead(this, VK_ACCESS_INDEX_READ_BIT, vk::PipelineStage::VertexInput,
2074 elementArrayBuffer);
2075
2076 return angle::Result::Continue;
2077 }
2078
handleDirtyGraphicsFramebufferFetchBarrier(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2079 angle::Result ContextVk::handleDirtyGraphicsFramebufferFetchBarrier(
2080 DirtyBits::Iterator *dirtyBitsIterator,
2081 DirtyBits dirtyBitMask)
2082 {
2083 VkMemoryBarrier memoryBarrier = {};
2084 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
2085 memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2086 memoryBarrier.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
2087
2088 mRenderPassCommandBuffer->pipelineBarrier(
2089 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
2090 GetLocalDependencyFlags(this), 1, &memoryBarrier, 0, nullptr, 0, nullptr);
2091
2092 return angle::Result::Continue;
2093 }
2094
handleDirtyGraphicsBlendBarrier(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2095 angle::Result ContextVk::handleDirtyGraphicsBlendBarrier(DirtyBits::Iterator *dirtyBitsIterator,
2096 DirtyBits dirtyBitMask)
2097 {
2098 VkMemoryBarrier memoryBarrier = {};
2099 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
2100 memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2101 memoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT;
2102
2103 mRenderPassCommandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2104 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2105 GetLocalDependencyFlags(this), 1, &memoryBarrier, 0,
2106 nullptr, 0, nullptr);
2107
2108 return angle::Result::Continue;
2109 }
2110
2111 template <typename CommandBufferHelperT>
handleDirtyShaderResourcesImpl(CommandBufferHelperT * commandBufferHelper,PipelineType pipelineType)2112 angle::Result ContextVk::handleDirtyShaderResourcesImpl(CommandBufferHelperT *commandBufferHelper,
2113 PipelineType pipelineType)
2114 {
2115 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2116 ASSERT(executable);
2117
2118 const bool hasImages = executable->hasImages();
2119 const bool hasStorageBuffers =
2120 executable->hasStorageBuffers() || executable->hasAtomicCounterBuffers();
2121 const bool hasUniformBuffers = executable->hasUniformBuffers();
2122
2123 if (!hasUniformBuffers && !hasStorageBuffers && !hasImages &&
2124 !executable->usesFramebufferFetch())
2125 {
2126 return angle::Result::Continue;
2127 }
2128
2129 if (hasImages)
2130 {
2131 ANGLE_TRY(updateActiveImages(commandBufferHelper));
2132 }
2133
2134 handleDirtyShaderBufferResourcesImpl(commandBufferHelper);
2135
2136 updateShaderResourcesDescriptorDesc(pipelineType);
2137
2138 ProgramExecutableVk *executableVk = getExecutable();
2139 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
2140 ANGLE_TRY(executableVk->updateShaderResourcesDescriptorSet(
2141 this, executable, &mUpdateDescriptorSetsBuilder, &mEmptyBuffer, &mResourceUseList,
2142 drawFramebufferVk, mShaderBuffersDescriptorDesc));
2143
2144 // Record usage of storage buffers and images in the command buffer to aid handling of
2145 // glMemoryBarrier.
2146 if (hasImages || hasStorageBuffers)
2147 {
2148 commandBufferHelper->setHasShaderStorageOutput();
2149 }
2150
2151 return angle::Result::Continue;
2152 }
2153
handleDirtyShaderBufferResourcesImpl(vk::CommandBufferHelperCommon * commandBufferHelper)2154 void ContextVk::handleDirtyShaderBufferResourcesImpl(
2155 vk::CommandBufferHelperCommon *commandBufferHelper)
2156 {
2157 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2158 ASSERT(executable);
2159
2160 // Process buffer barriers.
2161 for (const gl::ShaderType shaderType : executable->getLinkedShaderStages())
2162 {
2163 const std::vector<gl::InterfaceBlock> &ubos = executable->getUniformBlocks();
2164
2165 for (const gl::InterfaceBlock &ubo : ubos)
2166 {
2167 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
2168 mState.getIndexedUniformBuffer(ubo.binding);
2169
2170 if (!ubo.isActive(shaderType))
2171 {
2172 continue;
2173 }
2174
2175 if (bufferBinding.get() == nullptr)
2176 {
2177 continue;
2178 }
2179
2180 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
2181 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
2182
2183 commandBufferHelper->bufferRead(this, VK_ACCESS_UNIFORM_READ_BIT,
2184 vk::GetPipelineStage(shaderType), &bufferHelper);
2185 }
2186
2187 const std::vector<gl::InterfaceBlock> &ssbos = executable->getShaderStorageBlocks();
2188 for (const gl::InterfaceBlock &ssbo : ssbos)
2189 {
2190 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
2191 mState.getIndexedShaderStorageBuffer(ssbo.binding);
2192
2193 if (!ssbo.isActive(shaderType))
2194 {
2195 continue;
2196 }
2197
2198 if (bufferBinding.get() == nullptr)
2199 {
2200 continue;
2201 }
2202
2203 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
2204 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
2205
2206 // We set the SHADER_READ_BIT to be conservative.
2207 VkAccessFlags accessFlags = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
2208 commandBufferHelper->bufferWrite(this, accessFlags, vk::GetPipelineStage(shaderType),
2209 vk::AliasingMode::Allowed, &bufferHelper);
2210 }
2211
2212 const std::vector<gl::AtomicCounterBuffer> &acbs = executable->getAtomicCounterBuffers();
2213 for (const gl::AtomicCounterBuffer &atomicCounterBuffer : acbs)
2214 {
2215 uint32_t binding = atomicCounterBuffer.binding;
2216 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
2217 mState.getIndexedAtomicCounterBuffer(binding);
2218
2219 if (bufferBinding.get() == nullptr)
2220 {
2221 continue;
2222 }
2223
2224 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
2225 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
2226
2227 // We set SHADER_READ_BIT to be conservative.
2228 commandBufferHelper->bufferWrite(
2229 this, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
2230 vk::GetPipelineStage(shaderType), vk::AliasingMode::Allowed, &bufferHelper);
2231 }
2232 }
2233 }
2234
handleDirtyGraphicsShaderResources(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2235 angle::Result ContextVk::handleDirtyGraphicsShaderResources(DirtyBits::Iterator *dirtyBitsIterator,
2236 DirtyBits dirtyBitMask)
2237 {
2238 return handleDirtyShaderResourcesImpl(mRenderPassCommands, PipelineType::Graphics);
2239 }
2240
handleDirtyComputeShaderResources()2241 angle::Result ContextVk::handleDirtyComputeShaderResources()
2242 {
2243 return handleDirtyShaderResourcesImpl(mOutsideRenderPassCommands, PipelineType::Compute);
2244 }
2245
handleDirtyGraphicsTransformFeedbackBuffersEmulation(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2246 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation(
2247 DirtyBits::Iterator *dirtyBitsIterator,
2248 DirtyBits dirtyBitMask)
2249 {
2250 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2251 ASSERT(executable);
2252
2253 if (!executable->hasTransformFeedbackOutput())
2254 {
2255 return angle::Result::Continue;
2256 }
2257
2258 TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
2259
2260 if (mState.isTransformFeedbackActiveUnpaused())
2261 {
2262 size_t bufferCount = executable->getTransformFeedbackBufferCount();
2263 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &bufferHelpers =
2264 transformFeedbackVk->getBufferHelpers();
2265
2266 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
2267 {
2268 vk::BufferHelper *bufferHelper = bufferHelpers[bufferIndex];
2269 ASSERT(bufferHelper);
2270 mRenderPassCommands->bufferWrite(this, VK_ACCESS_SHADER_WRITE_BIT,
2271 vk::PipelineStage::VertexShader,
2272 vk::AliasingMode::Disallowed, bufferHelper);
2273 }
2274 }
2275
2276 // TODO(http://anglebug.com/3570): Need to update to handle Program Pipelines
2277 vk::BufferHelper *uniformBuffer = mDefaultUniformStorage.getCurrentBuffer();
2278 vk::DescriptorSetDesc xfbBufferDesc = transformFeedbackVk->getTransformFeedbackDesc();
2279 xfbBufferDesc.updateDefaultUniformBuffer(uniformBuffer ? uniformBuffer->getBufferSerial()
2280 : vk::kInvalidBufferSerial);
2281
2282 ProgramVk *programVk = getProgram();
2283 return programVk->getExecutable().updateUniformsAndXfbDescriptorSet(
2284 this, &mUpdateDescriptorSetsBuilder, &mResourceUseList, &mEmptyBuffer, *executable,
2285 uniformBuffer, xfbBufferDesc, mState.isTransformFeedbackActiveUnpaused(),
2286 transformFeedbackVk);
2287 }
2288
handleDirtyGraphicsTransformFeedbackBuffersExtension(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2289 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension(
2290 DirtyBits::Iterator *dirtyBitsIterator,
2291 DirtyBits dirtyBitMask)
2292 {
2293 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2294 ASSERT(executable);
2295
2296 if (!executable->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActive())
2297 {
2298 return angle::Result::Continue;
2299 }
2300
2301 TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
2302 size_t bufferCount = executable->getTransformFeedbackBufferCount();
2303
2304 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers =
2305 transformFeedbackVk->getBufferHelpers();
2306 gl::TransformFeedbackBuffersArray<vk::BufferHelper> &counterBuffers =
2307 transformFeedbackVk->getCounterBufferHelpers();
2308
2309 // Issue necessary barriers for the transform feedback buffers.
2310 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
2311 {
2312 vk::BufferHelper *bufferHelper = buffers[bufferIndex];
2313 ASSERT(bufferHelper);
2314 mRenderPassCommands->bufferWrite(this, VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT,
2315 vk::PipelineStage::TransformFeedback,
2316 vk::AliasingMode::Disallowed, bufferHelper);
2317 }
2318
2319 // Issue necessary barriers for the transform feedback counter buffer. Note that the barrier is
2320 // issued only on the first buffer (which uses a global memory barrier), as all the counter
2321 // buffers of the transform feedback object are used together. The rest of the buffers are
2322 // simply retained so they don't get deleted too early.
2323 ASSERT(counterBuffers[0].valid());
2324 mRenderPassCommands->bufferWrite(this,
2325 VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT |
2326 VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,
2327 vk::PipelineStage::TransformFeedback,
2328 vk::AliasingMode::Disallowed, &counterBuffers[0]);
2329 for (size_t bufferIndex = 1; bufferIndex < bufferCount; ++bufferIndex)
2330 {
2331 counterBuffers[bufferIndex].retainReadWrite(&getResourceUseList());
2332 }
2333
2334 const gl::TransformFeedbackBuffersArray<VkBuffer> &bufferHandles =
2335 transformFeedbackVk->getBufferHandles();
2336 const gl::TransformFeedbackBuffersArray<VkDeviceSize> &bufferOffsets =
2337 transformFeedbackVk->getBufferOffsets();
2338 const gl::TransformFeedbackBuffersArray<VkDeviceSize> &bufferSizes =
2339 transformFeedbackVk->getBufferSizes();
2340
2341 mRenderPassCommandBuffer->bindTransformFeedbackBuffers(
2342 0, static_cast<uint32_t>(bufferCount), bufferHandles.data(), bufferOffsets.data(),
2343 bufferSizes.data());
2344
2345 if (!mState.isTransformFeedbackActiveUnpaused())
2346 {
2347 return angle::Result::Continue;
2348 }
2349
2350 // We should have same number of counter buffers as xfb buffers have
2351 const gl::TransformFeedbackBuffersArray<VkBuffer> &counterBufferHandles =
2352 transformFeedbackVk->getCounterBufferHandles();
2353 const gl::TransformFeedbackBuffersArray<VkDeviceSize> &counterBufferOffsets =
2354 transformFeedbackVk->getCounterBufferOffsets();
2355
2356 bool rebindBuffers = transformFeedbackVk->getAndResetBufferRebindState();
2357
2358 mRenderPassCommands->beginTransformFeedback(bufferCount, counterBufferHandles.data(),
2359 counterBufferOffsets.data(), rebindBuffers);
2360
2361 return angle::Result::Continue;
2362 }
2363
handleDirtyGraphicsTransformFeedbackResume(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2364 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackResume(
2365 DirtyBits::Iterator *dirtyBitsIterator,
2366 DirtyBits dirtyBitMask)
2367 {
2368 if (mRenderPassCommands->isTransformFeedbackStarted())
2369 {
2370 mRenderPassCommands->resumeTransformFeedback();
2371 }
2372
2373 ANGLE_TRY(resumeXfbRenderPassQueriesIfActive());
2374
2375 return angle::Result::Continue;
2376 }
2377
handleDirtyGraphicsDescriptorSets(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2378 angle::Result ContextVk::handleDirtyGraphicsDescriptorSets(DirtyBits::Iterator *dirtyBitsIterator,
2379 DirtyBits dirtyBitMask)
2380 {
2381 return handleDirtyDescriptorSetsImpl(mRenderPassCommandBuffer, PipelineType::Graphics);
2382 }
2383
handleDirtyGraphicsUniforms(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2384 angle::Result ContextVk::handleDirtyGraphicsUniforms(DirtyBits::Iterator *dirtyBitsIterator,
2385 DirtyBits dirtyBitMask)
2386 {
2387 dirtyBitsIterator->setLaterBit(DIRTY_BIT_DESCRIPTOR_SETS);
2388 return handleDirtyUniformsImpl();
2389 }
2390
handleDirtyComputeUniforms()2391 angle::Result ContextVk::handleDirtyComputeUniforms()
2392 {
2393 return handleDirtyUniformsImpl();
2394 }
2395
handleDirtyUniformsImpl()2396 angle::Result ContextVk::handleDirtyUniformsImpl()
2397 {
2398 ProgramExecutableVk *programExecutableVk = getExecutable();
2399 TransformFeedbackVk *transformFeedbackVk =
2400 vk::SafeGetImpl(mState.getCurrentTransformFeedback());
2401 ANGLE_TRY(programExecutableVk->updateUniforms(
2402 this, &mUpdateDescriptorSetsBuilder, &mResourceUseList, &mEmptyBuffer,
2403 *mState.getProgramExecutable(), &mDefaultUniformStorage,
2404 mState.isTransformFeedbackActiveUnpaused(), transformFeedbackVk));
2405
2406 return angle::Result::Continue;
2407 }
2408
handleDirtyGraphicsViewport(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2409 angle::Result ContextVk::handleDirtyGraphicsViewport(DirtyBits::Iterator *dirtyBitsIterator,
2410 DirtyBits dirtyBitMask)
2411 {
2412 mRenderPassCommandBuffer->setViewport(0, 1, &mViewport);
2413 return angle::Result::Continue;
2414 }
2415
handleDirtyGraphicsScissor(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2416 angle::Result ContextVk::handleDirtyGraphicsScissor(DirtyBits::Iterator *dirtyBitsIterator,
2417 DirtyBits dirtyBitMask)
2418 {
2419 handleDirtyGraphicsScissorImpl(mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
2420 return angle::Result::Continue;
2421 }
2422
handleDirtyGraphicsScissorImpl(bool isPrimitivesGeneratedQueryActive)2423 void ContextVk::handleDirtyGraphicsScissorImpl(bool isPrimitivesGeneratedQueryActive)
2424 {
2425 // If primitives generated query and rasterizer discard are both active, but the Vulkan
2426 // implementation of the query does not support rasterizer discard, use an empty scissor to
2427 // emulate it.
2428 if (isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(
2429 isPrimitivesGeneratedQueryActive))
2430 {
2431 VkRect2D emptyScissor = {};
2432 mRenderPassCommandBuffer->setScissor(0, 1, &emptyScissor);
2433 }
2434 else
2435 {
2436 mRenderPassCommandBuffer->setScissor(0, 1, &mScissor);
2437 }
2438 }
2439
handleDirtyComputeDescriptorSets()2440 angle::Result ContextVk::handleDirtyComputeDescriptorSets()
2441 {
2442 return handleDirtyDescriptorSetsImpl(&mOutsideRenderPassCommands->getCommandBuffer(),
2443 PipelineType::Compute);
2444 }
2445
2446 template <typename CommandBufferT>
handleDirtyDescriptorSetsImpl(CommandBufferT * commandBuffer,PipelineType pipelineType)2447 angle::Result ContextVk::handleDirtyDescriptorSetsImpl(CommandBufferT *commandBuffer,
2448 PipelineType pipelineType)
2449 {
2450 // When using Vulkan secondary command buffers, the descriptor sets need to be updated before
2451 // they are bound.
2452 if (!CommandBufferT::ExecutesInline())
2453 {
2454 flushDescriptorSetUpdates();
2455 }
2456
2457 ProgramExecutableVk *executableVk = getExecutable();
2458 return executableVk->updateDescriptorSets(this, &mResourceUseList, commandBuffer, pipelineType);
2459 }
2460
syncObjectPerfCounters()2461 void ContextVk::syncObjectPerfCounters()
2462 {
2463 mPerfCounters.descriptorSetCacheTotalSize = 0;
2464 mPerfCounters.descriptorSetCacheKeySizeBytes = 0;
2465 mPerfCounters.uniformsAndXfbDescriptorSetCacheHits = 0;
2466 mPerfCounters.uniformsAndXfbDescriptorSetCacheMisses = 0;
2467 mPerfCounters.uniformsAndXfbDescriptorSetCacheTotalSize = 0;
2468 mPerfCounters.textureDescriptorSetCacheHits = 0;
2469 mPerfCounters.textureDescriptorSetCacheMisses = 0;
2470 mPerfCounters.textureDescriptorSetCacheTotalSize = 0;
2471 mPerfCounters.shaderResourcesDescriptorSetCacheHits = 0;
2472 mPerfCounters.shaderResourcesDescriptorSetCacheMisses = 0;
2473 mPerfCounters.shaderResourcesDescriptorSetCacheTotalSize = 0;
2474 mPerfCounters.dynamicBufferAllocations = 0;
2475
2476 // ProgramExecutableVk's descriptor set allocations
2477 const gl::ShaderProgramManager &shadersAndPrograms = mState.getShaderProgramManagerForCapture();
2478 const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
2479 shadersAndPrograms.getProgramsForCaptureAndPerf();
2480 for (const std::pair<GLuint, gl::Program *> &resource : programs)
2481 {
2482 gl::Program *program = resource.second;
2483 if (program->hasLinkingState())
2484 {
2485 continue;
2486 }
2487 ProgramVk *programVk = vk::GetImpl(resource.second);
2488 ProgramExecutablePerfCounters progPerfCounters =
2489 programVk->getExecutable().getDescriptorSetPerfCounters();
2490
2491 mPerfCounters.uniformsAndXfbDescriptorSetCacheHits +=
2492 progPerfCounters.cacheStats[DescriptorSetIndex::UniformsAndXfb].getHitCount();
2493 mPerfCounters.uniformsAndXfbDescriptorSetCacheMisses +=
2494 progPerfCounters.cacheStats[DescriptorSetIndex::UniformsAndXfb].getMissCount();
2495 mPerfCounters.uniformsAndXfbDescriptorSetCacheTotalSize +=
2496 progPerfCounters.cacheStats[DescriptorSetIndex::UniformsAndXfb].getSize();
2497 mPerfCounters.textureDescriptorSetCacheHits +=
2498 progPerfCounters.cacheStats[DescriptorSetIndex::Texture].getHitCount();
2499 mPerfCounters.textureDescriptorSetCacheMisses +=
2500 progPerfCounters.cacheStats[DescriptorSetIndex::Texture].getMissCount();
2501 mPerfCounters.textureDescriptorSetCacheTotalSize +=
2502 progPerfCounters.cacheStats[DescriptorSetIndex::Texture].getSize();
2503 mPerfCounters.shaderResourcesDescriptorSetCacheHits +=
2504 progPerfCounters.cacheStats[DescriptorSetIndex::ShaderResource].getHitCount();
2505 mPerfCounters.shaderResourcesDescriptorSetCacheMisses +=
2506 progPerfCounters.cacheStats[DescriptorSetIndex::ShaderResource].getMissCount();
2507 mPerfCounters.shaderResourcesDescriptorSetCacheTotalSize +=
2508 progPerfCounters.cacheStats[DescriptorSetIndex::ShaderResource].getSize();
2509
2510 for (uint32_t keySizeBytes : progPerfCounters.descriptorSetCacheKeySizesBytes)
2511 {
2512 mPerfCounters.descriptorSetCacheKeySizeBytes += keySizeBytes;
2513 }
2514 }
2515
2516 mPerfCounters.descriptorSetCacheTotalSize +=
2517 mPerfCounters.uniformsAndXfbDescriptorSetCacheTotalSize;
2518 mPerfCounters.descriptorSetCacheTotalSize += mPerfCounters.textureDescriptorSetCacheTotalSize;
2519 mPerfCounters.descriptorSetCacheTotalSize +=
2520 mPerfCounters.shaderResourcesDescriptorSetCacheTotalSize;
2521
2522 for (const DriverUniformsDescriptorSet &driverSet : mDriverUniforms)
2523 {
2524 mPerfCounters.descriptorSetCacheTotalSize += driverSet.descriptorSetCache.getSize();
2525 }
2526 }
2527
updateOverlayOnPresent()2528 void ContextVk::updateOverlayOnPresent()
2529 {
2530 const gl::OverlayType *overlay = mState.getOverlay();
2531 ASSERT(overlay->isEnabled());
2532
2533 syncObjectPerfCounters();
2534
2535 // Update overlay if active.
2536 {
2537 gl::RunningGraphWidget *renderPassCount =
2538 overlay->getRunningGraphWidget(gl::WidgetId::VulkanRenderPassCount);
2539 renderPassCount->add(mRenderPassCommands->getAndResetCounter());
2540 renderPassCount->next();
2541 }
2542
2543 {
2544 gl::RunningGraphWidget *writeDescriptorSetCount =
2545 overlay->getRunningGraphWidget(gl::WidgetId::VulkanWriteDescriptorSetCount);
2546 writeDescriptorSetCount->add(mPerfCounters.writeDescriptorSets);
2547 writeDescriptorSetCount->next();
2548 }
2549
2550 {
2551 gl::RunningGraphWidget *descriptorSetAllocationCount =
2552 overlay->getRunningGraphWidget(gl::WidgetId::VulkanDescriptorSetAllocations);
2553 descriptorSetAllocationCount->add(mPerfCounters.descriptorSetAllocations);
2554 descriptorSetAllocationCount->next();
2555 }
2556
2557 {
2558 gl::RunningGraphWidget *shaderResourceHitRate =
2559 overlay->getRunningGraphWidget(gl::WidgetId::VulkanShaderResourceDSHitRate);
2560 size_t numCacheAccesses = mPerfCounters.shaderResourcesDescriptorSetCacheHits +
2561 mPerfCounters.shaderResourcesDescriptorSetCacheMisses;
2562 if (numCacheAccesses > 0)
2563 {
2564 float hitRateFloat =
2565 static_cast<float>(mPerfCounters.shaderResourcesDescriptorSetCacheHits) /
2566 static_cast<float>(numCacheAccesses);
2567 size_t hitRate = static_cast<size_t>(hitRateFloat * 100.0f);
2568 shaderResourceHitRate->add(hitRate);
2569 shaderResourceHitRate->next();
2570 }
2571 }
2572
2573 {
2574 gl::RunningGraphWidget *dynamicBufferAllocations =
2575 overlay->getRunningGraphWidget(gl::WidgetId::VulkanDynamicBufferAllocations);
2576 dynamicBufferAllocations->next();
2577 }
2578
2579 {
2580 gl::CountWidget *cacheKeySize =
2581 overlay->getCountWidget(gl::WidgetId::VulkanDescriptorCacheKeySize);
2582 cacheKeySize->reset();
2583 cacheKeySize->add(mPerfCounters.descriptorSetCacheKeySizeBytes);
2584 }
2585
2586 {
2587 gl::RunningGraphWidget *dynamicBufferAllocations =
2588 overlay->getRunningGraphWidget(gl::WidgetId::VulkanDynamicBufferAllocations);
2589 dynamicBufferAllocations->add(mPerfCounters.dynamicBufferAllocations);
2590 }
2591 }
2592
addOverlayUsedBuffersCount(vk::CommandBufferHelperCommon * commandBuffer)2593 void ContextVk::addOverlayUsedBuffersCount(vk::CommandBufferHelperCommon *commandBuffer)
2594 {
2595 const gl::OverlayType *overlay = mState.getOverlay();
2596 if (!overlay->isEnabled())
2597 {
2598 return;
2599 }
2600
2601 gl::RunningHistogramWidget *widget =
2602 overlay->getRunningHistogramWidget(gl::WidgetId::VulkanRenderPassBufferCount);
2603 size_t buffersCount = commandBuffer->getUsedBuffersCount();
2604 if (buffersCount > 0)
2605 {
2606 widget->add(buffersCount);
2607 widget->next();
2608 }
2609
2610 {
2611 gl::RunningGraphWidget *textureDescriptorCacheSize =
2612 overlay->getRunningGraphWidget(gl::WidgetId::VulkanTextureDescriptorCacheSize);
2613 textureDescriptorCacheSize->add(mPerfCounters.textureDescriptorSetCacheTotalSize);
2614 textureDescriptorCacheSize->next();
2615 }
2616
2617 {
2618 gl::RunningGraphWidget *uniformDescriptorCacheSize =
2619 overlay->getRunningGraphWidget(gl::WidgetId::VulkanUniformDescriptorCacheSize);
2620 uniformDescriptorCacheSize->add(mPerfCounters.uniformsAndXfbDescriptorSetCacheTotalSize);
2621 uniformDescriptorCacheSize->next();
2622 }
2623
2624 {
2625 gl::RunningGraphWidget *descriptorCacheSize =
2626 overlay->getRunningGraphWidget(gl::WidgetId::VulkanDescriptorCacheSize);
2627 descriptorCacheSize->add(mPerfCounters.descriptorSetCacheTotalSize);
2628 descriptorCacheSize->next();
2629 }
2630 }
2631
submitFrame(const vk::Semaphore * signalSemaphore,Serial * submitSerialOut)2632 angle::Result ContextVk::submitFrame(const vk::Semaphore *signalSemaphore, Serial *submitSerialOut)
2633 {
2634 getShareGroupVk()->acquireResourceUseList(
2635 std::move(mOutsideRenderPassCommands->getResourceUseList()));
2636 getShareGroupVk()->acquireResourceUseList(std::move(mResourceUseList));
2637 getShareGroupVk()->acquireResourceUseList(std::move(mRenderPassCommands->getResourceUseList()));
2638
2639 ANGLE_TRY(submitCommands(signalSemaphore, submitSerialOut));
2640
2641 onRenderPassFinished(RenderPassClosureReason::AlreadySpecifiedElsewhere);
2642 return angle::Result::Continue;
2643 }
2644
submitFrameOutsideCommandBufferOnly(Serial * submitSerialOut)2645 angle::Result ContextVk::submitFrameOutsideCommandBufferOnly(Serial *submitSerialOut)
2646 {
2647 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::submitFrameOutsideCommandBufferOnly");
2648 getShareGroupVk()->acquireResourceUseList(
2649 std::move(mOutsideRenderPassCommands->getResourceUseList()));
2650
2651 return submitCommands(nullptr, submitSerialOut);
2652 }
2653
submitCommands(const vk::Semaphore * signalSemaphore,Serial * submitSerialOut)2654 angle::Result ContextVk::submitCommands(const vk::Semaphore *signalSemaphore,
2655 Serial *submitSerialOut)
2656 {
2657 if (mCurrentWindowSurface)
2658 {
2659 const vk::Semaphore *waitSemaphore =
2660 mCurrentWindowSurface->getAndResetAcquireImageSemaphore();
2661 if (waitSemaphore != nullptr)
2662 {
2663 addWaitSemaphore(waitSemaphore->getHandle(),
2664 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2665 }
2666 }
2667
2668 if (vk::CommandBufferHelperCommon::kEnableCommandStreamDiagnostics)
2669 {
2670 dumpCommandStreamDiagnostics();
2671 }
2672
2673 ANGLE_TRY(mRenderer->submitFrame(this, hasProtectedContent(), mContextPriority,
2674 std::move(mWaitSemaphores),
2675 std::move(mWaitSemaphoreStageMasks), signalSemaphore,
2676 std::move(mCurrentGarbage), &mCommandPools, submitSerialOut));
2677
2678 getShareGroupVk()->releaseResourceUseLists(*submitSerialOut);
2679 // Now that we have processed resourceUseList, some of pending garbage may no longer pending
2680 // and should be moved to garbage list.
2681 mRenderer->cleanupPendingSubmissionGarbage();
2682
2683 mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
2684
2685 if (mGpuEventsEnabled)
2686 {
2687 ANGLE_TRY(checkCompletedGpuEvents());
2688 }
2689
2690 mPerfCounters.submittedCommands++;
2691 resetTotalBufferToImageCopySize();
2692
2693 return angle::Result::Continue;
2694 }
2695
onCopyUpdate(VkDeviceSize size)2696 angle::Result ContextVk::onCopyUpdate(VkDeviceSize size)
2697 {
2698 mTotalBufferToImageCopySize += size;
2699 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::onCopyUpdate");
2700 // If the copy size exceeds the specified threshold, submit the outside command buffer.
2701 VkDeviceSize copySize = getTotalBufferToImageCopySize();
2702 if (copySize >= kMaxBufferToImageCopySize)
2703 {
2704 ANGLE_TRY(submitOutsideRenderPassCommandsImpl());
2705 }
2706 return angle::Result::Continue;
2707 }
2708
synchronizeCpuGpuTime()2709 angle::Result ContextVk::synchronizeCpuGpuTime()
2710 {
2711 ASSERT(mGpuEventsEnabled);
2712
2713 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
2714 ASSERT(platform);
2715
2716 // To synchronize CPU and GPU times, we need to get the CPU timestamp as close as possible
2717 // to the GPU timestamp. The process of getting the GPU timestamp is as follows:
2718 //
2719 // CPU GPU
2720 //
2721 // Record command buffer
2722 // with timestamp query
2723 //
2724 // Submit command buffer
2725 //
2726 // Post-submission work Begin execution
2727 //
2728 // ???? Write timestamp Tgpu
2729 //
2730 // ???? End execution
2731 //
2732 // ???? Return query results
2733 //
2734 // ????
2735 //
2736 // Get query results
2737 //
2738 // The areas of unknown work (????) on the CPU indicate that the CPU may or may not have
2739 // finished post-submission work while the GPU is executing in parallel. With no further
2740 // work, querying CPU timestamps before submission and after getting query results give the
2741 // bounds to Tgpu, which could be quite large.
2742 //
2743 // Using VkEvents, the GPU can be made to wait for the CPU and vice versa, in an effort to
2744 // reduce this range. This function implements the following procedure:
2745 //
2746 // CPU GPU
2747 //
2748 // Record command buffer
2749 // with timestamp query
2750 //
2751 // Submit command buffer
2752 //
2753 // Post-submission work Begin execution
2754 //
2755 // ???? Set Event GPUReady
2756 //
2757 // Wait on Event GPUReady Wait on Event CPUReady
2758 //
2759 // Get CPU Time Ts Wait on Event CPUReady
2760 //
2761 // Set Event CPUReady Wait on Event CPUReady
2762 //
2763 // Get CPU Time Tcpu Get GPU Time Tgpu
2764 //
2765 // Wait on Event GPUDone Set Event GPUDone
2766 //
2767 // Get CPU Time Te End Execution
2768 //
2769 // Idle Return query results
2770 //
2771 // Get query results
2772 //
2773 // If Te-Ts > epsilon, a GPU or CPU interruption can be assumed and the operation can be
2774 // retried. Once Te-Ts < epsilon, Tcpu can be taken to presumably match Tgpu. Finding an
2775 // epsilon that's valid for all devices may be difficult, so the loop can be performed only
2776 // a limited number of times and the Tcpu,Tgpu pair corresponding to smallest Te-Ts used for
2777 // calibration.
2778 //
2779 // Note: Once VK_EXT_calibrated_timestamps is ubiquitous, this should be redone.
2780
2781 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::synchronizeCpuGpuTime");
2782
2783 // Create a query used to receive the GPU timestamp
2784 vk::QueryHelper timestampQuery;
2785 ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, ×tampQuery, 1));
2786
2787 // Create the three events
2788 VkEventCreateInfo eventCreateInfo = {};
2789 eventCreateInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
2790 eventCreateInfo.flags = 0;
2791
2792 VkDevice device = getDevice();
2793 vk::DeviceScoped<vk::Event> cpuReady(device), gpuReady(device), gpuDone(device);
2794 ANGLE_VK_TRY(this, cpuReady.get().init(device, eventCreateInfo));
2795 ANGLE_VK_TRY(this, gpuReady.get().init(device, eventCreateInfo));
2796 ANGLE_VK_TRY(this, gpuDone.get().init(device, eventCreateInfo));
2797
2798 constexpr uint32_t kRetries = 10;
2799
2800 // Time suffixes used are S for seconds and Cycles for cycles
2801 double tightestRangeS = 1e6f;
2802 double TcpuS = 0;
2803 uint64_t TgpuCycles = 0;
2804 for (uint32_t i = 0; i < kRetries; ++i)
2805 {
2806 // Reset the events
2807 ANGLE_VK_TRY(this, cpuReady.get().reset(device));
2808 ANGLE_VK_TRY(this, gpuReady.get().reset(device));
2809 ANGLE_VK_TRY(this, gpuDone.get().reset(device));
2810
2811 // Record the command buffer
2812 vk::DeviceScoped<vk::PrimaryCommandBuffer> commandBatch(device);
2813 vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
2814
2815 vk::ResourceUseList scratchResourceUseList;
2816
2817 ANGLE_TRY(mRenderer->getCommandBufferOneOff(this, hasProtectedContent(), &commandBuffer));
2818
2819 commandBuffer.setEvent(gpuReady.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
2820 commandBuffer.waitEvents(1, cpuReady.get().ptr(), VK_PIPELINE_STAGE_HOST_BIT,
2821 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, nullptr, 0, nullptr, 0,
2822 nullptr);
2823 timestampQuery.writeTimestampToPrimary(this, &commandBuffer);
2824 timestampQuery.retain(&scratchResourceUseList);
2825
2826 commandBuffer.setEvent(gpuDone.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
2827
2828 ANGLE_VK_TRY(this, commandBuffer.end());
2829
2830 Serial submitSerial;
2831 // vkEvent's are externally synchronized, therefore need work to be submitted before calling
2832 // vkGetEventStatus
2833 ANGLE_TRY(mRenderer->queueSubmitOneOff(
2834 this, std::move(commandBuffer), hasProtectedContent(), mContextPriority, nullptr, 0,
2835 nullptr, vk::SubmitPolicy::EnsureSubmitted, &submitSerial));
2836 scratchResourceUseList.releaseResourceUsesAndUpdateSerials(submitSerial);
2837
2838 // Wait for GPU to be ready. This is a short busy wait.
2839 VkResult result = VK_EVENT_RESET;
2840 do
2841 {
2842 result = gpuReady.get().getStatus(device);
2843 if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
2844 {
2845 ANGLE_VK_TRY(this, result);
2846 }
2847 } while (result == VK_EVENT_RESET);
2848
2849 double TsS = platform->monotonicallyIncreasingTime(platform);
2850
2851 // Tell the GPU to go ahead with the timestamp query.
2852 ANGLE_VK_TRY(this, cpuReady.get().set(device));
2853 double cpuTimestampS = platform->monotonicallyIncreasingTime(platform);
2854
2855 // Wait for GPU to be done. Another short busy wait.
2856 do
2857 {
2858 result = gpuDone.get().getStatus(device);
2859 if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
2860 {
2861 ANGLE_VK_TRY(this, result);
2862 }
2863 } while (result == VK_EVENT_RESET);
2864
2865 double TeS = platform->monotonicallyIncreasingTime(platform);
2866
2867 // Get the query results
2868 ANGLE_TRY(finishToSerial(submitSerial));
2869
2870 vk::QueryResult gpuTimestampCycles(1);
2871 ANGLE_TRY(timestampQuery.getUint64Result(this, &gpuTimestampCycles));
2872
2873 // Use the first timestamp queried as origin.
2874 if (mGpuEventTimestampOrigin == 0)
2875 {
2876 mGpuEventTimestampOrigin =
2877 gpuTimestampCycles.getResult(vk::QueryResult::kDefaultResultIndex);
2878 }
2879
2880 // Take these CPU and GPU timestamps if there is better confidence.
2881 double confidenceRangeS = TeS - TsS;
2882 if (confidenceRangeS < tightestRangeS)
2883 {
2884 tightestRangeS = confidenceRangeS;
2885 TcpuS = cpuTimestampS;
2886 TgpuCycles = gpuTimestampCycles.getResult(vk::QueryResult::kDefaultResultIndex);
2887 }
2888 }
2889
2890 mGpuEventQueryPool.freeQuery(this, ×tampQuery);
2891
2892 // timestampPeriod gives nanoseconds/cycle.
2893 double TgpuS =
2894 (TgpuCycles - mGpuEventTimestampOrigin) *
2895 static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod) /
2896 1'000'000'000.0;
2897
2898 flushGpuEvents(TgpuS, TcpuS);
2899
2900 mGpuClockSync.gpuTimestampS = TgpuS;
2901 mGpuClockSync.cpuTimestampS = TcpuS;
2902
2903 return angle::Result::Continue;
2904 }
2905
traceGpuEventImpl(vk::OutsideRenderPassCommandBuffer * commandBuffer,char phase,const EventName & name)2906 angle::Result ContextVk::traceGpuEventImpl(vk::OutsideRenderPassCommandBuffer *commandBuffer,
2907 char phase,
2908 const EventName &name)
2909 {
2910 ASSERT(mGpuEventsEnabled);
2911
2912 GpuEventQuery gpuEvent;
2913 gpuEvent.name = name;
2914 gpuEvent.phase = phase;
2915 ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &gpuEvent.queryHelper, 1));
2916
2917 gpuEvent.queryHelper.writeTimestamp(this, commandBuffer);
2918
2919 mInFlightGpuEventQueries.push_back(std::move(gpuEvent));
2920 return angle::Result::Continue;
2921 }
2922
checkCompletedGpuEvents()2923 angle::Result ContextVk::checkCompletedGpuEvents()
2924 {
2925 ASSERT(mGpuEventsEnabled);
2926
2927 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
2928 ASSERT(platform);
2929
2930 int finishedCount = 0;
2931
2932 Serial lastCompletedSerial = getLastCompletedQueueSerial();
2933
2934 for (GpuEventQuery &eventQuery : mInFlightGpuEventQueries)
2935 {
2936 // Only check the timestamp query if the submission has finished.
2937 if (eventQuery.queryHelper.usedInRunningCommands(lastCompletedSerial))
2938 {
2939 break;
2940 }
2941
2942 // See if the results are available.
2943 vk::QueryResult gpuTimestampCycles(1);
2944 bool available = false;
2945 ANGLE_TRY(eventQuery.queryHelper.getUint64ResultNonBlocking(this, &gpuTimestampCycles,
2946 &available));
2947 if (!available)
2948 {
2949 break;
2950 }
2951
2952 mGpuEventQueryPool.freeQuery(this, &eventQuery.queryHelper);
2953
2954 GpuEvent gpuEvent;
2955 gpuEvent.gpuTimestampCycles =
2956 gpuTimestampCycles.getResult(vk::QueryResult::kDefaultResultIndex);
2957 gpuEvent.name = eventQuery.name;
2958 gpuEvent.phase = eventQuery.phase;
2959
2960 mGpuEvents.emplace_back(gpuEvent);
2961
2962 ++finishedCount;
2963 }
2964
2965 mInFlightGpuEventQueries.erase(mInFlightGpuEventQueries.begin(),
2966 mInFlightGpuEventQueries.begin() + finishedCount);
2967
2968 return angle::Result::Continue;
2969 }
2970
flushGpuEvents(double nextSyncGpuTimestampS,double nextSyncCpuTimestampS)2971 void ContextVk::flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuTimestampS)
2972 {
2973 if (mGpuEvents.empty())
2974 {
2975 return;
2976 }
2977
2978 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
2979 ASSERT(platform);
2980
2981 // Find the slope of the clock drift for adjustment
2982 double lastGpuSyncTimeS = mGpuClockSync.gpuTimestampS;
2983 double lastGpuSyncDiffS = mGpuClockSync.cpuTimestampS - mGpuClockSync.gpuTimestampS;
2984 double gpuSyncDriftSlope = 0;
2985
2986 double nextGpuSyncTimeS = nextSyncGpuTimestampS;
2987 double nextGpuSyncDiffS = nextSyncCpuTimestampS - nextSyncGpuTimestampS;
2988
2989 // No gpu trace events should have been generated before the clock sync, so if there is no
2990 // "previous" clock sync, there should be no gpu events (i.e. the function early-outs
2991 // above).
2992 ASSERT(mGpuClockSync.gpuTimestampS != std::numeric_limits<double>::max() &&
2993 mGpuClockSync.cpuTimestampS != std::numeric_limits<double>::max());
2994
2995 gpuSyncDriftSlope =
2996 (nextGpuSyncDiffS - lastGpuSyncDiffS) / (nextGpuSyncTimeS - lastGpuSyncTimeS);
2997
2998 for (const GpuEvent &gpuEvent : mGpuEvents)
2999 {
3000 double gpuTimestampS =
3001 (gpuEvent.gpuTimestampCycles - mGpuEventTimestampOrigin) *
3002 static_cast<double>(
3003 getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod) *
3004 1e-9;
3005
3006 // Account for clock drift.
3007 gpuTimestampS += lastGpuSyncDiffS + gpuSyncDriftSlope * (gpuTimestampS - lastGpuSyncTimeS);
3008
3009 // Generate the trace now that the GPU timestamp is available and clock drifts are
3010 // accounted for.
3011 static long long eventId = 1;
3012 static const unsigned char *categoryEnabled =
3013 TRACE_EVENT_API_GET_CATEGORY_ENABLED(platform, "gpu.angle.gpu");
3014 platform->addTraceEvent(platform, gpuEvent.phase, categoryEnabled, gpuEvent.name.data(),
3015 eventId++, gpuTimestampS, 0, nullptr, nullptr, nullptr,
3016 TRACE_EVENT_FLAG_NONE);
3017 }
3018
3019 mGpuEvents.clear();
3020 }
3021
clearAllGarbage()3022 void ContextVk::clearAllGarbage()
3023 {
3024 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::clearAllGarbage");
3025
3026 // The VMA virtual allocator code has assertion to ensure all sub-ranges are freed before
3027 // virtual block gets freed. We need to ensure all completed garbage objects are actually freed
3028 // to avoid hitting that assertion.
3029 mRenderer->cleanupCompletedCommandsGarbage();
3030
3031 for (vk::GarbageObject &garbage : mCurrentGarbage)
3032 {
3033 garbage.destroy(mRenderer);
3034 }
3035 mCurrentGarbage.clear();
3036 }
3037
handleDeviceLost()3038 void ContextVk::handleDeviceLost()
3039 {
3040 (void)mOutsideRenderPassCommands->reset(this);
3041 (void)mRenderPassCommands->reset(this);
3042 mRenderer->handleDeviceLost();
3043 clearAllGarbage();
3044
3045 mRenderer->notifyDeviceLost();
3046 }
3047
drawArrays(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count)3048 angle::Result ContextVk::drawArrays(const gl::Context *context,
3049 gl::PrimitiveMode mode,
3050 GLint first,
3051 GLsizei count)
3052 {
3053 uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
3054
3055 if (mode == gl::PrimitiveMode::LineLoop)
3056 {
3057 uint32_t numIndices;
3058 ANGLE_TRY(setupLineLoopDraw(context, mode, first, count, gl::DrawElementsType::InvalidEnum,
3059 nullptr, &numIndices));
3060 vk::LineLoopHelper::Draw(numIndices, 0, mRenderPassCommandBuffer);
3061 }
3062 else
3063 {
3064 ANGLE_TRY(setupDraw(context, mode, first, count, 1, gl::DrawElementsType::InvalidEnum,
3065 nullptr, mNonIndexedDirtyBitsMask));
3066 mRenderPassCommandBuffer->draw(clampedVertexCount, first);
3067 }
3068
3069 return angle::Result::Continue;
3070 }
3071
drawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances)3072 angle::Result ContextVk::drawArraysInstanced(const gl::Context *context,
3073 gl::PrimitiveMode mode,
3074 GLint first,
3075 GLsizei count,
3076 GLsizei instances)
3077 {
3078 if (mode == gl::PrimitiveMode::LineLoop)
3079 {
3080 uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
3081 uint32_t numIndices;
3082 ANGLE_TRY(setupLineLoopDraw(context, mode, first, clampedVertexCount,
3083 gl::DrawElementsType::InvalidEnum, nullptr, &numIndices));
3084 mRenderPassCommandBuffer->drawIndexedInstanced(numIndices, instances);
3085 return angle::Result::Continue;
3086 }
3087
3088 ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
3089 nullptr, mNonIndexedDirtyBitsMask));
3090 mRenderPassCommandBuffer->drawInstanced(gl::GetClampedVertexCount<uint32_t>(count), instances,
3091 first);
3092 return angle::Result::Continue;
3093 }
3094
drawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances,GLuint baseInstance)3095 angle::Result ContextVk::drawArraysInstancedBaseInstance(const gl::Context *context,
3096 gl::PrimitiveMode mode,
3097 GLint first,
3098 GLsizei count,
3099 GLsizei instances,
3100 GLuint baseInstance)
3101 {
3102 if (mode == gl::PrimitiveMode::LineLoop)
3103 {
3104 uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
3105 uint32_t numIndices;
3106 ANGLE_TRY(setupLineLoopDraw(context, mode, first, clampedVertexCount,
3107 gl::DrawElementsType::InvalidEnum, nullptr, &numIndices));
3108 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertexBaseInstance(numIndices, instances,
3109 0, 0, baseInstance);
3110 return angle::Result::Continue;
3111 }
3112
3113 ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
3114 nullptr, mNonIndexedDirtyBitsMask));
3115 mRenderPassCommandBuffer->drawInstancedBaseInstance(gl::GetClampedVertexCount<uint32_t>(count),
3116 instances, first, baseInstance);
3117 return angle::Result::Continue;
3118 }
3119
drawElements(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices)3120 angle::Result ContextVk::drawElements(const gl::Context *context,
3121 gl::PrimitiveMode mode,
3122 GLsizei count,
3123 gl::DrawElementsType type,
3124 const void *indices)
3125 {
3126 if (mode == gl::PrimitiveMode::LineLoop)
3127 {
3128 uint32_t indexCount;
3129 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
3130 vk::LineLoopHelper::Draw(indexCount, 0, mRenderPassCommandBuffer);
3131 }
3132 else
3133 {
3134 ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices));
3135 mRenderPassCommandBuffer->drawIndexed(count);
3136 }
3137
3138 return angle::Result::Continue;
3139 }
3140
drawElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)3141 angle::Result ContextVk::drawElementsBaseVertex(const gl::Context *context,
3142 gl::PrimitiveMode mode,
3143 GLsizei count,
3144 gl::DrawElementsType type,
3145 const void *indices,
3146 GLint baseVertex)
3147 {
3148 if (mode == gl::PrimitiveMode::LineLoop)
3149 {
3150 uint32_t indexCount;
3151 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
3152 vk::LineLoopHelper::Draw(indexCount, baseVertex, mRenderPassCommandBuffer);
3153 }
3154 else
3155 {
3156 ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices));
3157 mRenderPassCommandBuffer->drawIndexedBaseVertex(count, baseVertex);
3158 }
3159
3160 return angle::Result::Continue;
3161 }
3162
drawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances)3163 angle::Result ContextVk::drawElementsInstanced(const gl::Context *context,
3164 gl::PrimitiveMode mode,
3165 GLsizei count,
3166 gl::DrawElementsType type,
3167 const void *indices,
3168 GLsizei instances)
3169 {
3170 if (mode == gl::PrimitiveMode::LineLoop)
3171 {
3172 uint32_t indexCount;
3173 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
3174 count = indexCount;
3175 }
3176 else
3177 {
3178 ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices));
3179 }
3180
3181 mRenderPassCommandBuffer->drawIndexedInstanced(count, instances);
3182 return angle::Result::Continue;
3183 }
3184
drawElementsInstancedBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex)3185 angle::Result ContextVk::drawElementsInstancedBaseVertex(const gl::Context *context,
3186 gl::PrimitiveMode mode,
3187 GLsizei count,
3188 gl::DrawElementsType type,
3189 const void *indices,
3190 GLsizei instances,
3191 GLint baseVertex)
3192 {
3193 if (mode == gl::PrimitiveMode::LineLoop)
3194 {
3195 uint32_t indexCount;
3196 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
3197 count = indexCount;
3198 }
3199 else
3200 {
3201 ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices));
3202 }
3203
3204 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertex(count, instances, baseVertex);
3205 return angle::Result::Continue;
3206 }
3207
drawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex,GLuint baseInstance)3208 angle::Result ContextVk::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
3209 gl::PrimitiveMode mode,
3210 GLsizei count,
3211 gl::DrawElementsType type,
3212 const void *indices,
3213 GLsizei instances,
3214 GLint baseVertex,
3215 GLuint baseInstance)
3216 {
3217 if (mode == gl::PrimitiveMode::LineLoop)
3218 {
3219 uint32_t indexCount;
3220 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
3221 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertexBaseInstance(
3222 indexCount, instances, 0, baseVertex, baseInstance);
3223 return angle::Result::Continue;
3224 }
3225
3226 ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices));
3227 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertexBaseInstance(count, instances, 0,
3228 baseVertex, baseInstance);
3229 return angle::Result::Continue;
3230 }
3231
drawRangeElements(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices)3232 angle::Result ContextVk::drawRangeElements(const gl::Context *context,
3233 gl::PrimitiveMode mode,
3234 GLuint start,
3235 GLuint end,
3236 GLsizei count,
3237 gl::DrawElementsType type,
3238 const void *indices)
3239 {
3240 return drawElements(context, mode, count, type, indices);
3241 }
3242
drawRangeElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)3243 angle::Result ContextVk::drawRangeElementsBaseVertex(const gl::Context *context,
3244 gl::PrimitiveMode mode,
3245 GLuint start,
3246 GLuint end,
3247 GLsizei count,
3248 gl::DrawElementsType type,
3249 const void *indices,
3250 GLint baseVertex)
3251 {
3252 return drawElementsBaseVertex(context, mode, count, type, indices, baseVertex);
3253 }
3254
getDevice() const3255 VkDevice ContextVk::getDevice() const
3256 {
3257 return mRenderer->getDevice();
3258 }
3259
drawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect)3260 angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
3261 gl::PrimitiveMode mode,
3262 const void *indirect)
3263 {
3264 return multiDrawArraysIndirectHelper(context, mode, indirect, 1, 0);
3265 }
3266
drawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect)3267 angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
3268 gl::PrimitiveMode mode,
3269 gl::DrawElementsType type,
3270 const void *indirect)
3271 {
3272 return multiDrawElementsIndirectHelper(context, mode, type, indirect, 1, 0);
3273 }
3274
multiDrawArrays(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,GLsizei drawcount)3275 angle::Result ContextVk::multiDrawArrays(const gl::Context *context,
3276 gl::PrimitiveMode mode,
3277 const GLint *firsts,
3278 const GLsizei *counts,
3279 GLsizei drawcount)
3280 {
3281 return rx::MultiDrawArraysGeneral(this, context, mode, firsts, counts, drawcount);
3282 }
3283
multiDrawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,GLsizei drawcount)3284 angle::Result ContextVk::multiDrawArraysInstanced(const gl::Context *context,
3285 gl::PrimitiveMode mode,
3286 const GLint *firsts,
3287 const GLsizei *counts,
3288 const GLsizei *instanceCounts,
3289 GLsizei drawcount)
3290 {
3291 return rx::MultiDrawArraysInstancedGeneral(this, context, mode, firsts, counts, instanceCounts,
3292 drawcount);
3293 }
3294
multiDrawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect,GLsizei drawcount,GLsizei stride)3295 angle::Result ContextVk::multiDrawArraysIndirect(const gl::Context *context,
3296 gl::PrimitiveMode mode,
3297 const void *indirect,
3298 GLsizei drawcount,
3299 GLsizei stride)
3300 {
3301 return multiDrawArraysIndirectHelper(context, mode, indirect, drawcount, stride);
3302 }
3303
multiDrawArraysIndirectHelper(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect,GLsizei drawcount,GLsizei stride)3304 angle::Result ContextVk::multiDrawArraysIndirectHelper(const gl::Context *context,
3305 gl::PrimitiveMode mode,
3306 const void *indirect,
3307 GLsizei drawcount,
3308 GLsizei stride)
3309 {
3310 VertexArrayVk *vertexArrayVk = getVertexArray();
3311 if (drawcount > 1 && !CanMultiDrawIndirectUseCmd(this, vertexArrayVk, mode, drawcount, stride))
3312 {
3313 return rx::MultiDrawArraysIndirectGeneral(this, context, mode, indirect, drawcount, stride);
3314 }
3315
3316 // Stride must be a multiple of the size of VkDrawIndirectCommand (stride = 0 is invalid when
3317 // drawcount > 1).
3318 uint32_t vkStride = (stride == 0 && drawcount > 1) ? sizeof(VkDrawIndirectCommand) : stride;
3319
3320 gl::Buffer *indirectBuffer = mState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
3321 vk::BufferHelper *currentIndirectBuf = &vk::GetImpl(indirectBuffer)->getBuffer();
3322 VkDeviceSize currentIndirectBufOffset = reinterpret_cast<VkDeviceSize>(indirect);
3323
3324 if (vertexArrayVk->getStreamingVertexAttribsMask().any())
3325 {
3326 // Handling instanced vertex attributes is not covered for drawcount > 1.
3327 ASSERT(drawcount <= 1);
3328
3329 // We have instanced vertex attributes that need to be emulated for Vulkan.
3330 // invalidate any cache and map the buffer so that we can read the indirect data.
3331 // Mapping the buffer will cause a flush.
3332 ANGLE_TRY(currentIndirectBuf->invalidate(mRenderer, 0, sizeof(VkDrawIndirectCommand)));
3333 uint8_t *buffPtr;
3334 ANGLE_TRY(currentIndirectBuf->map(this, &buffPtr));
3335 const VkDrawIndirectCommand *indirectData =
3336 reinterpret_cast<VkDrawIndirectCommand *>(buffPtr + currentIndirectBufOffset);
3337
3338 ANGLE_TRY(drawArraysInstanced(context, mode, indirectData->firstVertex,
3339 indirectData->vertexCount, indirectData->instanceCount));
3340
3341 currentIndirectBuf->unmap(mRenderer);
3342 return angle::Result::Continue;
3343 }
3344
3345 if (mode == gl::PrimitiveMode::LineLoop)
3346 {
3347 // Line loop only supports handling at most one indirect parameter.
3348 ASSERT(drawcount <= 1);
3349
3350 ASSERT(indirectBuffer);
3351 vk::BufferHelper *dstIndirectBuf = nullptr;
3352
3353 ANGLE_TRY(setupLineLoopIndirectDraw(context, mode, currentIndirectBuf,
3354 currentIndirectBufOffset, &dstIndirectBuf));
3355
3356 mRenderPassCommandBuffer->drawIndexedIndirect(
3357 dstIndirectBuf->getBuffer(), dstIndirectBuf->getOffset(), drawcount, vkStride);
3358 return angle::Result::Continue;
3359 }
3360
3361 ANGLE_TRY(setupIndirectDraw(context, mode, mNonIndexedDirtyBitsMask, currentIndirectBuf));
3362
3363 mRenderPassCommandBuffer->drawIndirect(
3364 currentIndirectBuf->getBuffer(), currentIndirectBuf->getOffset() + currentIndirectBufOffset,
3365 drawcount, vkStride);
3366
3367 return angle::Result::Continue;
3368 }
3369
multiDrawElements(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,GLsizei drawcount)3370 angle::Result ContextVk::multiDrawElements(const gl::Context *context,
3371 gl::PrimitiveMode mode,
3372 const GLsizei *counts,
3373 gl::DrawElementsType type,
3374 const GLvoid *const *indices,
3375 GLsizei drawcount)
3376 {
3377 return rx::MultiDrawElementsGeneral(this, context, mode, counts, type, indices, drawcount);
3378 }
3379
multiDrawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,GLsizei drawcount)3380 angle::Result ContextVk::multiDrawElementsInstanced(const gl::Context *context,
3381 gl::PrimitiveMode mode,
3382 const GLsizei *counts,
3383 gl::DrawElementsType type,
3384 const GLvoid *const *indices,
3385 const GLsizei *instanceCounts,
3386 GLsizei drawcount)
3387 {
3388 return rx::MultiDrawElementsInstancedGeneral(this, context, mode, counts, type, indices,
3389 instanceCounts, drawcount);
3390 }
3391
multiDrawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect,GLsizei drawcount,GLsizei stride)3392 angle::Result ContextVk::multiDrawElementsIndirect(const gl::Context *context,
3393 gl::PrimitiveMode mode,
3394 gl::DrawElementsType type,
3395 const void *indirect,
3396 GLsizei drawcount,
3397 GLsizei stride)
3398 {
3399 return multiDrawElementsIndirectHelper(context, mode, type, indirect, drawcount, stride);
3400 }
3401
multiDrawElementsIndirectHelper(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect,GLsizei drawcount,GLsizei stride)3402 angle::Result ContextVk::multiDrawElementsIndirectHelper(const gl::Context *context,
3403 gl::PrimitiveMode mode,
3404 gl::DrawElementsType type,
3405 const void *indirect,
3406 GLsizei drawcount,
3407 GLsizei stride)
3408 {
3409 VertexArrayVk *vertexArrayVk = getVertexArray();
3410 if (drawcount > 1 && !CanMultiDrawIndirectUseCmd(this, vertexArrayVk, mode, drawcount, stride))
3411 {
3412 return rx::MultiDrawElementsIndirectGeneral(this, context, mode, type, indirect, drawcount,
3413 stride);
3414 }
3415
3416 // Stride must be a multiple of the size of VkDrawIndexedIndirectCommand (stride = 0 is invalid
3417 // when drawcount > 1).
3418 uint32_t vkStride =
3419 (stride == 0 && drawcount > 1) ? sizeof(VkDrawIndexedIndirectCommand) : stride;
3420
3421 gl::Buffer *indirectBuffer = mState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
3422 ASSERT(indirectBuffer);
3423 vk::BufferHelper *currentIndirectBuf = &vk::GetImpl(indirectBuffer)->getBuffer();
3424 VkDeviceSize currentIndirectBufOffset = reinterpret_cast<VkDeviceSize>(indirect);
3425
3426 // Reset the index buffer offset
3427 mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
3428 mCurrentIndexBufferOffset = 0;
3429
3430 if (vertexArrayVk->getStreamingVertexAttribsMask().any())
3431 {
3432 // Handling instanced vertex attributes is not covered for drawcount > 1.
3433 ASSERT(drawcount <= 1);
3434
3435 // We have instanced vertex attributes that need to be emulated for Vulkan.
3436 // invalidate any cache and map the buffer so that we can read the indirect data.
3437 // Mapping the buffer will cause a flush.
3438 ANGLE_TRY(
3439 currentIndirectBuf->invalidate(mRenderer, 0, sizeof(VkDrawIndexedIndirectCommand)));
3440 uint8_t *buffPtr;
3441 ANGLE_TRY(currentIndirectBuf->map(this, &buffPtr));
3442 const VkDrawIndexedIndirectCommand *indirectData =
3443 reinterpret_cast<VkDrawIndexedIndirectCommand *>(buffPtr + currentIndirectBufOffset);
3444
3445 ANGLE_TRY(drawElementsInstanced(context, mode, indirectData->indexCount, type, nullptr,
3446 indirectData->instanceCount));
3447
3448 currentIndirectBuf->unmap(mRenderer);
3449 return angle::Result::Continue;
3450 }
3451
3452 if (shouldConvertUint8VkIndexType(type) && mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
3453 {
3454 ANGLE_VK_PERF_WARNING(
3455 this, GL_DEBUG_SEVERITY_LOW,
3456 "Potential inefficiency emulating uint8 vertex attributes due to lack "
3457 "of hardware support");
3458
3459 vk::BufferHelper *dstIndirectBuf;
3460
3461 ANGLE_TRY(vertexArrayVk->convertIndexBufferIndirectGPU(
3462 this, currentIndirectBuf, currentIndirectBufOffset, &dstIndirectBuf));
3463
3464 currentIndirectBuf = dstIndirectBuf;
3465 currentIndirectBufOffset = 0;
3466 }
3467
3468 if (mode == gl::PrimitiveMode::LineLoop)
3469 {
3470 // Line loop only supports handling at most one indirect parameter.
3471 ASSERT(drawcount <= 1);
3472
3473 vk::BufferHelper *dstIndirectBuf;
3474
3475 ANGLE_TRY(setupLineLoopIndexedIndirectDraw(context, mode, type, currentIndirectBuf,
3476 currentIndirectBufOffset, &dstIndirectBuf));
3477
3478 currentIndirectBuf = dstIndirectBuf;
3479 currentIndirectBufOffset = 0;
3480 }
3481 else
3482 {
3483 ANGLE_TRY(setupIndexedIndirectDraw(context, mode, type, currentIndirectBuf));
3484 }
3485
3486 mRenderPassCommandBuffer->drawIndexedIndirect(
3487 currentIndirectBuf->getBuffer(), currentIndirectBuf->getOffset() + currentIndirectBufOffset,
3488 drawcount, vkStride);
3489
3490 return angle::Result::Continue;
3491 }
3492
multiDrawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,const GLuint * baseInstances,GLsizei drawcount)3493 angle::Result ContextVk::multiDrawArraysInstancedBaseInstance(const gl::Context *context,
3494 gl::PrimitiveMode mode,
3495 const GLint *firsts,
3496 const GLsizei *counts,
3497 const GLsizei *instanceCounts,
3498 const GLuint *baseInstances,
3499 GLsizei drawcount)
3500 {
3501 return rx::MultiDrawArraysInstancedBaseInstanceGeneral(
3502 this, context, mode, firsts, counts, instanceCounts, baseInstances, drawcount);
3503 }
3504
multiDrawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,const GLint * baseVertices,const GLuint * baseInstances,GLsizei drawcount)3505 angle::Result ContextVk::multiDrawElementsInstancedBaseVertexBaseInstance(
3506 const gl::Context *context,
3507 gl::PrimitiveMode mode,
3508 const GLsizei *counts,
3509 gl::DrawElementsType type,
3510 const GLvoid *const *indices,
3511 const GLsizei *instanceCounts,
3512 const GLint *baseVertices,
3513 const GLuint *baseInstances,
3514 GLsizei drawcount)
3515 {
3516 return rx::MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral(
3517 this, context, mode, counts, type, indices, instanceCounts, baseVertices, baseInstances,
3518 drawcount);
3519 }
3520
optimizeRenderPassForPresent(VkFramebuffer framebufferHandle,vk::ImageViewHelper * colorImageView,vk::ImageHelper * colorImage,vk::ImageHelper * colorImageMS,VkPresentModeKHR presentMode,bool * imageResolved)3521 angle::Result ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle,
3522 vk::ImageViewHelper *colorImageView,
3523 vk::ImageHelper *colorImage,
3524 vk::ImageHelper *colorImageMS,
3525 VkPresentModeKHR presentMode,
3526 bool *imageResolved)
3527 {
3528 if (!mRenderPassCommands->started())
3529 {
3530 return angle::Result::Continue;
3531 }
3532
3533 if (framebufferHandle != mRenderPassCommands->getFramebufferHandle())
3534 {
3535 return angle::Result::Continue;
3536 }
3537
3538 // EGL1.5 spec: The contents of ancillary buffers are always undefined after calling
3539 // eglSwapBuffers
3540 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
3541 RenderTargetVk *depthStencilRenderTarget = drawFramebufferVk->getDepthStencilRenderTarget();
3542 if (depthStencilRenderTarget != nullptr)
3543 {
3544 // Change depth/stencil attachment storeOp to DONT_CARE
3545 const gl::DepthStencilState &dsState = mState.getDepthStencilState();
3546 mRenderPassCommands->invalidateRenderPassDepthAttachment(
3547 dsState, mRenderPassCommands->getRenderArea());
3548 mRenderPassCommands->invalidateRenderPassStencilAttachment(
3549 dsState, mRenderPassCommands->getRenderArea());
3550 }
3551
3552 // Resolve the multisample image
3553 if (colorImageMS->valid())
3554 {
3555 vk::ImageOrBufferViewSubresourceSerial resolveImageViewSerial =
3556 colorImageView->getSubresourceSerial(gl::LevelIndex(0), 1, 0, vk::LayerMode::All,
3557 vk::SrgbDecodeMode::SkipDecode,
3558 gl::SrgbOverride::Default);
3559 ASSERT(resolveImageViewSerial.viewSerial.valid());
3560 drawFramebufferVk->updateColorResolveAttachment(0, resolveImageViewSerial);
3561
3562 const vk::ImageView *resolveImageView = nullptr;
3563 ANGLE_TRY(colorImageView->getLevelLayerDrawImageView(this, *colorImage, vk::LevelIndex(0),
3564 0, gl::SrgbWriteControlMode::Default,
3565 &resolveImageView));
3566 vk::Framebuffer *newFramebuffer = nullptr;
3567 constexpr SwapchainResolveMode kSwapchainResolveMode = SwapchainResolveMode::Enabled;
3568 ANGLE_TRY(drawFramebufferVk->getFramebuffer(this, &newFramebuffer, resolveImageView,
3569 kSwapchainResolveMode));
3570
3571 vk::RenderPassCommandBufferHelper &commandBufferHelper = getStartedRenderPassCommands();
3572 commandBufferHelper.updateRenderPassForResolve(this, newFramebuffer,
3573 drawFramebufferVk->getRenderPassDesc());
3574
3575 onImageRenderPassWrite(gl::LevelIndex(0), 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
3576 vk::ImageLayout::ColorAttachment, colorImage);
3577
3578 // Invalidate the surface. See comment in WindowSurfaceVk::doDeferredAcquireNextImage on
3579 // why this is not done when in DEMAND_REFRESH mode.
3580 if (presentMode != VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR)
3581 {
3582 const gl::Rectangle invalidateArea(0, 0, colorImageMS->getExtents().width,
3583 colorImageMS->getExtents().height);
3584 commandBufferHelper.invalidateRenderPassColorAttachment(
3585 mState, 0, vk::PackedAttachmentIndex(0), invalidateArea);
3586 }
3587
3588 ANGLE_TRY(
3589 flushCommandsAndEndRenderPass(RenderPassClosureReason::AlreadySpecifiedElsewhere));
3590
3591 // Remove the resolve attachment from the draw framebuffer.
3592 drawFramebufferVk->removeColorResolveAttachment(0);
3593
3594 *imageResolved = true;
3595
3596 mPerfCounters.swapchainResolveInSubpass++;
3597 }
3598
3599 // Use finalLayout instead of extra barrier for layout change to present
3600 if (colorImage != nullptr)
3601 {
3602 mRenderPassCommands->setImageOptimizeForPresent(colorImage);
3603 }
3604 return angle::Result::Continue;
3605 }
3606
getResetStatus()3607 gl::GraphicsResetStatus ContextVk::getResetStatus()
3608 {
3609 if (mRenderer->isDeviceLost())
3610 {
3611 // TODO(geofflang): It may be possible to track which context caused the device lost and
3612 // return either GL_GUILTY_CONTEXT_RESET or GL_INNOCENT_CONTEXT_RESET.
3613 // http://anglebug.com/2787
3614 return gl::GraphicsResetStatus::UnknownContextReset;
3615 }
3616
3617 return gl::GraphicsResetStatus::NoError;
3618 }
3619
insertEventMarker(GLsizei length,const char * marker)3620 angle::Result ContextVk::insertEventMarker(GLsizei length, const char *marker)
3621 {
3622 insertEventMarkerImpl(GL_DEBUG_SOURCE_APPLICATION, marker);
3623 return angle::Result::Continue;
3624 }
3625
insertEventMarkerImpl(GLenum source,const char * marker)3626 void ContextVk::insertEventMarkerImpl(GLenum source, const char *marker)
3627 {
3628 if (!mRenderer->enableDebugUtils() && !mRenderer->angleDebuggerMode())
3629 {
3630 return;
3631 }
3632
3633 VkDebugUtilsLabelEXT label;
3634 vk::MakeDebugUtilsLabel(source, marker, &label);
3635
3636 if (hasStartedRenderPass())
3637 {
3638 mRenderPassCommandBuffer->insertDebugUtilsLabelEXT(label);
3639 }
3640 else
3641 {
3642 mOutsideRenderPassCommands->getCommandBuffer().insertDebugUtilsLabelEXT(label);
3643 }
3644 }
3645
pushGroupMarker(GLsizei length,const char * marker)3646 angle::Result ContextVk::pushGroupMarker(GLsizei length, const char *marker)
3647 {
3648 return pushDebugGroupImpl(GL_DEBUG_SOURCE_APPLICATION, 0, marker);
3649 }
3650
popGroupMarker()3651 angle::Result ContextVk::popGroupMarker()
3652 {
3653 return popDebugGroupImpl();
3654 }
3655
pushDebugGroup(const gl::Context * context,GLenum source,GLuint id,const std::string & message)3656 angle::Result ContextVk::pushDebugGroup(const gl::Context *context,
3657 GLenum source,
3658 GLuint id,
3659 const std::string &message)
3660 {
3661 return pushDebugGroupImpl(source, id, message.c_str());
3662 }
3663
popDebugGroup(const gl::Context * context)3664 angle::Result ContextVk::popDebugGroup(const gl::Context *context)
3665 {
3666 return popDebugGroupImpl();
3667 }
3668
pushDebugGroupImpl(GLenum source,GLuint id,const char * message)3669 angle::Result ContextVk::pushDebugGroupImpl(GLenum source, GLuint id, const char *message)
3670 {
3671 if (!mRenderer->enableDebugUtils() && !mRenderer->angleDebuggerMode())
3672 {
3673 return angle::Result::Continue;
3674 }
3675
3676 VkDebugUtilsLabelEXT label;
3677 vk::MakeDebugUtilsLabel(source, message, &label);
3678
3679 if (hasStartedRenderPass())
3680 {
3681 mRenderPassCommandBuffer->beginDebugUtilsLabelEXT(label);
3682 }
3683 else
3684 {
3685 mOutsideRenderPassCommands->getCommandBuffer().beginDebugUtilsLabelEXT(label);
3686 }
3687
3688 return angle::Result::Continue;
3689 }
3690
popDebugGroupImpl()3691 angle::Result ContextVk::popDebugGroupImpl()
3692 {
3693 if (!mRenderer->enableDebugUtils() && !mRenderer->angleDebuggerMode())
3694 {
3695 return angle::Result::Continue;
3696 }
3697
3698 if (hasStartedRenderPass())
3699 {
3700 mRenderPassCommandBuffer->endDebugUtilsLabelEXT();
3701 }
3702 else
3703 {
3704 mOutsideRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
3705 }
3706
3707 return angle::Result::Continue;
3708 }
3709
logEvent(const char * eventString)3710 void ContextVk::logEvent(const char *eventString)
3711 {
3712 if (!mRenderer->angleDebuggerMode())
3713 {
3714 return;
3715 }
3716
3717 // Save this event (about an OpenGL ES command being called).
3718 mEventLog.push_back(eventString);
3719
3720 // Set a dirty bit in order to stay off the "hot path" for when not logging.
3721 mGraphicsDirtyBits.set(DIRTY_BIT_EVENT_LOG);
3722 mComputeDirtyBits.set(DIRTY_BIT_EVENT_LOG);
3723 }
3724
endEventLog(angle::EntryPoint entryPoint,PipelineType pipelineType)3725 void ContextVk::endEventLog(angle::EntryPoint entryPoint, PipelineType pipelineType)
3726 {
3727 if (!mRenderer->angleDebuggerMode())
3728 {
3729 return;
3730 }
3731
3732 if (pipelineType == PipelineType::Graphics)
3733 {
3734 ASSERT(mRenderPassCommands);
3735 mRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
3736 }
3737 else
3738 {
3739 ASSERT(pipelineType == PipelineType::Compute);
3740 ASSERT(mOutsideRenderPassCommands);
3741 mOutsideRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
3742 }
3743 }
endEventLogForClearOrQuery()3744 void ContextVk::endEventLogForClearOrQuery()
3745 {
3746 if (!mRenderer->angleDebuggerMode())
3747 {
3748 return;
3749 }
3750
3751 switch (mQueryEventType)
3752 {
3753 case GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd:
3754 ASSERT(mOutsideRenderPassCommands);
3755 mOutsideRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
3756 break;
3757 case GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd:
3758 ASSERT(mRenderPassCommands);
3759 mRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
3760 break;
3761 case GraphicsEventCmdBuf::NotInQueryCmd:
3762 // The glClear* or gl*Query* command was noop'd or otherwise ended early. We could
3763 // call handleDirtyEventLogImpl() to start the hierarchy, but it isn't clear which (if
3764 // any) command buffer to use. We'll just skip processing this command (other than to
3765 // let it stay queued for the next time handleDirtyEventLogImpl() is called.
3766 return;
3767 default:
3768 UNREACHABLE();
3769 }
3770
3771 mQueryEventType = GraphicsEventCmdBuf::NotInQueryCmd;
3772 }
3773
handleNoopDrawEvent()3774 angle::Result ContextVk::handleNoopDrawEvent()
3775 {
3776 // Even though this draw call is being no-op'd, we still must handle the dirty event log
3777 return handleDirtyEventLogImpl(mRenderPassCommandBuffer);
3778 }
3779
handleGraphicsEventLog(GraphicsEventCmdBuf queryEventType)3780 angle::Result ContextVk::handleGraphicsEventLog(GraphicsEventCmdBuf queryEventType)
3781 {
3782 ASSERT(mQueryEventType == GraphicsEventCmdBuf::NotInQueryCmd || mEventLog.empty());
3783 if (!mRenderer->angleDebuggerMode())
3784 {
3785 return angle::Result::Continue;
3786 }
3787
3788 mQueryEventType = queryEventType;
3789
3790 switch (mQueryEventType)
3791 {
3792 case GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd:
3793 ASSERT(mOutsideRenderPassCommands);
3794 return handleDirtyEventLogImpl(&mOutsideRenderPassCommands->getCommandBuffer());
3795 case GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd:
3796 ASSERT(mRenderPassCommands);
3797 return handleDirtyEventLogImpl(&mRenderPassCommands->getCommandBuffer());
3798 default:
3799 UNREACHABLE();
3800 return angle::Result::Stop;
3801 }
3802 }
3803
isViewportFlipEnabledForDrawFBO() const3804 bool ContextVk::isViewportFlipEnabledForDrawFBO() const
3805 {
3806 return mFlipViewportForDrawFramebuffer && mFlipYForCurrentSurface;
3807 }
3808
isViewportFlipEnabledForReadFBO() const3809 bool ContextVk::isViewportFlipEnabledForReadFBO() const
3810 {
3811 return mFlipViewportForReadFramebuffer;
3812 }
3813
isRotatedAspectRatioForDrawFBO() const3814 bool ContextVk::isRotatedAspectRatioForDrawFBO() const
3815 {
3816 return IsRotatedAspectRatio(mCurrentRotationDrawFramebuffer);
3817 }
3818
isRotatedAspectRatioForReadFBO() const3819 bool ContextVk::isRotatedAspectRatioForReadFBO() const
3820 {
3821 return IsRotatedAspectRatio(mCurrentRotationReadFramebuffer);
3822 }
3823
getRotationDrawFramebuffer() const3824 SurfaceRotation ContextVk::getRotationDrawFramebuffer() const
3825 {
3826 return mCurrentRotationDrawFramebuffer;
3827 }
3828
getRotationReadFramebuffer() const3829 SurfaceRotation ContextVk::getRotationReadFramebuffer() const
3830 {
3831 return mCurrentRotationReadFramebuffer;
3832 }
3833
updateColorMasks()3834 void ContextVk::updateColorMasks()
3835 {
3836 const gl::BlendStateExt &blendStateExt = mState.getBlendStateExt();
3837
3838 mClearColorMasks = blendStateExt.mColorMask;
3839
3840 FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
3841 mGraphicsPipelineDesc->updateColorWriteMasks(&mGraphicsPipelineTransition, mClearColorMasks,
3842 framebufferVk->getEmulatedAlphaAttachmentMask(),
3843 framebufferVk->getState().getEnabledDrawBuffers());
3844
3845 onColorAccessChange();
3846 }
3847
updateBlendFuncsAndEquations()3848 void ContextVk::updateBlendFuncsAndEquations()
3849 {
3850 const gl::BlendStateExt &blendStateExt = mState.getBlendStateExt();
3851
3852 FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
3853 mCachedDrawFramebufferColorAttachmentMask = framebufferVk->getState().getEnabledDrawBuffers();
3854
3855 mGraphicsPipelineDesc->updateBlendFuncs(&mGraphicsPipelineTransition, blendStateExt,
3856 mCachedDrawFramebufferColorAttachmentMask);
3857
3858 mGraphicsPipelineDesc->updateBlendEquations(&mGraphicsPipelineTransition, blendStateExt,
3859 mCachedDrawFramebufferColorAttachmentMask);
3860 }
3861
updateSampleMaskWithRasterizationSamples(const uint32_t rasterizationSamples)3862 void ContextVk::updateSampleMaskWithRasterizationSamples(const uint32_t rasterizationSamples)
3863 {
3864 // FramebufferVk::syncState could have been the origin for this call, at which point the
3865 // draw FBO may have changed, retrieve the latest draw FBO.
3866 FramebufferVk *drawFramebuffer = vk::GetImpl(mState.getDrawFramebuffer());
3867
3868 // If sample coverage is enabled, emulate it by generating and applying a mask on top of the
3869 // sample mask.
3870 uint32_t coverageSampleCount = GetCoverageSampleCount(mState, drawFramebuffer);
3871
3872 static_assert(sizeof(uint32_t) == sizeof(GLbitfield), "Vulkan assumes 32-bit sample masks");
3873 for (uint32_t maskNumber = 0; maskNumber < mState.getMaxSampleMaskWords(); ++maskNumber)
3874 {
3875 uint32_t mask = mState.isSampleMaskEnabled() && rasterizationSamples > 1
3876 ? mState.getSampleMaskWord(maskNumber)
3877 : std::numeric_limits<uint32_t>::max();
3878
3879 ApplySampleCoverage(mState, coverageSampleCount, maskNumber, &mask);
3880
3881 mGraphicsPipelineDesc->updateSampleMask(&mGraphicsPipelineTransition, maskNumber, mask);
3882 }
3883 }
3884
getCorrectedViewport(const gl::Rectangle & viewport) const3885 gl::Rectangle ContextVk::getCorrectedViewport(const gl::Rectangle &viewport) const
3886 {
3887 const gl::Caps &caps = getCaps();
3888 const VkPhysicalDeviceLimits &limitsVk = mRenderer->getPhysicalDeviceProperties().limits;
3889 const int viewportBoundsRangeLow = static_cast<int>(limitsVk.viewportBoundsRange[0]);
3890 const int viewportBoundsRangeHigh = static_cast<int>(limitsVk.viewportBoundsRange[1]);
3891
3892 // Clamp the viewport values to what Vulkan specifies
3893
3894 // width must be greater than 0.0 and less than or equal to
3895 // VkPhysicalDeviceLimits::maxViewportDimensions[0]
3896 int correctedWidth = std::min<int>(viewport.width, caps.maxViewportWidth);
3897 correctedWidth = std::max<int>(correctedWidth, 0);
3898 // height must be greater than 0.0 and less than or equal to
3899 // VkPhysicalDeviceLimits::maxViewportDimensions[1]
3900 int correctedHeight = std::min<int>(viewport.height, caps.maxViewportHeight);
3901 correctedHeight = std::max<int>(correctedHeight, 0);
3902 // x and y must each be between viewportBoundsRange[0] and viewportBoundsRange[1], inclusive.
3903 // Viewport size cannot be 0 so ensure there is always size for a 1x1 viewport
3904 int correctedX = std::min<int>(viewport.x, viewportBoundsRangeHigh - 1);
3905 correctedX = std::max<int>(correctedX, viewportBoundsRangeLow);
3906 int correctedY = std::min<int>(viewport.y, viewportBoundsRangeHigh - 1);
3907 correctedY = std::max<int>(correctedY, viewportBoundsRangeLow);
3908 // x + width must be less than or equal to viewportBoundsRange[1]
3909 if ((correctedX + correctedWidth) > viewportBoundsRangeHigh)
3910 {
3911 correctedWidth = viewportBoundsRangeHigh - correctedX;
3912 }
3913 // y + height must be less than or equal to viewportBoundsRange[1]
3914 if ((correctedY + correctedHeight) > viewportBoundsRangeHigh)
3915 {
3916 correctedHeight = viewportBoundsRangeHigh - correctedY;
3917 }
3918
3919 return gl::Rectangle(correctedX, correctedY, correctedWidth, correctedHeight);
3920 }
3921
updateViewport(FramebufferVk * framebufferVk,const gl::Rectangle & viewport,float nearPlane,float farPlane)3922 void ContextVk::updateViewport(FramebufferVk *framebufferVk,
3923 const gl::Rectangle &viewport,
3924 float nearPlane,
3925 float farPlane)
3926 {
3927
3928 gl::Box fbDimensions = framebufferVk->getState().getDimensions();
3929 gl::Rectangle correctedRect = getCorrectedViewport(viewport);
3930 gl::Rectangle rotatedRect;
3931 RotateRectangle(getRotationDrawFramebuffer(), false, fbDimensions.width, fbDimensions.height,
3932 correctedRect, &rotatedRect);
3933
3934 bool invertViewport =
3935 isViewportFlipEnabledForDrawFBO() && getFeatures().supportsNegativeViewport.enabled;
3936
3937 gl_vk::GetViewport(
3938 rotatedRect, nearPlane, farPlane, invertViewport,
3939 // If clip space origin is upper left, viewport origin's y value will be offset by the
3940 // height of the viewport when clip space is mapped into screen space.
3941 mState.getClipSpaceOrigin() == gl::ClipSpaceOrigin::UpperLeft,
3942 // If the surface is rotated 90/270 degrees, use the framebuffer's width instead of the
3943 // height for calculating the final viewport.
3944 isRotatedAspectRatioForDrawFBO() ? fbDimensions.width : fbDimensions.height, &mViewport);
3945
3946 // Ensure viewport is within Vulkan requirements
3947 vk::ClampViewport(&mViewport);
3948
3949 invalidateGraphicsDriverUniforms();
3950 mGraphicsDirtyBits.set(DIRTY_BIT_VIEWPORT);
3951 }
3952
updateDepthRange(float nearPlane,float farPlane)3953 void ContextVk::updateDepthRange(float nearPlane, float farPlane)
3954 {
3955 // GLES2.0 Section 2.12.1: Each of n and f are clamped to lie within [0, 1], as are all
3956 // arguments of type clampf.
3957 ASSERT(nearPlane >= 0.0f && nearPlane <= 1.0f);
3958 ASSERT(farPlane >= 0.0f && farPlane <= 1.0f);
3959 mViewport.minDepth = nearPlane;
3960 mViewport.maxDepth = farPlane;
3961
3962 invalidateGraphicsDriverUniforms();
3963 mGraphicsDirtyBits.set(DIRTY_BIT_VIEWPORT);
3964 }
3965
updateScissor(const gl::State & glState)3966 void ContextVk::updateScissor(const gl::State &glState)
3967 {
3968 FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
3969 gl::Rectangle renderArea = framebufferVk->getNonRotatedCompleteRenderArea();
3970
3971 // Clip the render area to the viewport.
3972 gl::Rectangle viewportClippedRenderArea;
3973 if (!gl::ClipRectangle(renderArea, getCorrectedViewport(glState.getViewport()),
3974 &viewportClippedRenderArea))
3975 {
3976 viewportClippedRenderArea = gl::Rectangle();
3977 }
3978
3979 gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false);
3980 gl::Rectangle rotatedScissoredArea;
3981 RotateRectangle(getRotationDrawFramebuffer(), isViewportFlipEnabledForDrawFBO(),
3982 renderArea.width, renderArea.height, scissoredArea, &rotatedScissoredArea);
3983 mScissor = gl_vk::GetRect(rotatedScissoredArea);
3984 mGraphicsDirtyBits.set(DIRTY_BIT_SCISSOR);
3985
3986 // If the scissor has grown beyond the previous scissoredRenderArea, grow the render pass render
3987 // area. The only undesirable effect this may have is that if the render area does not cover a
3988 // previously invalidated area, that invalidate will have to be discarded.
3989 if (mRenderPassCommandBuffer &&
3990 !mRenderPassCommands->getRenderArea().encloses(rotatedScissoredArea))
3991 {
3992 ASSERT(mRenderPassCommands->started());
3993 mRenderPassCommands->growRenderArea(this, rotatedScissoredArea);
3994 }
3995 }
3996
updateDepthStencil(const gl::State & glState)3997 void ContextVk::updateDepthStencil(const gl::State &glState)
3998 {
3999 const gl::DepthStencilState depthStencilState = glState.getDepthStencilState();
4000
4001 gl::Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
4002 mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition, depthStencilState,
4003 drawFramebuffer);
4004 mGraphicsPipelineDesc->updateDepthWriteEnabled(&mGraphicsPipelineTransition, depthStencilState,
4005 drawFramebuffer);
4006 mGraphicsPipelineDesc->updateStencilTestEnabled(&mGraphicsPipelineTransition, depthStencilState,
4007 drawFramebuffer);
4008 mGraphicsPipelineDesc->updateStencilFrontWriteMask(&mGraphicsPipelineTransition,
4009 depthStencilState, drawFramebuffer);
4010 mGraphicsPipelineDesc->updateStencilBackWriteMask(&mGraphicsPipelineTransition,
4011 depthStencilState, drawFramebuffer);
4012 }
4013
4014 // If the target is a single-sampled target, sampleShading should be disabled, to use Bresenham line
4015 // rasterization feature.
updateSampleShadingWithRasterizationSamples(const uint32_t rasterizationSamples)4016 void ContextVk::updateSampleShadingWithRasterizationSamples(const uint32_t rasterizationSamples)
4017 {
4018 bool sampleShadingEnable =
4019 (rasterizationSamples <= 1 ? false : mState.isSampleShadingEnabled());
4020
4021 mGraphicsPipelineDesc->updateSampleShading(&mGraphicsPipelineTransition, sampleShadingEnable,
4022 mState.getMinSampleShading());
4023 }
4024
4025 // If the target is switched between a single-sampled and multisample, the dependency related to the
4026 // rasterization sample should be updated.
updateRasterizationSamples(const uint32_t rasterizationSamples)4027 void ContextVk::updateRasterizationSamples(const uint32_t rasterizationSamples)
4028 {
4029 mGraphicsPipelineDesc->updateRasterizationSamples(&mGraphicsPipelineTransition,
4030 rasterizationSamples);
4031 updateSampleShadingWithRasterizationSamples(rasterizationSamples);
4032 updateSampleMaskWithRasterizationSamples(rasterizationSamples);
4033 }
4034
updateRasterizerDiscardEnabled(bool isPrimitivesGeneratedQueryActive)4035 void ContextVk::updateRasterizerDiscardEnabled(bool isPrimitivesGeneratedQueryActive)
4036 {
4037 // On some devices, when rasterizerDiscardEnable is enabled, the
4038 // VK_EXT_primitives_generated_query as well as the pipeline statistics query used to emulate it
4039 // are non-functional. For VK_EXT_primitives_generated_query there's a feature bit but not for
4040 // pipeline statistics query. If the primitives generated query is active (and rasterizer
4041 // discard is not supported), rasterizerDiscardEnable is set to false and the functionality
4042 // is otherwise emulated (by using an empty scissor).
4043
4044 // If the primitives generated query implementation supports rasterizer discard, just set
4045 // rasterizer discard as requested. Otherwise disable it.
4046 bool isRasterizerDiscardEnabled = mState.isRasterizerDiscardEnabled();
4047 bool isEmulatingRasterizerDiscard = isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(
4048 isPrimitivesGeneratedQueryActive);
4049
4050 mGraphicsPipelineDesc->updateRasterizerDiscardEnabled(
4051 &mGraphicsPipelineTransition, isRasterizerDiscardEnabled && !isEmulatingRasterizerDiscard);
4052
4053 invalidateCurrentGraphicsPipeline();
4054
4055 if (!isEmulatingRasterizerDiscard)
4056 {
4057 return;
4058 }
4059
4060 // If we are emulating rasterizer discard, update the scissor if in render pass. If not in
4061 // render pass, DIRTY_BIT_SCISSOR will be set when the render pass next starts.
4062 if (hasStartedRenderPass())
4063 {
4064 handleDirtyGraphicsScissorImpl(isPrimitivesGeneratedQueryActive);
4065 }
4066 }
4067
updateAdvancedBlendEquations(const gl::ProgramExecutable * executable)4068 void ContextVk::updateAdvancedBlendEquations(const gl::ProgramExecutable *executable)
4069 {
4070 if (!getFeatures().emulateAdvancedBlendEquations.enabled || executable == nullptr)
4071 {
4072 return;
4073 }
4074
4075 // If advanced blend equations is emulated and the program uses advanced equations, update the
4076 // driver uniforms to pass the equation to the shader.
4077 if (executable->getAdvancedBlendEquations().any())
4078 {
4079 invalidateGraphicsDriverUniforms();
4080 }
4081 }
4082
updateDither()4083 void ContextVk::updateDither()
4084 {
4085 if (!getFeatures().emulateDithering.enabled)
4086 {
4087 return;
4088 }
4089
4090 FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
4091
4092 // Dithering in OpenGL is vaguely defined, to the extent that no dithering is also a valid
4093 // dithering algorithm. Dithering is enabled by default, but emulating it has a non-negligible
4094 // cost. Similarly to some other GLES drivers, ANGLE enables dithering only on low-bit formats
4095 // where visual banding is particularly common; namely RGBA4444, RGBA5551 and RGB565.
4096 //
4097 // Dithering is emulated in the fragment shader and is controlled by a spec constant. Every 2
4098 // bits of the spec constant correspond to one attachment, with the value indicating:
4099 //
4100 // - 00: No dithering
4101 // - 01: Dither for RGBA4444
4102 // - 10: Dither for RGBA5551
4103 // - 11: Dither for RGB565
4104 //
4105 uint16_t ditherControl = 0;
4106 if (mState.isDitherEnabled())
4107 {
4108 // As dithering is emulated in the fragment shader itself, there are a number of situations
4109 // that can lead to incorrect blending. When blend is enabled, dither is not enabled to
4110 // avoid such situations.
4111 const gl::DrawBufferMask attachmentMask =
4112 framebufferVk->getState().getColorAttachmentsMask() &
4113 ~mState.getBlendEnabledDrawBufferMask();
4114 for (size_t colorIndex : attachmentMask)
4115 {
4116 RenderTargetVk *attachment = framebufferVk->getColorDrawRenderTarget(colorIndex);
4117 const angle::FormatID format = attachment->getImageActualFormatID();
4118
4119 uint16_t attachmentDitherControl = sh::vk::kDitherControlNoDither;
4120 switch (format)
4121 {
4122 case angle::FormatID::R4G4B4A4_UNORM:
4123 case angle::FormatID::B4G4R4A4_UNORM:
4124 attachmentDitherControl = sh::vk::kDitherControlDither4444;
4125 break;
4126 case angle::FormatID::R5G5B5A1_UNORM:
4127 case angle::FormatID::B5G5R5A1_UNORM:
4128 case angle::FormatID::A1R5G5B5_UNORM:
4129 attachmentDitherControl = sh::vk::kDitherControlDither5551;
4130 break;
4131 case angle::FormatID::R5G6B5_UNORM:
4132 case angle::FormatID::B5G6R5_UNORM:
4133 attachmentDitherControl = sh::vk::kDitherControlDither565;
4134 break;
4135 default:
4136 break;
4137 }
4138
4139 ditherControl |= static_cast<uint16_t>(attachmentDitherControl << 2 * colorIndex);
4140 }
4141 }
4142
4143 if (ditherControl != mGraphicsPipelineDesc->getEmulatedDitherControl())
4144 {
4145 mGraphicsPipelineDesc->updateEmulatedDitherControl(&mGraphicsPipelineTransition,
4146 ditherControl);
4147 invalidateCurrentGraphicsPipeline();
4148 }
4149 }
4150
checkAndUpdateFramebufferFetchStatus(const gl::ProgramExecutable * executable)4151 angle::Result ContextVk::checkAndUpdateFramebufferFetchStatus(
4152 const gl::ProgramExecutable *executable)
4153 {
4154 if (!executable)
4155 {
4156 return angle::Result::Continue;
4157 }
4158
4159 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
4160 ASSERT(drawFramebufferVk);
4161
4162 if (drawFramebufferVk->getRenderPassDesc().getFramebufferFetchMode() !=
4163 executable->usesFramebufferFetch())
4164 {
4165 drawFramebufferVk->onSwitchProgramFramebufferFetch(this,
4166 executable->usesFramebufferFetch());
4167 if (executable->usesFramebufferFetch())
4168 {
4169 mRenderer->onFramebufferFetchUsed();
4170
4171 // When framebuffer fetch is enabled, attachments can be read from even if output is
4172 // masked, so update their access.
4173 onColorAccessChange();
4174 }
4175 }
4176
4177 return angle::Result::Continue;
4178 }
4179
invalidateProgramExecutableHelper(const gl::Context * context)4180 angle::Result ContextVk::invalidateProgramExecutableHelper(const gl::Context *context)
4181 {
4182 const gl::State &glState = context->getState();
4183 const gl::ProgramExecutable *executable = glState.getProgramExecutable();
4184
4185 if (executable->hasLinkedShaderStage(gl::ShaderType::Compute))
4186 {
4187 invalidateCurrentComputePipeline();
4188 }
4189
4190 if (executable->hasLinkedShaderStage(gl::ShaderType::Vertex))
4191 {
4192 invalidateCurrentGraphicsPipeline();
4193 // No additional work is needed here. We will update the pipeline desc
4194 // later.
4195 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
4196 invalidateVertexAndIndexBuffers();
4197 bool useVertexBuffer = (executable->getMaxActiveAttribLocation() > 0);
4198 mNonIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
4199 mIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
4200 mCurrentGraphicsPipeline = nullptr;
4201 mGraphicsPipelineTransition.reset();
4202
4203 ProgramExecutableVk *executableVk = getExecutable();
4204 ASSERT(executableVk);
4205 executableVk->updateEarlyFragmentTestsOptimization(this, *executable);
4206
4207 if (getDrawFramebuffer()->getRenderPassDesc().getFramebufferFetchMode() !=
4208 executable->usesFramebufferFetch())
4209 {
4210 ANGLE_TRY(
4211 flushCommandsAndEndRenderPass(RenderPassClosureReason::FramebufferFetchEmulation));
4212
4213 ANGLE_TRY(checkAndUpdateFramebufferFetchStatus(executable));
4214 }
4215 }
4216
4217 return angle::Result::Continue;
4218 }
4219
syncState(const gl::Context * context,const gl::State::DirtyBits & dirtyBits,const gl::State::DirtyBits & bitMask,gl::Command command)4220 angle::Result ContextVk::syncState(const gl::Context *context,
4221 const gl::State::DirtyBits &dirtyBits,
4222 const gl::State::DirtyBits &bitMask,
4223 gl::Command command)
4224 {
4225 const gl::State &glState = context->getState();
4226 const gl::ProgramExecutable *programExecutable = glState.getProgramExecutable();
4227
4228 if ((dirtyBits & mPipelineDirtyBitsMask).any() &&
4229 (programExecutable == nullptr || command != gl::Command::Dispatch))
4230 {
4231 invalidateCurrentGraphicsPipeline();
4232 }
4233
4234 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
4235 VertexArrayVk *vertexArrayVk = getVertexArray();
4236
4237 for (auto iter = dirtyBits.begin(), endIter = dirtyBits.end(); iter != endIter; ++iter)
4238 {
4239 size_t dirtyBit = *iter;
4240 switch (dirtyBit)
4241 {
4242 case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED:
4243 case gl::State::DIRTY_BIT_SCISSOR:
4244 updateScissor(glState);
4245 break;
4246 case gl::State::DIRTY_BIT_VIEWPORT:
4247 {
4248 FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
4249 updateViewport(framebufferVk, glState.getViewport(), glState.getNearPlane(),
4250 glState.getFarPlane());
4251 // Update the scissor, which will be constrained to the viewport
4252 updateScissor(glState);
4253 break;
4254 }
4255 case gl::State::DIRTY_BIT_DEPTH_RANGE:
4256 updateDepthRange(glState.getNearPlane(), glState.getFarPlane());
4257 break;
4258 case gl::State::DIRTY_BIT_BLEND_ENABLED:
4259 mGraphicsPipelineDesc->updateBlendEnabled(&mGraphicsPipelineTransition,
4260 glState.getBlendStateExt().mEnabledMask);
4261 updateDither();
4262 break;
4263 case gl::State::DIRTY_BIT_BLEND_COLOR:
4264 mGraphicsPipelineDesc->updateBlendColor(&mGraphicsPipelineTransition,
4265 glState.getBlendColor());
4266 break;
4267 case gl::State::DIRTY_BIT_BLEND_FUNCS:
4268 mGraphicsPipelineDesc->updateBlendFuncs(
4269 &mGraphicsPipelineTransition, glState.getBlendStateExt(),
4270 drawFramebufferVk->getState().getColorAttachmentsMask());
4271 break;
4272 case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
4273 mGraphicsPipelineDesc->updateBlendEquations(
4274 &mGraphicsPipelineTransition, glState.getBlendStateExt(),
4275 drawFramebufferVk->getState().getColorAttachmentsMask());
4276 updateAdvancedBlendEquations(programExecutable);
4277 break;
4278 case gl::State::DIRTY_BIT_COLOR_MASK:
4279 updateColorMasks();
4280 break;
4281 case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
4282 mGraphicsPipelineDesc->updateAlphaToCoverageEnable(
4283 &mGraphicsPipelineTransition, glState.isSampleAlphaToCoverageEnabled());
4284 static_assert(gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE >
4285 gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED,
4286 "Dirty bit order");
4287 iter.setLaterBit(gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE);
4288 break;
4289 case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED:
4290 updateSampleMaskWithRasterizationSamples(drawFramebufferVk->getSamples());
4291 break;
4292 case gl::State::DIRTY_BIT_SAMPLE_COVERAGE:
4293 updateSampleMaskWithRasterizationSamples(drawFramebufferVk->getSamples());
4294 break;
4295 case gl::State::DIRTY_BIT_SAMPLE_MASK_ENABLED:
4296 updateSampleMaskWithRasterizationSamples(drawFramebufferVk->getSamples());
4297 break;
4298 case gl::State::DIRTY_BIT_SAMPLE_MASK:
4299 updateSampleMaskWithRasterizationSamples(drawFramebufferVk->getSamples());
4300 break;
4301 case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED:
4302 {
4303 mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition,
4304 glState.getDepthStencilState(),
4305 glState.getDrawFramebuffer());
4306 iter.setLaterBit(gl::State::DIRTY_BIT_DEPTH_MASK);
4307 break;
4308 }
4309 case gl::State::DIRTY_BIT_DEPTH_FUNC:
4310 mGraphicsPipelineDesc->updateDepthFunc(&mGraphicsPipelineTransition,
4311 glState.getDepthStencilState());
4312 break;
4313 case gl::State::DIRTY_BIT_DEPTH_MASK:
4314 {
4315 mGraphicsPipelineDesc->updateDepthWriteEnabled(&mGraphicsPipelineTransition,
4316 glState.getDepthStencilState(),
4317 glState.getDrawFramebuffer());
4318 onDepthStencilAccessChange();
4319 break;
4320 }
4321 case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED:
4322 {
4323 mGraphicsPipelineDesc->updateStencilTestEnabled(&mGraphicsPipelineTransition,
4324 glState.getDepthStencilState(),
4325 glState.getDrawFramebuffer());
4326 onDepthStencilAccessChange();
4327 break;
4328 }
4329 case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT:
4330 mGraphicsPipelineDesc->updateStencilFrontFuncs(&mGraphicsPipelineTransition,
4331 glState.getStencilRef(),
4332 glState.getDepthStencilState());
4333 onDepthStencilAccessChange();
4334 break;
4335 case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK:
4336 mGraphicsPipelineDesc->updateStencilBackFuncs(&mGraphicsPipelineTransition,
4337 glState.getStencilBackRef(),
4338 glState.getDepthStencilState());
4339 onDepthStencilAccessChange();
4340 break;
4341 case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT:
4342 mGraphicsPipelineDesc->updateStencilFrontOps(&mGraphicsPipelineTransition,
4343 glState.getDepthStencilState());
4344 onDepthStencilAccessChange();
4345 break;
4346 case gl::State::DIRTY_BIT_STENCIL_OPS_BACK:
4347 mGraphicsPipelineDesc->updateStencilBackOps(&mGraphicsPipelineTransition,
4348 glState.getDepthStencilState());
4349 onDepthStencilAccessChange();
4350 break;
4351 case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
4352 mGraphicsPipelineDesc->updateStencilFrontWriteMask(&mGraphicsPipelineTransition,
4353 glState.getDepthStencilState(),
4354 glState.getDrawFramebuffer());
4355 onDepthStencilAccessChange();
4356 break;
4357 case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
4358 mGraphicsPipelineDesc->updateStencilBackWriteMask(&mGraphicsPipelineTransition,
4359 glState.getDepthStencilState(),
4360 glState.getDrawFramebuffer());
4361 onDepthStencilAccessChange();
4362 break;
4363 case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
4364 case gl::State::DIRTY_BIT_CULL_FACE:
4365 mGraphicsPipelineDesc->updateCullMode(&mGraphicsPipelineTransition,
4366 glState.getRasterizerState());
4367 break;
4368 case gl::State::DIRTY_BIT_FRONT_FACE:
4369 mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
4370 glState.getRasterizerState(),
4371 isYFlipEnabledForDrawFBO());
4372 break;
4373 case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
4374 mGraphicsPipelineDesc->updatePolygonOffsetFillEnabled(
4375 &mGraphicsPipelineTransition, glState.isPolygonOffsetFillEnabled());
4376 break;
4377 case gl::State::DIRTY_BIT_POLYGON_OFFSET:
4378 mGraphicsPipelineDesc->updatePolygonOffset(&mGraphicsPipelineTransition,
4379 glState.getRasterizerState());
4380 break;
4381 case gl::State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED:
4382 updateRasterizerDiscardEnabled(
4383 mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
4384 onColorAccessChange();
4385 break;
4386 case gl::State::DIRTY_BIT_LINE_WIDTH:
4387 mGraphicsPipelineDesc->updateLineWidth(&mGraphicsPipelineTransition,
4388 glState.getLineWidth());
4389 break;
4390 case gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED:
4391 mGraphicsPipelineDesc->updatePrimitiveRestartEnabled(
4392 &mGraphicsPipelineTransition, glState.isPrimitiveRestartEnabled());
4393 break;
4394 case gl::State::DIRTY_BIT_CLEAR_COLOR:
4395 mClearColorValue.color.float32[0] = glState.getColorClearValue().red;
4396 mClearColorValue.color.float32[1] = glState.getColorClearValue().green;
4397 mClearColorValue.color.float32[2] = glState.getColorClearValue().blue;
4398 mClearColorValue.color.float32[3] = glState.getColorClearValue().alpha;
4399 break;
4400 case gl::State::DIRTY_BIT_CLEAR_DEPTH:
4401 mClearDepthStencilValue.depthStencil.depth = glState.getDepthClearValue();
4402 break;
4403 case gl::State::DIRTY_BIT_CLEAR_STENCIL:
4404 mClearDepthStencilValue.depthStencil.stencil =
4405 static_cast<uint32_t>(glState.getStencilClearValue());
4406 break;
4407 case gl::State::DIRTY_BIT_UNPACK_STATE:
4408 // This is a no-op, it's only important to use the right unpack state when we do
4409 // setImage or setSubImage in TextureVk, which is plumbed through the frontend
4410 // call
4411 break;
4412 case gl::State::DIRTY_BIT_UNPACK_BUFFER_BINDING:
4413 break;
4414 case gl::State::DIRTY_BIT_PACK_STATE:
4415 // This is a no-op, its only important to use the right pack state when we do
4416 // call readPixels later on.
4417 break;
4418 case gl::State::DIRTY_BIT_PACK_BUFFER_BINDING:
4419 break;
4420 case gl::State::DIRTY_BIT_DITHER_ENABLED:
4421 updateDither();
4422 break;
4423 case gl::State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING:
4424 updateFlipViewportReadFramebuffer(context->getState());
4425 updateSurfaceRotationReadFramebuffer(glState);
4426 break;
4427 case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
4428 {
4429 // FramebufferVk::syncState signals that we should start a new command buffer.
4430 // But changing the binding can skip FramebufferVk::syncState if the Framebuffer
4431 // has no dirty bits. Thus we need to explicitly clear the current command
4432 // buffer to ensure we start a new one. We don't actually close the render pass here
4433 // as some optimizations in non-draw commands require the render pass to remain
4434 // open, such as invalidate or blit. Note that we always start a new command buffer
4435 // because we currently can only support one open RenderPass at a time.
4436 onRenderPassFinished(RenderPassClosureReason::FramebufferBindingChange);
4437 if (getFeatures().preferSubmitAtFBOBoundary.enabled)
4438 {
4439 // This will behave as if user called glFlush, but the actual flush will be
4440 // triggered at endRenderPass time.
4441 mHasDeferredFlush = true;
4442 }
4443
4444 drawFramebufferVk->setReadOnlyDepthFeedbackLoopMode(false);
4445 updateFlipViewportDrawFramebuffer(glState);
4446 updateSurfaceRotationDrawFramebuffer(glState);
4447 SpecConstUsageBits usageBits = getCurrentProgramSpecConstUsageBits();
4448 updateGraphicsPipelineDescWithSpecConstUsageBits(usageBits);
4449 updateViewport(drawFramebufferVk, glState.getViewport(), glState.getNearPlane(),
4450 glState.getFarPlane());
4451 updateColorMasks();
4452 updateRasterizationSamples(drawFramebufferVk->getSamples());
4453 updateRasterizerDiscardEnabled(
4454 mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
4455
4456 mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
4457 glState.getRasterizerState(),
4458 isYFlipEnabledForDrawFBO());
4459 updateScissor(glState);
4460 updateDepthStencil(glState);
4461 updateDither();
4462
4463 // Clear the blend funcs/equations for color attachment indices that no longer
4464 // exist.
4465 gl::DrawBufferMask newColorAttachmentMask =
4466 drawFramebufferVk->getState().getColorAttachmentsMask();
4467 mGraphicsPipelineDesc->resetBlendFuncsAndEquations(
4468 &mGraphicsPipelineTransition, glState.getBlendStateExt(),
4469 mCachedDrawFramebufferColorAttachmentMask, newColorAttachmentMask);
4470 mCachedDrawFramebufferColorAttachmentMask = newColorAttachmentMask;
4471
4472 mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
4473 onDrawFramebufferRenderPassDescChange(drawFramebufferVk, nullptr);
4474
4475 // We may need to update the framebuffer's use of fetch to match the in-use program
4476 ANGLE_TRY(checkAndUpdateFramebufferFetchStatus(glState.getProgramExecutable()));
4477
4478 break;
4479 }
4480 case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
4481 break;
4482 case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
4483 {
4484 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
4485 ANGLE_TRY(vertexArrayVk->updateActiveAttribInfo(this));
4486 ANGLE_TRY(onIndexBufferChange(vertexArrayVk->getCurrentElementArrayBuffer()));
4487 break;
4488 }
4489 case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
4490 break;
4491 case gl::State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING:
4492 break;
4493 case gl::State::DIRTY_BIT_PROGRAM_BINDING:
4494 static_assert(
4495 gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE > gl::State::DIRTY_BIT_PROGRAM_BINDING,
4496 "Dirty bit order");
4497 iter.setLaterBit(gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE);
4498 break;
4499 case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
4500 {
4501 ASSERT(programExecutable);
4502 invalidateCurrentDefaultUniforms();
4503 updateAdvancedBlendEquations(programExecutable);
4504 getExecutable()->onProgramBind(*programExecutable);
4505 static_assert(
4506 gl::State::DIRTY_BIT_TEXTURE_BINDINGS > gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE,
4507 "Dirty bit order");
4508 iter.setLaterBit(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
4509 static_assert(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING >
4510 gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE,
4511 "Dirty bit order");
4512 iter.setLaterBit(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
4513 ANGLE_TRY(invalidateProgramExecutableHelper(context));
4514 break;
4515 }
4516 case gl::State::DIRTY_BIT_SAMPLER_BINDINGS:
4517 {
4518 static_assert(
4519 gl::State::DIRTY_BIT_TEXTURE_BINDINGS > gl::State::DIRTY_BIT_SAMPLER_BINDINGS,
4520 "Dirty bit order");
4521 iter.setLaterBit(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
4522 break;
4523 }
4524 case gl::State::DIRTY_BIT_TEXTURE_BINDINGS:
4525 ANGLE_TRY(invalidateCurrentTextures(context, command));
4526 break;
4527 case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
4528 // Nothing to do.
4529 break;
4530 case gl::State::DIRTY_BIT_IMAGE_BINDINGS:
4531 static_assert(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING >
4532 gl::State::DIRTY_BIT_IMAGE_BINDINGS,
4533 "Dirty bit order");
4534 iter.setLaterBit(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
4535 break;
4536 case gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING:
4537 static_assert(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING >
4538 gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING,
4539 "Dirty bit order");
4540 iter.setLaterBit(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
4541 break;
4542 case gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS:
4543 static_assert(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING >
4544 gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS,
4545 "Dirty bit order");
4546 iter.setLaterBit(gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
4547 break;
4548 case gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING:
4549 ANGLE_TRY(invalidateCurrentShaderResources(command));
4550 invalidateDriverUniforms();
4551 break;
4552 case gl::State::DIRTY_BIT_MULTISAMPLING:
4553 // TODO(syoussefi): this should configure the pipeline to render as if
4554 // single-sampled, and write the results to all samples of a pixel regardless of
4555 // coverage. See EXT_multisample_compatibility. http://anglebug.com/3204
4556 break;
4557 case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE:
4558 // TODO(syoussefi): this is part of EXT_multisample_compatibility. The
4559 // alphaToOne Vulkan feature should be enabled to support this extension.
4560 // http://anglebug.com/3204
4561 mGraphicsPipelineDesc->updateAlphaToOneEnable(&mGraphicsPipelineTransition,
4562 glState.isSampleAlphaToOneEnabled());
4563 break;
4564 case gl::State::DIRTY_BIT_SAMPLE_SHADING:
4565 updateSampleShadingWithRasterizationSamples(drawFramebufferVk->getSamples());
4566 break;
4567 case gl::State::DIRTY_BIT_COVERAGE_MODULATION:
4568 break;
4569 case gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE:
4570 break;
4571 case gl::State::DIRTY_BIT_CURRENT_VALUES:
4572 {
4573 invalidateDefaultAttributes(glState.getAndResetDirtyCurrentValues());
4574 break;
4575 }
4576 case gl::State::DIRTY_BIT_PROVOKING_VERTEX:
4577 break;
4578 case gl::State::DIRTY_BIT_EXTENDED:
4579 {
4580 gl::State::ExtendedDirtyBits extendedDirtyBits =
4581 glState.getAndResetExtendedDirtyBits();
4582 for (size_t extendedDirtyBit : extendedDirtyBits)
4583 {
4584 switch (extendedDirtyBit)
4585 {
4586 case gl::State::ExtendedDirtyBitType::EXTENDED_DIRTY_BIT_CLIP_CONTROL:
4587 updateViewport(vk::GetImpl(glState.getDrawFramebuffer()),
4588 glState.getViewport(), glState.getNearPlane(),
4589 glState.getFarPlane());
4590 // Since we are flipping the y coordinate, update front face state
4591 mGraphicsPipelineDesc->updateFrontFace(&mGraphicsPipelineTransition,
4592 glState.getRasterizerState(),
4593 isYFlipEnabledForDrawFBO());
4594 updateScissor(glState);
4595
4596 // If VK_EXT_depth_clip_control is not enabled, there's nothing needed
4597 // for depth correction for EXT_clip_control.
4598 // glState will be used to toggle control path of depth correction code
4599 // in SPIR-V tranform options.
4600 if (getFeatures().supportsDepthClipControl.enabled)
4601 {
4602 mGraphicsPipelineDesc->updateDepthClipControl(
4603 &mGraphicsPipelineTransition,
4604 !glState.isClipControlDepthZeroToOne());
4605 }
4606 break;
4607 case gl::State::ExtendedDirtyBitType::EXTENDED_DIRTY_BIT_CLIP_DISTANCES:
4608 invalidateGraphicsDriverUniforms();
4609 break;
4610 case gl::State::ExtendedDirtyBitType::
4611 EXTENDED_DIRTY_BIT_MIPMAP_GENERATION_HINT:
4612 break;
4613 case gl::State::ExtendedDirtyBitType::
4614 EXTENDED_DIRTY_BIT_SHADER_DERIVATIVE_HINT:
4615 break;
4616 default:
4617 UNREACHABLE();
4618 }
4619 }
4620 break;
4621 }
4622 case gl::State::DIRTY_BIT_PATCH_VERTICES:
4623 mGraphicsPipelineDesc->updatePatchVertices(&mGraphicsPipelineTransition,
4624 glState.getPatchVertices());
4625 break;
4626 default:
4627 UNREACHABLE();
4628 break;
4629 }
4630 }
4631
4632 return angle::Result::Continue;
4633 }
4634
getGPUDisjoint()4635 GLint ContextVk::getGPUDisjoint()
4636 {
4637 // No extension seems to be available to query this information.
4638 return 0;
4639 }
4640
getTimestamp()4641 GLint64 ContextVk::getTimestamp()
4642 {
4643 // This function should only be called if timestamp queries are available.
4644 ASSERT(mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
4645
4646 uint64_t timestamp = 0;
4647
4648 (void)getTimestamp(×tamp);
4649
4650 return static_cast<GLint64>(timestamp);
4651 }
4652
onMakeCurrent(const gl::Context * context)4653 angle::Result ContextVk::onMakeCurrent(const gl::Context *context)
4654 {
4655 mRenderer->reloadVolkIfNeeded();
4656
4657 // Flip viewports if the user did not request that the surface is flipped.
4658 egl::Surface *drawSurface = context->getCurrentDrawSurface();
4659 mFlipYForCurrentSurface =
4660 drawSurface != nullptr &&
4661 !IsMaskFlagSet(drawSurface->getOrientation(), EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE);
4662
4663 if (drawSurface && drawSurface->getType() == EGL_WINDOW_BIT)
4664 {
4665 mCurrentWindowSurface = GetImplAs<WindowSurfaceVk>(drawSurface);
4666 }
4667 else
4668 {
4669 mCurrentWindowSurface = nullptr;
4670 }
4671
4672 const gl::State &glState = context->getState();
4673 updateFlipViewportDrawFramebuffer(glState);
4674 updateFlipViewportReadFramebuffer(glState);
4675 updateSurfaceRotationDrawFramebuffer(glState);
4676 updateSurfaceRotationReadFramebuffer(glState);
4677
4678 if (getFeatures().forceDriverUniformOverSpecConst.enabled)
4679 {
4680 invalidateDriverUniforms();
4681 }
4682 else
4683 {
4684 // Force update mGraphicsPipelineDesc
4685 mCurrentGraphicsPipeline = nullptr;
4686 invalidateCurrentGraphicsPipeline();
4687 }
4688
4689 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
4690 if (executable && executable->hasTransformFeedbackOutput() &&
4691 mState.isTransformFeedbackActive())
4692 {
4693 onTransformFeedbackStateChanged();
4694 if (getFeatures().supportsTransformFeedbackExtension.enabled)
4695 {
4696 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
4697 }
4698 }
4699
4700 return angle::Result::Continue;
4701 }
4702
onUnMakeCurrent(const gl::Context * context)4703 angle::Result ContextVk::onUnMakeCurrent(const gl::Context *context)
4704 {
4705 ANGLE_TRY(flushImpl(nullptr, RenderPassClosureReason::ContextChange));
4706 mCurrentWindowSurface = nullptr;
4707 return angle::Result::Continue;
4708 }
4709
updateFlipViewportDrawFramebuffer(const gl::State & glState)4710 void ContextVk::updateFlipViewportDrawFramebuffer(const gl::State &glState)
4711 {
4712 // The default framebuffer (originating from the swapchain) is rendered upside-down due to the
4713 // difference in the coordinate systems of Vulkan and GLES. Rendering upside-down has the
4714 // effect that rendering is done the same way as OpenGL. The KHR_MAINTENANCE_1 extension is
4715 // subsequently enabled to allow negative viewports. We inverse rendering to the backbuffer by
4716 // reversing the height of the viewport and increasing Y by the height. So if the viewport was
4717 // (0, 0, width, height), it becomes (0, height, width, -height). Unfortunately, when we start
4718 // doing this, we also need to adjust a number of places since the rendering now happens
4719 // upside-down. Affected places so far:
4720 //
4721 // - readPixels
4722 // - copyTexImage
4723 // - framebuffer blit
4724 // - generating mipmaps
4725 // - Point sprites tests
4726 // - texStorage
4727 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
4728 mFlipViewportForDrawFramebuffer = drawFramebuffer->isDefault();
4729 }
4730
updateFlipViewportReadFramebuffer(const gl::State & glState)4731 void ContextVk::updateFlipViewportReadFramebuffer(const gl::State &glState)
4732 {
4733 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
4734 mFlipViewportForReadFramebuffer = readFramebuffer->isDefault();
4735 }
4736
getCurrentProgramSpecConstUsageBits() const4737 SpecConstUsageBits ContextVk::getCurrentProgramSpecConstUsageBits() const
4738 {
4739 SpecConstUsageBits usageBits;
4740 if (mState.getProgram())
4741 {
4742 usageBits = mState.getProgram()->getState().getSpecConstUsageBits();
4743 }
4744 else if (mState.getProgramPipeline())
4745 {
4746 usageBits = mState.getProgramPipeline()->getState().getSpecConstUsageBits();
4747 }
4748 return usageBits;
4749 }
4750
updateGraphicsPipelineDescWithSpecConstUsageBits(SpecConstUsageBits usageBits)4751 void ContextVk::updateGraphicsPipelineDescWithSpecConstUsageBits(SpecConstUsageBits usageBits)
4752 {
4753 SurfaceRotation rotationAndFlip = mCurrentRotationDrawFramebuffer;
4754 ASSERT(ToUnderlying(rotationAndFlip) < ToUnderlying(SurfaceRotation::FlippedIdentity));
4755 bool yFlipped =
4756 isViewportFlipEnabledForDrawFBO() && (usageBits.test(sh::vk::SpecConstUsage::YFlip) ||
4757 !getFeatures().supportsNegativeViewport.enabled);
4758
4759 // usageBits are only set when specialization constants are used. With gl_Position pre-rotation
4760 // handled by the SPIR-V transformer, we need to have this information even when the driver
4761 // uniform path is taken to pre-rotate everything else.
4762 const bool programUsesRotation = usageBits.test(sh::vk::SpecConstUsage::Rotation) ||
4763 getFeatures().forceDriverUniformOverSpecConst.enabled;
4764
4765 // If program is not using rotation at all, we force it to use the Identity or FlippedIdentity
4766 // slot to improve the program cache hit rate
4767 if (!programUsesRotation)
4768 {
4769 rotationAndFlip = yFlipped ? SurfaceRotation::FlippedIdentity : SurfaceRotation::Identity;
4770 }
4771 else if (yFlipped)
4772 {
4773 // DetermineSurfaceRotation() does not encode yflip information. Shader code uses
4774 // SurfaceRotation specialization constant to determine yflip as well. We add yflip
4775 // information to the SurfaceRotation here so the shader does yflip properly.
4776 rotationAndFlip = static_cast<SurfaceRotation>(
4777 ToUnderlying(SurfaceRotation::FlippedIdentity) + ToUnderlying(rotationAndFlip));
4778 }
4779 else
4780 {
4781 // If program is not using yflip, then we just use the non-flipped slot to increase the
4782 // chance of pipeline program cache hit even if drawable is yflipped.
4783 }
4784
4785 if (rotationAndFlip != mGraphicsPipelineDesc->getSurfaceRotation())
4786 {
4787 // surface rotation are specialization constants, which affects program compilation. When
4788 // rotation changes, we need to update GraphicsPipelineDesc so that the correct pipeline
4789 // program object will be retrieved.
4790 mGraphicsPipelineDesc->updateSurfaceRotation(&mGraphicsPipelineTransition, rotationAndFlip);
4791 }
4792
4793 if (usageBits.test(sh::vk::SpecConstUsage::DrawableSize))
4794 {
4795 const gl::Box &dimensions = getState().getDrawFramebuffer()->getDimensions();
4796 mGraphicsPipelineDesc->updateDrawableSize(&mGraphicsPipelineTransition, dimensions.width,
4797 dimensions.height);
4798 }
4799 else
4800 {
4801 // Always set specialization constant to 1x1 if it is not used so that pipeline program with
4802 // only drawable size difference will be able to be reused.
4803 mGraphicsPipelineDesc->updateDrawableSize(&mGraphicsPipelineTransition, 1, 1);
4804 }
4805 }
4806
updateSurfaceRotationDrawFramebuffer(const gl::State & glState)4807 void ContextVk::updateSurfaceRotationDrawFramebuffer(const gl::State &glState)
4808 {
4809 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
4810 mCurrentRotationDrawFramebuffer =
4811 DetermineSurfaceRotation(drawFramebuffer, mCurrentWindowSurface);
4812 }
4813
updateSurfaceRotationReadFramebuffer(const gl::State & glState)4814 void ContextVk::updateSurfaceRotationReadFramebuffer(const gl::State &glState)
4815 {
4816 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
4817 mCurrentRotationReadFramebuffer =
4818 DetermineSurfaceRotation(readFramebuffer, mCurrentWindowSurface);
4819 }
4820
getNativeCaps() const4821 gl::Caps ContextVk::getNativeCaps() const
4822 {
4823 return mRenderer->getNativeCaps();
4824 }
4825
getNativeTextureCaps() const4826 const gl::TextureCapsMap &ContextVk::getNativeTextureCaps() const
4827 {
4828 return mRenderer->getNativeTextureCaps();
4829 }
4830
getNativeExtensions() const4831 const gl::Extensions &ContextVk::getNativeExtensions() const
4832 {
4833 return mRenderer->getNativeExtensions();
4834 }
4835
getNativeLimitations() const4836 const gl::Limitations &ContextVk::getNativeLimitations() const
4837 {
4838 return mRenderer->getNativeLimitations();
4839 }
4840
createCompiler()4841 CompilerImpl *ContextVk::createCompiler()
4842 {
4843 return new CompilerVk();
4844 }
4845
createShader(const gl::ShaderState & state)4846 ShaderImpl *ContextVk::createShader(const gl::ShaderState &state)
4847 {
4848 return new ShaderVk(state);
4849 }
4850
createProgram(const gl::ProgramState & state)4851 ProgramImpl *ContextVk::createProgram(const gl::ProgramState &state)
4852 {
4853 return new ProgramVk(state);
4854 }
4855
createFramebuffer(const gl::FramebufferState & state)4856 FramebufferImpl *ContextVk::createFramebuffer(const gl::FramebufferState &state)
4857 {
4858 return FramebufferVk::CreateUserFBO(mRenderer, state);
4859 }
4860
createTexture(const gl::TextureState & state)4861 TextureImpl *ContextVk::createTexture(const gl::TextureState &state)
4862 {
4863 return new TextureVk(state, mRenderer);
4864 }
4865
createRenderbuffer(const gl::RenderbufferState & state)4866 RenderbufferImpl *ContextVk::createRenderbuffer(const gl::RenderbufferState &state)
4867 {
4868 return new RenderbufferVk(state);
4869 }
4870
createBuffer(const gl::BufferState & state)4871 BufferImpl *ContextVk::createBuffer(const gl::BufferState &state)
4872 {
4873 return new BufferVk(state);
4874 }
4875
createVertexArray(const gl::VertexArrayState & state)4876 VertexArrayImpl *ContextVk::createVertexArray(const gl::VertexArrayState &state)
4877 {
4878 return new VertexArrayVk(this, state);
4879 }
4880
createQuery(gl::QueryType type)4881 QueryImpl *ContextVk::createQuery(gl::QueryType type)
4882 {
4883 return new QueryVk(type);
4884 }
4885
createFenceNV()4886 FenceNVImpl *ContextVk::createFenceNV()
4887 {
4888 return new FenceNVVk();
4889 }
4890
createSync()4891 SyncImpl *ContextVk::createSync()
4892 {
4893 return new SyncVk();
4894 }
4895
createTransformFeedback(const gl::TransformFeedbackState & state)4896 TransformFeedbackImpl *ContextVk::createTransformFeedback(const gl::TransformFeedbackState &state)
4897 {
4898 return new TransformFeedbackVk(state);
4899 }
4900
createSampler(const gl::SamplerState & state)4901 SamplerImpl *ContextVk::createSampler(const gl::SamplerState &state)
4902 {
4903 return new SamplerVk(state);
4904 }
4905
createProgramPipeline(const gl::ProgramPipelineState & state)4906 ProgramPipelineImpl *ContextVk::createProgramPipeline(const gl::ProgramPipelineState &state)
4907 {
4908 return new ProgramPipelineVk(state);
4909 }
4910
createMemoryObject()4911 MemoryObjectImpl *ContextVk::createMemoryObject()
4912 {
4913 return new MemoryObjectVk();
4914 }
4915
createSemaphore()4916 SemaphoreImpl *ContextVk::createSemaphore()
4917 {
4918 return new SemaphoreVk();
4919 }
4920
createOverlay(const gl::OverlayState & state)4921 OverlayImpl *ContextVk::createOverlay(const gl::OverlayState &state)
4922 {
4923 return new OverlayVk(state);
4924 }
4925
invalidateCurrentDefaultUniforms()4926 void ContextVk::invalidateCurrentDefaultUniforms()
4927 {
4928 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
4929 ASSERT(executable);
4930
4931 if (executable->hasDefaultUniforms())
4932 {
4933 mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
4934 mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
4935 }
4936 }
4937
invalidateCurrentTextures(const gl::Context * context,gl::Command command)4938 angle::Result ContextVk::invalidateCurrentTextures(const gl::Context *context, gl::Command command)
4939 {
4940 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
4941 ASSERT(executable);
4942
4943 if (executable->hasTextures())
4944 {
4945 mGraphicsDirtyBits |= kTexturesAndDescSetDirtyBits;
4946 mComputeDirtyBits |= kTexturesAndDescSetDirtyBits;
4947
4948 ANGLE_TRY(updateActiveTextures(context, command));
4949
4950 // Take care of read-after-write hazards that require implicit synchronization.
4951 if (command == gl::Command::Dispatch)
4952 {
4953 ANGLE_TRY(endRenderPassIfComputeReadAfterAttachmentWrite());
4954 }
4955 }
4956
4957 return angle::Result::Continue;
4958 }
4959
invalidateCurrentShaderResources(gl::Command command)4960 angle::Result ContextVk::invalidateCurrentShaderResources(gl::Command command)
4961 {
4962 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
4963 ASSERT(executable);
4964
4965 const bool hasImages = executable->hasImages();
4966 const bool hasStorageBuffers =
4967 executable->hasStorageBuffers() || executable->hasAtomicCounterBuffers();
4968 const bool hasUniformBuffers = executable->hasUniformBuffers();
4969
4970 if (hasUniformBuffers || hasStorageBuffers || hasImages || executable->usesFramebufferFetch())
4971 {
4972 mGraphicsDirtyBits |= kResourcesAndDescSetDirtyBits;
4973 mComputeDirtyBits |= kResourcesAndDescSetDirtyBits;
4974 }
4975
4976 // Take care of read-after-write hazards that require implicit synchronization.
4977 if (hasUniformBuffers && command == gl::Command::Dispatch)
4978 {
4979 ANGLE_TRY(endRenderPassIfComputeReadAfterTransformFeedbackWrite());
4980 }
4981
4982 // If memory barrier has been issued but the command buffers haven't been flushed, make sure
4983 // they get a chance to do so if necessary on program and storage buffer/image binding change.
4984 const bool hasGLMemoryBarrierIssuedInCommandBuffers =
4985 mOutsideRenderPassCommands->hasGLMemoryBarrierIssued() ||
4986 mRenderPassCommands->hasGLMemoryBarrierIssued();
4987
4988 if ((hasStorageBuffers || hasImages) && hasGLMemoryBarrierIssuedInCommandBuffers)
4989 {
4990 mGraphicsDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
4991 mComputeDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
4992 }
4993
4994 return angle::Result::Continue;
4995 }
4996
updateShaderResourcesDescriptorDesc(PipelineType pipelineType)4997 void ContextVk::updateShaderResourcesDescriptorDesc(PipelineType pipelineType)
4998 {
4999 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
5000 ASSERT(executable);
5001
5002 const bool hasStorageBuffers =
5003 executable->hasStorageBuffers() || executable->hasAtomicCounterBuffers();
5004 const bool hasUniformBuffers = executable->hasUniformBuffers();
5005
5006 if (!hasUniformBuffers && !hasStorageBuffers)
5007 {
5008 return;
5009 }
5010
5011 mShaderBuffersDescriptorDesc.reset();
5012
5013 ProgramExecutableVk *executableVk = getExecutable();
5014
5015 const gl::BufferVector &uniformBuffers = mState.getOffsetBindingPointerUniformBuffers();
5016 bool isDynamicDescriptor = executableVk->usesDynamicUniformBufferDescriptors();
5017 bool appendOffset = !isDynamicDescriptor;
5018 AppendBufferVectorToDesc(&mShaderBuffersDescriptorDesc, uniformBuffers,
5019 mState.getUniformBuffersMask(), isDynamicDescriptor, appendOffset);
5020
5021 const gl::BufferVector &shaderStorageBuffers =
5022 mState.getOffsetBindingPointerShaderStorageBuffers();
5023 isDynamicDescriptor = executableVk->usesDynamicShaderStorageBufferDescriptors();
5024 appendOffset = true;
5025 AppendBufferVectorToDesc(&mShaderBuffersDescriptorDesc, shaderStorageBuffers,
5026 mState.getShaderStorageBuffersMask(), isDynamicDescriptor,
5027 appendOffset);
5028
5029 const gl::BufferVector &atomicCounterBuffers =
5030 mState.getOffsetBindingPointerAtomicCounterBuffers();
5031 isDynamicDescriptor = executableVk->usesDynamicAtomicCounterBufferDescriptors();
5032 appendOffset = true;
5033 AppendBufferVectorToDesc(&mShaderBuffersDescriptorDesc, atomicCounterBuffers,
5034 mState.getAtomicCounterBuffersMask(), isDynamicDescriptor,
5035 appendOffset);
5036 }
5037
invalidateGraphicsDriverUniforms()5038 void ContextVk::invalidateGraphicsDriverUniforms()
5039 {
5040 mGraphicsDirtyBits |= kDriverUniformsAndBindingDirtyBits;
5041 }
5042
invalidateDriverUniforms()5043 void ContextVk::invalidateDriverUniforms()
5044 {
5045 mGraphicsDirtyBits |= kDriverUniformsAndBindingDirtyBits;
5046 mComputeDirtyBits |= kDriverUniformsAndBindingDirtyBits;
5047 }
5048
onFramebufferChange(FramebufferVk * framebufferVk,gl::Command command)5049 angle::Result ContextVk::onFramebufferChange(FramebufferVk *framebufferVk, gl::Command command)
5050 {
5051 // This is called from FramebufferVk::syncState. Skip these updates if the framebuffer being
5052 // synced is the read framebuffer (which is not equal the draw framebuffer).
5053 if (framebufferVk != vk::GetImpl(mState.getDrawFramebuffer()))
5054 {
5055 return angle::Result::Continue;
5056 }
5057
5058 // Always consider the render pass finished. FramebufferVk::syncState (caller of this function)
5059 // normally closes the render pass, except for blit to allow an optimization. The following
5060 // code nevertheless must treat the render pass closed.
5061 onRenderPassFinished(RenderPassClosureReason::FramebufferChange);
5062
5063 // Ensure that the pipeline description is updated.
5064 if (mGraphicsPipelineDesc->getRasterizationSamples() !=
5065 static_cast<uint32_t>(framebufferVk->getSamples()))
5066 {
5067 updateRasterizationSamples(framebufferVk->getSamples());
5068 }
5069
5070 // Update scissor.
5071 updateScissor(mState);
5072
5073 // Update depth and stencil.
5074 updateDepthStencil(mState);
5075
5076 // Update dither based on attachment formats.
5077 updateDither();
5078
5079 if (mState.getProgramExecutable())
5080 {
5081 ANGLE_TRY(invalidateCurrentShaderResources(command));
5082 }
5083
5084 onDrawFramebufferRenderPassDescChange(framebufferVk, nullptr);
5085
5086 return angle::Result::Continue;
5087 }
5088
onDrawFramebufferRenderPassDescChange(FramebufferVk * framebufferVk,bool * renderPassDescChangedOut)5089 void ContextVk::onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk,
5090 bool *renderPassDescChangedOut)
5091 {
5092 mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition,
5093 framebufferVk->getRenderPassDesc());
5094 const gl::Box &dimensions = framebufferVk->getState().getDimensions();
5095 mGraphicsPipelineDesc->updateDrawableSize(&mGraphicsPipelineTransition, dimensions.width,
5096 dimensions.height);
5097
5098 if (renderPassDescChangedOut)
5099 {
5100 // If render pass desc has changed while processing the dirty bits, notify the caller.
5101 *renderPassDescChangedOut = true;
5102 }
5103 else
5104 {
5105 // Otherwise mark the pipeline as dirty.
5106 invalidateCurrentGraphicsPipeline();
5107 }
5108 }
5109
invalidateCurrentTransformFeedbackBuffers()5110 void ContextVk::invalidateCurrentTransformFeedbackBuffers()
5111 {
5112 if (getFeatures().supportsTransformFeedbackExtension.enabled)
5113 {
5114 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
5115 }
5116 else if (getFeatures().emulateTransformFeedback.enabled)
5117 {
5118 mGraphicsDirtyBits |= kXfbBuffersAndDescSetDirtyBits;
5119 }
5120 }
5121
onTransformFeedbackStateChanged()5122 void ContextVk::onTransformFeedbackStateChanged()
5123 {
5124 if (getFeatures().supportsTransformFeedbackExtension.enabled)
5125 {
5126 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
5127 }
5128 else if (getFeatures().emulateTransformFeedback.enabled)
5129 {
5130 invalidateGraphicsDriverUniforms();
5131 invalidateCurrentTransformFeedbackBuffers();
5132
5133 // Invalidate the graphics pipeline too. On transform feedback state change, the current
5134 // program may be used again, and it should switch between outputting transform feedback and
5135 // not.
5136 invalidateCurrentGraphicsPipeline();
5137 resetCurrentGraphicsPipeline();
5138 }
5139 }
5140
onBeginTransformFeedback(size_t bufferCount,const gl::TransformFeedbackBuffersArray<vk::BufferHelper * > & buffers,const gl::TransformFeedbackBuffersArray<vk::BufferHelper> & counterBuffers)5141 angle::Result ContextVk::onBeginTransformFeedback(
5142 size_t bufferCount,
5143 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers,
5144 const gl::TransformFeedbackBuffersArray<vk::BufferHelper> &counterBuffers)
5145 {
5146 onTransformFeedbackStateChanged();
5147
5148 bool shouldEndRenderPass = false;
5149
5150 // If any of the buffers were previously used in the render pass, break the render pass as a
5151 // barrier is needed.
5152 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
5153 {
5154 const vk::BufferHelper *buffer = buffers[bufferIndex];
5155 if (mRenderPassCommands->usesBuffer(*buffer))
5156 {
5157 shouldEndRenderPass = true;
5158 break;
5159 }
5160 }
5161
5162 if (getFeatures().supportsTransformFeedbackExtension.enabled)
5163 {
5164 // Break the render pass if the counter buffers are used too. Note that Vulkan requires a
5165 // barrier on the counter buffer between pause and resume, so it cannot be resumed in the
5166 // same render pass. Note additionally that we don't need to test all counters being used
5167 // in the render pass, as outside of the transform feedback object these buffers are
5168 // inaccessible and are therefore always used together.
5169 if (!shouldEndRenderPass && mRenderPassCommands->usesBuffer(counterBuffers[0]))
5170 {
5171 shouldEndRenderPass = true;
5172 }
5173
5174 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
5175 }
5176
5177 if (shouldEndRenderPass)
5178 {
5179 ANGLE_TRY(flushCommandsAndEndRenderPass(RenderPassClosureReason::BufferUseThenXfbWrite));
5180 }
5181
5182 populateTransformFeedbackBufferSet(bufferCount, buffers);
5183
5184 return angle::Result::Continue;
5185 }
5186
populateTransformFeedbackBufferSet(size_t bufferCount,const gl::TransformFeedbackBuffersArray<vk::BufferHelper * > & buffers)5187 void ContextVk::populateTransformFeedbackBufferSet(
5188 size_t bufferCount,
5189 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers)
5190 {
5191 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
5192 {
5193 vk::BufferHelper *buffer = buffers[bufferIndex];
5194 if (!mCurrentTransformFeedbackBuffers.contains(buffer))
5195 {
5196 mCurrentTransformFeedbackBuffers.insert(buffer);
5197 }
5198 }
5199 }
5200
onEndTransformFeedback()5201 void ContextVk::onEndTransformFeedback()
5202 {
5203 if (getFeatures().supportsTransformFeedbackExtension.enabled)
5204 {
5205 if (mRenderPassCommands->isTransformFeedbackStarted())
5206 {
5207 mRenderPassCommands->endTransformFeedback();
5208 }
5209 }
5210 else if (getFeatures().emulateTransformFeedback.enabled)
5211 {
5212 onTransformFeedbackStateChanged();
5213 }
5214 }
5215
onPauseTransformFeedback()5216 angle::Result ContextVk::onPauseTransformFeedback()
5217 {
5218 if (getFeatures().supportsTransformFeedbackExtension.enabled)
5219 {
5220 // If transform feedback was already active on this render pass, break it. This
5221 // is for simplicity to avoid tracking multiple simultaneously active transform feedback
5222 // settings in the render pass.
5223 if (mRenderPassCommands->isTransformFeedbackActiveUnpaused())
5224 {
5225 return flushCommandsAndEndRenderPass(RenderPassClosureReason::XfbPause);
5226 }
5227 }
5228 else if (getFeatures().emulateTransformFeedback.enabled)
5229 {
5230 invalidateCurrentTransformFeedbackBuffers();
5231 }
5232 return angle::Result::Continue;
5233 }
5234
invalidateGraphicsPipelineBinding()5235 void ContextVk::invalidateGraphicsPipelineBinding()
5236 {
5237 mGraphicsDirtyBits.set(DIRTY_BIT_PIPELINE_BINDING);
5238 }
5239
invalidateComputePipelineBinding()5240 void ContextVk::invalidateComputePipelineBinding()
5241 {
5242 mComputeDirtyBits.set(DIRTY_BIT_PIPELINE_BINDING);
5243 }
5244
invalidateGraphicsDescriptorSet(DescriptorSetIndex usedDescriptorSet)5245 void ContextVk::invalidateGraphicsDescriptorSet(DescriptorSetIndex usedDescriptorSet)
5246 {
5247 // UtilsVk currently only uses set 0
5248 ASSERT(usedDescriptorSet == DescriptorSetIndex::Internal);
5249 if (mDriverUniforms[PipelineType::Graphics].descriptorSet != VK_NULL_HANDLE)
5250 {
5251 mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
5252 }
5253 }
5254
invalidateComputeDescriptorSet(DescriptorSetIndex usedDescriptorSet)5255 void ContextVk::invalidateComputeDescriptorSet(DescriptorSetIndex usedDescriptorSet)
5256 {
5257 // UtilsVk currently only uses set 0
5258 ASSERT(usedDescriptorSet == DescriptorSetIndex::Internal);
5259 if (mDriverUniforms[PipelineType::Compute].descriptorSet != VK_NULL_HANDLE)
5260 {
5261 mComputeDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
5262 }
5263 }
5264
invalidateViewportAndScissor()5265 void ContextVk::invalidateViewportAndScissor()
5266 {
5267 mGraphicsDirtyBits.set(DIRTY_BIT_VIEWPORT);
5268 mGraphicsDirtyBits.set(DIRTY_BIT_SCISSOR);
5269 }
5270
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)5271 angle::Result ContextVk::dispatchCompute(const gl::Context *context,
5272 GLuint numGroupsX,
5273 GLuint numGroupsY,
5274 GLuint numGroupsZ)
5275 {
5276 ANGLE_TRY(setupDispatch(context));
5277
5278 mOutsideRenderPassCommands->getCommandBuffer().dispatch(numGroupsX, numGroupsY, numGroupsZ);
5279
5280 return angle::Result::Continue;
5281 }
5282
dispatchComputeIndirect(const gl::Context * context,GLintptr indirect)5283 angle::Result ContextVk::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
5284 {
5285 gl::Buffer *glBuffer = getState().getTargetBuffer(gl::BufferBinding::DispatchIndirect);
5286 vk::BufferHelper &buffer = vk::GetImpl(glBuffer)->getBuffer();
5287
5288 // Break the render pass if the indirect buffer was previously used as the output from transform
5289 // feedback.
5290 if (mCurrentTransformFeedbackBuffers.contains(&buffer))
5291 {
5292 ANGLE_TRY(flushCommandsAndEndRenderPass(
5293 RenderPassClosureReason::XfbWriteThenIndirectDispatchBuffer));
5294 }
5295
5296 ANGLE_TRY(setupDispatch(context));
5297
5298 // Process indirect buffer after command buffer has started.
5299 mOutsideRenderPassCommands->bufferRead(this, VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
5300 vk::PipelineStage::DrawIndirect, &buffer);
5301
5302 mOutsideRenderPassCommands->getCommandBuffer().dispatchIndirect(buffer.getBuffer(),
5303 buffer.getOffset() + indirect);
5304
5305 return angle::Result::Continue;
5306 }
5307
memoryBarrier(const gl::Context * context,GLbitfield barriers)5308 angle::Result ContextVk::memoryBarrier(const gl::Context *context, GLbitfield barriers)
5309 {
5310 // First, turn GL_ALL_BARRIER_BITS into a mask that has only the valid barriers set.
5311 constexpr GLbitfield kCoreBarrierBits =
5312 GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | GL_ELEMENT_ARRAY_BARRIER_BIT | GL_UNIFORM_BARRIER_BIT |
5313 GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_COMMAND_BARRIER_BIT |
5314 GL_PIXEL_BUFFER_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT |
5315 GL_FRAMEBUFFER_BARRIER_BIT | GL_TRANSFORM_FEEDBACK_BARRIER_BIT |
5316 GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT;
5317 constexpr GLbitfield kExtensionBarrierBits = GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT;
5318
5319 barriers &= kCoreBarrierBits | kExtensionBarrierBits;
5320
5321 // GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT specifies that a fence sync or glFinish must be used
5322 // after the barrier for the CPU to to see the shader writes. Since host-visible buffer writes
5323 // always issue a barrier automatically for the sake of glMapBuffer() (see
5324 // comment on |mIsAnyHostVisibleBufferWritten|), there's nothing to do for
5325 // GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT.
5326 barriers &= ~GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT;
5327
5328 // If no other barrier, early out.
5329 if (barriers == 0)
5330 {
5331 return angle::Result::Continue;
5332 }
5333
5334 // glMemoryBarrier for barrier bit X_BARRIER_BIT implies:
5335 //
5336 // - An execution+memory barrier: shader writes are made visible to subsequent X accesses
5337 //
5338 // Additionally, SHADER_IMAGE_ACCESS_BARRIER_BIT and SHADER_STORAGE_BARRIER_BIT imply:
5339 //
5340 // - An execution+memory barrier: all accesses are finished before image/buffer writes
5341 //
5342 // For the first barrier, we can simplify the implementation by assuming that prior writes are
5343 // expected to be used right after this barrier, so we can close the render pass or flush the
5344 // outside render pass commands right away if they have had any writes.
5345 //
5346 // It's noteworthy that some barrier bits affect draw/dispatch calls only, while others affect
5347 // other commands. For the latter, since storage buffer and images are not tracked in command
5348 // buffers, we can't rely on the command buffers being flushed in the usual way when recording
5349 // these commands (i.e. through |getOutsideRenderPassCommandBuffer()| and
5350 // |vk::CommandBufferAccess|). Conservatively flushing command buffers with any storage output
5351 // simplifies this use case. If this needs to be avoided in the future,
5352 // |getOutsideRenderPassCommandBuffer()| can be modified to flush the command buffers if they
5353 // have had any storage output.
5354 //
5355 // For the second barrier, we need to defer closing the render pass until there's a draw or
5356 // dispatch call that uses storage buffers or images that were previously used in the render
5357 // pass. This allows the render pass to remain open in scenarios such as this:
5358 //
5359 // - Draw using resource X
5360 // - glMemoryBarrier
5361 // - Draw/dispatch with storage buffer/image Y
5362 //
5363 // To achieve this, a dirty bit is added that breaks the render pass if any storage
5364 // buffer/images are used in it. Until the render pass breaks, changing the program or storage
5365 // buffer/image bindings should set this dirty bit again.
5366
5367 if (mRenderPassCommands->hasShaderStorageOutput())
5368 {
5369 // Break the render pass if necessary as future non-draw commands can't know if they should.
5370 ANGLE_TRY(flushCommandsAndEndRenderPass(
5371 RenderPassClosureReason::StorageResourceUseThenGLMemoryBarrier));
5372 }
5373 else if (mOutsideRenderPassCommands->hasShaderStorageOutput())
5374 {
5375 // Otherwise flush the outside render pass commands if necessary.
5376 ANGLE_TRY(flushOutsideRenderPassCommands());
5377 }
5378
5379 constexpr GLbitfield kWriteAfterAccessBarriers =
5380 GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT;
5381
5382 if ((barriers & kWriteAfterAccessBarriers) == 0)
5383 {
5384 return angle::Result::Continue;
5385 }
5386
5387 // Defer flushing the command buffers until a draw/dispatch with storage buffer/image is
5388 // encountered.
5389 mGraphicsDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
5390 mComputeDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
5391
5392 // Make sure memory barrier is issued for future usages of storage buffers and images even if
5393 // there's no binding change.
5394 mGraphicsDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
5395 mComputeDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
5396
5397 // Mark the command buffers as affected by glMemoryBarrier, so future program and storage
5398 // buffer/image binding changes can set DIRTY_BIT_MEMORY_BARRIER again.
5399 mOutsideRenderPassCommands->setGLMemoryBarrierIssued();
5400 mRenderPassCommands->setGLMemoryBarrierIssued();
5401
5402 return angle::Result::Continue;
5403 }
5404
memoryBarrierByRegion(const gl::Context * context,GLbitfield barriers)5405 angle::Result ContextVk::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers)
5406 {
5407 // Note: memoryBarrierByRegion is expected to affect only the fragment pipeline, but is
5408 // otherwise similar to memoryBarrier in function.
5409 //
5410 // TODO: Optimize memoryBarrierByRegion by issuing an in-subpass pipeline barrier instead of
5411 // breaking the render pass. http://anglebug.com/5132
5412 return memoryBarrier(context, barriers);
5413 }
5414
framebufferFetchBarrier()5415 void ContextVk::framebufferFetchBarrier()
5416 {
5417 mGraphicsDirtyBits.set(DIRTY_BIT_FRAMEBUFFER_FETCH_BARRIER);
5418 }
5419
blendBarrier()5420 void ContextVk::blendBarrier()
5421 {
5422 if (getFeatures().emulateAdvancedBlendEquations.enabled)
5423 {
5424 // When emulated, advanced blend is implemented through framebuffer fetch.
5425 framebufferFetchBarrier();
5426 }
5427 else
5428 {
5429 mGraphicsDirtyBits.set(DIRTY_BIT_BLEND_BARRIER);
5430 }
5431 }
5432
acquireTextures(const gl::Context * context,const gl::TextureBarrierVector & textureBarriers)5433 angle::Result ContextVk::acquireTextures(const gl::Context *context,
5434 const gl::TextureBarrierVector &textureBarriers)
5435 {
5436 for (const gl::TextureAndLayout &textureBarrier : textureBarriers)
5437 {
5438 TextureVk *textureVk = vk::GetImpl(textureBarrier.texture);
5439 vk::ImageHelper &image = textureVk->getImage();
5440 vk::ImageLayout layout = vk::GetImageLayoutFromGLImageLayout(textureBarrier.layout);
5441 // Image should not be accessed while unowned. Emulated formats may have staged updates
5442 // to clear the image after initialization.
5443 ASSERT(!image.hasStagedUpdatesInAllocatedLevels() || image.hasEmulatedImageChannels());
5444 image.setCurrentImageLayout(layout);
5445 }
5446 return angle::Result::Continue;
5447 }
5448
releaseTextures(const gl::Context * context,gl::TextureBarrierVector * textureBarriers)5449 angle::Result ContextVk::releaseTextures(const gl::Context *context,
5450 gl::TextureBarrierVector *textureBarriers)
5451 {
5452 for (gl::TextureAndLayout &textureBarrier : *textureBarriers)
5453 {
5454
5455 TextureVk *textureVk = vk::GetImpl(textureBarrier.texture);
5456
5457 ANGLE_TRY(textureVk->ensureImageInitialized(this, ImageMipLevels::EnabledLevels));
5458
5459 vk::ImageHelper &image = textureVk->getImage();
5460 ANGLE_TRY(onImageReleaseToExternal(image));
5461
5462 textureBarrier.layout =
5463 vk::ConvertImageLayoutToGLImageLayout(image.getCurrentImageLayout());
5464 }
5465
5466 ANGLE_TRY(flushImpl(nullptr, RenderPassClosureReason::ImageUseThenReleaseToExternal));
5467 return mRenderer->ensureNoPendingWork(this);
5468 }
5469
getQueryPool(gl::QueryType queryType)5470 vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType)
5471 {
5472 ASSERT(queryType == gl::QueryType::AnySamples ||
5473 queryType == gl::QueryType::AnySamplesConservative ||
5474 queryType == gl::QueryType::PrimitivesGenerated ||
5475 queryType == gl::QueryType::TransformFeedbackPrimitivesWritten ||
5476 queryType == gl::QueryType::Timestamp || queryType == gl::QueryType::TimeElapsed);
5477
5478 // For PrimitivesGenerated queries:
5479 //
5480 // - If VK_EXT_primitives_generated_query is supported, use that.
5481 // TODO: http://anglebug.com/5430
5482 // - Otherwise, if pipelineStatisticsQuery is supported, use that,
5483 // - Otherwise, use the same pool as TransformFeedbackPrimitivesWritten and share the query as
5484 // the Vulkan transform feedback query produces both results. This option is non-conformant
5485 // as the primitives generated query will not be functional without transform feedback.
5486 //
5487 if (queryType == gl::QueryType::PrimitivesGenerated &&
5488 !getFeatures().supportsPipelineStatisticsQuery.enabled)
5489 {
5490 queryType = gl::QueryType::TransformFeedbackPrimitivesWritten;
5491 }
5492
5493 // Assert that timestamp extension is available if needed.
5494 ASSERT(queryType != gl::QueryType::Timestamp && queryType != gl::QueryType::TimeElapsed ||
5495 mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
5496 ASSERT(mQueryPools[queryType].isValid());
5497 return &mQueryPools[queryType];
5498 }
5499
getClearColorValue() const5500 const VkClearValue &ContextVk::getClearColorValue() const
5501 {
5502 return mClearColorValue;
5503 }
5504
getClearDepthStencilValue() const5505 const VkClearValue &ContextVk::getClearDepthStencilValue() const
5506 {
5507 return mClearDepthStencilValue;
5508 }
5509
getClearColorMasks() const5510 gl::BlendStateExt::ColorMaskStorage::Type ContextVk::getClearColorMasks() const
5511 {
5512 return mClearColorMasks;
5513 }
5514
writeAtomicCounterBufferDriverUniformOffsets(uint32_t * offsetsOut,size_t offsetsSize)5515 void ContextVk::writeAtomicCounterBufferDriverUniformOffsets(uint32_t *offsetsOut,
5516 size_t offsetsSize)
5517 {
5518 const VkDeviceSize offsetAlignment =
5519 mRenderer->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
5520 size_t atomicCounterBufferCount = mState.getAtomicCounterBufferCount();
5521
5522 ASSERT(atomicCounterBufferCount <= offsetsSize * 4);
5523
5524 for (uint32_t bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
5525 {
5526 uint32_t offsetDiff = 0;
5527
5528 const gl::OffsetBindingPointer<gl::Buffer> *atomicCounterBuffer =
5529 &mState.getIndexedAtomicCounterBuffer(bufferIndex);
5530 if (atomicCounterBuffer->get())
5531 {
5532 VkDeviceSize offset = atomicCounterBuffer->getOffset();
5533 VkDeviceSize alignedOffset = (offset / offsetAlignment) * offsetAlignment;
5534
5535 // GL requires the atomic counter buffer offset to be aligned with uint.
5536 ASSERT((offset - alignedOffset) % sizeof(uint32_t) == 0);
5537 offsetDiff = static_cast<uint32_t>((offset - alignedOffset) / sizeof(uint32_t));
5538
5539 // We expect offsetDiff to fit in an 8-bit value. The maximum difference is
5540 // minStorageBufferOffsetAlignment / 4, where minStorageBufferOffsetAlignment
5541 // currently has a maximum value of 256 on any device.
5542 ASSERT(offsetDiff < (1 << 8));
5543 }
5544
5545 // The output array is already cleared prior to this call.
5546 ASSERT(bufferIndex % 4 != 0 || offsetsOut[bufferIndex / 4] == 0);
5547
5548 offsetsOut[bufferIndex / 4] |= static_cast<uint8_t>(offsetDiff) << ((bufferIndex % 4) * 8);
5549 }
5550 }
5551
pauseTransformFeedbackIfActiveUnpaused()5552 void ContextVk::pauseTransformFeedbackIfActiveUnpaused()
5553 {
5554 if (mRenderPassCommands->isTransformFeedbackActiveUnpaused())
5555 {
5556 ASSERT(getFeatures().supportsTransformFeedbackExtension.enabled);
5557 mRenderPassCommands->pauseTransformFeedback();
5558
5559 // Note that this function is called when render pass break is imminent
5560 // (flushCommandsAndEndRenderPass(), or UtilsVk::clearFramebuffer which will close the
5561 // render pass after the clear). This dirty bit allows transform feedback to resume
5562 // automatically on next render pass.
5563 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
5564 }
5565 }
5566
handleDirtyGraphicsDriverUniforms(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)5567 angle::Result ContextVk::handleDirtyGraphicsDriverUniforms(DirtyBits::Iterator *dirtyBitsIterator,
5568 DirtyBits dirtyBitMask)
5569 {
5570 // Allocate a new region in the dynamic buffer.
5571 bool useGraphicsDriverUniformsExtended = getFeatures().forceDriverUniformOverSpecConst.enabled;
5572 uint8_t *ptr;
5573 bool newBuffer;
5574 GraphicsDriverUniforms *driverUniforms;
5575 size_t driverUniformSize;
5576
5577 if (useGraphicsDriverUniformsExtended)
5578 {
5579 driverUniformSize = sizeof(GraphicsDriverUniformsExtended);
5580 }
5581 else
5582 {
5583 driverUniformSize = sizeof(GraphicsDriverUniforms);
5584 }
5585
5586 ANGLE_TRY(allocateDriverUniforms(driverUniformSize, &mDriverUniforms[PipelineType::Graphics],
5587 &ptr, &newBuffer));
5588
5589 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
5590 if (useGraphicsDriverUniformsExtended)
5591 {
5592 float halfRenderAreaWidth =
5593 static_cast<float>(drawFramebufferVk->getState().getDimensions().width) * 0.5f;
5594 float halfRenderAreaHeight =
5595 static_cast<float>(drawFramebufferVk->getState().getDimensions().height) * 0.5f;
5596
5597 float flipX = 1.0f;
5598 float flipY = -1.0f;
5599 // Y-axis flipping only comes into play with the default framebuffer (i.e. a swapchain
5600 // image). For 0-degree rotation, an FBO or pbuffer could be the draw framebuffer, and so we
5601 // must check whether flipY should be positive or negative. All other rotations, will be to
5602 // the default framebuffer, and so the value of isViewportFlipEnabledForDrawFBO() is assumed
5603 // true; the appropriate flipY value is chosen such that gl_FragCoord is positioned at the
5604 // lower-left corner of the window.
5605 switch (mCurrentRotationDrawFramebuffer)
5606 {
5607 case SurfaceRotation::Identity:
5608 flipX = 1.0f;
5609 flipY = isViewportFlipEnabledForDrawFBO() ? -1.0f : 1.0f;
5610 break;
5611 case SurfaceRotation::Rotated90Degrees:
5612 ASSERT(isViewportFlipEnabledForDrawFBO());
5613 flipX = 1.0f;
5614 flipY = 1.0f;
5615 break;
5616 case SurfaceRotation::Rotated180Degrees:
5617 ASSERT(isViewportFlipEnabledForDrawFBO());
5618 flipX = -1.0f;
5619 flipY = 1.0f;
5620 break;
5621 case SurfaceRotation::Rotated270Degrees:
5622 ASSERT(isViewportFlipEnabledForDrawFBO());
5623 flipX = -1.0f;
5624 flipY = -1.0f;
5625 break;
5626 default:
5627 UNREACHABLE();
5628 break;
5629 }
5630
5631 GraphicsDriverUniformsExtended *driverUniformsExt =
5632 reinterpret_cast<GraphicsDriverUniformsExtended *>(ptr);
5633 driverUniformsExt->halfRenderArea = {halfRenderAreaWidth, halfRenderAreaHeight};
5634 driverUniformsExt->flipXY = {flipX, flipY};
5635 driverUniformsExt->negFlipXY = {flipX, -flipY};
5636 memcpy(&driverUniformsExt->fragRotation,
5637 &kFragRotationMatrices[mCurrentRotationDrawFramebuffer],
5638 sizeof(PreRotationMatrixValues));
5639 driverUniforms = &driverUniformsExt->common;
5640 }
5641 else
5642 {
5643 driverUniforms = reinterpret_cast<GraphicsDriverUniforms *>(ptr);
5644 }
5645
5646 gl::Rectangle glViewport = mState.getViewport();
5647 if (isRotatedAspectRatioForDrawFBO())
5648 {
5649 // The surface is rotated 90/270 degrees. This changes the aspect ratio of the surface.
5650 std::swap(glViewport.x, glViewport.y);
5651 std::swap(glViewport.width, glViewport.height);
5652 }
5653
5654 float depthRangeNear = mState.getNearPlane();
5655 float depthRangeFar = mState.getFarPlane();
5656 float depthRangeDiff = depthRangeFar - depthRangeNear;
5657 int32_t numSamples = drawFramebufferVk->getSamples();
5658
5659 uint32_t advancedBlendEquation = 0;
5660 if (getFeatures().emulateAdvancedBlendEquations.enabled)
5661 {
5662 // Pass the advanced blend equation to shader as-is. If the equation is not one of the
5663 // advanced ones, 0 is expected.
5664 const gl::BlendStateExt &blendStateExt = mState.getBlendStateExt();
5665 if (blendStateExt.mUsesAdvancedBlendEquationMask.test(0))
5666 {
5667 advancedBlendEquation = static_cast<uint32_t>(gl::FromGLenum<gl::BlendEquationType>(
5668 getState().getBlendStateExt().getEquationColorIndexed(0)));
5669 }
5670 }
5671
5672 // Copy and flush to the device.
5673 *driverUniforms = {
5674 {static_cast<float>(glViewport.x), static_cast<float>(glViewport.y),
5675 static_cast<float>(glViewport.width), static_cast<float>(glViewport.height)},
5676 mState.getEnabledClipDistances().bits(),
5677 advancedBlendEquation,
5678 static_cast<int32_t>(mXfbVertexCountPerInstance),
5679 numSamples,
5680 {},
5681 {},
5682 {depthRangeNear, depthRangeFar, depthRangeDiff, 0.0f}};
5683
5684 if (mState.isTransformFeedbackActiveUnpaused())
5685 {
5686 TransformFeedbackVk *transformFeedbackVk =
5687 vk::GetImpl(mState.getCurrentTransformFeedback());
5688 transformFeedbackVk->getBufferOffsets(this, mXfbBaseVertex,
5689 driverUniforms->xfbBufferOffsets.data(),
5690 driverUniforms->xfbBufferOffsets.size());
5691 }
5692
5693 if (mState.hasValidAtomicCounterBuffer())
5694 {
5695 writeAtomicCounterBufferDriverUniformOffsets(driverUniforms->acbBufferOffsets.data(),
5696 driverUniforms->acbBufferOffsets.size());
5697 }
5698
5699 return updateDriverUniformsDescriptorSet(newBuffer, driverUniformSize, PipelineType::Graphics);
5700 }
5701
handleDirtyComputeDriverUniforms()5702 angle::Result ContextVk::handleDirtyComputeDriverUniforms()
5703 {
5704 // Allocate a new region in the dynamic buffer.
5705 uint8_t *ptr;
5706 bool newBuffer;
5707 ANGLE_TRY(allocateDriverUniforms(sizeof(ComputeDriverUniforms),
5708 &mDriverUniforms[PipelineType::Compute], &ptr, &newBuffer));
5709
5710 // Copy and flush to the device.
5711 ComputeDriverUniforms *driverUniforms = reinterpret_cast<ComputeDriverUniforms *>(ptr);
5712 *driverUniforms = {};
5713
5714 if (mState.hasValidAtomicCounterBuffer())
5715 {
5716 writeAtomicCounterBufferDriverUniformOffsets(driverUniforms->acbBufferOffsets.data(),
5717 driverUniforms->acbBufferOffsets.size());
5718 }
5719
5720 return updateDriverUniformsDescriptorSet(newBuffer, sizeof(ComputeDriverUniforms),
5721 PipelineType::Compute);
5722 }
5723
5724 template <typename CommandBufferT>
handleDirtyDriverUniformsBindingImpl(CommandBufferT * commandBuffer,VkPipelineBindPoint bindPoint,DriverUniformsDescriptorSet * driverUniforms)5725 void ContextVk::handleDirtyDriverUniformsBindingImpl(CommandBufferT *commandBuffer,
5726 VkPipelineBindPoint bindPoint,
5727 DriverUniformsDescriptorSet *driverUniforms)
5728 {
5729 // The descriptor pool that this descriptor set was allocated from needs to be retained when the
5730 // descriptor set is used in a new command. Since the descriptor pools are specific to each
5731 // ContextVk, we only need to retain them once to ensure the reference count and Serial are
5732 // updated correctly.
5733 if (!driverUniforms->descriptorPoolBinding.get().usedInRecordedCommands())
5734 {
5735 driverUniforms->descriptorPoolBinding.get().retain(&mResourceUseList);
5736 }
5737
5738 ProgramExecutableVk *executableVk = getExecutable();
5739 const uint32_t dynamicOffset =
5740 static_cast<uint32_t>(driverUniforms->currentBuffer->getOffset());
5741 commandBuffer->bindDescriptorSets(executableVk->getPipelineLayout(), bindPoint,
5742 DescriptorSetIndex::Internal, 1,
5743 &driverUniforms->descriptorSet, 1, &dynamicOffset);
5744 }
5745
handleDirtyGraphicsDriverUniformsBinding(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)5746 angle::Result ContextVk::handleDirtyGraphicsDriverUniformsBinding(
5747 DirtyBits::Iterator *dirtyBitsIterator,
5748 DirtyBits dirtyBitMask)
5749 {
5750 // Bind the driver descriptor set.
5751 handleDirtyDriverUniformsBindingImpl(mRenderPassCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
5752 &mDriverUniforms[PipelineType::Graphics]);
5753 return angle::Result::Continue;
5754 }
5755
handleDirtyComputeDriverUniformsBinding()5756 angle::Result ContextVk::handleDirtyComputeDriverUniformsBinding()
5757 {
5758 // Bind the driver descriptor set.
5759 handleDirtyDriverUniformsBindingImpl(&mOutsideRenderPassCommands->getCommandBuffer(),
5760 VK_PIPELINE_BIND_POINT_COMPUTE,
5761 &mDriverUniforms[PipelineType::Compute]);
5762 return angle::Result::Continue;
5763 }
5764
allocateDriverUniforms(size_t driverUniformsSize,DriverUniformsDescriptorSet * driverUniforms,uint8_t ** ptrOut,bool * newBufferOut)5765 angle::Result ContextVk::allocateDriverUniforms(size_t driverUniformsSize,
5766 DriverUniformsDescriptorSet *driverUniforms,
5767 uint8_t **ptrOut,
5768 bool *newBufferOut)
5769 {
5770 // Allocate a new region in the dynamic buffer. The allocate call may put buffer into dynamic
5771 // buffer's mInflightBuffers. During command submission time, these in-flight buffers are added
5772 // into context's mResourceUseList which will ensure they get tagged with queue serial number
5773 // before moving them into the free list.
5774 ANGLE_TRY(driverUniforms->dynamicBuffer.allocate(this, driverUniformsSize,
5775 &driverUniforms->currentBuffer, newBufferOut));
5776
5777 *ptrOut = driverUniforms->currentBuffer->getMappedMemory();
5778
5779 return angle::Result::Continue;
5780 }
5781
updateDriverUniformsDescriptorSet(bool newBuffer,size_t driverUniformsSize,PipelineType pipelineType)5782 angle::Result ContextVk::updateDriverUniformsDescriptorSet(bool newBuffer,
5783 size_t driverUniformsSize,
5784 PipelineType pipelineType)
5785 {
5786 DriverUniformsDescriptorSet &driverUniforms = mDriverUniforms[pipelineType];
5787
5788 ANGLE_TRY(driverUniforms.currentBuffer->flush(mRenderer));
5789
5790 if (!newBuffer)
5791 {
5792 return angle::Result::Continue;
5793 }
5794
5795 vk::BufferSerial bufferSerial = driverUniforms.currentBuffer->getBufferSerial();
5796 // Look up in the cache first
5797 if (driverUniforms.descriptorSetCache.get(bufferSerial.getValue(),
5798 &driverUniforms.descriptorSet))
5799 {
5800 // The descriptor pool that this descriptor set was allocated from needs to be retained each
5801 // time the descriptor set is used in a new command.
5802 driverUniforms.descriptorPoolBinding.get().retain(&mResourceUseList);
5803 return angle::Result::Continue;
5804 }
5805
5806 // Allocate a new descriptor set.
5807 bool newPoolAllocated;
5808 ANGLE_TRY(mDriverUniformsDescriptorPools[pipelineType].allocateSetsAndGetInfo(
5809 this, &mResourceUseList, driverUniforms.descriptorSetLayout.get(), 1,
5810 &driverUniforms.descriptorPoolBinding, &driverUniforms.descriptorSet, &newPoolAllocated));
5811
5812 // Clear descriptor set cache. It may no longer be valid.
5813 if (newPoolAllocated)
5814 {
5815 driverUniforms.descriptorSetCache.clear();
5816 }
5817
5818 // Update the driver uniform descriptor set.
5819 VkDescriptorBufferInfo &bufferInfo = mUpdateDescriptorSetsBuilder.allocDescriptorBufferInfo();
5820 bufferInfo.buffer = driverUniforms.currentBuffer->getBuffer().getHandle();
5821 bufferInfo.offset = 0;
5822 bufferInfo.range = driverUniformsSize;
5823
5824 VkWriteDescriptorSet &writeInfo = mUpdateDescriptorSetsBuilder.allocWriteDescriptorSet();
5825 writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
5826 writeInfo.dstSet = driverUniforms.descriptorSet;
5827 writeInfo.dstBinding = 0;
5828 writeInfo.dstArrayElement = 0;
5829 writeInfo.descriptorCount = 1;
5830 writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
5831 writeInfo.pImageInfo = nullptr;
5832 writeInfo.pTexelBufferView = nullptr;
5833 writeInfo.pBufferInfo = &bufferInfo;
5834
5835 // Add into descriptor set cache
5836 driverUniforms.descriptorSetCache.insert(bufferSerial.getValue(), driverUniforms.descriptorSet);
5837
5838 return angle::Result::Continue;
5839 }
5840
handleError(VkResult errorCode,const char * file,const char * function,unsigned int line)5841 void ContextVk::handleError(VkResult errorCode,
5842 const char *file,
5843 const char *function,
5844 unsigned int line)
5845 {
5846 ASSERT(errorCode != VK_SUCCESS);
5847
5848 GLenum glErrorCode = DefaultGLErrorCode(errorCode);
5849
5850 std::stringstream errorStream;
5851 errorStream << "Internal Vulkan error (" << errorCode << "): " << VulkanResultString(errorCode)
5852 << ".";
5853
5854 if (errorCode == VK_ERROR_DEVICE_LOST)
5855 {
5856 WARN() << errorStream.str();
5857 handleDeviceLost();
5858 }
5859
5860 mErrors->handleError(glErrorCode, errorStream.str().c_str(), file, function, line);
5861 }
5862
updateActiveTextures(const gl::Context * context,gl::Command command)5863 angle::Result ContextVk::updateActiveTextures(const gl::Context *context, gl::Command command)
5864 {
5865 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
5866 ASSERT(executable);
5867
5868 mActiveTexturesDesc.reset();
5869
5870 const gl::ActiveTexturesCache &textures = mState.getActiveTexturesCache();
5871 const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
5872 const gl::ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes();
5873
5874 bool recreatePipelineLayout = false;
5875 ImmutableSamplerIndexMap immutableSamplerIndexMap = {};
5876 for (size_t textureUnit : activeTextures)
5877 {
5878 gl::Texture *texture = textures[textureUnit];
5879 gl::TextureType textureType = textureTypes[textureUnit];
5880 ASSERT(textureType != gl::TextureType::InvalidEnum);
5881
5882 const bool isIncompleteTexture = texture == nullptr;
5883
5884 // Null textures represent incomplete textures.
5885 if (isIncompleteTexture)
5886 {
5887 ANGLE_TRY(getIncompleteTexture(
5888 context, textureType, executable->getSamplerFormatForTextureUnitIndex(textureUnit),
5889 &texture));
5890 }
5891
5892 TextureVk *textureVk = vk::GetImpl(texture);
5893 ASSERT(textureVk != nullptr);
5894
5895 vk::TextureUnit &activeTexture = mActiveTextures[textureUnit];
5896
5897 // Special handling of texture buffers. They have a buffer attached instead of an image.
5898 if (textureType == gl::TextureType::Buffer)
5899 {
5900 activeTexture.texture = textureVk;
5901 mActiveTexturesDesc.updateTexture(textureUnit, textureVk->getBufferViewSerial(),
5902 vk::SamplerSerial());
5903
5904 continue;
5905 }
5906
5907 if (!isIncompleteTexture && texture->isDepthOrStencil() &&
5908 shouldSwitchToReadOnlyDepthFeedbackLoopMode(texture, command))
5909 {
5910 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
5911 // Special handling for deferred clears.
5912 ANGLE_TRY(drawFramebufferVk->flushDeferredClears(this));
5913
5914 if (hasStartedRenderPass())
5915 {
5916 if (!textureVk->getImage().hasRenderPassUsageFlag(
5917 vk::RenderPassUsage::ReadOnlyAttachment))
5918 {
5919 // To enter depth feedback loop, we must flush and start a new renderpass.
5920 // Otherwise it will stick with writable layout and cause validation error.
5921 ANGLE_TRY(flushCommandsAndEndRenderPass(
5922 RenderPassClosureReason::DepthStencilUseInFeedbackLoop));
5923 }
5924 else
5925 {
5926 drawFramebufferVk->updateRenderPassReadOnlyDepthMode(this, mRenderPassCommands);
5927 }
5928 }
5929
5930 drawFramebufferVk->setReadOnlyDepthFeedbackLoopMode(true);
5931 }
5932
5933 gl::Sampler *sampler = mState.getSampler(static_cast<uint32_t>(textureUnit));
5934 const SamplerVk *samplerVk = sampler ? vk::GetImpl(sampler) : nullptr;
5935
5936 const vk::SamplerHelper &samplerHelper =
5937 samplerVk ? samplerVk->getSampler() : textureVk->getSampler();
5938 const gl::SamplerState &samplerState =
5939 sampler ? sampler->getSamplerState() : texture->getSamplerState();
5940 activeTexture.texture = textureVk;
5941 activeTexture.sampler = &samplerHelper;
5942 activeTexture.srgbDecode = samplerState.getSRGBDecode();
5943
5944 // GL_EXT_texture_sRGB_decode
5945 // The new parameter, TEXTURE_SRGB_DECODE_EXT controls whether the
5946 // decoding happens at sample time. It only applies to textures with an
5947 // internal format that is sRGB and is ignored for all other textures.
5948 const vk::ImageHelper &image = textureVk->getImage();
5949 ASSERT(image.valid());
5950 if (image.getActualFormat().isSRGB && activeTexture.srgbDecode == GL_SKIP_DECODE_EXT)
5951 {
5952 // Make sure we use the MUTABLE bit for the storage. Because the "skip decode" is a
5953 // Sampler state we might not have caught this setting in TextureVk::syncState.
5954 ANGLE_TRY(textureVk->ensureMutable(this));
5955 }
5956
5957 if (image.hasEmulatedImageFormat())
5958 {
5959 ANGLE_VK_PERF_WARNING(
5960 this, GL_DEBUG_SEVERITY_LOW,
5961 "The Vulkan driver does not support texture format 0x%04X, emulating with 0x%04X",
5962 image.getIntendedFormat().glInternalFormat,
5963 image.getActualFormat().glInternalFormat);
5964 }
5965
5966 vk::ImageOrBufferViewSubresourceSerial imageViewSerial =
5967 textureVk->getImageViewSubresourceSerial(samplerState);
5968 mActiveTexturesDesc.updateTexture(textureUnit, imageViewSerial,
5969 samplerHelper.getSamplerSerial());
5970
5971 if (image.hasImmutableSampler())
5972 {
5973 immutableSamplerIndexMap[image.getYcbcrConversionDesc()] =
5974 static_cast<uint32_t>(textureUnit);
5975 }
5976
5977 if (textureVk->getAndResetImmutableSamplerDirtyState())
5978 {
5979 recreatePipelineLayout = true;
5980 }
5981 }
5982
5983 ProgramExecutableVk *executableVk = getExecutable();
5984 if (!executableVk->areImmutableSamplersCompatible(immutableSamplerIndexMap))
5985 {
5986 recreatePipelineLayout = true;
5987 }
5988
5989 // Recreate the pipeline layout, if necessary.
5990 if (recreatePipelineLayout)
5991 {
5992 ANGLE_TRY(executableVk->createPipelineLayout(this, *executable, &mActiveTextures));
5993
5994 // The default uniforms descriptor set was reset during createPipelineLayout(), so mark them
5995 // dirty to get everything reallocated/rebound before the next draw.
5996 if (executable->hasDefaultUniforms())
5997 {
5998 executableVk->setAllDefaultUniformsDirty(*executable);
5999 }
6000 }
6001
6002 return angle::Result::Continue;
6003 }
6004
6005 template <typename CommandBufferHelperT>
updateActiveImages(CommandBufferHelperT * commandBufferHelper)6006 angle::Result ContextVk::updateActiveImages(CommandBufferHelperT *commandBufferHelper)
6007 {
6008 const gl::State &glState = mState;
6009 const gl::ProgramExecutable *executable = glState.getProgramExecutable();
6010 ASSERT(executable);
6011
6012 mActiveImages.fill(nullptr);
6013
6014 const gl::ActiveTextureMask &activeImages = executable->getActiveImagesMask();
6015 const gl::ActiveTextureArray<gl::ShaderBitSet> &activeImageShaderBits =
6016 executable->getActiveImageShaderBits();
6017
6018 // Note: currently, the image layout is transitioned entirely even if only one level or layer is
6019 // used. This is an issue if one subresource of the image is used as framebuffer attachment and
6020 // the other as image. This is a similar issue to http://anglebug.com/2914. Another issue
6021 // however is if multiple subresources of the same image are used at the same time.
6022 // Inefficiencies aside, setting write dependency on the same image multiple times is not
6023 // supported. The following makes sure write dependencies are set only once per image.
6024 std::set<vk::ImageHelper *> alreadyProcessed;
6025
6026 for (size_t imageUnitIndex : activeImages)
6027 {
6028 const gl::ImageUnit &imageUnit = glState.getImageUnit(imageUnitIndex);
6029 const gl::Texture *texture = imageUnit.texture.get();
6030 if (texture == nullptr)
6031 {
6032 continue;
6033 }
6034
6035 TextureVk *textureVk = vk::GetImpl(texture);
6036 mActiveImages[imageUnitIndex] = textureVk;
6037
6038 // The image should be flushed and ready to use at this point. There may still be
6039 // lingering staged updates in its staging buffer for unused texture mip levels or
6040 // layers. Therefore we can't verify it has no staged updates right here.
6041 gl::ShaderBitSet shaderStages = activeImageShaderBits[imageUnitIndex];
6042 ASSERT(shaderStages.any());
6043
6044 // Special handling of texture buffers. They have a buffer attached instead of an image.
6045 if (texture->getType() == gl::TextureType::Buffer)
6046 {
6047 BufferVk *bufferVk = vk::GetImpl(textureVk->getBuffer().get());
6048
6049 OnImageBufferWrite(this, bufferVk, shaderStages, commandBufferHelper);
6050
6051 textureVk->retainBufferViews(&mResourceUseList);
6052 continue;
6053 }
6054
6055 vk::ImageHelper *image = &textureVk->getImage();
6056
6057 if (alreadyProcessed.find(image) != alreadyProcessed.end())
6058 {
6059 continue;
6060 }
6061 alreadyProcessed.insert(image);
6062
6063 gl::LevelIndex level;
6064 uint32_t layerStart = 0;
6065 uint32_t layerCount = 0;
6066 const vk::ImageLayout imageLayout = GetImageWriteLayoutAndSubresource(
6067 imageUnit, *image, shaderStages, &level, &layerStart, &layerCount);
6068
6069 commandBufferHelper->imageWrite(this, level, layerStart, layerCount,
6070 image->getAspectFlags(), imageLayout,
6071 vk::AliasingMode::Allowed, image);
6072 }
6073
6074 return angle::Result::Continue;
6075 }
6076
flushImpl(const vk::Semaphore * signalSemaphore,RenderPassClosureReason renderPassClosureReason)6077 angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore,
6078 RenderPassClosureReason renderPassClosureReason)
6079 {
6080 Serial unusedSerial;
6081 return flushAndGetSerial(signalSemaphore, &unusedSerial, renderPassClosureReason);
6082 }
6083
flushAndGetSerial(const vk::Semaphore * signalSemaphore,Serial * submitSerialOut,RenderPassClosureReason renderPassClosureReason)6084 angle::Result ContextVk::flushAndGetSerial(const vk::Semaphore *signalSemaphore,
6085 Serial *submitSerialOut,
6086 RenderPassClosureReason renderPassClosureReason)
6087 {
6088 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::flushImpl");
6089
6090 // We must set this to false before calling flushCommandsAndEndRenderPass to prevent it from
6091 // calling back to flushImpl.
6092 mHasDeferredFlush = false;
6093
6094 // Avoid calling vkQueueSubmit() twice, since submitFrame() below will do that.
6095 ANGLE_TRY(flushCommandsAndEndRenderPassWithoutQueueSubmit(renderPassClosureReason));
6096
6097 if (mIsAnyHostVisibleBufferWritten)
6098 {
6099 // Make sure all writes to host-visible buffers are flushed. We have no way of knowing
6100 // whether any buffer will be mapped for readback in the future, and we can't afford to
6101 // flush and wait on a one-pipeline-barrier command buffer on every map().
6102 VkMemoryBarrier memoryBarrier = {};
6103 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6104 memoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
6105 memoryBarrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT;
6106
6107 const VkPipelineStageFlags supportedShaderStages =
6108 (VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
6109 VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
6110 VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |
6111 VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
6112 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT) &
6113 mRenderer->getSupportedVulkanPipelineStageMask();
6114 const VkPipelineStageFlags bufferWriteStages =
6115 VK_PIPELINE_STAGE_TRANSFER_BIT | supportedShaderStages |
6116 (getFeatures().supportsTransformFeedbackExtension.enabled
6117 ? VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT
6118 : 0);
6119
6120 mOutsideRenderPassCommands->getCommandBuffer().memoryBarrier(
6121 bufferWriteStages, VK_PIPELINE_STAGE_HOST_BIT, &memoryBarrier);
6122 mIsAnyHostVisibleBufferWritten = false;
6123 }
6124
6125 if (mGpuEventsEnabled)
6126 {
6127 EventName eventName = GetTraceEventName("Primary", mPerfCounters.primaryBuffers);
6128 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
6129 TRACE_EVENT_PHASE_END, eventName));
6130 }
6131 ANGLE_TRY(flushOutsideRenderPassCommands());
6132
6133 // We must add the per context dynamic buffers into mResourceUseList before submission so that
6134 // they get retained properly until GPU completes. We do not add current buffer into
6135 // mResourceUseList since they never get reused or freed until context gets destroyed, at which
6136 // time we always wait for GPU to finish before destroying the dynamic buffers.
6137 for (DriverUniformsDescriptorSet &driverUniform : mDriverUniforms)
6138 {
6139 driverUniform.dynamicBuffer.releaseInFlightBuffersToResourceUseList(this);
6140 }
6141 mDefaultUniformStorage.releaseInFlightBuffersToResourceUseList(this);
6142
6143 if (mHasInFlightStreamedVertexBuffers.any())
6144 {
6145 for (size_t attribIndex : mHasInFlightStreamedVertexBuffers)
6146 {
6147 mStreamedVertexBuffers[attribIndex].releaseInFlightBuffersToResourceUseList(this);
6148 }
6149 mHasInFlightStreamedVertexBuffers.reset();
6150 }
6151
6152 ANGLE_TRY(submitFrame(signalSemaphore, submitSerialOut));
6153
6154 ASSERT(mWaitSemaphores.empty());
6155 ASSERT(mWaitSemaphoreStageMasks.empty());
6156
6157 mPerfCounters.primaryBuffers++;
6158
6159 if (mGpuEventsEnabled)
6160 {
6161 EventName eventName = GetTraceEventName("Primary", mPerfCounters.primaryBuffers);
6162 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
6163 TRACE_EVENT_PHASE_BEGIN, eventName));
6164 }
6165
6166 // Try to detect frame boundary for both on screen and offscreen usage by detecting
6167 // fush/finish/swap.
6168 if ((renderPassClosureReason == RenderPassClosureReason::GLFlush ||
6169 renderPassClosureReason == RenderPassClosureReason::GLFinish ||
6170 renderPassClosureReason == RenderPassClosureReason::EGLSwapBuffers) &&
6171 mShareGroupVk->isDueForBufferPoolPrune())
6172 {
6173 mShareGroupVk->pruneDefaultBufferPools(mRenderer);
6174 }
6175
6176 return angle::Result::Continue;
6177 }
6178
finishImpl(RenderPassClosureReason renderPassClosureReason)6179 angle::Result ContextVk::finishImpl(RenderPassClosureReason renderPassClosureReason)
6180 {
6181 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::finishImpl");
6182
6183 ANGLE_TRY(flushImpl(nullptr, renderPassClosureReason));
6184 ANGLE_TRY(mRenderer->finish(this, hasProtectedContent()));
6185
6186 clearAllGarbage();
6187
6188 if (mGpuEventsEnabled)
6189 {
6190 // This loop should in practice execute once since the queue is already idle.
6191 while (mInFlightGpuEventQueries.size() > 0)
6192 {
6193 ANGLE_TRY(checkCompletedGpuEvents());
6194 }
6195 // Recalculate the CPU/GPU time difference to account for clock drifting. Avoid
6196 // unnecessary synchronization if there is no event to be adjusted (happens when
6197 // finish() gets called multiple times towards the end of the application).
6198 if (mGpuEvents.size() > 0)
6199 {
6200 ANGLE_TRY(synchronizeCpuGpuTime());
6201 }
6202 }
6203
6204 return angle::Result::Continue;
6205 }
6206
addWaitSemaphore(VkSemaphore semaphore,VkPipelineStageFlags stageMask)6207 void ContextVk::addWaitSemaphore(VkSemaphore semaphore, VkPipelineStageFlags stageMask)
6208 {
6209 mWaitSemaphores.push_back(semaphore);
6210 mWaitSemaphoreStageMasks.push_back(stageMask);
6211 }
6212
isSerialInUse(Serial serial) const6213 bool ContextVk::isSerialInUse(Serial serial) const
6214 {
6215 return serial > getLastCompletedQueueSerial();
6216 }
6217
checkCompletedCommands()6218 angle::Result ContextVk::checkCompletedCommands()
6219 {
6220 return mRenderer->checkCompletedCommands(this);
6221 }
6222
finishToSerial(Serial serial)6223 angle::Result ContextVk::finishToSerial(Serial serial)
6224 {
6225 return mRenderer->finishToSerial(this, serial);
6226 }
6227
getCompatibleRenderPass(const vk::RenderPassDesc & desc,vk::RenderPass ** renderPassOut)6228 angle::Result ContextVk::getCompatibleRenderPass(const vk::RenderPassDesc &desc,
6229 vk::RenderPass **renderPassOut)
6230 {
6231 // Note: Each context has it's own RenderPassCache so no locking needed.
6232 return mRenderPassCache.getCompatibleRenderPass(this, desc, renderPassOut);
6233 }
6234
getRenderPassWithOps(const vk::RenderPassDesc & desc,const vk::AttachmentOpsArray & ops,vk::RenderPass ** renderPassOut)6235 angle::Result ContextVk::getRenderPassWithOps(const vk::RenderPassDesc &desc,
6236 const vk::AttachmentOpsArray &ops,
6237 vk::RenderPass **renderPassOut)
6238 {
6239 // Note: Each context has it's own RenderPassCache so no locking needed.
6240 return mRenderPassCache.getRenderPassWithOps(this, desc, ops, renderPassOut);
6241 }
6242
getTimestamp(uint64_t * timestampOut)6243 angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
6244 {
6245 // The intent of this function is to query the timestamp without stalling the GPU.
6246 // Currently, that seems impossible, so instead, we are going to make a small submission
6247 // with just a timestamp query. First, the disjoint timer query extension says:
6248 //
6249 // > This will return the GL time after all previous commands have reached the GL server but
6250 // have not yet necessarily executed.
6251 //
6252 // The previous commands may be deferred at the moment and not yet flushed. The wording allows
6253 // us to make a submission to get the timestamp without flushing.
6254 //
6255 // Second:
6256 //
6257 // > By using a combination of this synchronous get command and the asynchronous timestamp
6258 // query object target, applications can measure the latency between when commands reach the
6259 // GL server and when they are realized in the framebuffer.
6260 //
6261 // This fits with the above strategy as well, although inevitably we are possibly
6262 // introducing a GPU bubble. This function directly generates a command buffer and submits
6263 // it instead of using the other member functions. This is to avoid changing any state,
6264 // such as the queue serial.
6265
6266 // Create a query used to receive the GPU timestamp
6267 VkDevice device = getDevice();
6268 vk::DeviceScoped<vk::DynamicQueryPool> timestampQueryPool(device);
6269 vk::QueryHelper timestampQuery;
6270 ANGLE_TRY(timestampQueryPool.get().init(this, VK_QUERY_TYPE_TIMESTAMP, 1));
6271 ANGLE_TRY(timestampQueryPool.get().allocateQuery(this, ×tampQuery, 1));
6272
6273 vk::ResourceUseList scratchResourceUseList;
6274
6275 // Record the command buffer
6276 vk::DeviceScoped<vk::PrimaryCommandBuffer> commandBatch(device);
6277 vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
6278
6279 ANGLE_TRY(mRenderer->getCommandBufferOneOff(this, hasProtectedContent(), &commandBuffer));
6280
6281 timestampQuery.writeTimestampToPrimary(this, &commandBuffer);
6282 timestampQuery.retain(&scratchResourceUseList);
6283 ANGLE_VK_TRY(this, commandBuffer.end());
6284
6285 // Create fence for the submission
6286 VkFenceCreateInfo fenceInfo = {};
6287 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
6288 fenceInfo.flags = 0;
6289
6290 vk::DeviceScoped<vk::Fence> fence(device);
6291 ANGLE_VK_TRY(this, fence.get().init(device, fenceInfo));
6292
6293 Serial throwAwaySerial;
6294 ANGLE_TRY(mRenderer->queueSubmitOneOff(this, std::move(commandBuffer), hasProtectedContent(),
6295 mContextPriority, nullptr, 0, &fence.get(),
6296 vk::SubmitPolicy::EnsureSubmitted, &throwAwaySerial));
6297
6298 // Wait for the submission to finish. Given no semaphores, there is hope that it would execute
6299 // in parallel with what's already running on the GPU.
6300 ANGLE_VK_TRY(this, fence.get().wait(device, mRenderer->getMaxFenceWaitTimeNs()));
6301 scratchResourceUseList.releaseResourceUsesAndUpdateSerials(throwAwaySerial);
6302
6303 // Get the query results
6304 vk::QueryResult result(1);
6305 ANGLE_TRY(timestampQuery.getUint64Result(this, &result));
6306 *timestampOut = result.getResult(vk::QueryResult::kDefaultResultIndex);
6307 timestampQueryPool.get().freeQuery(this, ×tampQuery);
6308
6309 // Convert results to nanoseconds.
6310 *timestampOut = static_cast<uint64_t>(
6311 *timestampOut *
6312 static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod));
6313
6314 return angle::Result::Continue;
6315 }
6316
invalidateDefaultAttribute(size_t attribIndex)6317 void ContextVk::invalidateDefaultAttribute(size_t attribIndex)
6318 {
6319 mDirtyDefaultAttribsMask.set(attribIndex);
6320 mGraphicsDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
6321 }
6322
invalidateDefaultAttributes(const gl::AttributesMask & dirtyMask)6323 void ContextVk::invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask)
6324 {
6325 if (dirtyMask.any())
6326 {
6327 mDirtyDefaultAttribsMask |= dirtyMask;
6328 mGraphicsDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
6329 mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
6330 }
6331 }
6332
getDriverUniformsDescriptorSetDesc() const6333 vk::DescriptorSetLayoutDesc ContextVk::getDriverUniformsDescriptorSetDesc() const
6334 {
6335 constexpr VkShaderStageFlags kShaderStages =
6336 VK_SHADER_STAGE_ALL_GRAPHICS | VK_SHADER_STAGE_COMPUTE_BIT;
6337
6338 vk::DescriptorSetLayoutDesc desc;
6339 desc.update(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, kShaderStages, nullptr);
6340 return desc;
6341 }
6342
shouldEmulateSeamfulCubeMapSampling() const6343 bool ContextVk::shouldEmulateSeamfulCubeMapSampling() const
6344 {
6345 // Only allow seamful cube map sampling in non-webgl ES2.
6346 if (mState.getClientMajorVersion() != 2 || mState.isWebGL())
6347 {
6348 return false;
6349 }
6350
6351 if (mRenderer->getFeatures().disallowSeamfulCubeMapEmulation.enabled)
6352 {
6353 return false;
6354 }
6355
6356 return true;
6357 }
6358
onBufferReleaseToExternal(const vk::BufferHelper & buffer)6359 angle::Result ContextVk::onBufferReleaseToExternal(const vk::BufferHelper &buffer)
6360 {
6361 if (mRenderPassCommands->usesBuffer(buffer))
6362 {
6363 return flushCommandsAndEndRenderPass(
6364 RenderPassClosureReason::BufferUseThenReleaseToExternal);
6365 }
6366 return angle::Result::Continue;
6367 }
6368
onImageReleaseToExternal(const vk::ImageHelper & image)6369 angle::Result ContextVk::onImageReleaseToExternal(const vk::ImageHelper &image)
6370 {
6371 if (IsRenderPassStartedAndUsesImage(*mRenderPassCommands, image))
6372 {
6373 return flushCommandsAndEndRenderPass(
6374 RenderPassClosureReason::ImageUseThenReleaseToExternal);
6375 }
6376 return angle::Result::Continue;
6377 }
6378
beginNewRenderPass(const vk::Framebuffer & framebuffer,const gl::Rectangle & renderArea,const vk::RenderPassDesc & renderPassDesc,const vk::AttachmentOpsArray & renderPassAttachmentOps,const vk::PackedAttachmentCount colorAttachmentCount,const vk::PackedAttachmentIndex depthStencilAttachmentIndex,const vk::PackedClearValuesArray & clearValues,vk::RenderPassCommandBuffer ** commandBufferOut)6379 angle::Result ContextVk::beginNewRenderPass(
6380 const vk::Framebuffer &framebuffer,
6381 const gl::Rectangle &renderArea,
6382 const vk::RenderPassDesc &renderPassDesc,
6383 const vk::AttachmentOpsArray &renderPassAttachmentOps,
6384 const vk::PackedAttachmentCount colorAttachmentCount,
6385 const vk::PackedAttachmentIndex depthStencilAttachmentIndex,
6386 const vk::PackedClearValuesArray &clearValues,
6387 vk::RenderPassCommandBuffer **commandBufferOut)
6388 {
6389 // Next end any currently outstanding render pass. The render pass is normally closed before
6390 // reaching here for various reasons, except typically when UtilsVk needs to start one.
6391 ANGLE_TRY(flushCommandsAndEndRenderPass(RenderPassClosureReason::NewRenderPass));
6392
6393 mPerfCounters.renderPasses++;
6394 return mRenderPassCommands->beginRenderPass(
6395 this, framebuffer, renderArea, renderPassDesc, renderPassAttachmentOps,
6396 colorAttachmentCount, depthStencilAttachmentIndex, clearValues, commandBufferOut);
6397 }
6398
startRenderPass(gl::Rectangle renderArea,vk::RenderPassCommandBuffer ** commandBufferOut,bool * renderPassDescChangedOut)6399 angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea,
6400 vk::RenderPassCommandBuffer **commandBufferOut,
6401 bool *renderPassDescChangedOut)
6402 {
6403 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
6404 ASSERT(drawFramebufferVk == vk::GetImpl(mState.getDrawFramebuffer()));
6405
6406 ANGLE_TRY(drawFramebufferVk->startNewRenderPass(this, renderArea, &mRenderPassCommandBuffer,
6407 renderPassDescChangedOut));
6408
6409 // Make sure the render pass is not restarted if it is started by UtilsVk (as opposed to
6410 // setupDraw(), which clears this bit automatically).
6411 mGraphicsDirtyBits.reset(DIRTY_BIT_RENDER_PASS);
6412
6413 ANGLE_TRY(resumeRenderPassQueriesIfActive());
6414
6415 if (commandBufferOut)
6416 {
6417 *commandBufferOut = mRenderPassCommandBuffer;
6418 }
6419
6420 return angle::Result::Continue;
6421 }
6422
startNextSubpass()6423 angle::Result ContextVk::startNextSubpass()
6424 {
6425 ASSERT(hasStartedRenderPass());
6426
6427 // The graphics pipelines are bound to a subpass, so update the subpass as well.
6428 mGraphicsPipelineDesc->nextSubpass(&mGraphicsPipelineTransition);
6429
6430 return mRenderPassCommands->nextSubpass(this, &mRenderPassCommandBuffer);
6431 }
6432
restoreFinishedRenderPass(vk::Framebuffer * framebuffer)6433 void ContextVk::restoreFinishedRenderPass(vk::Framebuffer *framebuffer)
6434 {
6435 if (mRenderPassCommandBuffer != nullptr)
6436 {
6437 // The render pass isn't finished yet, so nothing to restore.
6438 return;
6439 }
6440
6441 if (mRenderPassCommands->started() &&
6442 mRenderPassCommands->getFramebufferHandle() == framebuffer->getHandle())
6443 {
6444 // There is already a render pass open for this framebuffer, so just restore the
6445 // pointer rather than starting a whole new render pass. One possible path here
6446 // is if the draw framebuffer binding has changed from FBO A -> B -> A, without
6447 // any commands that started a new render pass for FBO B (such as a clear being
6448 // issued that was deferred).
6449 mRenderPassCommandBuffer = &mRenderPassCommands->getCommandBuffer();
6450 ASSERT(hasStartedRenderPass());
6451 }
6452 }
6453
getCurrentSubpassIndex() const6454 uint32_t ContextVk::getCurrentSubpassIndex() const
6455 {
6456 return mGraphicsPipelineDesc->getSubpass();
6457 }
6458
getCurrentViewCount() const6459 uint32_t ContextVk::getCurrentViewCount() const
6460 {
6461 FramebufferVk *drawFBO = vk::GetImpl(mState.getDrawFramebuffer());
6462 return drawFBO->getRenderPassDesc().viewCount();
6463 }
6464
flushCommandsAndEndRenderPassImpl(QueueSubmitType queueSubmit,RenderPassClosureReason reason)6465 angle::Result ContextVk::flushCommandsAndEndRenderPassImpl(QueueSubmitType queueSubmit,
6466 RenderPassClosureReason reason)
6467 {
6468 // Ensure we flush the RenderPass *after* the prior commands.
6469 ANGLE_TRY(flushOutsideRenderPassCommands());
6470 ASSERT(mOutsideRenderPassCommands->empty());
6471
6472 if (!mRenderPassCommands->started())
6473 {
6474 onRenderPassFinished(RenderPassClosureReason::AlreadySpecifiedElsewhere);
6475 return angle::Result::Continue;
6476 }
6477
6478 // Set dirty bits if render pass was open (and thus will be closed).
6479 mGraphicsDirtyBits |= mNewGraphicsCommandBufferDirtyBits;
6480 // Restart at subpass 0.
6481 mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
6482
6483 mCurrentTransformFeedbackBuffers.clear();
6484
6485 // Reset serials for XFB if active.
6486 if (mState.isTransformFeedbackActiveUnpaused())
6487 {
6488 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6489 ASSERT(executable);
6490 size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
6491
6492 TransformFeedbackVk *transformFeedbackVk =
6493 vk::GetImpl(mState.getCurrentTransformFeedback());
6494
6495 populateTransformFeedbackBufferSet(xfbBufferCount, transformFeedbackVk->getBufferHelpers());
6496 }
6497
6498 onRenderPassFinished(reason);
6499
6500 if (mGpuEventsEnabled)
6501 {
6502 EventName eventName = GetTraceEventName("RP", mPerfCounters.renderPasses);
6503 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
6504 TRACE_EVENT_PHASE_BEGIN, eventName));
6505 ANGLE_TRY(flushOutsideRenderPassCommands());
6506 }
6507
6508 addOverlayUsedBuffersCount(mRenderPassCommands);
6509
6510 pauseTransformFeedbackIfActiveUnpaused();
6511
6512 ANGLE_TRY(mRenderPassCommands->endRenderPass(this));
6513
6514 if (vk::CommandBufferHelperCommon::kEnableCommandStreamDiagnostics)
6515 {
6516 mRenderPassCommands->addCommandDiagnostics(this);
6517 }
6518
6519 vk::RenderPass *renderPass = nullptr;
6520 ANGLE_TRY(getRenderPassWithOps(mRenderPassCommands->getRenderPassDesc(),
6521 mRenderPassCommands->getAttachmentOps(), &renderPass));
6522
6523 flushDescriptorSetUpdates();
6524
6525 getShareGroupVk()->acquireResourceUseList(std::move(mRenderPassCommands->getResourceUseList()));
6526
6527 ANGLE_TRY(mRenderer->flushRenderPassCommands(this, hasProtectedContent(), *renderPass,
6528 &mRenderPassCommands));
6529
6530 if (mGpuEventsEnabled)
6531 {
6532 EventName eventName = GetTraceEventName("RP", mPerfCounters.renderPasses);
6533 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
6534 TRACE_EVENT_PHASE_END, eventName));
6535 ANGLE_TRY(flushOutsideRenderPassCommands());
6536 }
6537
6538 if (mHasDeferredFlush && queueSubmit == QueueSubmitType::PerformQueueSubmit)
6539 {
6540 // If we have deferred glFlush call in the middle of renderpass, flush them now.
6541 ANGLE_TRY(flushImpl(nullptr, RenderPassClosureReason::AlreadySpecifiedElsewhere));
6542 }
6543
6544 return angle::Result::Continue;
6545 }
6546
flushCommandsAndEndRenderPass(RenderPassClosureReason reason)6547 angle::Result ContextVk::flushCommandsAndEndRenderPass(RenderPassClosureReason reason)
6548 {
6549 return flushCommandsAndEndRenderPassImpl(QueueSubmitType::PerformQueueSubmit, reason);
6550 }
6551
flushCommandsAndEndRenderPassWithoutQueueSubmit(RenderPassClosureReason reason)6552 angle::Result ContextVk::flushCommandsAndEndRenderPassWithoutQueueSubmit(
6553 RenderPassClosureReason reason)
6554 {
6555 return flushCommandsAndEndRenderPassImpl(QueueSubmitType::SkipQueueSubmit, reason);
6556 }
6557
flushDirtyGraphicsRenderPass(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask,RenderPassClosureReason reason)6558 angle::Result ContextVk::flushDirtyGraphicsRenderPass(DirtyBits::Iterator *dirtyBitsIterator,
6559 DirtyBits dirtyBitMask,
6560 RenderPassClosureReason reason)
6561 {
6562 ASSERT(mRenderPassCommands->started());
6563
6564 ANGLE_TRY(flushCommandsAndEndRenderPassImpl(QueueSubmitType::PerformQueueSubmit, reason));
6565
6566 // Set dirty bits that need processing on new render pass on the dirty bits iterator that's
6567 // being processed right now.
6568 dirtyBitsIterator->setLaterBits(mNewGraphicsCommandBufferDirtyBits & dirtyBitMask);
6569
6570 // Additionally, make sure any dirty bits not included in the mask are left for future
6571 // processing. Note that |dirtyBitMask| is removed from |mNewGraphicsCommandBufferDirtyBits|
6572 // after dirty bits are iterated, so there's no need to mask them out.
6573 mGraphicsDirtyBits |= mNewGraphicsCommandBufferDirtyBits;
6574
6575 // Restart at subpass 0.
6576 mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
6577
6578 return angle::Result::Continue;
6579 }
6580
syncExternalMemory()6581 angle::Result ContextVk::syncExternalMemory()
6582 {
6583 VkMemoryBarrier memoryBarrier = {};
6584 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
6585 memoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
6586 memoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
6587
6588 mOutsideRenderPassCommands->getCommandBuffer().memoryBarrier(
6589 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &memoryBarrier);
6590 return angle::Result::Continue;
6591 }
6592
addCommandBufferDiagnostics(const std::string & commandBufferDiagnostics)6593 void ContextVk::addCommandBufferDiagnostics(const std::string &commandBufferDiagnostics)
6594 {
6595 mCommandBufferDiagnostics.push_back(commandBufferDiagnostics);
6596 }
6597
dumpCommandStreamDiagnostics()6598 void ContextVk::dumpCommandStreamDiagnostics()
6599 {
6600 std::ostream &out = std::cout;
6601
6602 if (mCommandBufferDiagnostics.empty())
6603 return;
6604
6605 out << "digraph {\n"
6606 << " node [shape=plaintext fontname=\"Consolas\"]\n";
6607
6608 for (size_t index = 0; index < mCommandBufferDiagnostics.size(); ++index)
6609 {
6610 const std::string &payload = mCommandBufferDiagnostics[index];
6611 out << " cb" << index << " [label =\"" << payload << "\"];\n";
6612 }
6613
6614 for (size_t index = 0; index < mCommandBufferDiagnostics.size() - 1; ++index)
6615 {
6616 out << " cb" << index << " -> cb" << index + 1 << "\n";
6617 }
6618
6619 mCommandBufferDiagnostics.clear();
6620
6621 out << "}\n";
6622 }
6623
initIndexTypeMap()6624 void ContextVk::initIndexTypeMap()
6625 {
6626 // Init gles-vulkan index type map
6627 mIndexTypeMap[gl::DrawElementsType::UnsignedByte] =
6628 mRenderer->getFeatures().supportsIndexTypeUint8.enabled ? VK_INDEX_TYPE_UINT8_EXT
6629 : VK_INDEX_TYPE_UINT16;
6630 mIndexTypeMap[gl::DrawElementsType::UnsignedShort] = VK_INDEX_TYPE_UINT16;
6631 mIndexTypeMap[gl::DrawElementsType::UnsignedInt] = VK_INDEX_TYPE_UINT32;
6632 }
6633
getVkIndexType(gl::DrawElementsType glIndexType) const6634 VkIndexType ContextVk::getVkIndexType(gl::DrawElementsType glIndexType) const
6635 {
6636 return mIndexTypeMap[glIndexType];
6637 }
6638
getVkIndexTypeSize(gl::DrawElementsType glIndexType) const6639 size_t ContextVk::getVkIndexTypeSize(gl::DrawElementsType glIndexType) const
6640 {
6641 gl::DrawElementsType elementsType = shouldConvertUint8VkIndexType(glIndexType)
6642 ? gl::DrawElementsType::UnsignedShort
6643 : glIndexType;
6644 ASSERT(elementsType < gl::DrawElementsType::EnumCount);
6645
6646 // Use GetDrawElementsTypeSize() to get the size
6647 return static_cast<size_t>(gl::GetDrawElementsTypeSize(elementsType));
6648 }
6649
shouldConvertUint8VkIndexType(gl::DrawElementsType glIndexType) const6650 bool ContextVk::shouldConvertUint8VkIndexType(gl::DrawElementsType glIndexType) const
6651 {
6652 return (glIndexType == gl::DrawElementsType::UnsignedByte &&
6653 !mRenderer->getFeatures().supportsIndexTypeUint8.enabled);
6654 }
6655
submitOutsideRenderPassCommandsImpl()6656 angle::Result ContextVk::submitOutsideRenderPassCommandsImpl()
6657 {
6658 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::submitOutsideRenderPassCommandsImpl");
6659 ANGLE_TRY(flushOutsideRenderPassCommands());
6660 Serial unusedSerial;
6661 ANGLE_TRY(submitFrameOutsideCommandBufferOnly(&unusedSerial));
6662 return angle::Result::Continue;
6663 }
6664
flushOutsideRenderPassCommands()6665 angle::Result ContextVk::flushOutsideRenderPassCommands()
6666 {
6667 if (mOutsideRenderPassCommands->empty())
6668 {
6669 return angle::Result::Continue;
6670 }
6671
6672 addOverlayUsedBuffersCount(mOutsideRenderPassCommands);
6673
6674 if (vk::CommandBufferHelperCommon::kEnableCommandStreamDiagnostics)
6675 {
6676 mOutsideRenderPassCommands->addCommandDiagnostics(this);
6677 }
6678
6679 flushDescriptorSetUpdates();
6680
6681 getShareGroupVk()->acquireResourceUseList(
6682 std::move(mOutsideRenderPassCommands->getResourceUseList()));
6683
6684 ANGLE_TRY(mRenderer->flushOutsideRPCommands(this, hasProtectedContent(),
6685 &mOutsideRenderPassCommands));
6686
6687 // Make sure appropriate dirty bits are set, in case another thread makes a submission before
6688 // the next dispatch call.
6689 mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
6690
6691 mPerfCounters.flushedOutsideRenderPassCommandBuffers++;
6692 return angle::Result::Continue;
6693 }
6694
beginRenderPassQuery(QueryVk * queryVk)6695 angle::Result ContextVk::beginRenderPassQuery(QueryVk *queryVk)
6696 {
6697 // Emit debug-util markers before calling the query command.
6698 ANGLE_TRY(handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd));
6699
6700 // To avoid complexity, we always start and end these queries inside the render pass. If the
6701 // render pass has not yet started, the query is deferred until it does.
6702 if (mRenderPassCommandBuffer)
6703 {
6704 ANGLE_TRY(queryVk->getQueryHelper()->beginRenderPassQuery(this));
6705 }
6706
6707 // Update rasterizer discard emulation with primitives generated query if necessary.
6708 if (queryVk->getType() == gl::QueryType::PrimitivesGenerated)
6709 {
6710 updateRasterizerDiscardEnabled(true);
6711 }
6712
6713 gl::QueryType type = queryVk->getType();
6714
6715 ASSERT(mActiveRenderPassQueries[type] == nullptr);
6716 mActiveRenderPassQueries[type] = queryVk;
6717
6718 return angle::Result::Continue;
6719 }
6720
endRenderPassQuery(QueryVk * queryVk)6721 angle::Result ContextVk::endRenderPassQuery(QueryVk *queryVk)
6722 {
6723 gl::QueryType type = queryVk->getType();
6724
6725 // Emit debug-util markers before calling the query command.
6726 ANGLE_TRY(handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd));
6727
6728 // End the query inside the render pass. In some situations, the query may not have actually
6729 // been issued, so there is nothing to do there. That is the case for transform feedback
6730 // queries which are deferred until a draw call with transform feedback active is issued, which
6731 // may have never happened.
6732 ASSERT(mRenderPassCommandBuffer == nullptr ||
6733 type == gl::QueryType::TransformFeedbackPrimitivesWritten || queryVk->hasQueryBegun());
6734 if (mRenderPassCommandBuffer && queryVk->hasQueryBegun())
6735 {
6736 queryVk->getQueryHelper()->endRenderPassQuery(this);
6737 }
6738
6739 // Update rasterizer discard emulation with primitives generated query if necessary.
6740 if (type == gl::QueryType::PrimitivesGenerated)
6741 {
6742 updateRasterizerDiscardEnabled(false);
6743 }
6744
6745 ASSERT(mActiveRenderPassQueries[type] == queryVk);
6746 mActiveRenderPassQueries[type] = nullptr;
6747
6748 return angle::Result::Continue;
6749 }
6750
pauseRenderPassQueriesIfActive()6751 void ContextVk::pauseRenderPassQueriesIfActive()
6752 {
6753 if (mRenderPassCommandBuffer == nullptr)
6754 {
6755 return;
6756 }
6757
6758 for (QueryVk *activeQuery : mActiveRenderPassQueries)
6759 {
6760 if (activeQuery)
6761 {
6762 activeQuery->onRenderPassEnd(this);
6763
6764 // No need to update rasterizer discard emulation with primitives generated query. The
6765 // state will be updated when the next render pass starts.
6766 }
6767 }
6768 }
6769
resumeRenderPassQueriesIfActive()6770 angle::Result ContextVk::resumeRenderPassQueriesIfActive()
6771 {
6772 ASSERT(mRenderPassCommandBuffer);
6773
6774 // Note: these queries should be processed in order. See comment in QueryVk::onRenderPassStart.
6775 for (QueryVk *activeQuery : mActiveRenderPassQueries)
6776 {
6777 if (activeQuery)
6778 {
6779 // Transform feedback queries are handled separately.
6780 if (activeQuery->getType() == gl::QueryType::TransformFeedbackPrimitivesWritten)
6781 {
6782 continue;
6783 }
6784
6785 ANGLE_TRY(activeQuery->onRenderPassStart(this));
6786
6787 // Update rasterizer discard emulation with primitives generated query if necessary.
6788 if (activeQuery->getType() == gl::QueryType::PrimitivesGenerated)
6789 {
6790 updateRasterizerDiscardEnabled(true);
6791 }
6792 }
6793 }
6794
6795 return angle::Result::Continue;
6796 }
6797
resumeXfbRenderPassQueriesIfActive()6798 angle::Result ContextVk::resumeXfbRenderPassQueriesIfActive()
6799 {
6800 ASSERT(mRenderPassCommandBuffer);
6801
6802 // All other queries are handled separately.
6803 QueryVk *xfbQuery = mActiveRenderPassQueries[gl::QueryType::TransformFeedbackPrimitivesWritten];
6804 if (xfbQuery && mState.isTransformFeedbackActiveUnpaused())
6805 {
6806 ANGLE_TRY(xfbQuery->onRenderPassStart(this));
6807 }
6808
6809 return angle::Result::Continue;
6810 }
6811
doesPrimitivesGeneratedQuerySupportRasterizerDiscard() const6812 bool ContextVk::doesPrimitivesGeneratedQuerySupportRasterizerDiscard() const
6813 {
6814 // TODO: If primitives generated is implemented with VK_EXT_primitives_generated_query, check
6815 // the corresponding feature bit. http://anglebug.com/5430.
6816
6817 // If primitives generated is emulated with pipeline statistics query, it's unknown on which
6818 // hardware rasterizer discard is supported. Assume it's supported on none.
6819 if (getFeatures().supportsPipelineStatisticsQuery.enabled)
6820 {
6821 return false;
6822 }
6823
6824 return true;
6825 }
6826
isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(bool isPrimitivesGeneratedQueryActive) const6827 bool ContextVk::isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(
6828 bool isPrimitivesGeneratedQueryActive) const
6829 {
6830 return isPrimitivesGeneratedQueryActive && mState.isRasterizerDiscardEnabled() &&
6831 !doesPrimitivesGeneratedQuerySupportRasterizerDiscard();
6832 }
6833
getActiveRenderPassQuery(gl::QueryType queryType) const6834 QueryVk *ContextVk::getActiveRenderPassQuery(gl::QueryType queryType) const
6835 {
6836 return mActiveRenderPassQueries[queryType];
6837 }
6838
isRobustResourceInitEnabled() const6839 bool ContextVk::isRobustResourceInitEnabled() const
6840 {
6841 return mState.isRobustResourceInitEnabled();
6842 }
6843
setDefaultUniformBlocksMinSizeForTesting(size_t minSize)6844 void ContextVk::setDefaultUniformBlocksMinSizeForTesting(size_t minSize)
6845 {
6846 mDefaultUniformStorage.setMinimumSizeForTesting(minSize);
6847 }
6848
initializeMultisampleTextureToBlack(const gl::Context * context,gl::Texture * glTexture)6849 angle::Result ContextVk::initializeMultisampleTextureToBlack(const gl::Context *context,
6850 gl::Texture *glTexture)
6851 {
6852 ASSERT(glTexture->getType() == gl::TextureType::_2DMultisample);
6853 TextureVk *textureVk = vk::GetImpl(glTexture);
6854
6855 return textureVk->initializeContents(context, gl::ImageIndex::Make2DMultisample());
6856 }
6857
onProgramExecutableReset(ProgramExecutableVk * executableVk)6858 void ContextVk::onProgramExecutableReset(ProgramExecutableVk *executableVk)
6859 {
6860 const gl::ProgramExecutable *executable = getState().getProgramExecutable();
6861 if (!executable)
6862 {
6863 return;
6864 }
6865
6866 // Only do this for the currently bound ProgramExecutableVk, since Program A can be linked while
6867 // Program B is currently in use and we don't want to reset/invalidate Program B's pipeline.
6868 if (executableVk != getExecutable())
6869 {
6870 return;
6871 }
6872
6873 // Reset *ContextVk::mCurrentGraphicsPipeline, since programInfo.release() freed the
6874 // PipelineHelper that it's currently pointing to.
6875 // TODO(http://anglebug.com/5624): rework updateActiveTextures(), createPipelineLayout(),
6876 // handleDirtyGraphicsPipeline(), and ProgramPipelineVk::link().
6877 resetCurrentGraphicsPipeline();
6878
6879 if (executable->hasLinkedShaderStage(gl::ShaderType::Compute))
6880 {
6881 invalidateCurrentComputePipeline();
6882 }
6883
6884 if (executable->hasLinkedShaderStage(gl::ShaderType::Vertex))
6885 {
6886 invalidateCurrentGraphicsPipeline();
6887 }
6888 }
6889
shouldSwitchToReadOnlyDepthFeedbackLoopMode(gl::Texture * texture,gl::Command command) const6890 bool ContextVk::shouldSwitchToReadOnlyDepthFeedbackLoopMode(gl::Texture *texture,
6891 gl::Command command) const
6892 {
6893 ASSERT(texture->isDepthOrStencil());
6894
6895 // When running compute we don't have a draw FBO.
6896 if (command == gl::Command::Dispatch)
6897 {
6898 return false;
6899 }
6900
6901 // The "readOnlyDepthMode" feature enables read-only depth-stencil feedback loops. We
6902 // only switch to "read-only" mode when there's loop. We track the depth-stencil access
6903 // mode in the RenderPass. The tracking tells us when we can retroactively go back and
6904 // change the RenderPass to read-only. If there are any writes we need to break and
6905 // finish the current RP before starting the read-only one.
6906 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
6907 return texture->isBoundToFramebuffer(drawFramebufferVk->getState().getFramebufferSerial()) &&
6908 !mState.isDepthWriteEnabled() && !drawFramebufferVk->isReadOnlyDepthFeedbackLoopMode();
6909 }
6910
onResourceAccess(const vk::CommandBufferAccess & access)6911 angle::Result ContextVk::onResourceAccess(const vk::CommandBufferAccess &access)
6912 {
6913 ANGLE_TRY(flushCommandBuffersIfNecessary(access));
6914
6915 vk::OutsideRenderPassCommandBuffer *commandBuffer =
6916 &mOutsideRenderPassCommands->getCommandBuffer();
6917
6918 for (const vk::CommandBufferImageAccess &imageAccess : access.getReadImages())
6919 {
6920 ASSERT(!IsRenderPassStartedAndUsesImage(*mRenderPassCommands, *imageAccess.image));
6921
6922 imageAccess.image->recordReadBarrier(this, imageAccess.aspectFlags, imageAccess.imageLayout,
6923 commandBuffer);
6924 imageAccess.image->retain(&mResourceUseList);
6925 }
6926
6927 for (const vk::CommandBufferImageWrite &imageWrite : access.getWriteImages())
6928 {
6929 ASSERT(!IsRenderPassStartedAndUsesImage(*mRenderPassCommands, *imageWrite.access.image));
6930
6931 imageWrite.access.image->recordWriteBarrier(this, imageWrite.access.aspectFlags,
6932 imageWrite.access.imageLayout, commandBuffer);
6933 imageWrite.access.image->retain(&mResourceUseList);
6934 imageWrite.access.image->onWrite(imageWrite.levelStart, imageWrite.levelCount,
6935 imageWrite.layerStart, imageWrite.layerCount,
6936 imageWrite.access.aspectFlags);
6937 }
6938
6939 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getReadBuffers())
6940 {
6941 ASSERT(!mRenderPassCommands->usesBufferForWrite(*bufferAccess.buffer));
6942 ASSERT(!mOutsideRenderPassCommands->usesBufferForWrite(*bufferAccess.buffer));
6943
6944 mOutsideRenderPassCommands->bufferRead(this, bufferAccess.accessType, bufferAccess.stage,
6945 bufferAccess.buffer);
6946 }
6947
6948 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getWriteBuffers())
6949 {
6950 ASSERT(!mRenderPassCommands->usesBuffer(*bufferAccess.buffer));
6951 ASSERT(!mOutsideRenderPassCommands->usesBuffer(*bufferAccess.buffer));
6952
6953 mOutsideRenderPassCommands->bufferWrite(this, bufferAccess.accessType, bufferAccess.stage,
6954 vk::AliasingMode::Disallowed, bufferAccess.buffer);
6955 }
6956
6957 return angle::Result::Continue;
6958 }
6959
flushCommandBuffersIfNecessary(const vk::CommandBufferAccess & access)6960 angle::Result ContextVk::flushCommandBuffersIfNecessary(const vk::CommandBufferAccess &access)
6961 {
6962 // Go over resources and decide whether the render pass needs to close, whether the outside
6963 // render pass commands need to be flushed, or neither. Note that closing the render pass
6964 // implies flushing the outside render pass as well, so if that needs to be done, we can close
6965 // the render pass and immediately return from this function. Otherwise, this function keeps
6966 // track of whether the outside render pass commands need to be closed, and if so, it will do
6967 // that once at the end.
6968
6969 // Read images only need to close the render pass if they need a layout transition.
6970 for (const vk::CommandBufferImageAccess &imageAccess : access.getReadImages())
6971 {
6972 // Note that different read methods are not compatible. A shader read uses a different
6973 // layout than a transfer read. So we cannot support simultaneous read usage as easily as
6974 // for Buffers. TODO: Don't close the render pass if the image was only used read-only in
6975 // the render pass. http://anglebug.com/4984
6976 if (IsRenderPassStartedAndUsesImage(*mRenderPassCommands, *imageAccess.image))
6977 {
6978 return flushCommandsAndEndRenderPass(RenderPassClosureReason::ImageUseThenOutOfRPRead);
6979 }
6980 }
6981
6982 // Write images only need to close the render pass if they need a layout transition.
6983 for (const vk::CommandBufferImageWrite &imageWrite : access.getWriteImages())
6984 {
6985 if (IsRenderPassStartedAndUsesImage(*mRenderPassCommands, *imageWrite.access.image))
6986 {
6987 return flushCommandsAndEndRenderPass(RenderPassClosureReason::ImageUseThenOutOfRPWrite);
6988 }
6989 }
6990
6991 bool shouldCloseOutsideRenderPassCommands = false;
6992
6993 // Read buffers only need a new command buffer if previously used for write.
6994 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getReadBuffers())
6995 {
6996 if (mRenderPassCommands->usesBufferForWrite(*bufferAccess.buffer))
6997 {
6998 return flushCommandsAndEndRenderPass(RenderPassClosureReason::BufferUseThenOutOfRPRead);
6999 }
7000 else if (mOutsideRenderPassCommands->usesBufferForWrite(*bufferAccess.buffer))
7001 {
7002 shouldCloseOutsideRenderPassCommands = true;
7003 }
7004 }
7005
7006 // Write buffers always need a new command buffer if previously used.
7007 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getWriteBuffers())
7008 {
7009 if (mRenderPassCommands->usesBuffer(*bufferAccess.buffer))
7010 {
7011 return flushCommandsAndEndRenderPass(
7012 RenderPassClosureReason::BufferUseThenOutOfRPWrite);
7013 }
7014 else if (mOutsideRenderPassCommands->usesBuffer(*bufferAccess.buffer))
7015 {
7016 shouldCloseOutsideRenderPassCommands = true;
7017 }
7018 }
7019
7020 if (shouldCloseOutsideRenderPassCommands)
7021 {
7022 return flushOutsideRenderPassCommands();
7023 }
7024
7025 return angle::Result::Continue;
7026 }
7027
endRenderPassIfComputeReadAfterTransformFeedbackWrite()7028 angle::Result ContextVk::endRenderPassIfComputeReadAfterTransformFeedbackWrite()
7029 {
7030 // Similar to flushCommandBuffersIfNecessary(), but using uniform buffers currently bound and
7031 // used by the current (compute) program. This is to handle read-after-write hazards where the
7032 // write originates from transform feedback.
7033 if (mCurrentTransformFeedbackBuffers.empty())
7034 {
7035 return angle::Result::Continue;
7036 }
7037
7038 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
7039 ASSERT(executable && executable->hasLinkedShaderStage(gl::ShaderType::Compute));
7040
7041 // Uniform buffers:
7042 const std::vector<gl::InterfaceBlock> &blocks = executable->getUniformBlocks();
7043
7044 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
7045 {
7046 const gl::InterfaceBlock &block = blocks[bufferIndex];
7047 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
7048 mState.getIndexedUniformBuffer(block.binding);
7049
7050 if (bufferBinding.get() == nullptr)
7051 {
7052 continue;
7053 }
7054
7055 vk::BufferHelper &buffer = vk::GetImpl(bufferBinding.get())->getBuffer();
7056 if (mCurrentTransformFeedbackBuffers.contains(&buffer))
7057 {
7058 return flushCommandsAndEndRenderPass(RenderPassClosureReason::XfbWriteThenComputeRead);
7059 }
7060 }
7061
7062 return angle::Result::Continue;
7063 }
7064
endRenderPassIfComputeReadAfterAttachmentWrite()7065 angle::Result ContextVk::endRenderPassIfComputeReadAfterAttachmentWrite()
7066 {
7067 // Similar to flushCommandBuffersIfNecessary(), but using textures currently bound and used by
7068 // the current (compute) program. This is to handle read-after-write hazards where the write
7069 // originates from a framebuffer attachment.
7070 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
7071 ASSERT(executable && executable->hasLinkedShaderStage(gl::ShaderType::Compute) &&
7072 executable->hasTextures());
7073
7074 const gl::ActiveTexturesCache &textures = mState.getActiveTexturesCache();
7075 const gl::ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes();
7076
7077 for (size_t textureUnit : executable->getActiveSamplersMask())
7078 {
7079 gl::Texture *texture = textures[textureUnit];
7080 gl::TextureType textureType = textureTypes[textureUnit];
7081
7082 if (texture == nullptr || textureType == gl::TextureType::Buffer)
7083 {
7084 continue;
7085 }
7086
7087 TextureVk *textureVk = vk::GetImpl(texture);
7088 ASSERT(textureVk != nullptr);
7089 vk::ImageHelper &image = textureVk->getImage();
7090
7091 if (IsRenderPassStartedAndUsesImage(*mRenderPassCommands, image))
7092 {
7093 return flushCommandsAndEndRenderPass(
7094 RenderPassClosureReason::ImageAttachmentThenComputeRead);
7095 }
7096 }
7097
7098 return angle::Result::Continue;
7099 }
7100
getExecutable() const7101 ProgramExecutableVk *ContextVk::getExecutable() const
7102 {
7103 gl::Program *program = mState.getProgram();
7104 if (program)
7105 {
7106 if (!program->hasLinkingState())
7107 {
7108 return &vk::GetImpl(program)->getExecutable();
7109 }
7110 }
7111 else
7112 {
7113 ProgramPipelineVk *programPipelineVk = getProgramPipeline();
7114 if (programPipelineVk)
7115 {
7116 return &programPipelineVk->getExecutable();
7117 }
7118 }
7119 return nullptr;
7120 }
7121
getPerfMonitorCounters()7122 const angle::PerfMonitorCounterGroups &ContextVk::getPerfMonitorCounters()
7123 {
7124 syncObjectPerfCounters();
7125
7126 angle::PerfMonitorCounters &counters =
7127 angle::GetPerfMonitorCounterGroup(mPerfMonitorCounters, "vulkan").counters;
7128
7129 #define ANGLE_UPDATE_PERF_MAP(COUNTER) \
7130 angle::GetPerfMonitorCounter(counters, #COUNTER).value = mPerfCounters.COUNTER;
7131
7132 ANGLE_VK_PERF_COUNTERS_X(ANGLE_UPDATE_PERF_MAP)
7133
7134 #undef ANGLE_UPDATE_PERF_MAP
7135
7136 return mPerfMonitorCounters;
7137 }
7138
7139 // UpdateDescriptorSetsBuilder implementation.
UpdateDescriptorSetsBuilder()7140 UpdateDescriptorSetsBuilder::UpdateDescriptorSetsBuilder()
7141 {
7142 // Reserve reasonable amount of spaces so that for majority of apps we don't need to grow at all
7143 mDescriptorBufferInfos.reserve(kDescriptorBufferInfosInitialSize);
7144 mDescriptorImageInfos.reserve(kDescriptorImageInfosInitialSize);
7145 mWriteDescriptorSets.reserve(kDescriptorWriteInfosInitialSize);
7146 }
7147
7148 UpdateDescriptorSetsBuilder::~UpdateDescriptorSetsBuilder() = default;
7149
7150 template <typename T, const T *VkWriteDescriptorSet::*pInfo>
growDescriptorCapacity(std::vector<T> * descriptorVector,size_t newSize)7151 void UpdateDescriptorSetsBuilder::growDescriptorCapacity(std::vector<T> *descriptorVector,
7152 size_t newSize)
7153 {
7154 const T *const oldInfoStart = descriptorVector->empty() ? nullptr : &(*descriptorVector)[0];
7155 size_t newCapacity = std::max(descriptorVector->capacity() << 1, newSize);
7156 descriptorVector->reserve(newCapacity);
7157
7158 if (oldInfoStart)
7159 {
7160 // patch mWriteInfo with new BufferInfo/ImageInfo pointers
7161 for (VkWriteDescriptorSet &set : mWriteDescriptorSets)
7162 {
7163 if (set.*pInfo)
7164 {
7165 size_t index = set.*pInfo - oldInfoStart;
7166 set.*pInfo = &(*descriptorVector)[index];
7167 }
7168 }
7169 }
7170 }
7171
7172 template <typename T, const T *VkWriteDescriptorSet::*pInfo>
allocDescriptorInfos(std::vector<T> * descriptorVector,size_t count)7173 T *UpdateDescriptorSetsBuilder::allocDescriptorInfos(std::vector<T> *descriptorVector, size_t count)
7174 {
7175 size_t oldSize = descriptorVector->size();
7176 size_t newSize = oldSize + count;
7177 if (newSize > descriptorVector->capacity())
7178 {
7179 // If we have reached capacity, grow the storage and patch the descriptor set with new
7180 // buffer info pointer
7181 growDescriptorCapacity<T, pInfo>(descriptorVector, newSize);
7182 }
7183 descriptorVector->resize(newSize);
7184 return &(*descriptorVector)[oldSize];
7185 }
7186
allocDescriptorBufferInfos(size_t count)7187 VkDescriptorBufferInfo *UpdateDescriptorSetsBuilder::allocDescriptorBufferInfos(size_t count)
7188 {
7189 return allocDescriptorInfos<VkDescriptorBufferInfo, &VkWriteDescriptorSet::pBufferInfo>(
7190 &mDescriptorBufferInfos, count);
7191 }
7192
allocDescriptorImageInfos(size_t count)7193 VkDescriptorImageInfo *UpdateDescriptorSetsBuilder::allocDescriptorImageInfos(size_t count)
7194 {
7195 return allocDescriptorInfos<VkDescriptorImageInfo, &VkWriteDescriptorSet::pImageInfo>(
7196 &mDescriptorImageInfos, count);
7197 }
7198
allocWriteDescriptorSets(size_t count)7199 VkWriteDescriptorSet *UpdateDescriptorSetsBuilder::allocWriteDescriptorSets(size_t count)
7200 {
7201 size_t oldSize = mWriteDescriptorSets.size();
7202 size_t newSize = oldSize + count;
7203 mWriteDescriptorSets.resize(newSize);
7204 return &mWriteDescriptorSets[oldSize];
7205 }
7206
flushDescriptorSetUpdates(VkDevice device)7207 uint32_t UpdateDescriptorSetsBuilder::flushDescriptorSetUpdates(VkDevice device)
7208 {
7209 if (mWriteDescriptorSets.empty())
7210 {
7211 ASSERT(mDescriptorBufferInfos.empty());
7212 ASSERT(mDescriptorImageInfos.empty());
7213 return 0;
7214 }
7215
7216 vkUpdateDescriptorSets(device, static_cast<uint32_t>(mWriteDescriptorSets.size()),
7217 mWriteDescriptorSets.data(), 0, nullptr);
7218
7219 uint32_t retVal = static_cast<uint32_t>(mDescriptorImageInfos.size());
7220
7221 mWriteDescriptorSets.clear();
7222 mDescriptorBufferInfos.clear();
7223 mDescriptorImageInfos.clear();
7224
7225 return retVal;
7226 }
7227
resetPerFramePerfCounters()7228 void ContextVk::resetPerFramePerfCounters()
7229 {
7230 mPerfCounters.renderPasses = 0;
7231 mPerfCounters.writeDescriptorSets = 0;
7232 mPerfCounters.flushedOutsideRenderPassCommandBuffers = 0;
7233 mPerfCounters.resolveImageCommands = 0;
7234 mPerfCounters.descriptorSetAllocations = 0;
7235
7236 const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
7237 mState.getShaderProgramManagerForCapture().getProgramsForCaptureAndPerf();
7238 for (const std::pair<GLuint, gl::Program *> &resource : programs)
7239 {
7240 gl::Program *program = resource.second;
7241 if (program->hasLinkingState())
7242 {
7243 continue;
7244 }
7245 ProgramVk *programVk = vk::GetImpl(program);
7246 programVk->getExecutable().resetDescriptorSetPerfCounters();
7247 }
7248 }
7249 } // namespace rx
7250