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