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/system_utils.h"
15 #include "common/utilities.h"
16 #include "image_util/loadimage.h"
17 #include "libANGLE/Context.h"
18 #include "libANGLE/Display.h"
19 #include "libANGLE/Program.h"
20 #include "libANGLE/Semaphore.h"
21 #include "libANGLE/ShareGroup.h"
22 #include "libANGLE/Surface.h"
23 #include "libANGLE/angletypes.h"
24 #include "libANGLE/renderer/renderer_utils.h"
25 #include "libANGLE/renderer/vulkan/BufferVk.h"
26 #include "libANGLE/renderer/vulkan/CompilerVk.h"
27 #include "libANGLE/renderer/vulkan/DisplayVk.h"
28 #include "libANGLE/renderer/vulkan/FenceNVVk.h"
29 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
30 #include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
31 #include "libANGLE/renderer/vulkan/OverlayVk.h"
32 #include "libANGLE/renderer/vulkan/ProgramPipelineVk.h"
33 #include "libANGLE/renderer/vulkan/ProgramVk.h"
34 #include "libANGLE/renderer/vulkan/QueryVk.h"
35 #include "libANGLE/renderer/vulkan/RenderbufferVk.h"
36 #include "libANGLE/renderer/vulkan/SamplerVk.h"
37 #include "libANGLE/renderer/vulkan/SemaphoreVk.h"
38 #include "libANGLE/renderer/vulkan/ShaderVk.h"
39 #include "libANGLE/renderer/vulkan/SurfaceVk.h"
40 #include "libANGLE/renderer/vulkan/SyncVk.h"
41 #include "libANGLE/renderer/vulkan/TextureVk.h"
42 #include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
43 #include "libANGLE/renderer/vulkan/VertexArrayVk.h"
44 #include "libANGLE/renderer/vulkan/vk_renderer.h"
45
46 #include <fstream>
47 #include <iostream>
48 #include <sstream>
49
50 namespace rx
51 {
52 namespace
53 {
54 // If the total size of copyBufferToImage commands in the outside command buffer reaches the
55 // threshold below, the latter is flushed.
56 static constexpr VkDeviceSize kMaxBufferToImageCopySize = 64 * 1024 * 1024;
57 // The number of queueSerials we will reserve for outsideRenderPassCommands when we generate one for
58 // RenderPassCommands.
59 static constexpr size_t kMaxReservedOutsideRenderPassQueueSerials = 15;
60
61 // Dumping the command stream is disabled by default.
62 static constexpr bool kEnableCommandStreamDiagnostics = false;
63
64 // All glMemoryBarrier bits that related to texture usage
65 static constexpr GLbitfield kWriteAfterAccessImageMemoryBarriers =
66 GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
67 static constexpr GLbitfield kWriteAfterAccessMemoryBarriers =
68 kWriteAfterAccessImageMemoryBarriers | GL_SHADER_STORAGE_BARRIER_BIT;
69
70 // For shader uniforms such as gl_DepthRange and the viewport size.
71 struct GraphicsDriverUniforms
72 {
73 // Contain packed 8-bit values for atomic counter buffer offsets. These offsets are within
74 // Vulkan's minStorageBufferOffsetAlignment limit and are used to support unaligned offsets
75 // allowed in GL.
76 std::array<uint32_t, 2> acbBufferOffsets;
77
78 // .x is near, .y is far
79 std::array<float, 2> depthRange;
80
81 // Used to flip gl_FragCoord. Packed uvec2
82 uint32_t renderArea;
83
84 // Packed vec4 of snorm8
85 uint32_t flipXY;
86
87 // Only the lower 16 bits used
88 uint32_t dither;
89
90 // Various bits of state:
91 // - Surface rotation
92 // - Advanced blend equation
93 // - Sample count
94 // - Enabled clip planes
95 // - Depth transformation
96 uint32_t misc;
97 };
98 static_assert(sizeof(GraphicsDriverUniforms) % (sizeof(uint32_t) * 4) == 0,
99 "GraphicsDriverUniforms should be 16bytes aligned");
100
101 // Only used when transform feedback is emulated.
102 struct GraphicsDriverUniformsExtended
103 {
104 GraphicsDriverUniforms common;
105
106 // Only used with transform feedback emulation
107 std::array<int32_t, 4> xfbBufferOffsets;
108 int32_t xfbVerticesPerInstance;
109
110 int32_t padding[3];
111 };
112 static_assert(sizeof(GraphicsDriverUniformsExtended) % (sizeof(uint32_t) * 4) == 0,
113 "GraphicsDriverUniformsExtended should be 16bytes aligned");
114
115 struct ComputeDriverUniforms
116 {
117 // Atomic counter buffer offsets with the same layout as in GraphicsDriverUniforms.
118 std::array<uint32_t, 4> acbBufferOffsets;
119 };
120
MakeFlipUniform(bool flipX,bool flipY,bool invertViewport)121 uint32_t MakeFlipUniform(bool flipX, bool flipY, bool invertViewport)
122 {
123 // Create snorm values of either -1 or 1, based on whether flipping is enabled or not
124 // respectively.
125 constexpr uint8_t kSnormOne = 0x7F;
126 constexpr uint8_t kSnormMinusOne = 0x81;
127
128 // .xy are flips for the fragment stage.
129 uint32_t x = flipX ? kSnormMinusOne : kSnormOne;
130 uint32_t y = flipY ? kSnormMinusOne : kSnormOne;
131
132 // .zw are flips for the vertex stage.
133 uint32_t z = x;
134 uint32_t w = flipY != invertViewport ? kSnormMinusOne : kSnormOne;
135
136 return x | y << 8 | z << 16 | w << 24;
137 }
138
DefaultGLErrorCode(VkResult result)139 GLenum DefaultGLErrorCode(VkResult result)
140 {
141 switch (result)
142 {
143 case VK_ERROR_OUT_OF_HOST_MEMORY:
144 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
145 case VK_ERROR_TOO_MANY_OBJECTS:
146 return GL_OUT_OF_MEMORY;
147 case VK_ERROR_DEVICE_LOST:
148 return GL_CONTEXT_LOST;
149 default:
150 return GL_INVALID_OPERATION;
151 }
152 }
153
154 constexpr gl::ShaderMap<vk::ImageLayout> kShaderReadOnlyImageLayouts = {
155 {gl::ShaderType::Vertex, vk::ImageLayout::VertexShaderReadOnly},
156 {gl::ShaderType::TessControl, vk::ImageLayout::PreFragmentShadersReadOnly},
157 {gl::ShaderType::TessEvaluation, vk::ImageLayout::PreFragmentShadersReadOnly},
158 {gl::ShaderType::Geometry, vk::ImageLayout::PreFragmentShadersReadOnly},
159 {gl::ShaderType::Fragment, vk::ImageLayout::FragmentShaderReadOnly},
160 {gl::ShaderType::Compute, vk::ImageLayout::ComputeShaderReadOnly}};
161
162 constexpr gl::ShaderMap<vk::ImageLayout> kShaderWriteImageLayouts = {
163 {gl::ShaderType::Vertex, vk::ImageLayout::VertexShaderWrite},
164 {gl::ShaderType::TessControl, vk::ImageLayout::PreFragmentShadersWrite},
165 {gl::ShaderType::TessEvaluation, vk::ImageLayout::PreFragmentShadersWrite},
166 {gl::ShaderType::Geometry, vk::ImageLayout::PreFragmentShadersWrite},
167 {gl::ShaderType::Fragment, vk::ImageLayout::FragmentShaderWrite},
168 {gl::ShaderType::Compute, vk::ImageLayout::ComputeShaderWrite}};
169
170 constexpr VkBufferUsageFlags kVertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
171 constexpr size_t kDynamicVertexDataSize = 16 * 1024;
172
CanMultiDrawIndirectUseCmd(ContextVk * contextVk,VertexArrayVk * vertexArray,gl::PrimitiveMode mode,GLsizei drawcount,GLsizei stride)173 bool CanMultiDrawIndirectUseCmd(ContextVk *contextVk,
174 VertexArrayVk *vertexArray,
175 gl::PrimitiveMode mode,
176 GLsizei drawcount,
177 GLsizei stride)
178 {
179 // Use the generic implementation if multiDrawIndirect is disabled, if line loop is being used
180 // for multiDraw, if drawcount is greater than maxDrawIndirectCount, or if there are streaming
181 // vertex attributes.
182 ASSERT(drawcount > 1);
183 const bool supportsMultiDrawIndirect =
184 contextVk->getFeatures().supportsMultiDrawIndirect.enabled;
185 const bool isMultiDrawLineLoop = (mode == gl::PrimitiveMode::LineLoop);
186 const bool isDrawCountBeyondLimit =
187 (static_cast<uint32_t>(drawcount) >
188 contextVk->getRenderer()->getPhysicalDeviceProperties().limits.maxDrawIndirectCount);
189 const bool isMultiDrawWithStreamingAttribs = vertexArray->getStreamingVertexAttribsMask().any();
190
191 const bool canMultiDrawIndirectUseCmd = supportsMultiDrawIndirect && !isMultiDrawLineLoop &&
192 !isDrawCountBeyondLimit &&
193 !isMultiDrawWithStreamingAttribs;
194 return canMultiDrawIndirectUseCmd;
195 }
196
GetCoverageSampleCount(const gl::State & glState,GLint samples)197 uint32_t GetCoverageSampleCount(const gl::State &glState, GLint samples)
198 {
199 ASSERT(glState.isSampleCoverageEnabled());
200
201 // Get a fraction of the samples based on the coverage parameters.
202 // There are multiple ways to obtain an integer value from a float -
203 // truncation, ceil and round
204 //
205 // round() provides a more even distribution of values but doesn't seem to play well
206 // with all vendors (AMD). A way to work around this is to increase the comparison threshold
207 // of deqp tests. Though this takes care of deqp tests other apps would still have issues.
208 //
209 // Truncation provides an uneven distribution near the edges of the interval but seems to
210 // play well with all vendors.
211 //
212 // We are going with truncation for expediency.
213 return static_cast<uint32_t>(glState.getSampleCoverageValue() * samples);
214 }
215
ApplySampleCoverage(const gl::State & glState,uint32_t coverageSampleCount,uint32_t * maskOut)216 void ApplySampleCoverage(const gl::State &glState, uint32_t coverageSampleCount, uint32_t *maskOut)
217 {
218 ASSERT(glState.isSampleCoverageEnabled());
219
220 uint32_t coverageMask = angle::BitMask<uint32_t>(coverageSampleCount);
221
222 if (glState.getSampleCoverageInvert())
223 {
224 coverageMask = ~coverageMask;
225 }
226
227 *maskOut &= coverageMask;
228 }
229
DetermineSurfaceRotation(const gl::Framebuffer * framebuffer,const WindowSurfaceVk * windowSurface)230 SurfaceRotation DetermineSurfaceRotation(const gl::Framebuffer *framebuffer,
231 const WindowSurfaceVk *windowSurface)
232 {
233 if (windowSurface && framebuffer->isDefault())
234 {
235 switch (windowSurface->getPreTransform())
236 {
237 case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
238 // Do not rotate gl_Position (surface matches the device's orientation):
239 return SurfaceRotation::Identity;
240 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
241 // Rotate gl_Position 90 degrees:
242 return SurfaceRotation::Rotated90Degrees;
243 case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
244 // Rotate gl_Position 180 degrees:
245 return SurfaceRotation::Rotated180Degrees;
246 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
247 // Rotate gl_Position 270 degrees:
248 return SurfaceRotation::Rotated270Degrees;
249 default:
250 UNREACHABLE();
251 return SurfaceRotation::Identity;
252 }
253 }
254 else
255 {
256 // Do not rotate gl_Position (offscreen framebuffer):
257 return SurfaceRotation::Identity;
258 }
259 }
260
261 // Should not generate a copy with modern C++.
GetTraceEventName(const char * title,uint64_t counter)262 EventName GetTraceEventName(const char *title, uint64_t counter)
263 {
264 EventName buf;
265 snprintf(buf.data(), kMaxGpuEventNameLen - 1, "%s %llu", title,
266 static_cast<unsigned long long>(counter));
267 return buf;
268 }
269
GetColorAccess(const gl::State & state,const gl::FramebufferState & framebufferState,const gl::DrawBufferMask & emulatedAlphaMask,const gl::ProgramExecutable * executable,size_t colorIndexGL)270 vk::ResourceAccess GetColorAccess(const gl::State &state,
271 const gl::FramebufferState &framebufferState,
272 const gl::DrawBufferMask &emulatedAlphaMask,
273 const gl::ProgramExecutable *executable,
274 size_t colorIndexGL)
275 {
276 // No access if draw buffer is disabled altogether
277 // Without framebuffer fetch:
278 // No access if color output is masked, or rasterizer discard is enabled
279 // With framebuffer fetch:
280 // Read access if color output is masked, or rasterizer discard is enabled
281
282 if (!framebufferState.getEnabledDrawBuffers().test(colorIndexGL))
283 {
284 return vk::ResourceAccess::Unused;
285 }
286
287 const gl::BlendStateExt &blendStateExt = state.getBlendStateExt();
288 uint8_t colorMask = gl::BlendStateExt::ColorMaskStorage::GetValueIndexed(
289 colorIndexGL, blendStateExt.getColorMaskBits());
290 if (emulatedAlphaMask[colorIndexGL])
291 {
292 colorMask &= ~VK_COLOR_COMPONENT_A_BIT;
293 }
294 const bool isOutputMasked = colorMask == 0 || state.isRasterizerDiscardEnabled();
295
296 if (isOutputMasked)
297 {
298 const bool hasFramebufferFetch =
299 executable ? executable->usesColorFramebufferFetch() : false;
300 return hasFramebufferFetch ? vk::ResourceAccess::ReadOnly : vk::ResourceAccess::Unused;
301 }
302
303 return vk::ResourceAccess::ReadWrite;
304 }
305
GetDepthAccess(const gl::DepthStencilState & dsState,const gl::ProgramExecutable * executable,UpdateDepthFeedbackLoopReason reason)306 vk::ResourceAccess GetDepthAccess(const gl::DepthStencilState &dsState,
307 const gl::ProgramExecutable *executable,
308 UpdateDepthFeedbackLoopReason reason)
309 {
310 // Skip if depth/stencil not actually accessed.
311 if (reason == UpdateDepthFeedbackLoopReason::None)
312 {
313 return vk::ResourceAccess::Unused;
314 }
315
316 // Note that clear commands don't respect depth test enable, only the mask
317 // Note Other state can be stated here too in the future, such as rasterizer discard.
318 if (!dsState.depthTest && reason != UpdateDepthFeedbackLoopReason::Clear)
319 {
320 return vk::ResourceAccess::Unused;
321 }
322
323 if (dsState.isDepthMaskedOut())
324 {
325 const bool hasFramebufferFetch =
326 executable ? executable->usesDepthFramebufferFetch() : false;
327
328 // If depthFunc is GL_ALWAYS or GL_NEVER, we do not need to load depth value.
329 return (dsState.depthFunc == GL_ALWAYS || dsState.depthFunc == GL_NEVER) &&
330 !hasFramebufferFetch
331 ? vk::ResourceAccess::Unused
332 : vk::ResourceAccess::ReadOnly;
333 }
334
335 return vk::ResourceAccess::ReadWrite;
336 }
337
GetStencilAccess(const gl::DepthStencilState & dsState,GLuint framebufferStencilSize,const gl::ProgramExecutable * executable,UpdateDepthFeedbackLoopReason reason)338 vk::ResourceAccess GetStencilAccess(const gl::DepthStencilState &dsState,
339 GLuint framebufferStencilSize,
340 const gl::ProgramExecutable *executable,
341 UpdateDepthFeedbackLoopReason reason)
342 {
343 // Skip if depth/stencil not actually accessed.
344 if (reason == UpdateDepthFeedbackLoopReason::None)
345 {
346 return vk::ResourceAccess::Unused;
347 }
348
349 // Note that clear commands don't respect stencil test enable, only the mask
350 // Note Other state can be stated here too in the future, such as rasterizer discard.
351 if (!dsState.stencilTest && reason != UpdateDepthFeedbackLoopReason::Clear)
352 {
353 return vk::ResourceAccess::Unused;
354 }
355
356 const bool hasFramebufferFetch = executable ? executable->usesStencilFramebufferFetch() : false;
357
358 return dsState.isStencilNoOp(framebufferStencilSize) &&
359 dsState.isStencilBackNoOp(framebufferStencilSize) && !hasFramebufferFetch
360 ? vk::ResourceAccess::ReadOnly
361 : vk::ResourceAccess::ReadWrite;
362 }
363
GetContextPriority(const gl::State & state)364 egl::ContextPriority GetContextPriority(const gl::State &state)
365 {
366 return egl::FromEGLenum<egl::ContextPriority>(state.getContextPriority());
367 }
368
IsStencilSamplerBinding(const gl::ProgramExecutable & executable,size_t textureUnit)369 bool IsStencilSamplerBinding(const gl::ProgramExecutable &executable, size_t textureUnit)
370 {
371 const gl::SamplerFormat format = executable.getSamplerFormatForTextureUnitIndex(textureUnit);
372 const bool isStencilTexture = format == gl::SamplerFormat::Unsigned;
373 return isStencilTexture;
374 }
375
GetDepthStencilAttachmentImageReadLayout(const vk::ImageHelper & image,gl::ShaderType firstShader)376 vk::ImageLayout GetDepthStencilAttachmentImageReadLayout(const vk::ImageHelper &image,
377 gl::ShaderType firstShader)
378 {
379 const bool isDepthTexture =
380 image.hasRenderPassUsageFlag(vk::RenderPassUsage::DepthTextureSampler);
381 const bool isStencilTexture =
382 image.hasRenderPassUsageFlag(vk::RenderPassUsage::StencilTextureSampler);
383
384 const bool isDepthReadOnlyAttachment =
385 image.hasRenderPassUsageFlag(vk::RenderPassUsage::DepthReadOnlyAttachment);
386 const bool isStencilReadOnlyAttachment =
387 image.hasRenderPassUsageFlag(vk::RenderPassUsage::StencilReadOnlyAttachment);
388
389 const bool isFS = firstShader == gl::ShaderType::Fragment;
390
391 // Only called when at least one aspect of the image is bound as texture
392 ASSERT(isDepthTexture || isStencilTexture);
393
394 // Check for feedback loop; this is when depth or stencil is both bound as a texture and is used
395 // in a non-read-only way as attachment.
396 if ((isDepthTexture && !isDepthReadOnlyAttachment) ||
397 (isStencilTexture && !isStencilReadOnlyAttachment))
398 {
399 return isFS ? vk::ImageLayout::DepthStencilFragmentShaderFeedback
400 : vk::ImageLayout::DepthStencilAllShadersFeedback;
401 }
402
403 if (isDepthReadOnlyAttachment)
404 {
405 if (isStencilReadOnlyAttachment)
406 {
407 // Depth read + stencil read
408 return isFS ? vk::ImageLayout::DepthReadStencilReadFragmentShaderRead
409 : vk::ImageLayout::DepthReadStencilReadAllShadersRead;
410 }
411 else
412 {
413 // Depth read + stencil write
414 return isFS ? vk::ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead
415 : vk::ImageLayout::DepthReadStencilWriteAllShadersDepthRead;
416 }
417 }
418 else
419 {
420 if (isStencilReadOnlyAttachment)
421 {
422 // Depth write + stencil read
423 return isFS ? vk::ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead
424 : vk::ImageLayout::DepthWriteStencilReadAllShadersStencilRead;
425 }
426 else
427 {
428 // Depth write + stencil write: This is definitely a feedback loop and is handled above.
429 UNREACHABLE();
430 return vk::ImageLayout::DepthStencilAllShadersFeedback;
431 }
432 }
433 }
434
GetImageReadLayout(TextureVk * textureVk,const gl::ProgramExecutable & executable,size_t textureUnit,PipelineType pipelineType)435 vk::ImageLayout GetImageReadLayout(TextureVk *textureVk,
436 const gl::ProgramExecutable &executable,
437 size_t textureUnit,
438 PipelineType pipelineType)
439 {
440 vk::ImageHelper &image = textureVk->getImage();
441
442 // If this texture has been bound as image and the current executable program accesses images,
443 // we consider this image's layout as writeable.
444 if (textureVk->hasBeenBoundAsImage() && executable.hasImages())
445 {
446 return pipelineType == PipelineType::Compute ? vk::ImageLayout::ComputeShaderWrite
447 : vk::ImageLayout::AllGraphicsShadersWrite;
448 }
449
450 gl::ShaderBitSet remainingShaderBits =
451 executable.getSamplerShaderBitsForTextureUnitIndex(textureUnit);
452 ASSERT(remainingShaderBits.any());
453 gl::ShaderType firstShader = remainingShaderBits.first();
454 gl::ShaderType lastShader = remainingShaderBits.last();
455 remainingShaderBits.reset(firstShader);
456 remainingShaderBits.reset(lastShader);
457
458 const bool isFragmentShaderOnly = firstShader == gl::ShaderType::Fragment;
459 if (isFragmentShaderOnly)
460 {
461 ASSERT(remainingShaderBits.none() && lastShader == firstShader);
462 }
463
464 if (image.hasRenderPassUsageFlag(vk::RenderPassUsage::RenderTargetAttachment))
465 {
466 // Right now we set the *TextureSampler flag only when RenderTargetAttachment is set since
467 // we do not track all textures in the render pass.
468
469 if (image.isDepthOrStencil())
470 {
471 if (IsStencilSamplerBinding(executable, textureUnit))
472 {
473 image.setRenderPassUsageFlag(vk::RenderPassUsage::StencilTextureSampler);
474 }
475 else
476 {
477 image.setRenderPassUsageFlag(vk::RenderPassUsage::DepthTextureSampler);
478 }
479
480 return GetDepthStencilAttachmentImageReadLayout(image, firstShader);
481 }
482
483 image.setRenderPassUsageFlag(vk::RenderPassUsage::ColorTextureSampler);
484
485 return isFragmentShaderOnly ? vk::ImageLayout::ColorWriteFragmentShaderFeedback
486 : vk::ImageLayout::ColorWriteAllShadersFeedback;
487 }
488
489 if (image.isDepthOrStencil())
490 {
491 // We always use a depth-stencil read-only layout for any depth Textures to simplify
492 // our implementation's handling of depth-stencil read-only mode. We don't have to
493 // split a RenderPass to transition a depth texture from shader-read to read-only.
494 // This improves performance in Manhattan. Future optimizations are likely possible
495 // here including using specialized barriers without breaking the RenderPass.
496 return isFragmentShaderOnly ? vk::ImageLayout::DepthReadStencilReadFragmentShaderRead
497 : vk::ImageLayout::DepthReadStencilReadAllShadersRead;
498 }
499
500 // We barrier against either:
501 // - Vertex only
502 // - Fragment only
503 // - Pre-fragment only (vertex, geometry and tessellation together)
504 if (remainingShaderBits.any() || firstShader != lastShader)
505 {
506 return lastShader == gl::ShaderType::Fragment ? vk::ImageLayout::AllGraphicsShadersReadOnly
507 : vk::ImageLayout::PreFragmentShadersReadOnly;
508 }
509
510 return kShaderReadOnlyImageLayouts[firstShader];
511 }
512
GetImageWriteLayoutAndSubresource(const gl::ImageUnit & imageUnit,vk::ImageHelper & image,gl::ShaderBitSet shaderStages,gl::LevelIndex * levelOut,uint32_t * layerStartOut,uint32_t * layerCountOut)513 vk::ImageLayout GetImageWriteLayoutAndSubresource(const gl::ImageUnit &imageUnit,
514 vk::ImageHelper &image,
515 gl::ShaderBitSet shaderStages,
516 gl::LevelIndex *levelOut,
517 uint32_t *layerStartOut,
518 uint32_t *layerCountOut)
519 {
520 *levelOut = gl::LevelIndex(static_cast<uint32_t>(imageUnit.level));
521
522 *layerStartOut = 0;
523 *layerCountOut = image.getLayerCount();
524 if (imageUnit.layered)
525 {
526 *layerStartOut = imageUnit.layered;
527 *layerCountOut = 1;
528 }
529
530 gl::ShaderType firstShader = shaderStages.first();
531 gl::ShaderType lastShader = shaderStages.last();
532 shaderStages.reset(firstShader);
533 shaderStages.reset(lastShader);
534 // We barrier against either:
535 // - Vertex only
536 // - Fragment only
537 // - Pre-fragment only (vertex, geometry and tessellation together)
538 if (shaderStages.any() || firstShader != lastShader)
539 {
540 return lastShader == gl::ShaderType::Fragment ? vk::ImageLayout::AllGraphicsShadersWrite
541 : vk::ImageLayout::PreFragmentShadersWrite;
542 }
543
544 return kShaderWriteImageLayouts[firstShader];
545 }
546
547 template <typename CommandBufferT>
OnTextureBufferRead(vk::BufferHelper * buffer,gl::ShaderBitSet stages,CommandBufferT * commandBufferHelper)548 void OnTextureBufferRead(vk::BufferHelper *buffer,
549 gl::ShaderBitSet stages,
550 CommandBufferT *commandBufferHelper)
551 {
552 ASSERT(stages.any());
553
554 // TODO: accept multiple stages in bufferRead. http://anglebug.com/42262235
555 for (gl::ShaderType stage : stages)
556 {
557 // Note: if another range of the same buffer is simultaneously used for storage,
558 // such as for transform feedback output, or SSBO, unnecessary barriers can be
559 // generated.
560 commandBufferHelper->bufferRead(VK_ACCESS_SHADER_READ_BIT, vk::GetPipelineStage(stage),
561 buffer);
562 }
563 }
564
OnImageBufferWrite(BufferVk * bufferVk,gl::ShaderBitSet stages,vk::CommandBufferHelperCommon * commandBufferHelper)565 void OnImageBufferWrite(BufferVk *bufferVk,
566 gl::ShaderBitSet stages,
567 vk::CommandBufferHelperCommon *commandBufferHelper)
568 {
569 vk::BufferHelper &buffer = bufferVk->getBuffer();
570
571 // TODO: accept multiple stages in bufferWrite. http://anglebug.com/42262235
572 for (gl::ShaderType stage : stages)
573 {
574 commandBufferHelper->bufferWrite(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
575 vk::GetPipelineStage(stage), &buffer);
576 }
577 }
578
579 constexpr angle::PackedEnumMap<RenderPassClosureReason, const char *> kRenderPassClosureReason = {{
580 {RenderPassClosureReason::AlreadySpecifiedElsewhere, nullptr},
581 {RenderPassClosureReason::ContextDestruction, "Render pass closed due to context destruction"},
582 {RenderPassClosureReason::ContextChange, "Render pass closed due to context change"},
583 {RenderPassClosureReason::GLFlush, "Render pass closed due to glFlush()"},
584 {RenderPassClosureReason::GLFinish, "Render pass closed due to glFinish()"},
585 {RenderPassClosureReason::EGLSwapBuffers, "Render pass closed due to eglSwapBuffers()"},
586 {RenderPassClosureReason::EGLWaitClient, "Render pass closed due to eglWaitClient()"},
587 {RenderPassClosureReason::SurfaceUnMakeCurrent,
588 "Render pass closed due to onSurfaceUnMakeCurrent()"},
589 {RenderPassClosureReason::FramebufferBindingChange,
590 "Render pass closed due to framebuffer binding change"},
591 {RenderPassClosureReason::FramebufferChange, "Render pass closed due to framebuffer change"},
592 {RenderPassClosureReason::NewRenderPass,
593 "Render pass closed due to starting a new render pass"},
594 {RenderPassClosureReason::BufferUseThenXfbWrite,
595 "Render pass closed due to buffer use as transform feedback output after prior use in render "
596 "pass"},
597 {RenderPassClosureReason::XfbWriteThenVertexIndexBuffer,
598 "Render pass closed due to transform feedback buffer use as vertex/index input"},
599 {RenderPassClosureReason::XfbWriteThenIndirectDrawBuffer,
600 "Render pass closed due to indirect draw buffer previously used as transform feedback output "
601 "in render pass"},
602 {RenderPassClosureReason::XfbResumeAfterDrawBasedClear,
603 "Render pass closed due to transform feedback resume after clear through draw"},
604 {RenderPassClosureReason::DepthStencilUseInFeedbackLoop,
605 "Render pass closed due to depth/stencil attachment use under feedback loop"},
606 {RenderPassClosureReason::DepthStencilWriteAfterFeedbackLoop,
607 "Render pass closed due to depth/stencil attachment write after feedback loop"},
608 {RenderPassClosureReason::PipelineBindWhileXfbActive,
609 "Render pass closed due to graphics pipeline change while transform feedback is active"},
610 {RenderPassClosureReason::BufferWriteThenMap,
611 "Render pass closed due to mapping buffer being written to by said render pass"},
612 {RenderPassClosureReason::BufferWriteThenOutOfRPRead,
613 "Render pass closed due to non-render-pass read of buffer that was written to in render pass"},
614 {RenderPassClosureReason::BufferUseThenOutOfRPWrite,
615 "Render pass closed due to non-render-pass write of buffer that was used in render pass"},
616 {RenderPassClosureReason::ImageUseThenOutOfRPRead,
617 "Render pass closed due to non-render-pass read of image that was used in render pass"},
618 {RenderPassClosureReason::ImageUseThenOutOfRPWrite,
619 "Render pass closed due to non-render-pass write of image that was used in render pass"},
620 {RenderPassClosureReason::XfbWriteThenComputeRead,
621 "Render pass closed due to compute read of buffer previously used as transform feedback "
622 "output in render pass"},
623 {RenderPassClosureReason::XfbWriteThenIndirectDispatchBuffer,
624 "Render pass closed due to indirect dispatch buffer previously used as transform feedback "
625 "output in render pass"},
626 {RenderPassClosureReason::ImageAttachmentThenComputeRead,
627 "Render pass closed due to compute read of image previously used as framebuffer attachment in "
628 "render pass"},
629 {RenderPassClosureReason::GetQueryResult, "Render pass closed due to getting query result"},
630 {RenderPassClosureReason::BeginNonRenderPassQuery,
631 "Render pass closed due to non-render-pass query begin"},
632 {RenderPassClosureReason::EndNonRenderPassQuery,
633 "Render pass closed due to non-render-pass query end"},
634 {RenderPassClosureReason::TimestampQuery, "Render pass closed due to timestamp query"},
635 {RenderPassClosureReason::EndRenderPassQuery,
636 "Render pass closed due to switch from query enabled draw to query disabled draw"},
637 {RenderPassClosureReason::GLReadPixels, "Render pass closed due to glReadPixels()"},
638 {RenderPassClosureReason::BufferUseThenReleaseToExternal,
639 "Render pass closed due to buffer (used by render pass) release to external"},
640 {RenderPassClosureReason::ImageUseThenReleaseToExternal,
641 "Render pass closed due to image (used by render pass) release to external"},
642 {RenderPassClosureReason::BufferInUseWhenSynchronizedMap,
643 "Render pass closed due to mapping buffer in use by GPU without GL_MAP_UNSYNCHRONIZED_BIT"},
644 {RenderPassClosureReason::GLMemoryBarrierThenStorageResource,
645 "Render pass closed due to glMemoryBarrier before storage output in render pass"},
646 {RenderPassClosureReason::StorageResourceUseThenGLMemoryBarrier,
647 "Render pass closed due to glMemoryBarrier after storage output in render pass"},
648 {RenderPassClosureReason::ExternalSemaphoreSignal,
649 "Render pass closed due to external semaphore signal"},
650 {RenderPassClosureReason::SyncObjectInit, "Render pass closed due to sync object insertion"},
651 {RenderPassClosureReason::SyncObjectWithFdInit,
652 "Render pass closed due to sync object with fd insertion"},
653 {RenderPassClosureReason::SyncObjectClientWait,
654 "Render pass closed due to sync object client wait"},
655 {RenderPassClosureReason::SyncObjectServerWait,
656 "Render pass closed due to sync object server wait"},
657 {RenderPassClosureReason::SyncObjectGetStatus,
658 "Render pass closed due to sync object get status"},
659 {RenderPassClosureReason::XfbPause, "Render pass closed due to transform feedback pause"},
660 {RenderPassClosureReason::FramebufferFetchEmulation,
661 "Render pass closed due to framebuffer fetch emulation"},
662 {RenderPassClosureReason::GenerateMipmapOnCPU,
663 "Render pass closed due to fallback to CPU when generating mipmaps"},
664 {RenderPassClosureReason::CopyTextureOnCPU,
665 "Render pass closed due to fallback to CPU when copying texture"},
666 {RenderPassClosureReason::TextureReformatToRenderable,
667 "Render pass closed due to reformatting texture to a renderable fallback"},
668 {RenderPassClosureReason::DeviceLocalBufferMap,
669 "Render pass closed due to mapping device local buffer"},
670 {RenderPassClosureReason::PrepareForBlit, "Render pass closed prior to draw-based blit"},
671 {RenderPassClosureReason::PrepareForImageCopy,
672 "Render pass closed prior to draw-based image copy"},
673 {RenderPassClosureReason::TemporaryForImageClear,
674 "Temporary render pass used for image clear closed"},
675 {RenderPassClosureReason::TemporaryForImageCopy,
676 "Temporary render pass used for image copy closed"},
677 {RenderPassClosureReason::TemporaryForOverlayDraw,
678 "Temporary render pass used for overlay draw closed"},
679 }};
680
GetLocalDependencyFlags(ContextVk * contextVk)681 VkDependencyFlags GetLocalDependencyFlags(ContextVk *contextVk)
682 {
683 VkDependencyFlags dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
684 if (contextVk->getCurrentViewCount() > 0)
685 {
686 dependencyFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
687 }
688 return dependencyFlags;
689 }
690
BlendModeSupportsDither(const ContextVk * contextVk,size_t colorIndex)691 bool BlendModeSupportsDither(const ContextVk *contextVk, size_t colorIndex)
692 {
693 const gl::State &state = contextVk->getState();
694
695 // Specific combinations of color blend modes are known to work with our dithering emulation.
696 // Note we specifically don't check alpha blend, as dither isn't applied to alpha.
697 // See http://b/232574868 for more discussion and reasoning.
698 gl::BlendFactorType srcBlendFactor = state.getBlendStateExt().getSrcColorIndexed(colorIndex);
699 gl::BlendFactorType dstBlendFactor = state.getBlendStateExt().getDstColorIndexed(colorIndex);
700
701 const bool ditheringCompatibleBlendFactors =
702 (srcBlendFactor == gl::BlendFactorType::SrcAlpha &&
703 dstBlendFactor == gl::BlendFactorType::OneMinusSrcAlpha);
704
705 const bool allowAdditionalBlendFactors =
706 contextVk->getFeatures().enableAdditionalBlendFactorsForDithering.enabled &&
707 (srcBlendFactor == gl::BlendFactorType::One &&
708 dstBlendFactor == gl::BlendFactorType::OneMinusSrcAlpha);
709
710 return ditheringCompatibleBlendFactors || allowAdditionalBlendFactors;
711 }
712
ShouldUseGraphicsDriverUniformsExtended(const vk::Context * context)713 bool ShouldUseGraphicsDriverUniformsExtended(const vk::Context *context)
714 {
715 return context->getFeatures().emulateTransformFeedback.enabled;
716 }
717
IsAnySamplesQuery(gl::QueryType type)718 bool IsAnySamplesQuery(gl::QueryType type)
719 {
720 return type == gl::QueryType::AnySamples || type == gl::QueryType::AnySamplesConservative;
721 }
722
723 enum class GraphicsPipelineSubsetRenderPass
724 {
725 Unused,
726 Required,
727 };
728
729 template <typename Cache>
CreateGraphicsPipelineSubset(ContextVk * contextVk,const vk::GraphicsPipelineDesc & desc,vk::GraphicsPipelineTransitionBits transition,GraphicsPipelineSubsetRenderPass renderPass,Cache * cache,vk::PipelineCacheAccess * pipelineCache,vk::PipelineHelper ** pipelineOut)730 angle::Result CreateGraphicsPipelineSubset(ContextVk *contextVk,
731 const vk::GraphicsPipelineDesc &desc,
732 vk::GraphicsPipelineTransitionBits transition,
733 GraphicsPipelineSubsetRenderPass renderPass,
734 Cache *cache,
735 vk::PipelineCacheAccess *pipelineCache,
736 vk::PipelineHelper **pipelineOut)
737 {
738 const vk::PipelineLayout unusedPipelineLayout;
739 const vk::ShaderModuleMap unusedShaders;
740 const vk::SpecializationConstants unusedSpecConsts = {};
741
742 if (*pipelineOut != nullptr && !transition.any())
743 {
744 return angle::Result::Continue;
745 }
746
747 if (*pipelineOut != nullptr)
748 {
749 ASSERT((*pipelineOut)->valid());
750 if ((*pipelineOut)->findTransition(transition, desc, pipelineOut))
751 {
752 return angle::Result::Continue;
753 }
754 }
755
756 vk::PipelineHelper *oldPipeline = *pipelineOut;
757
758 const vk::GraphicsPipelineDesc *descPtr = nullptr;
759 if (!cache->getPipeline(desc, &descPtr, pipelineOut))
760 {
761 const vk::RenderPass unusedRenderPass;
762 const vk::RenderPass *compatibleRenderPass = &unusedRenderPass;
763 if (renderPass == GraphicsPipelineSubsetRenderPass::Required)
764 {
765 // Pull in a compatible RenderPass if used by this subset.
766 ANGLE_TRY(contextVk->getCompatibleRenderPass(desc.getRenderPassDesc(),
767 &compatibleRenderPass));
768 }
769
770 ANGLE_TRY(cache->createPipeline(contextVk, pipelineCache, *compatibleRenderPass,
771 unusedPipelineLayout, unusedShaders, unusedSpecConsts,
772 PipelineSource::Draw, desc, &descPtr, pipelineOut));
773 }
774
775 if (oldPipeline)
776 {
777 oldPipeline->addTransition(transition, descPtr, *pipelineOut);
778 }
779
780 return angle::Result::Continue;
781 }
782
QueueSerialsHaveDifferentIndexOrSmaller(const QueueSerial & queueSerial1,const QueueSerial & queueSerial2)783 bool QueueSerialsHaveDifferentIndexOrSmaller(const QueueSerial &queueSerial1,
784 const QueueSerial &queueSerial2)
785 {
786 return queueSerial1.getIndex() != queueSerial2.getIndex() || queueSerial1 < queueSerial2;
787 }
788
UpdateImagesWithSharedCacheKey(const gl::ActiveTextureArray<TextureVk * > & activeImages,const std::vector<gl::ImageBinding> & imageBindings,const vk::SharedDescriptorSetCacheKey & sharedCacheKey)789 void UpdateImagesWithSharedCacheKey(const gl::ActiveTextureArray<TextureVk *> &activeImages,
790 const std::vector<gl::ImageBinding> &imageBindings,
791 const vk::SharedDescriptorSetCacheKey &sharedCacheKey)
792 {
793 for (const gl::ImageBinding &imageBinding : imageBindings)
794 {
795 uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size());
796 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
797 {
798 GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
799 // For simplicity, we do not check if uniform is active or duplicate. The worst case is
800 // we unnecessarily delete the cache entry when image bound to inactive uniform is
801 // destroyed.
802 activeImages[imageUnit]->onNewDescriptorSet(sharedCacheKey);
803 }
804 }
805 }
806
UpdateBufferWithSharedCacheKey(const gl::OffsetBindingPointer<gl::Buffer> & bufferBinding,VkDescriptorType descriptorType,const vk::SharedDescriptorSetCacheKey & sharedCacheKey)807 void UpdateBufferWithSharedCacheKey(const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding,
808 VkDescriptorType descriptorType,
809 const vk::SharedDescriptorSetCacheKey &sharedCacheKey)
810 {
811 if (bufferBinding.get() != nullptr)
812 {
813 // For simplicity, we do not check if uniform is active or duplicate. The worst case is
814 // we unnecessarily delete the cache entry when buffer bound to inactive uniform is
815 // destroyed.
816 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
817 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
818 if (vk::IsDynamicDescriptor(descriptorType))
819 {
820 bufferHelper.getBufferBlock()->onNewDescriptorSet(sharedCacheKey);
821 }
822 else
823 {
824 bufferHelper.onNewDescriptorSet(sharedCacheKey);
825 }
826 }
827 }
828
GenerateTextureUnitSamplerIndexMap(const std::vector<GLuint> & samplerBoundTextureUnits,std::unordered_map<size_t,uint32_t> * textureUnitSamplerIndexMapOut)829 void GenerateTextureUnitSamplerIndexMap(
830 const std::vector<GLuint> &samplerBoundTextureUnits,
831 std::unordered_map<size_t, uint32_t> *textureUnitSamplerIndexMapOut)
832 {
833 // Create a map of textureUnit <-> samplerIndex
834 for (size_t samplerIndex = 0; samplerIndex < samplerBoundTextureUnits.size(); samplerIndex++)
835 {
836 textureUnitSamplerIndexMapOut->insert(
837 {samplerBoundTextureUnits[samplerIndex], static_cast<uint32_t>(samplerIndex)});
838 }
839 }
840 } // anonymous namespace
841
flushDescriptorSetUpdates()842 void ContextVk::flushDescriptorSetUpdates()
843 {
844 mPerfCounters.writeDescriptorSets +=
845 mShareGroupVk->getUpdateDescriptorSetsBuilder()->flushDescriptorSetUpdates(getDevice());
846 }
847
onRenderPassFinished(RenderPassClosureReason reason)848 ANGLE_INLINE void ContextVk::onRenderPassFinished(RenderPassClosureReason reason)
849 {
850 if (mRenderPassCommandBuffer != nullptr)
851 {
852 pauseRenderPassQueriesIfActive();
853
854 // If reason is specified, add it to the command buffer right before ending the render pass,
855 // so it will show up in GPU debuggers.
856 const char *reasonText = kRenderPassClosureReason[reason];
857 if (reasonText)
858 {
859 insertEventMarkerImpl(GL_DEBUG_SOURCE_API, reasonText);
860 }
861
862 mRenderPassCommandBuffer = nullptr;
863
864 // Restart at subpass 0.
865 mGraphicsPipelineDesc->resetSubpass(&mGraphicsPipelineTransition);
866 }
867
868 mGraphicsDirtyBits.set(DIRTY_BIT_RENDER_PASS);
869 }
870
871 // ContextVk implementation.
ContextVk(const gl::State & state,gl::ErrorSet * errorSet,vk::Renderer * renderer)872 ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, vk::Renderer *renderer)
873 : ContextImpl(state, errorSet),
874 vk::Context(renderer),
875 mGraphicsDirtyBitHandlers{},
876 mComputeDirtyBitHandlers{},
877 mRenderPassCommandBuffer(nullptr),
878 mCurrentGraphicsPipeline(nullptr),
879 mCurrentGraphicsPipelineShaders(nullptr),
880 mCurrentGraphicsPipelineVertexInput(nullptr),
881 mCurrentGraphicsPipelineFragmentOutput(nullptr),
882 mCurrentComputePipeline(nullptr),
883 mCurrentDrawMode(gl::PrimitiveMode::InvalidEnum),
884 mCurrentWindowSurface(nullptr),
885 mCurrentRotationDrawFramebuffer(SurfaceRotation::Identity),
886 mCurrentRotationReadFramebuffer(SurfaceRotation::Identity),
887 mActiveRenderPassQueries{},
888 mLastIndexBufferOffset(nullptr),
889 mCurrentIndexBuffer(nullptr),
890 mCurrentIndexBufferOffset(0),
891 mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum),
892 mXfbBaseVertex(0),
893 mXfbVertexCountPerInstance(0),
894 mClearColorValue{},
895 mClearDepthStencilValue{},
896 mClearColorMasks(0),
897 mDeferredMemoryBarriers(0),
898 mFlipYForCurrentSurface(false),
899 mFlipViewportForDrawFramebuffer(false),
900 mFlipViewportForReadFramebuffer(false),
901 mIsAnyHostVisibleBufferWritten(false),
902 mCurrentQueueSerialIndex(kInvalidQueueSerialIndex),
903 mOutsideRenderPassCommands(nullptr),
904 mRenderPassCommands(nullptr),
905 mQueryEventType(GraphicsEventCmdBuf::NotInQueryCmd),
906 mGpuEventsEnabled(false),
907 mPrimaryBufferEventCounter(0),
908 mHasDeferredFlush(false),
909 mHasAnyCommandsPendingSubmission(false),
910 mIsInColorFramebufferFetchMode(false),
911 mAllowRenderPassToReactivate(true),
912 mTotalBufferToImageCopySize(0),
913 mEstimatedPendingImageGarbageSize(0),
914 mHasWaitSemaphoresPendingSubmission(false),
915 mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
916 mGpuEventTimestampOrigin(0),
917 mInitialContextPriority(renderer->getDriverPriority(GetContextPriority(state))),
918 mContextPriority(mInitialContextPriority),
919 mProtectionType(vk::ConvertProtectionBoolToType(state.hasProtectedContent())),
920 mShareGroupVk(vk::GetImpl(state.getShareGroup()))
921 {
922 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::ContextVk");
923 memset(&mClearColorValue, 0, sizeof(mClearColorValue));
924 memset(&mClearDepthStencilValue, 0, sizeof(mClearDepthStencilValue));
925 memset(&mViewport, 0, sizeof(mViewport));
926 memset(&mScissor, 0, sizeof(mScissor));
927
928 // Ensure viewport is within Vulkan requirements
929 vk::ClampViewport(&mViewport);
930
931 mNonIndexedDirtyBitsMask.set();
932 mNonIndexedDirtyBitsMask.reset(DIRTY_BIT_INDEX_BUFFER);
933
934 mIndexedDirtyBitsMask.set();
935
936 // Once a command buffer is ended, all bindings (through |vkCmdBind*| calls) are lost per Vulkan
937 // spec. Once a new command buffer is allocated, we must make sure every previously bound
938 // resource is bound again.
939 //
940 // Note that currently these dirty bits are set every time a new render pass command buffer is
941 // begun. However, using ANGLE's SecondaryCommandBuffer, the Vulkan command buffer (which is
942 // the primary command buffer) is not ended, so technically we don't need to rebind these.
943 mNewGraphicsCommandBufferDirtyBits = DirtyBits{
944 DIRTY_BIT_RENDER_PASS, DIRTY_BIT_COLOR_ACCESS, DIRTY_BIT_DEPTH_STENCIL_ACCESS,
945 DIRTY_BIT_PIPELINE_BINDING, DIRTY_BIT_TEXTURES, DIRTY_BIT_VERTEX_BUFFERS,
946 DIRTY_BIT_INDEX_BUFFER, DIRTY_BIT_SHADER_RESOURCES, DIRTY_BIT_DESCRIPTOR_SETS,
947 DIRTY_BIT_DRIVER_UNIFORMS,
948 };
949 if (getFeatures().supportsTransformFeedbackExtension.enabled ||
950 getFeatures().emulateTransformFeedback.enabled)
951 {
952 mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
953 }
954
955 mNewComputeCommandBufferDirtyBits =
956 DirtyBits{DIRTY_BIT_PIPELINE_BINDING, DIRTY_BIT_TEXTURES, DIRTY_BIT_SHADER_RESOURCES,
957 DIRTY_BIT_DESCRIPTOR_SETS, DIRTY_BIT_DRIVER_UNIFORMS};
958
959 mDynamicStateDirtyBits = DirtyBits{
960 DIRTY_BIT_DYNAMIC_VIEWPORT, DIRTY_BIT_DYNAMIC_SCISSOR,
961 DIRTY_BIT_DYNAMIC_LINE_WIDTH, DIRTY_BIT_DYNAMIC_DEPTH_BIAS,
962 DIRTY_BIT_DYNAMIC_BLEND_CONSTANTS, DIRTY_BIT_DYNAMIC_STENCIL_COMPARE_MASK,
963 DIRTY_BIT_DYNAMIC_STENCIL_WRITE_MASK, DIRTY_BIT_DYNAMIC_STENCIL_REFERENCE,
964 };
965 if (mRenderer->getFeatures().useVertexInputBindingStrideDynamicState.enabled ||
966 getFeatures().supportsVertexInputDynamicState.enabled)
967 {
968 mDynamicStateDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
969 }
970 if (mRenderer->getFeatures().useCullModeDynamicState.enabled)
971 {
972 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_CULL_MODE);
973 }
974 if (mRenderer->getFeatures().useFrontFaceDynamicState.enabled)
975 {
976 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_FRONT_FACE);
977 }
978 if (mRenderer->getFeatures().useDepthTestEnableDynamicState.enabled)
979 {
980 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_DEPTH_TEST_ENABLE);
981 }
982 if (mRenderer->getFeatures().useDepthWriteEnableDynamicState.enabled)
983 {
984 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_DEPTH_WRITE_ENABLE);
985 }
986 if (mRenderer->getFeatures().useDepthCompareOpDynamicState.enabled)
987 {
988 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_DEPTH_COMPARE_OP);
989 }
990 if (mRenderer->getFeatures().useStencilTestEnableDynamicState.enabled)
991 {
992 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_TEST_ENABLE);
993 }
994 if (mRenderer->getFeatures().useStencilOpDynamicState.enabled)
995 {
996 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_OP);
997 }
998 if (mRenderer->getFeatures().usePrimitiveRestartEnableDynamicState.enabled)
999 {
1000 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_PRIMITIVE_RESTART_ENABLE);
1001 }
1002 if (mRenderer->getFeatures().useRasterizerDiscardEnableDynamicState.enabled)
1003 {
1004 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_RASTERIZER_DISCARD_ENABLE);
1005 }
1006 if (mRenderer->getFeatures().useDepthBiasEnableDynamicState.enabled)
1007 {
1008 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_DEPTH_BIAS_ENABLE);
1009 }
1010 if (mRenderer->getFeatures().supportsLogicOpDynamicState.enabled)
1011 {
1012 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_LOGIC_OP);
1013 }
1014 if (getFeatures().supportsFragmentShadingRate.enabled)
1015 {
1016 mDynamicStateDirtyBits.set(DIRTY_BIT_DYNAMIC_FRAGMENT_SHADING_RATE);
1017 }
1018
1019 mNewGraphicsCommandBufferDirtyBits |= mDynamicStateDirtyBits;
1020
1021 mGraphicsDirtyBitHandlers[DIRTY_BIT_MEMORY_BARRIER] =
1022 &ContextVk::handleDirtyGraphicsMemoryBarrier;
1023 mGraphicsDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] =
1024 &ContextVk::handleDirtyGraphicsDefaultAttribs;
1025 mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE_DESC] =
1026 &ContextVk::handleDirtyGraphicsPipelineDesc;
1027 mGraphicsDirtyBitHandlers[DIRTY_BIT_READ_ONLY_DEPTH_FEEDBACK_LOOP_MODE] =
1028 &ContextVk::handleDirtyGraphicsReadOnlyDepthFeedbackLoopMode;
1029 mGraphicsDirtyBitHandlers[DIRTY_BIT_ANY_SAMPLE_PASSED_QUERY_END] =
1030 &ContextVk::handleDirtyAnySamplePassedQueryEnd;
1031 mGraphicsDirtyBitHandlers[DIRTY_BIT_RENDER_PASS] = &ContextVk::handleDirtyGraphicsRenderPass;
1032 mGraphicsDirtyBitHandlers[DIRTY_BIT_EVENT_LOG] = &ContextVk::handleDirtyGraphicsEventLog;
1033 mGraphicsDirtyBitHandlers[DIRTY_BIT_COLOR_ACCESS] = &ContextVk::handleDirtyGraphicsColorAccess;
1034 mGraphicsDirtyBitHandlers[DIRTY_BIT_DEPTH_STENCIL_ACCESS] =
1035 &ContextVk::handleDirtyGraphicsDepthStencilAccess;
1036 mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE_BINDING] =
1037 &ContextVk::handleDirtyGraphicsPipelineBinding;
1038 mGraphicsDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyGraphicsTextures;
1039 mGraphicsDirtyBitHandlers[DIRTY_BIT_VERTEX_BUFFERS] =
1040 &ContextVk::handleDirtyGraphicsVertexBuffers;
1041 mGraphicsDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyGraphicsIndexBuffer;
1042 mGraphicsDirtyBitHandlers[DIRTY_BIT_UNIFORMS] = &ContextVk::handleDirtyGraphicsUniforms;
1043 mGraphicsDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
1044 &ContextVk::handleDirtyGraphicsDriverUniforms;
1045 mGraphicsDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
1046 &ContextVk::handleDirtyGraphicsShaderResources;
1047 mGraphicsDirtyBitHandlers[DIRTY_BIT_UNIFORM_BUFFERS] =
1048 &ContextVk::handleDirtyGraphicsUniformBuffers;
1049 mGraphicsDirtyBitHandlers[DIRTY_BIT_FRAMEBUFFER_FETCH_BARRIER] =
1050 &ContextVk::handleDirtyGraphicsFramebufferFetchBarrier;
1051 mGraphicsDirtyBitHandlers[DIRTY_BIT_BLEND_BARRIER] =
1052 &ContextVk::handleDirtyGraphicsBlendBarrier;
1053 if (getFeatures().supportsTransformFeedbackExtension.enabled)
1054 {
1055 mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
1056 &ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension;
1057 mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME] =
1058 &ContextVk::handleDirtyGraphicsTransformFeedbackResume;
1059 }
1060 else if (getFeatures().emulateTransformFeedback.enabled)
1061 {
1062 mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
1063 &ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation;
1064 }
1065
1066 mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
1067 &ContextVk::handleDirtyGraphicsDescriptorSets;
1068
1069 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_VIEWPORT] =
1070 &ContextVk::handleDirtyGraphicsDynamicViewport;
1071 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_SCISSOR] =
1072 &ContextVk::handleDirtyGraphicsDynamicScissor;
1073 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_LINE_WIDTH] =
1074 &ContextVk::handleDirtyGraphicsDynamicLineWidth;
1075 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_DEPTH_BIAS] =
1076 &ContextVk::handleDirtyGraphicsDynamicDepthBias;
1077 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_BLEND_CONSTANTS] =
1078 &ContextVk::handleDirtyGraphicsDynamicBlendConstants;
1079 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_STENCIL_COMPARE_MASK] =
1080 &ContextVk::handleDirtyGraphicsDynamicStencilCompareMask;
1081 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_STENCIL_WRITE_MASK] =
1082 &ContextVk::handleDirtyGraphicsDynamicStencilWriteMask;
1083 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_STENCIL_REFERENCE] =
1084 &ContextVk::handleDirtyGraphicsDynamicStencilReference;
1085 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_CULL_MODE] =
1086 &ContextVk::handleDirtyGraphicsDynamicCullMode;
1087 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_FRONT_FACE] =
1088 &ContextVk::handleDirtyGraphicsDynamicFrontFace;
1089 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_DEPTH_TEST_ENABLE] =
1090 &ContextVk::handleDirtyGraphicsDynamicDepthTestEnable;
1091 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_DEPTH_WRITE_ENABLE] =
1092 &ContextVk::handleDirtyGraphicsDynamicDepthWriteEnable;
1093 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_DEPTH_COMPARE_OP] =
1094 &ContextVk::handleDirtyGraphicsDynamicDepthCompareOp;
1095 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_STENCIL_TEST_ENABLE] =
1096 &ContextVk::handleDirtyGraphicsDynamicStencilTestEnable;
1097 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_STENCIL_OP] =
1098 &ContextVk::handleDirtyGraphicsDynamicStencilOp;
1099 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_RASTERIZER_DISCARD_ENABLE] =
1100 &ContextVk::handleDirtyGraphicsDynamicRasterizerDiscardEnable;
1101 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_DEPTH_BIAS_ENABLE] =
1102 &ContextVk::handleDirtyGraphicsDynamicDepthBiasEnable;
1103 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_LOGIC_OP] =
1104 &ContextVk::handleDirtyGraphicsDynamicLogicOp;
1105 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_PRIMITIVE_RESTART_ENABLE] =
1106 &ContextVk::handleDirtyGraphicsDynamicPrimitiveRestartEnable;
1107 mGraphicsDirtyBitHandlers[DIRTY_BIT_DYNAMIC_FRAGMENT_SHADING_RATE] =
1108 &ContextVk::handleDirtyGraphicsDynamicFragmentShadingRate;
1109
1110 mComputeDirtyBitHandlers[DIRTY_BIT_MEMORY_BARRIER] =
1111 &ContextVk::handleDirtyComputeMemoryBarrier;
1112 mComputeDirtyBitHandlers[DIRTY_BIT_EVENT_LOG] = &ContextVk::handleDirtyComputeEventLog;
1113 mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE_DESC] = &ContextVk::handleDirtyComputePipelineDesc;
1114 mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE_BINDING] =
1115 &ContextVk::handleDirtyComputePipelineBinding;
1116 mComputeDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyComputeTextures;
1117 mComputeDirtyBitHandlers[DIRTY_BIT_UNIFORMS] = &ContextVk::handleDirtyComputeUniforms;
1118 mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
1119 &ContextVk::handleDirtyComputeDriverUniforms;
1120 mComputeDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
1121 &ContextVk::handleDirtyComputeShaderResources;
1122 mComputeDirtyBitHandlers[DIRTY_BIT_UNIFORM_BUFFERS] =
1123 &ContextVk::handleDirtyComputeUniformBuffers;
1124 mComputeDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
1125 &ContextVk::handleDirtyComputeDescriptorSets;
1126
1127 mGraphicsDirtyBits = mNewGraphicsCommandBufferDirtyBits;
1128 mComputeDirtyBits = mNewComputeCommandBufferDirtyBits;
1129
1130 // If coherent framebuffer fetch is emulated, a barrier is implicitly issued between draw calls
1131 // that use framebuffer fetch. As such, the corresponding dirty bit shouldn't be cleared until
1132 // a program without framebuffer fetch is used.
1133 if (mRenderer->isCoherentColorFramebufferFetchEmulated())
1134 {
1135 mPersistentGraphicsDirtyBits.set(DIRTY_BIT_FRAMEBUFFER_FETCH_BARRIER);
1136 }
1137
1138 FillWithNullptr(&mActiveImages);
1139
1140 // The following dirty bits don't affect the program pipeline:
1141 //
1142 // - READ_FRAMEBUFFER_BINDING only affects operations that read from said framebuffer,
1143 // - CLEAR_* only affect following clear calls,
1144 // - PACK/UNPACK_STATE only affect texture data upload/download,
1145 // - *_BINDING only affect descriptor sets.
1146 //
1147 // Additionally, state that is set dynamically doesn't invalidate the program pipeline.
1148 //
1149 mPipelineDirtyBitsMask.set();
1150 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
1151 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_CLEAR_COLOR);
1152 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_CLEAR_DEPTH);
1153 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_CLEAR_STENCIL);
1154 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_UNPACK_STATE);
1155 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_UNPACK_BUFFER_BINDING);
1156 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_PACK_STATE);
1157 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_PACK_BUFFER_BINDING);
1158 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_RENDERBUFFER_BINDING);
1159 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING);
1160 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING);
1161 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_SAMPLER_BINDINGS);
1162 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_TEXTURE_BINDINGS);
1163 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_IMAGE_BINDINGS);
1164 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING);
1165 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS);
1166 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING);
1167 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
1168
1169 // Dynamic state in core Vulkan 1.0:
1170 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_VIEWPORT);
1171 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_SCISSOR_TEST_ENABLED);
1172 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_SCISSOR);
1173 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_LINE_WIDTH);
1174 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_POLYGON_OFFSET);
1175 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_BLEND_COLOR);
1176 if (!getFeatures().useNonZeroStencilWriteMaskStaticState.enabled)
1177 {
1178 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
1179 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_STENCIL_WRITEMASK_BACK);
1180 }
1181
1182 // Dynamic state in VK_EXT_extended_dynamic_state:
1183 if (mRenderer->getFeatures().useCullModeDynamicState.enabled)
1184 {
1185 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_CULL_FACE_ENABLED);
1186 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_CULL_FACE);
1187 }
1188 if (mRenderer->getFeatures().useFrontFaceDynamicState.enabled)
1189 {
1190 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_FRONT_FACE);
1191 }
1192 if (mRenderer->getFeatures().useDepthTestEnableDynamicState.enabled)
1193 {
1194 // Depth test affects depth write state too in GraphicsPipelineDesc, so the pipeline needs
1195 // to stay dirty if depth test changes while depth write state is static.
1196 if (mRenderer->getFeatures().useDepthWriteEnableDynamicState.enabled)
1197 {
1198 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_DEPTH_TEST_ENABLED);
1199 }
1200 }
1201 if (mRenderer->getFeatures().useDepthWriteEnableDynamicState.enabled)
1202 {
1203 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_DEPTH_MASK);
1204 }
1205 if (mRenderer->getFeatures().useDepthCompareOpDynamicState.enabled)
1206 {
1207 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_DEPTH_FUNC);
1208 }
1209 if (mRenderer->getFeatures().useStencilTestEnableDynamicState.enabled)
1210 {
1211 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_STENCIL_TEST_ENABLED);
1212 }
1213 if (mRenderer->getFeatures().useStencilOpDynamicState.enabled)
1214 {
1215 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_STENCIL_FUNCS_FRONT);
1216 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_STENCIL_FUNCS_BACK);
1217 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_STENCIL_OPS_FRONT);
1218 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_STENCIL_OPS_BACK);
1219 }
1220 // Dynamic state in VK_EXT_extended_dynamic_state2:
1221 if (mRenderer->getFeatures().usePrimitiveRestartEnableDynamicState.enabled)
1222 {
1223 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED);
1224 }
1225 if (mRenderer->getFeatures().useRasterizerDiscardEnableDynamicState.enabled)
1226 {
1227 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED);
1228 }
1229 if (mRenderer->getFeatures().useDepthBiasEnableDynamicState.enabled)
1230 {
1231 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED);
1232 }
1233 if (getFeatures().supportsVertexInputDynamicState.enabled)
1234 {
1235 mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_VERTEX_ARRAY_BINDING);
1236 }
1237
1238 // Stash the mRefCountedEventRecycler in vk::Context for ImageHelper to conveniently access
1239 mShareGroupRefCountedEventsGarbageRecycler =
1240 mShareGroupVk->getRefCountedEventsGarbageRecycler();
1241
1242 mDeviceQueueIndex = renderer->getDeviceQueueIndex(mContextPriority);
1243
1244 angle::PerfMonitorCounterGroup vulkanGroup;
1245 vulkanGroup.name = "vulkan";
1246
1247 #define ANGLE_ADD_PERF_MONITOR_COUNTER_GROUP(COUNTER) \
1248 { \
1249 angle::PerfMonitorCounter counter; \
1250 counter.name = #COUNTER; \
1251 counter.value = 0; \
1252 vulkanGroup.counters.push_back(counter); \
1253 }
1254
1255 ANGLE_VK_PERF_COUNTERS_X(ANGLE_ADD_PERF_MONITOR_COUNTER_GROUP)
1256
1257 #undef ANGLE_ADD_PERF_MONITOR_COUNTER_GROUP
1258
1259 mPerfMonitorCounters.push_back(vulkanGroup);
1260 }
1261
~ContextVk()1262 ContextVk::~ContextVk() {}
1263
onDestroy(const gl::Context * context)1264 void ContextVk::onDestroy(const gl::Context *context)
1265 {
1266 // If there is a context lost, destroy all the command buffers and resources regardless of
1267 // whether they finished execution on GPU.
1268 if (mRenderer->isDeviceLost())
1269 {
1270 mRenderer->handleDeviceLost();
1271 }
1272
1273 // This will not destroy any resources. It will release them to be collected after finish.
1274 mIncompleteTextures.onDestroy(context);
1275
1276 // Flush and complete current outstanding work before destruction.
1277 (void)finishImpl(RenderPassClosureReason::ContextDestruction);
1278
1279 // The finish call could also generate device loss.
1280 if (mRenderer->isDeviceLost())
1281 {
1282 mRenderer->handleDeviceLost();
1283 }
1284
1285 // Everything must be finished
1286 ASSERT(mRenderer->hasResourceUseFinished(mSubmittedResourceUse));
1287
1288 VkDevice device = getDevice();
1289
1290 mShareGroupVk->cleanupRefCountedEventGarbage();
1291
1292 mDefaultUniformStorage.release(mRenderer);
1293 mEmptyBuffer.release(mRenderer);
1294
1295 for (vk::DynamicBuffer &defaultBuffer : mStreamedVertexBuffers)
1296 {
1297 defaultBuffer.destroy(mRenderer);
1298 }
1299
1300 for (vk::DynamicQueryPool &queryPool : mQueryPools)
1301 {
1302 queryPool.destroy(device);
1303 }
1304
1305 // Recycle current command buffers.
1306
1307 // Release functions are only used for Vulkan secondary command buffers.
1308 mOutsideRenderPassCommands->releaseCommandPool();
1309 mRenderPassCommands->releaseCommandPool();
1310
1311 // Detach functions are only used for ring buffer allocators.
1312 mOutsideRenderPassCommands->detachAllocator();
1313 mRenderPassCommands->detachAllocator();
1314
1315 mRenderer->recycleOutsideRenderPassCommandBufferHelper(&mOutsideRenderPassCommands);
1316 mRenderer->recycleRenderPassCommandBufferHelper(&mRenderPassCommands);
1317
1318 mInterfacePipelinesCache.destroy(device);
1319
1320 mUtils.destroy(this);
1321
1322 mRenderPassCache.destroy(this);
1323 mShaderLibrary.destroy(device);
1324 mGpuEventQueryPool.destroy(device);
1325
1326 // Must release all Vulkan secondary command buffers before destroying the pools.
1327 if ((!vk::OutsideRenderPassCommandBuffer::ExecutesInline() ||
1328 !vk::RenderPassCommandBuffer::ExecutesInline()) &&
1329 mRenderer->isAsyncCommandBufferResetAndGarbageCleanupEnabled())
1330 {
1331 // This will also reset Primary command buffers which is REQUIRED on some buggy Vulkan
1332 // implementations.
1333 (void)mRenderer->releaseFinishedCommands(this);
1334 }
1335
1336 mCommandPools.outsideRenderPassPool.destroy(device);
1337 mCommandPools.renderPassPool.destroy(device);
1338
1339 ASSERT(mCurrentGarbage.empty());
1340
1341 if (mCurrentQueueSerialIndex != kInvalidQueueSerialIndex)
1342 {
1343 releaseQueueSerialIndex();
1344 }
1345
1346 mImageLoadContext = {};
1347 }
1348
getVertexArray() const1349 VertexArrayVk *ContextVk::getVertexArray() const
1350 {
1351 return vk::GetImpl(mState.getVertexArray());
1352 }
1353
getDrawFramebuffer() const1354 FramebufferVk *ContextVk::getDrawFramebuffer() const
1355 {
1356 return vk::GetImpl(mState.getDrawFramebuffer());
1357 }
1358
getIncompleteTexture(const gl::Context * context,gl::TextureType type,gl::SamplerFormat format,gl::Texture ** textureOut)1359 angle::Result ContextVk::getIncompleteTexture(const gl::Context *context,
1360 gl::TextureType type,
1361 gl::SamplerFormat format,
1362 gl::Texture **textureOut)
1363 {
1364 return mIncompleteTextures.getIncompleteTexture(context, type, format, this, textureOut);
1365 }
1366
initialize(const angle::ImageLoadContext & imageLoadContext)1367 angle::Result ContextVk::initialize(const angle::ImageLoadContext &imageLoadContext)
1368 {
1369 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::initialize");
1370
1371 mImageLoadContext = imageLoadContext;
1372
1373 ANGLE_TRY(mShareGroupVk->unifyContextsPriority(this));
1374
1375 ANGLE_TRY(mQueryPools[gl::QueryType::AnySamples].init(this, VK_QUERY_TYPE_OCCLUSION,
1376 vk::kDefaultOcclusionQueryPoolSize));
1377 ANGLE_TRY(mQueryPools[gl::QueryType::AnySamplesConservative].init(
1378 this, VK_QUERY_TYPE_OCCLUSION, vk::kDefaultOcclusionQueryPoolSize));
1379
1380 // Only initialize the timestamp query pools if the extension is available.
1381 if (mRenderer->getQueueFamilyProperties().timestampValidBits > 0)
1382 {
1383 ANGLE_TRY(mQueryPools[gl::QueryType::Timestamp].init(this, VK_QUERY_TYPE_TIMESTAMP,
1384 vk::kDefaultTimestampQueryPoolSize));
1385 ANGLE_TRY(mQueryPools[gl::QueryType::TimeElapsed].init(this, VK_QUERY_TYPE_TIMESTAMP,
1386 vk::kDefaultTimestampQueryPoolSize));
1387 }
1388
1389 if (getFeatures().supportsTransformFeedbackExtension.enabled)
1390 {
1391 ANGLE_TRY(mQueryPools[gl::QueryType::TransformFeedbackPrimitivesWritten].init(
1392 this, VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT,
1393 vk::kDefaultTransformFeedbackQueryPoolSize));
1394 }
1395
1396 // If VK_EXT_primitives_generated_query is supported, use that to implement the OpenGL query.
1397 // Otherwise, the primitives generated query is provided through the Vulkan pipeline statistics
1398 // query if supported.
1399 if (getFeatures().supportsPrimitivesGeneratedQuery.enabled)
1400 {
1401 ANGLE_TRY(mQueryPools[gl::QueryType::PrimitivesGenerated].init(
1402 this, VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT,
1403 vk::kDefaultPrimitivesGeneratedQueryPoolSize));
1404 }
1405 else if (getFeatures().supportsPipelineStatisticsQuery.enabled)
1406 {
1407 ANGLE_TRY(mQueryPools[gl::QueryType::PrimitivesGenerated].init(
1408 this, VK_QUERY_TYPE_PIPELINE_STATISTICS, vk::kDefaultPrimitivesGeneratedQueryPoolSize));
1409 }
1410
1411 // Init GLES to Vulkan index type map.
1412 initIndexTypeMap();
1413
1414 mGraphicsPipelineDesc.reset(new vk::GraphicsPipelineDesc());
1415 mGraphicsPipelineDesc->initDefaults(this, vk::GraphicsPipelineSubset::Complete,
1416 pipelineRobustness(), pipelineProtectedAccess());
1417
1418 // Initialize current value/default attribute buffers.
1419 for (vk::DynamicBuffer &buffer : mStreamedVertexBuffers)
1420 {
1421 buffer.init(mRenderer, kVertexBufferUsage, vk::kVertexBufferAlignment,
1422 kDynamicVertexDataSize, true);
1423 }
1424
1425 #if ANGLE_ENABLE_VULKAN_GPU_TRACE_EVENTS
1426 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
1427 ASSERT(platform);
1428
1429 // GPU tracing workaround for anglebug.com/42261625. The renderer should not emit gpu events
1430 // during platform discovery.
1431 const unsigned char *gpuEventsEnabled =
1432 platform->getTraceCategoryEnabledFlag(platform, "gpu.angle.gpu");
1433 mGpuEventsEnabled = gpuEventsEnabled && *gpuEventsEnabled;
1434 #endif
1435
1436 // Assign initial command buffers from queue
1437 ANGLE_TRY(vk::OutsideRenderPassCommandBuffer::InitializeCommandPool(
1438 this, &mCommandPools.outsideRenderPassPool, mRenderer->getQueueFamilyIndex(),
1439 getProtectionType()));
1440 ANGLE_TRY(vk::RenderPassCommandBuffer::InitializeCommandPool(
1441 this, &mCommandPools.renderPassPool, mRenderer->getQueueFamilyIndex(),
1442 getProtectionType()));
1443 ANGLE_TRY(mRenderer->getOutsideRenderPassCommandBufferHelper(
1444 this, &mCommandPools.outsideRenderPassPool, &mOutsideRenderPassCommandsAllocator,
1445 &mOutsideRenderPassCommands));
1446 ANGLE_TRY(mRenderer->getRenderPassCommandBufferHelper(
1447 this, &mCommandPools.renderPassPool, &mRenderPassCommandsAllocator, &mRenderPassCommands));
1448
1449 // Allocate queueSerial index and generate queue serial for commands.
1450 ANGLE_TRY(allocateQueueSerialIndex());
1451
1452 // Initialize serials to be valid but appear submitted and finished.
1453 mLastFlushedQueueSerial = QueueSerial(mCurrentQueueSerialIndex, Serial());
1454 mLastSubmittedQueueSerial = mLastFlushedQueueSerial;
1455
1456 if (mGpuEventsEnabled)
1457 {
1458 // GPU events should only be available if timestamp queries are available.
1459 ASSERT(mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
1460 // Calculate the difference between CPU and GPU clocks for GPU event reporting.
1461 ANGLE_TRY(mGpuEventQueryPool.init(this, VK_QUERY_TYPE_TIMESTAMP,
1462 vk::kDefaultTimestampQueryPoolSize));
1463 ANGLE_TRY(synchronizeCpuGpuTime());
1464
1465 EventName eventName = GetTraceEventName("Primary", mPrimaryBufferEventCounter);
1466 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
1467 TRACE_EVENT_PHASE_BEGIN, eventName));
1468 }
1469
1470 size_t minAlignment = static_cast<size_t>(
1471 mRenderer->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
1472 mDefaultUniformStorage.init(mRenderer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, minAlignment,
1473 mRenderer->getDefaultUniformBufferSize(), true);
1474
1475 // Initialize an "empty" buffer for use with default uniform blocks where there are no uniforms,
1476 // or atomic counter buffer array indices that are unused.
1477 constexpr VkBufferUsageFlags kEmptyBufferUsage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
1478 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
1479 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
1480 VkBufferCreateInfo emptyBufferInfo = {};
1481 emptyBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1482 emptyBufferInfo.flags = 0;
1483 emptyBufferInfo.size = 16;
1484 emptyBufferInfo.usage = kEmptyBufferUsage;
1485 emptyBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1486 emptyBufferInfo.queueFamilyIndexCount = 0;
1487 emptyBufferInfo.pQueueFamilyIndices = nullptr;
1488 constexpr VkMemoryPropertyFlags kMemoryType = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
1489 ANGLE_TRY(mEmptyBuffer.init(this, emptyBufferInfo, kMemoryType));
1490
1491 // If the share group has one context and is about to add the second one, the first context's
1492 // mutable textures should be flushed.
1493 if (isEligibleForMutableTextureFlush())
1494 {
1495 ASSERT(mShareGroupVk->getContexts().size() == 1);
1496 for (auto context : mShareGroupVk->getContexts())
1497 {
1498 ANGLE_TRY(vk::GetImpl(context.second)->flushOutsideRenderPassCommands());
1499 }
1500 }
1501
1502 return angle::Result::Continue;
1503 }
1504
isSingleBufferedWindowCurrent() const1505 bool ContextVk::isSingleBufferedWindowCurrent() const
1506 {
1507 return (mCurrentWindowSurface != nullptr && mCurrentWindowSurface->isSharedPresentMode());
1508 }
1509
hasSomethingToFlush() const1510 bool ContextVk::hasSomethingToFlush() const
1511 {
1512 // Don't skip flushes for single-buffered windows with staged updates. It is expected that a
1513 // flush call on a single-buffered window ensures any pending updates reach the screen.
1514 const bool isSingleBufferedWindowWithStagedUpdates =
1515 isSingleBufferedWindowCurrent() && mCurrentWindowSurface->hasStagedUpdates();
1516
1517 return (mHasAnyCommandsPendingSubmission || hasActiveRenderPass() ||
1518 !mOutsideRenderPassCommands->empty() || isSingleBufferedWindowWithStagedUpdates);
1519 }
1520
flushImpl(const gl::Context * context)1521 angle::Result ContextVk::flushImpl(const gl::Context *context)
1522 {
1523 // Skip if there's nothing to flush.
1524 if (!hasSomethingToFlush())
1525 {
1526 return angle::Result::Continue;
1527 }
1528
1529 // Don't defer flushes when performing front buffer rendering. This can happen when -
1530 // 1. we have a single-buffered window, in this mode the application is not required to
1531 // call eglSwapBuffers(), and glFlush() is expected to ensure that work is submitted.
1532 // 2. the framebuffer attachment has FRONT_BUFFER usage. Attachments being rendered to with such
1533 // usage flags are expected to behave similar to a single-buffered window
1534 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
1535 ASSERT(drawFramebufferVk == vk::GetImpl(mState.getDrawFramebuffer()));
1536 const bool isSingleBufferedWindow = isSingleBufferedWindowCurrent();
1537 const bool frontBufferRenderingEnabled =
1538 isSingleBufferedWindow || drawFramebufferVk->hasFrontBufferUsage();
1539
1540 if (hasActiveRenderPass() && !frontBufferRenderingEnabled)
1541 {
1542 mHasDeferredFlush = true;
1543 return angle::Result::Continue;
1544 }
1545
1546 if (isSingleBufferedWindow &&
1547 mRenderer->getFeatures().swapbuffersOnFlushOrFinishWithSingleBuffer.enabled)
1548 {
1549 return mCurrentWindowSurface->onSharedPresentContextFlush(context);
1550 }
1551
1552 return flushAndSubmitCommands(nullptr, nullptr, RenderPassClosureReason::GLFlush);
1553 }
1554
flush(const gl::Context * context)1555 angle::Result ContextVk::flush(const gl::Context *context)
1556 {
1557 ANGLE_TRY(flushImpl(context));
1558
1559 if (!mCurrentWindowSurface || isSingleBufferedWindowCurrent())
1560 {
1561 ANGLE_TRY(onFramebufferBoundary(context));
1562 }
1563
1564 return angle::Result::Continue;
1565 }
1566
finish(const gl::Context * context)1567 angle::Result ContextVk::finish(const gl::Context *context)
1568 {
1569 const bool singleBufferedFlush = isSingleBufferedWindowCurrent() && hasSomethingToFlush();
1570
1571 if (mRenderer->getFeatures().swapbuffersOnFlushOrFinishWithSingleBuffer.enabled &&
1572 singleBufferedFlush)
1573 {
1574 ANGLE_TRY(mCurrentWindowSurface->onSharedPresentContextFlush(context));
1575 // While call above performs implicit flush, don't skip |finishImpl| below, since we still
1576 // need to wait for submitted commands.
1577 }
1578
1579 ANGLE_TRY(finishImpl(RenderPassClosureReason::GLFinish));
1580
1581 syncObjectPerfCounters(mRenderer->getCommandQueuePerfCounters());
1582
1583 if (!mCurrentWindowSurface || singleBufferedFlush)
1584 {
1585 ANGLE_TRY(onFramebufferBoundary(context));
1586 }
1587
1588 return angle::Result::Continue;
1589 }
1590
onFramebufferBoundary(const gl::Context * contextGL)1591 angle::Result ContextVk::onFramebufferBoundary(const gl::Context *contextGL)
1592 {
1593 mShareGroupVk->onFramebufferBoundary();
1594 return mRenderer->syncPipelineCacheVk(this, mRenderer->getGlobalOps(), contextGL);
1595 }
1596
setupDraw(const gl::Context * context,gl::PrimitiveMode mode,GLint firstVertexOrInvalid,GLsizei vertexOrIndexCount,GLsizei instanceCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,DirtyBits dirtyBitMask)1597 angle::Result ContextVk::setupDraw(const gl::Context *context,
1598 gl::PrimitiveMode mode,
1599 GLint firstVertexOrInvalid,
1600 GLsizei vertexOrIndexCount,
1601 GLsizei instanceCount,
1602 gl::DrawElementsType indexTypeOrInvalid,
1603 const void *indices,
1604 DirtyBits dirtyBitMask)
1605 {
1606 // Set any dirty bits that depend on draw call parameters or other objects.
1607 if (mode != mCurrentDrawMode)
1608 {
1609 invalidateCurrentGraphicsPipeline();
1610 mCurrentDrawMode = mode;
1611 mGraphicsPipelineDesc->updateTopology(&mGraphicsPipelineTransition, mCurrentDrawMode);
1612 }
1613
1614 // Must be called before the command buffer is started. Can call finish.
1615 VertexArrayVk *vertexArrayVk = getVertexArray();
1616 if (vertexArrayVk->getStreamingVertexAttribsMask().any())
1617 {
1618 // All client attribs & any emulated buffered attribs will be updated
1619 ANGLE_TRY(vertexArrayVk->updateStreamedAttribs(context, firstVertexOrInvalid,
1620 vertexOrIndexCount, instanceCount,
1621 indexTypeOrInvalid, indices));
1622
1623 mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
1624 }
1625
1626 ProgramExecutableVk *executableVk = vk::GetImpl(mState.getProgramExecutable());
1627 if (executableVk->updateAndCheckDirtyUniforms())
1628 {
1629 mGraphicsDirtyBits.set(DIRTY_BIT_UNIFORMS);
1630 }
1631
1632 // Update transform feedback offsets on every draw call when emulating transform feedback. This
1633 // relies on the fact that no geometry/tessellation, indirect or indexed calls are supported in
1634 // ES3.1 (and emulation is not done for ES3.2).
1635 if (getFeatures().emulateTransformFeedback.enabled &&
1636 mState.isTransformFeedbackActiveUnpaused())
1637 {
1638 ASSERT(firstVertexOrInvalid != -1);
1639 mXfbBaseVertex = firstVertexOrInvalid;
1640 mXfbVertexCountPerInstance = vertexOrIndexCount;
1641 invalidateGraphicsDriverUniforms();
1642 }
1643
1644 DirtyBits dirtyBits = mGraphicsDirtyBits & dirtyBitMask;
1645
1646 if (dirtyBits.any())
1647 {
1648 // Flush any relevant dirty bits.
1649 for (DirtyBits::Iterator dirtyBitIter = dirtyBits.begin(); dirtyBitIter != dirtyBits.end();
1650 ++dirtyBitIter)
1651 {
1652 ASSERT(mGraphicsDirtyBitHandlers[*dirtyBitIter]);
1653 ANGLE_TRY(
1654 (this->*mGraphicsDirtyBitHandlers[*dirtyBitIter])(&dirtyBitIter, dirtyBitMask));
1655 }
1656
1657 // Reset the processed dirty bits, except for those that are expected to persist between
1658 // draw calls (such as the framebuffer fetch barrier which needs to be issued again and
1659 // again).
1660 mGraphicsDirtyBits &= (~dirtyBitMask | mPersistentGraphicsDirtyBits);
1661 }
1662
1663 // Render pass must be always available at this point.
1664 ASSERT(hasActiveRenderPass());
1665
1666 ASSERT(mState.getAndResetDirtyUniformBlocks().none());
1667
1668 return angle::Result::Continue;
1669 }
1670
setupIndexedDraw(const gl::Context * context,gl::PrimitiveMode mode,GLsizei indexCount,GLsizei instanceCount,gl::DrawElementsType indexType,const void * indices)1671 angle::Result ContextVk::setupIndexedDraw(const gl::Context *context,
1672 gl::PrimitiveMode mode,
1673 GLsizei indexCount,
1674 GLsizei instanceCount,
1675 gl::DrawElementsType indexType,
1676 const void *indices)
1677 {
1678 ASSERT(mode != gl::PrimitiveMode::LineLoop);
1679
1680 if (indexType != mCurrentDrawElementsType)
1681 {
1682 mCurrentDrawElementsType = indexType;
1683 ANGLE_TRY(onIndexBufferChange(nullptr));
1684 }
1685
1686 VertexArrayVk *vertexArrayVk = getVertexArray();
1687 const gl::Buffer *elementArrayBuffer = vertexArrayVk->getState().getElementArrayBuffer();
1688 if (!elementArrayBuffer)
1689 {
1690 BufferBindingDirty bindingDirty;
1691 ANGLE_TRY(vertexArrayVk->convertIndexBufferCPU(this, indexType, indexCount, indices,
1692 &bindingDirty));
1693 mCurrentIndexBufferOffset = 0;
1694
1695 // We only set dirty bit when the bound buffer actually changed.
1696 if (bindingDirty == BufferBindingDirty::Yes)
1697 {
1698 mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
1699 }
1700 }
1701 else
1702 {
1703 mCurrentIndexBufferOffset = reinterpret_cast<VkDeviceSize>(indices);
1704
1705 if (indices != mLastIndexBufferOffset)
1706 {
1707 mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
1708 mLastIndexBufferOffset = indices;
1709 }
1710
1711 // When you draw with LineLoop mode or GL_UNSIGNED_BYTE type, we may allocate its own
1712 // element buffer and modify mCurrentElementArrayBuffer. When we switch out of that draw
1713 // mode, we must reset mCurrentElementArrayBuffer back to the vertexArray's element buffer.
1714 // Since in either case we set DIRTY_BIT_INDEX_BUFFER dirty bit, we use this bit to re-sync
1715 // mCurrentElementArrayBuffer.
1716 if (mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
1717 {
1718 vertexArrayVk->updateCurrentElementArrayBuffer();
1719 }
1720
1721 if (shouldConvertUint8VkIndexType(indexType) && mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
1722 {
1723 ANGLE_VK_PERF_WARNING(this, GL_DEBUG_SEVERITY_LOW,
1724 "Potential inefficiency emulating uint8 vertex attributes due to "
1725 "lack of hardware support");
1726
1727 BufferVk *bufferVk = vk::GetImpl(elementArrayBuffer);
1728 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
1729
1730 if (bufferHelper.isHostVisible() &&
1731 mRenderer->hasResourceUseFinished(bufferHelper.getResourceUse()))
1732 {
1733 uint8_t *src = nullptr;
1734 ANGLE_TRY(
1735 bufferVk->mapImpl(this, GL_MAP_READ_BIT, reinterpret_cast<void **>(&src)));
1736 // Note: bufferOffset is not added here because mapImpl already adds it.
1737 src += reinterpret_cast<uintptr_t>(indices);
1738 const size_t byteCount = static_cast<size_t>(elementArrayBuffer->getSize()) -
1739 reinterpret_cast<uintptr_t>(indices);
1740 BufferBindingDirty bindingDirty;
1741 ANGLE_TRY(vertexArrayVk->convertIndexBufferCPU(this, indexType, byteCount, src,
1742 &bindingDirty));
1743 ANGLE_TRY(bufferVk->unmapImpl(this));
1744 }
1745 else
1746 {
1747 ANGLE_TRY(vertexArrayVk->convertIndexBufferGPU(this, bufferVk, indices));
1748 }
1749
1750 mCurrentIndexBufferOffset = 0;
1751 }
1752 }
1753
1754 mCurrentIndexBuffer = vertexArrayVk->getCurrentElementArrayBuffer();
1755 return setupDraw(context, mode, 0, indexCount, instanceCount, indexType, indices,
1756 mIndexedDirtyBitsMask);
1757 }
1758
setupIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,DirtyBits dirtyBitMask,vk::BufferHelper * indirectBuffer)1759 angle::Result ContextVk::setupIndirectDraw(const gl::Context *context,
1760 gl::PrimitiveMode mode,
1761 DirtyBits dirtyBitMask,
1762 vk::BufferHelper *indirectBuffer)
1763 {
1764 GLint firstVertex = -1;
1765 GLsizei vertexCount = 0;
1766 GLsizei instanceCount = 1;
1767
1768 // Break the render pass if the indirect buffer was previously used as the output from transform
1769 // feedback.
1770 if (mCurrentTransformFeedbackQueueSerial.valid() &&
1771 indirectBuffer->writtenByCommandBuffer(mCurrentTransformFeedbackQueueSerial))
1772 {
1773 ANGLE_TRY(
1774 flushCommandsAndEndRenderPass(RenderPassClosureReason::XfbWriteThenIndirectDrawBuffer));
1775 }
1776
1777 ANGLE_TRY(setupDraw(context, mode, firstVertex, vertexCount, instanceCount,
1778 gl::DrawElementsType::InvalidEnum, nullptr, dirtyBitMask));
1779
1780 // Process indirect buffer after render pass has started.
1781 mRenderPassCommands->bufferRead(VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
1782 vk::PipelineStage::DrawIndirect, indirectBuffer);
1783
1784 return angle::Result::Continue;
1785 }
1786
setupIndexedIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType indexType,vk::BufferHelper * indirectBuffer)1787 angle::Result ContextVk::setupIndexedIndirectDraw(const gl::Context *context,
1788 gl::PrimitiveMode mode,
1789 gl::DrawElementsType indexType,
1790 vk::BufferHelper *indirectBuffer)
1791 {
1792 ASSERT(mode != gl::PrimitiveMode::LineLoop);
1793
1794 VertexArrayVk *vertexArrayVk = getVertexArray();
1795 mCurrentIndexBuffer = vertexArrayVk->getCurrentElementArrayBuffer();
1796 if (indexType != mCurrentDrawElementsType)
1797 {
1798 mCurrentDrawElementsType = indexType;
1799 ANGLE_TRY(onIndexBufferChange(nullptr));
1800 }
1801
1802 return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBuffer);
1803 }
1804
setupLineLoopIndexedIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType indexType,vk::BufferHelper * srcIndexBuffer,vk::BufferHelper * srcIndirectBuffer,VkDeviceSize indirectBufferOffset,vk::BufferHelper ** indirectBufferOut)1805 angle::Result ContextVk::setupLineLoopIndexedIndirectDraw(const gl::Context *context,
1806 gl::PrimitiveMode mode,
1807 gl::DrawElementsType indexType,
1808 vk::BufferHelper *srcIndexBuffer,
1809 vk::BufferHelper *srcIndirectBuffer,
1810 VkDeviceSize indirectBufferOffset,
1811 vk::BufferHelper **indirectBufferOut)
1812 {
1813 ASSERT(mode == gl::PrimitiveMode::LineLoop);
1814
1815 vk::BufferHelper *dstIndexBuffer = nullptr;
1816 vk::BufferHelper *dstIndirectBuffer = nullptr;
1817
1818 VertexArrayVk *vertexArrayVk = getVertexArray();
1819 ANGLE_TRY(vertexArrayVk->handleLineLoopIndexIndirect(this, indexType, srcIndexBuffer,
1820 srcIndirectBuffer, indirectBufferOffset,
1821 &dstIndexBuffer, &dstIndirectBuffer));
1822
1823 mCurrentIndexBuffer = dstIndexBuffer;
1824 *indirectBufferOut = dstIndirectBuffer;
1825
1826 if (indexType != mCurrentDrawElementsType)
1827 {
1828 mCurrentDrawElementsType = indexType;
1829 ANGLE_TRY(onIndexBufferChange(nullptr));
1830 }
1831
1832 return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, dstIndirectBuffer);
1833 }
1834
setupLineLoopIndirectDraw(const gl::Context * context,gl::PrimitiveMode mode,vk::BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset,vk::BufferHelper ** indirectBufferOut)1835 angle::Result ContextVk::setupLineLoopIndirectDraw(const gl::Context *context,
1836 gl::PrimitiveMode mode,
1837 vk::BufferHelper *indirectBuffer,
1838 VkDeviceSize indirectBufferOffset,
1839 vk::BufferHelper **indirectBufferOut)
1840 {
1841 ASSERT(mode == gl::PrimitiveMode::LineLoop);
1842
1843 vk::BufferHelper *indexBufferHelperOut = nullptr;
1844 vk::BufferHelper *indirectBufferHelperOut = nullptr;
1845
1846 VertexArrayVk *vertexArrayVk = getVertexArray();
1847 ANGLE_TRY(vertexArrayVk->handleLineLoopIndirectDraw(context, indirectBuffer,
1848 indirectBufferOffset, &indexBufferHelperOut,
1849 &indirectBufferHelperOut));
1850
1851 *indirectBufferOut = indirectBufferHelperOut;
1852 mCurrentIndexBuffer = indexBufferHelperOut;
1853
1854 if (gl::DrawElementsType::UnsignedInt != mCurrentDrawElementsType)
1855 {
1856 mCurrentDrawElementsType = gl::DrawElementsType::UnsignedInt;
1857 ANGLE_TRY(onIndexBufferChange(nullptr));
1858 }
1859
1860 return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBufferHelperOut);
1861 }
1862
setupLineLoopDraw(const gl::Context * context,gl::PrimitiveMode mode,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,uint32_t * numIndicesOut)1863 angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
1864 gl::PrimitiveMode mode,
1865 GLint firstVertex,
1866 GLsizei vertexOrIndexCount,
1867 gl::DrawElementsType indexTypeOrInvalid,
1868 const void *indices,
1869 uint32_t *numIndicesOut)
1870 {
1871 mCurrentIndexBufferOffset = 0;
1872 vk::BufferHelper *dstIndexBuffer = mCurrentIndexBuffer;
1873
1874 VertexArrayVk *vertexArrayVk = getVertexArray();
1875 ANGLE_TRY(vertexArrayVk->handleLineLoop(this, firstVertex, vertexOrIndexCount,
1876 indexTypeOrInvalid, indices, &dstIndexBuffer,
1877 numIndicesOut));
1878
1879 mCurrentIndexBuffer = dstIndexBuffer;
1880 ANGLE_TRY(onIndexBufferChange(nullptr));
1881 mCurrentDrawElementsType = indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum
1882 ? indexTypeOrInvalid
1883 : gl::DrawElementsType::UnsignedInt;
1884 return setupDraw(context, mode, firstVertex, vertexOrIndexCount, 1, indexTypeOrInvalid, indices,
1885 mIndexedDirtyBitsMask);
1886 }
1887
setupDispatch(const gl::Context * context)1888 angle::Result ContextVk::setupDispatch(const gl::Context *context)
1889 {
1890 // TODO: We don't currently check if this flush is necessary. It serves to make sure the
1891 // barriers issued during dirty bit handling aren't reordered too early.
1892 // http://anglebug.com/382090958
1893 ANGLE_TRY(flushOutsideRenderPassCommands());
1894
1895 ProgramExecutableVk *executableVk = vk::GetImpl(mState.getProgramExecutable());
1896 if (executableVk->updateAndCheckDirtyUniforms())
1897 {
1898 mComputeDirtyBits.set(DIRTY_BIT_UNIFORMS);
1899 }
1900
1901 DirtyBits dirtyBits = mComputeDirtyBits;
1902
1903 // Flush any relevant dirty bits.
1904 for (DirtyBits::Iterator dirtyBitIter = dirtyBits.begin(); dirtyBitIter != dirtyBits.end();
1905 ++dirtyBitIter)
1906 {
1907 ASSERT(mComputeDirtyBitHandlers[*dirtyBitIter]);
1908 ANGLE_TRY((this->*mComputeDirtyBitHandlers[*dirtyBitIter])(&dirtyBitIter));
1909 }
1910
1911 mComputeDirtyBits.reset();
1912
1913 ASSERT(mState.getAndResetDirtyUniformBlocks().none());
1914
1915 return angle::Result::Continue;
1916 }
1917
handleDirtyGraphicsMemoryBarrier(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)1918 angle::Result ContextVk::handleDirtyGraphicsMemoryBarrier(DirtyBits::Iterator *dirtyBitsIterator,
1919 DirtyBits dirtyBitMask)
1920 {
1921 return handleDirtyMemoryBarrierImpl(dirtyBitsIterator, dirtyBitMask);
1922 }
1923
handleDirtyComputeMemoryBarrier(DirtyBits::Iterator * dirtyBitsIterator)1924 angle::Result ContextVk::handleDirtyComputeMemoryBarrier(DirtyBits::Iterator *dirtyBitsIterator)
1925 {
1926 return handleDirtyMemoryBarrierImpl(nullptr, {});
1927 }
1928
renderPassUsesStorageResources() const1929 bool ContextVk::renderPassUsesStorageResources() const
1930 {
1931 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
1932 ASSERT(executable);
1933
1934 if (!mRenderPassCommands->started())
1935 {
1936 return false;
1937 }
1938
1939 // Storage images:
1940 for (size_t imageUnitIndex : executable->getActiveImagesMask())
1941 {
1942 const gl::Texture *texture = mState.getImageUnit(imageUnitIndex).texture.get();
1943 if (texture == nullptr)
1944 {
1945 continue;
1946 }
1947
1948 TextureVk *textureVk = vk::GetImpl(texture);
1949
1950 if (texture->getType() == gl::TextureType::Buffer)
1951 {
1952 vk::BufferHelper &buffer = vk::GetImpl(textureVk->getBuffer().get())->getBuffer();
1953 if (mRenderPassCommands->usesBuffer(buffer))
1954 {
1955 return true;
1956 }
1957 }
1958 else
1959 {
1960 vk::ImageHelper &image = textureVk->getImage();
1961 // Images only need to close the render pass if they need a layout transition. Outside
1962 // render pass command buffer doesn't need closing as the layout transition barriers are
1963 // recorded in sequence with the rest of the commands.
1964 if (mRenderPassCommands->usesImage(image))
1965 {
1966 return true;
1967 }
1968 }
1969 }
1970
1971 // Storage buffers:
1972 const std::vector<gl::InterfaceBlock> &blocks = executable->getShaderStorageBlocks();
1973 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
1974 {
1975 const uint32_t binding = executable->getShaderStorageBlockBinding(bufferIndex);
1976 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1977 mState.getIndexedShaderStorageBuffer(binding);
1978
1979 if (bufferBinding.get() == nullptr)
1980 {
1981 continue;
1982 }
1983
1984 vk::BufferHelper &buffer = vk::GetImpl(bufferBinding.get())->getBuffer();
1985 if (mRenderPassCommands->usesBuffer(buffer))
1986 {
1987 return true;
1988 }
1989 }
1990
1991 // Atomic counters:
1992 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers =
1993 executable->getAtomicCounterBuffers();
1994 for (uint32_t bufferIndex = 0; bufferIndex < atomicCounterBuffers.size(); ++bufferIndex)
1995 {
1996 const uint32_t binding = executable->getAtomicCounterBufferBinding(bufferIndex);
1997 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1998 mState.getIndexedAtomicCounterBuffer(binding);
1999
2000 if (bufferBinding.get() == nullptr)
2001 {
2002 continue;
2003 }
2004
2005 vk::BufferHelper &buffer = vk::GetImpl(bufferBinding.get())->getBuffer();
2006 if (mRenderPassCommands->usesBuffer(buffer))
2007 {
2008 return true;
2009 }
2010 }
2011
2012 return false;
2013 }
2014
handleDirtyMemoryBarrierImpl(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2015 angle::Result ContextVk::handleDirtyMemoryBarrierImpl(DirtyBits::Iterator *dirtyBitsIterator,
2016 DirtyBits dirtyBitMask)
2017 {
2018 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2019 ASSERT(executable);
2020
2021 const bool hasImages = executable->hasImages();
2022 const bool hasStorageBuffers = executable->hasStorageBuffers();
2023 const bool hasAtomicCounters = executable->hasAtomicCounterBuffers();
2024
2025 if (!hasImages && !hasStorageBuffers && !hasAtomicCounters)
2026 {
2027 return angle::Result::Continue;
2028 }
2029
2030 // Break the render pass if necessary. This is only needed for write-after-read situations, and
2031 // is done by checking whether current storage buffers and images are used in the render pass.
2032 if (renderPassUsesStorageResources())
2033 {
2034 // Either set later bits (if called during handling of graphics dirty bits), or set the
2035 // dirty bits directly (if called during handling of compute dirty bits).
2036 if (dirtyBitsIterator)
2037 {
2038 return flushDirtyGraphicsRenderPass(
2039 dirtyBitsIterator, dirtyBitMask,
2040 RenderPassClosureReason::GLMemoryBarrierThenStorageResource);
2041 }
2042 else
2043 {
2044 return flushCommandsAndEndRenderPass(
2045 RenderPassClosureReason::GLMemoryBarrierThenStorageResource);
2046 }
2047 }
2048
2049 // Flushing outside render pass commands is cheap. If a memory barrier has been issued in its
2050 // life time, just flush it instead of wasting time trying to figure out if it's necessary.
2051 if (mOutsideRenderPassCommands->hasGLMemoryBarrierIssued())
2052 {
2053 ANGLE_TRY(flushOutsideRenderPassCommands());
2054 }
2055
2056 return angle::Result::Continue;
2057 }
2058
handleDirtyGraphicsEventLog(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2059 angle::Result ContextVk::handleDirtyGraphicsEventLog(DirtyBits::Iterator *dirtyBitsIterator,
2060 DirtyBits dirtyBitMask)
2061 {
2062 return handleDirtyEventLogImpl(mRenderPassCommandBuffer);
2063 }
2064
handleDirtyComputeEventLog(DirtyBits::Iterator * dirtyBitsIterator)2065 angle::Result ContextVk::handleDirtyComputeEventLog(DirtyBits::Iterator *dirtyBitsIterator)
2066 {
2067 return handleDirtyEventLogImpl(&mOutsideRenderPassCommands->getCommandBuffer());
2068 }
2069
2070 template <typename CommandBufferT>
handleDirtyEventLogImpl(CommandBufferT * commandBuffer)2071 angle::Result ContextVk::handleDirtyEventLogImpl(CommandBufferT *commandBuffer)
2072 {
2073 // This method is called when a draw or dispatch command is being processed. It's purpose is
2074 // to call the vkCmd*DebugUtilsLabelEXT functions in order to communicate to debuggers
2075 // (e.g. AGI) the OpenGL ES commands that the application uses.
2076
2077 // Exit early if no OpenGL ES commands have been logged, or if no command buffer (for a no-op
2078 // draw), or if calling the vkCmd*DebugUtilsLabelEXT functions is not enabled.
2079 if (mEventLog.empty() || commandBuffer == nullptr || !mRenderer->angleDebuggerMode())
2080 {
2081 return angle::Result::Continue;
2082 }
2083
2084 // Insert OpenGL ES commands into debug label. We create a 3-level cascade here for
2085 // OpenGL-ES-first debugging in AGI. Here's the general outline of commands:
2086 // -glDrawCommand
2087 // --vkCmdBeginDebugUtilsLabelEXT() #1 for "glDrawCommand"
2088 // --OpenGL ES Commands
2089 // ---vkCmdBeginDebugUtilsLabelEXT() #2 for "OpenGL ES Commands"
2090 // ---Individual OpenGL ES Commands leading up to glDrawCommand
2091 // ----vkCmdBeginDebugUtilsLabelEXT() #3 for each individual OpenGL ES Command
2092 // ----vkCmdEndDebugUtilsLabelEXT() #3 for each individual OpenGL ES Command
2093 // ----...More Individual OGL Commands...
2094 // ----Final Individual OGL command will be the same glDrawCommand shown in #1 above
2095 // ---vkCmdEndDebugUtilsLabelEXT() #2 for "OpenGL ES Commands"
2096 // --VK SetupDraw & Draw-related commands will be embedded here under glDraw #1
2097 // --vkCmdEndDebugUtilsLabelEXT() #1 is called after each vkDraw* or vkDispatch* call
2098
2099 // AGI desires no parameters on the top-level of the hierarchy.
2100 std::string topLevelCommand = mEventLog.back();
2101 size_t startOfParameters = topLevelCommand.find("(");
2102 if (startOfParameters != std::string::npos)
2103 {
2104 topLevelCommand = topLevelCommand.substr(0, startOfParameters);
2105 }
2106 VkDebugUtilsLabelEXT label = {VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
2107 nullptr,
2108 topLevelCommand.c_str(),
2109 {0.0f, 0.0f, 0.0f, 0.0f}};
2110 // This is #1 from comment above
2111 commandBuffer->beginDebugUtilsLabelEXT(label);
2112 std::string oglCmds = "OpenGL ES Commands";
2113 label.pLabelName = oglCmds.c_str();
2114 // This is #2 from comment above
2115 commandBuffer->beginDebugUtilsLabelEXT(label);
2116 for (uint32_t i = 0; i < mEventLog.size(); ++i)
2117 {
2118 label.pLabelName = mEventLog[i].c_str();
2119 // NOTE: We have to use a begin/end pair here because AGI does not promote the
2120 // pLabelName from an insertDebugUtilsLabelEXT() call to the Commands panel.
2121 // Internal bug b/169243237 is tracking this and once the insert* call shows the
2122 // pLabelName similar to begin* call, we can switch these to insert* calls instead.
2123 // This is #3 from comment above.
2124 commandBuffer->beginDebugUtilsLabelEXT(label);
2125 commandBuffer->endDebugUtilsLabelEXT();
2126 }
2127 commandBuffer->endDebugUtilsLabelEXT();
2128 // The final end* call for #1 above is made in the ContextVk::draw* or
2129 // ContextVk::dispatch* function calls.
2130
2131 mEventLog.clear();
2132 return angle::Result::Continue;
2133 }
2134
handleDirtyGraphicsDefaultAttribs(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2135 angle::Result ContextVk::handleDirtyGraphicsDefaultAttribs(DirtyBits::Iterator *dirtyBitsIterator,
2136 DirtyBits dirtyBitMask)
2137 {
2138 ASSERT(mDirtyDefaultAttribsMask.any());
2139
2140 gl::AttributesMask attribsMask =
2141 mDirtyDefaultAttribsMask & mState.getProgramExecutable()->getAttributesMask();
2142 VertexArrayVk *vertexArrayVk = getVertexArray();
2143 for (size_t attribIndex : attribsMask)
2144 {
2145 ANGLE_TRY(vertexArrayVk->updateDefaultAttrib(this, attribIndex));
2146 }
2147
2148 mDirtyDefaultAttribsMask.reset();
2149 return angle::Result::Continue;
2150 }
2151
createGraphicsPipeline()2152 angle::Result ContextVk::createGraphicsPipeline()
2153 {
2154 ASSERT(mState.getProgramExecutable() != nullptr);
2155 ProgramExecutableVk *executableVk = vk::GetImpl(mState.getProgramExecutable());
2156 ASSERT(executableVk);
2157
2158 // Wait for any warmup task if necessary
2159 executableVk->waitForGraphicsPostLinkTasks(this, *mGraphicsPipelineDesc);
2160
2161 vk::PipelineCacheAccess pipelineCache;
2162 ANGLE_TRY(mRenderer->getPipelineCache(this, &pipelineCache));
2163
2164 vk::PipelineHelper *oldGraphicsPipeline = mCurrentGraphicsPipeline;
2165
2166 // Attempt to use an existing pipeline.
2167 const vk::GraphicsPipelineDesc *descPtr = nullptr;
2168 ANGLE_TRY(executableVk->getGraphicsPipeline(this, vk::GraphicsPipelineSubset::Complete,
2169 *mGraphicsPipelineDesc, &descPtr,
2170 &mCurrentGraphicsPipeline));
2171
2172 // If no such pipeline exists:
2173 //
2174 // - If VK_EXT_graphics_pipeline_library is not supported, create a new monolithic pipeline
2175 // - If VK_EXT_graphics_pipeline_library is supported:
2176 // * Create the Shaders subset of the pipeline through the program executable
2177 // * Create the VertexInput and FragmentOutput subsets
2178 // * Link them together through the program executable
2179 if (mCurrentGraphicsPipeline == nullptr)
2180 {
2181 // Not found in cache
2182 ASSERT(descPtr == nullptr);
2183 if (!getFeatures().supportsGraphicsPipelineLibrary.enabled)
2184 {
2185 ANGLE_TRY(executableVk->createGraphicsPipeline(
2186 this, vk::GraphicsPipelineSubset::Complete, &pipelineCache, PipelineSource::Draw,
2187 *mGraphicsPipelineDesc, &descPtr, &mCurrentGraphicsPipeline));
2188 }
2189 else
2190 {
2191 const vk::GraphicsPipelineTransitionBits kShadersTransitionBitsMask =
2192 vk::GetGraphicsPipelineTransitionBitsMask(vk::GraphicsPipelineSubset::Shaders);
2193 const vk::GraphicsPipelineTransitionBits kVertexInputTransitionBitsMask =
2194 vk::GetGraphicsPipelineTransitionBitsMask(vk::GraphicsPipelineSubset::VertexInput);
2195 const vk::GraphicsPipelineTransitionBits kFragmentOutputTransitionBitsMask =
2196 vk::GetGraphicsPipelineTransitionBitsMask(
2197 vk::GraphicsPipelineSubset::FragmentOutput);
2198
2199 // Recreate the shaders subset if necessary
2200 const vk::GraphicsPipelineTransitionBits shadersTransitionBits =
2201 mGraphicsPipelineLibraryTransition & kShadersTransitionBitsMask;
2202 if (mCurrentGraphicsPipelineShaders == nullptr || shadersTransitionBits.any())
2203 {
2204 bool shouldRecreatePipeline = true;
2205 if (mCurrentGraphicsPipelineShaders != nullptr)
2206 {
2207 ASSERT(mCurrentGraphicsPipelineShaders->valid());
2208 shouldRecreatePipeline = !mCurrentGraphicsPipelineShaders->findTransition(
2209 shadersTransitionBits, *mGraphicsPipelineDesc,
2210 &mCurrentGraphicsPipelineShaders);
2211 }
2212
2213 if (shouldRecreatePipeline)
2214 {
2215 vk::PipelineHelper *oldGraphicsPipelineShaders =
2216 mCurrentGraphicsPipelineShaders;
2217
2218 const vk::GraphicsPipelineDesc *shadersDescPtr = nullptr;
2219 ANGLE_TRY(executableVk->getGraphicsPipeline(
2220 this, vk::GraphicsPipelineSubset::Shaders, *mGraphicsPipelineDesc,
2221 &shadersDescPtr, &mCurrentGraphicsPipelineShaders));
2222 if (shadersDescPtr == nullptr)
2223 {
2224 ANGLE_TRY(executableVk->createGraphicsPipeline(
2225 this, vk::GraphicsPipelineSubset::Shaders, &pipelineCache,
2226 PipelineSource::Draw, *mGraphicsPipelineDesc, &shadersDescPtr,
2227 &mCurrentGraphicsPipelineShaders));
2228 }
2229 if (oldGraphicsPipelineShaders)
2230 {
2231 oldGraphicsPipelineShaders->addTransition(
2232 shadersTransitionBits, shadersDescPtr, mCurrentGraphicsPipelineShaders);
2233 }
2234 }
2235 }
2236
2237 // If blobs are reused between the pipeline libraries and the monolithic pipelines (so
2238 // |mergeProgramPipelineCachesToGlobalCache| would be enabled because merging the
2239 // pipelines would be beneficial), directly use the global cache for the vertex input
2240 // and fragment output pipelines. This _may_ cause stalls as the worker thread that
2241 // creates pipelines is also holding the same lock.
2242 //
2243 // On the other hand, if there is not going to be any reuse of blobs, use a private
2244 // pipeline cache to avoid the aforementioned potential stall.
2245 vk::PipelineCacheAccess interfacePipelineCacheStorage;
2246 vk::PipelineCacheAccess *interfacePipelineCache = &pipelineCache;
2247 if (!getFeatures().mergeProgramPipelineCachesToGlobalCache.enabled)
2248 {
2249 ANGLE_TRY(ensureInterfacePipelineCache());
2250 interfacePipelineCacheStorage.init(&mInterfacePipelinesCache, nullptr);
2251 interfacePipelineCache = &interfacePipelineCacheStorage;
2252 }
2253
2254 // Recreate the vertex input subset if necessary
2255 ANGLE_TRY(CreateGraphicsPipelineSubset(
2256 this, *mGraphicsPipelineDesc,
2257 mGraphicsPipelineLibraryTransition & kVertexInputTransitionBitsMask,
2258 GraphicsPipelineSubsetRenderPass::Unused,
2259 mShareGroupVk->getVertexInputGraphicsPipelineCache(), interfacePipelineCache,
2260 &mCurrentGraphicsPipelineVertexInput));
2261
2262 // Recreate the fragment output subset if necessary
2263 ANGLE_TRY(CreateGraphicsPipelineSubset(
2264 this, *mGraphicsPipelineDesc,
2265 mGraphicsPipelineLibraryTransition & kFragmentOutputTransitionBitsMask,
2266 GraphicsPipelineSubsetRenderPass::Required,
2267 mShareGroupVk->getFragmentOutputGraphicsPipelineCache(), interfacePipelineCache,
2268 &mCurrentGraphicsPipelineFragmentOutput));
2269
2270 // Link the three subsets into one pipeline.
2271 ANGLE_TRY(executableVk->linkGraphicsPipelineLibraries(
2272 this, &pipelineCache, *mGraphicsPipelineDesc, mCurrentGraphicsPipelineVertexInput,
2273 mCurrentGraphicsPipelineShaders, mCurrentGraphicsPipelineFragmentOutput, &descPtr,
2274 &mCurrentGraphicsPipeline));
2275
2276 // Reset the transition bits for pipeline libraries, they are only made to be up-to-date
2277 // here.
2278 mGraphicsPipelineLibraryTransition.reset();
2279 }
2280 }
2281
2282 // Maintain the transition cache
2283 if (oldGraphicsPipeline)
2284 {
2285 oldGraphicsPipeline->addTransition(mGraphicsPipelineTransition, descPtr,
2286 mCurrentGraphicsPipeline);
2287 }
2288
2289 return angle::Result::Continue;
2290 }
2291
handleDirtyGraphicsPipelineDesc(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2292 angle::Result ContextVk::handleDirtyGraphicsPipelineDesc(DirtyBits::Iterator *dirtyBitsIterator,
2293 DirtyBits dirtyBitMask)
2294 {
2295 const VkPipeline previousPipeline = mCurrentGraphicsPipeline
2296 ? mCurrentGraphicsPipeline->getPipeline().getHandle()
2297 : VK_NULL_HANDLE;
2298
2299 // Accumulate transition bits for the sake of pipeline libraries. If a cache is hit in this
2300 // path, |mGraphicsPipelineTransition| is reset while the partial pipelines are left stale. A
2301 // future partial library recreation would need to know the bits that have changed since.
2302 mGraphicsPipelineLibraryTransition |= mGraphicsPipelineTransition;
2303
2304 // Recreate the pipeline if necessary.
2305 bool shouldRecreatePipeline =
2306 mCurrentGraphicsPipeline == nullptr || mGraphicsPipelineTransition.any();
2307
2308 // If one can be found in the transition cache, recover it.
2309 if (mCurrentGraphicsPipeline != nullptr && mGraphicsPipelineTransition.any())
2310 {
2311 ASSERT(mCurrentGraphicsPipeline->valid());
2312 shouldRecreatePipeline = !mCurrentGraphicsPipeline->findTransition(
2313 mGraphicsPipelineTransition, *mGraphicsPipelineDesc, &mCurrentGraphicsPipeline);
2314 }
2315
2316 // Otherwise either retrieve the pipeline from the cache, or create a new one.
2317 if (shouldRecreatePipeline)
2318 {
2319 ANGLE_TRY(createGraphicsPipeline());
2320 }
2321
2322 mGraphicsPipelineTransition.reset();
2323
2324 // Update the queue serial for the pipeline object.
2325 ASSERT(mCurrentGraphicsPipeline && mCurrentGraphicsPipeline->valid());
2326
2327 const VkPipeline newPipeline = mCurrentGraphicsPipeline->getPipeline().getHandle();
2328
2329 // If there's no change in pipeline, avoid rebinding it later. If the rebind is due to a new
2330 // command buffer or UtilsVk, it will happen anyway with DIRTY_BIT_PIPELINE_BINDING.
2331 if (newPipeline == previousPipeline)
2332 {
2333 return angle::Result::Continue;
2334 }
2335
2336 // VK_EXT_transform_feedback disallows binding pipelines while transform feedback is active.
2337 // If a new pipeline needs to be bound, the render pass should necessarily be broken (which
2338 // implicitly pauses transform feedback), as resuming requires a barrier on the transform
2339 // feedback counter buffer.
2340 if (mRenderPassCommands->started())
2341 {
2342 mCurrentGraphicsPipeline->retainInRenderPass(mRenderPassCommands);
2343
2344 if (mRenderPassCommands->isTransformFeedbackActiveUnpaused())
2345 {
2346 ANGLE_TRY(
2347 flushDirtyGraphicsRenderPass(dirtyBitsIterator, dirtyBitMask,
2348 RenderPassClosureReason::PipelineBindWhileXfbActive));
2349
2350 dirtyBitsIterator->setLaterBit(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
2351 }
2352 }
2353
2354 // The pipeline needs to rebind because it's changed.
2355 dirtyBitsIterator->setLaterBit(DIRTY_BIT_PIPELINE_BINDING);
2356
2357 return angle::Result::Continue;
2358 }
2359
updateRenderPassDepthFeedbackLoopMode(UpdateDepthFeedbackLoopReason depthReason,UpdateDepthFeedbackLoopReason stencilReason)2360 angle::Result ContextVk::updateRenderPassDepthFeedbackLoopMode(
2361 UpdateDepthFeedbackLoopReason depthReason,
2362 UpdateDepthFeedbackLoopReason stencilReason)
2363 {
2364 return switchOutReadOnlyDepthStencilMode(nullptr, {}, depthReason, stencilReason);
2365 }
2366
switchOutReadOnlyDepthStencilMode(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask,UpdateDepthFeedbackLoopReason depthReason,UpdateDepthFeedbackLoopReason stencilReason)2367 angle::Result ContextVk::switchOutReadOnlyDepthStencilMode(
2368 DirtyBits::Iterator *dirtyBitsIterator,
2369 DirtyBits dirtyBitMask,
2370 UpdateDepthFeedbackLoopReason depthReason,
2371 UpdateDepthFeedbackLoopReason stencilReason)
2372 {
2373 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
2374 if (!hasActiveRenderPass() || drawFramebufferVk->getDepthStencilRenderTarget() == nullptr)
2375 {
2376 return angle::Result::Continue;
2377 }
2378
2379 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2380 const gl::DepthStencilState &dsState = mState.getDepthStencilState();
2381 vk::ResourceAccess depthAccess = GetDepthAccess(dsState, executable, depthReason);
2382 vk::ResourceAccess stencilAccess = GetStencilAccess(
2383 dsState, mState.getDrawFramebuffer()->getStencilBitCount(), executable, stencilReason);
2384
2385 if ((HasResourceWriteAccess(depthAccess) &&
2386 mDepthStencilAttachmentFlags[vk::RenderPassUsage::DepthReadOnlyAttachment]) ||
2387 (HasResourceWriteAccess(stencilAccess) &&
2388 mDepthStencilAttachmentFlags[vk::RenderPassUsage::StencilReadOnlyAttachment]))
2389 {
2390 // We should not in the actual feedback mode
2391 ASSERT((mDepthStencilAttachmentFlags & vk::kDepthStencilFeedbackModeBits).none());
2392
2393 // If we are switching out of read only mode and we are in feedback loop, we must end
2394 // render pass here. Otherwise, updating it to writeable layout will produce a writable
2395 // feedback loop that is illegal in vulkan and will trigger validation errors that depth
2396 // texture is using the writable layout.
2397 if (dirtyBitsIterator)
2398 {
2399 ANGLE_TRY(flushDirtyGraphicsRenderPass(
2400 dirtyBitsIterator, dirtyBitMask,
2401 RenderPassClosureReason::DepthStencilWriteAfterFeedbackLoop));
2402 }
2403 else
2404 {
2405 ANGLE_TRY(flushCommandsAndEndRenderPass(
2406 RenderPassClosureReason::DepthStencilWriteAfterFeedbackLoop));
2407 }
2408 // Clear read-only depth/stencil feedback mode.
2409 mDepthStencilAttachmentFlags &= ~vk::kDepthStencilReadOnlyBits;
2410 }
2411
2412 return angle::Result::Continue;
2413 }
2414
handleDirtyGraphicsReadOnlyDepthFeedbackLoopMode(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2415 angle::Result ContextVk::handleDirtyGraphicsReadOnlyDepthFeedbackLoopMode(
2416 DirtyBits::Iterator *dirtyBitsIterator,
2417 DirtyBits dirtyBitMask)
2418 {
2419 return switchOutReadOnlyDepthStencilMode(dirtyBitsIterator, dirtyBitMask,
2420 UpdateDepthFeedbackLoopReason::Draw,
2421 UpdateDepthFeedbackLoopReason::Draw);
2422 }
2423
handleDirtyAnySamplePassedQueryEnd(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2424 angle::Result ContextVk::handleDirtyAnySamplePassedQueryEnd(DirtyBits::Iterator *dirtyBitsIterator,
2425 DirtyBits dirtyBitMask)
2426 {
2427 if (mRenderPassCommands->started())
2428 {
2429 // When we switch from query enabled draw to query disabled draw, we do immediate flush to
2430 // ensure the query result will be ready early so that application thread calling
2431 // getQueryResult gets unblocked sooner.
2432 dirtyBitsIterator->setLaterBit(DIRTY_BIT_RENDER_PASS);
2433
2434 // Don't let next render pass end up reactivate and reuse the current render pass, which
2435 // defeats the purpose of it.
2436 mAllowRenderPassToReactivate = false;
2437 mHasDeferredFlush = true;
2438 }
2439 return angle::Result::Continue;
2440 }
2441
handleDirtyGraphicsRenderPass(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2442 angle::Result ContextVk::handleDirtyGraphicsRenderPass(DirtyBits::Iterator *dirtyBitsIterator,
2443 DirtyBits dirtyBitMask)
2444 {
2445 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
2446
2447 gl::Rectangle renderArea = drawFramebufferVk->getRenderArea(this);
2448 // Check to see if we can reactivate the current renderPass, if all arguments that we use to
2449 // start the render pass is the same. We don't need to check clear values since mid render pass
2450 // clear are handled differently.
2451 bool reactivateStartedRenderPass =
2452 hasStartedRenderPassWithQueueSerial(drawFramebufferVk->getLastRenderPassQueueSerial()) &&
2453 mAllowRenderPassToReactivate && renderArea == mRenderPassCommands->getRenderArea();
2454 if (reactivateStartedRenderPass)
2455 {
2456 INFO() << "Reactivate already started render pass on draw.";
2457 mRenderPassCommandBuffer = &mRenderPassCommands->getCommandBuffer();
2458 ASSERT(!drawFramebufferVk->hasDeferredClears());
2459 ASSERT(hasActiveRenderPass());
2460
2461 vk::RenderPassDesc framebufferRenderPassDesc = drawFramebufferVk->getRenderPassDesc();
2462 if (getFeatures().preferDynamicRendering.enabled)
2463 {
2464 // With dynamic rendering, drawFramebufferVk's render pass desc does not track
2465 // framebuffer fetch mode. For the purposes of the following ASSERT, assume they are
2466 // the same.
2467 framebufferRenderPassDesc.setFramebufferFetchMode(
2468 mRenderPassCommands->getRenderPassDesc().framebufferFetchMode());
2469 }
2470 ASSERT(framebufferRenderPassDesc == mRenderPassCommands->getRenderPassDesc());
2471
2472 return angle::Result::Continue;
2473 }
2474
2475 // If the render pass needs to be recreated, close it using the special mid-dirty-bit-handling
2476 // function, so later dirty bits can be set.
2477 if (mRenderPassCommands->started())
2478 {
2479 ANGLE_TRY(flushDirtyGraphicsRenderPass(dirtyBitsIterator,
2480 dirtyBitMask & ~DirtyBits{DIRTY_BIT_RENDER_PASS},
2481 RenderPassClosureReason::AlreadySpecifiedElsewhere));
2482 }
2483
2484 bool renderPassDescChanged = false;
2485
2486 ANGLE_TRY(startRenderPass(renderArea, nullptr, &renderPassDescChanged));
2487
2488 // The render pass desc can change when starting the render pass, for example due to
2489 // multisampled-render-to-texture needs based on loadOps. In that case, recreate the graphics
2490 // pipeline.
2491 if (renderPassDescChanged)
2492 {
2493 ANGLE_TRY(handleDirtyGraphicsPipelineDesc(dirtyBitsIterator, dirtyBitMask));
2494 }
2495
2496 // For dynamic rendering, the FramebufferVk's render pass desc does not track whether
2497 // framebuffer fetch is in use. In that case, ContextVk updates the command buffer's (and
2498 // graphics pipeline's) render pass desc only:
2499 //
2500 // - When the render pass starts
2501 // - When the program binding changes (see |invalidateProgramExecutableHelper|)
2502 if (getFeatures().preferDynamicRendering.enabled)
2503 {
2504 vk::FramebufferFetchMode framebufferFetchMode =
2505 vk::GetProgramFramebufferFetchMode(mState.getProgramExecutable());
2506 if (framebufferFetchMode != vk::FramebufferFetchMode::None)
2507 {
2508 // Note: this function sets a dirty bit through onColorAccessChange() not through
2509 // |dirtyBitsIterator|, but that dirty bit is always set on new render passes, so it
2510 // won't be missed.
2511 onFramebufferFetchUse(framebufferFetchMode);
2512 }
2513 else
2514 {
2515 // Reset framebuffer fetch mode. Note that |onFramebufferFetchUse| _accumulates_
2516 // framebuffer fetch mode.
2517 mRenderPassCommands->setFramebufferFetchMode(vk::FramebufferFetchMode::None);
2518 }
2519 }
2520
2521 return angle::Result::Continue;
2522 }
2523
handleDirtyGraphicsColorAccess(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2524 angle::Result ContextVk::handleDirtyGraphicsColorAccess(DirtyBits::Iterator *dirtyBitsIterator,
2525 DirtyBits dirtyBitMask)
2526 {
2527 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
2528 const gl::FramebufferState &framebufferState = drawFramebufferVk->getState();
2529
2530 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2531 ASSERT(executable);
2532
2533 // Update color attachment accesses
2534 vk::PackedAttachmentIndex colorIndexVk(0);
2535 for (size_t colorIndexGL : framebufferState.getColorAttachmentsMask())
2536 {
2537 if (framebufferState.getEnabledDrawBuffers().test(colorIndexGL))
2538 {
2539 vk::ResourceAccess colorAccess = GetColorAccess(
2540 mState, framebufferState, drawFramebufferVk->getEmulatedAlphaAttachmentMask(),
2541 executable, colorIndexGL);
2542 mRenderPassCommands->onColorAccess(colorIndexVk, colorAccess);
2543 }
2544 ++colorIndexVk;
2545 }
2546
2547 return angle::Result::Continue;
2548 }
2549
handleDirtyGraphicsDepthStencilAccess(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2550 angle::Result ContextVk::handleDirtyGraphicsDepthStencilAccess(
2551 DirtyBits::Iterator *dirtyBitsIterator,
2552 DirtyBits dirtyBitMask)
2553 {
2554 const FramebufferVk &drawFramebufferVk = *getDrawFramebuffer();
2555 if (drawFramebufferVk.getDepthStencilRenderTarget() == nullptr)
2556 {
2557 return angle::Result::Continue;
2558 }
2559
2560 // Update depth/stencil attachment accesses
2561 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2562 const gl::DepthStencilState &dsState = mState.getDepthStencilState();
2563 vk::ResourceAccess depthAccess =
2564 GetDepthAccess(dsState, executable, UpdateDepthFeedbackLoopReason::Draw);
2565 vk::ResourceAccess stencilAccess =
2566 GetStencilAccess(dsState, mState.getDrawFramebuffer()->getStencilBitCount(), executable,
2567 UpdateDepthFeedbackLoopReason::Draw);
2568 mRenderPassCommands->onDepthAccess(depthAccess);
2569 mRenderPassCommands->onStencilAccess(stencilAccess);
2570
2571 mRenderPassCommands->updateDepthReadOnlyMode(mDepthStencilAttachmentFlags);
2572 mRenderPassCommands->updateStencilReadOnlyMode(mDepthStencilAttachmentFlags);
2573
2574 return angle::Result::Continue;
2575 }
2576
handleDirtyGraphicsPipelineBinding(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2577 angle::Result ContextVk::handleDirtyGraphicsPipelineBinding(DirtyBits::Iterator *dirtyBitsIterator,
2578 DirtyBits dirtyBitMask)
2579 {
2580 ASSERT(mCurrentGraphicsPipeline);
2581
2582 const vk::Pipeline *pipeline = nullptr;
2583 ANGLE_TRY(mCurrentGraphicsPipeline->getPreferredPipeline(this, &pipeline));
2584
2585 mRenderPassCommandBuffer->bindGraphicsPipeline(*pipeline);
2586
2587 return angle::Result::Continue;
2588 }
2589
handleDirtyComputePipelineDesc(DirtyBits::Iterator * dirtyBitsIterator)2590 angle::Result ContextVk::handleDirtyComputePipelineDesc(DirtyBits::Iterator *dirtyBitsIterator)
2591 {
2592 if (mCurrentComputePipeline == nullptr)
2593 {
2594 vk::PipelineCacheAccess pipelineCache;
2595 ANGLE_TRY(mRenderer->getPipelineCache(this, &pipelineCache));
2596
2597 ProgramExecutableVk *executableVk = vk::GetImpl(mState.getProgramExecutable());
2598 ASSERT(executableVk);
2599
2600 executableVk->waitForComputePostLinkTasks(this);
2601 ANGLE_TRY(executableVk->getOrCreateComputePipeline(
2602 this, &pipelineCache, PipelineSource::Draw, pipelineRobustness(),
2603 pipelineProtectedAccess(), &mCurrentComputePipeline));
2604 }
2605
2606 ASSERT(mComputeDirtyBits.test(DIRTY_BIT_PIPELINE_BINDING));
2607
2608 return angle::Result::Continue;
2609 }
2610
handleDirtyComputePipelineBinding(DirtyBits::Iterator * dirtyBitsIterator)2611 angle::Result ContextVk::handleDirtyComputePipelineBinding(DirtyBits::Iterator *dirtyBitsIterator)
2612 {
2613 ASSERT(mCurrentComputePipeline);
2614
2615 mOutsideRenderPassCommands->getCommandBuffer().bindComputePipeline(
2616 mCurrentComputePipeline->getPipeline());
2617 mOutsideRenderPassCommands->retainResource(mCurrentComputePipeline);
2618
2619 return angle::Result::Continue;
2620 }
2621
2622 template <typename CommandBufferHelperT>
handleDirtyTexturesImpl(CommandBufferHelperT * commandBufferHelper,PipelineType pipelineType)2623 ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(
2624 CommandBufferHelperT *commandBufferHelper,
2625 PipelineType pipelineType)
2626 {
2627 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2628 ASSERT(executable);
2629 const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
2630
2631 for (size_t textureUnit : activeTextures)
2632 {
2633 TextureVk *textureVk = mActiveTextures[textureUnit];
2634
2635 // If it's a texture buffer, get the attached buffer.
2636 if (textureVk->getBuffer().get() != nullptr)
2637 {
2638 vk::BufferHelper *buffer = textureVk->getPossiblyEmulatedTextureBuffer(this);
2639 const gl::ShaderBitSet stages =
2640 executable->getSamplerShaderBitsForTextureUnitIndex(textureUnit);
2641
2642 OnTextureBufferRead(buffer, stages, commandBufferHelper);
2643
2644 textureVk->retainBufferViews(commandBufferHelper);
2645 continue;
2646 }
2647
2648 // The image should be flushed and ready to use at this point. There may still be
2649 // lingering staged updates in its staging buffer for unused texture mip levels or
2650 // layers. Therefore we can't verify it has no staged updates right here.
2651 vk::ImageHelper &image = textureVk->getImage();
2652
2653 const vk::ImageLayout imageLayout =
2654 GetImageReadLayout(textureVk, *executable, textureUnit, pipelineType);
2655
2656 // Ensure the image is in the desired layout
2657 commandBufferHelper->imageRead(this, image.getAspectFlags(), imageLayout, &image);
2658 }
2659
2660 if (executable->hasTextures())
2661 {
2662 ProgramExecutableVk *executableVk = vk::GetImpl(executable);
2663 ANGLE_TRY(executableVk->updateTexturesDescriptorSet(
2664 this, getCurrentFrameCount(), mActiveTextures, mState.getSamplers(), pipelineType,
2665 mShareGroupVk->getUpdateDescriptorSetsBuilder()));
2666 }
2667
2668 return angle::Result::Continue;
2669 }
2670
handleDirtyGraphicsTextures(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2671 angle::Result ContextVk::handleDirtyGraphicsTextures(DirtyBits::Iterator *dirtyBitsIterator,
2672 DirtyBits dirtyBitMask)
2673 {
2674 return handleDirtyTexturesImpl(mRenderPassCommands, PipelineType::Graphics);
2675 }
2676
handleDirtyComputeTextures(DirtyBits::Iterator * dirtyBitsIterator)2677 angle::Result ContextVk::handleDirtyComputeTextures(DirtyBits::Iterator *dirtyBitsIterator)
2678 {
2679 return handleDirtyTexturesImpl(mOutsideRenderPassCommands, PipelineType::Compute);
2680 }
2681
handleDirtyGraphicsVertexBuffers(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2682 angle::Result ContextVk::handleDirtyGraphicsVertexBuffers(DirtyBits::Iterator *dirtyBitsIterator,
2683 DirtyBits dirtyBitMask)
2684 {
2685 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2686 VertexArrayVk *vertexArrayVk = getVertexArray();
2687 uint32_t maxAttrib = mState.getProgramExecutable()->getMaxActiveAttribLocation();
2688 const gl::AttribArray<VkBuffer> &bufferHandles = vertexArrayVk->getCurrentArrayBufferHandles();
2689 const gl::AttribArray<VkDeviceSize> &bufferOffsets =
2690 vertexArrayVk->getCurrentArrayBufferOffsets();
2691
2692 if (mRenderer->getFeatures().useVertexInputBindingStrideDynamicState.enabled ||
2693 getFeatures().supportsVertexInputDynamicState.enabled)
2694 {
2695 const gl::AttribArray<GLuint> &bufferStrides =
2696 vertexArrayVk->getCurrentArrayBufferStrides();
2697 const gl::AttribArray<angle::FormatID> &bufferFormats =
2698 vertexArrayVk->getCurrentArrayBufferFormats();
2699 gl::AttribArray<VkDeviceSize> strides = {};
2700 const gl::AttribArray<GLuint> &bufferDivisors =
2701 vertexArrayVk->getCurrentArrayBufferDivisors();
2702 const gl::AttribArray<GLuint> &bufferRelativeOffsets =
2703 vertexArrayVk->getCurrentArrayBufferRelativeOffsets();
2704 const gl::AttributesMask &bufferCompressed =
2705 vertexArrayVk->getCurrentArrayBufferCompressed();
2706
2707 gl::AttribVector<VkVertexInputBindingDescription2EXT> bindingDescs;
2708 gl::AttribVector<VkVertexInputAttributeDescription2EXT> attributeDescs;
2709
2710 // Set stride to 0 for mismatching formats between the program's declared attribute and that
2711 // which is specified in glVertexAttribPointer. See comment in vk_cache_utils.cpp
2712 // (initializePipeline) for more details.
2713 const gl::AttributesMask &activeAttribLocations =
2714 executable->getNonBuiltinAttribLocationsMask();
2715 const gl::ComponentTypeMask &programAttribsTypeMask = executable->getAttributesTypeMask();
2716
2717 for (size_t attribIndex : activeAttribLocations)
2718 {
2719 const angle::Format &intendedFormat =
2720 mRenderer->getFormat(bufferFormats[attribIndex]).getIntendedFormat();
2721
2722 const gl::ComponentType attribType = GetVertexAttributeComponentType(
2723 intendedFormat.isPureInt(), intendedFormat.vertexAttribType);
2724 const gl::ComponentType programAttribType =
2725 gl::GetComponentTypeMask(programAttribsTypeMask, attribIndex);
2726
2727 const bool mismatchingType =
2728 attribType != programAttribType && (programAttribType == gl::ComponentType::Float ||
2729 attribType == gl::ComponentType::Float);
2730 strides[attribIndex] = mismatchingType ? 0 : bufferStrides[attribIndex];
2731
2732 if (getFeatures().supportsVertexInputDynamicState.enabled)
2733 {
2734 VkVertexInputBindingDescription2EXT bindingDesc = {};
2735 VkVertexInputAttributeDescription2EXT attribDesc = {};
2736 bindingDesc.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT;
2737 bindingDesc.binding = static_cast<uint32_t>(attribIndex);
2738 bindingDesc.stride = static_cast<uint32_t>(strides[attribIndex]);
2739 bindingDesc.divisor =
2740 bufferDivisors[attribIndex] > mRenderer->getMaxVertexAttribDivisor()
2741 ? 1
2742 : bufferDivisors[attribIndex];
2743 if (bindingDesc.divisor != 0)
2744 {
2745 bindingDesc.inputRate =
2746 static_cast<VkVertexInputRate>(VK_VERTEX_INPUT_RATE_INSTANCE);
2747 }
2748 else
2749 {
2750 bindingDesc.inputRate =
2751 static_cast<VkVertexInputRate>(VK_VERTEX_INPUT_RATE_VERTEX);
2752 // Divisor value is ignored by the implementation when using
2753 // VK_VERTEX_INPUT_RATE_VERTEX, but it is set to 1 to avoid a validation error
2754 // due to a validation layer issue.
2755 bindingDesc.divisor = 1;
2756 }
2757
2758 attribDesc.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT;
2759 attribDesc.binding = static_cast<uint32_t>(attribIndex);
2760 attribDesc.format = vk::GraphicsPipelineDesc::getPipelineVertexInputStateFormat(
2761 this, bufferFormats[attribIndex], bufferCompressed[attribIndex],
2762 programAttribType, static_cast<uint32_t>(attribIndex));
2763 attribDesc.location = static_cast<uint32_t>(attribIndex);
2764 attribDesc.offset = bufferRelativeOffsets[attribIndex];
2765
2766 bindingDescs.push_back(bindingDesc);
2767 attributeDescs.push_back(attribDesc);
2768 }
2769 }
2770
2771 if (getFeatures().supportsVertexInputDynamicState.enabled)
2772 {
2773 mRenderPassCommandBuffer->setVertexInput(
2774 static_cast<uint32_t>(bindingDescs.size()), bindingDescs.data(),
2775 static_cast<uint32_t>(attributeDescs.size()), attributeDescs.data());
2776 if (bindingDescs.size() != 0)
2777 {
2778
2779 mRenderPassCommandBuffer->bindVertexBuffers(0, maxAttrib, bufferHandles.data(),
2780 bufferOffsets.data());
2781 }
2782 }
2783 else
2784 {
2785 // TODO: Use the sizes parameters here to fix the robustness issue worked around in
2786 // crbug.com/1310038
2787 mRenderPassCommandBuffer->bindVertexBuffers2(
2788 0, maxAttrib, bufferHandles.data(), bufferOffsets.data(), nullptr, strides.data());
2789 }
2790 }
2791 else
2792 {
2793 mRenderPassCommandBuffer->bindVertexBuffers(0, maxAttrib, bufferHandles.data(),
2794 bufferOffsets.data());
2795 }
2796
2797 const gl::AttribArray<vk::BufferHelper *> &arrayBufferResources =
2798 vertexArrayVk->getCurrentArrayBuffers();
2799
2800 // Mark all active vertex buffers as accessed.
2801 for (uint32_t attribIndex = 0; attribIndex < maxAttrib; ++attribIndex)
2802 {
2803 vk::BufferHelper *arrayBuffer = arrayBufferResources[attribIndex];
2804 if (arrayBuffer)
2805 {
2806 mRenderPassCommands->bufferRead(VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
2807 vk::PipelineStage::VertexInput, arrayBuffer);
2808 }
2809 }
2810
2811 return angle::Result::Continue;
2812 }
2813
handleDirtyGraphicsIndexBuffer(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2814 angle::Result ContextVk::handleDirtyGraphicsIndexBuffer(DirtyBits::Iterator *dirtyBitsIterator,
2815 DirtyBits dirtyBitMask)
2816 {
2817 vk::BufferHelper *elementArrayBuffer = mCurrentIndexBuffer;
2818 ASSERT(elementArrayBuffer != nullptr);
2819
2820 VkDeviceSize bufferOffset;
2821 const vk::Buffer &buffer = elementArrayBuffer->getBufferForVertexArray(
2822 this, elementArrayBuffer->getSize(), &bufferOffset);
2823
2824 mRenderPassCommandBuffer->bindIndexBuffer(buffer, bufferOffset + mCurrentIndexBufferOffset,
2825 getVkIndexType(mCurrentDrawElementsType));
2826
2827 mRenderPassCommands->bufferRead(VK_ACCESS_INDEX_READ_BIT, vk::PipelineStage::VertexInput,
2828 elementArrayBuffer);
2829
2830 return angle::Result::Continue;
2831 }
2832
handleDirtyGraphicsFramebufferFetchBarrier(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2833 angle::Result ContextVk::handleDirtyGraphicsFramebufferFetchBarrier(
2834 DirtyBits::Iterator *dirtyBitsIterator,
2835 DirtyBits dirtyBitMask)
2836 {
2837 VkMemoryBarrier memoryBarrier = {};
2838 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
2839 memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2840 memoryBarrier.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
2841
2842 mRenderPassCommandBuffer->pipelineBarrier(
2843 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
2844 GetLocalDependencyFlags(this), 1, &memoryBarrier, 0, nullptr, 0, nullptr);
2845
2846 return angle::Result::Continue;
2847 }
2848
handleDirtyGraphicsBlendBarrier(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2849 angle::Result ContextVk::handleDirtyGraphicsBlendBarrier(DirtyBits::Iterator *dirtyBitsIterator,
2850 DirtyBits dirtyBitMask)
2851 {
2852 if (getFeatures().supportsBlendOperationAdvancedCoherent.enabled)
2853 {
2854 return angle::Result::Continue;
2855 }
2856
2857 VkMemoryBarrier memoryBarrier = {};
2858 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
2859 memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2860 memoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT;
2861
2862 mRenderPassCommandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2863 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2864 GetLocalDependencyFlags(this), 1, &memoryBarrier, 0,
2865 nullptr, 0, nullptr);
2866
2867 return angle::Result::Continue;
2868 }
2869
2870 template <typename CommandBufferHelperT>
handleDirtyShaderResourcesImpl(CommandBufferHelperT * commandBufferHelper,PipelineType pipelineType,DirtyBits::Iterator * dirtyBitsIterator)2871 angle::Result ContextVk::handleDirtyShaderResourcesImpl(CommandBufferHelperT *commandBufferHelper,
2872 PipelineType pipelineType,
2873 DirtyBits::Iterator *dirtyBitsIterator)
2874 {
2875 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
2876 ASSERT(executable);
2877
2878 // DIRTY_BIT_UNIFORM_BUFFERS is set when uniform buffer bindings change.
2879 // DIRTY_BIT_SHADER_RESOURCES gets set when the program executable has changed. In that case,
2880 // this function will update entire the shader resource descriptorSet. This means there is no
2881 // need to process uniform buffer bindings again.
2882 dirtyBitsIterator->resetLaterBit(DIRTY_BIT_UNIFORM_BUFFERS);
2883
2884 // This function processes uniform buffers, so it doesn't matter which are dirty. The following
2885 // makes sure the dirty bits are reset.
2886 mState.getAndResetDirtyUniformBlocks();
2887
2888 const bool hasImages = executable->hasImages();
2889 const bool hasStorageBuffers = executable->hasStorageBuffers();
2890 const bool hasAtomicCounterBuffers = executable->hasAtomicCounterBuffers();
2891 const bool hasUniformBuffers = executable->hasUniformBuffers();
2892 const bool hasFramebufferFetch = executable->usesColorFramebufferFetch() ||
2893 executable->usesDepthFramebufferFetch() ||
2894 executable->usesStencilFramebufferFetch();
2895
2896 if (!hasUniformBuffers && !hasStorageBuffers && !hasAtomicCounterBuffers && !hasImages &&
2897 !hasFramebufferFetch)
2898 {
2899 return angle::Result::Continue;
2900 }
2901
2902 const VkPhysicalDeviceLimits &limits = mRenderer->getPhysicalDeviceProperties().limits;
2903 ProgramExecutableVk *executableVk = vk::GetImpl(executable);
2904 const ShaderInterfaceVariableInfoMap &variableInfoMap = executableVk->getVariableInfoMap();
2905
2906 mShaderBufferWriteDescriptorDescs = executableVk->getShaderResourceWriteDescriptorDescs();
2907 // Update writeDescriptorDescs with inputAttachments
2908 mShaderBufferWriteDescriptorDescs.updateInputAttachments(
2909 *executable, variableInfoMap, vk::GetImpl(mState.getDrawFramebuffer()));
2910
2911 mShaderBuffersDescriptorDesc.resize(
2912 mShaderBufferWriteDescriptorDescs.getTotalDescriptorCount());
2913 if (hasUniformBuffers)
2914 {
2915 mShaderBuffersDescriptorDesc.updateShaderBuffers(
2916 commandBufferHelper, *executable, variableInfoMap,
2917 mState.getOffsetBindingPointerUniformBuffers(), executable->getUniformBlocks(),
2918 executableVk->getUniformBufferDescriptorType(), limits.maxUniformBufferRange,
2919 mEmptyBuffer, mShaderBufferWriteDescriptorDescs, mDeferredMemoryBarriers);
2920 }
2921 if (hasStorageBuffers)
2922 {
2923 mShaderBuffersDescriptorDesc.updateShaderBuffers(
2924 commandBufferHelper, *executable, variableInfoMap,
2925 mState.getOffsetBindingPointerShaderStorageBuffers(),
2926 executable->getShaderStorageBlocks(), executableVk->getStorageBufferDescriptorType(),
2927 limits.maxStorageBufferRange, mEmptyBuffer, mShaderBufferWriteDescriptorDescs,
2928 mDeferredMemoryBarriers);
2929 }
2930 if (hasAtomicCounterBuffers)
2931 {
2932 mShaderBuffersDescriptorDesc.updateAtomicCounters(
2933 commandBufferHelper, *executable, variableInfoMap,
2934 mState.getOffsetBindingPointerAtomicCounterBuffers(),
2935 executable->getAtomicCounterBuffers(), limits.minStorageBufferOffsetAlignment,
2936 mEmptyBuffer, mShaderBufferWriteDescriptorDescs);
2937 }
2938 if (hasImages)
2939 {
2940 ANGLE_TRY(updateActiveImages(commandBufferHelper));
2941 ANGLE_TRY(mShaderBuffersDescriptorDesc.updateImages(this, *executable, variableInfoMap,
2942 mActiveImages, mState.getImageUnits(),
2943 mShaderBufferWriteDescriptorDescs));
2944 }
2945 if (hasFramebufferFetch)
2946 {
2947 ANGLE_TRY(mShaderBuffersDescriptorDesc.updateInputAttachments(
2948 this, *executable, variableInfoMap, vk::GetImpl(mState.getDrawFramebuffer()),
2949 mShaderBufferWriteDescriptorDescs));
2950 }
2951
2952 mDeferredMemoryBarriers = 0;
2953
2954 vk::SharedDescriptorSetCacheKey newSharedCacheKey;
2955 ANGLE_TRY(executableVk->updateShaderResourcesDescriptorSet(
2956 this, getCurrentFrameCount(), mShareGroupVk->getUpdateDescriptorSetsBuilder(),
2957 mShaderBufferWriteDescriptorDescs, mShaderBuffersDescriptorDesc, &newSharedCacheKey));
2958
2959 if (newSharedCacheKey)
2960 {
2961 // A new cache entry has been created. We record this cache key in the images and buffers so
2962 // that the descriptorSet cache can be destroyed when buffer/image is destroyed.
2963 updateShaderResourcesWithSharedCacheKey(newSharedCacheKey);
2964 }
2965
2966 // Record usage of storage buffers and images in the command buffer to aid handling of
2967 // glMemoryBarrier.
2968 if (hasImages || hasStorageBuffers || hasAtomicCounterBuffers)
2969 {
2970 commandBufferHelper->setHasShaderStorageOutput();
2971 }
2972
2973 return angle::Result::Continue;
2974 }
2975
handleDirtyGraphicsShaderResources(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)2976 angle::Result ContextVk::handleDirtyGraphicsShaderResources(DirtyBits::Iterator *dirtyBitsIterator,
2977 DirtyBits dirtyBitMask)
2978 {
2979 return handleDirtyShaderResourcesImpl(mRenderPassCommands, PipelineType::Graphics,
2980 dirtyBitsIterator);
2981 }
2982
handleDirtyComputeShaderResources(DirtyBits::Iterator * dirtyBitsIterator)2983 angle::Result ContextVk::handleDirtyComputeShaderResources(DirtyBits::Iterator *dirtyBitsIterator)
2984 {
2985 return handleDirtyShaderResourcesImpl(mOutsideRenderPassCommands, PipelineType::Compute,
2986 dirtyBitsIterator);
2987 }
2988
2989 template <typename CommandBufferT>
handleDirtyUniformBuffersImpl(CommandBufferT * commandBufferHelper)2990 angle::Result ContextVk::handleDirtyUniformBuffersImpl(CommandBufferT *commandBufferHelper)
2991 {
2992 gl::ProgramExecutable *executable = mState.getProgramExecutable();
2993 ASSERT(executable);
2994 ASSERT(executable->hasUniformBuffers());
2995
2996 const VkPhysicalDeviceLimits &limits = mRenderer->getPhysicalDeviceProperties().limits;
2997 ProgramExecutableVk *executableVk = vk::GetImpl(executable);
2998 const ShaderInterfaceVariableInfoMap &variableInfoMap = executableVk->getVariableInfoMap();
2999
3000 gl::ProgramUniformBlockMask dirtyBits = mState.getAndResetDirtyUniformBlocks();
3001 for (size_t blockIndex : dirtyBits)
3002 {
3003 const GLuint binding = executable->getUniformBlockBinding(blockIndex);
3004 mShaderBuffersDescriptorDesc.updateOneShaderBuffer(
3005 commandBufferHelper, variableInfoMap, mState.getOffsetBindingPointerUniformBuffers(),
3006 executable->getUniformBlocks()[blockIndex], binding,
3007 executableVk->getUniformBufferDescriptorType(), limits.maxUniformBufferRange,
3008 mEmptyBuffer, mShaderBufferWriteDescriptorDescs, mDeferredMemoryBarriers);
3009 }
3010
3011 vk::SharedDescriptorSetCacheKey newSharedCacheKey;
3012 ANGLE_TRY(executableVk->updateShaderResourcesDescriptorSet(
3013 this, getCurrentFrameCount(), mShareGroupVk->getUpdateDescriptorSetsBuilder(),
3014 mShaderBufferWriteDescriptorDescs, mShaderBuffersDescriptorDesc, &newSharedCacheKey));
3015
3016 if (newSharedCacheKey)
3017 {
3018 // A new cache entry has been created. We record this cache key in the images and
3019 // buffers so that the descriptorSet cache can be destroyed when buffer/image is
3020 // destroyed.
3021 updateShaderResourcesWithSharedCacheKey(newSharedCacheKey);
3022 }
3023
3024 return angle::Result::Continue;
3025 }
3026
handleDirtyGraphicsUniformBuffers(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3027 angle::Result ContextVk::handleDirtyGraphicsUniformBuffers(DirtyBits::Iterator *dirtyBitsIterator,
3028 DirtyBits dirtyBitMask)
3029 {
3030 return handleDirtyUniformBuffersImpl(mRenderPassCommands);
3031 }
3032
handleDirtyComputeUniformBuffers(DirtyBits::Iterator * dirtyBitsIterator)3033 angle::Result ContextVk::handleDirtyComputeUniformBuffers(DirtyBits::Iterator *dirtyBitsIterator)
3034 {
3035 return handleDirtyUniformBuffersImpl(mOutsideRenderPassCommands);
3036 }
3037
handleDirtyGraphicsTransformFeedbackBuffersEmulation(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3038 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation(
3039 DirtyBits::Iterator *dirtyBitsIterator,
3040 DirtyBits dirtyBitMask)
3041 {
3042 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
3043 ASSERT(executable);
3044
3045 if (!executable->hasTransformFeedbackOutput())
3046 {
3047 return angle::Result::Continue;
3048 }
3049
3050 TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
3051
3052 if (mState.isTransformFeedbackActiveUnpaused())
3053 {
3054 size_t bufferCount = executable->getTransformFeedbackBufferCount();
3055 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &bufferHelpers =
3056 transformFeedbackVk->getBufferHelpers();
3057
3058 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
3059 {
3060 vk::BufferHelper *bufferHelper = bufferHelpers[bufferIndex];
3061 ASSERT(bufferHelper);
3062 mRenderPassCommands->bufferWrite(VK_ACCESS_SHADER_WRITE_BIT,
3063 vk::PipelineStage::VertexShader, bufferHelper);
3064 }
3065
3066 mCurrentTransformFeedbackQueueSerial = mRenderPassCommands->getQueueSerial();
3067 }
3068
3069 ProgramExecutableVk *executableVk = vk::GetImpl(executable);
3070 vk::BufferHelper *currentUniformBuffer = mDefaultUniformStorage.getCurrentBuffer();
3071
3072 const vk::WriteDescriptorDescs &writeDescriptorDescs =
3073 executableVk->getDefaultUniformWriteDescriptorDescs(transformFeedbackVk);
3074
3075 vk::DescriptorSetDescBuilder uniformsAndXfbDesc(writeDescriptorDescs.getTotalDescriptorCount());
3076 uniformsAndXfbDesc.updateUniformsAndXfb(
3077 this, *executable, writeDescriptorDescs, currentUniformBuffer, mEmptyBuffer,
3078 mState.isTransformFeedbackActiveUnpaused(), transformFeedbackVk);
3079
3080 vk::SharedDescriptorSetCacheKey newSharedCacheKey;
3081 ANGLE_TRY(executableVk->updateUniformsAndXfbDescriptorSet(
3082 this, getCurrentFrameCount(), mShareGroupVk->getUpdateDescriptorSetsBuilder(),
3083 writeDescriptorDescs, currentUniformBuffer, &uniformsAndXfbDesc, &newSharedCacheKey));
3084
3085 if (newSharedCacheKey)
3086 {
3087 if (currentUniformBuffer)
3088 {
3089 currentUniformBuffer->getBufferBlock()->onNewDescriptorSet(newSharedCacheKey);
3090 }
3091 transformFeedbackVk->onNewDescriptorSet(*executable, newSharedCacheKey);
3092 }
3093
3094 return angle::Result::Continue;
3095 }
3096
handleDirtyGraphicsTransformFeedbackBuffersExtension(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3097 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension(
3098 DirtyBits::Iterator *dirtyBitsIterator,
3099 DirtyBits dirtyBitMask)
3100 {
3101 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
3102 ASSERT(executable);
3103
3104 if (!executable->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActive())
3105 {
3106 return angle::Result::Continue;
3107 }
3108
3109 TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
3110 size_t bufferCount = executable->getTransformFeedbackBufferCount();
3111
3112 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers =
3113 transformFeedbackVk->getBufferHelpers();
3114 gl::TransformFeedbackBuffersArray<vk::BufferHelper> &counterBuffers =
3115 transformFeedbackVk->getCounterBufferHelpers();
3116
3117 // Issue necessary barriers for the transform feedback buffers.
3118 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
3119 {
3120 vk::BufferHelper *bufferHelper = buffers[bufferIndex];
3121 ASSERT(bufferHelper);
3122 mRenderPassCommands->bufferWrite(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT,
3123 vk::PipelineStage::TransformFeedback, bufferHelper);
3124 }
3125
3126 // Issue necessary barriers for the transform feedback counter buffer. Note that the barrier is
3127 // issued only on the first buffer (which uses a global memory barrier), as all the counter
3128 // buffers of the transform feedback object are used together. The rest of the buffers are
3129 // simply retained so they don't get deleted too early.
3130 ASSERT(counterBuffers[0].valid());
3131 mRenderPassCommands->bufferWrite(VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT |
3132 VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,
3133 vk::PipelineStage::TransformFeedback, &counterBuffers[0]);
3134 for (size_t bufferIndex = 1; bufferIndex < bufferCount; ++bufferIndex)
3135 {
3136 mRenderPassCommands->retainResourceForWrite(&counterBuffers[bufferIndex]);
3137 }
3138
3139 const gl::TransformFeedbackBuffersArray<VkBuffer> &bufferHandles =
3140 transformFeedbackVk->getBufferHandles();
3141 const gl::TransformFeedbackBuffersArray<VkDeviceSize> &bufferOffsets =
3142 transformFeedbackVk->getBufferOffsets();
3143 const gl::TransformFeedbackBuffersArray<VkDeviceSize> &bufferSizes =
3144 transformFeedbackVk->getBufferSizes();
3145
3146 mRenderPassCommandBuffer->bindTransformFeedbackBuffers(
3147 0, static_cast<uint32_t>(bufferCount), bufferHandles.data(), bufferOffsets.data(),
3148 bufferSizes.data());
3149
3150 if (!mState.isTransformFeedbackActiveUnpaused())
3151 {
3152 return angle::Result::Continue;
3153 }
3154
3155 // We should have same number of counter buffers as xfb buffers have
3156 const gl::TransformFeedbackBuffersArray<VkBuffer> &counterBufferHandles =
3157 transformFeedbackVk->getCounterBufferHandles();
3158 const gl::TransformFeedbackBuffersArray<VkDeviceSize> &counterBufferOffsets =
3159 transformFeedbackVk->getCounterBufferOffsets();
3160
3161 bool rebindBuffers = transformFeedbackVk->getAndResetBufferRebindState();
3162
3163 mRenderPassCommands->beginTransformFeedback(bufferCount, counterBufferHandles.data(),
3164 counterBufferOffsets.data(), rebindBuffers);
3165
3166 mCurrentTransformFeedbackQueueSerial = mRenderPassCommands->getQueueSerial();
3167
3168 return angle::Result::Continue;
3169 }
3170
handleDirtyGraphicsTransformFeedbackResume(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3171 angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackResume(
3172 DirtyBits::Iterator *dirtyBitsIterator,
3173 DirtyBits dirtyBitMask)
3174 {
3175 if (mRenderPassCommands->isTransformFeedbackStarted())
3176 {
3177 mRenderPassCommands->resumeTransformFeedback();
3178 }
3179
3180 ANGLE_TRY(resumeXfbRenderPassQueriesIfActive());
3181
3182 return angle::Result::Continue;
3183 }
3184
handleDirtyGraphicsDescriptorSets(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3185 angle::Result ContextVk::handleDirtyGraphicsDescriptorSets(DirtyBits::Iterator *dirtyBitsIterator,
3186 DirtyBits dirtyBitMask)
3187 {
3188 return handleDirtyDescriptorSetsImpl(mRenderPassCommands, PipelineType::Graphics);
3189 }
3190
handleDirtyGraphicsUniforms(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3191 angle::Result ContextVk::handleDirtyGraphicsUniforms(DirtyBits::Iterator *dirtyBitsIterator,
3192 DirtyBits dirtyBitMask)
3193 {
3194 return handleDirtyUniformsImpl(dirtyBitsIterator);
3195 }
3196
handleDirtyComputeUniforms(DirtyBits::Iterator * dirtyBitsIterator)3197 angle::Result ContextVk::handleDirtyComputeUniforms(DirtyBits::Iterator *dirtyBitsIterator)
3198 {
3199 return handleDirtyUniformsImpl(dirtyBitsIterator);
3200 }
3201
handleDirtyUniformsImpl(DirtyBits::Iterator * dirtyBitsIterator)3202 angle::Result ContextVk::handleDirtyUniformsImpl(DirtyBits::Iterator *dirtyBitsIterator)
3203 {
3204 dirtyBitsIterator->setLaterBit(DIRTY_BIT_DESCRIPTOR_SETS);
3205
3206 ProgramExecutableVk *executableVk = vk::GetImpl(mState.getProgramExecutable());
3207 TransformFeedbackVk *transformFeedbackVk =
3208 vk::SafeGetImpl(mState.getCurrentTransformFeedback());
3209 ANGLE_TRY(executableVk->updateUniforms(
3210 this, getCurrentFrameCount(), mShareGroupVk->getUpdateDescriptorSetsBuilder(),
3211 &mEmptyBuffer, &mDefaultUniformStorage, mState.isTransformFeedbackActiveUnpaused(),
3212 transformFeedbackVk));
3213
3214 return angle::Result::Continue;
3215 }
3216
handleDirtyGraphicsDynamicViewport(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3217 angle::Result ContextVk::handleDirtyGraphicsDynamicViewport(DirtyBits::Iterator *dirtyBitsIterator,
3218 DirtyBits dirtyBitMask)
3219 {
3220 mRenderPassCommandBuffer->setViewport(0, 1, &mViewport);
3221 return angle::Result::Continue;
3222 }
3223
handleDirtyGraphicsDynamicScissor(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3224 angle::Result ContextVk::handleDirtyGraphicsDynamicScissor(DirtyBits::Iterator *dirtyBitsIterator,
3225 DirtyBits dirtyBitMask)
3226 {
3227 handleDirtyGraphicsDynamicScissorImpl(mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
3228 return angle::Result::Continue;
3229 }
3230
handleDirtyGraphicsDynamicLineWidth(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3231 angle::Result ContextVk::handleDirtyGraphicsDynamicLineWidth(DirtyBits::Iterator *dirtyBitsIterator,
3232 DirtyBits dirtyBitMask)
3233 {
3234 // Clamp line width to min/max allowed values. It's not invalid GL to
3235 // provide out-of-range line widths, but it _is_ invalid Vulkan.
3236 const float lineWidth = gl::clamp(mState.getLineWidth(), mState.getCaps().minAliasedLineWidth,
3237 mState.getCaps().maxAliasedLineWidth);
3238 mRenderPassCommandBuffer->setLineWidth(lineWidth);
3239 return angle::Result::Continue;
3240 }
3241
handleDirtyGraphicsDynamicDepthBias(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3242 angle::Result ContextVk::handleDirtyGraphicsDynamicDepthBias(DirtyBits::Iterator *dirtyBitsIterator,
3243 DirtyBits dirtyBitMask)
3244 {
3245 const gl::RasterizerState &rasterState = mState.getRasterizerState();
3246
3247 float depthBiasConstantFactor = rasterState.polygonOffsetUnits;
3248 if (getFeatures().doubleDepthBiasConstantFactor.enabled)
3249 {
3250 depthBiasConstantFactor *= 2.0f;
3251 }
3252
3253 // Note: depth bias clamp is only exposed in EXT_polygon_offset_clamp.
3254 mRenderPassCommandBuffer->setDepthBias(depthBiasConstantFactor, rasterState.polygonOffsetClamp,
3255 rasterState.polygonOffsetFactor);
3256 return angle::Result::Continue;
3257 }
3258
handleDirtyGraphicsDynamicBlendConstants(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3259 angle::Result ContextVk::handleDirtyGraphicsDynamicBlendConstants(
3260 DirtyBits::Iterator *dirtyBitsIterator,
3261 DirtyBits dirtyBitMask)
3262 {
3263 const gl::ColorF &color = mState.getBlendColor();
3264 mRenderPassCommandBuffer->setBlendConstants(color.data());
3265 return angle::Result::Continue;
3266 }
3267
handleDirtyGraphicsDynamicStencilCompareMask(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3268 angle::Result ContextVk::handleDirtyGraphicsDynamicStencilCompareMask(
3269 DirtyBits::Iterator *dirtyBitsIterator,
3270 DirtyBits dirtyBitMask)
3271 {
3272 const gl::DepthStencilState &depthStencilState = mState.getDepthStencilState();
3273 mRenderPassCommandBuffer->setStencilCompareMask(depthStencilState.stencilMask,
3274 depthStencilState.stencilBackMask);
3275 return angle::Result::Continue;
3276 }
3277
handleDirtyGraphicsDynamicStencilWriteMask(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3278 angle::Result ContextVk::handleDirtyGraphicsDynamicStencilWriteMask(
3279 DirtyBits::Iterator *dirtyBitsIterator,
3280 DirtyBits dirtyBitMask)
3281 {
3282 const gl::DepthStencilState &depthStencilState = mState.getDepthStencilState();
3283 const gl::Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
3284 uint32_t frontWritemask = 0;
3285 uint32_t backWritemask = 0;
3286 // Don't write to stencil buffers that should not exist
3287 if (drawFramebuffer->hasStencil())
3288 {
3289 frontWritemask = depthStencilState.stencilWritemask;
3290 backWritemask = depthStencilState.stencilBackWritemask;
3291 }
3292
3293 mRenderPassCommandBuffer->setStencilWriteMask(frontWritemask, backWritemask);
3294 return angle::Result::Continue;
3295 }
3296
handleDirtyGraphicsDynamicStencilReference(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3297 angle::Result ContextVk::handleDirtyGraphicsDynamicStencilReference(
3298 DirtyBits::Iterator *dirtyBitsIterator,
3299 DirtyBits dirtyBitMask)
3300 {
3301 mRenderPassCommandBuffer->setStencilReference(mState.getStencilRef(),
3302 mState.getStencilBackRef());
3303 return angle::Result::Continue;
3304 }
3305
handleDirtyGraphicsDynamicCullMode(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3306 angle::Result ContextVk::handleDirtyGraphicsDynamicCullMode(DirtyBits::Iterator *dirtyBitsIterator,
3307 DirtyBits dirtyBitMask)
3308 {
3309 const gl::RasterizerState &rasterState = mState.getRasterizerState();
3310 mRenderPassCommandBuffer->setCullMode(gl_vk::GetCullMode(rasterState));
3311 return angle::Result::Continue;
3312 }
3313
handleDirtyGraphicsDynamicFrontFace(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3314 angle::Result ContextVk::handleDirtyGraphicsDynamicFrontFace(DirtyBits::Iterator *dirtyBitsIterator,
3315 DirtyBits dirtyBitMask)
3316 {
3317 const gl::RasterizerState &rasterState = mState.getRasterizerState();
3318 mRenderPassCommandBuffer->setFrontFace(
3319 gl_vk::GetFrontFace(rasterState.frontFace, isYFlipEnabledForDrawFBO()));
3320 return angle::Result::Continue;
3321 }
3322
handleDirtyGraphicsDynamicDepthTestEnable(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3323 angle::Result ContextVk::handleDirtyGraphicsDynamicDepthTestEnable(
3324 DirtyBits::Iterator *dirtyBitsIterator,
3325 DirtyBits dirtyBitMask)
3326 {
3327 const gl::DepthStencilState depthStencilState = mState.getDepthStencilState();
3328 gl::Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
3329
3330 // Only enable the depth test if the draw framebuffer has a depth buffer.
3331 mRenderPassCommandBuffer->setDepthTestEnable(depthStencilState.depthTest &&
3332 drawFramebuffer->hasDepth());
3333 return angle::Result::Continue;
3334 }
3335
handleDirtyGraphicsDynamicDepthWriteEnable(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3336 angle::Result ContextVk::handleDirtyGraphicsDynamicDepthWriteEnable(
3337 DirtyBits::Iterator *dirtyBitsIterator,
3338 DirtyBits dirtyBitMask)
3339 {
3340 const gl::DepthStencilState depthStencilState = mState.getDepthStencilState();
3341 gl::Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
3342
3343 // Only enable the depth write if the draw framebuffer has a depth buffer.
3344 const bool depthWriteEnabled =
3345 drawFramebuffer->hasDepth() && depthStencilState.depthTest && depthStencilState.depthMask;
3346 mRenderPassCommandBuffer->setDepthWriteEnable(depthWriteEnabled);
3347 return angle::Result::Continue;
3348 }
3349
handleDirtyGraphicsDynamicDepthCompareOp(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3350 angle::Result ContextVk::handleDirtyGraphicsDynamicDepthCompareOp(
3351 DirtyBits::Iterator *dirtyBitsIterator,
3352 DirtyBits dirtyBitMask)
3353 {
3354 const gl::DepthStencilState depthStencilState = mState.getDepthStencilState();
3355 mRenderPassCommandBuffer->setDepthCompareOp(gl_vk::GetCompareOp(depthStencilState.depthFunc));
3356 return angle::Result::Continue;
3357 }
3358
handleDirtyGraphicsDynamicStencilTestEnable(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3359 angle::Result ContextVk::handleDirtyGraphicsDynamicStencilTestEnable(
3360 DirtyBits::Iterator *dirtyBitsIterator,
3361 DirtyBits dirtyBitMask)
3362 {
3363 const gl::DepthStencilState depthStencilState = mState.getDepthStencilState();
3364 gl::Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
3365
3366 // Only enable the stencil test if the draw framebuffer has a stencil buffer.
3367 mRenderPassCommandBuffer->setStencilTestEnable(depthStencilState.stencilTest &&
3368 drawFramebuffer->hasStencil());
3369 return angle::Result::Continue;
3370 }
3371
handleDirtyGraphicsDynamicStencilOp(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3372 angle::Result ContextVk::handleDirtyGraphicsDynamicStencilOp(DirtyBits::Iterator *dirtyBitsIterator,
3373 DirtyBits dirtyBitMask)
3374 {
3375 const gl::DepthStencilState depthStencilState = mState.getDepthStencilState();
3376 mRenderPassCommandBuffer->setStencilOp(
3377 VK_STENCIL_FACE_FRONT_BIT, gl_vk::GetStencilOp(depthStencilState.stencilFail),
3378 gl_vk::GetStencilOp(depthStencilState.stencilPassDepthPass),
3379 gl_vk::GetStencilOp(depthStencilState.stencilPassDepthFail),
3380 gl_vk::GetCompareOp(depthStencilState.stencilFunc));
3381 mRenderPassCommandBuffer->setStencilOp(
3382 VK_STENCIL_FACE_BACK_BIT, gl_vk::GetStencilOp(depthStencilState.stencilBackFail),
3383 gl_vk::GetStencilOp(depthStencilState.stencilBackPassDepthPass),
3384 gl_vk::GetStencilOp(depthStencilState.stencilBackPassDepthFail),
3385 gl_vk::GetCompareOp(depthStencilState.stencilBackFunc));
3386 return angle::Result::Continue;
3387 }
3388
handleDirtyGraphicsDynamicRasterizerDiscardEnable(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3389 angle::Result ContextVk::handleDirtyGraphicsDynamicRasterizerDiscardEnable(
3390 DirtyBits::Iterator *dirtyBitsIterator,
3391 DirtyBits dirtyBitMask)
3392 {
3393 const bool isEmulatingRasterizerDiscard =
3394 isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(
3395 mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
3396 const bool isRasterizerDiscardEnabled = mState.isRasterizerDiscardEnabled();
3397
3398 mRenderPassCommandBuffer->setRasterizerDiscardEnable(isRasterizerDiscardEnabled &&
3399 !isEmulatingRasterizerDiscard);
3400 return angle::Result::Continue;
3401 }
3402
handleDirtyGraphicsDynamicDepthBiasEnable(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3403 angle::Result ContextVk::handleDirtyGraphicsDynamicDepthBiasEnable(
3404 DirtyBits::Iterator *dirtyBitsIterator,
3405 DirtyBits dirtyBitMask)
3406 {
3407 mRenderPassCommandBuffer->setDepthBiasEnable(mState.isPolygonOffsetEnabled());
3408 return angle::Result::Continue;
3409 }
3410
handleDirtyGraphicsDynamicLogicOp(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3411 angle::Result ContextVk::handleDirtyGraphicsDynamicLogicOp(DirtyBits::Iterator *dirtyBitsIterator,
3412 DirtyBits dirtyBitMask)
3413 {
3414 mRenderPassCommandBuffer->setLogicOp(gl_vk::GetLogicOp(gl::ToGLenum(mState.getLogicOp())));
3415 return angle::Result::Continue;
3416 }
3417
handleDirtyGraphicsDynamicPrimitiveRestartEnable(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3418 angle::Result ContextVk::handleDirtyGraphicsDynamicPrimitiveRestartEnable(
3419 DirtyBits::Iterator *dirtyBitsIterator,
3420 DirtyBits dirtyBitMask)
3421 {
3422 mRenderPassCommandBuffer->setPrimitiveRestartEnable(mState.isPrimitiveRestartEnabled());
3423 return angle::Result::Continue;
3424 }
3425
handleDirtyGraphicsDynamicFragmentShadingRate(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)3426 angle::Result ContextVk::handleDirtyGraphicsDynamicFragmentShadingRate(
3427 DirtyBits::Iterator *dirtyBitsIterator,
3428 DirtyBits dirtyBitMask)
3429 {
3430 FramebufferVk *drawFramebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
3431 const bool isFoveationEnabled = drawFramebufferVk->isFoveationEnabled();
3432
3433 gl::ShadingRate shadingRate =
3434 isFoveationEnabled ? gl::ShadingRate::_1x1 : getState().getShadingRate();
3435 if (shadingRate == gl::ShadingRate::Undefined)
3436 {
3437 // Shading rate has not been set. Since this is dynamic state, set it to 1x1
3438 shadingRate = gl::ShadingRate::_1x1;
3439 }
3440
3441 const bool shadingRateSupported = mRenderer->isShadingRateSupported(shadingRate);
3442 VkExtent2D fragmentSize = {};
3443
3444 switch (shadingRate)
3445 {
3446 case gl::ShadingRate::_1x1:
3447 ASSERT(shadingRateSupported);
3448 fragmentSize.width = 1;
3449 fragmentSize.height = 1;
3450 break;
3451 case gl::ShadingRate::_1x2:
3452 ASSERT(shadingRateSupported);
3453 fragmentSize.width = 1;
3454 fragmentSize.height = 2;
3455 break;
3456 case gl::ShadingRate::_2x1:
3457 ASSERT(shadingRateSupported);
3458 fragmentSize.width = 2;
3459 fragmentSize.height = 1;
3460 break;
3461 case gl::ShadingRate::_2x2:
3462 ASSERT(shadingRateSupported);
3463 fragmentSize.width = 2;
3464 fragmentSize.height = 2;
3465 break;
3466 case gl::ShadingRate::_4x2:
3467 if (shadingRateSupported)
3468 {
3469 fragmentSize.width = 4;
3470 fragmentSize.height = 2;
3471 }
3472 else
3473 {
3474 // Fallback to shading rate that preserves aspect ratio
3475 fragmentSize.width = 2;
3476 fragmentSize.height = 1;
3477 }
3478 break;
3479 case gl::ShadingRate::_4x4:
3480 if (shadingRateSupported)
3481 {
3482 fragmentSize.width = 4;
3483 fragmentSize.height = 4;
3484 }
3485 else
3486 {
3487 // Fallback to shading rate that preserves aspect ratio
3488 fragmentSize.width = 2;
3489 fragmentSize.height = 2;
3490 }
3491 break;
3492 default:
3493 UNREACHABLE();
3494 return angle::Result::Stop;
3495 }
3496
3497 VkFragmentShadingRateCombinerOpKHR shadingRateCombinerOp[2] = {
3498 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
3499 VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR};
3500
3501 // If foveated rendering is enabled update combiner op
3502 if (isFoveationEnabled)
3503 {
3504 shadingRateCombinerOp[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR;
3505 }
3506
3507 ASSERT(hasActiveRenderPass());
3508 mRenderPassCommandBuffer->setFragmentShadingRate(&fragmentSize, shadingRateCombinerOp);
3509
3510 return angle::Result::Continue;
3511 }
3512
handleDirtyGraphicsDynamicScissorImpl(bool isPrimitivesGeneratedQueryActive)3513 void ContextVk::handleDirtyGraphicsDynamicScissorImpl(bool isPrimitivesGeneratedQueryActive)
3514 {
3515 // If primitives generated query and rasterizer discard are both active, but the Vulkan
3516 // implementation of the query does not support rasterizer discard, use an empty scissor to
3517 // emulate it.
3518 if (isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(
3519 isPrimitivesGeneratedQueryActive))
3520 {
3521 VkRect2D emptyScissor = {};
3522 mRenderPassCommandBuffer->setScissor(0, 1, &emptyScissor);
3523 }
3524 else
3525 {
3526 mRenderPassCommandBuffer->setScissor(0, 1, &mScissor);
3527 }
3528 }
3529
handleDirtyComputeDescriptorSets(DirtyBits::Iterator * dirtyBitsIterator)3530 angle::Result ContextVk::handleDirtyComputeDescriptorSets(DirtyBits::Iterator *dirtyBitsIterator)
3531 {
3532 return handleDirtyDescriptorSetsImpl(mOutsideRenderPassCommands, PipelineType::Compute);
3533 }
3534
3535 template <typename CommandBufferHelperT>
handleDirtyDescriptorSetsImpl(CommandBufferHelperT * commandBufferHelper,PipelineType pipelineType)3536 angle::Result ContextVk::handleDirtyDescriptorSetsImpl(CommandBufferHelperT *commandBufferHelper,
3537 PipelineType pipelineType)
3538 {
3539 // When using Vulkan secondary command buffers, the descriptor sets need to be updated before
3540 // they are bound.
3541 if (!CommandBufferHelperT::ExecutesInline())
3542 {
3543 flushDescriptorSetUpdates();
3544 }
3545
3546 ProgramExecutableVk *executableVk = vk::GetImpl(mState.getProgramExecutable());
3547 return executableVk->bindDescriptorSets(this, getCurrentFrameCount(), commandBufferHelper,
3548 &commandBufferHelper->getCommandBuffer(), pipelineType);
3549 }
3550
syncObjectPerfCounters(const angle::VulkanPerfCounters & commandQueuePerfCounters)3551 void ContextVk::syncObjectPerfCounters(const angle::VulkanPerfCounters &commandQueuePerfCounters)
3552 {
3553 if (!mState.isPerfMonitorActive())
3554 {
3555 return;
3556 }
3557
3558 mPerfCounters.descriptorSetCacheTotalSize = 0;
3559 mPerfCounters.descriptorSetCacheKeySizeBytes = 0;
3560 mPerfCounters.uniformsAndXfbDescriptorSetCacheHits = 0;
3561 mPerfCounters.uniformsAndXfbDescriptorSetCacheMisses = 0;
3562 mPerfCounters.uniformsAndXfbDescriptorSetCacheTotalSize = 0;
3563 mPerfCounters.textureDescriptorSetCacheHits = 0;
3564 mPerfCounters.textureDescriptorSetCacheMisses = 0;
3565 mPerfCounters.textureDescriptorSetCacheTotalSize = 0;
3566 mPerfCounters.shaderResourcesDescriptorSetCacheHits = 0;
3567 mPerfCounters.shaderResourcesDescriptorSetCacheMisses = 0;
3568 mPerfCounters.shaderResourcesDescriptorSetCacheTotalSize = 0;
3569 mPerfCounters.dynamicBufferAllocations = 0;
3570
3571 // Share group descriptor set allocations and caching stats.
3572 memset(mVulkanCacheStats.data(), 0, sizeof(CacheStats) * mVulkanCacheStats.size());
3573 if (getFeatures().descriptorSetCache.enabled)
3574 {
3575 mShareGroupVk->getMetaDescriptorPools()[DescriptorSetIndex::UniformsAndXfb]
3576 .accumulateDescriptorCacheStats(VulkanCacheType::UniformsAndXfbDescriptors, this);
3577 mShareGroupVk->getMetaDescriptorPools()[DescriptorSetIndex::Texture]
3578 .accumulateDescriptorCacheStats(VulkanCacheType::TextureDescriptors, this);
3579 mShareGroupVk->getMetaDescriptorPools()[DescriptorSetIndex::ShaderResource]
3580 .accumulateDescriptorCacheStats(VulkanCacheType::ShaderResourcesDescriptors, this);
3581
3582 const CacheStats &uniCacheStats =
3583 mVulkanCacheStats[VulkanCacheType::UniformsAndXfbDescriptors];
3584 mPerfCounters.uniformsAndXfbDescriptorSetCacheHits = uniCacheStats.getHitCount();
3585 mPerfCounters.uniformsAndXfbDescriptorSetCacheMisses = uniCacheStats.getMissCount();
3586 mPerfCounters.uniformsAndXfbDescriptorSetCacheTotalSize = uniCacheStats.getSize();
3587
3588 const CacheStats &texCacheStats = mVulkanCacheStats[VulkanCacheType::TextureDescriptors];
3589 mPerfCounters.textureDescriptorSetCacheHits = texCacheStats.getHitCount();
3590 mPerfCounters.textureDescriptorSetCacheMisses = texCacheStats.getMissCount();
3591 mPerfCounters.textureDescriptorSetCacheTotalSize = texCacheStats.getSize();
3592
3593 const CacheStats &resCacheStats =
3594 mVulkanCacheStats[VulkanCacheType::ShaderResourcesDescriptors];
3595 mPerfCounters.shaderResourcesDescriptorSetCacheHits = resCacheStats.getHitCount();
3596 mPerfCounters.shaderResourcesDescriptorSetCacheMisses = resCacheStats.getMissCount();
3597 mPerfCounters.shaderResourcesDescriptorSetCacheTotalSize = resCacheStats.getSize();
3598
3599 mPerfCounters.descriptorSetCacheTotalSize =
3600 uniCacheStats.getSize() + texCacheStats.getSize() + resCacheStats.getSize() +
3601 mVulkanCacheStats[VulkanCacheType::DriverUniformsDescriptors].getSize();
3602
3603 mPerfCounters.descriptorSetCacheKeySizeBytes = 0;
3604
3605 for (DescriptorSetIndex descriptorSetIndex : angle::AllEnums<DescriptorSetIndex>())
3606 {
3607 vk::MetaDescriptorPool &descriptorPool =
3608 mShareGroupVk->getMetaDescriptorPools()[descriptorSetIndex];
3609 mPerfCounters.descriptorSetCacheKeySizeBytes +=
3610 descriptorPool.getTotalCacheKeySizeBytes();
3611 }
3612 }
3613
3614 // Update perf counters from the renderer as well
3615 mPerfCounters.commandQueueSubmitCallsTotal =
3616 commandQueuePerfCounters.commandQueueSubmitCallsTotal;
3617 mPerfCounters.commandQueueSubmitCallsPerFrame =
3618 commandQueuePerfCounters.commandQueueSubmitCallsPerFrame;
3619 mPerfCounters.vkQueueSubmitCallsTotal = commandQueuePerfCounters.vkQueueSubmitCallsTotal;
3620 mPerfCounters.vkQueueSubmitCallsPerFrame = commandQueuePerfCounters.vkQueueSubmitCallsPerFrame;
3621 mPerfCounters.commandQueueWaitSemaphoresTotal =
3622 commandQueuePerfCounters.commandQueueWaitSemaphoresTotal;
3623
3624 // Return current drawFramebuffer's cache stats
3625 mPerfCounters.framebufferCacheSize = mShareGroupVk->getFramebufferCache().getSize();
3626
3627 mPerfCounters.pendingSubmissionGarbageObjects =
3628 static_cast<uint64_t>(mRenderer->getPendingSubmissionGarbageSize());
3629 }
3630
updateOverlayOnPresent()3631 void ContextVk::updateOverlayOnPresent()
3632 {
3633 const gl::OverlayType *overlay = mState.getOverlay();
3634 ASSERT(overlay->isEnabled());
3635
3636 angle::VulkanPerfCounters commandQueuePerfCounters = mRenderer->getCommandQueuePerfCounters();
3637 syncObjectPerfCounters(commandQueuePerfCounters);
3638
3639 // Update overlay if active.
3640 {
3641 gl::RunningGraphWidget *renderPassCount =
3642 overlay->getRunningGraphWidget(gl::WidgetId::VulkanRenderPassCount);
3643 renderPassCount->add(mRenderPassCommands->getAndResetCounter());
3644 renderPassCount->next();
3645 }
3646
3647 {
3648 gl::RunningGraphWidget *writeDescriptorSetCount =
3649 overlay->getRunningGraphWidget(gl::WidgetId::VulkanWriteDescriptorSetCount);
3650 writeDescriptorSetCount->add(mPerfCounters.writeDescriptorSets);
3651 writeDescriptorSetCount->next();
3652 }
3653
3654 {
3655 gl::RunningGraphWidget *descriptorSetAllocationCount =
3656 overlay->getRunningGraphWidget(gl::WidgetId::VulkanDescriptorSetAllocations);
3657 descriptorSetAllocationCount->add(mPerfCounters.descriptorSetAllocations);
3658 descriptorSetAllocationCount->next();
3659 }
3660
3661 {
3662 gl::RunningGraphWidget *shaderResourceHitRate =
3663 overlay->getRunningGraphWidget(gl::WidgetId::VulkanShaderResourceDSHitRate);
3664 uint64_t numCacheAccesses = mPerfCounters.shaderResourcesDescriptorSetCacheHits +
3665 mPerfCounters.shaderResourcesDescriptorSetCacheMisses;
3666 if (numCacheAccesses > 0)
3667 {
3668 float hitRateFloat =
3669 static_cast<float>(mPerfCounters.shaderResourcesDescriptorSetCacheHits) /
3670 static_cast<float>(numCacheAccesses);
3671 size_t hitRate = static_cast<size_t>(hitRateFloat * 100.0f);
3672 shaderResourceHitRate->add(hitRate);
3673 shaderResourceHitRate->next();
3674 }
3675 }
3676
3677 {
3678 gl::RunningGraphWidget *dynamicBufferAllocations =
3679 overlay->getRunningGraphWidget(gl::WidgetId::VulkanDynamicBufferAllocations);
3680 dynamicBufferAllocations->next();
3681 }
3682
3683 {
3684 gl::CountWidget *cacheKeySize =
3685 overlay->getCountWidget(gl::WidgetId::VulkanDescriptorCacheKeySize);
3686 cacheKeySize->reset();
3687 cacheKeySize->add(mPerfCounters.descriptorSetCacheKeySizeBytes);
3688 }
3689
3690 {
3691 gl::RunningGraphWidget *dynamicBufferAllocations =
3692 overlay->getRunningGraphWidget(gl::WidgetId::VulkanDynamicBufferAllocations);
3693 dynamicBufferAllocations->add(mPerfCounters.dynamicBufferAllocations);
3694 }
3695
3696 {
3697 gl::RunningGraphWidget *attemptedSubmissionsWidget =
3698 overlay->getRunningGraphWidget(gl::WidgetId::VulkanAttemptedSubmissions);
3699 attemptedSubmissionsWidget->add(commandQueuePerfCounters.commandQueueSubmitCallsPerFrame);
3700 attemptedSubmissionsWidget->next();
3701
3702 gl::RunningGraphWidget *actualSubmissionsWidget =
3703 overlay->getRunningGraphWidget(gl::WidgetId::VulkanActualSubmissions);
3704 actualSubmissionsWidget->add(commandQueuePerfCounters.vkQueueSubmitCallsPerFrame);
3705 actualSubmissionsWidget->next();
3706 }
3707
3708 {
3709 gl::RunningGraphWidget *cacheLookupsWidget =
3710 overlay->getRunningGraphWidget(gl::WidgetId::VulkanPipelineCacheLookups);
3711 cacheLookupsWidget->add(mPerfCounters.pipelineCreationCacheHits +
3712 mPerfCounters.pipelineCreationCacheMisses);
3713 cacheLookupsWidget->next();
3714
3715 gl::RunningGraphWidget *cacheMissesWidget =
3716 overlay->getRunningGraphWidget(gl::WidgetId::VulkanPipelineCacheMisses);
3717 cacheMissesWidget->add(mPerfCounters.pipelineCreationCacheMisses);
3718 cacheMissesWidget->next();
3719
3720 overlay->getCountWidget(gl::WidgetId::VulkanTotalPipelineCacheHitTimeMs)
3721 ->set(mPerfCounters.pipelineCreationTotalCacheHitsDurationNs / 1000'000);
3722 overlay->getCountWidget(gl::WidgetId::VulkanTotalPipelineCacheMissTimeMs)
3723 ->set(mPerfCounters.pipelineCreationTotalCacheMissesDurationNs / 1000'000);
3724 }
3725 }
3726
addOverlayUsedBuffersCount(vk::CommandBufferHelperCommon * commandBuffer)3727 void ContextVk::addOverlayUsedBuffersCount(vk::CommandBufferHelperCommon *commandBuffer)
3728 {
3729 const gl::OverlayType *overlay = mState.getOverlay();
3730 if (!overlay->isEnabled())
3731 {
3732 return;
3733 }
3734
3735 {
3736 gl::RunningGraphWidget *textureDescriptorCacheSize =
3737 overlay->getRunningGraphWidget(gl::WidgetId::VulkanTextureDescriptorCacheSize);
3738 textureDescriptorCacheSize->add(mPerfCounters.textureDescriptorSetCacheTotalSize);
3739 textureDescriptorCacheSize->next();
3740 }
3741
3742 {
3743 gl::RunningGraphWidget *uniformDescriptorCacheSize =
3744 overlay->getRunningGraphWidget(gl::WidgetId::VulkanUniformDescriptorCacheSize);
3745 uniformDescriptorCacheSize->add(mPerfCounters.uniformsAndXfbDescriptorSetCacheTotalSize);
3746 uniformDescriptorCacheSize->next();
3747 }
3748
3749 {
3750 gl::RunningGraphWidget *descriptorCacheSize =
3751 overlay->getRunningGraphWidget(gl::WidgetId::VulkanDescriptorCacheSize);
3752 descriptorCacheSize->add(mPerfCounters.descriptorSetCacheTotalSize);
3753 descriptorCacheSize->next();
3754 }
3755 }
3756
submitCommands(const vk::Semaphore * signalSemaphore,const vk::SharedExternalFence * externalFence,Submit submission)3757 angle::Result ContextVk::submitCommands(const vk::Semaphore *signalSemaphore,
3758 const vk::SharedExternalFence *externalFence,
3759 Submit submission)
3760 {
3761 if (kEnableCommandStreamDiagnostics)
3762 {
3763 dumpCommandStreamDiagnostics();
3764 }
3765
3766 if (!mCurrentGarbage.empty() && submission == Submit::AllCommands)
3767 {
3768 // Clean up garbage.
3769 vk::ResourceUse use(mLastFlushedQueueSerial);
3770 mRenderer->collectGarbage(use, std::move(mCurrentGarbage));
3771 }
3772
3773 ASSERT(mLastFlushedQueueSerial.valid());
3774 ASSERT(QueueSerialsHaveDifferentIndexOrSmaller(mLastSubmittedQueueSerial,
3775 mLastFlushedQueueSerial));
3776
3777 ANGLE_TRY(mRenderer->submitCommands(this, getProtectionType(), mContextPriority,
3778 signalSemaphore, externalFence, mLastFlushedQueueSerial));
3779
3780 mLastSubmittedQueueSerial = mLastFlushedQueueSerial;
3781 mSubmittedResourceUse.setQueueSerial(mLastSubmittedQueueSerial);
3782
3783 // Now that we have submitted commands, some of pending garbage may no longer pending
3784 // and should be moved to garbage list.
3785 mRenderer->cleanupPendingSubmissionGarbage();
3786 // In case of big amount of render/submission within one frame, if we accumulate excessive
3787 // amount of garbage, also trigger the cleanup.
3788 mShareGroupVk->cleanupExcessiveRefCountedEventGarbage();
3789
3790 mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
3791
3792 if (mGpuEventsEnabled)
3793 {
3794 ANGLE_TRY(checkCompletedGpuEvents());
3795 }
3796
3797 mTotalBufferToImageCopySize = 0;
3798 mEstimatedPendingImageGarbageSize = 0;
3799
3800 // If we have destroyed a lot of memory, also prune to ensure memory gets freed as soon as
3801 // possible. For example we may end here when game launches and uploads a lot of textures before
3802 // draw the first frame.
3803 if (mRenderer->getSuballocationDestroyedSize() >= kMaxTotalEmptyBufferBytes)
3804 {
3805 mShareGroupVk->pruneDefaultBufferPools();
3806 }
3807
3808 return angle::Result::Continue;
3809 }
3810
onCopyUpdate(VkDeviceSize size,bool * commandBufferWasFlushedOut)3811 angle::Result ContextVk::onCopyUpdate(VkDeviceSize size, bool *commandBufferWasFlushedOut)
3812 {
3813 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::onCopyUpdate");
3814 *commandBufferWasFlushedOut = false;
3815
3816 mTotalBufferToImageCopySize += size;
3817 // If the copy size exceeds the specified threshold, submit the outside command buffer.
3818 if (mTotalBufferToImageCopySize >= kMaxBufferToImageCopySize)
3819 {
3820 ANGLE_TRY(flushAndSubmitOutsideRenderPassCommands());
3821 *commandBufferWasFlushedOut = true;
3822 }
3823 return angle::Result::Continue;
3824 }
3825
addToPendingImageGarbage(vk::ResourceUse use,VkDeviceSize size)3826 void ContextVk::addToPendingImageGarbage(vk::ResourceUse use, VkDeviceSize size)
3827 {
3828 if (!mRenderer->hasResourceUseFinished(use))
3829 {
3830 mEstimatedPendingImageGarbageSize += size;
3831 }
3832 }
3833
hasExcessPendingGarbage() const3834 bool ContextVk::hasExcessPendingGarbage() const
3835 {
3836 VkDeviceSize trackedPendingGarbage =
3837 mRenderer->getPendingSuballocationGarbageSize() + mEstimatedPendingImageGarbageSize;
3838 return trackedPendingGarbage >= mRenderer->getPendingGarbageSizeLimit();
3839 }
3840
synchronizeCpuGpuTime()3841 angle::Result ContextVk::synchronizeCpuGpuTime()
3842 {
3843 ASSERT(mGpuEventsEnabled);
3844
3845 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
3846 ASSERT(platform);
3847
3848 // To synchronize CPU and GPU times, we need to get the CPU timestamp as close as possible
3849 // to the GPU timestamp. The process of getting the GPU timestamp is as follows:
3850 //
3851 // CPU GPU
3852 //
3853 // Record command buffer
3854 // with timestamp query
3855 //
3856 // Submit command buffer
3857 //
3858 // Post-submission work Begin execution
3859 //
3860 // ???? Write timestamp Tgpu
3861 //
3862 // ???? End execution
3863 //
3864 // ???? Return query results
3865 //
3866 // ????
3867 //
3868 // Get query results
3869 //
3870 // The areas of unknown work (????) on the CPU indicate that the CPU may or may not have
3871 // finished post-submission work while the GPU is executing in parallel. With no further
3872 // work, querying CPU timestamps before submission and after getting query results give the
3873 // bounds to Tgpu, which could be quite large.
3874 //
3875 // Using VkEvents, the GPU can be made to wait for the CPU and vice versa, in an effort to
3876 // reduce this range. This function implements the following procedure:
3877 //
3878 // CPU GPU
3879 //
3880 // Record command buffer
3881 // with timestamp query
3882 //
3883 // Submit command buffer
3884 //
3885 // Post-submission work Begin execution
3886 //
3887 // ???? Set Event GPUReady
3888 //
3889 // Wait on Event GPUReady Wait on Event CPUReady
3890 //
3891 // Get CPU Time Ts Wait on Event CPUReady
3892 //
3893 // Set Event CPUReady Wait on Event CPUReady
3894 //
3895 // Get CPU Time Tcpu Get GPU Time Tgpu
3896 //
3897 // Wait on Event GPUDone Set Event GPUDone
3898 //
3899 // Get CPU Time Te End Execution
3900 //
3901 // Idle Return query results
3902 //
3903 // Get query results
3904 //
3905 // If Te-Ts > epsilon, a GPU or CPU interruption can be assumed and the operation can be
3906 // retried. Once Te-Ts < epsilon, Tcpu can be taken to presumably match Tgpu. Finding an
3907 // epsilon that's valid for all devices may be difficult, so the loop can be performed only
3908 // a limited number of times and the Tcpu,Tgpu pair corresponding to smallest Te-Ts used for
3909 // calibration.
3910 //
3911 // Note: Once VK_EXT_calibrated_timestamps is ubiquitous, this should be redone.
3912
3913 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::synchronizeCpuGpuTime");
3914
3915 // Create a query used to receive the GPU timestamp
3916 vk::QueryHelper timestampQuery;
3917 ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, ×tampQuery, 1));
3918
3919 // Create the three events
3920 VkEventCreateInfo eventCreateInfo = {};
3921 eventCreateInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
3922 eventCreateInfo.flags = 0;
3923
3924 VkDevice device = getDevice();
3925 vk::DeviceScoped<vk::Event> cpuReady(device), gpuReady(device), gpuDone(device);
3926 ANGLE_VK_TRY(this, cpuReady.get().init(device, eventCreateInfo));
3927 ANGLE_VK_TRY(this, gpuReady.get().init(device, eventCreateInfo));
3928 ANGLE_VK_TRY(this, gpuDone.get().init(device, eventCreateInfo));
3929
3930 constexpr uint32_t kRetries = 10;
3931
3932 // Time suffixes used are S for seconds and Cycles for cycles
3933 double tightestRangeS = 1e6f;
3934 double TcpuS = 0;
3935 uint64_t TgpuCycles = 0;
3936 for (uint32_t i = 0; i < kRetries; ++i)
3937 {
3938 // Reset the events
3939 ANGLE_VK_TRY(this, cpuReady.get().reset(device));
3940 ANGLE_VK_TRY(this, gpuReady.get().reset(device));
3941 ANGLE_VK_TRY(this, gpuDone.get().reset(device));
3942
3943 // Record the command buffer
3944 vk::DeviceScoped<vk::PrimaryCommandBuffer> commandBatch(device);
3945 vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
3946
3947 ANGLE_TRY(mRenderer->getCommandBufferOneOff(this, getProtectionType(), &commandBuffer));
3948
3949 commandBuffer.setEvent(gpuReady.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
3950 commandBuffer.waitEvents(1, cpuReady.get().ptr(), VK_PIPELINE_STAGE_HOST_BIT,
3951 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, nullptr, 0, nullptr, 0,
3952 nullptr);
3953 timestampQuery.writeTimestampToPrimary(this, &commandBuffer);
3954
3955 commandBuffer.setEvent(gpuDone.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
3956
3957 ANGLE_VK_TRY(this, commandBuffer.end());
3958
3959 QueueSerial submitSerial;
3960 // vkEvent's are externally synchronized, therefore need work to be submitted before calling
3961 // vkGetEventStatus
3962 ANGLE_TRY(mRenderer->queueSubmitOneOff(this, std::move(commandBuffer), getProtectionType(),
3963 mContextPriority, VK_NULL_HANDLE, 0,
3964 vk::SubmitPolicy::EnsureSubmitted, &submitSerial));
3965
3966 // Track it with the submitSerial.
3967 timestampQuery.setQueueSerial(submitSerial);
3968
3969 // Wait for GPU to be ready. This is a short busy wait.
3970 VkResult result = VK_EVENT_RESET;
3971 do
3972 {
3973 result = gpuReady.get().getStatus(device);
3974 if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
3975 {
3976 ANGLE_VK_TRY(this, result);
3977 }
3978 } while (result == VK_EVENT_RESET);
3979
3980 double TsS = platform->monotonicallyIncreasingTime(platform);
3981
3982 // Tell the GPU to go ahead with the timestamp query.
3983 ANGLE_VK_TRY(this, cpuReady.get().set(device));
3984 double cpuTimestampS = platform->monotonicallyIncreasingTime(platform);
3985
3986 // Wait for GPU to be done. Another short busy wait.
3987 do
3988 {
3989 result = gpuDone.get().getStatus(device);
3990 if (result != VK_EVENT_SET && result != VK_EVENT_RESET)
3991 {
3992 ANGLE_VK_TRY(this, result);
3993 }
3994 } while (result == VK_EVENT_RESET);
3995
3996 double TeS = platform->monotonicallyIncreasingTime(platform);
3997
3998 // Get the query results
3999 ANGLE_TRY(mRenderer->finishQueueSerial(this, submitSerial));
4000
4001 vk::QueryResult gpuTimestampCycles(1);
4002 ANGLE_TRY(timestampQuery.getUint64Result(this, &gpuTimestampCycles));
4003
4004 // Use the first timestamp queried as origin.
4005 if (mGpuEventTimestampOrigin == 0)
4006 {
4007 mGpuEventTimestampOrigin =
4008 gpuTimestampCycles.getResult(vk::QueryResult::kDefaultResultIndex);
4009 }
4010
4011 // Take these CPU and GPU timestamps if there is better confidence.
4012 double confidenceRangeS = TeS - TsS;
4013 if (confidenceRangeS < tightestRangeS)
4014 {
4015 tightestRangeS = confidenceRangeS;
4016 TcpuS = cpuTimestampS;
4017 TgpuCycles = gpuTimestampCycles.getResult(vk::QueryResult::kDefaultResultIndex);
4018 }
4019 }
4020
4021 mGpuEventQueryPool.freeQuery(this, ×tampQuery);
4022
4023 // timestampPeriod gives nanoseconds/cycle.
4024 double TgpuS =
4025 (TgpuCycles - mGpuEventTimestampOrigin) *
4026 static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod) /
4027 1'000'000'000.0;
4028
4029 flushGpuEvents(TgpuS, TcpuS);
4030
4031 mGpuClockSync.gpuTimestampS = TgpuS;
4032 mGpuClockSync.cpuTimestampS = TcpuS;
4033
4034 return angle::Result::Continue;
4035 }
4036
traceGpuEventImpl(vk::OutsideRenderPassCommandBuffer * commandBuffer,char phase,const EventName & name)4037 angle::Result ContextVk::traceGpuEventImpl(vk::OutsideRenderPassCommandBuffer *commandBuffer,
4038 char phase,
4039 const EventName &name)
4040 {
4041 ASSERT(mGpuEventsEnabled);
4042
4043 GpuEventQuery gpuEvent;
4044 gpuEvent.name = name;
4045 gpuEvent.phase = phase;
4046 ANGLE_TRY(mGpuEventQueryPool.allocateQuery(this, &gpuEvent.queryHelper, 1));
4047
4048 gpuEvent.queryHelper.writeTimestamp(this, commandBuffer);
4049
4050 mInFlightGpuEventQueries.push_back(std::move(gpuEvent));
4051 return angle::Result::Continue;
4052 }
4053
checkCompletedGpuEvents()4054 angle::Result ContextVk::checkCompletedGpuEvents()
4055 {
4056 ASSERT(mGpuEventsEnabled);
4057
4058 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
4059 ASSERT(platform);
4060
4061 int finishedCount = 0;
4062
4063 for (GpuEventQuery &eventQuery : mInFlightGpuEventQueries)
4064 {
4065 ASSERT(mRenderer->hasResourceUseSubmitted(eventQuery.queryHelper.getResourceUse()));
4066 // Only check the timestamp query if the submission has finished.
4067 if (!mRenderer->hasResourceUseFinished(eventQuery.queryHelper.getResourceUse()))
4068 {
4069 break;
4070 }
4071
4072 // See if the results are available.
4073 vk::QueryResult gpuTimestampCycles(1);
4074 bool available = false;
4075 ANGLE_TRY(eventQuery.queryHelper.getUint64ResultNonBlocking(this, &gpuTimestampCycles,
4076 &available));
4077 if (!available)
4078 {
4079 break;
4080 }
4081
4082 mGpuEventQueryPool.freeQuery(this, &eventQuery.queryHelper);
4083
4084 GpuEvent gpuEvent;
4085 gpuEvent.gpuTimestampCycles =
4086 gpuTimestampCycles.getResult(vk::QueryResult::kDefaultResultIndex);
4087 gpuEvent.name = eventQuery.name;
4088 gpuEvent.phase = eventQuery.phase;
4089
4090 mGpuEvents.emplace_back(gpuEvent);
4091
4092 ++finishedCount;
4093 }
4094
4095 mInFlightGpuEventQueries.erase(mInFlightGpuEventQueries.begin(),
4096 mInFlightGpuEventQueries.begin() + finishedCount);
4097
4098 return angle::Result::Continue;
4099 }
4100
flushGpuEvents(double nextSyncGpuTimestampS,double nextSyncCpuTimestampS)4101 void ContextVk::flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuTimestampS)
4102 {
4103 if (mGpuEvents.empty())
4104 {
4105 return;
4106 }
4107
4108 angle::PlatformMethods *platform = ANGLEPlatformCurrent();
4109 ASSERT(platform);
4110
4111 // Find the slope of the clock drift for adjustment
4112 double lastGpuSyncTimeS = mGpuClockSync.gpuTimestampS;
4113 double lastGpuSyncDiffS = mGpuClockSync.cpuTimestampS - mGpuClockSync.gpuTimestampS;
4114 double gpuSyncDriftSlope = 0;
4115
4116 double nextGpuSyncTimeS = nextSyncGpuTimestampS;
4117 double nextGpuSyncDiffS = nextSyncCpuTimestampS - nextSyncGpuTimestampS;
4118
4119 // No gpu trace events should have been generated before the clock sync, so if there is no
4120 // "previous" clock sync, there should be no gpu events (i.e. the function early-outs
4121 // above).
4122 ASSERT(mGpuClockSync.gpuTimestampS != std::numeric_limits<double>::max() &&
4123 mGpuClockSync.cpuTimestampS != std::numeric_limits<double>::max());
4124
4125 gpuSyncDriftSlope =
4126 (nextGpuSyncDiffS - lastGpuSyncDiffS) / (nextGpuSyncTimeS - lastGpuSyncTimeS);
4127
4128 for (const GpuEvent &gpuEvent : mGpuEvents)
4129 {
4130 double gpuTimestampS =
4131 (gpuEvent.gpuTimestampCycles - mGpuEventTimestampOrigin) *
4132 static_cast<double>(
4133 getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod) *
4134 1e-9;
4135
4136 // Account for clock drift.
4137 gpuTimestampS += lastGpuSyncDiffS + gpuSyncDriftSlope * (gpuTimestampS - lastGpuSyncTimeS);
4138
4139 // Generate the trace now that the GPU timestamp is available and clock drifts are
4140 // accounted for.
4141 static long long eventId = 1;
4142 static const unsigned char *categoryEnabled =
4143 TRACE_EVENT_API_GET_CATEGORY_ENABLED(platform, "gpu.angle.gpu");
4144 platform->addTraceEvent(platform, gpuEvent.phase, categoryEnabled, gpuEvent.name.data(),
4145 eventId++, gpuTimestampS, 0, nullptr, nullptr, nullptr,
4146 TRACE_EVENT_FLAG_NONE);
4147 }
4148
4149 mGpuEvents.clear();
4150 }
4151
clearAllGarbage()4152 void ContextVk::clearAllGarbage()
4153 {
4154 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::clearAllGarbage");
4155
4156 // The VMA virtual allocator code has assertion to ensure all sub-ranges are freed before
4157 // virtual block gets freed. We need to ensure all completed garbage objects are actually freed
4158 // to avoid hitting that assertion.
4159 mRenderer->cleanupGarbage(nullptr);
4160
4161 for (vk::GarbageObject &garbage : mCurrentGarbage)
4162 {
4163 garbage.destroy(mRenderer);
4164 }
4165 mCurrentGarbage.clear();
4166 }
4167
handleDeviceLost()4168 void ContextVk::handleDeviceLost()
4169 {
4170 vk::SecondaryCommandBufferCollector collector;
4171 (void)mOutsideRenderPassCommands->reset(this, &collector);
4172 (void)mRenderPassCommands->reset(this, &collector);
4173 collector.releaseCommandBuffers();
4174
4175 mRenderer->notifyDeviceLost();
4176 }
4177
drawArrays(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count)4178 angle::Result ContextVk::drawArrays(const gl::Context *context,
4179 gl::PrimitiveMode mode,
4180 GLint first,
4181 GLsizei count)
4182 {
4183 uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
4184
4185 if (mode == gl::PrimitiveMode::LineLoop)
4186 {
4187 uint32_t numIndices;
4188 ANGLE_TRY(setupLineLoopDraw(context, mode, first, count, gl::DrawElementsType::InvalidEnum,
4189 nullptr, &numIndices));
4190 LineLoopHelper::Draw(numIndices, 0, mRenderPassCommandBuffer);
4191 }
4192 else
4193 {
4194 ANGLE_TRY(setupDraw(context, mode, first, count, 1, gl::DrawElementsType::InvalidEnum,
4195 nullptr, mNonIndexedDirtyBitsMask));
4196 mRenderPassCommandBuffer->draw(clampedVertexCount, first);
4197 }
4198
4199 return angle::Result::Continue;
4200 }
4201
drawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances)4202 angle::Result ContextVk::drawArraysInstanced(const gl::Context *context,
4203 gl::PrimitiveMode mode,
4204 GLint first,
4205 GLsizei count,
4206 GLsizei instances)
4207 {
4208 if (mode == gl::PrimitiveMode::LineLoop)
4209 {
4210 uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
4211 uint32_t numIndices;
4212 ANGLE_TRY(setupLineLoopDraw(context, mode, first, clampedVertexCount,
4213 gl::DrawElementsType::InvalidEnum, nullptr, &numIndices));
4214 mRenderPassCommandBuffer->drawIndexedInstanced(numIndices, instances);
4215 return angle::Result::Continue;
4216 }
4217
4218 ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
4219 nullptr, mNonIndexedDirtyBitsMask));
4220 mRenderPassCommandBuffer->drawInstanced(gl::GetClampedVertexCount<uint32_t>(count), instances,
4221 first);
4222 return angle::Result::Continue;
4223 }
4224
drawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances,GLuint baseInstance)4225 angle::Result ContextVk::drawArraysInstancedBaseInstance(const gl::Context *context,
4226 gl::PrimitiveMode mode,
4227 GLint first,
4228 GLsizei count,
4229 GLsizei instances,
4230 GLuint baseInstance)
4231 {
4232 if (mode == gl::PrimitiveMode::LineLoop)
4233 {
4234 uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
4235 uint32_t numIndices;
4236 ANGLE_TRY(setupLineLoopDraw(context, mode, first, clampedVertexCount,
4237 gl::DrawElementsType::InvalidEnum, nullptr, &numIndices));
4238 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertexBaseInstance(numIndices, instances,
4239 0, 0, baseInstance);
4240 return angle::Result::Continue;
4241 }
4242
4243 ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
4244 nullptr, mNonIndexedDirtyBitsMask));
4245 mRenderPassCommandBuffer->drawInstancedBaseInstance(gl::GetClampedVertexCount<uint32_t>(count),
4246 instances, first, baseInstance);
4247 return angle::Result::Continue;
4248 }
4249
drawElements(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices)4250 angle::Result ContextVk::drawElements(const gl::Context *context,
4251 gl::PrimitiveMode mode,
4252 GLsizei count,
4253 gl::DrawElementsType type,
4254 const void *indices)
4255 {
4256 if (mode == gl::PrimitiveMode::LineLoop)
4257 {
4258 uint32_t indexCount;
4259 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
4260 LineLoopHelper::Draw(indexCount, 0, mRenderPassCommandBuffer);
4261 }
4262 else
4263 {
4264 ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices));
4265 mRenderPassCommandBuffer->drawIndexed(count);
4266 }
4267
4268 return angle::Result::Continue;
4269 }
4270
drawElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)4271 angle::Result ContextVk::drawElementsBaseVertex(const gl::Context *context,
4272 gl::PrimitiveMode mode,
4273 GLsizei count,
4274 gl::DrawElementsType type,
4275 const void *indices,
4276 GLint baseVertex)
4277 {
4278 if (mode == gl::PrimitiveMode::LineLoop)
4279 {
4280 uint32_t indexCount;
4281 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
4282 LineLoopHelper::Draw(indexCount, baseVertex, mRenderPassCommandBuffer);
4283 }
4284 else
4285 {
4286 ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices));
4287 mRenderPassCommandBuffer->drawIndexedBaseVertex(count, baseVertex);
4288 }
4289
4290 return angle::Result::Continue;
4291 }
4292
drawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances)4293 angle::Result ContextVk::drawElementsInstanced(const gl::Context *context,
4294 gl::PrimitiveMode mode,
4295 GLsizei count,
4296 gl::DrawElementsType type,
4297 const void *indices,
4298 GLsizei instances)
4299 {
4300 if (mode == gl::PrimitiveMode::LineLoop)
4301 {
4302 uint32_t indexCount;
4303 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
4304 count = indexCount;
4305 }
4306 else
4307 {
4308 ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices));
4309 }
4310
4311 mRenderPassCommandBuffer->drawIndexedInstanced(count, instances);
4312 return angle::Result::Continue;
4313 }
4314
drawElementsInstancedBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex)4315 angle::Result ContextVk::drawElementsInstancedBaseVertex(const gl::Context *context,
4316 gl::PrimitiveMode mode,
4317 GLsizei count,
4318 gl::DrawElementsType type,
4319 const void *indices,
4320 GLsizei instances,
4321 GLint baseVertex)
4322 {
4323 if (mode == gl::PrimitiveMode::LineLoop)
4324 {
4325 uint32_t indexCount;
4326 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
4327 count = indexCount;
4328 }
4329 else
4330 {
4331 ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices));
4332 }
4333
4334 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertex(count, instances, baseVertex);
4335 return angle::Result::Continue;
4336 }
4337
drawElementsInstancedBaseVertexBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances,GLint baseVertex,GLuint baseInstance)4338 angle::Result ContextVk::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context,
4339 gl::PrimitiveMode mode,
4340 GLsizei count,
4341 gl::DrawElementsType type,
4342 const void *indices,
4343 GLsizei instances,
4344 GLint baseVertex,
4345 GLuint baseInstance)
4346 {
4347 if (mode == gl::PrimitiveMode::LineLoop)
4348 {
4349 uint32_t indexCount;
4350 ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &indexCount));
4351 count = indexCount;
4352 }
4353 else
4354 {
4355 ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices));
4356 }
4357
4358 mRenderPassCommandBuffer->drawIndexedInstancedBaseVertexBaseInstance(count, instances, 0,
4359 baseVertex, baseInstance);
4360 return angle::Result::Continue;
4361 }
4362
drawRangeElements(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices)4363 angle::Result ContextVk::drawRangeElements(const gl::Context *context,
4364 gl::PrimitiveMode mode,
4365 GLuint start,
4366 GLuint end,
4367 GLsizei count,
4368 gl::DrawElementsType type,
4369 const void *indices)
4370 {
4371 return drawElements(context, mode, count, type, indices);
4372 }
4373
drawRangeElementsBaseVertex(const gl::Context * context,gl::PrimitiveMode mode,GLuint start,GLuint end,GLsizei count,gl::DrawElementsType type,const void * indices,GLint baseVertex)4374 angle::Result ContextVk::drawRangeElementsBaseVertex(const gl::Context *context,
4375 gl::PrimitiveMode mode,
4376 GLuint start,
4377 GLuint end,
4378 GLsizei count,
4379 gl::DrawElementsType type,
4380 const void *indices,
4381 GLint baseVertex)
4382 {
4383 return drawElementsBaseVertex(context, mode, count, type, indices, baseVertex);
4384 }
4385
getDevice() const4386 VkDevice ContextVk::getDevice() const
4387 {
4388 return mRenderer->getDevice();
4389 }
4390
drawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect)4391 angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
4392 gl::PrimitiveMode mode,
4393 const void *indirect)
4394 {
4395 return multiDrawArraysIndirectHelper(context, mode, indirect, 1, 0);
4396 }
4397
drawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect)4398 angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
4399 gl::PrimitiveMode mode,
4400 gl::DrawElementsType type,
4401 const void *indirect)
4402 {
4403 return multiDrawElementsIndirectHelper(context, mode, type, indirect, 1, 0);
4404 }
4405
multiDrawArrays(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,GLsizei drawcount)4406 angle::Result ContextVk::multiDrawArrays(const gl::Context *context,
4407 gl::PrimitiveMode mode,
4408 const GLint *firsts,
4409 const GLsizei *counts,
4410 GLsizei drawcount)
4411 {
4412 return rx::MultiDrawArraysGeneral(this, context, mode, firsts, counts, drawcount);
4413 }
4414
multiDrawArraysInstanced(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,GLsizei drawcount)4415 angle::Result ContextVk::multiDrawArraysInstanced(const gl::Context *context,
4416 gl::PrimitiveMode mode,
4417 const GLint *firsts,
4418 const GLsizei *counts,
4419 const GLsizei *instanceCounts,
4420 GLsizei drawcount)
4421 {
4422 return rx::MultiDrawArraysInstancedGeneral(this, context, mode, firsts, counts, instanceCounts,
4423 drawcount);
4424 }
4425
multiDrawArraysIndirect(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect,GLsizei drawcount,GLsizei stride)4426 angle::Result ContextVk::multiDrawArraysIndirect(const gl::Context *context,
4427 gl::PrimitiveMode mode,
4428 const void *indirect,
4429 GLsizei drawcount,
4430 GLsizei stride)
4431 {
4432 return multiDrawArraysIndirectHelper(context, mode, indirect, drawcount, stride);
4433 }
4434
multiDrawArraysIndirectHelper(const gl::Context * context,gl::PrimitiveMode mode,const void * indirect,GLsizei drawcount,GLsizei stride)4435 angle::Result ContextVk::multiDrawArraysIndirectHelper(const gl::Context *context,
4436 gl::PrimitiveMode mode,
4437 const void *indirect,
4438 GLsizei drawcount,
4439 GLsizei stride)
4440 {
4441 VertexArrayVk *vertexArrayVk = getVertexArray();
4442 if (drawcount > 1 && !CanMultiDrawIndirectUseCmd(this, vertexArrayVk, mode, drawcount, stride))
4443 {
4444 return rx::MultiDrawArraysIndirectGeneral(this, context, mode, indirect, drawcount, stride);
4445 }
4446
4447 // Stride must be a multiple of the size of VkDrawIndirectCommand (stride = 0 is invalid when
4448 // drawcount > 1).
4449 uint32_t vkStride = (stride == 0 && drawcount > 1) ? sizeof(VkDrawIndirectCommand) : stride;
4450
4451 gl::Buffer *indirectBuffer = mState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
4452 vk::BufferHelper *currentIndirectBuf = &vk::GetImpl(indirectBuffer)->getBuffer();
4453 VkDeviceSize currentIndirectBufOffset = reinterpret_cast<VkDeviceSize>(indirect);
4454
4455 if (vertexArrayVk->getStreamingVertexAttribsMask().any())
4456 {
4457 // Handling instanced vertex attributes is not covered for drawcount > 1.
4458 ASSERT(drawcount <= 1);
4459
4460 // We have instanced vertex attributes that need to be emulated for Vulkan.
4461 // invalidate any cache and map the buffer so that we can read the indirect data.
4462 // Mapping the buffer will cause a flush.
4463 ANGLE_TRY(currentIndirectBuf->invalidate(mRenderer, 0, sizeof(VkDrawIndirectCommand)));
4464 uint8_t *buffPtr;
4465 ANGLE_TRY(currentIndirectBuf->map(this, &buffPtr));
4466 const VkDrawIndirectCommand *indirectData =
4467 reinterpret_cast<VkDrawIndirectCommand *>(buffPtr + currentIndirectBufOffset);
4468
4469 ANGLE_TRY(drawArraysInstanced(context, mode, indirectData->firstVertex,
4470 indirectData->vertexCount, indirectData->instanceCount));
4471
4472 currentIndirectBuf->unmap(mRenderer);
4473 return angle::Result::Continue;
4474 }
4475
4476 if (mode == gl::PrimitiveMode::LineLoop)
4477 {
4478 // Line loop only supports handling at most one indirect parameter.
4479 ASSERT(drawcount <= 1);
4480
4481 ASSERT(indirectBuffer);
4482 vk::BufferHelper *dstIndirectBuf = nullptr;
4483
4484 ANGLE_TRY(setupLineLoopIndirectDraw(context, mode, currentIndirectBuf,
4485 currentIndirectBufOffset, &dstIndirectBuf));
4486
4487 mRenderPassCommandBuffer->drawIndexedIndirect(
4488 dstIndirectBuf->getBuffer(), dstIndirectBuf->getOffset(), drawcount, vkStride);
4489 return angle::Result::Continue;
4490 }
4491
4492 ANGLE_TRY(setupIndirectDraw(context, mode, mNonIndexedDirtyBitsMask, currentIndirectBuf));
4493
4494 mRenderPassCommandBuffer->drawIndirect(
4495 currentIndirectBuf->getBuffer(), currentIndirectBuf->getOffset() + currentIndirectBufOffset,
4496 drawcount, vkStride);
4497
4498 return angle::Result::Continue;
4499 }
4500
multiDrawElements(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,GLsizei drawcount)4501 angle::Result ContextVk::multiDrawElements(const gl::Context *context,
4502 gl::PrimitiveMode mode,
4503 const GLsizei *counts,
4504 gl::DrawElementsType type,
4505 const GLvoid *const *indices,
4506 GLsizei drawcount)
4507 {
4508 return rx::MultiDrawElementsGeneral(this, context, mode, counts, type, indices, drawcount);
4509 }
4510
multiDrawElementsInstanced(const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,GLsizei drawcount)4511 angle::Result ContextVk::multiDrawElementsInstanced(const gl::Context *context,
4512 gl::PrimitiveMode mode,
4513 const GLsizei *counts,
4514 gl::DrawElementsType type,
4515 const GLvoid *const *indices,
4516 const GLsizei *instanceCounts,
4517 GLsizei drawcount)
4518 {
4519 return rx::MultiDrawElementsInstancedGeneral(this, context, mode, counts, type, indices,
4520 instanceCounts, drawcount);
4521 }
4522
multiDrawElementsIndirect(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect,GLsizei drawcount,GLsizei stride)4523 angle::Result ContextVk::multiDrawElementsIndirect(const gl::Context *context,
4524 gl::PrimitiveMode mode,
4525 gl::DrawElementsType type,
4526 const void *indirect,
4527 GLsizei drawcount,
4528 GLsizei stride)
4529 {
4530 return multiDrawElementsIndirectHelper(context, mode, type, indirect, drawcount, stride);
4531 }
4532
multiDrawElementsIndirectHelper(const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect,GLsizei drawcount,GLsizei stride)4533 angle::Result ContextVk::multiDrawElementsIndirectHelper(const gl::Context *context,
4534 gl::PrimitiveMode mode,
4535 gl::DrawElementsType type,
4536 const void *indirect,
4537 GLsizei drawcount,
4538 GLsizei stride)
4539 {
4540 VertexArrayVk *vertexArrayVk = getVertexArray();
4541 if (drawcount > 1 && !CanMultiDrawIndirectUseCmd(this, vertexArrayVk, mode, drawcount, stride))
4542 {
4543 return rx::MultiDrawElementsIndirectGeneral(this, context, mode, type, indirect, drawcount,
4544 stride);
4545 }
4546
4547 // Stride must be a multiple of the size of VkDrawIndexedIndirectCommand (stride = 0 is invalid
4548 // when drawcount > 1).
4549 uint32_t vkStride =
4550 (stride == 0 && drawcount > 1) ? sizeof(VkDrawIndexedIndirectCommand) : stride;
4551
4552 gl::Buffer *indirectBuffer = mState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
4553 ASSERT(indirectBuffer);
4554 vk::BufferHelper *currentIndirectBuf = &vk::GetImpl(indirectBuffer)->getBuffer();
4555 VkDeviceSize currentIndirectBufOffset = reinterpret_cast<VkDeviceSize>(indirect);
4556
4557 // Reset the index buffer offset
4558 mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
4559 mCurrentIndexBufferOffset = 0;
4560
4561 if (vertexArrayVk->getStreamingVertexAttribsMask().any())
4562 {
4563 // Handling instanced vertex attributes is not covered for drawcount > 1.
4564 ASSERT(drawcount <= 1);
4565
4566 // We have instanced vertex attributes that need to be emulated for Vulkan.
4567 // invalidate any cache and map the buffer so that we can read the indirect data.
4568 // Mapping the buffer will cause a flush.
4569 ANGLE_TRY(
4570 currentIndirectBuf->invalidate(mRenderer, 0, sizeof(VkDrawIndexedIndirectCommand)));
4571 uint8_t *buffPtr;
4572 ANGLE_TRY(currentIndirectBuf->map(this, &buffPtr));
4573 const VkDrawIndexedIndirectCommand *indirectData =
4574 reinterpret_cast<VkDrawIndexedIndirectCommand *>(buffPtr + currentIndirectBufOffset);
4575
4576 ANGLE_TRY(drawElementsInstanced(context, mode, indirectData->indexCount, type, nullptr,
4577 indirectData->instanceCount));
4578
4579 currentIndirectBuf->unmap(mRenderer);
4580 return angle::Result::Continue;
4581 }
4582
4583 if (shouldConvertUint8VkIndexType(type) && mGraphicsDirtyBits[DIRTY_BIT_INDEX_BUFFER])
4584 {
4585 ANGLE_VK_PERF_WARNING(
4586 this, GL_DEBUG_SEVERITY_LOW,
4587 "Potential inefficiency emulating uint8 vertex attributes due to lack "
4588 "of hardware support");
4589
4590 ANGLE_TRY(vertexArrayVk->convertIndexBufferIndirectGPU(
4591 this, currentIndirectBuf, currentIndirectBufOffset, ¤tIndirectBuf));
4592 currentIndirectBufOffset = 0;
4593 }
4594
4595 // If the line-loop handling function modifies the element array buffer in the vertex array,
4596 // there is a possibility that the modified version is used as a source for the next line-loop
4597 // draw, which can lead to errors. To avoid this, a local index buffer pointer is used to pass
4598 // the current index buffer (after translation, in case it is needed) and use the resulting
4599 // index buffer for draw.
4600 vk::BufferHelper *currentIndexBuf = vertexArrayVk->getCurrentElementArrayBuffer();
4601 if (mode == gl::PrimitiveMode::LineLoop)
4602 {
4603 // Line loop only supports handling at most one indirect parameter.
4604 ASSERT(drawcount <= 1);
4605 ANGLE_TRY(setupLineLoopIndexedIndirectDraw(context, mode, type, currentIndexBuf,
4606 currentIndirectBuf, currentIndirectBufOffset,
4607 ¤tIndirectBuf));
4608 currentIndirectBufOffset = 0;
4609 }
4610 else
4611 {
4612 ANGLE_TRY(setupIndexedIndirectDraw(context, mode, type, currentIndirectBuf));
4613 }
4614
4615 mRenderPassCommandBuffer->drawIndexedIndirect(
4616 currentIndirectBuf->getBuffer(), currentIndirectBuf->getOffset() + currentIndirectBufOffset,
4617 drawcount, vkStride);
4618
4619 return angle::Result::Continue;
4620 }
4621
multiDrawArraysInstancedBaseInstance(const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,const GLuint * baseInstances,GLsizei drawcount)4622 angle::Result ContextVk::multiDrawArraysInstancedBaseInstance(const gl::Context *context,
4623 gl::PrimitiveMode mode,
4624 const GLint *firsts,
4625 const GLsizei *counts,
4626 const GLsizei *instanceCounts,
4627 const GLuint *baseInstances,
4628 GLsizei drawcount)
4629 {
4630 return rx::MultiDrawArraysInstancedBaseInstanceGeneral(
4631 this, context, mode, firsts, counts, instanceCounts, baseInstances, drawcount);
4632 }
4633
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)4634 angle::Result ContextVk::multiDrawElementsInstancedBaseVertexBaseInstance(
4635 const gl::Context *context,
4636 gl::PrimitiveMode mode,
4637 const GLsizei *counts,
4638 gl::DrawElementsType type,
4639 const GLvoid *const *indices,
4640 const GLsizei *instanceCounts,
4641 const GLint *baseVertices,
4642 const GLuint *baseInstances,
4643 GLsizei drawcount)
4644 {
4645 return rx::MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral(
4646 this, context, mode, counts, type, indices, instanceCounts, baseVertices, baseInstances,
4647 drawcount);
4648 }
4649
optimizeRenderPassForPresent(vk::ImageViewHelper * colorImageView,vk::ImageHelper * colorImage,vk::ImageHelper * colorImageMS,vk::PresentMode presentMode,bool * imageResolved)4650 angle::Result ContextVk::optimizeRenderPassForPresent(vk::ImageViewHelper *colorImageView,
4651 vk::ImageHelper *colorImage,
4652 vk::ImageHelper *colorImageMS,
4653 vk::PresentMode presentMode,
4654 bool *imageResolved)
4655 {
4656 // Note: mRenderPassCommandBuffer may be nullptr because the render pass is marked for closure.
4657 // That doesn't matter and the render pass can continue to be modified. This function shouldn't
4658 // rely on mRenderPassCommandBuffer.
4659
4660 // The caller must have verified this is the right render pass by calling
4661 // |hasStartedRenderPassWithSwapchainFramebuffer()|.
4662 ASSERT(mRenderPassCommands->started());
4663
4664 // EGL1.5 spec: The contents of ancillary buffers are always undefined after calling
4665 // eglSwapBuffers
4666 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
4667 RenderTargetVk *depthStencilRenderTarget = drawFramebufferVk->getDepthStencilRenderTarget();
4668 if (depthStencilRenderTarget != nullptr)
4669 {
4670 // Change depth/stencil attachment storeOp to DONT_CARE
4671 const gl::DepthStencilState &dsState = mState.getDepthStencilState();
4672 mRenderPassCommands->invalidateRenderPassDepthAttachment(
4673 dsState, mRenderPassCommands->getRenderArea());
4674 mRenderPassCommands->invalidateRenderPassStencilAttachment(
4675 dsState, mState.getDrawFramebuffer()->getStencilBitCount(),
4676 mRenderPassCommands->getRenderArea());
4677 }
4678
4679 // Use finalLayout instead of extra barrier for layout change to present
4680 if (colorImage != nullptr && getFeatures().supportsPresentation.enabled)
4681 {
4682 mRenderPassCommands->setImageOptimizeForPresent(colorImage);
4683 }
4684
4685 // Resolve the multisample image
4686 vk::RenderPassCommandBufferHelper &commandBufferHelper = getStartedRenderPassCommands();
4687 gl::Rectangle renderArea = commandBufferHelper.getRenderArea();
4688 const gl::Rectangle invalidateArea(0, 0, colorImageMS->getRotatedExtents().width,
4689 colorImageMS->getRotatedExtents().height);
4690 if (colorImageMS->valid() && renderArea == invalidateArea)
4691 {
4692 // Due to lack of support for GL_MESA_framebuffer_flip_y, it is currently impossible for the
4693 // application to resolve the default framebuffer into an FBO with a resolve attachment. If
4694 // that is ever supported, the path that adds the resolve attachment would invalidate the
4695 // framebuffer that the render pass holds on to, in which case this function is not called.
4696 // Either way, there cannot be a resolve attachment here already.
4697 ASSERT(!mRenderPassCommands->getFramebuffer().hasColorResolveAttachment(0));
4698
4699 // Add the resolve attachment to the render pass
4700 const vk::ImageView *resolveImageView = nullptr;
4701 ANGLE_TRY(colorImageView->getLevelLayerDrawImageView(this, *colorImage, vk::LevelIndex(0),
4702 0, &resolveImageView));
4703
4704 mRenderPassCommands->addColorResolveAttachment(0, colorImage, resolveImageView->getHandle(),
4705 gl::LevelIndex(0), 0, 1, {});
4706 onImageRenderPassWrite(gl::LevelIndex(0), 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
4707 vk::ImageLayout::ColorWrite, colorImage);
4708
4709 // Invalidate the surface. See comment in WindowSurfaceVk::doDeferredAcquireNextImage on
4710 // why this is not done when in DEMAND_REFRESH mode.
4711 if (presentMode != vk::PresentMode::SharedDemandRefreshKHR)
4712 {
4713 commandBufferHelper.invalidateRenderPassColorAttachment(
4714 mState, 0, vk::PackedAttachmentIndex(0), invalidateArea);
4715 }
4716
4717 ANGLE_TRY(
4718 flushCommandsAndEndRenderPass(RenderPassClosureReason::AlreadySpecifiedElsewhere));
4719
4720 *imageResolved = true;
4721
4722 mPerfCounters.swapchainResolveInSubpass++;
4723 }
4724
4725 return angle::Result::Continue;
4726 }
4727
getResetStatus()4728 gl::GraphicsResetStatus ContextVk::getResetStatus()
4729 {
4730 if (mRenderer->isDeviceLost())
4731 {
4732 // TODO(geofflang): It may be possible to track which context caused the device lost and
4733 // return either GL_GUILTY_CONTEXT_RESET or GL_INNOCENT_CONTEXT_RESET.
4734 // http://anglebug.com/42261488
4735 return gl::GraphicsResetStatus::UnknownContextReset;
4736 }
4737
4738 return gl::GraphicsResetStatus::NoError;
4739 }
4740
insertEventMarker(GLsizei length,const char * marker)4741 angle::Result ContextVk::insertEventMarker(GLsizei length, const char *marker)
4742 {
4743 insertEventMarkerImpl(GL_DEBUG_SOURCE_APPLICATION, marker);
4744 return angle::Result::Continue;
4745 }
4746
insertEventMarkerImpl(GLenum source,const char * marker)4747 void ContextVk::insertEventMarkerImpl(GLenum source, const char *marker)
4748 {
4749 if (!isDebugEnabled())
4750 {
4751 return;
4752 }
4753
4754 VkDebugUtilsLabelEXT label;
4755 vk::MakeDebugUtilsLabel(source, marker, &label);
4756
4757 if (hasActiveRenderPass())
4758 {
4759 mRenderPassCommandBuffer->insertDebugUtilsLabelEXT(label);
4760 }
4761 else
4762 {
4763 mOutsideRenderPassCommands->getCommandBuffer().insertDebugUtilsLabelEXT(label);
4764 }
4765 }
4766
pushGroupMarker(GLsizei length,const char * marker)4767 angle::Result ContextVk::pushGroupMarker(GLsizei length, const char *marker)
4768 {
4769 return pushDebugGroupImpl(GL_DEBUG_SOURCE_APPLICATION, 0, marker);
4770 }
4771
popGroupMarker()4772 angle::Result ContextVk::popGroupMarker()
4773 {
4774 return popDebugGroupImpl();
4775 }
4776
pushDebugGroup(const gl::Context * context,GLenum source,GLuint id,const std::string & message)4777 angle::Result ContextVk::pushDebugGroup(const gl::Context *context,
4778 GLenum source,
4779 GLuint id,
4780 const std::string &message)
4781 {
4782 return pushDebugGroupImpl(source, id, message.c_str());
4783 }
4784
popDebugGroup(const gl::Context * context)4785 angle::Result ContextVk::popDebugGroup(const gl::Context *context)
4786 {
4787 return popDebugGroupImpl();
4788 }
4789
pushDebugGroupImpl(GLenum source,GLuint id,const char * message)4790 angle::Result ContextVk::pushDebugGroupImpl(GLenum source, GLuint id, const char *message)
4791 {
4792 if (!isDebugEnabled())
4793 {
4794 return angle::Result::Continue;
4795 }
4796
4797 VkDebugUtilsLabelEXT label;
4798 vk::MakeDebugUtilsLabel(source, message, &label);
4799
4800 if (hasActiveRenderPass())
4801 {
4802 mRenderPassCommandBuffer->beginDebugUtilsLabelEXT(label);
4803 }
4804 else
4805 {
4806 mOutsideRenderPassCommands->getCommandBuffer().beginDebugUtilsLabelEXT(label);
4807 }
4808
4809 return angle::Result::Continue;
4810 }
4811
popDebugGroupImpl()4812 angle::Result ContextVk::popDebugGroupImpl()
4813 {
4814 if (!isDebugEnabled())
4815 {
4816 return angle::Result::Continue;
4817 }
4818
4819 if (hasActiveRenderPass())
4820 {
4821 mRenderPassCommandBuffer->endDebugUtilsLabelEXT();
4822 }
4823 else
4824 {
4825 mOutsideRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
4826 }
4827
4828 return angle::Result::Continue;
4829 }
4830
logEvent(const char * eventString)4831 void ContextVk::logEvent(const char *eventString)
4832 {
4833 if (!mRenderer->angleDebuggerMode())
4834 {
4835 return;
4836 }
4837
4838 // Save this event (about an OpenGL ES command being called).
4839 mEventLog.push_back(eventString);
4840
4841 // Set a dirty bit in order to stay off the "hot path" for when not logging.
4842 mGraphicsDirtyBits.set(DIRTY_BIT_EVENT_LOG);
4843 mComputeDirtyBits.set(DIRTY_BIT_EVENT_LOG);
4844 }
4845
endEventLog(angle::EntryPoint entryPoint,PipelineType pipelineType)4846 void ContextVk::endEventLog(angle::EntryPoint entryPoint, PipelineType pipelineType)
4847 {
4848 if (!mRenderer->angleDebuggerMode())
4849 {
4850 return;
4851 }
4852
4853 if (pipelineType == PipelineType::Graphics)
4854 {
4855 ASSERT(mRenderPassCommands);
4856 mRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
4857 }
4858 else
4859 {
4860 ASSERT(pipelineType == PipelineType::Compute);
4861 ASSERT(mOutsideRenderPassCommands);
4862 mOutsideRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
4863 }
4864 }
endEventLogForClearOrQuery()4865 void ContextVk::endEventLogForClearOrQuery()
4866 {
4867 if (!mRenderer->angleDebuggerMode())
4868 {
4869 return;
4870 }
4871
4872 switch (mQueryEventType)
4873 {
4874 case GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd:
4875 ASSERT(mOutsideRenderPassCommands);
4876 mOutsideRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
4877 break;
4878 case GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd:
4879 ASSERT(mRenderPassCommands);
4880 mRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
4881 break;
4882 case GraphicsEventCmdBuf::NotInQueryCmd:
4883 // The glClear* or gl*Query* command was noop'd or otherwise ended early. We could
4884 // call handleDirtyEventLogImpl() to start the hierarchy, but it isn't clear which (if
4885 // any) command buffer to use. We'll just skip processing this command (other than to
4886 // let it stay queued for the next time handleDirtyEventLogImpl() is called.
4887 return;
4888 default:
4889 UNREACHABLE();
4890 }
4891
4892 mQueryEventType = GraphicsEventCmdBuf::NotInQueryCmd;
4893 }
4894
handleNoopDrawEvent()4895 angle::Result ContextVk::handleNoopDrawEvent()
4896 {
4897 // Even though this draw call is being no-op'd, we still must handle the dirty event log
4898 return handleDirtyEventLogImpl(mRenderPassCommandBuffer);
4899 }
4900
handleGraphicsEventLog(GraphicsEventCmdBuf queryEventType)4901 angle::Result ContextVk::handleGraphicsEventLog(GraphicsEventCmdBuf queryEventType)
4902 {
4903 ASSERT(mQueryEventType == GraphicsEventCmdBuf::NotInQueryCmd || mEventLog.empty());
4904 if (!mRenderer->angleDebuggerMode())
4905 {
4906 return angle::Result::Continue;
4907 }
4908
4909 mQueryEventType = queryEventType;
4910
4911 switch (mQueryEventType)
4912 {
4913 case GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd:
4914 ASSERT(mOutsideRenderPassCommands);
4915 return handleDirtyEventLogImpl(&mOutsideRenderPassCommands->getCommandBuffer());
4916 case GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd:
4917 ASSERT(mRenderPassCommands);
4918 return handleDirtyEventLogImpl(&mRenderPassCommands->getCommandBuffer());
4919 default:
4920 UNREACHABLE();
4921 return angle::Result::Stop;
4922 }
4923 }
4924
isViewportFlipEnabledForDrawFBO() const4925 bool ContextVk::isViewportFlipEnabledForDrawFBO() const
4926 {
4927 return mFlipViewportForDrawFramebuffer && mFlipYForCurrentSurface;
4928 }
4929
isViewportFlipEnabledForReadFBO() const4930 bool ContextVk::isViewportFlipEnabledForReadFBO() const
4931 {
4932 return mFlipViewportForReadFramebuffer;
4933 }
4934
isRotatedAspectRatioForDrawFBO() const4935 bool ContextVk::isRotatedAspectRatioForDrawFBO() const
4936 {
4937 return IsRotatedAspectRatio(mCurrentRotationDrawFramebuffer);
4938 }
4939
isRotatedAspectRatioForReadFBO() const4940 bool ContextVk::isRotatedAspectRatioForReadFBO() const
4941 {
4942 return IsRotatedAspectRatio(mCurrentRotationReadFramebuffer);
4943 }
4944
getRotationDrawFramebuffer() const4945 SurfaceRotation ContextVk::getRotationDrawFramebuffer() const
4946 {
4947 return mCurrentRotationDrawFramebuffer;
4948 }
4949
getRotationReadFramebuffer() const4950 SurfaceRotation ContextVk::getRotationReadFramebuffer() const
4951 {
4952 return mCurrentRotationReadFramebuffer;
4953 }
4954
getSurfaceRotationImpl(const gl::Framebuffer * framebuffer,const egl::Surface * surface)4955 SurfaceRotation ContextVk::getSurfaceRotationImpl(const gl::Framebuffer *framebuffer,
4956 const egl::Surface *surface)
4957 {
4958 SurfaceRotation surfaceRotation = SurfaceRotation::Identity;
4959 if (surface && surface->getType() == EGL_WINDOW_BIT)
4960 {
4961 const WindowSurfaceVk *windowSurface = GetImplAs<WindowSurfaceVk>(surface);
4962 surfaceRotation = DetermineSurfaceRotation(framebuffer, windowSurface);
4963 }
4964 return surfaceRotation;
4965 }
4966
updateColorMasks()4967 void ContextVk::updateColorMasks()
4968 {
4969 const gl::BlendStateExt &blendStateExt = mState.getBlendStateExt();
4970
4971 mClearColorMasks = blendStateExt.getColorMaskBits();
4972
4973 FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
4974 mGraphicsPipelineDesc->updateColorWriteMasks(&mGraphicsPipelineTransition, mClearColorMasks,
4975 framebufferVk->getEmulatedAlphaAttachmentMask(),
4976 framebufferVk->getState().getEnabledDrawBuffers());
4977
4978 // This function may be called outside of ContextVk::syncState, and so invalidates the graphics
4979 // pipeline.
4980 invalidateCurrentGraphicsPipeline();
4981
4982 onColorAccessChange();
4983 }
4984
updateMissingOutputsMask()4985 void ContextVk::updateMissingOutputsMask()
4986 {
4987 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
4988 if (executable == nullptr)
4989 {
4990 return;
4991 }
4992
4993 const gl::DrawBufferMask framebufferMask = mState.getDrawFramebuffer()->getDrawBufferMask();
4994 const gl::DrawBufferMask shaderOutMask = executable->getActiveOutputVariablesMask();
4995 const gl::DrawBufferMask missingOutputsMask = ~shaderOutMask & framebufferMask;
4996
4997 mGraphicsPipelineDesc->updateMissingOutputsMask(&mGraphicsPipelineTransition,
4998 missingOutputsMask);
4999 }
5000
updateBlendFuncsAndEquations()5001 void ContextVk::updateBlendFuncsAndEquations()
5002 {
5003 const gl::BlendStateExt &blendStateExt = mState.getBlendStateExt();
5004
5005 FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
5006 mCachedDrawFramebufferColorAttachmentMask = framebufferVk->getState().getEnabledDrawBuffers();
5007
5008 mGraphicsPipelineDesc->updateBlendFuncs(&mGraphicsPipelineTransition, blendStateExt,
5009 mCachedDrawFramebufferColorAttachmentMask);
5010
5011 mGraphicsPipelineDesc->updateBlendEquations(&mGraphicsPipelineTransition, blendStateExt,
5012 mCachedDrawFramebufferColorAttachmentMask);
5013
5014 // This function may be called outside of ContextVk::syncState, and so invalidates the graphics
5015 // pipeline.
5016 invalidateCurrentGraphicsPipeline();
5017 }
5018
updateSampleMaskWithRasterizationSamples(const uint32_t rasterizationSamples)5019 void ContextVk::updateSampleMaskWithRasterizationSamples(const uint32_t rasterizationSamples)
5020 {
5021 static_assert(sizeof(uint32_t) == sizeof(GLbitfield), "Vulkan assumes 32-bit sample masks");
5022 ASSERT(mState.getMaxSampleMaskWords() == 1);
5023
5024 uint32_t mask = std::numeric_limits<uint16_t>::max();
5025
5026 // The following assumes that supported sample counts for multisampled
5027 // rendering does not include 1. This is true in the Vulkan backend,
5028 // where 1x multisampling is disallowed.
5029 if (rasterizationSamples > 1)
5030 {
5031 if (mState.isSampleMaskEnabled())
5032 {
5033 mask = mState.getSampleMaskWord(0) & angle::BitMask<uint32_t>(rasterizationSamples);
5034 }
5035
5036 // If sample coverage is enabled, emulate it by generating and applying a mask on top of the
5037 // sample mask.
5038 if (mState.isSampleCoverageEnabled())
5039 {
5040 ApplySampleCoverage(mState, GetCoverageSampleCount(mState, rasterizationSamples),
5041 &mask);
5042 }
5043 }
5044
5045 mGraphicsPipelineDesc->updateSampleMask(&mGraphicsPipelineTransition, 0, mask);
5046 }
5047
updateAlphaToCoverageWithRasterizationSamples(const uint32_t rasterizationSamples)5048 void ContextVk::updateAlphaToCoverageWithRasterizationSamples(const uint32_t rasterizationSamples)
5049 {
5050 // The following assumes that supported sample counts for multisampled
5051 // rendering does not include 1. This is true in the Vulkan backend,
5052 // where 1x multisampling is disallowed.
5053 mGraphicsPipelineDesc->updateAlphaToCoverageEnable(
5054 &mGraphicsPipelineTransition,
5055 mState.isSampleAlphaToCoverageEnabled() && rasterizationSamples > 1);
5056 }
5057
updateFrameBufferFetchSamples(const uint32_t prevSamples,const uint32_t curSamples)5058 void ContextVk::updateFrameBufferFetchSamples(const uint32_t prevSamples, const uint32_t curSamples)
5059 {
5060 const bool isPrevMultisampled = prevSamples > 1;
5061 const bool isCurMultisampled = curSamples > 1;
5062 if (isPrevMultisampled != isCurMultisampled)
5063 {
5064 // If we change from single sample to multisample, we need to use the Shader Program with
5065 // ProgramTransformOptions.multisampleFramebufferFetch == true. Invalidate the graphics
5066 // pipeline so that we can fetch the shader with the correct permutation option in
5067 // handleDirtyGraphicsPipelineDesc()
5068 invalidateCurrentGraphicsPipeline();
5069 }
5070 }
5071
getCorrectedViewport(const gl::Rectangle & viewport) const5072 gl::Rectangle ContextVk::getCorrectedViewport(const gl::Rectangle &viewport) const
5073 {
5074 const gl::Caps &caps = getCaps();
5075 const VkPhysicalDeviceLimits &limitsVk = mRenderer->getPhysicalDeviceProperties().limits;
5076 const int viewportBoundsRangeLow = static_cast<int>(limitsVk.viewportBoundsRange[0]);
5077 const int viewportBoundsRangeHigh = static_cast<int>(limitsVk.viewportBoundsRange[1]);
5078
5079 // Clamp the viewport values to what Vulkan specifies
5080
5081 // width must be greater than 0.0 and less than or equal to
5082 // VkPhysicalDeviceLimits::maxViewportDimensions[0]
5083 int correctedWidth = std::min<int>(viewport.width, caps.maxViewportWidth);
5084 correctedWidth = std::max<int>(correctedWidth, 0);
5085 // height must be greater than 0.0 and less than or equal to
5086 // VkPhysicalDeviceLimits::maxViewportDimensions[1]
5087 int correctedHeight = std::min<int>(viewport.height, caps.maxViewportHeight);
5088 correctedHeight = std::max<int>(correctedHeight, 0);
5089 // x and y must each be between viewportBoundsRange[0] and viewportBoundsRange[1], inclusive.
5090 // Viewport size cannot be 0 so ensure there is always size for a 1x1 viewport
5091 int correctedX = std::min<int>(viewport.x, viewportBoundsRangeHigh - 1);
5092 correctedX = std::max<int>(correctedX, viewportBoundsRangeLow);
5093 int correctedY = std::min<int>(viewport.y, viewportBoundsRangeHigh - 1);
5094 correctedY = std::max<int>(correctedY, viewportBoundsRangeLow);
5095 // x + width must be less than or equal to viewportBoundsRange[1]
5096 if ((correctedX + correctedWidth) > viewportBoundsRangeHigh)
5097 {
5098 correctedWidth = viewportBoundsRangeHigh - correctedX;
5099 }
5100 // y + height must be less than or equal to viewportBoundsRange[1]
5101 if ((correctedY + correctedHeight) > viewportBoundsRangeHigh)
5102 {
5103 correctedHeight = viewportBoundsRangeHigh - correctedY;
5104 }
5105
5106 return gl::Rectangle(correctedX, correctedY, correctedWidth, correctedHeight);
5107 }
5108
updateViewport(FramebufferVk * framebufferVk,const gl::Rectangle & viewport,float nearPlane,float farPlane)5109 void ContextVk::updateViewport(FramebufferVk *framebufferVk,
5110 const gl::Rectangle &viewport,
5111 float nearPlane,
5112 float farPlane)
5113 {
5114
5115 gl::Box fbDimensions = framebufferVk->getState().getDimensions();
5116 gl::Rectangle correctedRect = getCorrectedViewport(viewport);
5117 gl::Rectangle rotatedRect;
5118 RotateRectangle(getRotationDrawFramebuffer(), false, fbDimensions.width, fbDimensions.height,
5119 correctedRect, &rotatedRect);
5120
5121 const bool invertViewport = isViewportFlipEnabledForDrawFBO();
5122
5123 gl_vk::GetViewport(
5124 rotatedRect, nearPlane, farPlane, invertViewport,
5125 // If clip space origin is upper left, viewport origin's y value will be offset by the
5126 // height of the viewport when clip space is mapped into screen space.
5127 mState.getClipOrigin() == gl::ClipOrigin::UpperLeft,
5128 // If the surface is rotated 90/270 degrees, use the framebuffer's width instead of the
5129 // height for calculating the final viewport.
5130 isRotatedAspectRatioForDrawFBO() ? fbDimensions.width : fbDimensions.height, &mViewport);
5131
5132 // Ensure viewport is within Vulkan requirements
5133 vk::ClampViewport(&mViewport);
5134
5135 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_VIEWPORT);
5136 }
5137
updateFrontFace()5138 void ContextVk::updateFrontFace()
5139 {
5140 if (mRenderer->getFeatures().useFrontFaceDynamicState.enabled)
5141 {
5142 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_FRONT_FACE);
5143 }
5144 else
5145 {
5146 mGraphicsPipelineDesc->updateFrontFace(
5147 &mGraphicsPipelineTransition, mState.getRasterizerState(), isYFlipEnabledForDrawFBO());
5148 }
5149 }
5150
updateDepthRange(float nearPlane,float farPlane)5151 void ContextVk::updateDepthRange(float nearPlane, float farPlane)
5152 {
5153 // GLES2.0 Section 2.12.1: Each of n and f are clamped to lie within [0, 1], as are all
5154 // arguments of type clampf.
5155 ASSERT(nearPlane >= 0.0f && nearPlane <= 1.0f);
5156 ASSERT(farPlane >= 0.0f && farPlane <= 1.0f);
5157 mViewport.minDepth = nearPlane;
5158 mViewport.maxDepth = farPlane;
5159
5160 invalidateGraphicsDriverUniforms();
5161 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_VIEWPORT);
5162 }
5163
updateScissor(const gl::State & glState)5164 void ContextVk::updateScissor(const gl::State &glState)
5165 {
5166 FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
5167 gl::Rectangle renderArea = framebufferVk->getNonRotatedCompleteRenderArea();
5168
5169 // Clip the render area to the viewport.
5170 gl::Rectangle viewportClippedRenderArea;
5171 if (!gl::ClipRectangle(renderArea, getCorrectedViewport(glState.getViewport()),
5172 &viewportClippedRenderArea))
5173 {
5174 viewportClippedRenderArea = gl::Rectangle();
5175 }
5176
5177 gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false);
5178 gl::Rectangle rotatedScissoredArea;
5179 RotateRectangle(getRotationDrawFramebuffer(), isViewportFlipEnabledForDrawFBO(),
5180 renderArea.width, renderArea.height, scissoredArea, &rotatedScissoredArea);
5181 mScissor = gl_vk::GetRect(rotatedScissoredArea);
5182 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_SCISSOR);
5183
5184 // If the scissor has grown beyond the previous scissoredRenderArea, grow the render pass render
5185 // area. The only undesirable effect this may have is that if the render area does not cover a
5186 // previously invalidated area, that invalidate will have to be discarded.
5187 if (mRenderPassCommandBuffer &&
5188 !mRenderPassCommands->getRenderArea().encloses(rotatedScissoredArea))
5189 {
5190 ASSERT(mRenderPassCommands->started());
5191 mRenderPassCommands->growRenderArea(this, rotatedScissoredArea);
5192 }
5193 }
5194
updateDepthStencil(const gl::State & glState)5195 void ContextVk::updateDepthStencil(const gl::State &glState)
5196 {
5197 updateDepthTestEnabled(glState);
5198 updateDepthWriteEnabled(glState);
5199 updateStencilTestEnabled(glState);
5200 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_WRITE_MASK);
5201 }
5202
updateDepthTestEnabled(const gl::State & glState)5203 void ContextVk::updateDepthTestEnabled(const gl::State &glState)
5204 {
5205 const gl::DepthStencilState depthStencilState = glState.getDepthStencilState();
5206 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
5207
5208 if (mRenderer->getFeatures().useDepthTestEnableDynamicState.enabled)
5209 {
5210 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_DEPTH_TEST_ENABLE);
5211 }
5212 else
5213 {
5214 mGraphicsPipelineDesc->updateDepthTestEnabled(&mGraphicsPipelineTransition,
5215 depthStencilState, drawFramebuffer);
5216 }
5217 }
5218
updateDepthWriteEnabled(const gl::State & glState)5219 void ContextVk::updateDepthWriteEnabled(const gl::State &glState)
5220 {
5221 const gl::DepthStencilState depthStencilState = glState.getDepthStencilState();
5222 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
5223
5224 if (mRenderer->getFeatures().useDepthWriteEnableDynamicState.enabled)
5225 {
5226 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_DEPTH_WRITE_ENABLE);
5227 }
5228 else
5229 {
5230 mGraphicsPipelineDesc->updateDepthWriteEnabled(&mGraphicsPipelineTransition,
5231 depthStencilState, drawFramebuffer);
5232 }
5233 }
5234
updateDepthFunc(const gl::State & glState)5235 void ContextVk::updateDepthFunc(const gl::State &glState)
5236 {
5237 if (mRenderer->getFeatures().useDepthCompareOpDynamicState.enabled)
5238 {
5239 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_DEPTH_COMPARE_OP);
5240 }
5241 else
5242 {
5243 mGraphicsPipelineDesc->updateDepthFunc(&mGraphicsPipelineTransition,
5244 glState.getDepthStencilState());
5245 }
5246 }
5247
updateStencilTestEnabled(const gl::State & glState)5248 void ContextVk::updateStencilTestEnabled(const gl::State &glState)
5249 {
5250 const gl::DepthStencilState depthStencilState = glState.getDepthStencilState();
5251 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
5252
5253 if (mRenderer->getFeatures().useStencilTestEnableDynamicState.enabled)
5254 {
5255 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_TEST_ENABLE);
5256 }
5257 else
5258 {
5259 mGraphicsPipelineDesc->updateStencilTestEnabled(&mGraphicsPipelineTransition,
5260 depthStencilState, drawFramebuffer);
5261 }
5262 }
5263
5264 // If the target is a single-sampled target, sampleShading should be disabled, to use Bresenham line
5265 // rasterization feature.
updateSampleShadingWithRasterizationSamples(const uint32_t rasterizationSamples)5266 void ContextVk::updateSampleShadingWithRasterizationSamples(const uint32_t rasterizationSamples)
5267 {
5268 bool sampleShadingEnable =
5269 (rasterizationSamples <= 1 ? false : mState.isSampleShadingEnabled());
5270 float minSampleShading = mState.getMinSampleShading();
5271
5272 // If sample shading is not enabled, check if it should be implicitly enabled according to the
5273 // program. Normally the driver should do this, but some drivers don't.
5274 if (rasterizationSamples > 1 && !sampleShadingEnable &&
5275 getFeatures().explicitlyEnablePerSampleShading.enabled)
5276 {
5277 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
5278 if (executable && executable->enablesPerSampleShading())
5279 {
5280 sampleShadingEnable = true;
5281 minSampleShading = 1.0;
5282 }
5283 }
5284
5285 mGraphicsPipelineDesc->updateSampleShading(&mGraphicsPipelineTransition, sampleShadingEnable,
5286 minSampleShading);
5287 }
5288
5289 // If the target is switched between a single-sampled and multisample, the dependency related to the
5290 // rasterization sample should be updated.
updateRasterizationSamples(const uint32_t rasterizationSamples)5291 void ContextVk::updateRasterizationSamples(const uint32_t rasterizationSamples)
5292 {
5293 uint32_t prevSampleCount = mGraphicsPipelineDesc->getRasterizationSamples();
5294 updateFrameBufferFetchSamples(prevSampleCount, rasterizationSamples);
5295 mGraphicsPipelineDesc->updateRasterizationSamples(&mGraphicsPipelineTransition,
5296 rasterizationSamples);
5297 updateSampleShadingWithRasterizationSamples(rasterizationSamples);
5298 updateSampleMaskWithRasterizationSamples(rasterizationSamples);
5299 updateAlphaToCoverageWithRasterizationSamples(rasterizationSamples);
5300 }
5301
updateRasterizerDiscardEnabled(bool isPrimitivesGeneratedQueryActive)5302 void ContextVk::updateRasterizerDiscardEnabled(bool isPrimitivesGeneratedQueryActive)
5303 {
5304 // On some devices, when rasterizerDiscardEnable is enabled, the
5305 // VK_EXT_primitives_generated_query as well as the pipeline statistics query used to emulate it
5306 // are non-functional. For VK_EXT_primitives_generated_query there's a feature bit but not for
5307 // pipeline statistics query. If the primitives generated query is active (and rasterizer
5308 // discard is not supported), rasterizerDiscardEnable is set to false and the functionality
5309 // is otherwise emulated (by using an empty scissor).
5310
5311 // If the primitives generated query implementation supports rasterizer discard, just set
5312 // rasterizer discard as requested. Otherwise disable it.
5313 const bool isEmulatingRasterizerDiscard =
5314 isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(
5315 isPrimitivesGeneratedQueryActive);
5316
5317 if (mRenderer->getFeatures().useRasterizerDiscardEnableDynamicState.enabled)
5318 {
5319 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_RASTERIZER_DISCARD_ENABLE);
5320 }
5321 else
5322 {
5323 const bool isRasterizerDiscardEnabled = mState.isRasterizerDiscardEnabled();
5324
5325 mGraphicsPipelineDesc->updateRasterizerDiscardEnabled(
5326 &mGraphicsPipelineTransition,
5327 isRasterizerDiscardEnabled && !isEmulatingRasterizerDiscard);
5328
5329 invalidateCurrentGraphicsPipeline();
5330 }
5331
5332 if (isEmulatingRasterizerDiscard)
5333 {
5334 // If we are emulating rasterizer discard, update the scissor to use an empty one if
5335 // rasterizer discard is enabled.
5336 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_SCISSOR);
5337 }
5338 }
5339
updateAdvancedBlendEquations(const gl::ProgramExecutable * executable)5340 void ContextVk::updateAdvancedBlendEquations(const gl::ProgramExecutable *executable)
5341 {
5342 if (!getFeatures().emulateAdvancedBlendEquations.enabled || executable == nullptr)
5343 {
5344 return;
5345 }
5346
5347 // If advanced blend equations is emulated and the program uses advanced equations, update the
5348 // driver uniforms to pass the equation to the shader.
5349 if (executable->getAdvancedBlendEquations().any())
5350 {
5351 invalidateGraphicsDriverUniforms();
5352 }
5353 }
5354
updateDither()5355 void ContextVk::updateDither()
5356 {
5357 if (getFeatures().supportsLegacyDithering.enabled)
5358 {
5359 FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
5360 if (framebufferVk->updateLegacyDither(this))
5361 {
5362 // Can't reactivate: same framebuffer but the render pass desc has changed.
5363 mAllowRenderPassToReactivate = false;
5364
5365 onRenderPassFinished(RenderPassClosureReason::LegacyDithering);
5366 }
5367
5368 // update GraphicsPipelineDesc renderpass legacy dithering bit
5369 if (isDitherEnabled() != mGraphicsPipelineDesc->isLegacyDitherEnabled())
5370 {
5371 const vk::FramebufferFetchMode framebufferFetchMode =
5372 vk::GetProgramFramebufferFetchMode(mState.getProgramExecutable());
5373 mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition, getFeatures(),
5374 framebufferVk->getRenderPassDesc(),
5375 framebufferFetchMode);
5376 invalidateCurrentGraphicsPipeline();
5377 }
5378 }
5379
5380 if (!getFeatures().emulateDithering.enabled)
5381 {
5382 return;
5383 }
5384
5385 FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
5386
5387 // Dithering in OpenGL is vaguely defined, to the extent that no dithering is also a valid
5388 // dithering algorithm. Dithering is enabled by default, but emulating it has a non-negligible
5389 // cost. Similarly to some other GLES drivers, ANGLE enables dithering only on low-bit formats
5390 // where visual banding is particularly common; namely RGBA4444, RGBA5551 and RGB565.
5391 //
5392 // Dithering is emulated in the fragment shader and is controlled by a spec constant. Every 2
5393 // bits of the spec constant correspond to one attachment, with the value indicating:
5394 //
5395 // - 00: No dithering
5396 // - 01: Dither for RGBA4444
5397 // - 10: Dither for RGBA5551
5398 // - 11: Dither for RGB565
5399 //
5400 uint16_t ditherControl = 0;
5401 if (mState.isDitherEnabled())
5402 {
5403 const gl::DrawBufferMask attachmentMask =
5404 framebufferVk->getState().getColorAttachmentsMask();
5405
5406 for (size_t colorIndex : attachmentMask)
5407 {
5408 // As dithering is emulated in the fragment shader itself, there are a number of
5409 // situations that can lead to incorrect blending. We only allow blending with specific
5410 // combinations know to not interfere with dithering.
5411 if (mState.isBlendEnabledIndexed(static_cast<GLuint>(colorIndex)) &&
5412 !BlendModeSupportsDither(this, colorIndex))
5413 {
5414 continue;
5415 }
5416
5417 RenderTargetVk *attachment = framebufferVk->getColorDrawRenderTarget(colorIndex);
5418
5419 const angle::FormatID format = attachment->getImageActualFormatID();
5420
5421 uint16_t attachmentDitherControl = sh::vk::kDitherControlNoDither;
5422 switch (format)
5423 {
5424 case angle::FormatID::R4G4B4A4_UNORM:
5425 case angle::FormatID::B4G4R4A4_UNORM:
5426 attachmentDitherControl = sh::vk::kDitherControlDither4444;
5427 break;
5428 case angle::FormatID::R5G5B5A1_UNORM:
5429 case angle::FormatID::B5G5R5A1_UNORM:
5430 case angle::FormatID::A1R5G5B5_UNORM:
5431 attachmentDitherControl = sh::vk::kDitherControlDither5551;
5432 break;
5433 case angle::FormatID::R5G6B5_UNORM:
5434 case angle::FormatID::B5G6R5_UNORM:
5435 attachmentDitherControl = sh::vk::kDitherControlDither565;
5436 break;
5437 default:
5438 break;
5439 }
5440
5441 ditherControl |= static_cast<uint16_t>(attachmentDitherControl << 2 * colorIndex);
5442 }
5443 }
5444
5445 if (ditherControl != mGraphicsPipelineDesc->getEmulatedDitherControl())
5446 {
5447 mGraphicsPipelineDesc->updateEmulatedDitherControl(&mGraphicsPipelineTransition,
5448 ditherControl);
5449 invalidateCurrentGraphicsPipeline();
5450 }
5451 }
5452
updateStencilWriteWorkaround()5453 void ContextVk::updateStencilWriteWorkaround()
5454 {
5455 if (!getFeatures().useNonZeroStencilWriteMaskStaticState.enabled)
5456 {
5457 return;
5458 }
5459
5460 // On certain drivers, having a stencil write mask of 0 in static state enables optimizations
5461 // that make the interaction of the stencil write mask dynamic state with discard and alpha to
5462 // coverage broken. When the program has discard, or when alpha to coverage is enabled, these
5463 // optimizations are disabled by specifying a non-zero static state for stencil write mask.
5464 const bool programHasDiscard = mState.getProgramExecutable()->hasDiscard();
5465 const bool isAlphaToCoverageEnabled = mState.isSampleAlphaToCoverageEnabled();
5466
5467 mGraphicsPipelineDesc->updateNonZeroStencilWriteMaskWorkaround(
5468 &mGraphicsPipelineTransition, programHasDiscard || isAlphaToCoverageEnabled);
5469 }
5470
invalidateProgramExecutableHelper(const gl::Context * context)5471 angle::Result ContextVk::invalidateProgramExecutableHelper(const gl::Context *context)
5472 {
5473 const gl::State &glState = context->getState();
5474 const gl::ProgramExecutable *executable = glState.getProgramExecutable();
5475
5476 if (executable->hasLinkedShaderStage(gl::ShaderType::Compute))
5477 {
5478 invalidateCurrentComputePipeline();
5479 }
5480
5481 if (executable->hasLinkedShaderStage(gl::ShaderType::Vertex))
5482 {
5483 invalidateCurrentGraphicsPipeline();
5484 // No additional work is needed here. We will update the pipeline desc
5485 // later.
5486 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
5487 invalidateVertexAndIndexBuffers();
5488 // If VK_EXT_vertex_input_dynamic_state is enabled then vkCmdSetVertexInputEXT must be
5489 // called in the current command buffer prior to the draw command, even if there are no
5490 // active vertex attributes.
5491 const bool useVertexBuffer = (executable->getMaxActiveAttribLocation() > 0) ||
5492 getFeatures().supportsVertexInputDynamicState.enabled;
5493 mNonIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
5494 mIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
5495 resetCurrentGraphicsPipeline();
5496
5497 const vk::FramebufferFetchMode framebufferFetchMode =
5498 vk::GetProgramFramebufferFetchMode(executable);
5499 const bool hasColorFramebufferFetch =
5500 framebufferFetchMode != vk::FramebufferFetchMode::None;
5501 if (getFeatures().preferDynamicRendering.enabled)
5502 {
5503 // Update the framebuffer fetch mode on the pipeline desc directly. This is an inherent
5504 // property of the executable. Even if the bit is placed in RenderPassDesc because of
5505 // the non-dynamic-rendering path, updating it without affecting the transition bits is
5506 // valid because there cannot be a transition link between pipelines of different
5507 // programs. This is attested by the fact that |resetCurrentGraphicsPipeline| above
5508 // sets |mCurrentGraphicsPipeline| to nullptr.
5509 mGraphicsPipelineDesc->setRenderPassFramebufferFetchMode(framebufferFetchMode);
5510
5511 if (framebufferFetchMode != vk::FramebufferFetchMode::None)
5512 {
5513 onFramebufferFetchUse(framebufferFetchMode);
5514 }
5515 }
5516 else
5517 {
5518 ASSERT(!FramebufferFetchModeHasDepthStencil(framebufferFetchMode));
5519 if (mIsInColorFramebufferFetchMode != hasColorFramebufferFetch)
5520 {
5521 ASSERT(getDrawFramebuffer()->getRenderPassDesc().hasColorFramebufferFetch() ==
5522 mIsInColorFramebufferFetchMode);
5523
5524 ANGLE_TRY(switchToColorFramebufferFetchMode(hasColorFramebufferFetch));
5525
5526 // When framebuffer fetch is enabled, attachments can be read from even if output is
5527 // masked, so update their access.
5528 onColorAccessChange();
5529 }
5530
5531 // If permanentlySwitchToFramebufferFetchMode is enabled,
5532 // mIsInColorFramebufferFetchMode will remain true throughout the entire time.
5533 // If we switch from a program that doesn't use framebuffer fetch and doesn't
5534 // read/write to the framebuffer color attachment, to a
5535 // program that uses framebuffer fetch and needs to read from the framebuffer
5536 // color attachment, we will miss the call
5537 // onColorAccessChange() above and miss setting the dirty bit
5538 // DIRTY_BIT_COLOR_ACCESS. This means we will not call
5539 // handleDirtyGraphicsColorAccess that updates the access value of
5540 // framebuffer color attachment from unused to readonly. This makes the
5541 // color attachment to continue using LoadOpNone, and the second program
5542 // will not be able to read the value in the color attachment.
5543 if (getFeatures().permanentlySwitchToFramebufferFetchMode.enabled &&
5544 hasColorFramebufferFetch)
5545 {
5546 onColorAccessChange();
5547 }
5548 }
5549
5550 // If framebuffer fetch is exposed but is internally non-coherent, make sure a framebuffer
5551 // fetch barrier is issued before each draw call as long as a program with framebuffer fetch
5552 // is used. If the application would have correctly used non-coherent framebuffer fetch, it
5553 // would have been optimal _not_ to expose the coherent extension. However, lots of
5554 // Android applications expect coherent framebuffer fetch to be available.
5555 if (mRenderer->isCoherentColorFramebufferFetchEmulated())
5556 {
5557 mGraphicsDirtyBits.set(DIRTY_BIT_FRAMEBUFFER_FETCH_BARRIER, hasColorFramebufferFetch);
5558 }
5559
5560 updateStencilWriteWorkaround();
5561
5562 mGraphicsPipelineDesc->updateVertexShaderComponentTypes(
5563 &mGraphicsPipelineTransition, executable->getNonBuiltinAttribLocationsMask(),
5564 executable->getAttributesTypeMask());
5565
5566 updateMissingOutputsMask();
5567 }
5568
5569 return angle::Result::Continue;
5570 }
5571
syncState(const gl::Context * context,const gl::state::DirtyBits dirtyBits,const gl::state::DirtyBits bitMask,const gl::state::ExtendedDirtyBits extendedDirtyBits,const gl::state::ExtendedDirtyBits extendedBitMask,gl::Command command)5572 angle::Result ContextVk::syncState(const gl::Context *context,
5573 const gl::state::DirtyBits dirtyBits,
5574 const gl::state::DirtyBits bitMask,
5575 const gl::state::ExtendedDirtyBits extendedDirtyBits,
5576 const gl::state::ExtendedDirtyBits extendedBitMask,
5577 gl::Command command)
5578 {
5579 const gl::State &glState = context->getState();
5580 const gl::ProgramExecutable *programExecutable = glState.getProgramExecutable();
5581
5582 if ((dirtyBits & mPipelineDirtyBitsMask).any() &&
5583 (programExecutable == nullptr || command != gl::Command::Dispatch))
5584 {
5585 invalidateCurrentGraphicsPipeline();
5586 }
5587
5588 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
5589 VertexArrayVk *vertexArrayVk = getVertexArray();
5590
5591 for (auto iter = dirtyBits.begin(), endIter = dirtyBits.end(); iter != endIter; ++iter)
5592 {
5593 size_t dirtyBit = *iter;
5594 switch (dirtyBit)
5595 {
5596 case gl::state::DIRTY_BIT_SCISSOR_TEST_ENABLED:
5597 case gl::state::DIRTY_BIT_SCISSOR:
5598 updateScissor(glState);
5599 break;
5600 case gl::state::DIRTY_BIT_VIEWPORT:
5601 {
5602 FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
5603 updateViewport(framebufferVk, glState.getViewport(), glState.getNearPlane(),
5604 glState.getFarPlane());
5605 // Update the scissor, which will be constrained to the viewport
5606 updateScissor(glState);
5607 break;
5608 }
5609 case gl::state::DIRTY_BIT_DEPTH_RANGE:
5610 updateDepthRange(glState.getNearPlane(), glState.getFarPlane());
5611 break;
5612 case gl::state::DIRTY_BIT_BLEND_ENABLED:
5613 mGraphicsPipelineDesc->updateBlendEnabled(
5614 &mGraphicsPipelineTransition, glState.getBlendStateExt().getEnabledMask());
5615 updateDither();
5616 updateAdvancedBlendEquations(programExecutable);
5617 break;
5618 case gl::state::DIRTY_BIT_BLEND_COLOR:
5619 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_BLEND_CONSTANTS);
5620 break;
5621 case gl::state::DIRTY_BIT_BLEND_FUNCS:
5622 mGraphicsPipelineDesc->updateBlendFuncs(
5623 &mGraphicsPipelineTransition, glState.getBlendStateExt(),
5624 drawFramebufferVk->getState().getColorAttachmentsMask());
5625 break;
5626 case gl::state::DIRTY_BIT_BLEND_EQUATIONS:
5627 mGraphicsPipelineDesc->updateBlendEquations(
5628 &mGraphicsPipelineTransition, glState.getBlendStateExt(),
5629 drawFramebufferVk->getState().getColorAttachmentsMask());
5630 updateAdvancedBlendEquations(programExecutable);
5631 break;
5632 case gl::state::DIRTY_BIT_COLOR_MASK:
5633 updateColorMasks();
5634 break;
5635 case gl::state::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
5636 updateAlphaToCoverageWithRasterizationSamples(drawFramebufferVk->getSamples());
5637 updateStencilWriteWorkaround();
5638
5639 static_assert(gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE >
5640 gl::state::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED,
5641 "Dirty bit order");
5642 iter.setLaterBit(gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE);
5643 break;
5644 case gl::state::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED:
5645 updateSampleMaskWithRasterizationSamples(drawFramebufferVk->getSamples());
5646 break;
5647 case gl::state::DIRTY_BIT_SAMPLE_COVERAGE:
5648 updateSampleMaskWithRasterizationSamples(drawFramebufferVk->getSamples());
5649 break;
5650 case gl::state::DIRTY_BIT_SAMPLE_MASK_ENABLED:
5651 updateSampleMaskWithRasterizationSamples(drawFramebufferVk->getSamples());
5652 break;
5653 case gl::state::DIRTY_BIT_SAMPLE_MASK:
5654 updateSampleMaskWithRasterizationSamples(drawFramebufferVk->getSamples());
5655 break;
5656 case gl::state::DIRTY_BIT_DEPTH_TEST_ENABLED:
5657 updateDepthTestEnabled(glState);
5658 iter.setLaterBit(gl::state::DIRTY_BIT_DEPTH_MASK);
5659 break;
5660 case gl::state::DIRTY_BIT_DEPTH_FUNC:
5661 updateDepthFunc(glState);
5662 onDepthStencilAccessChange();
5663 break;
5664 case gl::state::DIRTY_BIT_DEPTH_MASK:
5665 updateDepthWriteEnabled(glState);
5666 onDepthStencilAccessChange();
5667 break;
5668 case gl::state::DIRTY_BIT_STENCIL_TEST_ENABLED:
5669 updateStencilTestEnabled(glState);
5670 onDepthStencilAccessChange();
5671 break;
5672 case gl::state::DIRTY_BIT_STENCIL_FUNCS_FRONT:
5673 if (mRenderer->getFeatures().useStencilOpDynamicState.enabled)
5674 {
5675 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_OP);
5676 }
5677 else
5678 {
5679 mGraphicsPipelineDesc->updateStencilFrontFuncs(&mGraphicsPipelineTransition,
5680 glState.getDepthStencilState());
5681 }
5682 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_COMPARE_MASK);
5683 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_REFERENCE);
5684 onDepthStencilAccessChange();
5685 break;
5686 case gl::state::DIRTY_BIT_STENCIL_FUNCS_BACK:
5687 if (mRenderer->getFeatures().useStencilOpDynamicState.enabled)
5688 {
5689 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_OP);
5690 }
5691 else
5692 {
5693 mGraphicsPipelineDesc->updateStencilBackFuncs(&mGraphicsPipelineTransition,
5694 glState.getDepthStencilState());
5695 }
5696 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_COMPARE_MASK);
5697 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_REFERENCE);
5698 onDepthStencilAccessChange();
5699 break;
5700 case gl::state::DIRTY_BIT_STENCIL_OPS_FRONT:
5701 if (mRenderer->getFeatures().useStencilOpDynamicState.enabled)
5702 {
5703 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_OP);
5704 }
5705 else
5706 {
5707 mGraphicsPipelineDesc->updateStencilFrontOps(&mGraphicsPipelineTransition,
5708 glState.getDepthStencilState());
5709 }
5710 onDepthStencilAccessChange();
5711 break;
5712 case gl::state::DIRTY_BIT_STENCIL_OPS_BACK:
5713 if (mRenderer->getFeatures().useStencilOpDynamicState.enabled)
5714 {
5715 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_OP);
5716 }
5717 else
5718 {
5719 mGraphicsPipelineDesc->updateStencilBackOps(&mGraphicsPipelineTransition,
5720 glState.getDepthStencilState());
5721 }
5722 onDepthStencilAccessChange();
5723 break;
5724 case gl::state::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
5725 case gl::state::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
5726 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_STENCIL_WRITE_MASK);
5727 onDepthStencilAccessChange();
5728 break;
5729 case gl::state::DIRTY_BIT_CULL_FACE_ENABLED:
5730 case gl::state::DIRTY_BIT_CULL_FACE:
5731 if (mRenderer->getFeatures().useCullModeDynamicState.enabled)
5732 {
5733 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_CULL_MODE);
5734 }
5735 else
5736 {
5737 mGraphicsPipelineDesc->updateCullMode(&mGraphicsPipelineTransition,
5738 glState.getRasterizerState());
5739 }
5740 break;
5741 case gl::state::DIRTY_BIT_FRONT_FACE:
5742 updateFrontFace();
5743 break;
5744 case gl::state::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
5745 if (mRenderer->getFeatures().useDepthBiasEnableDynamicState.enabled)
5746 {
5747 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_DEPTH_BIAS_ENABLE);
5748 }
5749 else
5750 {
5751 mGraphicsPipelineDesc->updatePolygonOffsetEnabled(
5752 &mGraphicsPipelineTransition, glState.isPolygonOffsetEnabled());
5753 }
5754 break;
5755 case gl::state::DIRTY_BIT_POLYGON_OFFSET:
5756 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_DEPTH_BIAS);
5757 break;
5758 case gl::state::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED:
5759 updateRasterizerDiscardEnabled(
5760 mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
5761 onColorAccessChange();
5762 break;
5763 case gl::state::DIRTY_BIT_LINE_WIDTH:
5764 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_LINE_WIDTH);
5765 break;
5766 case gl::state::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED:
5767 if (mRenderer->getFeatures().usePrimitiveRestartEnableDynamicState.enabled)
5768 {
5769 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_PRIMITIVE_RESTART_ENABLE);
5770 }
5771 else
5772 {
5773 mGraphicsPipelineDesc->updatePrimitiveRestartEnabled(
5774 &mGraphicsPipelineTransition, glState.isPrimitiveRestartEnabled());
5775 }
5776 // Additionally set the index buffer dirty if conversion from uint8 might have been
5777 // necessary. Otherwise if primitive restart is enabled and the index buffer is
5778 // translated to uint16_t with a value of 0xFFFF, it cannot be reused when primitive
5779 // restart is disabled.
5780 if (!mRenderer->getFeatures().supportsIndexTypeUint8.enabled)
5781 {
5782 mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
5783 }
5784 break;
5785 case gl::state::DIRTY_BIT_CLEAR_COLOR:
5786 mClearColorValue.color.float32[0] = glState.getColorClearValue().red;
5787 mClearColorValue.color.float32[1] = glState.getColorClearValue().green;
5788 mClearColorValue.color.float32[2] = glState.getColorClearValue().blue;
5789 mClearColorValue.color.float32[3] = glState.getColorClearValue().alpha;
5790 break;
5791 case gl::state::DIRTY_BIT_CLEAR_DEPTH:
5792 mClearDepthStencilValue.depthStencil.depth = glState.getDepthClearValue();
5793 break;
5794 case gl::state::DIRTY_BIT_CLEAR_STENCIL:
5795 mClearDepthStencilValue.depthStencil.stencil =
5796 static_cast<uint32_t>(glState.getStencilClearValue());
5797 break;
5798 case gl::state::DIRTY_BIT_UNPACK_STATE:
5799 // This is a no-op, it's only important to use the right unpack state when we do
5800 // setImage or setSubImage in TextureVk, which is plumbed through the frontend
5801 // call
5802 break;
5803 case gl::state::DIRTY_BIT_UNPACK_BUFFER_BINDING:
5804 break;
5805 case gl::state::DIRTY_BIT_PACK_STATE:
5806 // This is a no-op, its only important to use the right pack state when we do
5807 // call readPixels later on.
5808 break;
5809 case gl::state::DIRTY_BIT_PACK_BUFFER_BINDING:
5810 break;
5811 case gl::state::DIRTY_BIT_DITHER_ENABLED:
5812 updateDither();
5813 break;
5814 case gl::state::DIRTY_BIT_READ_FRAMEBUFFER_BINDING:
5815 updateFlipViewportReadFramebuffer(context->getState());
5816 updateSurfaceRotationReadFramebuffer(glState, context->getCurrentReadSurface());
5817 break;
5818 case gl::state::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
5819 {
5820 // FramebufferVk::syncState signals that we should start a new command buffer.
5821 // But changing the binding can skip FramebufferVk::syncState if the Framebuffer
5822 // has no dirty bits. Thus we need to explicitly clear the current command
5823 // buffer to ensure we start a new one. We don't actually close the render pass here
5824 // as some optimizations in non-draw commands require the render pass to remain
5825 // open, such as invalidate or blit. Note that we always start a new command buffer
5826 // because we currently can only support one open RenderPass at a time.
5827 //
5828 // The render pass is not closed if binding is changed to the same framebuffer as
5829 // before.
5830 if (hasActiveRenderPass() && hasStartedRenderPassWithQueueSerial(
5831 drawFramebufferVk->getLastRenderPassQueueSerial()))
5832 {
5833 break;
5834 }
5835
5836 onRenderPassFinished(RenderPassClosureReason::FramebufferBindingChange);
5837 // If we are switching from user FBO to system frame buffer, we always submit work
5838 // first so that these FBO rendering will not have to wait for ANI semaphore (which
5839 // draw to system frame buffer must wait for).
5840 if ((getFeatures().preferSubmitAtFBOBoundary.enabled ||
5841 mState.getDrawFramebuffer()->isDefault()) &&
5842 mRenderPassCommands->started())
5843 {
5844 // This will behave as if user called glFlush, but the actual flush will be
5845 // triggered at endRenderPass time.
5846 mHasDeferredFlush = true;
5847 }
5848
5849 mDepthStencilAttachmentFlags.reset();
5850 updateFlipViewportDrawFramebuffer(glState);
5851 updateSurfaceRotationDrawFramebuffer(glState, context->getCurrentDrawSurface());
5852 updateViewport(drawFramebufferVk, glState.getViewport(), glState.getNearPlane(),
5853 glState.getFarPlane());
5854 updateColorMasks();
5855 updateMissingOutputsMask();
5856 updateRasterizationSamples(drawFramebufferVk->getSamples());
5857 updateRasterizerDiscardEnabled(
5858 mState.isQueryActive(gl::QueryType::PrimitivesGenerated));
5859
5860 updateFrontFace();
5861 updateScissor(glState);
5862 updateDepthStencil(glState);
5863 updateDither();
5864
5865 // Clear the blend funcs/equations for color attachment indices that no longer
5866 // exist.
5867 gl::DrawBufferMask newColorAttachmentMask =
5868 drawFramebufferVk->getState().getColorAttachmentsMask();
5869 mGraphicsPipelineDesc->resetBlendFuncsAndEquations(
5870 &mGraphicsPipelineTransition, glState.getBlendStateExt(),
5871 mCachedDrawFramebufferColorAttachmentMask, newColorAttachmentMask);
5872 mCachedDrawFramebufferColorAttachmentMask = newColorAttachmentMask;
5873
5874 if (!getFeatures().preferDynamicRendering.enabled)
5875 {
5876 // The framebuffer may not be in sync with usage of framebuffer fetch programs.
5877 drawFramebufferVk->switchToColorFramebufferFetchMode(
5878 this, mIsInColorFramebufferFetchMode);
5879 }
5880
5881 onDrawFramebufferRenderPassDescChange(drawFramebufferVk, nullptr);
5882
5883 break;
5884 }
5885 case gl::state::DIRTY_BIT_RENDERBUFFER_BINDING:
5886 break;
5887 case gl::state::DIRTY_BIT_VERTEX_ARRAY_BINDING:
5888 {
5889 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
5890 ANGLE_TRY(vertexArrayVk->updateActiveAttribInfo(this));
5891 ANGLE_TRY(onIndexBufferChange(vertexArrayVk->getCurrentElementArrayBuffer()));
5892 break;
5893 }
5894 case gl::state::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
5895 break;
5896 case gl::state::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING:
5897 break;
5898 case gl::state::DIRTY_BIT_PROGRAM_BINDING:
5899 static_assert(
5900 gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE > gl::state::DIRTY_BIT_PROGRAM_BINDING,
5901 "Dirty bit order");
5902 iter.setLaterBit(gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE);
5903 break;
5904 case gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE:
5905 {
5906 ASSERT(programExecutable);
5907 invalidateCurrentDefaultUniforms();
5908 updateAdvancedBlendEquations(programExecutable);
5909 vk::GetImpl(programExecutable)->onProgramBind();
5910 static_assert(
5911 gl::state::DIRTY_BIT_TEXTURE_BINDINGS > gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE,
5912 "Dirty bit order");
5913 iter.setLaterBit(gl::state::DIRTY_BIT_TEXTURE_BINDINGS);
5914 ANGLE_TRY(invalidateCurrentShaderResources(command));
5915 invalidateDriverUniforms();
5916 ANGLE_TRY(invalidateProgramExecutableHelper(context));
5917
5918 static_assert(
5919 gl::state::DIRTY_BIT_SAMPLE_SHADING > gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE,
5920 "Dirty bit order");
5921 if (getFeatures().explicitlyEnablePerSampleShading.enabled)
5922 {
5923 iter.setLaterBit(gl::state::DIRTY_BIT_SAMPLE_SHADING);
5924 }
5925
5926 break;
5927 }
5928 case gl::state::DIRTY_BIT_SAMPLER_BINDINGS:
5929 {
5930 static_assert(
5931 gl::state::DIRTY_BIT_TEXTURE_BINDINGS > gl::state::DIRTY_BIT_SAMPLER_BINDINGS,
5932 "Dirty bit order");
5933 iter.setLaterBit(gl::state::DIRTY_BIT_TEXTURE_BINDINGS);
5934 break;
5935 }
5936 case gl::state::DIRTY_BIT_TEXTURE_BINDINGS:
5937 ANGLE_TRY(invalidateCurrentTextures(context, command));
5938 break;
5939 case gl::state::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
5940 // Nothing to do.
5941 break;
5942 case gl::state::DIRTY_BIT_IMAGE_BINDINGS:
5943 static_assert(gl::state::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING >
5944 gl::state::DIRTY_BIT_IMAGE_BINDINGS,
5945 "Dirty bit order");
5946 iter.setLaterBit(gl::state::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
5947 break;
5948 case gl::state::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING:
5949 static_assert(gl::state::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING >
5950 gl::state::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING,
5951 "Dirty bit order");
5952 iter.setLaterBit(gl::state::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING);
5953 break;
5954 case gl::state::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS:
5955 ANGLE_TRY(invalidateCurrentShaderUniformBuffers(command));
5956 break;
5957 case gl::state::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING:
5958 ANGLE_TRY(invalidateCurrentShaderResources(command));
5959 invalidateDriverUniforms();
5960 break;
5961 case gl::state::DIRTY_BIT_MULTISAMPLING:
5962 // When disabled, this should configure the pipeline to render as if single-sampled,
5963 // and write the results to all samples of a pixel regardless of coverage. See
5964 // EXT_multisample_compatibility. This is not possible in Vulkan without some
5965 // gymnastics, so continue multisampled rendering anyway.
5966 // http://anglebug.com/42266123
5967 //
5968 // Potentially, the GLES1 renderer can switch rendering between two images and blit
5969 // from one to the other when the mode changes. Then this extension wouldn't need
5970 // to be exposed.
5971 iter.setLaterBit(gl::state::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE);
5972 break;
5973 case gl::state::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE:
5974 // This is part of EXT_multisample_compatibility, and requires the alphaToOne Vulkan
5975 // feature.
5976 // http://anglebug.com/42266123
5977 mGraphicsPipelineDesc->updateAlphaToOneEnable(
5978 &mGraphicsPipelineTransition,
5979 glState.isMultisamplingEnabled() && glState.isSampleAlphaToOneEnabled());
5980 break;
5981 case gl::state::DIRTY_BIT_SAMPLE_SHADING:
5982 updateSampleShadingWithRasterizationSamples(drawFramebufferVk->getSamples());
5983 break;
5984 case gl::state::DIRTY_BIT_COVERAGE_MODULATION:
5985 break;
5986 case gl::state::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE:
5987 break;
5988 case gl::state::DIRTY_BIT_CURRENT_VALUES:
5989 {
5990 invalidateDefaultAttributes(glState.getAndResetDirtyCurrentValues());
5991 break;
5992 }
5993 case gl::state::DIRTY_BIT_PROVOKING_VERTEX:
5994 break;
5995 case gl::state::DIRTY_BIT_EXTENDED:
5996 {
5997 for (auto extendedIter = extendedDirtyBits.begin(),
5998 extendedEndIter = extendedDirtyBits.end();
5999 extendedIter != extendedEndIter; ++extendedIter)
6000 {
6001 const size_t extendedDirtyBit = *extendedIter;
6002 switch (extendedDirtyBit)
6003 {
6004 case gl::state::EXTENDED_DIRTY_BIT_CLIP_CONTROL:
6005 updateViewport(vk::GetImpl(glState.getDrawFramebuffer()),
6006 glState.getViewport(), glState.getNearPlane(),
6007 glState.getFarPlane());
6008 // Since we are flipping the y coordinate, update front face state
6009 updateFrontFace();
6010 updateScissor(glState);
6011
6012 // If VK_EXT_depth_clip_control is not enabled, there's nothing needed
6013 // for depth correction for EXT_clip_control.
6014 // glState will be used to toggle control path of depth correction code
6015 // in SPIR-V tranform options.
6016 if (getFeatures().supportsDepthClipControl.enabled)
6017 {
6018 mGraphicsPipelineDesc->updateDepthClipControl(
6019 &mGraphicsPipelineTransition,
6020 !glState.isClipDepthModeZeroToOne());
6021 }
6022 else
6023 {
6024 invalidateGraphicsDriverUniforms();
6025 }
6026 break;
6027 case gl::state::EXTENDED_DIRTY_BIT_CLIP_DISTANCES:
6028 invalidateGraphicsDriverUniforms();
6029 break;
6030 case gl::state::EXTENDED_DIRTY_BIT_DEPTH_CLAMP_ENABLED:
6031 // TODO(https://anglebug.com/42266182): Use EDS3
6032 mGraphicsPipelineDesc->updateDepthClampEnabled(
6033 &mGraphicsPipelineTransition, glState.isDepthClampEnabled());
6034 break;
6035 case gl::state::EXTENDED_DIRTY_BIT_MIPMAP_GENERATION_HINT:
6036 break;
6037 case gl::state::EXTENDED_DIRTY_BIT_POLYGON_MODE:
6038 // TODO(https://anglebug.com/42266182): Use EDS3
6039 mGraphicsPipelineDesc->updatePolygonMode(&mGraphicsPipelineTransition,
6040 glState.getPolygonMode());
6041 // When polygon mode is changed, depth bias might need to be toggled.
6042 static_assert(
6043 gl::state::EXTENDED_DIRTY_BIT_POLYGON_OFFSET_LINE_ENABLED >
6044 gl::state::EXTENDED_DIRTY_BIT_POLYGON_MODE,
6045 "Dirty bit order");
6046 extendedIter.setLaterBit(
6047 gl::state::EXTENDED_DIRTY_BIT_POLYGON_OFFSET_LINE_ENABLED);
6048 break;
6049 case gl::state::EXTENDED_DIRTY_BIT_POLYGON_OFFSET_POINT_ENABLED:
6050 case gl::state::EXTENDED_DIRTY_BIT_POLYGON_OFFSET_LINE_ENABLED:
6051 if (mRenderer->getFeatures().useDepthBiasEnableDynamicState.enabled)
6052 {
6053 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_DEPTH_BIAS_ENABLE);
6054 }
6055 else
6056 {
6057 mGraphicsPipelineDesc->updatePolygonOffsetEnabled(
6058 &mGraphicsPipelineTransition, glState.isPolygonOffsetEnabled());
6059 }
6060 break;
6061 case gl::state::EXTENDED_DIRTY_BIT_SHADER_DERIVATIVE_HINT:
6062 break;
6063 case gl::state::EXTENDED_DIRTY_BIT_LOGIC_OP_ENABLED:
6064 mGraphicsPipelineDesc->updateLogicOpEnabled(
6065 &mGraphicsPipelineTransition, glState.isLogicOpEnabled());
6066 break;
6067 case gl::state::EXTENDED_DIRTY_BIT_LOGIC_OP:
6068 if (mRenderer->getFeatures().supportsLogicOpDynamicState.enabled)
6069 {
6070 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_LOGIC_OP);
6071 }
6072 else
6073 {
6074 mGraphicsPipelineDesc->updateLogicOp(
6075 &mGraphicsPipelineTransition,
6076 gl_vk::GetLogicOp(gl::ToGLenum(glState.getLogicOp())));
6077 }
6078 break;
6079 case gl::state::EXTENDED_DIRTY_BIT_SHADING_RATE:
6080 if (getFeatures().supportsFragmentShadingRate.enabled)
6081 {
6082 mGraphicsDirtyBits.set(DIRTY_BIT_DYNAMIC_FRAGMENT_SHADING_RATE);
6083 }
6084 break;
6085 case gl::state::EXTENDED_DIRTY_BIT_BLEND_ADVANCED_COHERENT:
6086 break;
6087 default:
6088 UNREACHABLE();
6089 }
6090 }
6091 break;
6092 }
6093 case gl::state::DIRTY_BIT_PATCH_VERTICES:
6094 mGraphicsPipelineDesc->updatePatchVertices(&mGraphicsPipelineTransition,
6095 glState.getPatchVertices());
6096 break;
6097 default:
6098 UNREACHABLE();
6099 break;
6100 }
6101 }
6102
6103 return angle::Result::Continue;
6104 }
6105
getGPUDisjoint()6106 GLint ContextVk::getGPUDisjoint()
6107 {
6108 // No extension seems to be available to query this information.
6109 return 0;
6110 }
6111
getTimestamp()6112 GLint64 ContextVk::getTimestamp()
6113 {
6114 // This function should only be called if timestamp queries are available.
6115 ASSERT(mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
6116
6117 uint64_t timestamp = 0;
6118
6119 (void)getTimestamp(×tamp);
6120
6121 return static_cast<GLint64>(timestamp);
6122 }
6123
onMakeCurrent(const gl::Context * context)6124 angle::Result ContextVk::onMakeCurrent(const gl::Context *context)
6125 {
6126 mRenderer->reloadVolkIfNeeded();
6127
6128 if (mCurrentQueueSerialIndex == kInvalidQueueSerialIndex)
6129 {
6130 ANGLE_TRY(allocateQueueSerialIndex());
6131 }
6132
6133 // Flip viewports if the user did not request that the surface is flipped.
6134 const egl::Surface *drawSurface = context->getCurrentDrawSurface();
6135 const egl::Surface *readSurface = context->getCurrentReadSurface();
6136 mFlipYForCurrentSurface =
6137 drawSurface != nullptr &&
6138 !IsMaskFlagSet(drawSurface->getOrientation(), EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE);
6139
6140 if (drawSurface && drawSurface->getType() == EGL_WINDOW_BIT)
6141 {
6142 mCurrentWindowSurface = GetImplAs<WindowSurfaceVk>(drawSurface);
6143 }
6144 else
6145 {
6146 mCurrentWindowSurface = nullptr;
6147 }
6148
6149 const gl::State &glState = context->getState();
6150 updateFlipViewportDrawFramebuffer(glState);
6151 updateFlipViewportReadFramebuffer(glState);
6152 updateSurfaceRotationDrawFramebuffer(glState, drawSurface);
6153 updateSurfaceRotationReadFramebuffer(glState, readSurface);
6154
6155 invalidateDriverUniforms();
6156
6157 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6158 if (executable && executable->hasTransformFeedbackOutput() &&
6159 mState.isTransformFeedbackActive())
6160 {
6161 onTransformFeedbackStateChanged();
6162 if (getFeatures().supportsTransformFeedbackExtension.enabled)
6163 {
6164 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
6165 }
6166 }
6167
6168 return angle::Result::Continue;
6169 }
6170
onUnMakeCurrent(const gl::Context * context)6171 angle::Result ContextVk::onUnMakeCurrent(const gl::Context *context)
6172 {
6173 ANGLE_TRY(flushAndSubmitCommands(nullptr, nullptr, RenderPassClosureReason::ContextChange));
6174 mCurrentWindowSurface = nullptr;
6175
6176 if (mCurrentQueueSerialIndex != kInvalidQueueSerialIndex)
6177 {
6178 releaseQueueSerialIndex();
6179 }
6180 return angle::Result::Continue;
6181 }
6182
onSurfaceUnMakeCurrent(WindowSurfaceVk * surface)6183 angle::Result ContextVk::onSurfaceUnMakeCurrent(WindowSurfaceVk *surface)
6184 {
6185 // It is possible to destroy "WindowSurfaceVk" while not all rendering commands are submitted:
6186 // 1. Make "WindowSurfaceVk" current.
6187 // 2. Draw something.
6188 // 3. Make other Surface current (same Context).
6189 // 4. (optional) Draw something.
6190 // 5. Delete "WindowSurfaceVk".
6191 // 6. UnMake the Context from current.
6192 // Flush all command to the GPU while still having access to the Context.
6193
6194 // The above "onUnMakeCurrent()" may have already been called.
6195 if (mCurrentQueueSerialIndex != kInvalidQueueSerialIndex)
6196 {
6197 // May be nullptr if only used as a readSurface.
6198 ASSERT(mCurrentWindowSurface == surface || mCurrentWindowSurface == nullptr);
6199 ANGLE_TRY(flushAndSubmitCommands(nullptr, nullptr,
6200 RenderPassClosureReason::SurfaceUnMakeCurrent));
6201 mCurrentWindowSurface = nullptr;
6202 }
6203 ASSERT(mCurrentWindowSurface == nullptr);
6204
6205 // Everything must be flushed and submitted.
6206 ASSERT(mOutsideRenderPassCommands->empty());
6207 ASSERT(!mRenderPassCommands->started());
6208 ASSERT(mWaitSemaphores.empty());
6209 ASSERT(!mHasWaitSemaphoresPendingSubmission);
6210 ASSERT(mLastSubmittedQueueSerial == mLastFlushedQueueSerial);
6211 return angle::Result::Continue;
6212 }
6213
onSurfaceUnMakeCurrent(OffscreenSurfaceVk * surface)6214 angle::Result ContextVk::onSurfaceUnMakeCurrent(OffscreenSurfaceVk *surface)
6215 {
6216 // It is possible to destroy "OffscreenSurfaceVk" while RenderPass is still opened:
6217 // 1. Make "OffscreenSurfaceVk" current.
6218 // 2. Draw something with RenderPass.
6219 // 3. Make other Surface current (same Context)
6220 // 4. Delete "OffscreenSurfaceVk".
6221 // 5. UnMake the Context from current.
6222 // End RenderPass to avoid crash in the "RenderPassCommandBufferHelper::endRenderPass()".
6223 // Flush commands unconditionally even if surface is not used in the RenderPass to fix possible
6224 // problems related to other accesses. "flushAndSubmitCommands()" is not required because
6225 // "OffscreenSurfaceVk" uses GC.
6226
6227 // The above "onUnMakeCurrent()" may have already been called.
6228 if (mCurrentQueueSerialIndex != kInvalidQueueSerialIndex)
6229 {
6230 ANGLE_TRY(flushCommandsAndEndRenderPass(RenderPassClosureReason::SurfaceUnMakeCurrent));
6231 }
6232
6233 // Everything must be flushed but may be pending submission.
6234 ASSERT(mOutsideRenderPassCommands->empty());
6235 ASSERT(!mRenderPassCommands->started());
6236 ASSERT(mWaitSemaphores.empty());
6237 return angle::Result::Continue;
6238 }
6239
updateFlipViewportDrawFramebuffer(const gl::State & glState)6240 void ContextVk::updateFlipViewportDrawFramebuffer(const gl::State &glState)
6241 {
6242 // The default framebuffer (originating from the swapchain) is rendered upside-down due to the
6243 // difference in the coordinate systems of Vulkan and GLES. Rendering upside-down has the
6244 // effect that rendering is done the same way as OpenGL. The KHR_MAINTENANCE_1 extension is
6245 // subsequently enabled to allow negative viewports. We inverse rendering to the backbuffer by
6246 // reversing the height of the viewport and increasing Y by the height. So if the viewport was
6247 // (0, 0, width, height), it becomes (0, height, width, -height). Unfortunately, when we start
6248 // doing this, we also need to adjust a number of places since the rendering now happens
6249 // upside-down. Affected places so far:
6250 //
6251 // - readPixels
6252 // - copyTexImage
6253 // - framebuffer blit
6254 // - generating mipmaps
6255 // - Point sprites tests
6256 // - texStorage
6257 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
6258 mFlipViewportForDrawFramebuffer = drawFramebuffer->isDefault();
6259 }
6260
updateFlipViewportReadFramebuffer(const gl::State & glState)6261 void ContextVk::updateFlipViewportReadFramebuffer(const gl::State &glState)
6262 {
6263 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
6264 mFlipViewportForReadFramebuffer = readFramebuffer->isDefault();
6265 }
6266
updateSurfaceRotationDrawFramebuffer(const gl::State & glState,const egl::Surface * currentDrawSurface)6267 void ContextVk::updateSurfaceRotationDrawFramebuffer(const gl::State &glState,
6268 const egl::Surface *currentDrawSurface)
6269 {
6270 const SurfaceRotation rotation =
6271 getSurfaceRotationImpl(glState.getDrawFramebuffer(), currentDrawSurface);
6272 mCurrentRotationDrawFramebuffer = rotation;
6273
6274 if (!getFeatures().preferDriverUniformOverSpecConst.enabled)
6275 {
6276 const bool isRotatedAspectRatio = IsRotatedAspectRatio(rotation);
6277 // Update spec consts
6278 if (isRotatedAspectRatio != mGraphicsPipelineDesc->getSurfaceRotation())
6279 {
6280 // surface rotation are specialization constants, which affects program compilation.
6281 // When rotation changes, we need to update GraphicsPipelineDesc so that the correct
6282 // pipeline program object will be retrieved.
6283 mGraphicsPipelineDesc->updateSurfaceRotation(&mGraphicsPipelineTransition,
6284 isRotatedAspectRatio);
6285 invalidateCurrentGraphicsPipeline();
6286 }
6287 }
6288 }
6289
updateSurfaceRotationReadFramebuffer(const gl::State & glState,const egl::Surface * currentReadSurface)6290 void ContextVk::updateSurfaceRotationReadFramebuffer(const gl::State &glState,
6291 const egl::Surface *currentReadSurface)
6292 {
6293 mCurrentRotationReadFramebuffer =
6294 getSurfaceRotationImpl(glState.getReadFramebuffer(), currentReadSurface);
6295 }
6296
getNativeCaps() const6297 gl::Caps ContextVk::getNativeCaps() const
6298 {
6299 return mRenderer->getNativeCaps();
6300 }
6301
getNativeTextureCaps() const6302 const gl::TextureCapsMap &ContextVk::getNativeTextureCaps() const
6303 {
6304 return mRenderer->getNativeTextureCaps();
6305 }
6306
getNativeExtensions() const6307 const gl::Extensions &ContextVk::getNativeExtensions() const
6308 {
6309 return mRenderer->getNativeExtensions();
6310 }
6311
getNativeLimitations() const6312 const gl::Limitations &ContextVk::getNativeLimitations() const
6313 {
6314 return mRenderer->getNativeLimitations();
6315 }
6316
getNativePixelLocalStorageOptions() const6317 const ShPixelLocalStorageOptions &ContextVk::getNativePixelLocalStorageOptions() const
6318 {
6319 return mRenderer->getNativePixelLocalStorageOptions();
6320 }
6321
createCompiler()6322 CompilerImpl *ContextVk::createCompiler()
6323 {
6324 return new CompilerVk();
6325 }
6326
createShader(const gl::ShaderState & state)6327 ShaderImpl *ContextVk::createShader(const gl::ShaderState &state)
6328 {
6329 return new ShaderVk(state);
6330 }
6331
createProgram(const gl::ProgramState & state)6332 ProgramImpl *ContextVk::createProgram(const gl::ProgramState &state)
6333 {
6334 return new ProgramVk(state);
6335 }
6336
createProgramExecutable(const gl::ProgramExecutable * executable)6337 ProgramExecutableImpl *ContextVk::createProgramExecutable(const gl::ProgramExecutable *executable)
6338 {
6339 return new ProgramExecutableVk(executable);
6340 }
6341
createFramebuffer(const gl::FramebufferState & state)6342 FramebufferImpl *ContextVk::createFramebuffer(const gl::FramebufferState &state)
6343 {
6344 return new FramebufferVk(mRenderer, state);
6345 }
6346
createTexture(const gl::TextureState & state)6347 TextureImpl *ContextVk::createTexture(const gl::TextureState &state)
6348 {
6349 return new TextureVk(state, mRenderer);
6350 }
6351
createRenderbuffer(const gl::RenderbufferState & state)6352 RenderbufferImpl *ContextVk::createRenderbuffer(const gl::RenderbufferState &state)
6353 {
6354 return new RenderbufferVk(state);
6355 }
6356
createBuffer(const gl::BufferState & state)6357 BufferImpl *ContextVk::createBuffer(const gl::BufferState &state)
6358 {
6359 return new BufferVk(state);
6360 }
6361
createVertexArray(const gl::VertexArrayState & state)6362 VertexArrayImpl *ContextVk::createVertexArray(const gl::VertexArrayState &state)
6363 {
6364 return new VertexArrayVk(this, state);
6365 }
6366
createQuery(gl::QueryType type)6367 QueryImpl *ContextVk::createQuery(gl::QueryType type)
6368 {
6369 return new QueryVk(type);
6370 }
6371
createFenceNV()6372 FenceNVImpl *ContextVk::createFenceNV()
6373 {
6374 return new FenceNVVk();
6375 }
6376
createSync()6377 SyncImpl *ContextVk::createSync()
6378 {
6379 return new SyncVk();
6380 }
6381
createTransformFeedback(const gl::TransformFeedbackState & state)6382 TransformFeedbackImpl *ContextVk::createTransformFeedback(const gl::TransformFeedbackState &state)
6383 {
6384 return new TransformFeedbackVk(state);
6385 }
6386
createSampler(const gl::SamplerState & state)6387 SamplerImpl *ContextVk::createSampler(const gl::SamplerState &state)
6388 {
6389 return new SamplerVk(state);
6390 }
6391
createProgramPipeline(const gl::ProgramPipelineState & state)6392 ProgramPipelineImpl *ContextVk::createProgramPipeline(const gl::ProgramPipelineState &state)
6393 {
6394 return new ProgramPipelineVk(state);
6395 }
6396
createMemoryObject()6397 MemoryObjectImpl *ContextVk::createMemoryObject()
6398 {
6399 return new MemoryObjectVk();
6400 }
6401
createSemaphore()6402 SemaphoreImpl *ContextVk::createSemaphore()
6403 {
6404 return new SemaphoreVk();
6405 }
6406
createOverlay(const gl::OverlayState & state)6407 OverlayImpl *ContextVk::createOverlay(const gl::OverlayState &state)
6408 {
6409 return new OverlayVk(state);
6410 }
6411
invalidateCurrentDefaultUniforms()6412 void ContextVk::invalidateCurrentDefaultUniforms()
6413 {
6414 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6415 ASSERT(executable);
6416
6417 if (executable->hasDefaultUniforms())
6418 {
6419 mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
6420 mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
6421 }
6422 }
6423
invalidateCurrentTextures(const gl::Context * context,gl::Command command)6424 angle::Result ContextVk::invalidateCurrentTextures(const gl::Context *context, gl::Command command)
6425 {
6426 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6427 ASSERT(executable);
6428
6429 if (executable->hasTextures())
6430 {
6431 mGraphicsDirtyBits |= kTexturesAndDescSetDirtyBits;
6432 mComputeDirtyBits |= kTexturesAndDescSetDirtyBits;
6433
6434 ANGLE_TRY(updateActiveTextures(context, command));
6435
6436 if (command == gl::Command::Dispatch)
6437 {
6438 ANGLE_TRY(endRenderPassIfComputeAccessAfterGraphicsImageAccess());
6439 }
6440 }
6441 return angle::Result::Continue;
6442 }
6443
invalidateCurrentShaderResources(gl::Command command)6444 angle::Result ContextVk::invalidateCurrentShaderResources(gl::Command command)
6445 {
6446 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6447 ASSERT(executable);
6448
6449 const bool hasImages = executable->hasImages();
6450 const bool hasStorageBuffers =
6451 executable->hasStorageBuffers() || executable->hasAtomicCounterBuffers();
6452 const bool hasUniformBuffers = executable->hasUniformBuffers();
6453
6454 if (hasUniformBuffers || hasStorageBuffers || hasImages ||
6455 executable->usesColorFramebufferFetch() || executable->usesDepthFramebufferFetch() ||
6456 executable->usesStencilFramebufferFetch())
6457 {
6458 mGraphicsDirtyBits |= kResourcesAndDescSetDirtyBits;
6459 mComputeDirtyBits |= kResourcesAndDescSetDirtyBits;
6460 }
6461
6462 // Take care of read-after-write hazards that require implicit synchronization.
6463 if (hasUniformBuffers && command == gl::Command::Dispatch)
6464 {
6465 ANGLE_TRY(endRenderPassIfComputeReadAfterTransformFeedbackWrite());
6466 }
6467
6468 // Take care of implict layout transition by compute program access-after-read.
6469 if (hasImages && command == gl::Command::Dispatch)
6470 {
6471 ANGLE_TRY(endRenderPassIfComputeAccessAfterGraphicsImageAccess());
6472 }
6473
6474 // If memory barrier has been issued but the command buffers haven't been flushed, make sure
6475 // they get a chance to do so if necessary on program and storage buffer/image binding change.
6476 const bool hasGLMemoryBarrierIssuedInCommandBuffers =
6477 mOutsideRenderPassCommands->hasGLMemoryBarrierIssued() ||
6478 mRenderPassCommands->hasGLMemoryBarrierIssued();
6479
6480 if ((hasStorageBuffers || hasImages) && hasGLMemoryBarrierIssuedInCommandBuffers)
6481 {
6482 mGraphicsDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
6483 mComputeDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
6484 }
6485
6486 return angle::Result::Continue;
6487 }
6488
invalidateCurrentShaderUniformBuffers(gl::Command command)6489 angle::Result ContextVk::invalidateCurrentShaderUniformBuffers(gl::Command command)
6490 {
6491 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6492 ASSERT(executable);
6493
6494 if (executable->hasUniformBuffers())
6495 {
6496 if (executable->hasLinkedShaderStage(gl::ShaderType::Compute))
6497 {
6498 mComputeDirtyBits |= kUniformBuffersAndDescSetDirtyBits;
6499 }
6500 else
6501 {
6502 mGraphicsDirtyBits |= kUniformBuffersAndDescSetDirtyBits;
6503 }
6504
6505 if (command == gl::Command::Dispatch)
6506 {
6507 // Take care of read-after-write hazards that require implicit synchronization.
6508 ANGLE_TRY(endRenderPassIfComputeReadAfterTransformFeedbackWrite());
6509 }
6510 }
6511 return angle::Result::Continue;
6512 }
6513
updateShaderResourcesWithSharedCacheKey(const vk::SharedDescriptorSetCacheKey & sharedCacheKey)6514 void ContextVk::updateShaderResourcesWithSharedCacheKey(
6515 const vk::SharedDescriptorSetCacheKey &sharedCacheKey)
6516 {
6517 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6518 ProgramExecutableVk *executableVk = vk::GetImpl(executable);
6519
6520 if (executable->hasUniformBuffers())
6521 {
6522 const std::vector<gl::InterfaceBlock> &blocks = executable->getUniformBlocks();
6523 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
6524 {
6525 const GLuint binding = executable->getUniformBlockBinding(bufferIndex);
6526 UpdateBufferWithSharedCacheKey(mState.getOffsetBindingPointerUniformBuffers()[binding],
6527 executableVk->getUniformBufferDescriptorType(),
6528 sharedCacheKey);
6529 }
6530 }
6531 if (executable->hasStorageBuffers())
6532 {
6533 const std::vector<gl::InterfaceBlock> &blocks = executable->getShaderStorageBlocks();
6534 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
6535 {
6536 const GLuint binding = executable->getShaderStorageBlockBinding(bufferIndex);
6537 UpdateBufferWithSharedCacheKey(
6538 mState.getOffsetBindingPointerShaderStorageBuffers()[binding],
6539 executableVk->getStorageBufferDescriptorType(), sharedCacheKey);
6540 }
6541 }
6542 if (executable->hasAtomicCounterBuffers())
6543 {
6544 const std::vector<gl::AtomicCounterBuffer> &blocks = executable->getAtomicCounterBuffers();
6545 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
6546 {
6547 const GLuint binding = executable->getAtomicCounterBufferBinding(bufferIndex);
6548 UpdateBufferWithSharedCacheKey(
6549 mState.getOffsetBindingPointerAtomicCounterBuffers()[binding],
6550 executableVk->getAtomicCounterBufferDescriptorType(), sharedCacheKey);
6551 }
6552 }
6553 if (executable->hasImages())
6554 {
6555 UpdateImagesWithSharedCacheKey(mActiveImages, executable->getImageBindings(),
6556 sharedCacheKey);
6557 }
6558 }
6559
invalidateGraphicsDriverUniforms()6560 void ContextVk::invalidateGraphicsDriverUniforms()
6561 {
6562 mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS);
6563 }
6564
invalidateDriverUniforms()6565 void ContextVk::invalidateDriverUniforms()
6566 {
6567 mGraphicsDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS);
6568 mComputeDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS);
6569 }
6570
onFramebufferChange(FramebufferVk * framebufferVk,gl::Command command)6571 angle::Result ContextVk::onFramebufferChange(FramebufferVk *framebufferVk, gl::Command command)
6572 {
6573 // This is called from FramebufferVk::syncState. Skip these updates if the framebuffer being
6574 // synced is the read framebuffer (which is not equal the draw framebuffer).
6575 if (framebufferVk != vk::GetImpl(mState.getDrawFramebuffer()))
6576 {
6577 return angle::Result::Continue;
6578 }
6579
6580 // Always consider the render pass finished. FramebufferVk::syncState (caller of this function)
6581 // normally closes the render pass, except for blit to allow an optimization. The following
6582 // code nevertheless must treat the render pass closed.
6583 onRenderPassFinished(RenderPassClosureReason::FramebufferChange);
6584
6585 // Ensure that the pipeline description is updated.
6586 if (mGraphicsPipelineDesc->getRasterizationSamples() !=
6587 static_cast<uint32_t>(framebufferVk->getSamples()))
6588 {
6589 updateRasterizationSamples(framebufferVk->getSamples());
6590 }
6591
6592 // Update scissor.
6593 updateScissor(mState);
6594
6595 // Update depth and stencil.
6596 updateDepthStencil(mState);
6597
6598 // Update dither based on attachment formats.
6599 updateDither();
6600
6601 // Attachments might have changed.
6602 updateMissingOutputsMask();
6603
6604 if (mState.getProgramExecutable())
6605 {
6606 ANGLE_TRY(invalidateCurrentShaderResources(command));
6607 }
6608
6609 onDrawFramebufferRenderPassDescChange(framebufferVk, nullptr);
6610 return angle::Result::Continue;
6611 }
6612
onDrawFramebufferRenderPassDescChange(FramebufferVk * framebufferVk,bool * renderPassDescChangedOut)6613 void ContextVk::onDrawFramebufferRenderPassDescChange(FramebufferVk *framebufferVk,
6614 bool *renderPassDescChangedOut)
6615 {
6616 ASSERT(getFeatures().supportsFragmentShadingRate.enabled ||
6617 !framebufferVk->isFoveationEnabled());
6618
6619 const vk::FramebufferFetchMode framebufferFetchMode =
6620 vk::GetProgramFramebufferFetchMode(mState.getProgramExecutable());
6621 mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition, getFeatures(),
6622 framebufferVk->getRenderPassDesc(),
6623 framebufferFetchMode);
6624
6625 if (renderPassDescChangedOut)
6626 {
6627 // If render pass desc has changed while processing the dirty bits, notify the caller.
6628 // In most paths, |renderPassDescChangedOut| is nullptr and the pipeline will be
6629 // invalidated.
6630 //
6631 // |renderPassDescChangedOut| only serves |ContextVk::handleDirtyGraphicsRenderPass|, which
6632 // may need to reprocess the pipeline while processing dirty bits. At that point, marking
6633 // the pipeline dirty is ineffective, and the pipeline dirty bit handler is directly called
6634 // as a result of setting this variable to true.
6635 *renderPassDescChangedOut = true;
6636 }
6637 else
6638 {
6639 // Otherwise mark the pipeline as dirty.
6640 invalidateCurrentGraphicsPipeline();
6641 }
6642
6643 // Update render area in the driver uniforms.
6644 invalidateGraphicsDriverUniforms();
6645 }
6646
invalidateCurrentTransformFeedbackBuffers()6647 void ContextVk::invalidateCurrentTransformFeedbackBuffers()
6648 {
6649 if (getFeatures().supportsTransformFeedbackExtension.enabled)
6650 {
6651 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
6652 }
6653 else if (getFeatures().emulateTransformFeedback.enabled)
6654 {
6655 mGraphicsDirtyBits |= kXfbBuffersAndDescSetDirtyBits;
6656 }
6657 }
6658
onTransformFeedbackStateChanged()6659 void ContextVk::onTransformFeedbackStateChanged()
6660 {
6661 if (getFeatures().supportsTransformFeedbackExtension.enabled)
6662 {
6663 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
6664 }
6665 else if (getFeatures().emulateTransformFeedback.enabled)
6666 {
6667 invalidateGraphicsDriverUniforms();
6668 invalidateCurrentTransformFeedbackBuffers();
6669
6670 // Invalidate the graphics pipeline too. On transform feedback state change, the current
6671 // program may be used again, and it should switch between outputting transform feedback and
6672 // not.
6673 invalidateCurrentGraphicsPipeline();
6674 resetCurrentGraphicsPipeline();
6675 }
6676 }
6677
onBeginTransformFeedback(size_t bufferCount,const gl::TransformFeedbackBuffersArray<vk::BufferHelper * > & buffers,const gl::TransformFeedbackBuffersArray<vk::BufferHelper> & counterBuffers)6678 angle::Result ContextVk::onBeginTransformFeedback(
6679 size_t bufferCount,
6680 const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers,
6681 const gl::TransformFeedbackBuffersArray<vk::BufferHelper> &counterBuffers)
6682 {
6683 onTransformFeedbackStateChanged();
6684
6685 bool shouldEndRenderPass = false;
6686
6687 if (hasActiveRenderPass())
6688 {
6689 // If any of the buffers were previously used in the render pass, break the render pass as a
6690 // barrier is needed.
6691 for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
6692 {
6693 const vk::BufferHelper *buffer = buffers[bufferIndex];
6694 if (mRenderPassCommands->usesBuffer(*buffer))
6695 {
6696 shouldEndRenderPass = true;
6697 break;
6698 }
6699 }
6700 }
6701
6702 if (getFeatures().supportsTransformFeedbackExtension.enabled)
6703 {
6704 // Break the render pass if the counter buffers are used too. Note that Vulkan requires a
6705 // barrier on the counter buffer between pause and resume, so it cannot be resumed in the
6706 // same render pass. Note additionally that we don't need to test all counters being used
6707 // in the render pass, as outside of the transform feedback object these buffers are
6708 // inaccessible and are therefore always used together.
6709 if (!shouldEndRenderPass && isRenderPassStartedAndUsesBuffer(counterBuffers[0]))
6710 {
6711 shouldEndRenderPass = true;
6712 }
6713
6714 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
6715 }
6716
6717 if (shouldEndRenderPass)
6718 {
6719 ANGLE_TRY(flushCommandsAndEndRenderPass(RenderPassClosureReason::BufferUseThenXfbWrite));
6720 }
6721
6722 return angle::Result::Continue;
6723 }
6724
onEndTransformFeedback()6725 void ContextVk::onEndTransformFeedback()
6726 {
6727 if (getFeatures().supportsTransformFeedbackExtension.enabled)
6728 {
6729 if (mRenderPassCommands->isTransformFeedbackStarted())
6730 {
6731 mRenderPassCommands->endTransformFeedback();
6732 }
6733 }
6734 else if (getFeatures().emulateTransformFeedback.enabled)
6735 {
6736 onTransformFeedbackStateChanged();
6737 }
6738 }
6739
onPauseTransformFeedback()6740 angle::Result ContextVk::onPauseTransformFeedback()
6741 {
6742 if (getFeatures().supportsTransformFeedbackExtension.enabled)
6743 {
6744 // If transform feedback was already active on this render pass, break it. This
6745 // is for simplicity to avoid tracking multiple simultaneously active transform feedback
6746 // settings in the render pass.
6747 if (mRenderPassCommands->isTransformFeedbackActiveUnpaused())
6748 {
6749 return flushCommandsAndEndRenderPass(RenderPassClosureReason::XfbPause);
6750 }
6751 }
6752 onTransformFeedbackStateChanged();
6753 return angle::Result::Continue;
6754 }
6755
invalidateGraphicsPipelineBinding()6756 void ContextVk::invalidateGraphicsPipelineBinding()
6757 {
6758 mGraphicsDirtyBits.set(DIRTY_BIT_PIPELINE_BINDING);
6759 }
6760
invalidateComputePipelineBinding()6761 void ContextVk::invalidateComputePipelineBinding()
6762 {
6763 mComputeDirtyBits.set(DIRTY_BIT_PIPELINE_BINDING);
6764 }
6765
invalidateGraphicsDescriptorSet(DescriptorSetIndex usedDescriptorSet)6766 void ContextVk::invalidateGraphicsDescriptorSet(DescriptorSetIndex usedDescriptorSet)
6767 {
6768 // UtilsVk currently only uses set 0
6769 ASSERT(usedDescriptorSet == DescriptorSetIndex::Internal);
6770 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6771
6772 if (executable && executable->hasUniformBuffers())
6773 {
6774 mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
6775 return;
6776 }
6777 }
6778
invalidateComputeDescriptorSet(DescriptorSetIndex usedDescriptorSet)6779 void ContextVk::invalidateComputeDescriptorSet(DescriptorSetIndex usedDescriptorSet)
6780 {
6781 // UtilsVk currently only uses set 0
6782 ASSERT(usedDescriptorSet == DescriptorSetIndex::Internal);
6783 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
6784
6785 if (executable && executable->hasUniformBuffers())
6786 {
6787 mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
6788 return;
6789 }
6790 }
6791
invalidateAllDynamicState()6792 void ContextVk::invalidateAllDynamicState()
6793 {
6794 mGraphicsDirtyBits |= mDynamicStateDirtyBits;
6795 }
6796
dispatchCompute(const gl::Context * context,GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)6797 angle::Result ContextVk::dispatchCompute(const gl::Context *context,
6798 GLuint numGroupsX,
6799 GLuint numGroupsY,
6800 GLuint numGroupsZ)
6801 {
6802 ANGLE_TRY(setupDispatch(context));
6803
6804 mOutsideRenderPassCommands->getCommandBuffer().dispatch(numGroupsX, numGroupsY, numGroupsZ);
6805 // Track completion of compute.
6806 mOutsideRenderPassCommands->flushSetEvents(this);
6807
6808 return angle::Result::Continue;
6809 }
6810
dispatchComputeIndirect(const gl::Context * context,GLintptr indirect)6811 angle::Result ContextVk::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
6812 {
6813 gl::Buffer *glBuffer = getState().getTargetBuffer(gl::BufferBinding::DispatchIndirect);
6814 vk::BufferHelper &buffer = vk::GetImpl(glBuffer)->getBuffer();
6815
6816 // Break the render pass if the indirect buffer was previously used as the output from transform
6817 // feedback.
6818 if (mCurrentTransformFeedbackQueueSerial.valid() &&
6819 buffer.writtenByCommandBuffer(mCurrentTransformFeedbackQueueSerial))
6820 {
6821 ANGLE_TRY(flushCommandsAndEndRenderPass(
6822 RenderPassClosureReason::XfbWriteThenIndirectDispatchBuffer));
6823 }
6824
6825 ANGLE_TRY(setupDispatch(context));
6826
6827 // Process indirect buffer after command buffer has started.
6828 mOutsideRenderPassCommands->bufferRead(VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
6829 vk::PipelineStage::DrawIndirect, &buffer);
6830
6831 mOutsideRenderPassCommands->getCommandBuffer().dispatchIndirect(buffer.getBuffer(),
6832 buffer.getOffset() + indirect);
6833
6834 // Track completion of compute.
6835 mOutsideRenderPassCommands->flushSetEvents(this);
6836
6837 return angle::Result::Continue;
6838 }
6839
memoryBarrier(const gl::Context * context,GLbitfield barriers)6840 angle::Result ContextVk::memoryBarrier(const gl::Context *context, GLbitfield barriers)
6841 {
6842 // First, turn GL_ALL_BARRIER_BITS into a mask that has only the valid barriers set.
6843 constexpr GLbitfield kAllMemoryBarrierBits = kBufferMemoryBarrierBits | kImageMemoryBarrierBits;
6844 barriers &= kAllMemoryBarrierBits;
6845
6846 // GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT specifies that a fence sync or glFinish must be used
6847 // after the barrier for the CPU to to see the shader writes. Since host-visible buffer writes
6848 // always issue a barrier automatically for the sake of glMapBuffer() (see
6849 // comment on |mIsAnyHostVisibleBufferWritten|), there's nothing to do for
6850 // GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT.
6851 barriers &= ~GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT;
6852
6853 // If no other barrier, early out.
6854 if (barriers == 0)
6855 {
6856 return angle::Result::Continue;
6857 }
6858
6859 // glMemoryBarrier for barrier bit X_BARRIER_BIT implies:
6860 //
6861 // - An execution+memory barrier: shader writes are made visible to subsequent X accesses
6862 //
6863 // Additionally, SHADER_IMAGE_ACCESS_BARRIER_BIT and SHADER_STORAGE_BARRIER_BIT imply:
6864 //
6865 // - An execution+memory barrier: all accesses are finished before image/buffer writes
6866 //
6867 // For the first barrier, we can simplify the implementation by assuming that prior writes are
6868 // expected to be used right after this barrier, so we can close the render pass or flush the
6869 // outside render pass commands right away if they have had any writes.
6870 //
6871 // It's noteworthy that some barrier bits affect draw/dispatch calls only, while others affect
6872 // other commands. For the latter, since storage buffer and images are not tracked in command
6873 // buffers, we can't rely on the command buffers being flushed in the usual way when recording
6874 // these commands (i.e. through |getOutsideRenderPassCommandBuffer()| and
6875 // |vk::CommandBufferAccess|). Conservatively flushing command buffers with any storage output
6876 // simplifies this use case. If this needs to be avoided in the future,
6877 // |getOutsideRenderPassCommandBuffer()| can be modified to flush the command buffers if they
6878 // have had any storage output.
6879 //
6880 // For the second barrier, we need to defer closing the render pass until there's a draw or
6881 // dispatch call that uses storage buffers or images that were previously used in the render
6882 // pass. This allows the render pass to remain open in scenarios such as this:
6883 //
6884 // - Draw using resource X
6885 // - glMemoryBarrier
6886 // - Draw/dispatch with storage buffer/image Y
6887 //
6888 // To achieve this, a dirty bit is added that breaks the render pass if any storage
6889 // buffer/images are used in it. Until the render pass breaks, changing the program or storage
6890 // buffer/image bindings should set this dirty bit again.
6891
6892 if (mRenderPassCommands->hasShaderStorageOutput())
6893 {
6894 // Break the render pass if necessary as future non-draw commands can't know if they should.
6895 ANGLE_TRY(flushCommandsAndEndRenderPass(
6896 RenderPassClosureReason::StorageResourceUseThenGLMemoryBarrier));
6897 }
6898 else if (mOutsideRenderPassCommands->hasShaderStorageOutput())
6899 {
6900 // Otherwise flush the outside render pass commands if necessary.
6901 ANGLE_TRY(flushOutsideRenderPassCommands());
6902 }
6903
6904 if ((barriers & kWriteAfterAccessMemoryBarriers) == 0)
6905 {
6906 return angle::Result::Continue;
6907 }
6908
6909 // Accumulate unprocessed memoryBarrier bits
6910 mDeferredMemoryBarriers |= barriers;
6911
6912 // Defer flushing the command buffers until a draw/dispatch with storage buffer/image is
6913 // encountered.
6914 mGraphicsDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
6915 mComputeDirtyBits.set(DIRTY_BIT_MEMORY_BARRIER);
6916
6917 // Make sure memory barrier is issued for future usages of storage buffers and images even if
6918 // there's no binding change.
6919 mGraphicsDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
6920 mComputeDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
6921
6922 // Mark the command buffers as affected by glMemoryBarrier, so future program and storage
6923 // buffer/image binding changes can set DIRTY_BIT_MEMORY_BARRIER again.
6924 mOutsideRenderPassCommands->setGLMemoryBarrierIssued();
6925 mRenderPassCommands->setGLMemoryBarrierIssued();
6926
6927 return angle::Result::Continue;
6928 }
6929
memoryBarrierByRegion(const gl::Context * context,GLbitfield barriers)6930 angle::Result ContextVk::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers)
6931 {
6932 // Note: memoryBarrierByRegion is expected to affect only the fragment pipeline, but is
6933 // otherwise similar to memoryBarrier in function.
6934 //
6935 // TODO: Optimize memoryBarrierByRegion by issuing an in-subpass pipeline barrier instead of
6936 // breaking the render pass. http://anglebug.com/42263695
6937 return memoryBarrier(context, barriers);
6938 }
6939
framebufferFetchBarrier()6940 void ContextVk::framebufferFetchBarrier()
6941 {
6942 // No need for a barrier with VK_EXT_rasterization_order_attachment_access.
6943 if (getFeatures().supportsRasterizationOrderAttachmentAccess.enabled)
6944 {
6945 return;
6946 }
6947
6948 mGraphicsDirtyBits.set(DIRTY_BIT_FRAMEBUFFER_FETCH_BARRIER);
6949 }
6950
blendBarrier()6951 void ContextVk::blendBarrier()
6952 {
6953 if (getFeatures().emulateAdvancedBlendEquations.enabled)
6954 {
6955 // When emulated, advanced blend is implemented through framebuffer fetch.
6956 framebufferFetchBarrier();
6957 }
6958 else
6959 {
6960 mGraphicsDirtyBits.set(DIRTY_BIT_BLEND_BARRIER);
6961 }
6962 }
6963
acquireTextures(const gl::Context * context,const gl::TextureBarrierVector & textureBarriers)6964 angle::Result ContextVk::acquireTextures(const gl::Context *context,
6965 const gl::TextureBarrierVector &textureBarriers)
6966 {
6967 for (const gl::TextureAndLayout &textureBarrier : textureBarriers)
6968 {
6969 TextureVk *textureVk = vk::GetImpl(textureBarrier.texture);
6970 vk::ImageHelper &image = textureVk->getImage();
6971 vk::ImageLayout layout = vk::GetImageLayoutFromGLImageLayout(this, textureBarrier.layout);
6972 // Image should not be accessed while unowned. Emulated formats may have staged updates
6973 // to clear the image after initialization.
6974 ASSERT(!image.hasStagedUpdatesInAllocatedLevels() || image.hasEmulatedImageChannels());
6975 image.setCurrentImageLayout(getRenderer(), layout);
6976 }
6977 return angle::Result::Continue;
6978 }
6979
releaseTextures(const gl::Context * context,gl::TextureBarrierVector * textureBarriers)6980 angle::Result ContextVk::releaseTextures(const gl::Context *context,
6981 gl::TextureBarrierVector *textureBarriers)
6982 {
6983 for (gl::TextureAndLayout &textureBarrier : *textureBarriers)
6984 {
6985 TextureVk *textureVk = vk::GetImpl(textureBarrier.texture);
6986
6987 ANGLE_TRY(textureVk->ensureImageInitialized(this, ImageMipLevels::EnabledLevels));
6988
6989 vk::ImageHelper &image = textureVk->getImage();
6990 ANGLE_TRY(onImageReleaseToExternal(image));
6991
6992 textureBarrier.layout =
6993 vk::ConvertImageLayoutToGLImageLayout(image.getCurrentImageLayout());
6994 }
6995
6996 ANGLE_TRY(flushAndSubmitCommands(nullptr, nullptr,
6997 RenderPassClosureReason::ImageUseThenReleaseToExternal));
6998 return mRenderer->waitForResourceUseToBeSubmittedToDevice(this, mSubmittedResourceUse);
6999 }
7000
getQueryPool(gl::QueryType queryType)7001 vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType)
7002 {
7003 ASSERT(queryType == gl::QueryType::AnySamples ||
7004 queryType == gl::QueryType::AnySamplesConservative ||
7005 queryType == gl::QueryType::PrimitivesGenerated ||
7006 queryType == gl::QueryType::TransformFeedbackPrimitivesWritten ||
7007 queryType == gl::QueryType::Timestamp || queryType == gl::QueryType::TimeElapsed);
7008
7009 // For PrimitivesGenerated queries:
7010 //
7011 // - If VK_EXT_primitives_generated_query is supported, use that.
7012 // - Otherwise, if pipelineStatisticsQuery is supported, use that,
7013 // - Otherwise, use the same pool as TransformFeedbackPrimitivesWritten and share the query as
7014 // the Vulkan transform feedback query produces both results. This option is non-conformant
7015 // as the primitives generated query will not be functional without transform feedback.
7016 //
7017 if (queryType == gl::QueryType::PrimitivesGenerated &&
7018 !getFeatures().supportsPrimitivesGeneratedQuery.enabled &&
7019 !getFeatures().supportsPipelineStatisticsQuery.enabled)
7020 {
7021 queryType = gl::QueryType::TransformFeedbackPrimitivesWritten;
7022 }
7023
7024 // Assert that timestamp extension is available if needed.
7025 ASSERT((queryType != gl::QueryType::Timestamp && queryType != gl::QueryType::TimeElapsed) ||
7026 mRenderer->getQueueFamilyProperties().timestampValidBits > 0);
7027 ASSERT(mQueryPools[queryType].isValid());
7028 return &mQueryPools[queryType];
7029 }
7030
getClearColorValue() const7031 const VkClearValue &ContextVk::getClearColorValue() const
7032 {
7033 return mClearColorValue;
7034 }
7035
getClearDepthStencilValue() const7036 const VkClearValue &ContextVk::getClearDepthStencilValue() const
7037 {
7038 return mClearDepthStencilValue;
7039 }
7040
getClearColorMasks() const7041 gl::BlendStateExt::ColorMaskStorage::Type ContextVk::getClearColorMasks() const
7042 {
7043 return mClearColorMasks;
7044 }
7045
writeAtomicCounterBufferDriverUniformOffsets(uint32_t * offsetsOut,size_t offsetsSize)7046 void ContextVk::writeAtomicCounterBufferDriverUniformOffsets(uint32_t *offsetsOut,
7047 size_t offsetsSize)
7048 {
7049 const VkDeviceSize offsetAlignment =
7050 mRenderer->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
7051 size_t atomicCounterBufferCount = mState.getAtomicCounterBufferCount();
7052
7053 ASSERT(atomicCounterBufferCount <= offsetsSize * 4);
7054
7055 for (uint32_t bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
7056 {
7057 uint32_t offsetDiff = 0;
7058
7059 const gl::OffsetBindingPointer<gl::Buffer> *atomicCounterBuffer =
7060 &mState.getIndexedAtomicCounterBuffer(bufferIndex);
7061 if (atomicCounterBuffer->get())
7062 {
7063 VkDeviceSize offset = atomicCounterBuffer->getOffset();
7064 VkDeviceSize alignedOffset = (offset / offsetAlignment) * offsetAlignment;
7065
7066 // GL requires the atomic counter buffer offset to be aligned with uint.
7067 ASSERT((offset - alignedOffset) % sizeof(uint32_t) == 0);
7068 offsetDiff = static_cast<uint32_t>((offset - alignedOffset) / sizeof(uint32_t));
7069
7070 // We expect offsetDiff to fit in an 8-bit value. The maximum difference is
7071 // minStorageBufferOffsetAlignment / 4, where minStorageBufferOffsetAlignment
7072 // currently has a maximum value of 256 on any device.
7073 ASSERT(offsetDiff < (1 << 8));
7074 }
7075
7076 // The output array is already cleared prior to this call.
7077 ASSERT(bufferIndex % 4 != 0 || offsetsOut[bufferIndex / 4] == 0);
7078
7079 offsetsOut[bufferIndex / 4] |= static_cast<uint8_t>(offsetDiff) << ((bufferIndex % 4) * 8);
7080 }
7081 }
7082
pauseTransformFeedbackIfActiveUnpaused()7083 void ContextVk::pauseTransformFeedbackIfActiveUnpaused()
7084 {
7085 if (mRenderPassCommands->isTransformFeedbackActiveUnpaused())
7086 {
7087 ASSERT(getFeatures().supportsTransformFeedbackExtension.enabled);
7088 mRenderPassCommands->pauseTransformFeedback();
7089
7090 // Note that this function is called when render pass break is imminent
7091 // (flushCommandsAndEndRenderPass(), or UtilsVk::clearFramebuffer which will close the
7092 // render pass after the clear). This dirty bit allows transform feedback to resume
7093 // automatically on next render pass.
7094 mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
7095 }
7096 }
7097
handleDirtyGraphicsDriverUniforms(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask)7098 angle::Result ContextVk::handleDirtyGraphicsDriverUniforms(DirtyBits::Iterator *dirtyBitsIterator,
7099 DirtyBits dirtyBitMask)
7100 {
7101 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
7102
7103 static_assert(gl::IMPLEMENTATION_MAX_FRAMEBUFFER_SIZE <= 0xFFFF,
7104 "Not enough bits for render area");
7105 static_assert(gl::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE <= 0xFFFF,
7106 "Not enough bits for render area");
7107 uint16_t renderAreaWidth, renderAreaHeight;
7108 SetBitField(renderAreaWidth, drawFramebufferVk->getState().getDimensions().width);
7109 SetBitField(renderAreaHeight, drawFramebufferVk->getState().getDimensions().height);
7110 const uint32_t renderArea = renderAreaHeight << 16 | renderAreaWidth;
7111
7112 bool flipX = false;
7113 bool flipY = false;
7114 // Y-axis flipping only comes into play with the default framebuffer (i.e. a swapchain
7115 // image). For 0-degree rotation, an FBO or pbuffer could be the draw framebuffer, and so we
7116 // must check whether flipY should be positive or negative. All other rotations, will be to
7117 // the default framebuffer, and so the value of isViewportFlipEnabledForDrawFBO() is assumed
7118 // true; the appropriate flipY value is chosen such that gl_FragCoord is positioned at the
7119 // lower-left corner of the window.
7120 switch (mCurrentRotationDrawFramebuffer)
7121 {
7122 case SurfaceRotation::Identity:
7123 flipY = isViewportFlipEnabledForDrawFBO();
7124 break;
7125 case SurfaceRotation::Rotated90Degrees:
7126 ASSERT(isViewportFlipEnabledForDrawFBO());
7127 break;
7128 case SurfaceRotation::Rotated180Degrees:
7129 ASSERT(isViewportFlipEnabledForDrawFBO());
7130 flipX = true;
7131 break;
7132 case SurfaceRotation::Rotated270Degrees:
7133 ASSERT(isViewportFlipEnabledForDrawFBO());
7134 flipX = true;
7135 flipY = true;
7136 break;
7137 default:
7138 UNREACHABLE();
7139 break;
7140 }
7141
7142 const bool invertViewport = isViewportFlipEnabledForDrawFBO();
7143
7144 // Create the extended driver uniform, and populate the extended data fields if necessary.
7145 GraphicsDriverUniformsExtended driverUniformsExt = {};
7146 if (ShouldUseGraphicsDriverUniformsExtended(this))
7147 {
7148 if (mState.isTransformFeedbackActiveUnpaused())
7149 {
7150 TransformFeedbackVk *transformFeedbackVk =
7151 vk::GetImpl(mState.getCurrentTransformFeedback());
7152 transformFeedbackVk->getBufferOffsets(this, mXfbBaseVertex,
7153 driverUniformsExt.xfbBufferOffsets.data(),
7154 driverUniformsExt.xfbBufferOffsets.size());
7155 }
7156 driverUniformsExt.xfbVerticesPerInstance = static_cast<int32_t>(mXfbVertexCountPerInstance);
7157 }
7158
7159 // Create the driver uniform object that will be used as push constant argument.
7160 GraphicsDriverUniforms *driverUniforms = &driverUniformsExt.common;
7161 uint32_t driverUniformSize = GetDriverUniformSize(this, PipelineType::Graphics);
7162
7163 const float depthRangeNear = mState.getNearPlane();
7164 const float depthRangeFar = mState.getFarPlane();
7165 const uint32_t numSamples = drawFramebufferVk->getSamples();
7166 const uint32_t isLayered = drawFramebufferVk->getLayerCount() > 1;
7167
7168 uint32_t advancedBlendEquation = 0;
7169 if (getFeatures().emulateAdvancedBlendEquations.enabled && mState.isBlendEnabled())
7170 {
7171 // Pass the advanced blend equation to shader as-is. If the equation is not one of the
7172 // advanced ones, 0 is expected.
7173 const gl::BlendStateExt &blendStateExt = mState.getBlendStateExt();
7174 if (blendStateExt.getUsesAdvancedBlendEquationMask().test(0))
7175 {
7176 advancedBlendEquation =
7177 static_cast<uint32_t>(getState().getBlendStateExt().getEquationColorIndexed(0));
7178 }
7179 }
7180
7181 const uint32_t swapXY = IsRotatedAspectRatio(mCurrentRotationDrawFramebuffer);
7182 const uint32_t enabledClipDistances = mState.getEnabledClipDistances().bits();
7183 const uint32_t transformDepth =
7184 getFeatures().supportsDepthClipControl.enabled ? 0 : !mState.isClipDepthModeZeroToOne();
7185
7186 static_assert(angle::BitMask<uint32_t>(gl::IMPLEMENTATION_MAX_CLIP_DISTANCES) <=
7187 sh::vk::kDriverUniformsMiscEnabledClipPlanesMask,
7188 "Not enough bits for enabled clip planes");
7189
7190 ASSERT((swapXY & ~sh::vk::kDriverUniformsMiscSwapXYMask) == 0);
7191 ASSERT((advancedBlendEquation & ~sh::vk::kDriverUniformsMiscAdvancedBlendEquationMask) == 0);
7192 ASSERT((numSamples & ~sh::vk::kDriverUniformsMiscSampleCountMask) == 0);
7193 ASSERT((enabledClipDistances & ~sh::vk::kDriverUniformsMiscEnabledClipPlanesMask) == 0);
7194 ASSERT((transformDepth & ~sh::vk::kDriverUniformsMiscTransformDepthMask) == 0);
7195
7196 const uint32_t misc =
7197 swapXY | advancedBlendEquation << sh::vk::kDriverUniformsMiscAdvancedBlendEquationOffset |
7198 numSamples << sh::vk::kDriverUniformsMiscSampleCountOffset |
7199 enabledClipDistances << sh::vk::kDriverUniformsMiscEnabledClipPlanesOffset |
7200 transformDepth << sh::vk::kDriverUniformsMiscTransformDepthOffset |
7201 isLayered << sh::vk::kDriverUniformsMiscLayeredFramebufferOffset;
7202
7203 // Copy and flush to the device.
7204 *driverUniforms = {
7205 {},
7206 {depthRangeNear, depthRangeFar},
7207 renderArea,
7208 MakeFlipUniform(flipX, flipY, invertViewport),
7209 mGraphicsPipelineDesc->getEmulatedDitherControl(),
7210 misc,
7211 };
7212
7213 if (mState.hasValidAtomicCounterBuffer())
7214 {
7215 writeAtomicCounterBufferDriverUniformOffsets(driverUniforms->acbBufferOffsets.data(),
7216 driverUniforms->acbBufferOffsets.size());
7217 }
7218
7219 // Update push constant driver uniforms.
7220 ProgramExecutableVk *executableVk = vk::GetImpl(mState.getProgramExecutable());
7221 mRenderPassCommands->getCommandBuffer().pushConstants(
7222 executableVk->getPipelineLayout(), getRenderer()->getSupportedVulkanShaderStageMask(), 0,
7223 driverUniformSize, driverUniforms);
7224
7225 return angle::Result::Continue;
7226 }
7227
handleDirtyComputeDriverUniforms(DirtyBits::Iterator * dirtyBitsIterator)7228 angle::Result ContextVk::handleDirtyComputeDriverUniforms(DirtyBits::Iterator *dirtyBitsIterator)
7229 {
7230 // Create the driver uniform object that will be used as push constant argument.
7231 ComputeDriverUniforms driverUniforms = {};
7232 uint32_t driverUniformSize = GetDriverUniformSize(this, PipelineType::Compute);
7233
7234 if (mState.hasValidAtomicCounterBuffer())
7235 {
7236 writeAtomicCounterBufferDriverUniformOffsets(driverUniforms.acbBufferOffsets.data(),
7237 driverUniforms.acbBufferOffsets.size());
7238 }
7239
7240 // Update push constant driver uniforms.
7241 ProgramExecutableVk *executableVk = vk::GetImpl(mState.getProgramExecutable());
7242 mOutsideRenderPassCommands->getCommandBuffer().pushConstants(
7243 executableVk->getPipelineLayout(), getRenderer()->getSupportedVulkanShaderStageMask(), 0,
7244 driverUniformSize, &driverUniforms);
7245
7246 return angle::Result::Continue;
7247 }
7248
handleError(VkResult errorCode,const char * file,const char * function,unsigned int line)7249 void ContextVk::handleError(VkResult errorCode,
7250 const char *file,
7251 const char *function,
7252 unsigned int line)
7253 {
7254 ASSERT(errorCode != VK_SUCCESS);
7255
7256 GLenum glErrorCode = DefaultGLErrorCode(errorCode);
7257
7258 std::stringstream errorStream;
7259 errorStream << "Internal Vulkan error (" << errorCode << "): " << VulkanResultString(errorCode)
7260 << ".";
7261
7262 getRenderer()->getMemoryAllocationTracker()->logMemoryStatsOnError();
7263
7264 if (errorCode == VK_ERROR_DEVICE_LOST)
7265 {
7266 WARN() << errorStream.str();
7267 handleDeviceLost();
7268 }
7269
7270 mErrors->handleError(glErrorCode, errorStream.str().c_str(), file, function, line);
7271 }
7272
initBufferAllocation(vk::BufferHelper * bufferHelper,uint32_t memoryTypeIndex,size_t allocationSize,size_t alignment,BufferUsageType bufferUsageType)7273 angle::Result ContextVk::initBufferAllocation(vk::BufferHelper *bufferHelper,
7274 uint32_t memoryTypeIndex,
7275 size_t allocationSize,
7276 size_t alignment,
7277 BufferUsageType bufferUsageType)
7278 {
7279 vk::BufferPool *pool = getDefaultBufferPool(allocationSize, memoryTypeIndex, bufferUsageType);
7280 VkResult result = bufferHelper->initSuballocation(this, memoryTypeIndex, allocationSize,
7281 alignment, bufferUsageType, pool);
7282 if (ANGLE_LIKELY(result == VK_SUCCESS))
7283 {
7284 if (mRenderer->getFeatures().allocateNonZeroMemory.enabled)
7285 {
7286 ANGLE_TRY(bufferHelper->initializeNonZeroMemory(
7287 this, GetDefaultBufferUsageFlags(mRenderer), allocationSize));
7288 }
7289
7290 return angle::Result::Continue;
7291 }
7292
7293 // If the error is not OOM, we should stop and handle the error. In case of OOM, we can try
7294 // other options.
7295 bool shouldTryFallback = (result == VK_ERROR_OUT_OF_DEVICE_MEMORY);
7296 ANGLE_VK_CHECK(this, shouldTryFallback, result);
7297
7298 // If memory allocation fails, it is possible to retry the allocation after cleaning the garbage
7299 // and waiting for submitted commands to finish if necessary.
7300 bool anyGarbageCleaned = false;
7301 bool someGarbageCleaned = false;
7302 do
7303 {
7304 ANGLE_TRY(mRenderer->cleanupSomeGarbage(this, &anyGarbageCleaned));
7305 if (anyGarbageCleaned)
7306 {
7307 someGarbageCleaned = true;
7308 result = bufferHelper->initSuballocation(this, memoryTypeIndex, allocationSize,
7309 alignment, bufferUsageType, pool);
7310 }
7311 } while (result != VK_SUCCESS && anyGarbageCleaned);
7312
7313 if (someGarbageCleaned)
7314 {
7315 INFO() << "Initial allocation failed. Cleaned some garbage | Allocation result: "
7316 << ((result == VK_SUCCESS) ? "SUCCESS" : "FAIL");
7317 }
7318
7319 // If memory allocation fails, it is possible retry after flushing the context and cleaning all
7320 // the garbage.
7321 if (result != VK_SUCCESS)
7322 {
7323 ANGLE_TRY(finishImpl(RenderPassClosureReason::OutOfMemory));
7324 INFO() << "Context flushed due to out-of-memory error.";
7325 result = bufferHelper->initSuballocation(this, memoryTypeIndex, allocationSize, alignment,
7326 bufferUsageType, pool);
7327 }
7328
7329 // If the allocation continues to fail despite all the fallback options, the error must be
7330 // returned.
7331 ANGLE_VK_CHECK(this, result == VK_SUCCESS, result);
7332
7333 // Initialize with non-zero value if needed.
7334 if (mRenderer->getFeatures().allocateNonZeroMemory.enabled)
7335 {
7336 ANGLE_TRY(bufferHelper->initializeNonZeroMemory(this, GetDefaultBufferUsageFlags(mRenderer),
7337 allocationSize));
7338 }
7339
7340 return angle::Result::Continue;
7341 }
7342
initImageAllocation(vk::ImageHelper * imageHelper,bool hasProtectedContent,const vk::MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,vk::MemoryAllocationType allocationType)7343 angle::Result ContextVk::initImageAllocation(vk::ImageHelper *imageHelper,
7344 bool hasProtectedContent,
7345 const vk::MemoryProperties &memoryProperties,
7346 VkMemoryPropertyFlags flags,
7347 vk::MemoryAllocationType allocationType)
7348 {
7349 VkMemoryPropertyFlags oomExcludedFlags = 0;
7350 VkMemoryPropertyFlags outputFlags;
7351 VkDeviceSize outputSize;
7352
7353 if (hasProtectedContent)
7354 {
7355 flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
7356 }
7357
7358 // Get memory requirements for the allocation.
7359 VkMemoryRequirements memoryRequirements;
7360 imageHelper->getImage().getMemoryRequirements(getDevice(), &memoryRequirements);
7361 bool allocateDedicatedMemory =
7362 mRenderer->getImageMemorySuballocator().needsDedicatedMemory(memoryRequirements.size);
7363
7364 VkResult result = imageHelper->initMemory(this, memoryProperties, flags, oomExcludedFlags,
7365 &memoryRequirements, allocateDedicatedMemory,
7366 allocationType, &outputFlags, &outputSize);
7367 if (ANGLE_LIKELY(result == VK_SUCCESS))
7368 {
7369 if (mRenderer->getFeatures().allocateNonZeroMemory.enabled)
7370 {
7371 ANGLE_TRY(imageHelper->initializeNonZeroMemory(this, hasProtectedContent, outputFlags,
7372 outputSize));
7373 }
7374
7375 return angle::Result::Continue;
7376 }
7377
7378 // If the error is not OOM, we should stop and handle the error. In case of OOM, we can try
7379 // other options.
7380 bool shouldTryFallback = (result == VK_ERROR_OUT_OF_DEVICE_MEMORY);
7381 ANGLE_VK_CHECK(this, shouldTryFallback, result);
7382
7383 // If memory allocation fails, it is possible to retry the allocation after cleaning the garbage
7384 // and waiting for submitted commands to finish if necessary.
7385 bool anyGarbageCleaned = false;
7386 bool someGarbageCleaned = false;
7387 do
7388 {
7389 ANGLE_TRY(mRenderer->cleanupSomeGarbage(this, &anyGarbageCleaned));
7390 if (anyGarbageCleaned)
7391 {
7392 someGarbageCleaned = true;
7393 result = imageHelper->initMemory(this, memoryProperties, flags, oomExcludedFlags,
7394 &memoryRequirements, allocateDedicatedMemory,
7395 allocationType, &outputFlags, &outputSize);
7396 }
7397 } while (result != VK_SUCCESS && anyGarbageCleaned);
7398
7399 if (someGarbageCleaned)
7400 {
7401 INFO() << "Initial allocation failed. Cleaned some garbage | Allocation result: "
7402 << ((result == VK_SUCCESS) ? "SUCCESS" : "FAIL");
7403 }
7404
7405 // If memory allocation fails, it is possible retry after flushing the context and cleaning all
7406 // the garbage.
7407 if (result != VK_SUCCESS)
7408 {
7409 ANGLE_TRY(finishImpl(RenderPassClosureReason::OutOfMemory));
7410 INFO() << "Context flushed due to out-of-memory error.";
7411 result = imageHelper->initMemory(this, memoryProperties, flags, oomExcludedFlags,
7412 &memoryRequirements, allocateDedicatedMemory,
7413 allocationType, &outputFlags, &outputSize);
7414 }
7415
7416 // If no fallback has worked so far, we should record the failed allocation information in case
7417 // it needs to be logged.
7418 if (result != VK_SUCCESS)
7419 {
7420 uint32_t pendingMemoryTypeIndex;
7421 if (vma::FindMemoryTypeIndexForImageInfo(
7422 mRenderer->getAllocator().getHandle(), &imageHelper->getVkImageCreateInfo(), flags,
7423 flags, allocateDedicatedMemory, &pendingMemoryTypeIndex) == VK_SUCCESS)
7424 {
7425 mRenderer->getMemoryAllocationTracker()->setPendingMemoryAlloc(
7426 allocationType, memoryRequirements.size, pendingMemoryTypeIndex);
7427 }
7428 }
7429
7430 // If there is no space for the new allocation and other fallbacks have proved ineffective, the
7431 // allocation may still be made outside the device from all other memory types, although it will
7432 // result in performance penalty. This is a last resort.
7433 if (result != VK_SUCCESS)
7434 {
7435 oomExcludedFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
7436 result = imageHelper->initMemory(this, memoryProperties, flags, oomExcludedFlags,
7437 &memoryRequirements, allocateDedicatedMemory,
7438 allocationType, &outputFlags, &outputSize);
7439 INFO()
7440 << "Allocation failed. Removed the DEVICE_LOCAL bit requirement | Allocation result: "
7441 << ((result == VK_SUCCESS) ? "SUCCESS" : "FAIL");
7442
7443 if (result == VK_SUCCESS)
7444 {
7445 // For images allocated here, although allocation is preferred on the device, it is not
7446 // required.
7447 mRenderer->getMemoryAllocationTracker()->compareExpectedFlagsWithAllocatedFlags(
7448 flags & ~oomExcludedFlags, flags, outputFlags,
7449 reinterpret_cast<void *>(imageHelper->getAllocation().getHandle()));
7450
7451 getPerfCounters().deviceMemoryImageAllocationFallbacks++;
7452 }
7453 }
7454
7455 // If the allocation continues to fail despite all the fallback options, the error must be
7456 // returned.
7457 ANGLE_VK_CHECK(this, result == VK_SUCCESS, result);
7458
7459 // Initialize with non-zero value if needed.
7460 if (mRenderer->getFeatures().allocateNonZeroMemory.enabled)
7461 {
7462 ANGLE_TRY(imageHelper->initializeNonZeroMemory(this, hasProtectedContent, outputFlags,
7463 outputSize));
7464 imageHelper->getImage().getHandle();
7465 }
7466
7467 return angle::Result::Continue;
7468 }
7469
releaseBufferAllocation(vk::BufferHelper * bufferHelper)7470 angle::Result ContextVk::releaseBufferAllocation(vk::BufferHelper *bufferHelper)
7471 {
7472 bufferHelper->releaseBufferAndDescriptorSetCache(mRenderer);
7473
7474 if (ANGLE_UNLIKELY(hasExcessPendingGarbage()))
7475 {
7476 ANGLE_TRY(flushAndSubmitCommands(nullptr, nullptr,
7477 RenderPassClosureReason::ExcessivePendingGarbage));
7478 }
7479 return angle::Result::Continue;
7480 }
7481
initBufferForBufferCopy(vk::BufferHelper * bufferHelper,size_t size,vk::MemoryCoherency coherency)7482 angle::Result ContextVk::initBufferForBufferCopy(vk::BufferHelper *bufferHelper,
7483 size_t size,
7484 vk::MemoryCoherency coherency)
7485 {
7486 uint32_t memoryTypeIndex = mRenderer->getStagingBufferMemoryTypeIndex(coherency);
7487 size_t alignment = mRenderer->getStagingBufferAlignment();
7488 return initBufferAllocation(bufferHelper, memoryTypeIndex, size, alignment,
7489 BufferUsageType::Dynamic);
7490 }
7491
initBufferForImageCopy(vk::BufferHelper * bufferHelper,size_t size,vk::MemoryCoherency coherency,angle::FormatID formatId,VkDeviceSize * offset,uint8_t ** dataPtr)7492 angle::Result ContextVk::initBufferForImageCopy(vk::BufferHelper *bufferHelper,
7493 size_t size,
7494 vk::MemoryCoherency coherency,
7495 angle::FormatID formatId,
7496 VkDeviceSize *offset,
7497 uint8_t **dataPtr)
7498 {
7499 // When a buffer is used in copyImage, the offset must be multiple of pixel bytes. This may
7500 // result in non-power of two alignment. VMA's virtual allocator can not handle non-power of two
7501 // alignment. We have to adjust offset manually.
7502 uint32_t memoryTypeIndex = mRenderer->getStagingBufferMemoryTypeIndex(coherency);
7503 size_t imageCopyAlignment = vk::GetImageCopyBufferAlignment(formatId);
7504
7505 // Add extra padding for potential offset alignment
7506 size_t allocationSize = size + imageCopyAlignment;
7507 allocationSize = roundUp(allocationSize, imageCopyAlignment);
7508 size_t stagingAlignment = static_cast<size_t>(mRenderer->getStagingBufferAlignment());
7509
7510 ANGLE_TRY(initBufferAllocation(bufferHelper, memoryTypeIndex, allocationSize, stagingAlignment,
7511 BufferUsageType::Static));
7512
7513 *offset = roundUp(bufferHelper->getOffset(), static_cast<VkDeviceSize>(imageCopyAlignment));
7514 *dataPtr = bufferHelper->getMappedMemory() + (*offset) - bufferHelper->getOffset();
7515
7516 return angle::Result::Continue;
7517 }
7518
initBufferForVertexConversion(ConversionBuffer * conversionBuffer,size_t size,vk::MemoryHostVisibility hostVisibility)7519 angle::Result ContextVk::initBufferForVertexConversion(ConversionBuffer *conversionBuffer,
7520 size_t size,
7521 vk::MemoryHostVisibility hostVisibility)
7522 {
7523 vk::BufferHelper *bufferHelper = conversionBuffer->getBuffer();
7524 if (bufferHelper->valid())
7525 {
7526 // If size is big enough and it is idle, then just reuse the existing buffer. Or if current
7527 // render pass uses the buffer, try to allocate a new one to avoid breaking the render pass.
7528 if (size <= bufferHelper->getSize() &&
7529 (hostVisibility == vk::MemoryHostVisibility::Visible) ==
7530 bufferHelper->isHostVisible() &&
7531 !isRenderPassStartedAndUsesBuffer(*bufferHelper))
7532 {
7533 if (mRenderer->hasResourceUseFinished(bufferHelper->getResourceUse()))
7534 {
7535 bufferHelper->initializeBarrierTracker(this);
7536 return angle::Result::Continue;
7537 }
7538 else if (hostVisibility == vk::MemoryHostVisibility::NonVisible)
7539 {
7540 // For device local buffer, we can reuse the buffer even if it is still GPU busy.
7541 // The memory barrier should take care of this.
7542 return angle::Result::Continue;
7543 }
7544 }
7545
7546 bufferHelper->release(mRenderer);
7547 }
7548
7549 // Mark entire buffer dirty if we have to reallocate the buffer.
7550 conversionBuffer->setEntireBufferDirty();
7551
7552 uint32_t memoryTypeIndex = mRenderer->getVertexConversionBufferMemoryTypeIndex(hostVisibility);
7553 size_t alignment = static_cast<size_t>(mRenderer->getVertexConversionBufferAlignment());
7554
7555 // The size is retrieved and used in descriptor set. The descriptor set wants aligned size,
7556 // otherwise there are test failures. Note that the underlying VMA allocation is always
7557 // allocated with an aligned size anyway.
7558 size_t sizeToAllocate = roundUp(size, alignment);
7559
7560 return initBufferAllocation(bufferHelper, memoryTypeIndex, sizeToAllocate, alignment,
7561 BufferUsageType::Static);
7562 }
7563
updateActiveTextures(const gl::Context * context,gl::Command command)7564 angle::Result ContextVk::updateActiveTextures(const gl::Context *context, gl::Command command)
7565 {
7566 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
7567 ProgramExecutableVk *executableVk = vk::GetImpl(executable);
7568
7569 const gl::ActiveTexturesCache &textures = mState.getActiveTexturesCache();
7570 const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
7571 const gl::ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes();
7572
7573 FillWithNullptr(&mActiveTextures);
7574
7575 bool recreatePipelineLayout = false;
7576 ImmutableSamplerIndexMap immutableSamplerIndexMap = {};
7577 std::unordered_map<size_t, uint32_t> textureUnitSamplerIndexMap = {};
7578 for (size_t textureUnit : activeTextures)
7579 {
7580 gl::Texture *texture = textures[textureUnit];
7581 gl::TextureType textureType = textureTypes[textureUnit];
7582 ASSERT(textureType != gl::TextureType::InvalidEnum);
7583
7584 const bool isIncompleteTexture = texture == nullptr;
7585
7586 // Null textures represent incomplete textures.
7587 if (isIncompleteTexture)
7588 {
7589 ANGLE_TRY(getIncompleteTexture(
7590 context, textureType, executable->getSamplerFormatForTextureUnitIndex(textureUnit),
7591 &texture));
7592 }
7593
7594 TextureVk *textureVk = vk::GetImpl(texture);
7595 ASSERT(textureVk != nullptr);
7596
7597 mActiveTextures[textureUnit] = textureVk;
7598
7599 if (textureType == gl::TextureType::Buffer)
7600 {
7601 continue;
7602 }
7603
7604 if (!isIncompleteTexture && texture->isDepthOrStencil())
7605 {
7606 const bool isStencilTexture = IsStencilSamplerBinding(*executable, textureUnit);
7607 ANGLE_TRY(switchToReadOnlyDepthStencilMode(texture, command, getDrawFramebuffer(),
7608 isStencilTexture));
7609 }
7610
7611 gl::Sampler *sampler = mState.getSampler(static_cast<uint32_t>(textureUnit));
7612 const gl::SamplerState &samplerState =
7613 sampler ? sampler->getSamplerState() : texture->getSamplerState();
7614
7615 // GL_EXT_texture_sRGB_decode
7616 // The new parameter, TEXTURE_SRGB_DECODE_EXT controls whether the
7617 // decoding happens at sample time. It only applies to textures with an
7618 // internal format that is sRGB and is ignored for all other textures.
7619 ANGLE_TRY(textureVk->updateSrgbDecodeState(this, samplerState));
7620
7621 const vk::ImageHelper &image = textureVk->getImage();
7622 if (image.hasInefficientlyEmulatedImageFormat())
7623 {
7624 ANGLE_VK_PERF_WARNING(
7625 this, GL_DEBUG_SEVERITY_LOW,
7626 "The Vulkan driver does not support texture format 0x%04X, emulating with 0x%04X",
7627 image.getIntendedFormat().glInternalFormat,
7628 image.getActualFormat().glInternalFormat);
7629 }
7630
7631 if (image.hasImmutableSampler())
7632 {
7633 if (textureUnitSamplerIndexMap.empty())
7634 {
7635 GenerateTextureUnitSamplerIndexMap(executable->getSamplerBoundTextureUnits(),
7636 &textureUnitSamplerIndexMap);
7637 }
7638 immutableSamplerIndexMap[image.getYcbcrConversionDesc()] =
7639 textureUnitSamplerIndexMap[textureUnit];
7640 }
7641
7642 if (textureVk->getAndResetImmutableSamplerDirtyState())
7643 {
7644 recreatePipelineLayout = true;
7645 }
7646 }
7647
7648 if (!executableVk->areImmutableSamplersCompatible(immutableSamplerIndexMap))
7649 {
7650 recreatePipelineLayout = true;
7651 }
7652
7653 // Recreate the pipeline layout, if necessary.
7654 if (recreatePipelineLayout)
7655 {
7656 executableVk->resetLayout(this);
7657 ANGLE_TRY(executableVk->createPipelineLayout(
7658 this, &getPipelineLayoutCache(), &getDescriptorSetLayoutCache(), &mActiveTextures));
7659 ANGLE_TRY(executableVk->initializeDescriptorPools(this, &getDescriptorSetLayoutCache(),
7660 &getMetaDescriptorPools()));
7661
7662 // The default uniforms descriptor set was reset during createPipelineLayout(), so mark them
7663 // dirty to get everything reallocated/rebound before the next draw.
7664 if (executable->hasDefaultUniforms())
7665 {
7666 executableVk->setAllDefaultUniformsDirty();
7667 }
7668 }
7669
7670 return angle::Result::Continue;
7671 }
7672
7673 template <typename CommandBufferHelperT>
updateActiveImages(CommandBufferHelperT * commandBufferHelper)7674 angle::Result ContextVk::updateActiveImages(CommandBufferHelperT *commandBufferHelper)
7675 {
7676 const gl::State &glState = mState;
7677 const gl::ProgramExecutable *executable = glState.getProgramExecutable();
7678 ASSERT(executable);
7679
7680 // If there are memoryBarrier call being made that requires we insert barriers for images we
7681 // must do so.
7682 bool memoryBarrierRequired = false;
7683 if ((mDeferredMemoryBarriers & kWriteAfterAccessImageMemoryBarriers) != 0)
7684 {
7685 memoryBarrierRequired = true;
7686 mDeferredMemoryBarriers &= ~kWriteAfterAccessImageMemoryBarriers;
7687 }
7688
7689 FillWithNullptr(&mActiveImages);
7690
7691 const gl::ActiveTextureMask &activeImages = executable->getActiveImagesMask();
7692 const gl::ActiveTextureArray<gl::ShaderBitSet> &activeImageShaderBits =
7693 executable->getActiveImageShaderBits();
7694
7695 // Note: currently, the image layout is transitioned entirely even if only one level or layer is
7696 // used. This is an issue if one subresource of the image is used as framebuffer attachment and
7697 // the other as image. This is a similar issue to http://anglebug.com/40096531. Another issue
7698 // however is if multiple subresources of the same image are used at the same time.
7699 // Inefficiencies aside, setting write dependency on the same image multiple times is not
7700 // supported. The following makes sure write dependencies are set only once per image.
7701 std::set<vk::ImageHelper *> alreadyProcessed;
7702
7703 for (size_t imageUnitIndex : activeImages)
7704 {
7705 const gl::ImageUnit &imageUnit = glState.getImageUnit(imageUnitIndex);
7706 const gl::Texture *texture = imageUnit.texture.get();
7707 if (texture == nullptr)
7708 {
7709 continue;
7710 }
7711
7712 TextureVk *textureVk = vk::GetImpl(texture);
7713 mActiveImages[imageUnitIndex] = textureVk;
7714
7715 // The image should be flushed and ready to use at this point. There may still be
7716 // lingering staged updates in its staging buffer for unused texture mip levels or
7717 // layers. Therefore we can't verify it has no staged updates right here.
7718 gl::ShaderBitSet shaderStages = activeImageShaderBits[imageUnitIndex];
7719 ASSERT(shaderStages.any());
7720
7721 // Special handling of texture buffers. They have a buffer attached instead of an image.
7722 if (texture->getType() == gl::TextureType::Buffer)
7723 {
7724 BufferVk *bufferVk = vk::GetImpl(textureVk->getBuffer().get());
7725
7726 OnImageBufferWrite(bufferVk, shaderStages, commandBufferHelper);
7727
7728 textureVk->retainBufferViews(commandBufferHelper);
7729 continue;
7730 }
7731
7732 vk::ImageHelper *image = &textureVk->getImage();
7733
7734 if (alreadyProcessed.find(image) != alreadyProcessed.end())
7735 {
7736 continue;
7737 }
7738 alreadyProcessed.insert(image);
7739
7740 gl::LevelIndex level;
7741 uint32_t layerStart = 0;
7742 uint32_t layerCount = 0;
7743 const vk::ImageLayout imageLayout = GetImageWriteLayoutAndSubresource(
7744 imageUnit, *image, shaderStages, &level, &layerStart, &layerCount);
7745
7746 if (imageLayout == image->getCurrentImageLayout() && !memoryBarrierRequired)
7747 {
7748 // GL spec does not require implementation to do WAW barriers for shader image access.
7749 // If there is no layout change, we skip the barrier here unless there is prior
7750 // memoryBarrier call.
7751 commandBufferHelper->retainImageWithEvent(this, image);
7752 }
7753 else
7754 {
7755 commandBufferHelper->imageWrite(this, level, layerStart, layerCount,
7756 image->getAspectFlags(), imageLayout, image);
7757 }
7758 }
7759
7760 return angle::Result::Continue;
7761 }
7762
flushAndSubmitCommands(const vk::Semaphore * signalSemaphore,const vk::SharedExternalFence * externalFence,RenderPassClosureReason renderPassClosureReason)7763 angle::Result ContextVk::flushAndSubmitCommands(const vk::Semaphore *signalSemaphore,
7764 const vk::SharedExternalFence *externalFence,
7765 RenderPassClosureReason renderPassClosureReason)
7766 {
7767 // Even if render pass does not have any command, we may still need to submit it in case it has
7768 // CLEAR loadOp.
7769 bool someCommandsNeedFlush =
7770 !mOutsideRenderPassCommands->empty() || mRenderPassCommands->started();
7771 bool someCommandAlreadyFlushedNeedsSubmit =
7772 mLastFlushedQueueSerial != mLastSubmittedQueueSerial;
7773 bool someOtherReasonNeedsSubmit = signalSemaphore != nullptr || externalFence != nullptr ||
7774 mHasWaitSemaphoresPendingSubmission;
7775
7776 if (!someCommandsNeedFlush && !someCommandAlreadyFlushedNeedsSubmit &&
7777 !someOtherReasonNeedsSubmit)
7778 {
7779 // We have nothing to submit.
7780 return angle::Result::Continue;
7781 }
7782
7783 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::flushAndSubmitCommands");
7784 if (someCommandsNeedFlush)
7785 {
7786 // If any of secondary command buffer not empty, we need to do flush
7787 // Avoid calling vkQueueSubmit() twice, since submitCommands() below will do that.
7788 ANGLE_TRY(flushCommandsAndEndRenderPassWithoutSubmit(renderPassClosureReason));
7789 }
7790 else if (someCommandAlreadyFlushedNeedsSubmit)
7791 {
7792 // This is when someone already called flushCommandsAndEndRenderPassWithoutQueueSubmit.
7793 // Nothing to flush but we have some command to submit.
7794 ASSERT(mLastFlushedQueueSerial.valid());
7795 ASSERT(QueueSerialsHaveDifferentIndexOrSmaller(mLastSubmittedQueueSerial,
7796 mLastFlushedQueueSerial));
7797 }
7798
7799 const bool outsideRenderPassWritesToBuffer =
7800 mOutsideRenderPassCommands->getAndResetHasHostVisibleBufferWrite();
7801 const bool renderPassWritesToBuffer =
7802 mRenderPassCommands->getAndResetHasHostVisibleBufferWrite();
7803 if (mIsAnyHostVisibleBufferWritten || outsideRenderPassWritesToBuffer ||
7804 renderPassWritesToBuffer)
7805 {
7806 // Make sure all writes to host-visible buffers are flushed. We have no way of knowing
7807 // whether any buffer will be mapped for readback in the future, and we can't afford to
7808 // flush and wait on a one-pipeline-barrier command buffer on every map().
7809 VkMemoryBarrier memoryBarrier = {};
7810 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
7811 memoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
7812 memoryBarrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT;
7813
7814 mOutsideRenderPassCommands->getCommandBuffer().memoryBarrier(
7815 mRenderer->getSupportedBufferWritePipelineStageMask(), VK_PIPELINE_STAGE_HOST_BIT,
7816 memoryBarrier);
7817 mIsAnyHostVisibleBufferWritten = false;
7818 }
7819
7820 if (mGpuEventsEnabled)
7821 {
7822 EventName eventName = GetTraceEventName("Primary", mPrimaryBufferEventCounter);
7823 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
7824 TRACE_EVENT_PHASE_END, eventName));
7825 }
7826
7827 // This will handle any commands that might be recorded above as well as flush any wait
7828 // semaphores.
7829 ANGLE_TRY(flushOutsideRenderPassCommands());
7830
7831 if (mLastFlushedQueueSerial == mLastSubmittedQueueSerial)
7832 {
7833 // We have to do empty submission...
7834 ASSERT(!someCommandsNeedFlush);
7835 mLastFlushedQueueSerial = mOutsideRenderPassCommands->getQueueSerial();
7836 generateOutsideRenderPassCommandsQueueSerial();
7837 }
7838
7839 // We must add the per context dynamic buffers into resourceUseList before submission so that
7840 // they get retained properly until GPU completes. We do not add current buffer into
7841 // resourceUseList since they never get reused or freed until context gets destroyed, at which
7842 // time we always wait for GPU to finish before destroying the dynamic buffers.
7843 mDefaultUniformStorage.updateQueueSerialAndReleaseInFlightBuffers(this,
7844 mLastFlushedQueueSerial);
7845
7846 if (mHasInFlightStreamedVertexBuffers.any())
7847 {
7848 for (size_t attribIndex : mHasInFlightStreamedVertexBuffers)
7849 {
7850 mStreamedVertexBuffers[attribIndex].updateQueueSerialAndReleaseInFlightBuffers(
7851 this, mLastFlushedQueueSerial);
7852 }
7853 mHasInFlightStreamedVertexBuffers.reset();
7854 }
7855
7856 ASSERT(mWaitSemaphores.empty());
7857 ASSERT(mWaitSemaphoreStageMasks.empty());
7858
7859 ANGLE_TRY(submitCommands(signalSemaphore, externalFence, Submit::AllCommands));
7860
7861 ASSERT(mOutsideRenderPassCommands->getQueueSerial() > mLastSubmittedQueueSerial);
7862
7863 mHasAnyCommandsPendingSubmission = false;
7864 mHasWaitSemaphoresPendingSubmission = false;
7865 onRenderPassFinished(RenderPassClosureReason::AlreadySpecifiedElsewhere);
7866
7867 if (mGpuEventsEnabled)
7868 {
7869 EventName eventName = GetTraceEventName("Primary", ++mPrimaryBufferEventCounter);
7870 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
7871 TRACE_EVENT_PHASE_BEGIN, eventName));
7872 }
7873
7874 // Since we just flushed, deferred flush is no longer deferred.
7875 mHasDeferredFlush = false;
7876 return angle::Result::Continue;
7877 }
7878
finishImpl(RenderPassClosureReason renderPassClosureReason)7879 angle::Result ContextVk::finishImpl(RenderPassClosureReason renderPassClosureReason)
7880 {
7881 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::finishImpl");
7882
7883 ANGLE_TRY(flushAndSubmitCommands(nullptr, nullptr, renderPassClosureReason));
7884
7885 // You must have to wait for all queue indices ever used to finish. Just wait for
7886 // mLastSubmittedQueueSerial (which only contains current index) to finish is not enough, if it
7887 // has ever became unCurrent and then Current again.
7888 ANGLE_TRY(mRenderer->finishResourceUse(this, mSubmittedResourceUse));
7889
7890 clearAllGarbage();
7891
7892 if (mGpuEventsEnabled)
7893 {
7894 // This loop should in practice execute once since the queue is already idle.
7895 while (mInFlightGpuEventQueries.size() > 0)
7896 {
7897 ANGLE_TRY(checkCompletedGpuEvents());
7898 }
7899 // Recalculate the CPU/GPU time difference to account for clock drifting. Avoid
7900 // unnecessary synchronization if there is no event to be adjusted (happens when
7901 // finish() gets called multiple times towards the end of the application).
7902 if (mGpuEvents.size() > 0)
7903 {
7904 ANGLE_TRY(synchronizeCpuGpuTime());
7905 }
7906 }
7907
7908 return angle::Result::Continue;
7909 }
7910
addWaitSemaphore(VkSemaphore semaphore,VkPipelineStageFlags stageMask)7911 void ContextVk::addWaitSemaphore(VkSemaphore semaphore, VkPipelineStageFlags stageMask)
7912 {
7913 mWaitSemaphores.push_back(semaphore);
7914 mWaitSemaphoreStageMasks.push_back(stageMask);
7915 mHasWaitSemaphoresPendingSubmission = true;
7916 }
7917
getCompatibleRenderPass(const vk::RenderPassDesc & desc,const vk::RenderPass ** renderPassOut)7918 angle::Result ContextVk::getCompatibleRenderPass(const vk::RenderPassDesc &desc,
7919 const vk::RenderPass **renderPassOut)
7920 {
7921 if (getFeatures().preferDynamicRendering.enabled)
7922 {
7923 *renderPassOut = &mNullRenderPass;
7924 return angle::Result::Continue;
7925 }
7926
7927 // Note: Each context has it's own RenderPassCache so no locking needed.
7928 return mRenderPassCache.getCompatibleRenderPass(this, desc, renderPassOut);
7929 }
7930
getRenderPassWithOps(const vk::RenderPassDesc & desc,const vk::AttachmentOpsArray & ops,const vk::RenderPass ** renderPassOut)7931 angle::Result ContextVk::getRenderPassWithOps(const vk::RenderPassDesc &desc,
7932 const vk::AttachmentOpsArray &ops,
7933 const vk::RenderPass **renderPassOut)
7934 {
7935 if (getFeatures().preferDynamicRendering.enabled)
7936 {
7937 if (mState.isPerfMonitorActive())
7938 {
7939 mRenderPassCommands->updatePerfCountersForDynamicRenderingInstance(this,
7940 &mPerfCounters);
7941 }
7942 return angle::Result::Continue;
7943 }
7944
7945 // Note: Each context has it's own RenderPassCache so no locking needed.
7946 return mRenderPassCache.getRenderPassWithOps(this, desc, ops, renderPassOut);
7947 }
7948
getTimestamp(uint64_t * timestampOut)7949 angle::Result ContextVk::getTimestamp(uint64_t *timestampOut)
7950 {
7951 // The intent of this function is to query the timestamp without stalling the GPU.
7952 // Currently, that seems impossible, so instead, we are going to make a small submission
7953 // with just a timestamp query. First, the disjoint timer query extension says:
7954 //
7955 // > This will return the GL time after all previous commands have reached the GL server but
7956 // have not yet necessarily executed.
7957 //
7958 // The previous commands may be deferred at the moment and not yet flushed. The wording allows
7959 // us to make a submission to get the timestamp without flushing.
7960 //
7961 // Second:
7962 //
7963 // > By using a combination of this synchronous get command and the asynchronous timestamp
7964 // query object target, applications can measure the latency between when commands reach the
7965 // GL server and when they are realized in the framebuffer.
7966 //
7967 // This fits with the above strategy as well, although inevitably we are possibly
7968 // introducing a GPU bubble. This function directly generates a command buffer and submits
7969 // it instead of using the other member functions. This is to avoid changing any state,
7970 // such as the queue serial.
7971
7972 // Create a query used to receive the GPU timestamp
7973 VkDevice device = getDevice();
7974 vk::DeviceScoped<vk::DynamicQueryPool> timestampQueryPool(device);
7975 vk::QueryHelper timestampQuery;
7976 ANGLE_TRY(timestampQueryPool.get().init(this, VK_QUERY_TYPE_TIMESTAMP, 1));
7977 ANGLE_TRY(timestampQueryPool.get().allocateQuery(this, ×tampQuery, 1));
7978
7979 // Record the command buffer
7980 vk::DeviceScoped<vk::PrimaryCommandBuffer> commandBatch(device);
7981 vk::PrimaryCommandBuffer &commandBuffer = commandBatch.get();
7982
7983 ANGLE_TRY(mRenderer->getCommandBufferOneOff(this, getProtectionType(), &commandBuffer));
7984
7985 timestampQuery.writeTimestampToPrimary(this, &commandBuffer);
7986 ANGLE_VK_TRY(this, commandBuffer.end());
7987
7988 QueueSerial submitQueueSerial;
7989 ANGLE_TRY(mRenderer->queueSubmitOneOff(this, std::move(commandBuffer), getProtectionType(),
7990 mContextPriority, VK_NULL_HANDLE, 0,
7991 vk::SubmitPolicy::AllowDeferred, &submitQueueSerial));
7992 // Track it with the submitSerial.
7993 timestampQuery.setQueueSerial(submitQueueSerial);
7994
7995 // Wait for the submission to finish. Given no semaphores, there is hope that it would execute
7996 // in parallel with what's already running on the GPU.
7997 ANGLE_TRY(mRenderer->finishQueueSerial(this, submitQueueSerial));
7998
7999 // Get the query results
8000 vk::QueryResult result(1);
8001 ANGLE_TRY(timestampQuery.getUint64Result(this, &result));
8002 *timestampOut = result.getResult(vk::QueryResult::kDefaultResultIndex);
8003 timestampQueryPool.get().freeQuery(this, ×tampQuery);
8004
8005 // Convert results to nanoseconds.
8006 *timestampOut = static_cast<uint64_t>(
8007 *timestampOut *
8008 static_cast<double>(getRenderer()->getPhysicalDeviceProperties().limits.timestampPeriod));
8009
8010 return angle::Result::Continue;
8011 }
8012
invalidateDefaultAttribute(size_t attribIndex)8013 void ContextVk::invalidateDefaultAttribute(size_t attribIndex)
8014 {
8015 mDirtyDefaultAttribsMask.set(attribIndex);
8016 mGraphicsDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
8017 }
8018
invalidateDefaultAttributes(const gl::AttributesMask & dirtyMask)8019 void ContextVk::invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask)
8020 {
8021 if (dirtyMask.any())
8022 {
8023 mDirtyDefaultAttribsMask |= dirtyMask;
8024 mGraphicsDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS);
8025 mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
8026 }
8027 }
8028
onBufferReleaseToExternal(const vk::BufferHelper & buffer)8029 angle::Result ContextVk::onBufferReleaseToExternal(const vk::BufferHelper &buffer)
8030 {
8031 if (mRenderPassCommands->usesBuffer(buffer))
8032 {
8033 return flushCommandsAndEndRenderPass(
8034 RenderPassClosureReason::BufferUseThenReleaseToExternal);
8035 }
8036 return angle::Result::Continue;
8037 }
8038
onImageReleaseToExternal(const vk::ImageHelper & image)8039 angle::Result ContextVk::onImageReleaseToExternal(const vk::ImageHelper &image)
8040 {
8041 if (isRenderPassStartedAndUsesImage(image))
8042 {
8043 return flushCommandsAndEndRenderPass(
8044 RenderPassClosureReason::ImageUseThenReleaseToExternal);
8045 }
8046 return angle::Result::Continue;
8047 }
8048
beginNewRenderPass(vk::RenderPassFramebuffer && 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)8049 angle::Result ContextVk::beginNewRenderPass(
8050 vk::RenderPassFramebuffer &&framebuffer,
8051 const gl::Rectangle &renderArea,
8052 const vk::RenderPassDesc &renderPassDesc,
8053 const vk::AttachmentOpsArray &renderPassAttachmentOps,
8054 const vk::PackedAttachmentCount colorAttachmentCount,
8055 const vk::PackedAttachmentIndex depthStencilAttachmentIndex,
8056 const vk::PackedClearValuesArray &clearValues,
8057 vk::RenderPassCommandBuffer **commandBufferOut)
8058 {
8059 // End any currently outstanding render pass. The render pass is normally closed before reaching
8060 // here for various reasons, except typically when UtilsVk needs to start one.
8061 ANGLE_TRY(flushCommandsAndEndRenderPass(RenderPassClosureReason::NewRenderPass));
8062
8063 // Now generate queueSerial for the renderPass.
8064 QueueSerial renderPassQueueSerial;
8065 generateRenderPassCommandsQueueSerial(&renderPassQueueSerial);
8066
8067 mPerfCounters.renderPasses++;
8068 ANGLE_TRY(mRenderPassCommands->beginRenderPass(
8069 this, std::move(framebuffer), renderArea, renderPassDesc, renderPassAttachmentOps,
8070 colorAttachmentCount, depthStencilAttachmentIndex, clearValues, renderPassQueueSerial,
8071 commandBufferOut));
8072
8073 // By default all render pass should allow to be reactivated.
8074 mAllowRenderPassToReactivate = true;
8075
8076 if (mCurrentGraphicsPipeline)
8077 {
8078 ASSERT(mCurrentGraphicsPipeline->valid());
8079 mCurrentGraphicsPipeline->retainInRenderPass(mRenderPassCommands);
8080 }
8081 return angle::Result::Continue;
8082 }
8083
startRenderPass(gl::Rectangle renderArea,vk::RenderPassCommandBuffer ** commandBufferOut,bool * renderPassDescChangedOut)8084 angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea,
8085 vk::RenderPassCommandBuffer **commandBufferOut,
8086 bool *renderPassDescChangedOut)
8087 {
8088 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
8089 ASSERT(drawFramebufferVk == vk::GetImpl(mState.getDrawFramebuffer()));
8090
8091 ANGLE_TRY(drawFramebufferVk->startNewRenderPass(this, renderArea, &mRenderPassCommandBuffer,
8092 renderPassDescChangedOut));
8093
8094 // Make sure the render pass is not restarted if it is started by UtilsVk (as opposed to
8095 // setupDraw(), which clears this bit automatically).
8096 mGraphicsDirtyBits.reset(DIRTY_BIT_RENDER_PASS);
8097
8098 ANGLE_TRY(resumeRenderPassQueriesIfActive());
8099
8100 if (commandBufferOut)
8101 {
8102 *commandBufferOut = mRenderPassCommandBuffer;
8103 }
8104
8105 return angle::Result::Continue;
8106 }
8107
startNextSubpass()8108 angle::Result ContextVk::startNextSubpass()
8109 {
8110 ASSERT(hasActiveRenderPass());
8111
8112 // The graphics pipelines are bound to a subpass, so update the subpass as well.
8113 mGraphicsPipelineDesc->nextSubpass(&mGraphicsPipelineTransition);
8114
8115 return mRenderPassCommands->nextSubpass(this, &mRenderPassCommandBuffer);
8116 }
8117
getCurrentSubpassIndex() const8118 uint32_t ContextVk::getCurrentSubpassIndex() const
8119 {
8120 return mGraphicsPipelineDesc->getSubpass();
8121 }
8122
getCurrentViewCount() const8123 uint32_t ContextVk::getCurrentViewCount() const
8124 {
8125 FramebufferVk *drawFBO = vk::GetImpl(mState.getDrawFramebuffer());
8126 return drawFBO->getRenderPassDesc().viewCount();
8127 }
8128
flushCommandsAndEndRenderPassWithoutSubmit(RenderPassClosureReason reason)8129 angle::Result ContextVk::flushCommandsAndEndRenderPassWithoutSubmit(RenderPassClosureReason reason)
8130 {
8131 // Ensure we flush the RenderPass *after* the prior commands.
8132 ANGLE_TRY(flushOutsideRenderPassCommands());
8133 ASSERT(mOutsideRenderPassCommands->empty());
8134
8135 if (!mRenderPassCommands->started())
8136 {
8137 onRenderPassFinished(RenderPassClosureReason::AlreadySpecifiedElsewhere);
8138 return angle::Result::Continue;
8139 }
8140
8141 // Set dirty bits if render pass was open (and thus will be closed).
8142 mGraphicsDirtyBits |= mNewGraphicsCommandBufferDirtyBits;
8143
8144 mCurrentTransformFeedbackQueueSerial = QueueSerial();
8145
8146 onRenderPassFinished(reason);
8147
8148 if (mGpuEventsEnabled)
8149 {
8150 EventName eventName = GetTraceEventName("RP", mPerfCounters.renderPasses);
8151 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
8152 TRACE_EVENT_PHASE_BEGIN, eventName));
8153 ANGLE_TRY(flushOutsideRenderPassCommands());
8154 }
8155
8156 addOverlayUsedBuffersCount(mRenderPassCommands);
8157
8158 pauseTransformFeedbackIfActiveUnpaused();
8159
8160 ANGLE_TRY(mRenderPassCommands->endRenderPass(this));
8161
8162 if (kEnableCommandStreamDiagnostics)
8163 {
8164 addCommandBufferDiagnostics(mRenderPassCommands->getCommandDiagnostics());
8165 }
8166
8167 flushDescriptorSetUpdates();
8168 // Collect RefCountedEvent garbage before submitting to renderer
8169 mRenderPassCommands->collectRefCountedEventsGarbage(
8170 mShareGroupVk->getRefCountedEventsGarbageRecycler());
8171
8172 // Save the queueSerial before calling flushRenderPassCommands, which may return a new
8173 // mRenderPassCommands
8174 ASSERT(QueueSerialsHaveDifferentIndexOrSmaller(mLastFlushedQueueSerial,
8175 mRenderPassCommands->getQueueSerial()));
8176 mLastFlushedQueueSerial = mRenderPassCommands->getQueueSerial();
8177
8178 const vk::RenderPass unusedRenderPass;
8179 const vk::RenderPass *renderPass = &unusedRenderPass;
8180 VkFramebuffer framebufferOverride = VK_NULL_HANDLE;
8181
8182 ANGLE_TRY(getRenderPassWithOps(mRenderPassCommands->getRenderPassDesc(),
8183 mRenderPassCommands->getAttachmentOps(), &renderPass));
8184
8185 // If a new framebuffer is used to accommodate resolve attachments that have been added
8186 // after the fact, create a temp one now and add it to garbage list.
8187 if (!getFeatures().preferDynamicRendering.enabled &&
8188 mRenderPassCommands->getFramebuffer().needsNewFramebufferWithResolveAttachments())
8189 {
8190 vk::Framebuffer tempFramebuffer;
8191 ANGLE_TRY(mRenderPassCommands->getFramebuffer().packResolveViewsAndCreateFramebuffer(
8192 this, *renderPass, &tempFramebuffer));
8193
8194 framebufferOverride = tempFramebuffer.getHandle();
8195 addGarbage(&tempFramebuffer);
8196 }
8197
8198 if (mRenderPassCommands->getAndResetHasHostVisibleBufferWrite())
8199 {
8200 mIsAnyHostVisibleBufferWritten = true;
8201 }
8202 ANGLE_TRY(mRenderer->flushRenderPassCommands(this, getProtectionType(), mContextPriority,
8203 *renderPass, framebufferOverride,
8204 &mRenderPassCommands));
8205
8206 // We just flushed outSideRenderPassCommands above, and any future use of
8207 // outsideRenderPassCommands must have a queueSerial bigger than renderPassCommands. To ensure
8208 // this ordering, we generate a new queueSerial for outsideRenderPassCommands here.
8209 mOutsideRenderPassSerialFactory.reset();
8210
8211 // Generate a new serial for outside commands.
8212 generateOutsideRenderPassCommandsQueueSerial();
8213
8214 if (mGpuEventsEnabled)
8215 {
8216 EventName eventName = GetTraceEventName("RP", mPerfCounters.renderPasses);
8217 ANGLE_TRY(traceGpuEvent(&mOutsideRenderPassCommands->getCommandBuffer(),
8218 TRACE_EVENT_PHASE_END, eventName));
8219 ANGLE_TRY(flushOutsideRenderPassCommands());
8220 }
8221
8222 mHasAnyCommandsPendingSubmission = true;
8223 return angle::Result::Continue;
8224 }
8225
flushCommandsAndEndRenderPass(RenderPassClosureReason reason)8226 angle::Result ContextVk::flushCommandsAndEndRenderPass(RenderPassClosureReason reason)
8227 {
8228 // The main reason we have mHasDeferredFlush is not to break render pass just because we want
8229 // to issue a flush. So there must be a started RP if it is true. Otherwise we should just
8230 // issue a flushAndSubmitCommands immediately instead of set mHasDeferredFlush to true.
8231 ASSERT(!mHasDeferredFlush || mRenderPassCommands->started());
8232
8233 ANGLE_TRY(flushCommandsAndEndRenderPassWithoutSubmit(reason));
8234
8235 if (mHasDeferredFlush || hasExcessPendingGarbage())
8236 {
8237 // If we have deferred glFlush call in the middle of render pass, or if there is too much
8238 // pending garbage, perform a flush now.
8239 RenderPassClosureReason flushImplReason =
8240 (hasExcessPendingGarbage()) ? RenderPassClosureReason::ExcessivePendingGarbage
8241 : RenderPassClosureReason::AlreadySpecifiedElsewhere;
8242 ANGLE_TRY(flushAndSubmitCommands(nullptr, nullptr, flushImplReason));
8243 }
8244 return angle::Result::Continue;
8245 }
8246
flushDirtyGraphicsRenderPass(DirtyBits::Iterator * dirtyBitsIterator,DirtyBits dirtyBitMask,RenderPassClosureReason reason)8247 angle::Result ContextVk::flushDirtyGraphicsRenderPass(DirtyBits::Iterator *dirtyBitsIterator,
8248 DirtyBits dirtyBitMask,
8249 RenderPassClosureReason reason)
8250 {
8251 ASSERT(mRenderPassCommands->started());
8252
8253 ANGLE_TRY(flushCommandsAndEndRenderPass(reason));
8254
8255 // Set dirty bits that need processing on new render pass on the dirty bits iterator that's
8256 // being processed right now.
8257 dirtyBitsIterator->setLaterBits(mNewGraphicsCommandBufferDirtyBits & dirtyBitMask);
8258
8259 // Additionally, make sure any dirty bits not included in the mask are left for future
8260 // processing. Note that |dirtyBitMask| is removed from |mNewGraphicsCommandBufferDirtyBits|
8261 // after dirty bits are iterated, so there's no need to mask them out.
8262 mGraphicsDirtyBits |= mNewGraphicsCommandBufferDirtyBits;
8263
8264 ASSERT(mGraphicsPipelineDesc->getSubpass() == 0);
8265
8266 return angle::Result::Continue;
8267 }
8268
syncExternalMemory()8269 angle::Result ContextVk::syncExternalMemory()
8270 {
8271 VkMemoryBarrier memoryBarrier = {};
8272 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
8273 memoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
8274 memoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
8275
8276 mOutsideRenderPassCommands->getCommandBuffer().memoryBarrier(
8277 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, memoryBarrier);
8278 return angle::Result::Continue;
8279 }
8280
onSyncObjectInit(vk::SyncHelper * syncHelper,SyncFenceScope scope)8281 angle::Result ContextVk::onSyncObjectInit(vk::SyncHelper *syncHelper, SyncFenceScope scope)
8282 {
8283 // Submit the commands:
8284 //
8285 // - This breaks the current render pass to ensure the proper ordering of the sync object in the
8286 // commands,
8287 // - The sync object has a valid serial when it's waited on later,
8288 // - After waiting on the sync object, every resource that's used so far (and is being synced)
8289 // will also be aware that it's finished (based on the serial) and won't incur a further wait
8290 // (for example when a buffer is mapped).
8291 //
8292 // The submission is done immediately for EGL sync objects, and when no render pass is open. If
8293 // a render pass is open, the submission is deferred. This is done to be able to optimize
8294 // scenarios such as sync object init followed by eglSwapBuffers() (that would otherwise incur
8295 // another submission, as well as not being able to optimize the render-to-swapchain render
8296 // pass).
8297 if (scope != SyncFenceScope::CurrentContextToShareGroup || !mRenderPassCommands->started())
8298 {
8299 ANGLE_TRY(
8300 flushAndSubmitCommands(nullptr, nullptr, RenderPassClosureReason::SyncObjectInit));
8301 // Even if no commands is generated, and flushAndSubmitCommands bails out, queueSerial is
8302 // valid since Context initialization. It will always test finished/signaled.
8303 ASSERT(mLastSubmittedQueueSerial.valid());
8304
8305 // If src synchronization scope is all contexts (an ANGLE extension), set the syncHelper
8306 // serial to the last serial of all contexts, instead of just the current context.
8307 if (scope == SyncFenceScope::AllContextsToAllContexts)
8308 {
8309 const size_t maxIndex = mRenderer->getLargestQueueSerialIndexEverAllocated();
8310 for (SerialIndex index = 0; index <= maxIndex; ++index)
8311 {
8312 syncHelper->setSerial(index, mRenderer->getLastSubmittedSerial(index));
8313 }
8314 }
8315 else
8316 {
8317 syncHelper->setQueueSerial(mLastSubmittedQueueSerial);
8318 }
8319
8320 return angle::Result::Continue;
8321 }
8322
8323 // Otherwise we must have a started render pass. The sync object will track the completion of
8324 // this render pass.
8325 mRenderPassCommands->retainResource(syncHelper);
8326
8327 onRenderPassFinished(RenderPassClosureReason::SyncObjectInit);
8328
8329 // Mark the context as having a deffered flush. This is later used to close the render pass and
8330 // cause a submission in this context if another context wants to wait on the fence while the
8331 // original context never issued a submission naturally. Note that this also takes care of
8332 // contexts that think they issued a submission (through glFlush) but that the submission got
8333 // deferred.
8334 mHasDeferredFlush = true;
8335
8336 return angle::Result::Continue;
8337 }
8338
flushCommandsAndEndRenderPassIfDeferredSyncInit(RenderPassClosureReason reason)8339 angle::Result ContextVk::flushCommandsAndEndRenderPassIfDeferredSyncInit(
8340 RenderPassClosureReason reason)
8341 {
8342 if (!mHasDeferredFlush)
8343 {
8344 return angle::Result::Continue;
8345 }
8346
8347 // If we have deferred glFlush call in the middle of render pass, flush them now.
8348 return flushCommandsAndEndRenderPass(reason);
8349 }
8350
addCommandBufferDiagnostics(const std::string & commandBufferDiagnostics)8351 void ContextVk::addCommandBufferDiagnostics(const std::string &commandBufferDiagnostics)
8352 {
8353 mCommandBufferDiagnostics.push_back(commandBufferDiagnostics);
8354 }
8355
dumpCommandStreamDiagnostics()8356 void ContextVk::dumpCommandStreamDiagnostics()
8357 {
8358 std::ostream &out = std::cout;
8359
8360 if (mCommandBufferDiagnostics.empty())
8361 return;
8362
8363 out << "digraph {\n" << " node [shape=plaintext fontname=\"Consolas\"]\n";
8364
8365 for (size_t index = 0; index < mCommandBufferDiagnostics.size(); ++index)
8366 {
8367 const std::string &payload = mCommandBufferDiagnostics[index];
8368 out << " cb" << index << " [label =\"" << payload << "\"];\n";
8369 }
8370
8371 for (size_t index = 0; index < mCommandBufferDiagnostics.size() - 1; ++index)
8372 {
8373 out << " cb" << index << " -> cb" << index + 1 << "\n";
8374 }
8375
8376 mCommandBufferDiagnostics.clear();
8377
8378 out << "}\n";
8379 }
8380
initIndexTypeMap()8381 void ContextVk::initIndexTypeMap()
8382 {
8383 // Init gles-vulkan index type map
8384 mIndexTypeMap[gl::DrawElementsType::UnsignedByte] =
8385 mRenderer->getFeatures().supportsIndexTypeUint8.enabled ? VK_INDEX_TYPE_UINT8_EXT
8386 : VK_INDEX_TYPE_UINT16;
8387 mIndexTypeMap[gl::DrawElementsType::UnsignedShort] = VK_INDEX_TYPE_UINT16;
8388 mIndexTypeMap[gl::DrawElementsType::UnsignedInt] = VK_INDEX_TYPE_UINT32;
8389 }
8390
getVkIndexType(gl::DrawElementsType glIndexType) const8391 VkIndexType ContextVk::getVkIndexType(gl::DrawElementsType glIndexType) const
8392 {
8393 return mIndexTypeMap[glIndexType];
8394 }
8395
getVkIndexTypeSize(gl::DrawElementsType glIndexType) const8396 size_t ContextVk::getVkIndexTypeSize(gl::DrawElementsType glIndexType) const
8397 {
8398 gl::DrawElementsType elementsType = shouldConvertUint8VkIndexType(glIndexType)
8399 ? gl::DrawElementsType::UnsignedShort
8400 : glIndexType;
8401 ASSERT(elementsType < gl::DrawElementsType::EnumCount);
8402
8403 // Use GetDrawElementsTypeSize() to get the size
8404 return static_cast<size_t>(gl::GetDrawElementsTypeSize(elementsType));
8405 }
8406
shouldConvertUint8VkIndexType(gl::DrawElementsType glIndexType) const8407 bool ContextVk::shouldConvertUint8VkIndexType(gl::DrawElementsType glIndexType) const
8408 {
8409 return (glIndexType == gl::DrawElementsType::UnsignedByte &&
8410 !mRenderer->getFeatures().supportsIndexTypeUint8.enabled);
8411 }
8412
GetDriverUniformSize(vk::Context * context,PipelineType pipelineType)8413 uint32_t GetDriverUniformSize(vk::Context *context, PipelineType pipelineType)
8414 {
8415 if (pipelineType == PipelineType::Compute)
8416 {
8417 return sizeof(ComputeDriverUniforms);
8418 }
8419
8420 ASSERT(pipelineType == PipelineType::Graphics);
8421 if (ShouldUseGraphicsDriverUniformsExtended(context))
8422 {
8423 return sizeof(GraphicsDriverUniformsExtended);
8424 }
8425 else
8426 {
8427 return sizeof(GraphicsDriverUniforms);
8428 }
8429 }
8430
flushAndSubmitOutsideRenderPassCommands()8431 angle::Result ContextVk::flushAndSubmitOutsideRenderPassCommands()
8432 {
8433 ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::flushAndSubmitOutsideRenderPassCommands");
8434 ANGLE_TRY(flushOutsideRenderPassCommands());
8435 return submitCommands(nullptr, nullptr, Submit::OutsideRenderPassCommandsOnly);
8436 }
8437
flushOutsideRenderPassCommands()8438 angle::Result ContextVk::flushOutsideRenderPassCommands()
8439 {
8440 if (!mWaitSemaphores.empty())
8441 {
8442 ASSERT(mHasWaitSemaphoresPendingSubmission);
8443 ANGLE_TRY(mRenderer->flushWaitSemaphores(getProtectionType(), mContextPriority,
8444 std::move(mWaitSemaphores),
8445 std::move(mWaitSemaphoreStageMasks)));
8446 }
8447 ASSERT(mWaitSemaphores.empty());
8448 ASSERT(mWaitSemaphoreStageMasks.empty());
8449
8450 if (mOutsideRenderPassCommands->empty())
8451 {
8452 return angle::Result::Continue;
8453 }
8454 ASSERT(mOutsideRenderPassCommands->getQueueSerial().valid());
8455
8456 addOverlayUsedBuffersCount(mOutsideRenderPassCommands);
8457
8458 if (kEnableCommandStreamDiagnostics)
8459 {
8460 addCommandBufferDiagnostics(mOutsideRenderPassCommands->getCommandDiagnostics());
8461 }
8462
8463 flushDescriptorSetUpdates();
8464
8465 // Track completion of this command buffer.
8466 mOutsideRenderPassCommands->flushSetEvents(this);
8467 mOutsideRenderPassCommands->collectRefCountedEventsGarbage(
8468 mShareGroupVk->getRefCountedEventsGarbageRecycler());
8469
8470 // Save the queueSerial before calling flushOutsideRPCommands, which may return a new
8471 // mOutsideRenderPassCommands
8472 ASSERT(QueueSerialsHaveDifferentIndexOrSmaller(mLastFlushedQueueSerial,
8473 mOutsideRenderPassCommands->getQueueSerial()));
8474 mLastFlushedQueueSerial = mOutsideRenderPassCommands->getQueueSerial();
8475
8476 if (mOutsideRenderPassCommands->getAndResetHasHostVisibleBufferWrite())
8477 {
8478 mIsAnyHostVisibleBufferWritten = true;
8479 }
8480 ANGLE_TRY(mRenderer->flushOutsideRPCommands(this, getProtectionType(), mContextPriority,
8481 &mOutsideRenderPassCommands));
8482
8483 // Make sure appropriate dirty bits are set, in case another thread makes a submission before
8484 // the next dispatch call.
8485 mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
8486 mHasAnyCommandsPendingSubmission = true;
8487 mPerfCounters.flushedOutsideRenderPassCommandBuffers++;
8488
8489 if (mRenderPassCommands->started() && mOutsideRenderPassSerialFactory.empty())
8490 {
8491 ANGLE_PERF_WARNING(
8492 getDebug(), GL_DEBUG_SEVERITY_HIGH,
8493 "Running out of reserved outsideRenderPass queueSerial. ending renderPass now.");
8494 // flushCommandsAndEndRenderPass will end up call back into this function again. We must
8495 // ensure mOutsideRenderPassCommands is empty so that it can early out.
8496 ASSERT(mOutsideRenderPassCommands->empty());
8497 // We used up all reserved serials. In order to maintain serial order (outsideRenderPass
8498 // must be smaller than render pass), we also endRenderPass here as well. This is not
8499 // expected to happen often in real world usage.
8500 return flushCommandsAndEndRenderPass(
8501 RenderPassClosureReason::OutOfReservedQueueSerialForOutsideCommands);
8502 }
8503 else
8504 {
8505 // Since queueSerial is used to decide if a resource is being used or not, we have to
8506 // generate a new queueSerial for outsideCommandBuffer since we just flushed
8507 // outsideRenderPassCommands.
8508 generateOutsideRenderPassCommandsQueueSerial();
8509 }
8510
8511 return angle::Result::Continue;
8512 }
8513
beginRenderPassQuery(QueryVk * queryVk)8514 angle::Result ContextVk::beginRenderPassQuery(QueryVk *queryVk)
8515 {
8516 gl::QueryType type = queryVk->getType();
8517
8518 // Emit debug-util markers before calling the query command.
8519 ANGLE_TRY(handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd));
8520
8521 // To avoid complexity, we always start and end these queries inside the render pass. If the
8522 // render pass has not yet started, the query is deferred until it does.
8523 if (mRenderPassCommandBuffer)
8524 {
8525 ANGLE_TRY(queryVk->getQueryHelper()->beginRenderPassQuery(this));
8526 // Remove the dirty bit since next draw call will have active query enabled
8527 if (getFeatures().preferSubmitOnAnySamplesPassedQueryEnd.enabled && IsAnySamplesQuery(type))
8528 {
8529 mGraphicsDirtyBits.reset(DIRTY_BIT_ANY_SAMPLE_PASSED_QUERY_END);
8530 }
8531 }
8532
8533 // Update rasterizer discard emulation with primitives generated query if necessary.
8534 if (type == gl::QueryType::PrimitivesGenerated)
8535 {
8536 updateRasterizerDiscardEnabled(true);
8537 }
8538
8539 ASSERT(mActiveRenderPassQueries[type] == nullptr);
8540 mActiveRenderPassQueries[type] = queryVk;
8541
8542 return angle::Result::Continue;
8543 }
8544
endRenderPassQuery(QueryVk * queryVk)8545 angle::Result ContextVk::endRenderPassQuery(QueryVk *queryVk)
8546 {
8547 gl::QueryType type = queryVk->getType();
8548
8549 // Emit debug-util markers before calling the query command.
8550 ANGLE_TRY(handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd));
8551
8552 // End the query inside the render pass. In some situations, the query may not have actually
8553 // been issued, so there is nothing to do there. That is the case for transform feedback
8554 // queries which are deferred until a draw call with transform feedback active is issued, which
8555 // may have never happened.
8556 ASSERT(mRenderPassCommandBuffer == nullptr ||
8557 type == gl::QueryType::TransformFeedbackPrimitivesWritten || queryVk->hasQueryBegun());
8558 if (mRenderPassCommandBuffer && queryVk->hasQueryBegun())
8559 {
8560 queryVk->getQueryHelper()->endRenderPassQuery(this);
8561 // Set dirty bit so that we can detect and do something when a draw without active query is
8562 // issued.
8563 if (getFeatures().preferSubmitOnAnySamplesPassedQueryEnd.enabled && IsAnySamplesQuery(type))
8564 {
8565 mGraphicsDirtyBits.set(DIRTY_BIT_ANY_SAMPLE_PASSED_QUERY_END);
8566 }
8567 }
8568
8569 // Update rasterizer discard emulation with primitives generated query if necessary.
8570 if (type == gl::QueryType::PrimitivesGenerated)
8571 {
8572 updateRasterizerDiscardEnabled(false);
8573 }
8574
8575 ASSERT(mActiveRenderPassQueries[type] == queryVk);
8576 mActiveRenderPassQueries[type] = nullptr;
8577
8578 return angle::Result::Continue;
8579 }
8580
pauseRenderPassQueriesIfActive()8581 void ContextVk::pauseRenderPassQueriesIfActive()
8582 {
8583 for (QueryVk *activeQuery : mActiveRenderPassQueries)
8584 {
8585 if (activeQuery)
8586 {
8587 activeQuery->onRenderPassEnd(this);
8588 // No need to update rasterizer discard emulation with primitives generated query. The
8589 // state will be updated when the next render pass starts.
8590 }
8591 }
8592 }
8593
resumeRenderPassQueriesIfActive()8594 angle::Result ContextVk::resumeRenderPassQueriesIfActive()
8595 {
8596 // Note: these queries should be processed in order. See comment in QueryVk::onRenderPassStart.
8597 for (QueryVk *activeQuery : mActiveRenderPassQueries)
8598 {
8599 if (activeQuery)
8600 {
8601 // Transform feedback queries are handled separately.
8602 if (activeQuery->getType() == gl::QueryType::TransformFeedbackPrimitivesWritten)
8603 {
8604 continue;
8605 }
8606
8607 ANGLE_TRY(activeQuery->onRenderPassStart(this));
8608
8609 // Update rasterizer discard emulation with primitives generated query if necessary.
8610 if (activeQuery->getType() == gl::QueryType::PrimitivesGenerated)
8611 {
8612 updateRasterizerDiscardEnabled(true);
8613 }
8614 }
8615 }
8616
8617 return angle::Result::Continue;
8618 }
8619
resumeXfbRenderPassQueriesIfActive()8620 angle::Result ContextVk::resumeXfbRenderPassQueriesIfActive()
8621 {
8622 // All other queries are handled separately.
8623 QueryVk *xfbQuery = mActiveRenderPassQueries[gl::QueryType::TransformFeedbackPrimitivesWritten];
8624 if (xfbQuery && mState.isTransformFeedbackActiveUnpaused())
8625 {
8626 ANGLE_TRY(xfbQuery->onRenderPassStart(this));
8627 }
8628
8629 return angle::Result::Continue;
8630 }
8631
doesPrimitivesGeneratedQuerySupportRasterizerDiscard() const8632 bool ContextVk::doesPrimitivesGeneratedQuerySupportRasterizerDiscard() const
8633 {
8634 // If primitives generated is implemented with VK_EXT_primitives_generated_query, check the
8635 // corresponding feature bit.
8636 if (getFeatures().supportsPrimitivesGeneratedQuery.enabled)
8637 {
8638 return mRenderer->getPhysicalDevicePrimitivesGeneratedQueryFeatures()
8639 .primitivesGeneratedQueryWithRasterizerDiscard == VK_TRUE;
8640 }
8641
8642 // If primitives generated is emulated with pipeline statistics query, it's unknown on which
8643 // hardware rasterizer discard is supported. Assume it's supported on none.
8644 if (getFeatures().supportsPipelineStatisticsQuery.enabled)
8645 {
8646 return false;
8647 }
8648
8649 return true;
8650 }
8651
isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(bool isPrimitivesGeneratedQueryActive) const8652 bool ContextVk::isEmulatingRasterizerDiscardDuringPrimitivesGeneratedQuery(
8653 bool isPrimitivesGeneratedQueryActive) const
8654 {
8655 return isPrimitivesGeneratedQueryActive && mState.isRasterizerDiscardEnabled() &&
8656 !doesPrimitivesGeneratedQuerySupportRasterizerDiscard();
8657 }
8658
getActiveRenderPassQuery(gl::QueryType queryType) const8659 QueryVk *ContextVk::getActiveRenderPassQuery(gl::QueryType queryType) const
8660 {
8661 return mActiveRenderPassQueries[queryType];
8662 }
8663
isRobustResourceInitEnabled() const8664 bool ContextVk::isRobustResourceInitEnabled() const
8665 {
8666 return mState.isRobustResourceInitEnabled();
8667 }
8668
setDefaultUniformBlocksMinSizeForTesting(size_t minSize)8669 void ContextVk::setDefaultUniformBlocksMinSizeForTesting(size_t minSize)
8670 {
8671 mDefaultUniformStorage.setMinimumSizeForTesting(minSize);
8672 }
8673
initializeMultisampleTextureToBlack(const gl::Context * context,gl::Texture * glTexture)8674 angle::Result ContextVk::initializeMultisampleTextureToBlack(const gl::Context *context,
8675 gl::Texture *glTexture)
8676 {
8677 ASSERT(glTexture->getType() == gl::TextureType::_2DMultisample);
8678 TextureVk *textureVk = vk::GetImpl(glTexture);
8679
8680 return textureVk->initializeContentsWithBlack(context, GL_NONE,
8681 gl::ImageIndex::Make2DMultisample());
8682 }
8683
onProgramExecutableReset(ProgramExecutableVk * executableVk)8684 void ContextVk::onProgramExecutableReset(ProgramExecutableVk *executableVk)
8685 {
8686 // We can not check if executableVk deleted is what we was bound to, since by the time we get
8687 // here, the program executable in the context's state has already been updated.
8688 // Reset ContextVk::mCurrentGraphicsPipeline, since programInfo.release() freed the
8689 // PipelineHelper that it's currently pointing to.
8690 // TODO(http://anglebug.com/42264159): rework updateActiveTextures(), createPipelineLayout(),
8691 // handleDirtyGraphicsPipeline(), and ProgramPipelineVk::link().
8692 resetCurrentGraphicsPipeline();
8693 invalidateCurrentComputePipeline();
8694 invalidateCurrentGraphicsPipeline();
8695 }
8696
switchToReadOnlyDepthStencilMode(gl::Texture * texture,gl::Command command,FramebufferVk * drawFramebuffer,bool isStencilTexture)8697 angle::Result ContextVk::switchToReadOnlyDepthStencilMode(gl::Texture *texture,
8698 gl::Command command,
8699 FramebufferVk *drawFramebuffer,
8700 bool isStencilTexture)
8701 {
8702 ASSERT(texture->isDepthOrStencil());
8703
8704 // When running compute we don't have a draw FBO.
8705 if (command == gl::Command::Dispatch)
8706 {
8707 return angle::Result::Continue;
8708 }
8709
8710 // The readOnlyDepth/StencilMode flag enables read-only depth-stencil feedback loops. We only
8711 // switch to read-only mode when there's a loop. The render pass tracks the depth and stencil
8712 // access modes, which indicates whether it's possible to retroactively go back and change the
8713 // attachment layouts to read-only.
8714 //
8715 // If there are any writes, the render pass needs to break, so that one using the read-only
8716 // layouts can start.
8717 FramebufferVk *drawFramebufferVk = getDrawFramebuffer();
8718 if (!texture->isBoundToFramebuffer(drawFramebufferVk->getState().getFramebufferSerial()))
8719 {
8720 return angle::Result::Continue;
8721 }
8722
8723 if (isStencilTexture)
8724 {
8725 if (mState.isStencilWriteEnabled(mState.getDrawFramebuffer()->getStencilBitCount()))
8726 {
8727 // This looks like a feedback loop, but we don't issue a warning because the application
8728 // may have correctly used BASE and MAX levels to avoid it. ANGLE doesn't track that.
8729 mDepthStencilAttachmentFlags.set(vk::RenderPassUsage::StencilFeedbackLoop);
8730 }
8731 else if (!mDepthStencilAttachmentFlags[vk::RenderPassUsage::StencilFeedbackLoop])
8732 {
8733 // If we are not in the actual feedback loop mode, switch to read-only stencil mode
8734 mDepthStencilAttachmentFlags.set(vk::RenderPassUsage::StencilReadOnlyAttachment);
8735 }
8736 }
8737
8738 // Switch to read-only depth feedback loop if not already
8739 if (mState.isDepthWriteEnabled())
8740 {
8741 // This looks like a feedback loop, but we don't issue a warning because the application
8742 // may have correctly used BASE and MAX levels to avoid it. ANGLE doesn't track that.
8743 mDepthStencilAttachmentFlags.set(vk::RenderPassUsage::DepthFeedbackLoop);
8744 }
8745 else if (!mDepthStencilAttachmentFlags[vk::RenderPassUsage::DepthFeedbackLoop])
8746 {
8747 // If we are not in the actual feedback loop mode, switch to read-only depth mode
8748 mDepthStencilAttachmentFlags.set(vk::RenderPassUsage::DepthReadOnlyAttachment);
8749 }
8750
8751 if ((mDepthStencilAttachmentFlags & vk::kDepthStencilReadOnlyBits).none())
8752 {
8753 return angle::Result::Continue;
8754 }
8755
8756 // If the aspect that's switching to read-only has a pending clear, it can't be done in the same
8757 // render pass (as the clear is a write operation). In that case, flush the deferred clears for
8758 // the aspect that is turning read-only first. The other deferred clears (such as color) can
8759 // stay deferred.
8760 if ((!isStencilTexture && drawFramebuffer->hasDeferredDepthClear()) ||
8761 (isStencilTexture && drawFramebuffer->hasDeferredStencilClear()))
8762 {
8763 ANGLE_TRY(drawFramebuffer->flushDepthStencilDeferredClear(
8764 this, isStencilTexture ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT));
8765 }
8766
8767 // If the render pass needs closing, mark it as such. Note that a write to depth/stencil may be
8768 // pending through a deferred clear.
8769 if (hasActiveRenderPass())
8770 {
8771 const vk::RenderPassUsage readOnlyAttachmentUsage =
8772 isStencilTexture ? vk::RenderPassUsage::StencilReadOnlyAttachment
8773 : vk::RenderPassUsage::DepthReadOnlyAttachment;
8774 TextureVk *textureVk = vk::GetImpl(texture);
8775
8776 if (!textureVk->getImage().hasRenderPassUsageFlag(readOnlyAttachmentUsage))
8777 {
8778 // If the render pass has written to this aspect, it needs to be closed.
8779 if ((!isStencilTexture && getStartedRenderPassCommands().hasDepthWriteOrClear()) ||
8780 (isStencilTexture && getStartedRenderPassCommands().hasStencilWriteOrClear()))
8781 {
8782 onRenderPassFinished(RenderPassClosureReason::DepthStencilUseInFeedbackLoop);
8783
8784 // Don't let the render pass reactivate.
8785 mAllowRenderPassToReactivate = false;
8786 }
8787 }
8788
8789 // Make sure to update the current render pass's tracking of read-only depth/stencil mode.
8790 mGraphicsDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_ACCESS);
8791 }
8792
8793 return angle::Result::Continue;
8794 }
8795
onResourceAccess(const vk::CommandBufferAccess & access)8796 angle::Result ContextVk::onResourceAccess(const vk::CommandBufferAccess &access)
8797 {
8798 ANGLE_TRY(flushCommandBuffersIfNecessary(access));
8799
8800 for (const vk::CommandBufferImageAccess &imageAccess : access.getReadImages())
8801 {
8802 vk::ImageHelper *image = imageAccess.image;
8803 ASSERT(!isRenderPassStartedAndUsesImage(*image));
8804
8805 imageAccess.image->recordReadBarrier(this, imageAccess.aspectFlags, imageAccess.imageLayout,
8806 mOutsideRenderPassCommands);
8807 mOutsideRenderPassCommands->retainImage(image);
8808 }
8809
8810 for (const vk::CommandBufferImageSubresourceAccess &imageReadAccess :
8811 access.getReadImageSubresources())
8812 {
8813 vk::ImageHelper *image = imageReadAccess.access.image;
8814 ASSERT(!isRenderPassStartedAndUsesImage(*image));
8815
8816 image->recordReadSubresourceBarrier(
8817 this, imageReadAccess.access.aspectFlags, imageReadAccess.access.imageLayout,
8818 imageReadAccess.levelStart, imageReadAccess.levelCount, imageReadAccess.layerStart,
8819 imageReadAccess.layerCount, mOutsideRenderPassCommands);
8820 mOutsideRenderPassCommands->retainImage(image);
8821 }
8822
8823 for (const vk::CommandBufferImageSubresourceAccess &imageWrite : access.getWriteImages())
8824 {
8825 vk::ImageHelper *image = imageWrite.access.image;
8826 ASSERT(!isRenderPassStartedAndUsesImage(*image));
8827
8828 image->recordWriteBarrier(this, imageWrite.access.aspectFlags,
8829 imageWrite.access.imageLayout, imageWrite.levelStart,
8830 imageWrite.levelCount, imageWrite.layerStart,
8831 imageWrite.layerCount, mOutsideRenderPassCommands);
8832 mOutsideRenderPassCommands->retainImage(image);
8833 image->onWrite(imageWrite.levelStart, imageWrite.levelCount, imageWrite.layerStart,
8834 imageWrite.layerCount, imageWrite.access.aspectFlags);
8835 }
8836
8837 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getReadBuffers())
8838 {
8839 ASSERT(!isRenderPassStartedAndUsesBufferForWrite(*bufferAccess.buffer));
8840 ASSERT(!mOutsideRenderPassCommands->usesBufferForWrite(*bufferAccess.buffer));
8841
8842 mOutsideRenderPassCommands->bufferRead(bufferAccess.accessType, bufferAccess.stage,
8843 bufferAccess.buffer);
8844 }
8845
8846 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getWriteBuffers())
8847 {
8848 ASSERT(!isRenderPassStartedAndUsesBuffer(*bufferAccess.buffer));
8849 ASSERT(!mOutsideRenderPassCommands->usesBuffer(*bufferAccess.buffer));
8850
8851 mOutsideRenderPassCommands->bufferWrite(bufferAccess.accessType, bufferAccess.stage,
8852 bufferAccess.buffer);
8853 }
8854
8855 for (const vk::CommandBufferBufferExternalAcquireRelease &bufferAcquireRelease :
8856 access.getExternalAcquireReleaseBuffers())
8857 {
8858 mOutsideRenderPassCommands->retainResourceForWrite(bufferAcquireRelease.buffer);
8859 }
8860
8861 for (const vk::CommandBufferResourceAccess &resourceAccess : access.getAccessResources())
8862 {
8863 mOutsideRenderPassCommands->retainResource(resourceAccess.resource);
8864 }
8865
8866 return angle::Result::Continue;
8867 }
8868
flushCommandBuffersIfNecessary(const vk::CommandBufferAccess & access)8869 angle::Result ContextVk::flushCommandBuffersIfNecessary(const vk::CommandBufferAccess &access)
8870 {
8871 // Go over resources and decide whether the render pass needs to close, whether the outside
8872 // render pass commands need to be flushed, or neither. Note that closing the render pass
8873 // implies flushing the outside render pass as well, so if that needs to be done, we can close
8874 // the render pass and immediately return from this function. Otherwise, this function keeps
8875 // track of whether the outside render pass commands need to be closed, and if so, it will do
8876 // that once at the end.
8877
8878 // Read images only need to close the render pass if they need a layout transition.
8879 for (const vk::CommandBufferImageAccess &imageAccess : access.getReadImages())
8880 {
8881 // Note that different read methods are not compatible. A shader read uses a different
8882 // layout than a transfer read. So we cannot support simultaneous read usage as easily as
8883 // for Buffers. TODO: Don't close the render pass if the image was only used read-only in
8884 // the render pass. http://anglebug.com/42263557
8885 if (isRenderPassStartedAndUsesImage(*imageAccess.image))
8886 {
8887 return flushCommandsAndEndRenderPass(RenderPassClosureReason::ImageUseThenOutOfRPRead);
8888 }
8889 }
8890
8891 // In cases where the image has both read and write permissions, the render pass should be
8892 // closed if there is a read from a previously written subresource (in a specific level/layer),
8893 // or a write to a previously read one.
8894 for (const vk::CommandBufferImageSubresourceAccess &imageSubresourceAccess :
8895 access.getReadImageSubresources())
8896 {
8897 if (isRenderPassStartedAndUsesImage(*imageSubresourceAccess.access.image))
8898 {
8899 return flushCommandsAndEndRenderPass(RenderPassClosureReason::ImageUseThenOutOfRPRead);
8900 }
8901 }
8902
8903 // Write images only need to close the render pass if they need a layout transition.
8904 for (const vk::CommandBufferImageSubresourceAccess &imageWrite : access.getWriteImages())
8905 {
8906 if (isRenderPassStartedAndUsesImage(*imageWrite.access.image))
8907 {
8908 return flushCommandsAndEndRenderPass(RenderPassClosureReason::ImageUseThenOutOfRPWrite);
8909 }
8910 }
8911
8912 bool shouldCloseOutsideRenderPassCommands = false;
8913
8914 // Read buffers only need a new command buffer if previously used for write.
8915 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getReadBuffers())
8916 {
8917 if (isRenderPassStartedAndUsesBufferForWrite(*bufferAccess.buffer))
8918 {
8919 return flushCommandsAndEndRenderPass(
8920 RenderPassClosureReason::BufferWriteThenOutOfRPRead);
8921 }
8922 else if (mOutsideRenderPassCommands->usesBufferForWrite(*bufferAccess.buffer))
8923 {
8924 shouldCloseOutsideRenderPassCommands = true;
8925 }
8926 }
8927
8928 // Write buffers always need a new command buffer if previously used.
8929 for (const vk::CommandBufferBufferAccess &bufferAccess : access.getWriteBuffers())
8930 {
8931 if (isRenderPassStartedAndUsesBuffer(*bufferAccess.buffer))
8932 {
8933 return flushCommandsAndEndRenderPass(
8934 RenderPassClosureReason::BufferUseThenOutOfRPWrite);
8935 }
8936 else if (mOutsideRenderPassCommands->usesBuffer(*bufferAccess.buffer))
8937 {
8938 shouldCloseOutsideRenderPassCommands = true;
8939 }
8940 }
8941
8942 if (shouldCloseOutsideRenderPassCommands)
8943 {
8944 return flushOutsideRenderPassCommands();
8945 }
8946
8947 return angle::Result::Continue;
8948 }
8949
endRenderPassIfComputeReadAfterTransformFeedbackWrite()8950 angle::Result ContextVk::endRenderPassIfComputeReadAfterTransformFeedbackWrite()
8951 {
8952 // Similar to flushCommandBuffersIfNecessary(), but using uniform buffers currently bound and
8953 // used by the current (compute) program. This is to handle read-after-write hazards where the
8954 // write originates from transform feedback.
8955 if (!mCurrentTransformFeedbackQueueSerial.valid())
8956 {
8957 return angle::Result::Continue;
8958 }
8959
8960 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
8961 ASSERT(executable && executable->hasLinkedShaderStage(gl::ShaderType::Compute));
8962
8963 // Uniform buffers:
8964 const std::vector<gl::InterfaceBlock> &blocks = executable->getUniformBlocks();
8965
8966 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
8967 {
8968 const GLuint binding = executable->getUniformBlockBinding(bufferIndex);
8969 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
8970 mState.getIndexedUniformBuffer(binding);
8971
8972 if (bufferBinding.get() == nullptr)
8973 {
8974 continue;
8975 }
8976
8977 vk::BufferHelper &buffer = vk::GetImpl(bufferBinding.get())->getBuffer();
8978 if (buffer.writtenByCommandBuffer(mCurrentTransformFeedbackQueueSerial))
8979 {
8980 return flushCommandsAndEndRenderPass(RenderPassClosureReason::XfbWriteThenComputeRead);
8981 }
8982 }
8983
8984 return angle::Result::Continue;
8985 }
8986
8987 // When textures/images bound/used by current compute program and have been accessed
8988 // as sampled texture in current render pass, need to take care the implicit layout
8989 // transition of these textures/images in the render pass.
endRenderPassIfComputeAccessAfterGraphicsImageAccess()8990 angle::Result ContextVk::endRenderPassIfComputeAccessAfterGraphicsImageAccess()
8991 {
8992 const gl::ProgramExecutable *executable = mState.getProgramExecutable();
8993 ASSERT(executable && executable->hasLinkedShaderStage(gl::ShaderType::Compute));
8994
8995 for (size_t imageUnitIndex : executable->getActiveImagesMask())
8996 {
8997 const gl::Texture *texture = mState.getImageUnit(imageUnitIndex).texture.get();
8998 if (texture == nullptr)
8999 {
9000 continue;
9001 }
9002
9003 TextureVk *textureVk = vk::GetImpl(texture);
9004
9005 if (texture->getType() == gl::TextureType::Buffer)
9006 {
9007 continue;
9008 }
9009 else
9010 {
9011 vk::ImageHelper &image = textureVk->getImage();
9012
9013 // This is to handle the implicit layout transition in render pass of this image,
9014 // while it currently be bound and used by current compute program.
9015 if (mRenderPassCommands->startedAndUsesImageWithBarrier(image))
9016 {
9017 return flushCommandsAndEndRenderPass(
9018 RenderPassClosureReason::GraphicsTextureImageAccessThenComputeAccess);
9019 }
9020 }
9021 }
9022
9023 const gl::ActiveTexturesCache &textures = mState.getActiveTexturesCache();
9024 const gl::ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes();
9025
9026 for (size_t textureUnit : executable->getActiveSamplersMask())
9027 {
9028 gl::Texture *texture = textures[textureUnit];
9029 gl::TextureType textureType = textureTypes[textureUnit];
9030
9031 if (texture == nullptr || textureType == gl::TextureType::Buffer)
9032 {
9033 continue;
9034 }
9035
9036 TextureVk *textureVk = vk::GetImpl(texture);
9037 ASSERT(textureVk != nullptr);
9038 vk::ImageHelper &image = textureVk->getImage();
9039
9040 // Similar to flushCommandBuffersIfNecessary(), but using textures currently bound and used
9041 // by the current (compute) program. This is to handle read-after-write hazards where the
9042 // write originates from a framebuffer attachment.
9043 if (image.hasRenderPassUsageFlag(vk::RenderPassUsage::RenderTargetAttachment) &&
9044 isRenderPassStartedAndUsesImage(image))
9045 {
9046 return flushCommandsAndEndRenderPass(
9047 RenderPassClosureReason::ImageAttachmentThenComputeRead);
9048 }
9049
9050 // Take care of the read image layout transition require implicit synchronization.
9051 if (mRenderPassCommands->startedAndUsesImageWithBarrier(image))
9052 {
9053 return flushCommandsAndEndRenderPass(
9054 RenderPassClosureReason::GraphicsTextureImageAccessThenComputeAccess);
9055 }
9056 }
9057
9058 return angle::Result::Continue;
9059 }
9060
getPerfMonitorCounters()9061 const angle::PerfMonitorCounterGroups &ContextVk::getPerfMonitorCounters()
9062 {
9063 syncObjectPerfCounters(mRenderer->getCommandQueuePerfCounters());
9064
9065 angle::PerfMonitorCounters &counters =
9066 angle::GetPerfMonitorCounterGroup(mPerfMonitorCounters, "vulkan").counters;
9067
9068 #define ANGLE_UPDATE_PERF_MAP(COUNTER) \
9069 angle::GetPerfMonitorCounter(counters, #COUNTER).value = mPerfCounters.COUNTER;
9070
9071 ANGLE_VK_PERF_COUNTERS_X(ANGLE_UPDATE_PERF_MAP)
9072
9073 #undef ANGLE_UPDATE_PERF_MAP
9074
9075 return mPerfMonitorCounters;
9076 }
9077
switchToColorFramebufferFetchMode(bool hasColorFramebufferFetch)9078 angle::Result ContextVk::switchToColorFramebufferFetchMode(bool hasColorFramebufferFetch)
9079 {
9080 ASSERT(!getFeatures().preferDynamicRendering.enabled);
9081
9082 // If framebuffer fetch is permanent, make sure we never switch out of it.
9083 if (getFeatures().permanentlySwitchToFramebufferFetchMode.enabled &&
9084 mIsInColorFramebufferFetchMode)
9085 {
9086 return angle::Result::Continue;
9087 }
9088
9089 ASSERT(mIsInColorFramebufferFetchMode != hasColorFramebufferFetch);
9090 mIsInColorFramebufferFetchMode = hasColorFramebufferFetch;
9091
9092 // If a render pass is already open, close it.
9093 if (mRenderPassCommands->started())
9094 {
9095 ANGLE_TRY(
9096 flushCommandsAndEndRenderPass(RenderPassClosureReason::FramebufferFetchEmulation));
9097 }
9098
9099 // If there's a draw buffer bound, switch it to framebuffer fetch mode. Every other framebuffer
9100 // will switch when bound.
9101 if (mState.getDrawFramebuffer() != nullptr)
9102 {
9103 getDrawFramebuffer()->switchToColorFramebufferFetchMode(this,
9104 mIsInColorFramebufferFetchMode);
9105 }
9106
9107 // Clear the render pass cache; all render passes will be incompatible from now on with the
9108 // old ones.
9109 if (getFeatures().permanentlySwitchToFramebufferFetchMode.enabled)
9110 {
9111 mRenderPassCache.clear(this);
9112 }
9113
9114 mRenderer->onColorFramebufferFetchUse();
9115
9116 return angle::Result::Continue;
9117 }
9118
onFramebufferFetchUse(vk::FramebufferFetchMode framebufferFetchMode)9119 void ContextVk::onFramebufferFetchUse(vk::FramebufferFetchMode framebufferFetchMode)
9120 {
9121 ASSERT(getFeatures().preferDynamicRendering.enabled);
9122
9123 if (mRenderPassCommands->started())
9124 {
9125 // Accumulate framebuffer fetch mode to allow multiple draw calls in the same render pass
9126 // where some use color framebuffer fetch and some depth/stencil
9127 const vk::FramebufferFetchMode mergedMode = vk::FramebufferFetchModeMerge(
9128 mRenderPassCommands->getRenderPassDesc().framebufferFetchMode(), framebufferFetchMode);
9129
9130 mRenderPassCommands->setFramebufferFetchMode(mergedMode);
9131
9132 // When framebuffer fetch is enabled, attachments can be read from even if output is
9133 // masked, so update their access.
9134 if (FramebufferFetchModeHasColor(framebufferFetchMode))
9135 {
9136 onColorAccessChange();
9137 }
9138 if (FramebufferFetchModeHasDepthStencil(framebufferFetchMode))
9139 {
9140 onDepthStencilAccessChange();
9141 }
9142 }
9143
9144 if (FramebufferFetchModeHasColor(framebufferFetchMode))
9145 {
9146 mRenderer->onColorFramebufferFetchUse();
9147 }
9148 }
9149
allocateQueueSerialIndex()9150 ANGLE_INLINE angle::Result ContextVk::allocateQueueSerialIndex()
9151 {
9152 ASSERT(mCurrentQueueSerialIndex == kInvalidQueueSerialIndex);
9153 // Make everything appears to be flushed and submitted
9154 ANGLE_TRY(mRenderer->allocateQueueSerialIndex(&mCurrentQueueSerialIndex));
9155 // Note queueSerial for render pass is deferred until begin time.
9156 generateOutsideRenderPassCommandsQueueSerial();
9157 return angle::Result::Continue;
9158 }
9159
releaseQueueSerialIndex()9160 ANGLE_INLINE void ContextVk::releaseQueueSerialIndex()
9161 {
9162 ASSERT(mCurrentQueueSerialIndex != kInvalidQueueSerialIndex);
9163 mRenderer->releaseQueueSerialIndex(mCurrentQueueSerialIndex);
9164 mCurrentQueueSerialIndex = kInvalidQueueSerialIndex;
9165 }
9166
generateOutsideRenderPassCommandsQueueSerial()9167 ANGLE_INLINE void ContextVk::generateOutsideRenderPassCommandsQueueSerial()
9168 {
9169 ASSERT(mCurrentQueueSerialIndex != kInvalidQueueSerialIndex);
9170
9171 // If there is reserved serial number, use that. Otherwise generate a new one.
9172 Serial serial;
9173 if (mOutsideRenderPassSerialFactory.generate(&serial))
9174 {
9175 ASSERT(mRenderPassCommands->getQueueSerial().valid());
9176 ASSERT(mRenderPassCommands->getQueueSerial().getSerial() > serial);
9177 mOutsideRenderPassCommands->setQueueSerial(mCurrentQueueSerialIndex, serial);
9178 return;
9179 }
9180
9181 serial = mRenderer->generateQueueSerial(mCurrentQueueSerialIndex);
9182 mOutsideRenderPassCommands->setQueueSerial(mCurrentQueueSerialIndex, serial);
9183 }
9184
generateRenderPassCommandsQueueSerial(QueueSerial * queueSerialOut)9185 ANGLE_INLINE void ContextVk::generateRenderPassCommandsQueueSerial(QueueSerial *queueSerialOut)
9186 {
9187 ASSERT(mCurrentQueueSerialIndex != kInvalidQueueSerialIndex);
9188
9189 // We reserve some serial number for outsideRenderPassCommands in case we have to flush.
9190 ASSERT(mOutsideRenderPassCommands->getQueueSerial().valid());
9191 mRenderer->reserveQueueSerials(mCurrentQueueSerialIndex,
9192 kMaxReservedOutsideRenderPassQueueSerials,
9193 &mOutsideRenderPassSerialFactory);
9194
9195 Serial serial = mRenderer->generateQueueSerial(mCurrentQueueSerialIndex);
9196 *queueSerialOut = QueueSerial(mCurrentQueueSerialIndex, serial);
9197 }
9198
resetPerFramePerfCounters()9199 void ContextVk::resetPerFramePerfCounters()
9200 {
9201 mPerfCounters.renderPasses = 0;
9202 mPerfCounters.writeDescriptorSets = 0;
9203 mPerfCounters.flushedOutsideRenderPassCommandBuffers = 0;
9204 mPerfCounters.resolveImageCommands = 0;
9205 mPerfCounters.descriptorSetAllocations = 0;
9206
9207 mRenderer->resetCommandQueuePerFrameCounters();
9208
9209 mShareGroupVk->getMetaDescriptorPools()[DescriptorSetIndex::UniformsAndXfb]
9210 .resetDescriptorCacheStats();
9211 mShareGroupVk->getMetaDescriptorPools()[DescriptorSetIndex::Texture]
9212 .resetDescriptorCacheStats();
9213 mShareGroupVk->getMetaDescriptorPools()[DescriptorSetIndex::ShaderResource]
9214 .resetDescriptorCacheStats();
9215 }
9216
ensureInterfacePipelineCache()9217 angle::Result ContextVk::ensureInterfacePipelineCache()
9218 {
9219 if (!mInterfacePipelinesCache.valid())
9220 {
9221 VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {};
9222 pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
9223
9224 ANGLE_VK_TRY(this, mInterfacePipelinesCache.init(getDevice(), pipelineCacheCreateInfo));
9225 }
9226
9227 return angle::Result::Continue;
9228 }
9229 } // namespace rx
9230