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