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