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